beguiners question, zx assembly
beguiners question, zx assembly
Hi All,
I am new in the zx basic, and needless to say, assembly. I have a simple doubt (i think). I was following the tutorial here:
http://chuntey.arjunnair.in/?p=63
and to run it I was trying the 'randomize usr 33000'. However, the keyboard commands are irresponsive. If I compile it with pasmo to generate a tap file it generates a small code with clear 32999 poke etc. The keyboard works with the first run but not the second. Do I have to enable the keyboard somehow in basic to run something in machine code? Here is the original assembly code by Jon Kingsman
main
org 33000
di
ld hl, 22537 ;initialise road
push hl ;save road posn
xor a
ld b,24
fillscreen
ld (hl),a
inc hl
ld (hl),a
ld de,9
add hl,de
ld (hl),a
inc hl
ld (hl),a
ld de,21
add hl,de
djnz fillscreen
ld c,b ;initialise score
push bc ;save score
ld hl,23278 ;initialise car
ld a,8
ld (hl),a
ld (32900),hl ;save car posn
principalloop
ld hl,(32900) ;retrieve car posn
ld a,56 ;erase car
ld (hl),a
ei
ld bc,65278 ;read keyboard caps to v
in a,(c)
cp 191
jr nz, moveright
inc l
moveright
ld bc,32766 ;read keyboard space to b
in a,(c)
cp 191
jr nz, dontmove
dec l
dontmove
di
ld (32900),hl ;store car posn
ld de, 32 ;new carposn
xor a ;set carry flag to 0
sbc hl,de
ld a,(hl) ;crash?
or a
jr z,gameover
ld a,8 ;print car
ld (hl),a
ld hl,23263 ;scroll road
ld de,23295
ld bc,736
lddr
pop bc ;retrieve score
pop hl ;retrieve road posn
push hl ;save road posn
ld a,56 ;delete old road
ld (hl),a
inc hl
ld (hl),a
ld de,9
add hl,de
ld (hl),a
inc hl
ld (hl),a
;random road left or right
ld hl,14000 ;source of random bytes in ROM
ld d,0
ld e,c
add hl, de
ld a,(hl)
pop hl ;retrieve road posn
dec hl ;move road posn 1 left
and 1
jr z, roadleft
inc hl
inc hl
roadleft
ld a,l ;check left
cp 255
jr nz, checkright
inc hl
inc hl
checkright
ld a,l
cp 21
jr nz, newroadposn
dec hl
dec hl
newroadposn
push hl ;save road posn
xor a ;print new road
ld (hl),a
inc hl
ld (hl),a
ld de,9
add hl,de
ld (hl),a
inc hl
ld (hl),a
inc bc ;add 1 to score
push bc ;save score
;wait routine
ld bc,$1fff ;max waiting time
wait
dec bc
ld a,b
or c
jr nz, wait
jp principalloop
gameover
pop bc ;retrieve score
pop hl ;empty stack
ei
ret; game and tutorial written by Jon Kingsman ('bigjon', 'bj'). electronic mail gmail.com - atsign - jon.kingsman (reversed)
; end 33000
thank you!
I am new in the zx basic, and needless to say, assembly. I have a simple doubt (i think). I was following the tutorial here:
http://chuntey.arjunnair.in/?p=63
and to run it I was trying the 'randomize usr 33000'. However, the keyboard commands are irresponsive. If I compile it with pasmo to generate a tap file it generates a small code with clear 32999 poke etc. The keyboard works with the first run but not the second. Do I have to enable the keyboard somehow in basic to run something in machine code? Here is the original assembly code by Jon Kingsman
main
org 33000
di
ld hl, 22537 ;initialise road
push hl ;save road posn
xor a
ld b,24
fillscreen
ld (hl),a
inc hl
ld (hl),a
ld de,9
add hl,de
ld (hl),a
inc hl
ld (hl),a
ld de,21
add hl,de
djnz fillscreen
ld c,b ;initialise score
push bc ;save score
ld hl,23278 ;initialise car
ld a,8
ld (hl),a
ld (32900),hl ;save car posn
principalloop
ld hl,(32900) ;retrieve car posn
ld a,56 ;erase car
ld (hl),a
ei
ld bc,65278 ;read keyboard caps to v
in a,(c)
cp 191
jr nz, moveright
inc l
moveright
ld bc,32766 ;read keyboard space to b
in a,(c)
cp 191
jr nz, dontmove
dec l
dontmove
di
ld (32900),hl ;store car posn
ld de, 32 ;new carposn
xor a ;set carry flag to 0
sbc hl,de
ld a,(hl) ;crash?
or a
jr z,gameover
ld a,8 ;print car
ld (hl),a
ld hl,23263 ;scroll road
ld de,23295
ld bc,736
lddr
pop bc ;retrieve score
pop hl ;retrieve road posn
push hl ;save road posn
ld a,56 ;delete old road
ld (hl),a
inc hl
ld (hl),a
ld de,9
add hl,de
ld (hl),a
inc hl
ld (hl),a
;random road left or right
ld hl,14000 ;source of random bytes in ROM
ld d,0
ld e,c
add hl, de
ld a,(hl)
pop hl ;retrieve road posn
dec hl ;move road posn 1 left
and 1
jr z, roadleft
inc hl
inc hl
roadleft
ld a,l ;check left
cp 255
jr nz, checkright
inc hl
inc hl
checkright
ld a,l
cp 21
jr nz, newroadposn
dec hl
dec hl
newroadposn
push hl ;save road posn
xor a ;print new road
ld (hl),a
inc hl
ld (hl),a
ld de,9
add hl,de
ld (hl),a
inc hl
ld (hl),a
inc bc ;add 1 to score
push bc ;save score
;wait routine
ld bc,$1fff ;max waiting time
wait
dec bc
ld a,b
or c
jr nz, wait
jp principalloop
gameover
pop bc ;retrieve score
pop hl ;empty stack
ei
ret; game and tutorial written by Jon Kingsman ('bigjon', 'bj'). electronic mail gmail.com - atsign - jon.kingsman (reversed)
; end 33000
thank you!
richardson leao
Neuroscientist, Uppsala University
Neuroscientist, Uppsala University
Re: beguiners question, zx assembly
because the tutorial is wrong. first, it stores car position in "32900", despite the fact that the author definitely knows about labels. this is already a huge red flag. but this is not the case of the keyboard reading bug.
the case is that the author doesn't know how to reliably read the keyboard. keyboard port also contains EAR flag, i.e. tape input. its default value is not fixed, and it can be 0 or 1 (or even change randomly). yet the author ignores this fact, and assumes that it is always 0. this happened to be the case for the emulator when it just finished loading the tape, but then the flag reverts to 1, and BOOM! cp 191 never works anymore (because returned value is 255). the fact is that the car is constantly moving to the left, and then immediately to the right, so effectively it is frozen. (i.e. the code thinks that you're holding both "left" and "right" keys all the time).
tl;dr: "cp 191" is a bug. you have to mask bits 6 and 7 of keyboard ports, and never assume that values of those bits are somehow known. by the way, even some "official" ZX games had this bug.
here, the easiest way to fix the bug is to insert "and 191" before each "cp 191".
bit this is still not a good tutorial. it does things for nothing and without any reason (playing with the interrupts, for example).
the case is that the author doesn't know how to reliably read the keyboard. keyboard port also contains EAR flag, i.e. tape input. its default value is not fixed, and it can be 0 or 1 (or even change randomly). yet the author ignores this fact, and assumes that it is always 0. this happened to be the case for the emulator when it just finished loading the tape, but then the flag reverts to 1, and BOOM! cp 191 never works anymore (because returned value is 255). the fact is that the car is constantly moving to the left, and then immediately to the right, so effectively it is frozen. (i.e. the code thinks that you're holding both "left" and "right" keys all the time).
tl;dr: "cp 191" is a bug. you have to mask bits 6 and 7 of keyboard ports, and never assume that values of those bits are somehow known. by the way, even some "official" ZX games had this bug.
here, the easiest way to fix the bug is to insert "and 191" before each "cp 191".
bit this is still not a good tutorial. it does things for nothing and without any reason (playing with the interrupts, for example).
Last edited by ketmar on Mon Oct 12, 2020 11:00 pm, edited 3 times in total.
Re: beguiners question, zx assembly
I've just assembled it using the assembler in Spin and it assembled without problems.
Then I ran it 6-8 times without assembling it again and it works perfectly.
Perhaps you're in 128K mode? Have you tried in 48K mode?
Then I ran it 6-8 times without assembling it again and it works perfectly.
Perhaps you're in 128K mode? Have you tried in 48K mode?
Website: Tardis Remakes / Mostly remakes of Arcade and ZX Spectrum games.
My games for the Spectrum: Dingo, The Speccies, The Speccies 2, Vallation & Sqij.
Twitter: Sokurah
My games for the Spectrum: Dingo, The Speccies, The Speccies 2, Vallation & Sqij.
Twitter: Sokurah
Re: beguiners question, zx assembly
I think that this CP value:
...may vary depending on which version of Speccy you're using (128k, +2, 48k etc.). But I can't remember off the top of my head. I'm sure some more knowledgeable members here will be able to confirm. I think programmers tend to get rid of any ambiguity by using something like AND 31, as it's only the lowest 5 bits that you're interested in when reading the keyboard.
[Edit: Oh, Ketmar got there before me]
Code: Select all
in a,(c)
cp 191
[Edit: Oh, Ketmar got there before me]
My Speccy site: thirdharmoniser.com
Re: beguiners question, zx assembly
I would say that you should always mask out what you don't need, and in the case of keyboard only bits 0 to 4 are relevant, hence all other bits (5 to 7) should be masked out (00011111 for AND).
Re: beguiners question, zx assembly
yeah. but i tried to workaround the bug with minimal changes. if we'll follow the logic of the code, it is better to set bits, not to mask them. so we can do this:
Code: Select all
or #E0
inc a
jr z,.not_pressed
Re: beguiners question, zx assembly
#E0 is a Maskketmar wrote: ↑Wed Oct 14, 2020 6:40 pm yeah. but i tried to workaround the bug with minimal changes. if we'll follow the logic of the code, it is better to set bits, not to mask them. so we can do this:Code: Select all
or #E0 inc a jr z,.not_pressed
What you do with it, is called masking.
A mask can be used (masking) for setting (ORing) or clearing (ANDing), or toggling (XORing) bits, or whatever other function you may require.
Re: beguiners question, zx assembly
common use of the term "mask bits" is equal to "reset bits". sure, ORing with a mask is masking too, but there is no common term for it (afaik). almost every programmer will think about ANDing when they read "we need to mask some bits". so i used the term in this sense to avoid confusions.
Re: beguiners question, zx assembly
works for me. how would i substitute the coloured spaces for udgs?ketmar wrote: ↑Mon Oct 12, 2020 10:53 pm because the tutorial is wrong. first, it stores car position in "32900", despite the fact that the author definitely knows about labels. this is already a huge red flag. but this is not the case of the keyboard reading bug.
the case is that the author doesn't know how to reliably read the keyboard. keyboard port also contains EAR flag, i.e. tape input. its default value is not fixed, and it can be 0 or 1 (or even change randomly). yet the author ignores this fact, and assumes that it is always 0. this happened to be the case for the emulator when it just finished loading the tape, but then the flag reverts to 1, and BOOM! cp 191 never works anymore (because returned value is 255). the fact is that the car is constantly moving to the left, and then immediately to the right, so effectively it is frozen. (i.e. the code thinks that you're holding both "left" and "right" keys all the time).
tl;dr: "cp 191" is a bug. you have to mask bits 6 and 7 of keyboard ports, and never assume that values of those bits are somehow known. by the way, even some "official" ZX games had this bug.
here, the easiest way to fix the bug is to insert "and 191" before each "cp 191".
bit this is still not a good tutorial. it does things for nothing and without any reason (playing with the interrupts, for example).
i started programming the spectrum when i was 8 :-
1 plot rnd*255,rnd*175
2 goto 1
1 plot rnd*255,rnd*175
2 goto 1
Re: beguiners question, zx assembly
Read the second chapter of the Jonathan Cauldwell book [mention]777[/mention] , it's covered in there.
Re: beguiners question, zx assembly
this program doesnt work, it just says b integer out of range:
Code: Select all
org 40000
; We want a black screen.
ld a,71 ; white ink (7) on black paper (0),
; bright (64).
ld (23693),a ; set our screen colours.
xor a ; quick way to load accumulator with zero.
call 8859 ; set permanent border colours.
; Set up the graphics.
ld hl,blocks ; address of user-defined graphics data.
ld (23675),hl ; make UDGs point to it.
; Okay, let's start the game.
call 3503 ; ROM routine - clears screen, opens chan 2.
; Initialise coordinates.
ld hl,21+15*256 ; load hl pair with starting coords.
ld (plx),hl ; set player coords.
call basexy ; set the x and y positions of the player.
call splayr ; show player base symbol.
; This is the main loop.
mloop equ $
; Delete the player.
call basexy ; set the x and y positions of the player.
call wspace ; display space over player.
; Now we've deleted the player we can move him before redisplaying him
; at his new coordinates.
ld bc,63486 ; keyboard row 1-5/joystick port 2.
in a,(c) ; see what keys are pressed.
rra ; outermost bit = key 1.
push af ; remember the value.
call nc,mpl ; it's being pressed, move left.
pop af ; restore accumulator.
rra ; next bit along (value 2) = key 2.
push af ; remember the value.
call nc,mpr ; being pressed, so move right.
pop af ; restore accumulator.
rra ; next bit (value 4) = key 3.
push af ; remember the value.
call nc,mpd ; being pressed, so move down.
pop af ; restore accumulator.
rra ; next bit (value 8) reads key 4.
call nc,mpu ; it's being pressed, move up.
; Now he's moved we can redisplay the player.
call basexy ; set the x and y positions of the player.
call splayr ; show player.
halt ; delay.
; Jump back to beginning of main loop.
jp mloop
; Move player left.
mpl ld hl,ply ; remember, y is the horizontal coord!
ld a,(hl) ; what's the current value?
and a ; is it zero?
ret z ; yes - we can't go any further left.
dec (hl) ; subtract 1 from y coordinate.
ret
; Move player right.
mpr ld hl,ply ; remember, y is the horizontal coord!
ld a,(hl) ; what's the current value?
cp 31 ; is it at the right edge (31)?
ret z ; yes - we can't go any further left.
inc (hl) ; add 1 to y coordinate.
ret
; Move player up.
mpu ld hl,plx ; remember, x is the vertical coord!
ld a,(hl) ; what's the current value?
cp 4 ; is it at upper limit (4)?
ret z ; yes - we can go no further then.
dec (hl) ; subtract 1 from x coordinate.
ret
; Move player down.
mpd ld hl,plx ; remember, x is the vertical coord!
ld a,(hl) ; what's the current value?
cp 21 ; is it already at the bottom (21)?
ret z ; yes - we can't go down any more.
inc (hl) ; add 1 to x coordinate.
ret
; Set up the x and y coordinates for the player's gunbase position,
; this routine is called prior to display and deletion of gunbase.
basexy ld a,22 ; AT code.
rst 16
ld a,(plx) ; player vertical coord.
rst 16 ; set vertical position of player.
ld a,(ply) ; player's horizontal position.
rst 16 ; set the horizontal coord.
ret
; Show player at current print position.
splayr ld a,69 ; cyan ink (5) on black paper (0),
; bright (64).
ld (23695),a ; set our temporary screen colours.
ld a,144 ; ASCII code for User Defined Graphic 'A'.
rst 16 ; draw player.
ret
wspace ld a,71 ; white ink (7) on black paper (0),
; bright (64).
ld (23695),a ; set our temporary screen colours.
ld a,32 ; SPACE character.
rst 16 ; display space.
ret
plx defb 0 ; player's x coordinate.
ply defb 0 ; player's y coordinate.
; UDG graphics.
blocks defb 16,16,56,56,124,124,254,254 ; player base.
i started programming the spectrum when i was 8 :-
1 plot rnd*255,rnd*175
2 goto 1
1 plot rnd*255,rnd*175
2 goto 1
Re: beguiners question, zx assembly
When I assembled this in ZX Spin I got the same thing.
It's because the assembler is evaluating the LD HL,21+15*256 line from left to right instead of the multiplication in the expression getting priority over the addition, as expected by the author. So the result is the UDG being printed off screen, causing the Out of Range error.
The code runs fine if you force the assembler to evaluate it in the correct order, giving the intended starting x,y of 15, 21:
Code: Select all
; Initialise coordinates.
ld hl,21+(15*256) ; load hl pair with starting coords.
Cosmium
https://cosmium.itch.io/
https://cosmium.itch.io/
Re: beguiners question, zx assembly
Gosh [mention]Cosmium[/mention],
That brings back memories. I had the same problem years ago with Spin. Pasmo does not have that issue though.
That brings back memories. I had the same problem years ago with Spin. Pasmo does not have that issue though.
Re: beguiners question, zx assembly
My Speccy site: thirdharmoniser.com