Gamecoding in machinecode on a ZX81.

Any discussions related to the creation of new hardware or software for the ZX80 or ZX81
dr beep
Posts: 2060
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Gamecoding in machinecode on a ZX81.

Post by dr beep »

I see requests about reading the keyboard, how to move a character over the screen.
In stead off answering each question indicidually I thougth that the best way was to guide
new gamecoders through the steps of coding machinecode on a ZX81.

This course will guide you through the steps needed to code your own games in the near future.

I will guide you through:

1) How to begin
2) First program
3) Output on display
4) Input from keyboard
5) Movement
6) Scoring
7) Extra's

I will place steps in this "course" in this folder.

So the first is:

1) How to begin
dr beep
Posts: 2060
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Gamecoding in machinecode on a ZX81.

Post by dr beep »

1) How to begin

Although we are coding FOR the ZX81, we will NOT be coding ON a ZX81.

By coding on a PC we can use the storage of the PC to keep progress,
use full memory of the ZX81 without needing room for a compiler,
use a proper keyboard to type (no offence), use most of the ZX81 by using
the most optimized machinecoder there is.

Classic gamedesign on a ZX81 required a BASIC-program containing a HUGE REM line
with the program stored behind the REM, followed by a line with RAND USR nr to start the machinecode.

Although you can still use this method in modern developping tools you can also
code this BASIC-needs to start a game fully over the systemvariables. In this way you save bytes, which can come handy when coding in 1K.

When you save a program from a ZX81 the ROM will automatically save the systemvariables with your program. When we develop outside the ZX81 we need to define these systemvariables ourself in the development of the game.

My advice: when you start coding, neglect them. You don't need to know HOW they work, just accept THAT they work as needed. At the end I might explain how the ZX81 starts the code.

To start coding you need an editor to alter your program and a compiler to make a .P from your source. I have made a start in this ZIP file.
ZX81course.zip
(558.86 KiB) Downloaded 476 times
Unpack it on your PC and you will get 2 maps inside the ZX81COURSE.
The first map is GAME1, our first game we will code. When you want another game just add a folder and copy the GAME1-000.ASM and the COMPILE.BAT to the new folder.

You are now ready to program your first progam.s
dr beep
Posts: 2060
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Gamecoding in machinecode on a ZX81.

Post by dr beep »

2) First program

At this moment you have unzipped the packege and you will have installed
ZX81COURSE on your PC.

Inside this map you have 2 other maps: GAME1 and SJASM.

SJASM contains the compiler, but inside the map GAME1 is a COMPILE.BAT which is the only
part we need. So we can keep SJASM for what it is; the technical part to compile our games.

Inside GAME1 we see 2 files GAME1-000.ASM and COMPILE.BAT

GAME1-000.ASM is our source. During the development we will save progress of the game by incressing the number at the end. If we disturb the code in a way we can't repair easily we can always return to a moment we knew the game worked as wanted and begin again from that point.

You can edit the GAME-000.ASM. If your PC doesn;t recognize .ASM-files you can open the source with the right mousebuton (assuming normally you use leftmouse) and select OPEN WITH and then use NOTEPAD. You can choose any editor you like, but NOTEPAD will do fine.

Use the cursorkeys to scroll through the code.
Until the line "; DO NOT CHANGE SYSVAR ABOVE!" you have the systemvariables set.
This part is normally saved by the ZX81, but has a few alterations to AUTORUN your program.
This will be explained in the EXTRA'S but is not needed to know.

The game will start at the label GAMECODE.
This first program will JR to GAMECODE (JUMP RELATIVE) back to the start, so in an endless loop.

Under the program we have built a small screen. Just a few lines of text.
Now let us compile this programm to see what is on the screen.

Exit the editor (without saving) if you made a change.
Now place your mouse on the GAME1-000.ASM and drag the file into the COMPILE.BAT.
A black DOS-box will appear. If all goes well no errormessages appears.
Press a key to close the box. Inside your folder you will now have a .LST and a .P
extra. You can start the .P in the emulator to see the result of your FIRST PROGRAM.
dr beep
Posts: 2060
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Gamecoding in machinecode on a ZX81.

Post by dr beep »

3) Output on display.

In BASIC you can use the command PRINT to show text on the screen.
What rhe BASIC-interpreter does is displaying the text on the current position on the screen.
To display text in machinecode you can use a routine in the ROM, however the ROM is slow and
we want speed so we won't be using the ROM other than useable parts like decoding a keypress.

Even a CLS will be our own routine. On a ZX81 the screen can be compressed but when the ZX81 has over 3.5K of RAM the ROM will fully unpack the screen. By not using CLS we can use a compressed screen even in 16K.

When you write a game on the ZX81 you will automatically use the ZX81-characterset.
This characterset is different from other computers. The ZX Spectrum, C64, MSX and PC use the standard ASCII-characterset. This means that we need to translate the characters we type on our PC to display to characters that fit the ZX81. A "!" is NOT a character on the ZX81.

More info about the characterset is on wikipedia: https://en.wikipedia.org/wiki/ZX81_character_set
The ZX81 has 128 printable characters. 64 normal and 64 inverted characters.

Besides the special characters the ZX81 has an ingenious display. As mentioned earlier the screen
can be compressed. A compressed screen fills the line of the screen with blancs without storing blancs in memory. The ZX81 does this with a special linemarker at the end of eacht line; byte 118 (HALT).

When the display encounters this byte the hardware will fill the line until the next line must be displayed. The first line is always a single 118. The ZX81 screen has standard 32 columns and 24 rows WITH the linemarker.
A FULL screen is therefore 1+24x33=793 bytes. A compressed screen is only 25 bytes of 118.
A HUGE difference if you want to code in 1K.

Our game will be 20 columns with 20 rows so 1+20x21=421 bytes needed for the screen.
However you need 4 extra NEWLINES (118) to fill the screen, a total of 425 bytes.
Empty lines at the bottom can be replaced with a single "JP (HL)". So in the end we need 422 bytes
The JP (HL) trick will be explained in the EXTRA, but for no we use it.

Now let us make the screen

Edit the GAME1-000.ASM and save it as GAME1-001.ASM. You now have a version to make alterations.

Go to the dfile and erase the lines between the comments
"; each line has text and a Newline" and "; this byte fills the unused part of the screen"

Copy this part 20x into the deleted part.

Code: Select all

	block 20,128		; BLOCK places 20x character 128,inverted space
	db 118
We have our screen set, now add some display

First let us define the start of our screen.
Machinecode doesn't know linenumber but uses labels to tell us where a part of code or memory is.
We will define our screen. Set the label "screen" before the first block, like this:
screen block 20,128

This is a marker at the begin of our screen.

We want to see output to the screen, so we alter the GAMECODE JR GAMECODE in this

Code: Select all

gamecode 
	ld a,63
showa	ld (screen),a			
	dec a
	jr nz,showa
	jr gamecode
I will not explain full Z80, but I will explain how the code works. This will understand Z80 much quicker than going deep into the ins and outs of the Z80. Your knowledge will grow during the course.
In BASIC you use variables. In MC you can see registers as direct variables. So what does this program do:
You set the A register to 63, the final not inverted character displayable.
showa is the label to write the register to the screen
Then we decrease the register by 1
We test if A is NOT ZERO. If not we show the next character
If it IS zero we go back to start to begin again on 63.

Save the code and again compile. Now GAME1-001.P should appear.
Start the game and see what you altered.

Questions or errors. let me know.
dr beep
Posts: 2060
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Gamecoding in machinecode on a ZX81.

Post by dr beep »

4) Input from keyboard


Input on the ZX81 can be obtained in 2 ways.
The easiest way is to use the systemvariable stored in LASTK.
The other way is to read parts of the keyboard or joysticks.

Each 1/50 sec the screen is displayed and the keyboard is read.
The result of reading the keyboard is stored in LASTK, a 2 byte address
containing information about the key that is pressed.

For now we will test IF a key is pressed, not what key.

So again open now GAME1-001.ASM and save as GAME1-002.ASM

We want to see what is displayed. In our earlier version the display was
raging fast. We can add a check if a key is pressed, if not the program will halt.

For this I need to explain the registers a bit
With the register A, B, C, D, E, H and L you can set values from 0 to 255
(negative numbers are also possible but just see it as 0-255)
However B and C, D and E, H and L together form a 16bit register.
This will give you values from 0-65535
You can read and write 16 bits registers directly from a memorylocation.
For 8 bits that is only possible for the A-register, as we did with the writing
to the screen. To test a key press we need to read LASTK. We can do that with A but then
we don;t know what to write to the screen. So we use a pair to read LASTK. BC is the best
to use as we will find out later.

Place the following code UNDER the line with the label "showa"

Code: Select all

nokey	ld bc,(lastk)
	inc c
	jr z,nokey

This routine reads the LASTK and test if ANY key is pressed.
If NOKEY is pressed C holds 255 and if you add 1 to it it becomes 0 again (overflow)
When that happens we wait in the loop for ANY KEY press.

Save the code and compile. Run the code.
Now you see that we need to press a key to go to the next display.
However the code is still running fast when we press a key.

Get GAME1-002.ASM again in edit, we add a few lines

Again UNDER SHOWA add the following code

Code: Select all

upkey	ld bc,(lastk)
	inc c
	jr nz,upkey
Like before LASTK is read, but now the routine waits until a key is released.
If a key is pressed C is NOT 255 and will never get to 0.

Save and compile.... and try to figure out what you must do to show the character.

LASTK stores information about the key, but not the printable value of the key.
The keyboard of the ZX81 is defined in 40 keys and numeric value.
The table is:

Code: Select all

 1  2  3  4  5   6  7  8  9  0
15 16 17 18 19  24 23 22 21 20

 Q  W  E  R  T   Y  U  I  O  P
10 11 12 13 14  29 28 27 26 25

 A  S  D  F  G   H  J  K  L  NEWL
 5  6  7  8  9  34 33 32 31  30

SH  Z  X  C  V   B  N  M  SY SPACE
 0  1  2  3  4  39 38 37  36 35
lucky for us the ROM is possible to do the translation for us.
And it even has a table to read from the keynumber the ASCII-character.

Let's edit GAME1-002.ASM and save it as GAME1-003.ASM.
We will alter the routine too much.
A CALL is like GOSUB in BASIC it goes to a subroutine and returns after the CALL with a RET(urn)

Replace the code between gamecode and dfile with this:

Code: Select all

gamecode ld bc,(lastk)		; get key information
	ld a,c			; copy C in A to keep C
	inc a			; Test if NOKEY pressed
	jr z,gamecode		; NO KEY, wiat for key
	call #7bd		; BC holds info about key, ROM can translated this here
	ld a,(hl)		; After the CALL registerpair HL points to ASCII-character, get characer
	ld (screen),a		; write character
	jr gamecode 		; JUMP back to start
Save and compile, see what happens when you press a key.
dr beep
Posts: 2060
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Gamecoding in machinecode on a ZX81.

Post by dr beep »

5 movement part 1

So far we can display a character and read information from the keyboard.
If we combine these 2 we can move a character over the screen.

In BASIC we can use INKEY# and PRINT AT to do this.
We will do something similar in machincode.

Let's start with a horizontal back- and forward move.

open GAME1-003.ASM and save it as GAME1-004.ASM

Until now we wrote to a fixed location on the screen. If we want a moving character we need
to make the writing to a more variable location.

Code: Select all

gamecode ld hl,screen

moveloop ld (hl),"O"-27		; we move a "O" on the screen


wkey	ld bc,(lastk)		; get key information
	ld a,c			; copy C in A to keep C
	inc a			; Test if NOKEY pressed
	jr z,wkey		; NO KEY, wait for key

	ld (hl),128		; we pressed a key, so we erase the old position

	push hl			; Save screenpointer on stack
	call #7bd		; BC holds info about key, ROM can translated this here
	ld a,(hl)		; After the CALL registercp 128pair HL points to ASCII-character, get characer
	pop hl			; get screenpointer

	cp "O"-27		; did we press the "O"?
	jr nz,right		; we didn't go left

	dec hl			; move 1 position left
	ld a,(hl)		; get next position on the screen 
	cp 128			; test if it is on the screen
	jr z,okmove		; if inverted space, then move is ok
	inc hl			; undo move left
	jr okmove

right	cp "P"-27		; did we press "P", right
	jr nz,okmove		; if not, movetest done
	inc hl			l move right
	ld a,(hl)		; get new position
	cp 128			; test out of screen
	jr z,okmove		; if not, move allowed
	dec hl			; undo move right
okmove  jr moveloop		; stay in playloop
Save the code, compile and run

See what happens when you press O and P
David G
Posts: 387
Joined: Thu Jul 17, 2014 7:58 am
Location: 21 North, 156 West

Re: Gamecoding in machinecode on a ZX81.

Post by David G »

dr beep wrote: Sun Jan 31, 2021 1:57 pmZX81course.zip ... Unpack it on your PC and you will get 2 maps inside the ZX81COURSE
Is the word "map" meaning Folder (directory)? I unzipped/unpacked the Course and inside are two sub-folders Game1 and sjasm

I'm trying this now. It appears that the compiler will work with either Linux or a Windows/Dos PC
dr beep
Posts: 2060
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Gamecoding in machinecode on a ZX81.

Post by dr beep »

Map=folder

Compiler is windows version.

what kind of error do you get?
David G
Posts: 387
Joined: Thu Jul 17, 2014 7:58 am
Location: 21 North, 156 West

Re: Gamecoding in machinecode on a ZX81.

Post by David G »

It's working, no error. I am using Windows 8.1, when I drag and drop as you suggested it uses the command prompt automatically. It created the P file

It loads, and automatically runs, then displays some text

It took me some hour to figure out how it runs the machine code when there is no BASIC line. when i finally found it GOTO USR 16393 it was mind-boggling. Some years ago I read that one could overwrite parts of the System Variables to store some amounts of machine code but this is a whole new level. The code *and the display* is entirely before the normal BASIC area, not one byte of the program area has been used!

My next wonder is how a display of 40 characters per line is able to work ...
dr beep
Posts: 2060
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Gamecoding in machinecode on a ZX81.

Post by dr beep »

David G wrote: Mon Feb 01, 2021 12:54 pm It's working, no error. I am using Windows 8.1, when I drag and drop as you suggested it uses the command prompt automatically. It created the P file

It loads, and automatically runs, then displays some text

It took me some hour to figure out how it runs the machine code when there is no BASIC line. when i finally found it GOTO USR 16393 it was mind-boggling. Some years ago I read that one could overwrite parts of the System Variables to store some amounts of machine code but this is a whole new level. The code *and the display* is entirely before the normal BASIC area, not one byte of the program area has been used!

My next wonder is how a display of 40 characters per line is able to work ...
How this works will explained in the EXTRA’s

I can also help with 40 char display.
Post Reply