/* * READCART Copyright (c) Kevin Thacker, 2001 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This program can be used to read a ROM (or a cartridge) connected to the reading hardware. The reading hardware is connected to the parallel port of the PC */ /* This file has been designed to compile under DJGPP and will run in a pure DOS prompt only */ /* NOTE: This project is for PC only. I have made this project and it does work, HOWEVER I CAN'T BE HELD RESPONSIBLE FOR ANY DAMAGE TO YOUR PC, READER OR ROM/CARTRIDGE, THAT MAY BE CAUSED FROM TRYING THIS PROJECT. YOU TRY THIS PROJECT AT YOUR OWN RISK!!!! */ #include #include #include #include #include #include /* reading hardware has: 2 * 74LS4040 12-bit ripple counters 1 * 74LS04 NOT gate 1 * 74LS244 8-bit data buffer 1 * cartridge edge connector */ /* Signals: /STROBE is counter reset for both 12-bit ripple counters, /INITIALISE is the clock for the first 12-bit ripple counter, /XT is the clock for the second 12-bit ripple counter, D0 is used to select the nibble to read /ERROR, SELECT, PAPER END and BUSY are used to read the nibble */ /* Reading procedure: 1. Reset count of both counters to 0, Reset byte read count to 0. 2. Select upper nibble to read 3. Read nibble 4. Select lower nibble to read 5. Read nibble. 6. Combine nibbles into data-byte and store 7. Update clock of counter 0. If byte read count has reached 4096, Update clock of counter 1 and reset byte read count. 8. go to step 2 and repeat for all data-bytes. */ /* NOTE: 1. counters are advanced on a negative transition 2. The count of both counters is reset with a "1", and can be done at any time. This reset must be held at "0" for the count to increment. */ /* printer port I/O port base in PC hardware */ #define PRINTER_PORT_BASE 0x0378 #define PRINTER_PORT_DATA PRINTER_PORT_BASE+0 #define PRINTER_PORT_STATUS PRINTER_PORT_BASE+1 #define PRINTER_PORT_CONTROL PRINTER_PORT_BASE+2 /* perform a short delay */ void delay() { unsigned short printer_data_port = PRINTER_PORT_DATA; /* every I/O access incurs a delay, so this should give quite a lot of delay */ /* if this delay is too short, there could be chances of the ROM overheating and exploding! */ inb(printer_data_port); inb(printer_data_port); inb(printer_data_port); inb(printer_data_port); inb(printer_data_port); inb(printer_data_port); inb(printer_data_port); inb(printer_data_port); } /* temporary store for cartridge data */ unsigned char cart_data[512*1024]; int main(int argc, char *argv[]) { if (argc!=2) { printf("READCART\r\n"); printf("\r\n"); printf("A tool for reading a CPC+/GX4000 cartridge using the parallel port of the PC\r\n"); printf("\r\n"); printf("YOU USE THIS TOOL AT YOUR OWN RISK. I CAN'T BE HELD RESPONSIBLE FROM ANY DAMAGE\r\n"); printf("THAT IS CAUSED TO CARTRIDGE, CARTRIDGE ROM, YOUR PC OR READING HARDWARE.\r\n"); printf("\r\n"); printf("Usage: %s \r\n",argv[0]); } else { unsigned long i; FILE *fh; unsigned short printer_data_port = PRINTER_PORT_DATA; unsigned short printer_status_port = PRINTER_PORT_STATUS; unsigned short printer_control_port = PRINTER_PORT_CONTROL; unsigned long count; unsigned char control; control = 0; /* init = 1, select = 0, /strobe = 0 */ /* on printer port: init = 1, select = 1, /strobe = 1 */ control |=(1<<1); /* reset 74LS4040's */ /* clear strobe bit - /STROBE on printer port will be 1 */ control &= ~1; outb(printer_control_port,control); delay(); /* set strobe bit - /STROBE on printer port will be 0 */ control |=1; outb(printer_control_port,control); delay(); count = 0; for (i=0; i<512*1024; i++) { int j; unsigned char data,nibble,status; status = inb(printer_status_port); /* bit 3 is /error, and this is bit 0 of data */ /* bit 4 is select, and this is bit 1 of data */ /* bit 5 is paper end and this is bit 2 of data */ /* bit 7 is busy and this is bit 3 of the data (notted) */ /* get data */ data = 0; /* switch to top nibble */ outb(printer_port_data, 0); /* get top nibble */ nibble = ((status>>3) & 0x07) | (((status^0x080) & 0x080)>>(7-3)); data = data<<4; data = data|nibble; /* switch to bottom nibble */ outb(printer_port_data, 1); /* get bottom nibble */ nibble = ((status>>3) & 0x07) | (((status^0x080) & 0x080)>>(7-3)); data = data<<4; data = data|nibble; /* store */ cart_data[i] = data; /* delay */ delay(); /* toggle clock of first 74LS4040 */ control|=(1<<2); outb(printer_control_port,control); delay(); control&=~(1<<2); outb(printer_control_port,control); delay(); count++; if (count>=(1<<12)) { count = 0; /* toggle clock of second 74LS4040 */ control&=~(1<<1); outb(printer_control_port,control); delay(); control|=(1<<1); outb(printer_control_port,control); delay(); } /* save data to disk */ fh = fopen(argv[1],"wb"); if (fh!=NULL) { fwrite(cart_data, 512*1024,1,fh); fclose(fh); } } } return 0; }