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? ???
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".
Both commands are identical in this regard. The won't change the content of A, but will set the flags.
I think It's better to refer to several sources. For example, Rodnay Zaks's Programming the Z80 (http://www.z80.info/zaks.html), 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 (https://amstrad.eu/librairie/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.
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 (http://www.z80.info/zaks.html), 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 (https://amstrad.eu/librairie/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
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.
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. ???
(https://www.cpcwiki.eu/forum/programming/'and-a'-or-'or-a'-in-an-assembly-keypress-routine/?action=dlattach;attach=31631)
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.
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.
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
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
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...)
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).
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
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.
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.
Try this for your RND function;
.rnd
ld a,r
ld b,1
add a,b
ld (rnd+3),a
ret
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).
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
Quote from: GUNHED on 13:00, 27 June 20
Instead of this bulky code...
Once a TROLL, always a TROLL!
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
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.
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.
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.
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.
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
Try the one I wrote (based on others' work) , it's really good.
From: http://www.cpcwiki.eu/index.php/Programming:Random_Number_Generator (http://www.cpcwiki.eu/index.php/Programming:Random_Number_Generator) & https://www.cpcwiki.eu/forum/programming/testing-those-assembly-8bit-random-number-generators/msg114333/#msg114333 (https://www.cpcwiki.eu/forum/programming/testing-those-assembly-8bit-random-number-generators/msg114333/#msg114333)
;-----> Generate a random number
; ouput a=answer 0<=a<=255
ld hl,(seed_ion)
ld a,r
ld d,a
ld e,a
add hl,de
xor l
add a
xor h
ld l,a
ld (seed_ion),hl
ret
seed_ion: .dw 0x0
Quote from: Singaja on 17:52, 29 June 20
Try the one I wrote (based on others' work) , it's really good.
I'll have a look at it if the examples in the following thread seem to predictable:
https://www.cpcwiki.eu/forum/programming/pseudo-random-number-generation/ (https://www.cpcwiki.eu/forum/programming/pseudo-random-number-generation/)
Cheers.