beguiners question, zx assembly

The place for codemasters or beginners to talk about programming any language for the Spectrum.
Post Reply
rleao
Drutt
Posts: 21
Joined: Sun Sep 20, 2020 8:55 pm

beguiners question, zx assembly

Post by rleao »

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!
richardson leao
Neuroscientist, Uppsala University
User avatar
ketmar
Manic Miner
Posts: 613
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: beguiners question, zx assembly

Post by ketmar »

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).
Last edited by ketmar on Mon Oct 12, 2020 11:00 pm, edited 3 times in total.
User avatar
Sokurah
Manic Miner
Posts: 283
Joined: Tue Nov 14, 2017 10:38 am
Contact:

Re: beguiners question, zx assembly

Post by Sokurah »

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?
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
User avatar
Morkin
Bugaboo
Posts: 3251
Joined: Mon Nov 13, 2017 8:50 am
Location: Bristol, UK

Re: beguiners question, zx assembly

Post by Morkin »

I think that this CP value:

Code: Select all

in a,(c)
cp 191
...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]
My Speccy site: thirdharmoniser.com
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: beguiners question, zx assembly

Post by RMartins »

ketmar wrote: Mon Oct 12, 2020 10:53 pm ...
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.

...
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).
User avatar
ketmar
Manic Miner
Posts: 613
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: beguiners question, zx assembly

Post by ketmar »

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
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: beguiners question, zx assembly

Post by RMartins »

ketmar 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
#E0 is a Mask

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.
User avatar
ketmar
Manic Miner
Posts: 613
Joined: Tue Jun 16, 2020 5:25 pm
Location: Ukraine

Re: beguiners question, zx assembly

Post by ketmar »

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.
User avatar
777
Manic Miner
Posts: 512
Joined: Fri Jun 26, 2020 11:23 am
Location: sw uk

Re: beguiners question, zx assembly

Post by 777 »

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).
works for me. how would i substitute the coloured spaces for udgs?
i started programming the spectrum when i was 8 :-

1 plot rnd*255,rnd*175
2 goto 1
User avatar
PeterJ
Site Admin
Posts: 6858
Joined: Thu Nov 09, 2017 7:19 pm
Location: Surrey, UK

Re: beguiners question, zx assembly

Post by PeterJ »

Read the second chapter of the Jonathan Cauldwell book [mention]777[/mention] , it's covered in there.
User avatar
777
Manic Miner
Posts: 512
Joined: Fri Jun 26, 2020 11:23 am
Location: sw uk

Re: beguiners question, zx assembly

Post by 777 »

PeterJ wrote: Thu Oct 15, 2020 7:29 pm Read the second chapter of the Jonathan Cauldwell book @777 , it's covered in there.
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.
not sure why
i started programming the spectrum when i was 8 :-

1 plot rnd*255,rnd*175
2 goto 1
User avatar
Cosmium
Microbot
Posts: 154
Joined: Tue Dec 04, 2018 10:20 pm
Location: USA

Re: beguiners question, zx assembly

Post by Cosmium »

777 wrote: Fri Oct 16, 2020 12:02 am
PeterJ wrote: Thu Oct 15, 2020 7:29 pm Read the second chapter of the Jonathan Cauldwell book @777 , it's covered in there.
this program doesnt work, it just says b integer out of range:
not sure why
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.
User avatar
PeterJ
Site Admin
Posts: 6858
Joined: Thu Nov 09, 2017 7:19 pm
Location: Surrey, UK

Re: beguiners question, zx assembly

Post by PeterJ »

Gosh [mention]Cosmium[/mention],

That brings back memories. I had the same problem years ago with Spin. Pasmo does not have that issue though.
User avatar
Morkin
Bugaboo
Posts: 3251
Joined: Mon Nov 13, 2017 8:50 am
Location: Bristol, UK

Re: beguiners question, zx assembly

Post by Morkin »

Yeah, I think someone should update that guide at some point..! :lol:
My Speccy site: thirdharmoniser.com
Post Reply