Page 1 of 1

8.8 Fixed Point arithmetic

Posted: Sun Mar 07, 2021 7:56 pm
by presh
Looking for some working Z80 code for multiplying and dividing *signed* 8.8 Fixed Point numbers.

The example mulfixed8_8 I found at Z80 Heaven seems to output D.E * D.E, rather than H.L * D.E as advertised. (The mul16 subroutine seems to work fine)

And the method I found at cemetech is unsigned only.

(I haven't tried the 8.8 division routine yet!)

Anyone got some go-to routines for these which they have verified working?

:?

Re: 8.8 Fixed Point arithmetic

Posted: Mon Mar 08, 2021 11:03 am
by presh
Perhaps I have misinterpreted some of the code. This part of mulfixed8_8 wouldn't compile in Pasmo, as the label _: is repeated, e.g.

Code: Select all

; Now make sure the inputs are positive
  xor d     ;A now has the value of H, since I XORed it with D twice (cancelling)
  jp p,+_  ;if Positive, don't negate
  xor a
  sub l
  ld l,a
  sbc a,a
  sub h
  ld h,a
_:
  bit 7,d
  jr z,+_
  xor a
  sub e
  ld e,a
  sbc a,a
  sub d
  ld d,a
_:
Which gives:

Code: Select all

ERROR on line 26 of file mulfixed8_8.asm
ERROR: Invalid definition, previously defined as EQU or label
So I've changed the labels as follows:

Code: Select all

; Now make sure the inputs are positive
  xor d     ;A now has the value of H, since I XORed it with D twice (cancelling)
  jp p,_1   ;if Positive, don't negate
  xor a
  sub l
  ld l,a
  sbc a,a
  sub h
  ld h,a
_1:
  bit 7,d
  jp z,_2
  xor a
  sub e
  ld e,a
  sbc a,a
  sub d
  ld d,a[color=#FF0000]
_2:
But perhaps I have misunderstood what jp [cond ,] +[label] means (I've not seen a + used before a label) and fudged the logic as a result?

Re: 8.8 Fixed Point arithmetic

Posted: Mon Mar 08, 2021 11:18 am
by catmeows
Jump label looks fine. Why you think the multiplication routine doesn't work?

Re: 8.8 Fixed Point arithmetic

Posted: Mon Mar 08, 2021 11:59 am
by Joefish
For some 3D stuff I was looking for some 16.8 fixed point maths routines, to reproduce some stuff I did on an ST using 16.16 fixed point with its 32-bit registers. (It was very easy to swap or copy out the 16-bit halves whenever you needed a rounded-off integer). But for the Speccy it meant I'd have to reverse-engineer the 32-bit multiplies and divides I could find and reduce the number of bits involved. No easy task with highly optimised code.

Although I reasoned that the code might run faster if I worked backwards through each step of the calculations, worked out how many bits I needed at each step, and used different sized multiplies / divides as appropriate. It would just take a lot longer to write!

Re: 8.8 Fixed Point arithmetic

Posted: Mon Mar 08, 2021 12:06 pm
by presh
catmeows wrote: Mon Mar 08, 2021 11:18 am Why you think the multiplication routine doesn't work?
I made a super-simple test (4 x 1.5 = 6)

Called with PRINT USR so it will display the value in BC when we RET (though this will be 256x the actual answer as it discards the fixed point, essentially shifting it left 8 times)

Code: Select all

  ; HL = 4.0
  LD H, 4
  LD L, 0
  
  ; DE = 1.5
  LD D, 1
  LD E, 128
  
  ; H.L = H.L * D.E
  CALL mulfixed8_8
  
  ; RTB (should be 4*1.5*256 = 1536)
  ; instead it's 1.5*1.5*256 = 576!!
  LD B, H
  LD C, L
  ; LD B, 0
  ; LD C, H
  RET 
Changing HL makes no difference.
Result is always D.E * D.E

Re: 8.8 Fixed Point arithmetic

Posted: Mon Mar 08, 2021 12:54 pm
by catmeows
I see the bug. The mul16 computes BC*DE, but the fixed 8.8 pass HL and BC (and BC is copied from DE).

Re: 8.8 Fixed Point arithmetic

Posted: Mon Mar 08, 2021 4:17 pm
by presh
catmeows wrote: Mon Mar 08, 2021 12:54 pm I see the bug. The mul16 computes BC*DE, but the fixed 8.8 pass HL and BC (and BC is copied from DE).
Ugh, how did I not spot this!!! They even state it in the comments :oops: Thank you [mention]catmeows[/mention]
; Now we need to put HL in BC to use mul16
ld b,d
ld c,e
call mul16
:roll:

I also spotted another typo just below (though this won't make the whole thing fail - just wrong overflow value):
;We should check for overflow. If D>0, we will set HL to 0x7FFF
ld a,d
or a
jp z,_3
ld hl,$FFFF
_3:

Re: 8.8 Fixed Point arithmetic

Posted: Mon Mar 08, 2021 4:25 pm
by presh
Looks to be working now - thanks again [mention]catmeows[/mention] !

I may be back when I tackle division... :lol:

Re: 8.8 Fixed Point arithmetic

Posted: Mon Mar 08, 2021 4:43 pm
by catmeows
You are welcome.

That is quite interesting page about math, thanks for sharing.

Re: 8.8 Fixed Point arithmetic

Posted: Mon Mar 08, 2021 5:30 pm
by presh
Joefish wrote: Mon Mar 08, 2021 11:59 am It was very easy to swap or copy out the 16-bit halves whenever you needed a rounded-off integer
...
I reasoned that the code might run faster if I worked backwards through each step of the calculations, worked out how many bits I needed at each step, and used different sized multiplies / divides as appropriate. It would just take a lot longer to write!
Yeah, this is why I'm using 8.8 even though, say, 4.12 would give greater precision - quick, hassle-free access of the integer part. Nice!

Picking your routines based on expected input/output values sounds like a neat optimisation! Meanwhile, I'm still trying to get the damn thing working at all... maybe I should fix that first :lol:

Re: 8.8 Fixed Point arithmetic

Posted: Mon Mar 08, 2021 5:56 pm
by Mpk
I was coming coming here to ask about floats generally, as I need to handle large numbers in my silly project.

Is using the calc stack with 5-character floats and the built-in commands discouraged? Too slow?

Speed is not a concern for me at the moment.

Thanks,
Mpk

Re: 8.8 Fixed Point arithmetic

Posted: Mon Mar 08, 2021 6:20 pm
by Einar Saukas
Mpk wrote: Mon Mar 08, 2021 5:56 pm Is using the calc stack with 5-character floats and the built-in commands discouraged? Too slow?
Yes, it's much easier but extremely slow.

Mpk wrote: Mon Mar 08, 2021 5:56 pm Speed is not a concern for me at the moment.
In this case, I suggest you go ahead and use the calculator stack. It should be much easier to make your project work this way.

Even if speed becomes a concern later, it should be easier to modify a fully working program to replace these routines, instead of implementing everything the hard way from scratch.

Re: 8.8 Fixed Point arithmetic

Posted: Mon Mar 08, 2021 9:22 pm
by Mpk
Alright, thanks!

Slow and steady it is.

Mpk

Re: 8.8 Fixed Point arithmetic

Posted: Tue Mar 09, 2021 10:28 am
by presh
[mention]Mpk[/mention] there are also some z80 floating point libraries, which may give you the best of both worlds?

e.g. https://github.com/Zeda/z80float

I haven't tried them as I'm prioritising speed over accuracy (for now, at least)

Re: 8.8 Fixed Point arithmetic

Posted: Tue Mar 09, 2021 11:26 am
by Mpk
Does anyone know of any tutorial / examples for using the calc stack functions?

All I can find is the ROM disassembly pages ( e.g. https://skoolkid.github.io/rom/asm/3014.html) which are thorough, but not very friendly for the neophyte. I can get the multiply working fine, but the addition one just seems to return the top value unaltered. I think I'm not setting the DE/HL pointers correctly.

[mention]presh[/mention] Thanks, I may look at those if I can't get the basic ones working.

Re: 8.8 Fixed Point arithmetic

Posted: Sun Mar 21, 2021 12:48 am
by ZedaZ80
presh wrote: Mon Mar 08, 2021 4:17 pm I also spotted another typo just below (though this won't make the whole thing fail - just wrong overflow value):
;We should check for overflow. If D>0, we will set HL to 0x7FFF
ld a,d
or a
jp z,_3
ld hl,$FFFF
_3:
Thanks, fixed :)

The labels with +_ and -_ come from the spasm assembler popular with Texas Instruments Z80 calculators.

Code: Select all

_: is a temporary label,
+_ refers to the closest following _:, and
-_ refers to the closest preceding _:.
I'm trying to steer away from that niche syntax as I grow older and wiser in the ways of Z80 assembly compilers, but I have a large body of code that was written with spasm in mind.

I've also put these routines up on GitHub here:
mulfixed_88.z80
divfixed_88.z80
sqrtfixed_88.z80
Since they are up on GitHub, feel free to offer optimizations and routines as well as bug reports. I'm fairly busy these days, but I still do Z80 work at least one day a week.

If you do want to venture into using floats, I recommend the 24-bit floats here (these floats are small enough to be passed in registers!). I'm still working on the routines though, so they are apt to change as I find optimizations, but the inputs/outputs will remain the same. Depending on your project, there are 32-bit float routines, as well as 80-bit float routines in that library (you know, in case you need to do some high-precision computing on your Z80 :P).