Speeding Up Truchet Tiles on My ZX81 with Machine Code
Taking my ZX81 Truchet tiles program from BASIC to machine code for a big speed boost. Faster, smoother, and fun to watch in action.
Having finished my last Truchet tiles program in BASIC, I wondered how fast it would run in machine code. Soon afterward, I gave it a try, writing a version that runs significantly faster than the BASIC one. Let’s dive in and see how it works.
# Setting things up.
Turning Truchet into a machine language program was straightforward enough. After copying in my standard template, I stuck with the same looping concept I had originally used. The main loop of the program does just that—setting up the display locations and using the BC register as the X and Y loops.
mainloop:
ld de,(d_file) ; grab display file
inc de ; add one
ld b,12 ; height x 2
y_loop:
ld c,16 ; width x 2
x_loop:
With that done, I randomly print a tile—more on that in a bit. The rest of the X loop looks like this:
push bc ; save loop
call print_a_tile
pop bc ; restore loop
call delay
; done with x?
dec c
jp nz,x_loop
Before closing out the Y loop, I need to shift the display down a row. I could have optimized this a bit to remove the push
and pop
, but it keeps things more readable. Notice that I jump ahead 34. That’s because each tile is 2×2 and I have to move past the end-of-line return character on the first row, plus the row beneath it (33 with return).
push bc
ld bc,34 ; jump ahead
ex de,hl
add hl,bc ; to next row
ex de,hl
pop bc
; de at start of next row
; done with y?
djnz y_loop
jp mainloop ; start again!
Truchet ML, ZX81 Starting Screenshot, 2025 by Steven Reid
# Printing the tiles.
With the setup complete, now I need to print the tile. First, I have the tile patterns defined later in the program:
; Truchet tile patterns
tile_1: db $06,$00,$00,$06
tile_2: db $00,$86,$86,$00
The print_a_tile
routine uses these locations to decide which tile to print. After setting HL to point to the first tile, the program calls a simple 8-bit random number generator. I then compare the result with 127 to decide if I’ll print a different tile.
print_a_tile:
; get tile
ld hl,tile_1 ; set to 1st tile data
call rnd ; get which tile
cp 127 ; compare to 50%
jp m, print_tile ; print first tile
ld hl,tile_2 ; set to 2nd tile data
At this point, DE points at the screen location of the tile, while HL points at the tile data. This is important since I’m going to use the ldi
instruction to copy the contents at HL directly to the screen.
print_tile:
; de = display file location
; hl = tile pattern data
ld bc,33 ; next row
; print 1st row
ldi ; print 1st char
ldi ; print 2nd char
At this point, half the Truchet tile is displayed. To print the bottom half, I move the display pointer down a line. Before I do that, I save DE since it’s already pointing to the correct location for the next tile, thanks to how ldi
works. This is also why I set BC to 33 instead of 31. Here’s the code for the second row:
push de ; save display location
ex de,hl
add hl,bc ; move to print tile
ex de,hl
; print 2nd row
ldi ; print 1st char
ldi ; print 2nd char
pop de ; restore location
ret
Truchet ML, ZX81 Screenshot, 2025 by Steven Reid
# It’s so fast!
With the primary routines complete, running the program uncovered a bit of a problem. It was too fast! Odd to say on the ZX81, I know, but I needed to slow things down a bit. I added my default delay routine, along with a break check, to finish the program. The final version was still faster than the BASIC one and very pleasant to watch.
Now that it’s running smoothly, I’ve been thinking about ways to use it. With a less random routine—say, a memory pointer to ROM—I could make this into a scrolling background. That would fit nicely in a shooting or jumping game. Fun for another day.
---
Want to try it out? You can run the program, or view the code if you’d like to see how it works.