RC2025 – Part 6 – Using an 8×8 LED matrix from Z80 assembly language

A smiley face drawn on an LED matrix using an RC2014 computer

As part of the 2025 RetroChallenge I’ve been developing an NES controller module for the RC2014 computer.

Up until now, I’ve just been outputting to a terminal. However, I’d like to use something a bit more visual on the RC2014. I’ve decided to use Peacock Media’s 8×8 LED matrix module for this.

The module works by outputting an 8-bit value to one IO port for the row and another 8-bit value to another IO port for the column. These describe which LEDs should be enabled. Each bit in the byte refers to either a row or a column.

The default IO port for the row is 0, and the default IO port for the column is 2.

If I want the top left corner to light, I need to set bit 8 of the column and bit 1 of the row.

If you have the SCM (Small Computer Monitor) program running on an RC2014, you can quickly test it out using the following.

o 0 1
o 2 80

This sets the row to hexadecimal 1, which in binary is 00000001, and the column to hexadecimal 80 which in binary is 1000000.

A smiley face in BASIC

In the documentation for the 8×8 module, Shelia Dixon gives us an example BASIC program to draw a smiley face.

This works by rapidly updating the pixels rather than keeping them permanently on. Repeated fast enough, persistence of vision makes the LEDs appear to be on constantly.

10 FOR I=0 TO 7
20 READ R,C
30 OUT 2,0 : OUT 0,R : OUT 2,C
40 NEXT I
50 RESTORE
60 GOTO 10
1000 DATA 1,60, 2,66, 4,169, 8,169
1010 DATA 16,133, 32,185, 64,66, 128,60

A smiley face in Z80 assembly language

I wanted to convert the BASIC program to Z80 assembly language to help me better understand how this works.

I take a similar approach to the BASIC program. I iterate over a loop 8 times to represent the current Row. I keep this counter in register b. In register c, I keep the current bit the row is pointing to. In each iteration, I read a byte of data from memory that represents the Column. The position in memory is pointed to by register pair hl. Once the data has been output, I then shift the value in register c to the right so it points to the next row.

The final code looks like this.


; A simple program to display a smiley face on an 8x8 LED matrix
; connected to the RC2014 Z80 computer.
; Robert Price - 19th October 2025
;
; Based on the original BASIC example by Shiela Dixon
        ORG $9000

ROW     EQU 0
COLUMN  EQU 2

main:
        ld b, 8           ; 8 rows to display
        ld c, 0b10000000  ; start with bit 7 set for row 8
        ld hl, data       ; point to the smiley data
.loop:
        xor a             ; clear a
        out (COLUMN), a   ; clear the columns
        ld a, c           ; get the current row bit
        out (ROW), a      ; select the row
        ld a, (hl)        ; get the column data for this row
        out (COLUMN), a   ; output the column data
        inc hl            ; point to next row data
        srl c             ; shift to next row bit
        djnz .loop        ; loop for all 8 rows        

        jr main           ; repeat forever

data:
        db 0b00111100     ; 60
        db 0b01000010     ; 66
        db 0b10111001     ; 185
        db 0b10000101     ; 133
        db 0b10101001     ; 169
        db 0b10101001     ; 169
        db 0b01000010     ; 66  
        db 0b00111100     ; 60

        END