Rear Gunner XL – Part 1 – Getting started

The development environment for doing ZX81 games is the same as for the Spectrum, just that you need a ZX81 emulator to see the results on.  You can still use whatever text-editor/project solution you are used to, and the same assembler – it’s just Z80 again after all.  For the emulator I’d recommend using either EightyOne – which is very accurate – or No$ZX81 – which is much faster to boot, but not quite as exact.  I personally use No$ZX81 for day-to-day development & testing, given it’s quick turnaround, and EightyOne for final testing.

There are two things however that we need to sort out before we start converting the game.  Luckily both of these have already been solved by some intelligent people way before I came onto the scene, by the use of two ‘template’ files.  I can take no credit for either of the files, but they both do their jobs very well, so I’ve very grateful to the original authors.

The first bridge to cross is the fact that the ZX81 doesn’t use ASCII, but Sinclair’s own made-up character set instead.  Because of this, if you try to use ASCII strings in your game – such as to print ‘Hello World’, then it won’t show what you expect, as if you compile it as a string it’ll be an ASCII string, not a ZX81 string.  So the following code, which would be fine on the Speccy, won’t work on the ZX81:

defb 'Hello World!', 0

There are two solutions to this.  The first is to write a convertor to take an ASCII string and convert it to a ZX81 string, by using a macro.  The second is to use a series of defines for each letter to allow you to specify the string as the ZX81 expects it, such as:

defb _H, _E, _L, _L, _O, __, _W, _O, _R, _L, _D, 0

Although this second method seems more long-winded than the first, it’s actually the one I use, because there are so few characters in ZX81 set, and so many in ASCII, that it’s easy to make a mistake, and it also allows for custom defines to be added for all the various graphics characters.  Perhaps if I wrote text-heavy games like adventures I might think differently, but for most of my games I tend to keep text at a minimum.

So here is a file – template_charcode.z80 – which does just that:

; A useful reference
;
; ____0___1___2___3___4___5___6___7___8___9___A___B___C__D_E_F_
; 00 SPC GRA GRA GRA GRA GRA GRA GRA GRA GRA GRA  "  GBP $ : ? 0F
; 10  (   )   >   <   =   +   -   *   /   ;   ,   .   0  1 2 3 1F
; 20  4   5   6   7   8   9   A   B   C   D   E   F   G  H I J 2F
; 30  K   L   M   N   O   P   Q   R   S   T   U   V   W  X Y Z 3F

__ EQU $00
_QT EQU $0B
_CO EQU $0E
_QU EQU $0F
_CL EQU $0e
_OB EQU $10
_CB EQU $11
_GT EQU $12
_LT EQU $13
_ADD EQU $15
_SUB EQU $16
_ST EQU $17
_FS EQU $18
_SCL EQU $19
_CM EQU $1a
_DT EQU $1b
_0 EQU $1c
_1 EQU $1d
_2 EQU $1e
_3 EQU $1f
_4 EQU $20
_5 EQU $21
_6 EQU $22
_7 EQU $23
_8 EQU $24
_9 EQU $25
_A EQU $26
_B EQU $27
_C EQU $28
_D EQU $29
_E EQU $2a
_F EQU $2b
_G EQU $2c
_H EQU $2d
_I EQU $2e
_J EQU $2f
_K EQU $30
_L EQU $31
_M EQU $32
_N EQU $33
_O EQU $34
_P EQU $35
_Q EQU $36
_R EQU $37
_S EQU $38
_T EQU $39
_U EQU $3a
_V EQU $3b
_W EQU $3c
_X EQU $3d
_Y EQU $3e
_Z EQU $3f

The other thing of note in getting setup is that the emulator image we need to produce for the ZX81 is different to that of the Spectrum.  With the Spectrum we get the assembler to produce a BASIC program which loads our game code, and then run it.  On the ZX81 however there’s just a single file (usually seen with a .P extension), which overwrites the entire RAM of the machine – the BASIC listing, any machine code, the display file, system setup, everything.  The easiest way of getting machine code into this single file is to actually embed it within the BASIC itself.  Luckily there’s a really good template file for this too – template_main.z80:

INCLUDE ".\template_charcode.z80"

; if you want the program to autorun, leave these as-is.
; if you don't, comment out the 1st line and uncomment the second.
AUTORUN EQU line1
;AUTORUN EQU dfile

; SYSVARS which aren't saved
ERR_NR EQU $4000
FLAGS EQU $4001
ERR_SP EQU $4002
RAMTOP EQU $4004
MODE EQU $4006
PPC EQU $4007

ORG $4009

; SYSVARS which are. This is the start of the .P
VERSN: DEFB 0
E_PPC: DEFW 0
D_FILE: DEFW dfile
DF_CC: DEFW dfile+1
VARS: DEFW vars
DEST: DEFW 0
E_LINE: DEFW vars+1
CH_ADD: DEFW last-1
X_PTR: DEFW 0
STKBOT: DEFW last
STKEND: DEFW last
BERG: DEFB 0
MEM: DEFW MEMBOT
DEFB 0
DF_SZ: DEFB 2
S_TOP: DEFW 1
LAST_K: DEFB $FF, $FF, $FF
MARGIN: DEFB 55
NXTLIN: DEFW AUTORUN ; #define this in your main asm file; use 'line0', etc. 'dfile' if no autorun.
OLDPPC: DEFW 0
FLAGX: DEFB 0
STRLEN: DEFW 0
T_ADDR: DEFW $0C8D
SEED: DEFW 0
FRAMES: DEFW $FFFF
COORDS: DEFB 0, 0
PR_CC: DEFB $B
CS_POSN: DEFB 33, 24
CDFLAG: DEFB %01000000
PRTBUF: DEFS 33
MEMBOT: DEFS 30      ; calculator's scratch 
DEFS 2

; some useful ROM routines
RESET EQU $0000
SLOWFAST EQU $0207
SETFAST EQU $02E7
NEXTLINE EQU $0676
DECODEKEY EQU $07bd
PRINTAT EQU $08f5
MAKEROOM EQU $099e
CLS EQU $0a2a
STACK2BC EQU $0bf5
STACK2A EQU $0c02
CLASS6 EQU $0d92
FINDINT EQU $0ea7
FAST EQU $0f23
SLOW EQU $0f2b
DEBOUNCE EQU $0f4b
SETMIN EQU $14BC

;= First BASIC line, asm code ==================================
line0:
 DEFB $00, $01 ; line number 
 DEFW line1-$-2 ; line length
 DEFB $ea ; REM
 DEFB $7e ; m/c for ld a,(hl),  BASIC token for 'next 5 bytes are fp number'
 jp start ; this instruction and all following will be hidden. All you see is the REM...
 DEFB 0, 0 ; ... what a neat trick - thanks Math123!
 DEFB $76 ; end of line

; Program code.
start:
 INCLUDE "main.z80"

 ; return to basic - resumes program execution at next line
 jp    NEXTLINE

;= Second BASIC line, calls ASM ==================================
line1:
 DEFB 0, 2                         ; line number
 DEFW dfile-$-2                   ; line length 
 DEFB $f9, $d4, $c5                 ; RAND USR VAL 
 DEFB _QT,_1,_6,_5,_2,_1,_QT ; "16521"
 DEFB $76 ; N/L

dfile: 
;- Display file --------------------------------------------
 DEFB $76 ; Initial N/L.
 REPT 24 ; 32 spaces to make an expanded line. 
  REPT 32 
   DEFB __ 
  ENDM 
  DEFB $76 ; N/L to next line.
 ENDM

;- BASIC-Variables ----------------------------------------
 vars: DEFB $80
;- End of program area ----------------------------
 last:

With this, you place your code in a main.z80 file and compile template_main.z80 to produce the .P image file.  The code is compiled and placed into line #0 of the BASIC listing, and when the .P file is loaded it automatically starts running the BASIC from line #1 – which immediately runs our code from line #0.  You’ll see that file also has some defines for useful ROM routines, should you need them.

You’ll notice at the end of that main template a section labelled ‘Display file‘.  This is the ZX81’s screen memory, and the template initialises it as 24 rows of 32 columns of spaces – so an blank screen.  This might seem strange at first – the Spectrum automatically has this – but it’s actually a crafty memory-saving trick.  The original ZX81 had 1K – 1024 bytes – of memory, and a screen is 24 * 32 characters, which consumes 768 bytes – and so doesn’t leave much room for anything else at all!  (Just try writing a BASIC program to fill every character on the screen on a 1K machine and it’ll run out of memory before it gets to the bottom). So the trick used is to give each row a ‘newline’ character – $76 – at the end, and if you don’t want all 32 characters in a row you simply only have as many as you need before that newline.  So a blank screen can actually be stored only 24 bytes – 24 newline characters.  As we are working towards a game it’s best to focus on a 16K minimum, and so be able to use a full-size screen, which the template code allocates and has setup ready for use.

Another trick of having this display file in the code is that we can put whatever we want it in – think of it like an instant loading screen!  Okay, so you won’t actually be able to see it until the game has loaded, but if the first thing your game does is wait then it’ll be immediately visible for all to see.  (I did this in a few game, Boulder Logic for example)

And that’s all the setup we have to do.  Whatever we now put in our main.z80 file is down to us and what we want our game to do.

Now where did I put that BASIC manual…?

 

P.S. This is a WordPress blog, and it appears to have Z80 gremlins which keep removing the underscore ‘_’ character from random points in my listings.  Shout if you see them!

Advertisements

2 thoughts on “Rear Gunner XL – Part 1 – Getting started

  1. I found ZX-IDE (https://www.sinclairzxworld.com/viewtopic.php?f=6&t=1064) as the easiest and fastest way to code and test ZX81 programs. It even allows you to directly write BASIC within your source assembly file. For instance, here is an example of the ‘WAIT FOR ANY KEY’ program that you published, with a small BASIC program to test it:
    1 REM _asm
    wfk: ld a,0
    in a,(254)
    cpl
    and %00011111
    jp z, wfk
    ret
    END _asm
    20 PRINT “PRESS A KEY”
    30 RAND USR #wfk
    40 PRINT “KEY PRESSED”

    My 2 cents. Bruno.

    Liked by 1 person

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s