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

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.

We can also use a part of the sysvar for code or storage.
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 4:25 pm 3) Output on display.
It worked first time!
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 10:38 pm
dr beep wrote: Sun Jan 31, 2021 4:25 pm 3) Output on display.
It worked first time!
keep going.... more to follow.
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 2

You might have noticed that the movement is INCREDIBLY FAST.
I did this on purpose to show how fast machinecode even on a ZX81
with 80% CPU time used to display can be.

We need to slow down the display.

Get GAME1-004.ASM in edit and save it as GAME1-005.ASM to keep track of the progress.

We already saw that each 1/50 sec the keyboard is read. During that same time an internal clock
is changed. We can use the change of this timer to slowdown our game.

This counter is stored in the systemvariable FRAMES, which is also defined in our code, as is LASTK.
FRAMES is a counter that starts at 65535 and count down to 32768. After that it goes back to 65535.
Why this count and this way? We may only guess about the reason, but it works just like that.
On the ZX Spectrum the counter is 24 bits and counting upwards from 0.

We can make a waitloop that checks the current state of the FRAMES and then wait for a change.
The best location to place this routine would be AFTER displaying our character.
In this way the program will wait with all items displayed. During the intrupt not only the keyboard is checked and timer altered but also a new screen is displayed.

Under moveloop we add the following code

Code: Select all

	push hl		; save our displayposition
	
	ld hl,frames	; make hl point to the timecounter
	ld a,(hl)	; get the timecounter in A

wfr	cp (hl)		; test if the value is the same
	jr z,wfr	; this remains the same until the intrupt changes FRAMES

	pop hl		; retrieve our displayposition
The program will go in a loop (WaitFrame) until a change appears.
Compile to see what happens now!
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 3

Now the displat is much better.
If you think it is too fast you could add more delay with a small alteration.

As we know, FRAMES is decreased each 1/50 sec. The number is stored as a 16 bit number.
Storage of 16 bits numbers is done with the least significnat byte first and the most significant byte behind that. So the number 64001 = 64*256+1, the 64 is the MSB and the 1 the LSB.
In FRAMES we read the LSB which is changed every 1/50 sec. If we want to wait 2 intrupts we need to check for the value 2 less than the current.

Change the code like this and see how much slower it is with 2 delays

Code: Select all

	push hl		; save our displayposition
	
	ld hl,frames	; make hl point to the timecounter
	ld a,(hl)	; get the timecounter in A
	sub 2		; take of 2, the number we want to test
wfr	cp (hl)		; test if the value is the same
	jr nz,wfr	; NOW WE WAIT UNTIL FRAMES MATCHES A!

	pop hl		; retrieve our displayposition
Again save and compile, we will work with this speed for the game.
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 (4)

Now we only move on the first line we want to move over the entire playfield.

It is time to add an equivalent for the PRINT AT command from BASIC.
I normally use B and C registers as equivalent for the BASIC-variables Y and X.

We already used a CALL-subroutine to a ROM-program, but now we will make a routine
that will calculate the location on the screen. The advantage of 2 registers holding the coordinates is also that we can easily test if we are out of range.

Our coordinates go from 1,1 to 20,20
Each line has 21 bytes so to get to positition 2,2 we need to add 1 full line and 1 position.
For position 1,1 we don't need to add anything to screen, however it is easier to
start 1 line and 1 column too low and then add a full line and 1 column, therefore
we set the start at SCREEN-21-1.

I added vertical movement and coordinates in the new code
Now replace the code from gamecode to dfile with the folowing code:

Compile and run, we can now move all over the screen with QAOP.

Code: Select all

gamecode 
	ld bc,#0101		; B=1, C=1, first position on the screen

moveloop 

	call field		; find PRINT AT position

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

	push hl	
	ld hl,frames		; make hl point to the timecounter
	ld a,(hl)		; get the timecounter in A
	sub 2			; take of 2, the number we want to test
wfr	cp (hl)			; test if the value is the same
	jr nz,wfr		; NOW WE WAIT UNTIL FRAMES MATCHES A!
	pop hl

	push bc			; NOW WE NEED TO SAVE BC!

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

	call #7bd		; BC holds info about key, ROM can translated this here
	pop bc
	ld a,(hl)		; get character

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

left	dec c
	jr nz,okmove
	inc c			
	jr okmove

right	cp "P"-27		; did we press "P", right
	jr nz,up		
	inc c			; move right
	ld a,c			; get new position
	cp 21			; test out of screen
	jr nz,okmove		; if not, move allowed
	dec c
	jr okmove

up	cp "Q"-27
	jr nz,down
	dec b
	jr nz,okmove
	inc b			
	jr okmove

down	cp "A"-27		; did we press "A", down
	jr nz,okmove		
	inc b			; move down
	ld a,b			; get new position
	cp 21			; test out of screen
	jr nz,okmove		; if not, move allowed
	dec b
okmove  jr moveloop		; stay in playloop
		

; BC = XY, return HL=field on screen
field	push bc			; save Y and X
	ld hl,screen-21-1	; always 1xY and 1xX added, line is 20+HALT
	ld de,21		; the size of 1 line (20 + HALT)
frow	add hl,de		; add rows until B=0
	djnz frow		; DEC B, JR NZ frow
	add hl,bc		; B now 0, C is X, so HL now field on screen
	pop bc			; get back original Y X
	ret
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: Tue Feb 02, 2021 1:59 pm 5 movement 3If you think it is too fast you could add more delay with a small alteration
...
Change the code like this and see how much slower it is with 2 delays
Changing the speed to 2 frames works. At first I tried to scan the few lines of code update and make the change by hand, but missed that the jr z changed to jr nz. Good old copy/paste fixed it for me and it indeed it slowed it down

Also tried "sub 3", which definitely slowed it down even more. Will continue with your recommended "sub 2"

Tried on the US version ZX81 which runs at 60hz. The game seems to run at the same speed, though maybe there is little difference
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: Thu Feb 04, 2021 10:35 am
dr beep wrote: Tue Feb 02, 2021 1:59 pm 5 movement 3If you think it is too fast you could add more delay with a small alteration
...
Change the code like this and see how much slower it is with 2 delays
Changing the speed to 2 frames works. At first I tried to scan the few lines of code update and make the change by hand, but missed that the jr z changed to jr nz. Good old copy/paste fixed it for me and it indeed it slowed it down

Also tried "sub 3", which definitely slowed it down even more. Will continue with your recommended "sub 2"

Tried on the US version ZX81 which runs at 60hz. The game seems to run at the same speed, though maybe there is little difference
That is why I am doing it step by step.
Z80 opcodes can be learned in many books, but how it becomes a game is best found out step by step.
In the endyou see a whole game and know how it works.
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: Tue Feb 02, 2021 9:37 pm 5 movement (4)

Now we only move on the first line we want to move over the entire playfield.
Do we need to make the playfield larger? The road is still one lane high, and when I press 'A', the player moves down off the road and crashes the ZX81
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 »

playfield is in size.


Try (a few) right and then down. See if cursor goes down in the right way.
Post Reply