Hello World on the 65c02
18 Jan 2026TL;DR. Check wiring before blaming software.
After completing the build of my 8-bit computer based on Ben Eater’s kits, I have now started work on his 65c02 project.
I ran into some issue with the Arduino Mega, but decided to skip that bit for now. Instead, I went on to build the entire thing and proceeded with loading Wozmon on it directly.
To absolutely nobody’s surprise, that didn’t work. So; back to taking a more incremental approach.
Step 1: I built the module with the 65C02, the ROM chip and the versatile
input/output adapter. Then, I customized Ben’s sample
blink.s program to make it into a nice
Cylon (or Knight
Rider’s
KITT) woosh. That worked! In case you’re
interested, that bruteforce code is below. I named the file myblink.s.
Step 2: The next step was to connect up the display module and see if
that worked with Ben’s
hello-world.s program. No
issue!
Step 3: Now on a roll, it was time to hook up the RAM and run
hello-world.s again. Bingo! That worked. Next, let’s run
hello-world-final.s.
And for sure, that did NOT work.
Step 4: Of course, rather than second-guessing my own build, as any good software engineer, I blamed the failure to run on somebody else faulty code.
All I needed to do was write a short test program to demonstrate that I was right. So, I decided to do just that.
Basically, I took the first four low bits of PORTA and hooked up LEDs to them. The first two bits were toggled by writing directly to PORTA. The second two used three subroutines to toggle the next two pins. That way, I can see that the program is running, and since we already demonstrated that it was fine without needing a stack, it was a good control.
Clearly, this didn’t work either. The first two LEDs toggled just fine, but the last two didn’t. Commenting out the subroutine calls confirmed that Ben’s program was fine after all; it really must have been my build instead of Ben’s code. Who would have thought?
Anyway; after carefully checking all address lines (no issue), all data lines (no issue), and the control lines, I finally identified that my read/write pin was off-by-one on the 65C02.
Running the program again quickly demonstrated that my four LEDs now were toggling nicely.
That meant that the all component involved were working (i.e., the 65c02, the RAM, the ROM, the versatile I/O adapter, and the NAND gates.
And for sure, hello-world-final.s now also worked nicely.
Step 5: All that was left now was replacing the 555-based timer with the 1MHz crystal, and we’re all good.
Lesson learned: Start troubleshooting layer 1.
Next up: Serial interfacing!
myblink.s
.org $8000
reset:
lda #$ff
sta $6002
lda #$50
sta $6000
loop:
lda #1
ltr:
sta $6000 ; output value
cmp #128 ; if we are on the last bit
beq rev ;
asl ; shift left
jmp ltr
rev:
sta $6000
cmp #1
beq ltr
lsr
jmp rev
.org $fffc
.word reset
.word $0000
ram-test.s
PORTB = $6000
PORTA = $6001
DDRB = $6002
DDRA = $6003
.org $8000
reset:
lda #%00001111 ; set least signficant bits on port A to output
sta DDRA
loop:
; first try without using ram
lda #%00000001
sta PORTA
lda #%00000010
sta PORTA
; then try with ram
jsr pattern1
jsr output
jsr pattern2
jsr output
jmp loop
pattern1:
lda #%00000100
rts
pattern2:
lda #%00001000
rts
output:
sta PORTA
rts
.org $fffc
.word reset
.word $0000