Writing up a custom clock for the Nintendo E-Reader
I am building a Nonogram game (aka Picross) for the Nintendo GBA E-Reader. Nonograms traditionally have a 30 minute time limit. The E-Reader's built in ERAPI has a clock, but it maxes out at about 18 minutes. So I had no choice but to write my own. It was very simple actually. But I figured I'd blog about it as an example of what it is like to write games in z80 assembly for the E-Reader and using ERAPI.

ERAPI's DrawTime
ERAPI has ERAPI_DrawTime
, ERAPI_DrawTimeNewValue
and ERAPI_DrawTimeDeltaValue
to draw times to the screen. These functions are easy to use and take up almost no precious space to use them.
To use them, first you establish a time struct. It is a collection of values that inform the DrawTime
functions where and how to draw the time.
time_struct: .db 0 ; bg # .db 0 ; palette # .db 10 ; x in tiles .db 8 ; y in tiles .dw 4107 ; system sprite ; to use as the font .db 11 ; separator ; 10=. ; 11=: ; 12=/ ; 13=- .db 1 ; format ; 0=mm:ss:ff ; 1=mm:ss ; 2=mmss ; 3=mm ; 4=mm:ss ; 5=mm, 6=mm .dw 65000 ; starting value .db 0 ; loaded sprite?
.db
means "place a byte here" and .dw
means "place a word here", which is a two byte value. So this struct in C would look like
struct TimeStruct { uint8 backgroundIndex; uint8 paletteIndex; uint8 x; uint8 y; uint16 spriteId; uint8 separator; uint8 format; uint16 startingValue; uint8 loadedSprite };
I don't know what the loaded sprite
byte is for, I've not investigated it yet. Everything else is pretty self explanatory. For the system sprite, that is the "font". You can see them all here. Turn off pokemon and other to just see the number fonts.

To draw a time to the screen, call ERAPI_DrawTime
and give it your time struct.
ld hl, time_struct rst 0.db ERAPI_DrawTime
;; force a screen refresh so the time gets drawn right away ld a, 1halt
Then the time will show up as expected.

The value
word is what the time is in system frames. There are about 60 frames per second on the GBA, so if you set this value to 60
, the clock will show 00:01
. This is a two byte value, so the maximum number it can accept is 65535
. Hmmmm... what is that in seconds? It is 1092 seconds, so the max time the ERAPI clock can show is 18:12
. Once it goes to 18:13
, the clock rolls over to zero and starts over.
Changing the time
The other functions are used to change the time as the game progresses. ERAPI_DrawTimeNewValue
will set an entirely new time value.
;; our new time value ld de, 12345ld hl, time_struct .db ERAPI_DrawTimeNewValue
This is exactly the same as ERAPI_DrawTime
, except it is taking the time value from de
instead of the time_struct.
And ERAPI_DrawTimeDeltaValue
adds the new value onto the current one. Typically you call this every frame to have the clock either count up or down, to act as a timer.
;; the delta value ld de, 1ld hl, time_struct .db ERAPI_DrawTimeDeltaValue
But that max time though
As we discussed above, the maximum time the ERAPI clock can show is 18 minutes and 12 seconds. A Nonogram game traditionally gives you 30 minutes to solve a puzzle. What to do?
One approach is to use the ERAPI clock twice. Set it to 15 minutes and also set up two tokens somewhere. Once the 15 minutes counts down, take away a token, and restart the clock again at 15 minutes. Once that 15 minutes elapses, take away the second token and now it's game over. Sure, this would work, but wow it's clunky.
I decided to take the space hit and implement my own clock.
Making a clock from scratch
Fortunately ERAPI still has other functions available that allow us to make our clock with ease. The ERAPI_DrawNumber*
functions are similar to the DrawTime
functions, but just draw straight numbers to the screen. Also there is ERAPI_Div
for division, and ERAPI_Mod
for performing a modulus (which is dividing two numbers and just keeping the remainder).
The overall gameplan is this, first in JavaScript for simplicity.
let frameCounter = 0;// start the clock/timer at 30 minutes let secondCounter = 30 * 60;
const minutesNumberStruct = { backgroundIndex: 0, paletteIndex: 14, x: 10, y: 4, systemSprite: 4149, numberOfDigits: 2, numberOfExtraDigits: 0, // pad out numbers with zeroes // so say 9 gets shown as 09 fillWith: 0, loadedSprite: 0, value: 30,};
const secondsNumberStruct = { backgroundIndex: 0, paletteIndex: 14, x: 13, y: 4, systemSprite: 4149, numberOfDigits: 2, numberOfExtraDigits: 0, // pad out numbers with zeroes // so say 9 gets shown as 09 fillWith: 0, loadedSprite: 0, value: 30,};
// called once at the start of the game function clockInit() { // get our numbers loaded into ERAPI // and up onto the screen ERAPI_DrawNumber(minutesNumberStruct); ERAPI_DrawNumber(secondsNumberStruct);}
function clockFrame() { frameCounter += 1;
if (frameCounter === 60) { // a second has elapsed frameCounter = 0; secondCounter -= 1; }
const minutes = secondsCounter / 60; ERAPI_DrawNumberNewValue(minutesNumberStruct, minutes ); const seconds = secondsCounter % 60; ERAPI_DrawNumberNewValue(secondsNumberStruct, seconds );}
There's a lot of code related to setup. The number structs are very similar to the time structs. But actually working out the clock and drawing its current value to the screen is quite simple.
And here it is an z80 assembly.
CL_MINUTES_X_TILE = 9CL_MINUTES_Y_TILE = 1CL_SECONDS_X_TILE = 12CL_SECONDS_Y_TILE = 1
clock_init: ;; init the number drawing ld hl, _cl_minutes_number rst 0 .db ERAPI_DrawNumber
ld hl, _cl_seconds_number rst 0 .db ERAPI_DrawNumber
ret
clock_frame: ;; increment the frame counter ld a, (_cl_frame_counter) inc a ;; did it just hit 60 frames, ie one second? cp 60 ;; if no, skip down below jr nz, clock_frame__skip_reset_frame_counter ;; we've counted an entire second, reset frame counter ld a, 0 ;; and decrement seconds ld hl, (_cl_seconds_counter) dec hl ld (_cl_seconds_counter), hl
clock_frame__skip_reset_frame_counter: ;; save the new value for the frame counter ld (_cl_frame_counter), a
;; now draw the current time to the screen call _cl_render
ret
_cl_render: ;; draw minutes ld hl, (_cl_seconds_counter) ld de, 60 ;; hl = hl/de rst 8 .db ERAPI_Div ;; hl is now secondsCounter / 60 ;; which is the current minutes
;; move number to de, where DrawNumberNewValue needs it push hl pop de ld hl, _cl_minutes_number ;; draw the new minutes value to the screen rst 0 .db ERAPI_DrawNumberNewValue
;; draw seconds ld hl, (_cl_seconds_counter) ld de, 60 ;; hl = hl%de rst 8 .db ERAPI_Mod ;; hl is now secondsCounter % 60 ;; which is the current seconds
;; move number to de, where DrawNumberNewValue needs it push hl pop de ld hl, _cl_seconds_number ;; draw the new seconds value to the screen rst 0 .db ERAPI_DrawNumberNewValue
ret
_cl_seconds_counter: ;; 30 minutes .dw 30 * 60_cl_frame_counter: .db 0
_cl_minutes_number: .db 0 ; background index .db 14 ; palette # .db CL_MINUTES_X_TILE ; x in tiles .db CL_MINUTES_Y_TILE ; y in tiles .dw 4149 ; system sprite to use as the font .db 2 ; number of digits .db 0 ; number of extra zeroes on right .db 1 ; 0 fill with spaces, 1 fill with zeroes .db 0 ; loaded sprite? .dw 0 ; value
_cl_seconds_number: .db 0 ; background index .db 14 ; palette # .db CL_SECONDS_X_TILE ; x in tiles .db CL_SECONDS_Y_TILE ; y in tiles .dw 4149 ; system sprite to use as the font .db 2 ; number of digits .db 0 ; number of extra zeroes on right .db 1 ; 0 fill with spaces, 1 fill with zeroes .db 0 ; loaded sprite? .dw 0 ; value
If you're not familiar with z80 assembly, that is a lot to take in. It's pretty much identical to the JavaScript version. If you take it line by line and compare it to the JavaScript version, it will hopefully become clear.
In action
And here is the final result
Don't forget this game has a long ways to go. The final version will look very different.
The colon separator
The code above doesn't add the colon that goes between the minutes and seconds. That is just a simple sprite. If we could use ERAPI_DrawTime
, it'd handle the colon for us. But since we are using ERAPI_DrawNumber
instead, the colon is up to us. If wanted, you could also use ERAPI_SpriteAutoAnimate
to show the colon blinking once per second. I decided not to do that as it was a little distracting.
How much space does it use?
The nice thing about ERAPI_DrawTime
is it takes up hardly any space at all in your game. An ERAPI function call is just a handful of bytes and each time struct is 11 bytes.
My clock implementation is currently 174 bytes, plus the bytes needed to call it. That doesn't sound like much, but for an E-Reader game that is positively massive. I can probably trim the size down through some optimizations. But make no doubt, this custom clock is an expensive feature. But I feel like it is necessary, nonograms without a 30 minute timer just wouldn't be right.
Conclusion
Hopefully this blog post gave you a little taste of what writing z80 assembly for an E-Reader game is like. One day I will write up real tutorials on how to make an E-Reader game. But that won't be for a while.
If you like the E-Reader, check out https://retrodotcards.com or follow me on Bluesky.