#define LV(x) ((x) ? HIGH : LOW) // pinout sorta like this: https://myoldcomputer.nl/Files/Datasheet/2364-Commodore.pdf const int kDataPins[] = { PA12, PA11, PB12, PB11, PB2, PB1, PB15, PB14, }; const int kAddressPins[] = { D15, D14, D12, D11, D10, D9, D8, D7, D6, D5, D4, D3, D2, }; const int kOutputEnablePin = PC9; const int kWriteEnablePin = PC8; void setData(int direction) { for (int i = 0; i < 8; i++) { pinMode(kDataPins[i], direction); } } void setup() { pinMode(LED_BUILTIN, OUTPUT); Serial.begin(115200); setData(INPUT); for (int i = 0; i < 13; i++) { pinMode(kAddressPins[i], OUTPUT); } pinMode(kOutputEnablePin, OUTPUT); digitalWrite(kOutputEnablePin, HIGH); pinMode(kWriteEnablePin, OUTPUT); digitalWrite(kWriteEnablePin, HIGH); } int readData() { int out = 0; for (int i = 0; i < 8; i++) { if (digitalRead(kDataPins[i]) == HIGH) { out += (1 << i); } } return out; } void writeData(int data) { for (int i = 0; i < 8; i++) { digitalWrite(kDataPins[i], LV(data & (1 << i))); } } void writeAddress(int address) { for (int i = 0; i < 13; i++) { digitalWrite(kAddressPins[i], LV(address & (1 << i))); } } int read(int address) { writeAddress(address); delayMicroseconds(1); digitalWrite(kOutputEnablePin, LOW); delayMicroseconds(1); int out = readData(); digitalWrite(kOutputEnablePin, HIGH); return out; } void write(int address, int data) { writeAddress(address); delayMicroseconds(1); digitalWrite(kWriteEnablePin, LOW); writeData(data); delayMicroseconds(1); digitalWrite(kWriteEnablePin, HIGH); } void chiperase() { write(0x5555, 0xaa); write(0x2aaa, 0x55); write(0x5555, 0x80); write(0x5555, 0xaa); write(0x2aaa, 0x55); write(0x5555, 0x10); delay(20); } constexpr int kBufferSize = 256; int address = 0; int led_counter = 0; int led = HIGH; char buffer[kBufferSize] = {}; int buffer_size = 0; const char* kSampleData = "this is a blarg"; int readnibble(const char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'F') return 10 + c - 'A'; if (c >= 'a' && c <= 'f') return 10 + c - 'a'; return -1; } int readint8(const char* buffer) { int n1 = readnibble(buffer[0]); int n2 = readnibble(buffer[1]); if (n1 < 0 || n2 < 0) return -1; return (n1 << 4) + n2; } int readint16(const char* buffer) { int i1 = readint8(buffer); int i2 = readint8(buffer + 2); if (i1 < 0 || i2 < 0) return -1; return (i1 << 8) + i2; } int readpage(const char* buffer, char page[64]) { for (int i = 0; i < 64; i++) { int b = readint8(&buffer[i*2]); if (b < 0) { Serial.printf("error: wrong hex character %c%c\n", buffer[i*2], buffer[i*2+1]); return -1; } page[i] = b; } return 0; } int writepage(int address, const char page[64]) { int start = micros(); for (int i = 0; i < 64; i++) { write(address + i, page[i]); } int end = micros(); delay(10); return end - start; } void dump16(int address) { address = address & 0x1ff0; char buff[16]; for (int i = 0; i < 16; i++) { buff[i] = read(address + i); } Serial.printf("%04x:", address); for (int i = 0; i < 16; i++) { Serial.printf(" %02x", buff[i]); } Serial.print(" "); for (int i = 0; i < 16; i++) { if (buff[i] >= 33 && buff[i] <= 127) { Serial.printf("%c", buff[i]); } else { Serial.print("."); } } Serial.print("\n"); } void runcmd(const char* buffer, int size) { int cmd = buffer[0]; if (size < 1) { dump16(address); address += 16; return; } if (cmd == '0') { address = 0; } else if (cmd == 'a') { if (size < 5) { Serial.println("error: incomplete address command"); return; } address = readint16(buffer + 1); } else if (cmd == 'w') { if (size < 1 + 4 + 2) { Serial.println("error: incomplete write command"); return; } int address = readint16(buffer + 1); int data = readint8(buffer + 5); setData(OUTPUT); write(address, data); delay(10); setData(INPUT); Serial.printf("wrote data at 0x%04x\n", address); dump16(address & 0x1ff0); } else if (cmd == 'p') { if (size < 1 + 4 + 128) { Serial.println("error: incomplete page command"); return; } int address = readint16(buffer + 1) & 0x1fc0; char page[64]; if (readpage(buffer + 5, page) != 0) return; setData(OUTPUT); int elapsed = writepage(address, page); setData(INPUT); Serial.printf("wrote page at 0x%04x in %d us\n", address, elapsed); dump16(address); dump16(address + 16); dump16(address + 32); dump16(address + 48); } else if (cmd == 's') { int addr = address & 0x1ff0; Serial.printf("writing sample data to 0x%04x\n", addr); setData(OUTPUT); for (int i = 0; i < 16; i++) { write(addr + i, kSampleData[i]); } setData(INPUT); } else if (cmd == 'e') { setData(OUTPUT); chiperase(); setData(INPUT); Serial.println("chip erased"); } } void loop() { if (led_counter > 200000) { led_counter = 0; led = (led == HIGH) ? LOW : HIGH; digitalWrite(LED_BUILTIN, led); } led_counter += 1; if (Serial.available()) { char c = Serial.read(); if (c == '\n') { buffer[buffer_size] = 0; runcmd(buffer, buffer_size); buffer_size = 0; buffer[0] = 0; } else { buffer[buffer_size] = c; buffer_size = min(kBufferSize - 1, buffer_size + 1); } } }