├── CartDump └── CartDump.ino ├── Photos └── Final.jpg ├── README.md ├── Schematic.123 ├── Schematic.png └── SerialDump ├── SerialClass.cpp ├── SerialClass.h ├── SerialDump.cpp ├── SerialDump.sln ├── SerialDump.v11.suo ├── SerialDump.vcxproj └── SerialDump.vcxproj.filters /CartDump/CartDump.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Commodore 64 Cartridge Dumper 3 | * 4 | * (c) 2014 Robert Crossfield 5 | **/ 6 | 7 | int pinsAddress[16] = {52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22}; 8 | int pinsData[8] = {23, 25, 27, 29, 31, 33, 35, 37}; 9 | 10 | String commandInput = ""; // a string to hold incoming data 11 | boolean commandComplete = false; 12 | 13 | void setup() { 14 | Serial.begin(9600); 15 | 16 | for( int pin = 0; pin < 16; ++pin ) 17 | pinMode(pinsAddress[pin], OUTPUT); 18 | 19 | for( int pin = 0; pin < 8; ++pin ) { 20 | pinMode(pinsData[pin], INPUT); 21 | } 22 | 23 | commandInput.reserve(200); 24 | } 25 | 26 | /** 27 | * Handle serial port event 28 | **/ 29 | void serialEvent() { 30 | while (Serial.available()) { 31 | char inChar = (char)Serial.read(); 32 | 33 | commandInput += inChar; 34 | if (inChar == '\n') 35 | commandComplete = true; 36 | } 37 | } 38 | 39 | void loop() { 40 | 41 | if( commandComplete == true ) { 42 | commandComplete = false; 43 | 44 | if( commandInput == "DUMP\n" ) 45 | dump(); 46 | 47 | commandInput = ""; 48 | } 49 | } 50 | 51 | void dump() { 52 | Serial.println("dumping"); 53 | 54 | for( int address = 0; address < 0x2000; ++address ) 55 | Serial.write(readAddress( address )); 56 | 57 | } 58 | 59 | /** 60 | * Read a byte from an address 61 | * 62 | * @param int pAddress Address to read a byte from 63 | * 64 | * @return char 65 | **/ 66 | unsigned char readAddress( int pAddress ) { 67 | 68 | setAddress( pAddress ); 69 | 70 | return getData(); 71 | } 72 | 73 | /** 74 | * Read the data pins 75 | * 76 | * @return char 77 | **/ 78 | unsigned char getData() { 79 | unsigned char data = 0; 80 | 81 | for( int pin = 0; pin < 8; ++pin ) { 82 | unsigned char pinData = digitalRead( pinsData[pin] ); 83 | if( pinData == HIGH ) 84 | data |= (1 << pin); 85 | } 86 | 87 | return data; 88 | } 89 | 90 | /** 91 | * Set the address pins 92 | * 93 | * @param int pAddress 94 | **/ 95 | void setAddress( int pAddress ) { 96 | 97 | for( int pin = 0; pin < 16; ++pin ) { 98 | if( pAddress & 1 ) 99 | digitalWrite( pinsAddress[pin], HIGH ); 100 | else 101 | digitalWrite( pinsAddress[pin], LOW ); 102 | 103 | pAddress >>= 1; 104 | } 105 | 106 | //delay(2); 107 | } 108 | 109 | -------------------------------------------------------------------------------- /Photos/Final.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/segrax/Arduino-C64-Cartridge-Dumper/f81db7ee08e1aebc5197c0141be124befefaa895/Photos/Final.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | C64 Cartridge Dumper 2 | ------------------- 3 | 4 | As a software reverse engineer, we always look to push the limits... and finding an old cartridge in my garage, 5 | and no available ROM online, got me wondering whats inside it. 6 | 7 | This dumper is a WIP, it doesn't support bank switching... but can rip standard 8k Carts without issue. 8 | 9 | The provided C application is merely the Arduino serial example, with a few minor modifications to begin the dump, and save all received bytes to a file. 10 | 11 | The Arudino "CartDump" sketch is the heart of the ripping, setting the address pins as required, reading the data pins back and sending the resulting byte over USB to the serial listener C app. 12 | 13 | 14 | Most of the information about the Expansion Port is taken from http://www.c64-wiki.com/index.php/Expansion_Port 15 | ![Schematic of the Cart Dumper](https://raw.githubusercontent.com/segrax/Arduino-C64-Cartridge-Dumper/master/Schematic.png) 16 | 17 | Completed Device 18 | ![Photo of completed device](https://raw.githubusercontent.com/segrax/Arduino-C64-Cartridge-Dumper/master/Photos/Final.jpg) 19 | -------------------------------------------------------------------------------- /Schematic.123: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/segrax/Arduino-C64-Cartridge-Dumper/f81db7ee08e1aebc5197c0141be124befefaa895/Schematic.123 -------------------------------------------------------------------------------- /Schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/segrax/Arduino-C64-Cartridge-Dumper/f81db7ee08e1aebc5197c0141be124befefaa895/Schematic.png -------------------------------------------------------------------------------- /SerialDump/SerialClass.cpp: -------------------------------------------------------------------------------- 1 | #include "SerialClass.h" 2 | 3 | Serial::Serial(char *portName) 4 | { 5 | //We're not yet connected 6 | this->connected = false; 7 | 8 | //Try to connect to the given port throuh CreateFile 9 | this->hSerial = CreateFile(portName, 10 | GENERIC_READ | GENERIC_WRITE, 11 | 0, 12 | NULL, 13 | OPEN_EXISTING, 14 | FILE_ATTRIBUTE_NORMAL, 15 | NULL); 16 | 17 | //Check if the connection was successfull 18 | if(this->hSerial==INVALID_HANDLE_VALUE) 19 | { 20 | //If not success full display an Error 21 | if(GetLastError()==ERROR_FILE_NOT_FOUND){ 22 | 23 | //Print Error if neccessary 24 | printf("ERROR: Handle was not attached. Reason: %s not available.\n", portName); 25 | 26 | } 27 | else 28 | { 29 | printf("ERROR!!!"); 30 | } 31 | } 32 | else 33 | { 34 | //If connected we try to set the comm parameters 35 | DCB dcbSerialParams = {0}; 36 | 37 | //Try to get the current 38 | if (!GetCommState(this->hSerial, &dcbSerialParams)) 39 | { 40 | //If impossible, show an error 41 | printf("failed to get current serial parameters!"); 42 | } 43 | else 44 | { 45 | //Define serial connection parameters for the arduino board 46 | dcbSerialParams.BaudRate=CBR_9600; 47 | dcbSerialParams.ByteSize=8; 48 | dcbSerialParams.StopBits=ONESTOPBIT; 49 | dcbSerialParams.Parity=NOPARITY; 50 | 51 | //Set the parameters and check for their proper application 52 | if(!SetCommState(hSerial, &dcbSerialParams)) 53 | { 54 | printf("ALERT: Could not set Serial Port parameters"); 55 | } 56 | else 57 | { 58 | //If everything went fine we're connected 59 | this->connected = true; 60 | //We wait 2s as the arduino board will be reseting 61 | Sleep(ARDUINO_WAIT_TIME); 62 | } 63 | } 64 | } 65 | 66 | } 67 | 68 | Serial::~Serial() 69 | { 70 | //Check if we are connected before trying to disconnect 71 | if(this->connected) 72 | { 73 | //We're no longer connected 74 | this->connected = false; 75 | //Close the serial handler 76 | CloseHandle(this->hSerial); 77 | } 78 | } 79 | 80 | int Serial::ReadData(char *buffer, unsigned int nbChar) 81 | { 82 | //Number of bytes we'll have read 83 | DWORD bytesRead; 84 | //Number of bytes we'll really ask to read 85 | unsigned int toRead; 86 | 87 | //Use the ClearCommError function to get status info on the Serial port 88 | ClearCommError(this->hSerial, &this->errors, &this->status); 89 | 90 | //Check if there is something to read 91 | if(this->status.cbInQue>0) 92 | { 93 | //If there is we check if there is enough data to read the required number 94 | //of characters, if not we'll read only the available characters to prevent 95 | //locking of the application. 96 | if(this->status.cbInQue>nbChar) 97 | { 98 | toRead = nbChar; 99 | } 100 | else 101 | { 102 | toRead = this->status.cbInQue; 103 | } 104 | 105 | //Try to read the require number of chars, and return the number of read bytes on success 106 | if(ReadFile(this->hSerial, buffer, toRead, &bytesRead, NULL) && bytesRead != 0) 107 | { 108 | return bytesRead; 109 | } 110 | 111 | } 112 | 113 | //If nothing has been read, or that an error was detected return -1 114 | return -1; 115 | 116 | } 117 | 118 | 119 | bool Serial::WriteData(char *buffer, unsigned int nbChar) 120 | { 121 | DWORD bytesSend; 122 | 123 | //Try to write the buffer on the Serial port 124 | if(!WriteFile(this->hSerial, (void *)buffer, nbChar, &bytesSend, 0)) 125 | { 126 | //In case it don't work get comm error and return false 127 | ClearCommError(this->hSerial, &this->errors, &this->status); 128 | 129 | return false; 130 | } 131 | else 132 | return true; 133 | } 134 | 135 | bool Serial::IsConnected() 136 | { 137 | //Simply return the connection status 138 | return this->connected; 139 | } -------------------------------------------------------------------------------- /SerialDump/SerialClass.h: -------------------------------------------------------------------------------- 1 | #ifndef SERIALCLASS_H_INCLUDED 2 | #define SERIALCLASS_H_INCLUDED 3 | 4 | #define ARDUINO_WAIT_TIME 2000 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class Serial 11 | { 12 | private: 13 | //Serial comm handler 14 | HANDLE hSerial; 15 | //Connection status 16 | bool connected; 17 | //Get various information about the connection 18 | COMSTAT status; 19 | //Keep track of last error 20 | DWORD errors; 21 | 22 | public: 23 | //Initialize Serial communication with the given COM port 24 | Serial(char *portName); 25 | //Close the connection 26 | //NOTA: for some reason you can't connect again before exiting 27 | //the program and running it again 28 | ~Serial(); 29 | //Read data in a buffer, if nbChar is greater than the 30 | //maximum number of bytes available, it will return only the 31 | //bytes available. The function return -1 when nothing could 32 | //be read, the number of bytes actually read. 33 | int ReadData(char *buffer, unsigned int nbChar); 34 | //Writes data from a buffer through the Serial connection 35 | //return true on success. 36 | bool WriteData(char *buffer, unsigned int nbChar); 37 | //Check if we are actually connected 38 | bool IsConnected(); 39 | 40 | 41 | }; 42 | 43 | #endif // SERIALCLASS_H_INCLUDED -------------------------------------------------------------------------------- /SerialDump/SerialDump.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "SerialClass.h" 4 | #include 5 | #include 6 | 7 | int _tmain(int argc, _TCHAR* argv[]) { 8 | printf("C64 Cartridge Dumper"); 9 | 10 | Serial* SP = new Serial("\\\\.\\COM3"); 11 | 12 | if (SP->IsConnected()) 13 | printf("connected"); 14 | else 15 | exit(1); 16 | 17 | char incomingData[0x200] = ""; 18 | 19 | int totalRead = 0x2000; 20 | int dataLength = 0x1ff; 21 | int readResult = 0; 22 | int readTotal = 0; 23 | 24 | SP->WriteData("DUMP\n", 5); 25 | Sleep(2000); 26 | 27 | SP->ReadData(incomingData,0x09); 28 | 29 | std::ofstream myFile ("dump.bin", std::ios::out | std::ios::binary); 30 | 31 | while(SP->IsConnected()) { 32 | readResult = SP->ReadData(incomingData,dataLength); 33 | if( readResult == -1 ) 34 | continue; 35 | 36 | myFile.write (incomingData, readResult); 37 | readTotal += readResult; 38 | 39 | if( readTotal >= totalRead ) 40 | break; 41 | 42 | printf("Bytes read: %i\n",readResult); 43 | 44 | Sleep(1000); 45 | } 46 | myFile.close(); 47 | return 0; 48 | } -------------------------------------------------------------------------------- /SerialDump/SerialDump.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SerialDump", "SerialDump.vcxproj", "{1B2DFC06-FBD0-4F8C-9413-17B367479D24}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {1B2DFC06-FBD0-4F8C-9413-17B367479D24}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {1B2DFC06-FBD0-4F8C-9413-17B367479D24}.Debug|Win32.Build.0 = Debug|Win32 14 | {1B2DFC06-FBD0-4F8C-9413-17B367479D24}.Release|Win32.ActiveCfg = Release|Win32 15 | {1B2DFC06-FBD0-4F8C-9413-17B367479D24}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /SerialDump/SerialDump.v11.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/segrax/Arduino-C64-Cartridge-Dumper/f81db7ee08e1aebc5197c0141be124befefaa895/SerialDump/SerialDump.v11.suo -------------------------------------------------------------------------------- /SerialDump/SerialDump.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {1B2DFC06-FBD0-4F8C-9413-17B367479D24} 15 | Win32Proj 16 | SerialDump 17 | 18 | 19 | 20 | Application 21 | true 22 | v110 23 | MultiByte 24 | 25 | 26 | Application 27 | false 28 | v110 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | Level3 53 | Disabled 54 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 55 | 56 | 57 | Console 58 | true 59 | 60 | 61 | 62 | 63 | Level3 64 | 65 | 66 | MaxSpeed 67 | true 68 | true 69 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 70 | 71 | 72 | Console 73 | true 74 | true 75 | true 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /SerialDump/SerialDump.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | 29 | 30 | Header Files 31 | 32 | 33 | --------------------------------------------------------------------------------