summaryrefslogtreecommitdiff
path: root/avx512-0037785/packages/qlunits/src/qlfloat.pas
diff options
context:
space:
mode:
Diffstat (limited to 'avx512-0037785/packages/qlunits/src/qlfloat.pas')
-rw-r--r--avx512-0037785/packages/qlunits/src/qlfloat.pas182
1 files changed, 182 insertions, 0 deletions
diff --git a/avx512-0037785/packages/qlunits/src/qlfloat.pas b/avx512-0037785/packages/qlunits/src/qlfloat.pas
new file mode 100644
index 0000000000..d96a523d6e
--- /dev/null
+++ b/avx512-0037785/packages/qlunits/src/qlfloat.pas
@@ -0,0 +1,182 @@
+{
+ Conversion code from various number formats to QL Float format.
+
+ Code ported from the C68/QL-GCC libc implementation available at:
+ http://morloch.hd.free.fr/qdos/qdosgcc.html
+
+ The QL wiki claims the original of these sources are by
+ Dave Walker, and they are in the Public Domain.
+ https://qlwiki.qlforum.co.uk/doku.php?id=qlwiki:c68
+
+ **********************************************************************}
+unit qlfloat;
+
+interface
+
+uses
+ qdos;
+
+function longint_to_qlfp(qlf: Pqlfloat; val: longint): Pqlfloat;
+function double_to_qlfp(qlf: Pqlfloat; val: Pdouble): Pqlfloat;
+
+
+implementation
+
+function longint_to_qlfp(qlf: Pqlfloat; val: longint): Pqlfloat; assembler; nostackframe;
+asm
+ { pointer to qlfloat is in a0 }
+ { val is in d0 }
+
+ movem.l d2-d4/a0,-(sp) { save register variables and a0 }
+ moveq.l #0,d2 { sign value }
+ move.l d2,d3 { shift value }
+ tst.l d0 { zero or -ve ? }
+ beq @zeroval { zero }
+ bpl @plusval { +ve }
+
+{ i is negative here. set the sign value then make i positive }
+
+ moveq #1,d2 { boolean to say -ve }
+ not.l d0 { i has all bits reversed }
+ bne @plusval { i was not -1, so can continue }
+
+{ i was -1, so cannot go into following loop, as it now is zero }
+
+ moveq #0,d2 { pretend i was positive }
+ move.l #$80000000,d1 { set d1 correctly }
+ move.w #31,d3 { shift value }
+ bra @outloop { continue }
+
+@plusval:
+ move.l d0,d1 { save a copy of the original i }
+
+{ check for shortcuts with shifts }
+
+ and.l #$ffffff00,d0 { shift by 23 ? }
+ bne @bigger23 { no cheat available }
+ move.w #23,d3 { shift value is 23 }
+ lsl.l d3,d1 { shift copy of i }
+ bra @nbigger { continue }
+
+{ check for 15 bit shortcut shift }
+
+@bigger23:
+ move.l d1,d0 { restore i }
+ and.l #$ffff0000,d0 { shift by 15 ? }
+ bne @nbigger { no cheat available }
+ move.w #15,d3 { shift value is 15 }
+ lsl.l d3,d1 { shift copy of i }
+
+{ no shortcuts available }
+
+@nbigger:
+ move.l d1,d0 { restore i }
+ and.l #$40000000,d0 { if(!(i & 0x40000000)) }
+ bne @outloop { bit is set, no more shifts }
+ lsl.l #1,d1 { shift copy of i }
+ addq.l #1,d3 { increment shift count }
+ bra @nbigger { ensures i is restored }
+
+{ finished shifts - copy into qlfloat }
+{ correct shifted i is in d1, d0 contains i & 0x40000000 }
+
+@outloop:
+ move.w #$81f,d4
+ sub.w d3,d4 { set exponent correctly }
+ move.w d4,(a0)+ { copy into exponent }
+
+{ difference here between positive and negative numbers
+; negative should just be shifted until first zero, so as we
+; have 2s complemented and shifted until first one, we must now
+; re-complement what is left }
+
+ tst.b d2
+ beq @setmant { positive value here - just copy it }
+
+{ negative value, xor it with -1 shifted by same amount as in shift (d3)
+; to convert it back to -ve representation }
+
+ moveq.l #-1,d2 { set d2 to all $FFs }
+ lsl.l d3,d2 { shift it by shift (d3 ) }
+ eor.l d2,d1 { not the value by xoring }
+
+{ negative value restored by above }
+
+@setmant:
+ move.l d1,(a0) { copy into mantissa }
+@fin:
+ movem.l (sp)+,d2-d4/a0 { reset register variables and return value }
+ rts
+
+{ quick exit if zero }
+
+@zeroval:
+ move.w d2,(a0)+ { zero exponent }
+ move.l d2,(a0) { zero mantissa }
+ bra @fin
+end;
+
+
+function double_to_qlfp(qlf: Pqlfloat; val: Pdouble): Pqlfloat; assembler; nostackframe;
+asm
+{----------------------------- IEEE -----------------------------------
+; routine to convert IEEE double precision (8 byte) floating point
+; to a QLFLOAT_t.
+}
+ { pointer to qlfloat is in a0 }
+ move.l (a1),d0 { high long of IEEE double }
+
+{ SNG - avoid loading low part for now so we can treat D1 as temporary }
+
+ add.l d0,d0 { Put sign bit in carry }
+ lsr.l #1,d0 { put zero where sign was }
+ bne @notzero { not zero }
+ move.l 4(a1),d1 { Test low bits too (probably zero!) }
+ bne @notzero
+
+{ here the double was a signed zero - set the QLFLOAT_t and return }
+
+ move.w d1,(a0)+ { We know that D1 is 0 at this point }
+ bra @positive
+
+{ was not zero - do manipulations }
+
+@notzero:
+ move.l d0,d1 { set non-signed high part copy }
+{ We are going to lose least significant byte so we
+; can afford to over-write it. We can thus take
+; advantage that the shift size when specified in
+; a register is modulo 64 }
+ move.b #20,d0 { shift amount for exponent }
+ lsr.l d0,d0 { get exponent - tricky but it works! }
+ add.w #$402,d0 { adjust to QLFLOAT_t exponent }
+ move.w d0,(a0)+ { set QLFLOAT_t exponent }
+
+{ now deal with mantissa }
+
+ and.l #$fffff,d1 { get top 20 mantissa bits }
+ or.l #$100000,d1 { add implied bit }
+ moveq #10,d0 { shift amount ;; save another 2 code bytes }
+ lsl.l d0,d1 { shift top 21 bits into place }
+
+ move.l 4(a1),d0 { get less significant bits }
+
+{ We are going to lose least significant byte so we
+; can afford to over-write it. We can thus take
+; advantage that the shift size when specified in
+; a register is modulo 64 }
+ move.b #22,d0 { amount to shift down low long: not MOVEQ! }
+ lsr.l d0,d0 { position low 10 bits of mantissa }
+ or.l d0,d1 { D1 now positive mantissa }
+
+@lowzer:
+ tst.b (a1) { Top byte of IEEE argument }
+ bpl @positive { No need to negate if positive }
+ neg.l d1 { Mantissa in D1 now }
+@positive:
+ move.l d1,(a0) { put mantissa in QLFLOAT_t }
+ subq.l #2,a0 { correct for return address }
+ move.l a0,d0 { set return value as original QLFLOAT_t address }
+end;
+
+end.