Ben Eater 6502 Update

As I mentioned in my last post, I have been working on the Ben Eater 6502 kit. I finally got the space to set up a proper workbench and have been hacking on it daily for the last week or so. This post is describing what I have done so far.

I’ve had a blast putting it together. If you aren’t very familiar with the kit/video series, you should definitely check it out.

BE 6502 Implementation

You start by building a clock module using 555 timers for oscillation and switch debouncing. This clock module allows you to set the speed of the processor when running automatically as well as to change it into single-step mode.

Once this module is complete, you move on to installing the 6502 processor and wiring up all of its connections. My breadboard is a real mess – definitely compared to the inhuman neatness of Ben’s examples! But to make things easier for me, I created a section of my breadboard to serve as a bus location. This area breaks out the 16 address pins and 8 data pins into one convenient spot where other parts of the project can tap into them.

The next step is to install a 74HC00 quad NAND gate IC. By using this gate and tieing address line 15 to it on both inputs, we invert address 15; it allows you to use it for the chip select line on the Amtel AT28C256 32k ROM chip. This signal turns the chip off when accessing the first 32k of memory but enables it when accessing the higher 32k. In addition to the kit, I bought the programmer from Ben’s website to allow me to follow along and push programs to the 6502 manually at first via opcodes and now using the vasm assembler.

In addition to the above, there is a part of the project where you wire up an Arduino mega to act as a souped-up logic analyzer – or machine monitor. This setup is invaluable in debugging. Additionally – you will see in the next paragraph or two that it has served double duty in my case when I encountered a problem.

From there we wire in another IC, the W65C22, which is a VIA (Versatile Interface Adapter) to answer to memory in the $6000 range. This IC provides two 8 bit ports that can be used to interface with Input/Output devices. Initially, I hooked up LEDs to it and used a program in the videos to make them flash and do a chaser effect. Then I hooked up the HD4470U controlled LCD unit (it came as a single package) to the VIA. Then following the instructions in the video was able to create the classic Hello, World! display on the LCD.

The next step was optimizing the Hello World program because, in assembly, each step needed to be handled manually. This meant repeating a lot of setup code for each letter to be printed as well as repeating a few setup instructions for the display unit at the beginning of the program. This verbosity made for a large program – that could be optimized with subroutines.

The only problem is that the Breadboard 6502 doesn’t yet have any ram. The 6502 uses address from $01FF to $0100 for the stack. When you jump to a subroutine, and the processor normally writes the return address to the stack – there was no memory to store it. The lack of a stack meant that the optimized program using subroutines wouldn’t work.

I attempted to, and this is where I am still stuck, install the HM62256B (32KB CMOS Static Ram) IC. This IC uses additional ports on the quad NAND gate IC is mapped to the top 16 KB of the address space. The problem is this chip didn’t work. I ran my program, monitoring it with the Arduino, and it simply wasn’t working. Either the RAM wasn’t accepting the return address and writing it to memory or wasn’t writing the correct information out to the data bus when the address for the stack pointer was accessed. Either way, it wouldn’t work at all. I double and triple checked my wiring – I think the issue is either timing-related (though this seems unlikely as it persists no matter how fast or slow, or even single step I run the clock) or the IC is bad. I did try using my EEPROM programmer to write to it – and it failed there – but I’m not sure the EEPROM programmer would have been successful with good ram either. So I have ordered a replacement IC and hope it will work when it arrives.

But not to be thwarted. I decided to press on – I had the idea that since the Arduino was monitoring both the Address and the Data Bus, I could build a temporary stack using it. And, wouldn’t you know – it worked, well sort of. I have to run the clock very slowly. But I can the optimized Hello World program working using the Arduino to emulate RAM for the stack. My C/C++ is very rusty, but here are some of the changes I made to the sketch I typed in from the videos to make this work:

I added an array for the stack to the initialization section of the code

unsigned char stack[256];

In the setup routine, I replaced the loop setting the data pins to INPUT to a call to a new subroutine I wrote to switch them from INPUT to OUTPUT and vice versa.

void setup() {
  for (int n=0; n<16; n+=1) {
    pinMode(ADDR[n], INPUT);
    
  }
  setDataPinMode(INPUT);
  pinMode(CLOCK, INPUT);
  pinMode(READ_WRITE, INPUT);
  attachInterrupt(digitalPinToInterrupt(CLOCK), onClock, RISING);
  Serial.begin(57600);
}


void setDataPinMode(int direction) {
    for (int n=0; n<8; n+=1) {
      pinMode(DATA[n], direction);
    }
}

I created a routine to write data to the Data Bus when a stack address was being accessed for read (it is noisy because I was debugging it with Serial prints):

void writeData(unsigned char stackByte) {
  int currentBit = 7;
  char output[5];
  sprintf(output, "%02x ", stackByte);
  Serial.print(output);
  while(currentBit>=0) {
     int bitValue = stackByte & 0x01;
     digitalWrite(DATA[currentBit], bitValue);
     sprintf(output,"%d", bitValue);
     Serial.print(output);
     currentBit--;
     stackByte = stackByte >> 1;
  }
  Serial.print(" ");
}

Finally, in the onClock routine, I store the data to the stack array if the processor sets the read-write pin to write and I call the above procedures when the processor wants to read the stack:

void onClock() {
  char output[15];
  bool stored = false;
  bool rwflag = false;
  setDataPinMode(INPUT);
   
  unsigned int address=0;
  for (int n=0; n<16; n += 1) {
    int bit  = digitalRead(ADDR[n]) ? 1 : 0;
    Serial.print(bit);
    address=(address << 1) + bit;
  }


  Serial.print("   ");
  byte data=0;
  for (int n=0; n<8; n += 1) {
    int bit  = digitalRead(DATA[n]) ? 1 : 0;
    Serial.print(bit);
    data = (data << 1) + bit;
  }

  rwflag = digitalRead(READ_WRITE) ;
  
  if(address>=0x0100 && address<0x0200   ) {
    if(rwflag==false) {
      sprintf(output, "%02x ", data);
      Serial.print(output);
      stack[address-0x0100]= data;
      sprintf(output, "SV=%02x ", stack[address-0x0100]);
      Serial.print(output);
      stored=1;
    } else {
      setDataPinMode(OUTPUT);
      Serial.print(" Writing Data");
      writeData(stack[address-0x100]);
    }
  }

  sprintf(output, " %04x %c %02x %c", address, rwflag ? 'r' : 'w', data, stored ? 'S' : ' '); 
  
  
  Serial.println(output);
}

Here is what it looks like on the Arduino monitor when the processor pushes something onto the stack.
BE 6502 Stack Data Save

And here is what it looks like when the processor pops a value off of the stack.
BE 6502 Stack Data Write

As I mentioned above, my C++ is pretty rusty – and most of this is just copy and paste from places I found code online. But I managed to piece together something that works – albeit painfully slowly. Hopefully, the SRAM chip is just bad, and I can replace this hack with real RAM, but it was really kind of cool to see it up and running saying Hello, World!

There is one, currently published, video I haven’t finished yet and I think there will be at least one (or maybe a few more) in the series to add some tactile switches for input (or at least that is what the schematic eludes to). So I’ll post more when I have more progress.