Following Ben Eater’s 6502 project – parts 1-3

No, this is not a post about stalking. I’ve been toying with a design for a simple 6502-based homebrew computer for a while now. I’ve built a kit and am in the middle of laying out the schematic for the first board for my own design.

So I was thrilled when Ben Eater, one of the best educators on YouTube, embarked on a multi-part series that will, we’re promised, culminate with a 6502 machine that can print ‘Hello world’ on a screen.

I’m not going to repeat what Ben says in the videos – I strongly urge you to watch them, and buy the accompanying kit if you can. The first video is here. But as I’m following along, building the computer, I thought I would add a few comments to relate my experiences.

Part 1

There was nothing particularly challenging about following along with the first video, if you pay attention to what Ben’s saying.

As you’ve probably guessed, I didn’t.

When connecting the address and data lines to an Arduino Mega, I missed the order in which Ben had linked them. In his C code for the Arduino, he creates two char arrays that contain the pin numbers, thus:

const char ADDR[] = {22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52};
const char DATA[] = {39, 41, 43, 45, 47, 49, 51, 53};

Now, in my head, I assumed that the first item in each array, with index 0, would be the least significant bit of the data or address bus – ie, ADDR[0], which is pin 22, would relate to A0 on the address bus. Nuh-uh.

It took a while before I properly heard what Ben was saying: “These are the 16 pins that I used for the address, starting with A15 which is on pin 22 going to A0 which is on pin 52.”

So, that was an unhappy hour. As soon as I got my pins in the right order, it all started working fine.

Having the pins in reverse order like this makes sense when it comes to printing the binary value of the bus using a loop. Yes, you could set up the loop index to run from 15 down to 0, but this makes it harder to build the hex value in the same loop.

I also diverted slightly from Ben’s approach in which he sets the data lines using resistors connecting to the VCC and GND rails. Instead, I used an eight-position DIP switch. The ‘off’ side of each switch is connected both to the data lines and, via a resistor network, to GND. The ‘on’ side of each switch is connected to VCC.

This was unnecessary work. In the next part, the resistors are quickly dropped and the data lines get connected to an EEPROM to get their settings. Oh well.

Part 2

I had no problems with the second video. I was pleased to find, however, how simple (if labour-intensive) it is to write 6502 machine code using Python, and also how trivially easy it is to control the 6522 Versatile Interface Adapter (VIA) chip. This gives you general-purpose I/O (GPIO) pins – two ports of eight pins each – that will be familiar to anyone who has used an Arduino or other microcontroller.

Part 3

In part three, Ben switches to using assembler, to make life a little easier.

This is where I part company with him a little. Rather than the Vasm assembler he recommends, which looks perfectly fine and wonderful, I’m using Beebasm.

I was brought up on the BBC Micro and am currently the proud owner of a BBC Master Turbo. The BBC machines were famous for having an excellent inline assembler that you could embed in Basic code, even to the point of using Basic variables in the assembler code. As well as programming for the Ben Eater machine and my own homebrew 6502, I’ll also be coding for the Beeb. It make sense, then, to use a single assembler dialect for all of them.

Beebasm runs on multiple platforms (I’m using a Mac) and both faithfully recreates the Beeb’s assembler as well as adding more bells and whistles. It can be used to create code for many 6502-based machines, not just the BBC Micro.

There are some significant differences between Vasm and Beebasm. In Vasm, for example, you specify the code origin with .org – with Beebasm it’s ORG without the full-stop (or org – Beebasm is agnostic about upper and lower case). Labels in Beebasm start with a full-stop. To create a word, you use equw rather than .word. And you include the filename you want to save to in the assembler file itself.

Here, then, is my version of the code Ben uses in the video above, adapted for Beebasm:

; Beebasm version of Ben Eater’s first assembler code for the 6502 project.
ORG $8000
.start
    lda #$ff    ; set VIA port B pins as outputs
    sta $6002

    lda #$50    ; initial value to set on I/O pins
    sta $6000   ; write to I/O pins
.loop
    ror A       ; change value in A by rotating bits to right
    sta $6000   ; write to I/O pins

    jmp loop    ; repeat

ORG $fffc
    equw start  ; write $8000 to $fffc  
    equw $0000  ; fill final two bytes of 32KB space with nulls
.end

SAVE "test.bin", start, end

Note also that Beebasm doesn’t like using the ‘implied’ version of ‘ror’. Some assemblers will assume that you mean to ‘rotate right’ the value in the accumulator if nothing is supplied after ‘ror’. But Beebasm requires you to specify the accumulator (or memory address). We’ve specified the accumulator here with ‘A’.

Assuming this is stored in a file called test.asm, this is assembled with:

beebasm -i test.asm

It outputs a file called test.bin, ready to burn to the EEPROM.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.