Created
September 23, 2024 12:06
-
-
Save ctigeek/1ce86a4d6be38cd79af84a040faab6ad to your computer and use it in GitHub Desktop.
Arduino 6502
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void FillRom(byte *buffer) { | |
for (int i=0x00; i<= 0x06; i++) { | |
buffer[i] = 0xEA; | |
} | |
//load A with 0x77 and push | |
buffer[0x07] = 0xA9; | |
buffer[0x08] = 0x77; | |
buffer[0x09] = 0x48; | |
//load A with 0x88 and push | |
buffer[0x0A] = 0xA9; | |
buffer[0x0B] = 0x88; | |
buffer[0x0C] = 0x48; | |
//pop off stack into A twice | |
buffer[0x0D] = 0x68; | |
buffer[0x0E] = 0x68; | |
buffer[0x0F] = Op_JMP_abs; | |
buffer[0x10] = 0x00; | |
buffer[0x11] = 0x80; | |
} | |
// BE Bus Enable. Set high for normal operation. | |
const char BE = 40; // OUTPUT ONLY, Port G1 | |
// PHI2 the clock. | |
const char CLOCK=41; // INPUT ONLY for now., PORT G0 | |
//RWB Read-Write bit. When high, the CPU is reading data. | |
const char RWB = 42; // INPUT ONLY, port L7 | |
//RESB Reset. When low for 2+ cycles, the CPU is reset and PC is set to FFFC-D. | |
const char RESB= 43; // OUTPUT ONLY, port L6 | |
//VPB vector pull. When low, the CPU is reading the interrupt vector . | |
const char VPB = 44; // INPUT ONLY, port L5 | |
//RDY READY. When low, the CPU will stop. Keep high for normal operation. | |
const char RDY = 45; // OUTPUT port L4 | |
//IRQB Interrupt Request. Low will trigger an interrupt. | |
const char IRQB = 46; // OUTPUT ONLY port L3 | |
//NMIB Non Maskable Interrupt. Low will trigger an interrupt. | |
const char NMIB = 47; // OUTPUT ONLY port L2 | |
// Synchronize OpCode fetch. Goes high when CPU is fetching an op code. | |
const char SYNC = 48; // INPUT ONLY port L1 | |
//DATA, input + output | |
const char D0 = 22; | |
const char D1 = 23; // PORT A | |
const char D2 = 24; | |
const char D3 = 25; | |
const char D4 = 26; | |
const char D5 = 27; | |
const char D6 = 28; | |
const char D7 = 29; | |
// Address lines | |
const char Ad0 = 53; | |
const char Ad1 = 52; | |
const char Ad2 = 51; | |
const char Ad3 = 50; // PORT B | |
const char Ad4 = 10; | |
const char Ad5 = 11; | |
const char Ad6 = 12; | |
const char Ad7 = 13; | |
///////////////////////////// | |
const char Ad8 = 37; | |
const char Ad9 = 36; //PORT C | |
const char AdA = 35; | |
const char AdB = 34; | |
const char AdC = 33; | |
const char AdD = 32; | |
const char AdE = 31; | |
const char AdF = 30; | |
//===================== Op Codes. https://www.masswerk.at/6502/6502_instruction_set.html | |
const uint8_t Op_NOP = 0xEA; // No Operation | |
const uint8_t Op_JSR = 0x20; // Jump Subroutine. + 2bytes absolute address | |
const uint8_t Op_RTI = 0x40; // Return from Interupt | |
const uint8_t Op_JMP_abs = 0x4C; // Jump absolute. + 2 bytes absolute address | |
const uint8_t Op_JMP_ind = 0x6C; // Jump indirect. + 2 bytes indirect address | |
const uint8_t Op_RTS = 0x60; // Return from subroutine. | |
// special addresses | |
const uint16_t RESET_ADDRESS_LB = 0xFFFC; | |
const uint16_t RESET_ADDRESS_HB = 0xFFFD; | |
const uint8_t RESET_VECTOR_LB = 0x00; | |
const uint8_t RESET_VECTOR_HB = 0x80; | |
//global vars to track state... | |
String Clock_status = ""; | |
uint8_t RWB_status = LOW; | |
uint8_t VPB_status = HIGH; | |
uint8_t SYNC_status = HIGH; | |
uint16_t address = 0x00; | |
uint8_t data = 0x00; | |
const uint16_t ROM_SIZE = 0x02FF; | |
byte ROM[ROM_SIZE]; | |
void setup() { | |
SetAddressPinsToInput(); | |
SetDataPinsToInput(); | |
pinMode(CLOCK, INPUT); | |
//set BE to high. If set to low, address and data go HI-Z | |
pinMode(BE, OUTPUT); | |
digitalWrite(BE, HIGH); | |
//when RWB is high, the processor is reading data. When low, writing data. | |
pinMode(RWB, INPUT); | |
// set RESB to low for 2 clock cycles | |
pinMode(RESB, OUTPUT); | |
digitalWrite(RESB, HIGH); | |
// this has something to do with interrupts. can be ignored for now. | |
pinMode(VPB, INPUT); | |
pinMode(RDY, OUTPUT); | |
digitalWrite(RDY, HIGH); | |
pinMode(IRQB, OUTPUT); | |
digitalWrite(IRQB, HIGH); | |
pinMode(NMIB, OUTPUT); | |
digitalWrite(NMIB, HIGH); | |
pinMode(SYNC, INPUT); | |
Serial.begin(57600); | |
Serial.println("Emulator started."); | |
ResetCPU(); | |
FillRom(ROM); | |
} | |
void loop() { | |
if (Clock_status == "LOW") { | |
WaitForClockHigh(); | |
} | |
else { | |
WaitForClockLow(); | |
} | |
if (RWB_status == HIGH) { // READ from RAM or ROM or IO | |
if (address <= 0x3FFF) { // 0011 1111 1111 1111 16k | |
ReadDataLines(); | |
Serial.println("RAM HIT!!!"); | |
} | |
else if (address >= 0x8000) { // 1000 0000 0000 0000 32k | |
address = address & 0x7FFF; | |
WriteDataLines(ROM[address]); | |
Serial.println("ROM HIT!!!"); | |
} | |
else { // ??? | |
Serial.print("unknown address!!!!!!!!!!!!!!!"); | |
WriteDataLines(Op_NOP); | |
} | |
} | |
else { // this is a memory or IO write operation | |
ReadDataLines(); | |
} | |
if (Clock_status != "LOW") { | |
DumpData(); | |
} | |
} | |
void DumpData() { | |
String isRWB = RWB_status == HIGH ? "READ " : "WRITE"; | |
String isVPB = VPB_status == HIGH ? "_________" : "INTERRUPT"; | |
String isSYNC = SYNC_status == HIGH ? "OP FETCH" : "________"; | |
Serial.print(" CLOCK:"); | |
Serial.print(Clock_status); | |
Serial.print(" RWB="); | |
Serial.print(isRWB); | |
Serial.print(" VPB="); | |
Serial.print(isVPB); | |
Serial.print(" SYNC="); | |
Serial.print(isSYNC); | |
Serial.print(" ADDRESS="); | |
Serial.print(address,HEX); | |
Serial.print(" data="); | |
Serial.println(data,HEX); | |
} | |
void ResetCPU() { | |
Serial.println("Resetting CPU.... make sure clock is running..."); | |
digitalWrite(RESB, LOW); | |
WaitForClockLow(); | |
WaitForClockHigh(); | |
//Serial.println("Resetting: 2 more clock cycles"); | |
WaitForClockLow(); | |
WaitForClockHigh(); | |
//Serial.println("Resetting: 1 more clock cycle"); | |
WaitForClockLow(); | |
WaitForClockHigh(); | |
digitalWrite(RESB, HIGH); | |
Serial.println(" Keep the clock running...."); | |
for (int i=25; i>=0; i--) | |
{ | |
if (Clock_status == "LOW") { | |
WaitForClockHigh(); | |
} | |
else { | |
WaitForClockLow(); | |
} | |
if (VPB_status == LOW) { | |
if (address == RESET_ADDRESS_LB) { | |
WriteDataLines(RESET_VECTOR_LB); | |
} | |
else if (address == RESET_ADDRESS_HB) { | |
WriteDataLines(RESET_VECTOR_HB); | |
i=1; | |
} | |
else { | |
Serial.println("This should never happen 1111."); | |
WriteDataLines(0x00); | |
} | |
DumpData(); | |
} | |
} | |
WaitForClockLow(); | |
SetDataPinsToInput(); | |
Serial.println("Reset complete."); | |
} | |
void WaitForClockLow() { | |
bool clockIsHigh = digitalRead(CLOCK) == HIGH; | |
while (clockIsHigh) { | |
clockIsHigh = digitalRead(CLOCK) == HIGH; // wait for clock to go low. | |
} | |
Clock_status = "LOW"; | |
RWB_status = digitalRead(RWB); | |
VPB_status = digitalRead(VPB); | |
SYNC_status = digitalRead(SYNC); | |
address = ReadAddressLines(); | |
// do not read data here! | |
} | |
void WaitForClockHigh() { | |
bool clockIsHigh = digitalRead(CLOCK) == HIGH; | |
while (!clockIsHigh) { | |
clockIsHigh = digitalRead(CLOCK) == HIGH; // wait for clock to go high. | |
} | |
Clock_status = "HIGH"; | |
RWB_status = digitalRead(RWB); | |
VPB_status = digitalRead(VPB); | |
SYNC_status = digitalRead(SYNC); | |
address = ReadAddressLines(); | |
// do not read data here! | |
} | |
void WriteDataLines(uint8_t somedata) { | |
DDRA = B11111111; // all write | |
PORTA = somedata; | |
data = somedata; | |
// digitalWrite(D0, bitRead(somedata, 0)); | |
// digitalWrite(D1, bitRead(somedata, 1)); | |
// digitalWrite(D2, bitRead(somedata, 2)); | |
// digitalWrite(D3, bitRead(somedata, 3)); | |
// digitalWrite(D4, bitRead(somedata, 4)); | |
// digitalWrite(D5, bitRead(somedata, 5)); | |
// digitalWrite(D6, bitRead(somedata, 6)); | |
// digitalWrite(D7, bitRead(somedata, 7)); | |
} | |
uint8_t ReadDataLines() { | |
DDRA = B00000000; //all input | |
//SetDataPinsToInput(); | |
uint8_t byteread = PINA; | |
data = byteread; | |
return byteread; | |
// uint8_t byteread = 0x00; | |
// bitWrite(byteread, 0, digitalRead(D0)); | |
// bitWrite(byteread, 1, digitalRead(D1)); | |
// bitWrite(byteread, 2, digitalRead(D2)); | |
// bitWrite(byteread, 3, digitalRead(D3)); | |
// bitWrite(byteread, 4, digitalRead(D4)); | |
// bitWrite(byteread, 5, digitalRead(D5)); | |
// bitWrite(byteread, 6, digitalRead(D6)); | |
// bitWrite(byteread, 7, digitalRead(D7)); | |
// return byteread; | |
} | |
uint16_t ReadAddressLines() { | |
uint16_t addressread = PINB | (PINC << 8); | |
return addressread; | |
// uint16_t addressread = 0x0000; | |
// bitWrite(addressread, 0, digitalRead(Ad0)); | |
// bitWrite(addressread, 1, digitalRead(Ad1)); | |
// bitWrite(addressread, 2, digitalRead(Ad2)); | |
// bitWrite(addressread, 3, digitalRead(Ad3)); | |
// bitWrite(addressread, 4, digitalRead(Ad4)); | |
// bitWrite(addressread, 5, digitalRead(Ad5)); | |
// bitWrite(addressread, 6, digitalRead(Ad6)); | |
// bitWrite(addressread, 7, digitalRead(Ad7)); | |
// bitWrite(addressread, 8, digitalRead(Ad8)); | |
// bitWrite(addressread, 9, digitalRead(Ad9)); | |
// bitWrite(addressread, 10, digitalRead(AdA)); | |
// bitWrite(addressread, 11, digitalRead(AdB)); | |
// bitWrite(addressread, 12, digitalRead(AdC)); | |
// bitWrite(addressread, 13, digitalRead(AdD)); | |
// bitWrite(addressread, 14, digitalRead(AdE)); | |
// bitWrite(addressread, 15, digitalRead(AdF)); | |
// return addressread; | |
} | |
void SetAddressPinsToInput() { | |
DDRB = B00000000; | |
DDRC = B00000000; | |
// pinMode(Ad0, INPUT); | |
// pinMode(Ad1, INPUT); | |
// pinMode(Ad2, INPUT); | |
// pinMode(Ad3, INPUT); | |
// pinMode(Ad4, INPUT); | |
// pinMode(Ad5, INPUT); | |
// pinMode(Ad6, INPUT); | |
// pinMode(Ad7, INPUT); | |
// pinMode(Ad8, INPUT); | |
// pinMode(Ad9, INPUT); | |
// pinMode(AdA, INPUT); | |
// pinMode(AdB, INPUT); | |
// pinMode(AdC, INPUT); | |
// pinMode(AdD, INPUT); | |
// pinMode(AdE, INPUT); | |
// pinMode(AdF, INPUT); | |
} | |
void SetDataPinsToInput() { | |
DDRA = B00000000; | |
// pinMode(D0, INPUT); | |
// pinMode(D1, INPUT); | |
// pinMode(D2, INPUT); | |
// pinMode(D3, INPUT); | |
// pinMode(D4, INPUT); | |
// pinMode(D5, INPUT); | |
// pinMode(D6, INPUT); | |
// pinMode(D7, INPUT); | |
} | |
void SetDataPinsToOutput() { | |
DDRA = B11111111; | |
// pinMode(D0, OUTPUT); | |
// pinMode(D1, OUTPUT); | |
// pinMode(D2, OUTPUT); | |
// pinMode(D3, OUTPUT); | |
// pinMode(D4, OUTPUT); | |
// pinMode(D5, OUTPUT); | |
// pinMode(D6, OUTPUT); | |
// pinMode(D7, OUTPUT); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment