In previous posts, I’ve covered how to read an NES controller from an RC2014 computer, and also how to use an 8×8 LED matrix. I now want to combine these and use the NES controller to move a pixel on the LED matrix.
The first thing we want to do is to draw a pixel in the top left corner of the LED matrix. To do this, I’ll use register b for the Row data and register c for the Column data. We need to set a single bit in each because we only want a single pixel lit.
ORG $9000
ROW EQU 0
COLUMN EQU 2
setup:
ld b, 0b00000001 ; Row bit for the pixel
ld c, 0b10000000 ; Column bit for the pixel
main:
.draw_pixel:
xor a ; clear a
out (COLUMN), a ; clear the columns
ld a, b ; get the current row bit
out (ROW), a ; select the row
ld a, c ; get the column data for this row
out (COLUMN), a ; output the column data
jr main ; repeat forever
END
Now that we have a pixel, we need to read the NES controller and react to movement on the joypad.
We can use Z80 rlc and rrc operations to move the single bit to the left or right in the Row and Column registers. If we reach the end of the byte, the bit will roll over to the other end of the byte.
To test which button is being pressed, we can use a bit operation. If the button isn’t being pressed, we can jump ahead to test the next button.
In our main loop, we can add the following.
UP_BTN EQU $04
DOWN_BTN EQU $05
LEFT_BTN EQU $06
RIGHT_BTN EQU $07
main:
call get_buttons ; Get NES controller button states in A
.test_left:
bit LEFT_BTN, a
jr nz, .test_right
rlc c
.test_right:
bit RIGHT_BTN, a
jr nz, .test_up
rrc c
.test_up:
bit UP_BTN, a
jr nz, .test_down
rrc b
.test_down:
bit DOWN_BTN, a
jr nz, .draw_pixel
rlc b
.draw_pixel:
We also need to include the get_buttons routine we previously wrote. This returns the buttons being pressed on the NES controller in register a.
INCLUDE "NESController.inc"
END
At the moment, this is executing far too fast, so we end up with an entire row or column being lit. We need to add a delay. We can write a very simple Z80 routine to just loop X times as a simple delay.
delay:
ld de, 50000
.delay_loop:
dec de
ld a, d
or e
jr nz, .delay_loop
ret
The final working code
Putting this all together, we end up with the following code…
; A simple program to move a pixel on an 8x8 LED matrix
; connected to the RC2014 Z80 computer.
; Robert Price - 19th October 2025
ORG $9000
ROW EQU 0
COLUMN EQU 2
UP_BTN EQU $04
DOWN_BTN EQU $05
LEFT_BTN EQU $06
RIGHT_BTN EQU $07
setup:
ld b, 0b00000001 ; Row bit for the pixel
ld c, 0b10000000 ; Column bit for the pixel
main:
call get_buttons ; Get NES controller button states in A
.test_left:
bit LEFT_BTN, a
jr nz, .test_right
rlc c
.test_right:
bit RIGHT_BTN, a
jr nz, .test_up
rrc c
.test_up:
bit UP_BTN, a
jr nz, .test_down
rrc b
.test_down:
bit DOWN_BTN, a
jr nz, .draw_pixel
rlc b
.draw_pixel:
xor a ; clear a
out (COLUMN), a ; clear the columns
ld a, b ; get the current row bit
out (ROW), a ; select the row
ld a, c ; get the column data for this row
out (COLUMN), a ; output the column data
call delay ; small delay to make movement visible
jr main ; repeat forever
delay:
ld de, 50000
.delay_loop:
dec de
ld a, d
or e
jr nz, .delay_loop
ret
INCLUDE "NESController.inc"
END
Here is a video of the code in action.