273 lines
5.4 KiB
C++
273 lines
5.4 KiB
C++
#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);
|
|
}
|
|
}
|
|
}
|