6502-hacking/6502-controller/6502-controller.ino
2020-01-13 19:54:28 -08:00

292 lines
5.5 KiB
C++

#define PIN_CLK 13
#define PIN_RST A4
#define PIN_RW A5
#define PIN_CE A3
#define PIN_BTN PC13
#define CLK_DELAY 100
#define ROM_SIZE 0x7fff
const char ADDR[] = { PC4, PB13, PB14, PB15, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14 };
const char DATA[] = { PB1, PB2, PB12, PA11, PA12, PC5, PC6, PC8 };
uint8_t running = 0;
uint8_t start = 0;
PROGMEM static uint8_t rom[ROM_SIZE];
uint16_t rom_idx = 0;
uint32_t rom_load_start = 0;
enum states {
IDLE,
WRITE // write rom to memory
};
enum states state = IDLE;
uint16_t readAddress() {
uint16_t addr = 0;
for(uint8_t i = 1; i < 16; i++) {
addr = (addr << 1) + (digitalRead(ADDR[i]) ? 1 : 0);
}
return addr;
}
uint16_t readState() {
uint8_t bit = 0;
uint16_t addr = 0;
uint8_t data = 0;
uint8_t i = 0;
// check chip enable, 0 = enabled; 1 = disabled
uint8_t CE = digitalRead(PIN_CE) ? 0 : 1;
// debugging lines start with D:
Serial.print("D: ");
for(i = 1; i < 16; i++) {
bit = digitalRead(ADDR[i]) ? 1 : 0;
addr = (addr << 1) + bit;
Serial.print(bit);
}
Serial.print(" ");
for(i = 0; i < 8; i++) {
pinMode(DATA[i], INPUT);
bit = digitalRead(DATA[i]) ? 1 : 0;
data = (data << 1) + bit;
Serial.print(bit);
// set DATA pinMode based on Chip Enable
pinMode(DATA[i], CE ? OUTPUT : INPUT);
}
Serial.printf(
" %04x %c %02x %s\r\n",
addr,
(digitalRead(PIN_RW) ? 'r' : 'W'),
data,
CE ? "CE" : "!CE"
);
return addr;
}
void resetHigh() {
Serial.println("D: Setting reset HIGH");
pinMode(PIN_RST, OUTPUT);
digitalWrite(PIN_RST, HIGH);
}
void resetLow() {
Serial.println("D: Setting reset LOW");
pinMode(PIN_RST, OUTPUT);
digitalWrite(PIN_RST, LOW);
}
void startClock() {
running = 1;
Serial.println("D: starting clock");
}
void stopClock() {
running = 0;
Serial.println("D: stoping clock");
}
unsigned int lastUserButton = 0;
void advanceClock() {
//pinMode(PIN_RST, OUTPUT);
//digitalWrite(PIN_RST, HIGH);
digitalWrite(PIN_CLK, !digitalRead(PIN_CLK));
delay(CLK_DELAY);
digitalWrite(PIN_CLK, !digitalRead(PIN_CLK));
delay(CLK_DELAY);
}
void onUserButton() {
if(millis() - lastUserButton > 100) {
readState();
advanceClock();
lastUserButton = millis();
}
}
void onChipEnable() {
uint8_t CE = digitalRead(PIN_CE) ? 0 : 1;
//Serial.printf("CE: %s\n", CE ? "Disabled" : "Enabled");
for(uint8_t i = 0; i < 8; i++) {
pinMode(DATA[i], CE ? OUTPUT : INPUT);
}
//setOutByte(rom[readAddress()]);
}
void setOutByte(char b) {
for(uint8_t i = 0; i < 8; i++) {
pinMode(DATA[i], OUTPUT);
if((b >> (7 - i)) & 1)
digitalWrite(DATA[i], HIGH);
else
digitalWrite(DATA[i], LOW);
}
}
void reset() {
uint8_t CE = digitalRead(PIN_CE) ? 0 : 1;
// set data pins according to Chip Enable state
// 1 = disabled; 0 = enabled
for(uint8_t i = 0; i < 8; i++) {
pinMode(DATA[i], CE ? OUTPUT : INPUT);
digitalWrite(DATA[i], LOW);
}
}
void clearProgMem() {
uint8_t i = 0;
// clear rom
bzero((void*)&rom, ROM_SIZE);
Serial.println("D: memory cleared");
}
void onAddressChange() {
uint16_t addr = readAddress();
uint8_t byt = rom[addr];
setOutByte(byt);
//Serial.printf("%04x: %02x\r\n", addr, byt);
}
void setup() {
uint8_t i = 0;
Serial.begin(115200);
for(i = 0; i < 16; i++) {
pinMode(ADDR[i], INPUT);
attachInterrupt(digitalPinToInterrupt(ADDR[i]), onAddressChange, CHANGE);
}
reset();
//setOutByte(0xea);
pinMode(PIN_CLK, OUTPUT);
pinMode(PIN_RST, INPUT);
pinMode(PIN_BTN, INPUT);
pinMode(PIN_RW, INPUT);
pinMode(PIN_CE, INPUT);
attachInterrupt(digitalPinToInterrupt(PIN_BTN), onUserButton, FALLING);
attachInterrupt(digitalPinToInterrupt(PIN_CE), onChipEnable, CHANGE);
digitalWrite(PIN_CLK, LOW);
digitalWrite(PIN_RST, LOW);
start = millis();
Serial.println("D: clearing rom");
clearProgMem();
}
void loop() {
if(state == WRITE) {
while(true && rom_idx < 0x7ffe && millis() - rom_load_start < 3000) {
// freshen the start time
if(Serial.available() > 0) rom_load_start = millis();
while(Serial.available() > 0) {
rom[rom_idx++] = Serial.read();
}
}
state = IDLE;
Serial.printf("Read 0x%04X bytes into memory\r\n", rom_idx);
Serial.printf("0x7ffc: 0x%02X 0x%02X\r\n", rom[0x7ffc], rom[0x7ffd]);
return;
}
uint8_t CE = digitalRead(PIN_CE) ? 0 : 1;
if(running) {
uint16_t addr = readState();
if(CE) {
//setOutByte(rom[addr]);
//Serial.printf("Setting output %02X\r\n", rom[addr]);
}
advanceClock();
}
if(Serial.available() > 0) {
char c = Serial.read();
//Serial.print(c);
if(c == '0') resetHigh();
if(c == '1') resetLow();
if(c == '3') readState();
if(c == '4') startClock();
if(c == '5') stopClock();
if(c == '6') reset();
if(c == '7') clearProgMem();
if(c == '8') {
for(uint16_t i = 0; i < 0x100; i++) {
if(i % 16 == 0) Serial.printf("0x%04X: ", i);
Serial.printf("%02x", rom[i]);
if(i % 2 == 1) Serial.print(" ");
if(i % 16 == 15) Serial.println();
}
}
if(c == 'l') {
// activate load mode and reset counter
state = WRITE;
rom_idx = 0;
rom_load_start = millis();
bzero((void*)&rom, ROM_SIZE);
Serial.println("D: ready for ROM");
return;
}
/*
if(c == '2') {
// only leave in for debugging
while(!Serial.available()) {};
char b = Serial.read();
setOutByte(b);
}
*/
// flush serial queue
// while(Serial.available() > 0) Serial.read();
}
}