Michael Cartwright
Published © MIT

Ben Eater 6502 - Mega as 4K RAM

By optimizing GPIO port access we can run the 6502 at full speed (using Ben's clock) and reliably simulate memory using the Ardunio Mega.

IntermediateFull instructions provided2 hours715
Ben Eater 6502 - Mega as 4K RAM

Things used in this project

Hardware components

Arduino Mega 2560
Arduino Mega 2560
×1
65C02
×1
Ben Eater Kit 1: Clock module
×1

Software apps and online services

Arduino IDE
Arduino IDE
VASM for 6502

Story

Read more

Code

Mega 2560 Memory Simulator

Arduino
4KB memory simulation for 8 bit processors running up to a "few" 100KHz.
// 4KB memory simulation for 8 bit processors running up to a "few" 100KHz.

// PORTL = Data
// PORTA = Address LSB
// PORTC = Address MSB

#define CLOCK 2
#define READ_WRITE 3

#define SERIAL_DIAGNOSTICS

unsigned char memory[0x1000]; // 4K of memory mapped to 0xF000..0xFFFF

void setup() {

#ifndef SERIAL_DIAGNOSTICS
  pinMode(LED_BUILTIN, OUTPUT);
#endif

  for (int n=0; n < 0x1000; n++)
  {
    // fill memory with something noteworthy so we can at least see when we are accessing it:
    memory[n] = 0xEA; // NOP
  }

/*

// Sample code implemented below:

    .org $F000

reset:
  lda #$00
  
loop:
  inc
  sta $F100
  ldx $F100
  jmp loop

  .org $fffc
  .word reset
  .word $0000

*/  

  // .org 0xF000
  // reset:
  memory[0x0000] = 0xA9; // LDA
  memory[0x0001] = 0x00; // #$00

  // loop:
  memory[0x0002] = 0x1A; // INC

  // storing and loading A to valid memory allows us to see it on the data bus in diagnostics
  memory[0x0003] = 0x8D; //STA
  memory[0x0004] = 0x00;
  memory[0x0005] = 0xF1;

  memory[0x0006] = 0xAE; //LDX
  memory[0x0007] = 0x00;
  memory[0x0008] = 0xF1;

  memory[0x0009] = 0x4C; // JMP loop
  memory[0x000A] = 0x02;
  memory[0x000B] = 0xF0;

  // .org 0xFFFC
  memory[0x0FFC] = 0x00; // reset
  memory[0x0FFD] = 0xF0;

  DDRL = 0x00; // Data = INPUT
  
  DDRA = 0x00; // Address = INPUT
  DDRC = 0x00; // Address = INPUT
  
  pinMode(CLOCK, INPUT);
  pinMode(READ_WRITE, INPUT);

  attachInterrupt(digitalPinToInterrupt(CLOCK), onClock, RISING);
#ifdef SERIAL_DIAGNOSTICS  
  Serial.begin(115200);
#endif
}

void onClock() 
{
  char output[15];

  unsigned int address = PINA + (PINC << 8);
  
  //int readWrite = digitalRead(READ_WRITE);
  int readWritePin = PINE & (1<<PE5); // READ_WRITE: PIN 3 is PE5
  
  unsigned char data = 0;
  if (readWritePin)
  {
    // RWB=1=read (CPU is reading so we are writing to pins)
    DDRL = 0xFF;
    if (address >= 0xF000)
    {
      data = memory[address & 0x0FFF];
    }
    PORTL = data;
  }
  else
  {
    // RWB=0=write (CPU is writing so we are reading pins)
    DDRL = 0x00;
    if (address >= 0xF000)
    {
      data = PINL;
      memory[address & 0x0FFF] = data;
    }
  }

#ifdef SERIAL_DIAGNOSTICS
  sprintf(output, "   0x%04X 0x%02X %c", address, data, (readWritePin ? 'R' : 'W'));
  Serial.println(output);  
#endif

}

void loop() 
{
#ifndef SERIAL_DIAGNOSTICS
  // Toggle the Mega's built-in LED as a heartbeat indicator:
  if (memory[0x0100] < 0x7F)  
  {
    digitalWrite(LED_BUILTIN, LOW);
  }
  if (memory[0x0100] >= 0x7F)  
  {
    digitalWrite(LED_BUILTIN, HIGH);
  }
#endif
}

Credits

Michael Cartwright

Michael Cartwright

21 projects • 14 followers

Comments