; Z80 TV Game startup routine - 21.03.2026, Alex J. Lowry
;
; Based on the Z80 TV Game startup routine developed by Inufuto for the Cate
; compiler.
;
; https://github.com/inufuto/Cate_examples/blob/main/z80tvg/aerial/Startup.asm
;
; This startup routine will automatically determine whether the system has an
; 8255 or Z80PIO installed, and configure the correct operating mode for
; either chip. This procedure does not cause any adverse effects on the Z80
; TV Game 2, and is 100% cross-compatible with all known Z80 TV Game
; variants that currently exist.
;
; This source code was written for the AZ80 assembler for Windows and DOS,
; and may need some modification to work with other assemblers. For
; example, many Z80 assemblers expect a colon after each address label
; declaration.
;
; You can download the AZ80 assembler here:
; https://www.retrotechnology.com/restore/az80.html
;
; Video memory locations:
;
; Byte in upper left corner: $C1E4
; Byte in upper right corner: $C1F8 ... Upper left + $14
; Byte in lower left corner: $DA62 ... Upper left + ($1E * $D1)
; Byte in lower right corner: $DA76 ... Upper left + $14 + ($1E * $D1)
;
; Number of visible byte columns: Hex 15 / Dec 21
; Number of visible scanlines: Hex D2 / Dec 210
;
; Number of visible pixel (bit) columns: Hex A8 / Dec 168
;
SysRAMStart equ $8000 ; Start of system RAM.
SysRAMEnd equ $bfff ; End of system RAM.
VRAMStart equ $c000 ; Start of video RAM.
VRAMEnd equ $dfff ; End of video RAM.
ScrStart equ $c1e4 ; First visible byte. This value can be
; readjusted to match TV offset as
; required. The value
; $c1e4 - ($1e * $10) will position the
; image at the highest possible point in
; video memory.
ScrLine equ $001e ; Length of one scanline.
JoyPort1 equ $00 ; Location of input port for player 1
; controller.
JoyPort2 equ $01 ; Location of input port for player 2
; controller. (Only on Z80 TV Game 2)
AudioPort equ $02 ; Location of audio output port.
di ; Disable interrupts.
StartClearMem
ld a, $00 ; Load blank byte into A.
ld de, SysRAMStart
ld bc, VRAMEnd ; Initialize address pointers for clearing system and
; video RAM.
StartClearMem1
ld (de), a ; Load current address with value of A.
ld a, c
cp e ; Compare low byte of BC and DE.
jr nz, StartClearMem2 ; If not equal, keep running the loop. Otherwise...
ld a, b ;
cp d ; Compare high byte of BC/DE.
jr z, StartClearMemEnd ; If equal, end loop.
StartClearMem2
ld a, $00 ; Reset A with blank byte.
inc de ; Continue to next screen address.
jr StartClearMem1 ; Loop back.
StartClearMemEnd
ld sp, SysRAMEnd + 1 ; Initialize stack pointer.
ld a, $90 ; Does this system have an 8255 or a Z80 PIO?
out ($03), a ; $90 to Port $03 - 8255 control register and PIO port.
; $02 control register.
; If this is an 8255-based system, the control register has now been properly
; set.
;
; 1 - Mode Set Flag Active (Bit 7)
; 0 - \__ Group A Mode = 0 (Bit 6)
; 0 - / (Bit 5)
; 1 - Port A = Input ($00) (Bit 4)
; 0 - Port C (Upper) = Output ($02) (Bit 3)
; 0 - Group B Mode = 0 (Bit 2)
; 0 - Port B = Output ($01) (Bit 1)
; 0 - Port C (Lower) = Output ($02) (Bit 0)
ld a, $aa ; $AA to Port $01 - 8255 unused output port and PIO
out ($01), a ; port $00 ctrl. register.
in a, ($01) ; Query for input from $01.
cp $aa ; An 8255 will return the value in its port $01
; register, while a Z80PIO will return some other
; value. Unfortunately there isn't much
; documentation on this particular functionality of
; the Z80PIO, so I don't know exactly what value it
; returns.
jr z, Test8255 ; If the returned value is not $AA, continue to the
; Z80PIO initialization routine. Otherwise, jump
; forward to a second test to make sure this is an
; 8255-based system.
StartupPIO ; Initialize Z80PIO. This code will only be run if the
; system is a Z80PIO-based Z80TVG or a Z80TVG2.
ld a, $4f ;
out ($01), a ; $4F to Port $01 - PIO control port for port $00.
ld a, $0f ;
out ($03), a ; $0F to Port $03 - PIO control port for port $00.
jr EndStartup ; Jump to the end of this startup routine.
; If this is an PIO-based system, the control register has now been properly
; set.
;
; Port $01 (control register for port $00):
; 0 - \__ Input Mode
; 1 - /
; 0 - (unused)
; 0 - (unused)
; 1 - \
; 1 - \__ Signifies that the operating
; 1 - / mode is being set
; 1 - /
;
; Port $03 (control register for port $02):
; 0 - \__ Output Mode
; 0 - /
; 0 - (unused)
; 0 - (unused)
; 1 - \
; 1 - \__ Signifies that the operating
; 1 - / mode is being set
; 1 - /
Test8255
ld a, $55 ; Send some data to Port $01.
out ($01), a ;
in a, ($01) ; Try receiving data from the same port.
cp $55 ; An 8255 will return the value in its port $01
; register, while a Z80PIO will return some other
; value. Unfortunately there isn't much
; documentation on this particular functionality of
; the Z80PIO, so I don't know exactly what value it
; returns.
jr nz, StartupPIO ; If the returned value is not $55, jump to the Z80PIO
; initialization routine. Otherwise, continue
; onward.
EndStartup
Inufuto: Developer of Cate, a multi-platform compiler that can generate software for the Z80 TV Game.
All the games he has created with it thus far have Z80 TV Game versions.
Inufuto has also designed a PCB version of the Z80 TV Game that outputs VGA video via a Raspberry Pi Pico.
Takeda Toshiya: Developer of eZ80TVGAME, a Z80 TV Game emulator for Windows.
lsluk: Developer of vdmgr, a multi-platform emulator for Windows that supports the Z80 TV Game.
RobertK: Developer of several games for the Z80 TV Game.
Last updated on Mar 23, 2026.
This page was first uploaded on Mar 23, 2026.
visitors since Dec 26, 2025.