News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_AMSDOS

"and a" or "or a" in an assembly keypress routine.

Started by AMSDOS, 03:29, 09 May 20

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

AMSDOS

While writing an Assembly routine to exit when a Key is pressed, I don't understand why if I write this:



.loop
    call &bb09
    or a
    jr nz,exit
    ld a,"*"
    call &bb5a
    jr loop
.exit
    ret



It works the same as if I had an "and a". My Assembly language book doesn't have an example about it, though in the decision making process some examples use "and a" instead of "cp #00", which is quicker I realise, though in that line of code it seems "and a" or "or a" are acceptable, unless one of those has consequences I'm unaware of?  ???
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

pelrun

AND and OR operations are both the identity function when applied to two copies of a value. They only differ in how they handle non-identical bits (i.e 0 to 1 or vice versa) but when you give it the same value twice everything is 1 to 1 or 0 to 0.


However, AND and OR *instructions* also set the flags based on the result. So it's a way to set the Z flag from A without changing A, and is one less byte than "cp 00".

GUNHED

Both commands are identical in this regard. The won't change the content of A, but will set the flags.
http://futureos.de --> Get the revolutionary FutureOS (Update: 2023.11.30)
http://futureos.cpc-live.com/files/LambdaSpeak_RSX_by_TFM.zip --> Get the RSX-ROM for LambdaSpeak :-) (Updated: 2021.12.26)

mr.freeze

I think It's better to refer to several sources. For example, Rodnay Zaks's Programming the Z80, describe a slow (but efficient for him) 16-bit comparison routine as it was for the 8080, without taking profit of the V flag (but using IX and IY). Leventhal and Saville's Z80 Assembly Language Subroutines was more helpful. Then I discovered the trick of inverting the sign bit and using CF and ZF for the comparison on Stackoverflow.

AMSDOS

Quote from: mr.freeze on 17:03, 10 May 20
I think It's better to refer to several sources. For example, Rodnay Zaks's Programming the Z80, describe a slow (but efficient for him) 16-bit comparison routine as it was for the 8080, without taking profit of the V flag (but using IX and IY). Leventhal and Saville's Z80 Assembly Language Subroutines was more helpful. Then I discovered the trick of inverting the sign bit and using CF and ZF for the comparison on Stackoverflow.


In my case here, I was wondering why the 'and' and 'or' instructions would work in a Loop, which has to do with the value in the Accumulator and while it's 0, the jump to exit won't happen, though as soon as a key has been pressed 'A' holds a value which either an 'and' or 'or' will generate and the not zero jump to exit occurs.


This example is a part of me trying to understand what a BASIC WHILE loop would look ilke in Assembly and how to code in a Tiny BASIC environment.  :D
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

mr.freeze

Quote from: AMSDOS on 10:45, 11 May 20

In my case here, I was wondering why the 'and' and 'or' instructions would work in a Loop, which has to do with the value in the Accumulator and while it's 0, the jump to exit won't happen, though as soon as a key has been pressed 'A' holds a value which either an 'and' or 'or' will generate and the not zero jump to exit occurs.


This example is a part of me trying to understand what a BASIC WHILE loop would look ilke in Assembly and how to code in a Tiny BASIC environment.  :D
Ah yes, I misread your post. I thought that your book was using or and and interchangeably without explanations. I must have been in a negative mood.
Good luck with your BASIC compiler.

AMSDOS

#6
This time I was trying to come up with a way of executing code when a certain value or over was reached. In BASIC I was using MOD, based on an example I'd seen in a BASIC tutorial game I typed-in a couple of years ago, though in Assembly there doesn't seem to be an equivalent, except for a firmware that's part of the Math Routines though annoyingly resides at different addresses depending on which computer is being used.


So I tried to see what I could come up with by using 'and', which seems to be the closest thing assembly has to compare with a BASIC MOD, even though their much different, it looks as though I came up with a Prime Number Generator without realising it.  ???





So, with that I made a little BASIC example of moving the man around the screen and the grumpy face moves when a value of 15 or more is found, which is based around variable 'a' that counts in a cycle 1 to 100.




100 MODE 0:DEFINT a-z:x=10:y=10:bx=1:bxd=1:by=1:byd=1:LOCATE bx,by:PRINT CHR$(225);:LOCATE x,y:PRINT CHR$(248);:a=1
110 WHILE 1
120   IF INKEY(1)=0 THEN IF x<20 THEN LOCATE x,y:PRINT" ";:x=x+1:LOCATE x,y:PRINT CHR$(250);
130   IF INKEY(8)=0 THEN IF x>1 THEN LOCATE x,y:PRINT" ";:x=x-1:LOCATE x,y:PRINT CHR$(251);
140   IF INKEY(0)=0 THEN IF y>1 THEN LOCATE x,y:PRINT" ";:y=y-1:LOCATE x,y:PRINT CHR$(248);
150   IF INKEY(2)=0 THEN IF y<25 THEN LOCATE x,y:PRINT" ";:y=y+1:LOCATE x,y:PRINT CHR$(249);
170   r = a + 1 AND a
180   n = a - r
190   IF n>=15 THEN GOSUB 1000
200   a=a+1:IF a=100 THEN a=1
210   CALL &BD19
220 WEND
1000 LOCATE bx,by:PRINT" "
1010 bx=bx+bxd:IF bx=20 THEN bxd=-1 ELSE IF bx=1 THEN bxd=1
1020 by=by+byd:IF by=25 THEN byd=-1 ELSE IF by=1 THEN byd=1
1030 LOCATE bx,by:PRINT CHR$(225);
1040 RETURN



Line 190 can be played around with to have:


190   IF n>15 THEN GOSUB 1000


or whatever to determine the speed of the grumpy face, and should translate a bit easier to assembly.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

pelrun

AND can be used as MOD but only when the modulus is of the form (2^n)-1. 15 happens to be one of those cases (2^4-1).


There's a couple of different methods to do a generic MOD operation. First is just to subtract the modulus repeatedly in a loop until the result is less than the modulus. The other is to do an integer division by the modulus, multiply by the modulus, then subtract from the original value. Obviously given the lack of division/multiplication operations in z80 assembly, the former is the simpler operation.

AMSDOS

This is what I came up with using the Loops, which seems to work:


org &8000


;;


ld a,10 ;; 10
.loop2
ld b,4 ;; mod 4
cp b
jr c,over ;; is b greater than a
.loop dec a ;; dec a
djnz loop ;; decrease b
jr loop2 ;; return for another run
.over ;; jump here if b is greater than a
ld (result),a ;; and store result
ret
.result
defb 0
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

pelrun

You don't need to manually implement a SUB operation!  :laugh:



      org &8000

      ;;

      ld a,10  ;; 10
      ld b,4    ;; mod 4

.loop
      sub b
      jr nc, loop        ;; loop until underflow
      add a,b            ;; go back one step
      ld (result),a      ;; and store result
      ret
.result
      defb 0

roudoudou

Quote from: AMSDOS on 03:29, 09 May 20
While writing an Assembly routine to exit when a Key is pressed, I don't understand why if I write this:



.loop
    call &bb09
    or a
    jr nz,exit
    ld a,"*"
    call &bb5a
    jr loop
.exit
    ret



It works the same as if I had an "and a". My Assembly language book doesn't have an example about it, though in the decision making process some examples use "and a" instead of "cp #00", which is quicker I realise, though in that line of code it seems "and a" or "or a" are acceptable, unless one of those has consequences I'm unaware of?  ???
OR A is faster than CP #00
But doing a JR NZ toward a RET is slower than a single RET NZ  ;D (plus you have a write a label, source is bigger, less readable...)


My pronouns are RASM and ACE

AMSDOS

Quote from: roudoudou on 08:17, 14 June 20
But doing a JR NZ toward a RET is slower than a single RET NZ  ;D (plus you have a write a label, source is bigger, less readable...)


I would agree if I was coding an Assembly programme, though I'm coding a small language and interpreting what a WHILE..WEND statement might look in Assembly (as mentioned above). So the JR NZ or JP NZ may not necessarily Jump to a RET, it could, though If I had WHILE, which starts with the ret nz, I then enter the code which is executed within the WHILE loop, but when I initiate WEND, that's when I need to move the code by 2 or 3 bytes depending on if JR or JP is used. At that point I don't know if there's other code to follow and that's where that's a problem in saying that RET NZ should stay or go, in a practical sense a WHILE..WEND loop would normally exit to some closing code (reset some colours or screen mode etc).
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

Urusergi

Quote from: roudoudou on 08:17, 14 June 20But doing a JR NZ toward a RET is slower than a single RET NZ  ;D (plus you have a write a label, source is bigger, less readable...)

And finally... there is no need to use "or a" or "and a"  :P

.loop
    call &bb09
    ret c
    ld a,"*"
    call &bb5a
    jr loop


AMSDOS

Quote from: pelrun on 05:49, 14 June 20
You don't need to manually implement a SUB operation!  :laugh:



      org &8000

      ;;

      ld a,10  ;; 10
      ld b,4    ;; mod 4

.loop
      sub b
      jr nc, loop        ;; loop until underflow
      add a,b            ;; go back one step
      ld (result),a      ;; and store result
      ret
.result
      defb 0



So in Locomotive BASIC, if I perform a:


FOR n=1 TO 100:PRINT INT(RND*255 MOD 10);:NEXT n


I get numbers between 0 and 9, so in theory an 8bit Random Number Generator in Assembly with your MOD routine will produce Output within a Certain Range Plus whatever incremented if found.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

AMSDOS

I thought I'd have "mod" and "rnd" routines working by now in the small tbas language I've been creating, though I'm puzzled why everything has been doubled spaced!


In tbas it looks like this:

cls
let b(0)=0
while b(0)<10
let b(1)=r(10)+1
let b(2)=r(20)+1
locate b(1),b(2)
print "*"
let b(0)=+1
wend



though I've been able to code it in assembly, it has something to do with the 2nd statement following the  1st because with one random number generator routine, the double spacing doesn't occur, but I don't understand because in the assembly the numbers return are stored in their own dedicated positions, though this following assembly routine is how I would code it in tbas, only with my main programme code being at &7000 instead of &4000, and at first I thought it was working until I noticed everything being double spaced! :(


A small BASIC code confirms this:
for a=1 to 100:call &7000:next a




org &7000


call rnd
ld b,10
call mod
inc a
ld (num1),a


call rnd
ld b,20
call mod
inc a
ld (num2),a


ld a,(num1)
ld h,a
ld a,(num2)
ld l,a
call &bb75
ld a,"*"
call &bb5a
ret


.num1 defb 0
.num2 defb 0



org &8000


.seed defb 0


.rnd
ld a,(seed)
ld b,a
add a,a
add a,a
add a,b
inc a
ld (seed),a
ret


.mod
sub b
jr nc,mod
add a,b
ret



Would be greatful of what I'm doing wrong, thanks.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

tastefulmrship

Try this for your RND function;

.rnd
    ld a,r
    ld b,1
    add a,b
    ld (rnd+3),a
    ret


AMSDOS

Quote from: SuTeKH/Epyteor on 07:40, 27 June 20
Try this for your RND function;

.rnd
    ld a,r
    ld b,1
    add a,b
    ld (rnd+3),a
    ret



It's producing a good spead of random values even after mod is applied, probably because of the use of the refresh register 'r', without the need of any further random number generators (as seen in the screenshot).











* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

GUNHED

Instead of this bulky code...

Quote from: SuTeKH/Epyteor on 07:40, 27 June 20
.rnd
    ld a,r
    ld b,1
    add a,b
    ld (rnd+3),a
    ret



It would be better to use this one:
.rnd
    ld a,r
    inc a
    ld (rnd+3),a

    ret


That's in effect the same, but shorter:
.rnd

    ld a,r
    ld (rnd+3),a
    ret


But all these examples are pretty simple and no good choice for random numbers.


Better use this:

.rnd
    ld a,r
    xor a,(hl)
    ld (rnd+3),a
    ret

http://futureos.de --> Get the revolutionary FutureOS (Update: 2023.11.30)
http://futureos.cpc-live.com/files/LambdaSpeak_RSX_by_TFM.zip --> Get the RSX-ROM for LambdaSpeak :-) (Updated: 2021.12.26)

tastefulmrship


Urusergi

Quote from: GUNHED on 13:00, 27 June 20
Instead of this bulky code...


It would be better to use this one:
.rnd
    ld a,r
    inc a
    ld (rnd+3),a

    ret


That's in effect the same, but shorter:
.rnd

    ld a,r
    ld (rnd+3),a
    ret


But all these examples are pretty simple and no good choice for random numbers.


Better use this:

.rnd
    ld a,r
    xor a,(hl)
    ld (rnd+3),a
    ret



Sorry, but you are wrong. This is a self-modifying code and that's why the instruction ld b,1 has to be


AMSDOS

Quote from: Urusergi on 14:41, 27 June 20
Sorry, but you are wrong. This is a self-modifying code and that's why the instruction ld b,1 has to be


I agree the 'ld b,1' is the only place a need seed can be stored. I took screenshots of the random numbers produced when I had the 'add a,b' opcode, and 'xor (hl)' opcode with the 'add a,b' version returning values across the 8bit range and 'xor (hl)' limited from 0->127, which is the range acquired from the refresh register (r), unless there's another trick, the problem I found if numbers between 0 and &7f are xor with &ff for example a limited range of 255 to 128 is the result, I did other little experiments based on carry flags or using xor &bf and got values between 191..255 & 0...60, leaving a large gap with no value.


The other day after writing about my troubles with the double spacing, I threw out that 8bit random number generator which may only be fine for Assembly code. I put a 16bit random number generator I had from when I was following the Assembly Guide in AA after they gave away Devpac on their Covertape, which helped eliminate the double spacing, though it appears that too could produce the a distinct random pattern, however I wasn't using the refresh register to alternate the seed.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

andycadley

R register behaviour is very predictable and not really a very good source for any kind of random number generator. There are much better algorithms out there and plenty of z80 code samples on the web.

GUNHED

The R register is of course nice to be used - in addition - but it's not enough to have a well random number generator.


In a time where people eventually discover the greatness or ROMs it's not a good thing to use self modifying code anyway - except you have a significant speed gain.
http://futureos.de --> Get the revolutionary FutureOS (Update: 2023.11.30)
http://futureos.cpc-live.com/files/LambdaSpeak_RSX_by_TFM.zip --> Get the RSX-ROM for LambdaSpeak :-) (Updated: 2021.12.26)

AMSDOS

I found a couple, that weren't using the 'r' register, one of those doesn't produce a 0, another one uses a large seed before returning a 8bit number, I guess I could test to see if I like the speed of it, it may be acceptable. Some of the other ones were using 'r' register, but if you say the values from it are quite predictable, I'll have a look at these other ones.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

AMSDOS

I had a look at 2 small Pseudo Random Number generators, the 1st one was horrible, throwing out numbers in a pattern, maybe it works better on a Spectrum (I dunno), the 2nd was a little better, though as far as it was concerned, random numbers only appear once until it's been through the 255 range and yes I mean 255 because 0 isn't included.


I guess the key work there is "Pseudo", I found a site which has a Linear Feedback Shift Register which takes a 64bit seed to return a 8bit number (as mentioned earlier), should that be what I look at?



;; Fast RND
;;
;; An 8-bit pseudo-random number generator,
;; using a similar method to the Spectrum ROM,
;; - without the overhead of the Spectrum ROM.
;;
;; R = random number seed
;; an integer in the range [1, 256]
;;
;; R -> (33*R) mod 257
;;
;; S = R - 1
;; an 8-bit unsigned integer


;; http://www.z80.info/pseudo-random.txt


ld a, (seed)
ld b, a


rrca ; multiply by 32
rrca
rrca
xor &1f


add a, b
sbc a, 255 ; carry


ld (seed), a
ret




;; https://www.sbprojects.net/projects/mpf1/rndtest.php


                LD      A,(SEED)      ;;  Get random number seed
                LD      C,A           ;;  Calculate next random number
                AND     A,&B8         ;;  &X10111000
                SCF
                JP      PO,SF
                CCF
.SF            LD      A,C
                RLA
                LD      C,A
                LD      (SEED),A      ;;  Save random number seed
RET
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

Powered by SMFPacks Menu Editor Mod