Table of Contents
Tutorial Progress
A record of my progress through the Ben Eater You Tube tutorial
Day One : Tuesday 16/8/22
- Kit arrived
- Installed:
- CPU
- EEPROM
- NAND Gate
- Address & Data lines between CPU and EEPROM and address decoder for EEPROM
- Used python “makerom.py” script to burn eprom:
rom = bytearray([0xea] * 32768 ) rom[0] = 0xa9 rom[1] = 0x42 rom[2] = 0x8d rom[3] = 0x00 rom[4] = 0x60 rom[0x7ffc] = 0x00 rom[0x7ffd] = 0x80 with open("rom.bin", "wb") as out_file: out_file.write(rom)
ROM file hexdump:
00000000 a9 42 8d 00 60 ea ea ea ea ea ea ea ea ea ea ea |.B..`...........| 00000010 ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea |................| * 00007ff
- Unable to confirm correct running - still waiting for Arduino Mega to act as a logic analyzer. LEDs on data or Address lines show activity….
Next stage
- add the 65C22 VIA and use LEDs on output to show correct running
- make an 8-bit binary counter with LEDs as an exercise
Day Two : Wednesday 17/8/22
Using Siglent Function Generator as the CPU PHI2 clock
- added 65C22 VIA and 8 leds
- much debugging of hardware/wiring - breadboard is a NASTY way of doing this…..!
- ordered some IC sockets & other hardware to allow me to build a version on Vero/perf board and move away from breadboard once I've got the the point in the tutorials where all the hardware is stable.
- used python script to get the “01010101 → 10101010” LED sequence running.
Self-study
- modified assembly code to make the LEDs flash in a binary count
8 bit counter
### 8-bit Counter code = bytearray([ 0xa9, 0xff, # lda #$FF 0x8d, 0x02, 0x60, # sta $6002 : put 11111111 into VIA's Port B control register - all port pins are OUTPUT 0xa9, 0xff, # lda #$ff (start with all LEDs lit) 0x8d, 0x00, 0x60, # sta $6000 0x1a, # inc A 0x4c, 0x07, 0x80, # jmp $8007 ]) rom = code + bytearray([0xea] * (32768 - len(code))) rom[0x7ffc] = 0x00 rom[0x7ffd] = 0x80 with open("rom.bin", "wb") as out_file: out_file.write(rom);
This assembles as :
00000000 a9 ff 8d 02 60 a9 ff 8d 00 60 1a 4c 07 80 ea ea |....`....`.L....| 00000010 ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea |................| * 00007ff0 ea ea ea ea ea ea ea ea ea ea ea ea 00 80 ea ea |................| 00008000
LEDs flash in binary count to 255 and cycle round… endlessly.
16 bit counter
I wanted to see if I could extend the counter to 16-bits, using 2 VIA ports to drive the LEDs
To make life easier I moved to assembly
language and the VASM
assembler as recommended in the tutorial.
To count beyond a single 8-bit byte needs a way of holding 2 separate bytes of the count, the low byte and high byte, and only increment the high byte when the low byte rolls past 11111111
. Tricky with no RAM installed yet.
I used the 2 index registers X
and Y
. The carry bit is set as a result of arithmetic on the Accumulator register, so X
(low byte) has to be copied to the Accumulator for the addition of 1
each time round the loop.
.org $8000 reset: lda #$ff sta $6002 ; set port B pins to all output sta $6003 ; set port A pins to all output lda #$00 tax ; X holds the low byte. initialize to zero tay ; Y holds the high byte. initialize to zero loop: txa ; copy low byte to A adc #$01 ; add 1 tax ; copy new value to X bcs high_b ; if carry flag set, branch to increment the high byte print: txa ; bring the low byte to A sta $6000 ; send low byte to Port B LEDs tya ; bring the high byte to A sta $6001 ; send high byte to Port A LEDs jmp loop high_b: iny ; increment high byte in Y jmp print .org $fffc .word reset .word $0000
Assembled code
00000000 a9 ff 8d 02 60 8d 03 60 a9 00 aa a8 8a 69 01 aa |....`..`.....i..| 00000010 b0 0b 8a 8d 00 60 98 8d 01 60 4c 0c 80 c8 4c 12 |.....`...`L...L.| 00000020 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00007ff0 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 |................| 00008000
Add another 8 LEDs, to Port A, to show the High Byte….
It now counts to 1111111111111111
or $FFFF
or 65535
as displayed by the LEDs attached to both VIA ports.
Next stage
is to add the LCD module in place of the flashing LEDs
Day Three : Friday 19/8/22
LCD
- added the LCD module to the VIA output port(s)
- put the “hello.s” assembled code into ROM
- LCD printed
Hello, w
and no more….
8 Characters… what, why?
Lots of messing about with the assembler code to see if I could get all the Hello, world!
message to print to the LCD.
By adding the necessary instruction to change the display position I could use all 16 characters of the display, but I couldn't get it to print all the message in one go…. The same happened with a different LCD module.
Eventually I checked, and re-checked, the address and data lines between CPU, ROM and VIA and must have re-inserted one that was loose. Afterwards the display showed Hello, world!
correctly.
I assume the error was that an address line between CPU and ROM wasn't connected, so at one step of the program the ROM went to the wrong address and returned garbage data, and the program stopped, or just randomly stepped through the otherwise empty ROM?
Anyway, whatever the mechanism, ensuring all address & data lines were seated correctly cured the bug.
Next Stage
- adding RAM
- rebuilding on “properly wired” stripboard to remove the annoyance of breadboard wires coming adrift.
Day 4 : Saturday 21/8/22
- added RAM
- re-wrote “hello_world” to use 4-bit LCD addressing and moved LCD to PORTB of VIA, freeing up all of PORTA for other uses
- began building veroboard version to
Day 5 : Sunday 22/8/22
- completed veroboard build and tested with 4-bit/2-line LCD “Hello world”
PORTB = $6000 PORTA = $6001 DDRB = $6002 DDRA = $6003 E = %01000000 RW = %00100000 RS = %00010000 LED = %10000000 .org $8000 reset: ldx #$ff txs lda #%11111111 ; Set all pins on port B to output sta DDRB lda #%00000000 ; Set all pins on port A to input sta DDRA jsr lcd_init lda #%00101000 ; Set 4-bit mode; 2-line display; 5x8 font jsr lcd_instruction lda #%00001110 ; Display on; cursor on; blink off jsr lcd_instruction lda #%00000110 ; Increment and shift cursor; don't shift display jsr lcd_instruction lda #%00000001 ; Clear display jsr lcd_instruction ldx #0 print1: lda message1,x beq print2 jsr print_char inx jmp print1 message1: .asciiz "Shed-o-tron II " message2: .asciiz "* * 22/8/22 * * " loop: lda #LED sta PORTB jmp loop print2: lda #%10101001 jsr lcd_instruction ldx #0 line2: lda message2,x beq loop jsr print_char inx jmp line2 lcd_wait: pha lda #%11110000 ; LCD data is input sta DDRB lcdbusy: lda #RW sta PORTB lda #(RW | E) sta PORTB lda PORTB ; Read high nibble pha ; and put on stack since it has the busy flag lda #RW sta PORTB lda #(RW | E) sta PORTB lda PORTB ; Read low nibble pla ; Get high nibble off stack and #%00001000 bne lcdbusy lda #RW sta PORTB lda #%11111111 ; LCD data is output sta DDRB pla rts lcd_init: lda #%00000010 ; Set 4-bit mode sta PORTB ora #E sta PORTB and #%00001111 sta PORTB rts lcd_instruction: jsr lcd_wait pha lsr lsr lsr lsr ; Send high 4 bits sta PORTB ora #E ; Set E bit to send instruction sta PORTB eor #E ; Clear E bit sta PORTB pla and #%00001111 ; Send low 4 bits sta PORTB ora #E ; Set E bit to send instruction sta PORTB eor #E ; Clear E bit sta PORTB rts print_char: jsr lcd_wait pha lsr lsr lsr lsr ; Send high 4 bits ora #RS ; Set RS sta PORTB ora #E ; Set E bit to send instruction sta PORTB eor #E ; Clear E bit sta PORTB pla and #%00001111 ; Send low 4 bits ora #RS ; Set RS sta PORTB ora #E ; Set E bit to send instruction sta PORTB eor #E ; Clear E bit sta PORTB rts ; Reset/IRQ vectors .org $fffc .word reset .word $0000
Next Stage
- begin expanding software
- routines to examine memory contents and display (in HEX) the contents of selected memory location(s)
- add switches to VIA PORTA and begin reading state of switches and update LCD with information
- a power-on memory test and toggle LED/LCD?
Further Information
Github : https://github.com/gm4slv/6502