Skip to content

Instantly share code, notes, and snippets.

@arpruss
Last active July 11, 2021 00:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arpruss/59c943709e84d3b7dd4ed7faa187f2f5 to your computer and use it in GitHub Desktop.
Save arpruss/59c943709e84d3b7dd4ed7faa187f2f5 to your computer and use it in GitHub Desktop.
// simply read a 32k Gameboy cartridge
// public domain / CC0
#define CHUNK_SIZE 16
uint16_t address;
uint16_t globalChecksum;
uint16_t correctGlobalChecksum;
uint8_t headerChecksum;
uint8_t correctHeaderChecksum;
bool needToWarnHeaderChecksum = false;
const uint32_t aPins[15] = { PB8, PB9, PC13, PB7, PA0, PA1, PA2, PA3,
PA4, PA5, PA6, PA7, PB0, PB1, PB10 };
const uint32_t dPins[8] = { PB4, PB3, PA9, PA8, PB15, PB14, PB13, PA10 }; // 5V tolerant
void setAddress(uint16_t address) {
uint16_t mask = 1;
for (unsigned bit = 0 ; bit < sizeof(aPins)/sizeof(*aPins) ; bit++, mask <<= 1)
digitalWrite(aPins[bit], (mask & address) ? 1 : 0);
}
uint8_t readByte() {
uint8_t out = 0;
uint8_t mask = 1;
for (unsigned bit = 0 ; mask ; bit++, mask <<= 1)
if (digitalRead(dPins[bit]))
out |= mask;
return out;
}
uint8_t simpleReadByte(uint16_t addr) {
setAddress(addr);
delayMicroseconds(1);
return readByte();
}
void setup() {
for (int i=0;i<15;i++)
pinMode(aPins[i],OUTPUT); // maybe OUTPUT_PULLDOWN in some cases?
for (int i=0;i<8;i++)
pinMode(dPins[i],INPUT);
Serial.begin();
delay(3000);
address = 0x0;
headerChecksum = 0;
globalChecksum = 0;
}
void loop() {
char buf[120];
if (address >= 0x8000) {
sprintf(buf, "; header checksum: %02x (correct is: %02x)\n", headerChecksum, correctHeaderChecksum);
Serial.println(buf);
sprintf(buf, "; ROM checksum: %04x (correct is: %04x)\n", globalChecksum, correctGlobalChecksum);
Serial.println(buf);
while(1) ;
address = 0x7d00;
}
sprintf(buf, "%04x: ", (unsigned)address);
Serial.print(buf);
for (int i=0; i<CHUNK_SIZE; i++) {
uint8_t r = simpleReadByte(address);
sprintf(buf, "%02x", (unsigned)r);
Serial.print(buf);
if (0x134 <= address && address < 0x14d) {
headerChecksum -= r+1;
}
if (address != 0x14e && address != 0x14f) {
globalChecksum += r;
}
if (address == 0x14D) {
correctHeaderChecksum = r;
if (r != headerChecksum)
needToWarnHeaderChecksum = true;
}
else if (address == 0x14e) {
correctGlobalChecksum = (uint16_t)r << 8;
}
else if (address == 0x14f) {
correctGlobalChecksum |= r;
}
address++;
}
Serial.write('\n');
if (needToWarnHeaderChecksum) {
sprintf(buf, "; header checksum mismatch: is %02x, should be %02x !\n", headerChecksum, correctHeaderChecksum);
Serial.print(buf);
needToWarnHeaderChecksum = false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment