LIST C,P ; For Z1 assembler, generates .COM file ; directly in a single pass. ; ; revised 9-2-87: IEEE revised format notes 24 Oct 1986 ; ; by Neil R. Koozer ; Kellogg Star Rt. Box 125 ; Oakland, OR 97462 ; ; This code is hereby released to the public domain for unrestricted ; usage. The only thing you may not do is to copyright it as your own ; or restrict its unlimited usage in any way. ; ; This file assembles under Z1.COM (public domain assembler). To assem- ; ble, type: ; B>Z1 ZMATH ; ; The 2-character symbols starting with $ are psuedo-labels used in the ; single-pass assembler Z1.COM. The psuedo-labels $A thru $Z are re- ; usable local labels for forward references only. $_ is similar but ; with a nesting behavior. The rest of the psuedo-labels ($1, $@, etc) ; are for backward references only. ; ; The three principal routines, MULT, DIV, and SQRT, illustrate fast Z80 ; code for double precision floating point operations. These routines ; use more memory than is customary in order to achieve high speed. The ; example drivers at the end of this file illustrate how to call the ; floating point routines. ; ; revised IEEE double precision format (8 bytes): ; ; byte 0 low exponent (bias 03FFh) ; byte 1, bits 0 to 2 high exponent (bias 03FFfh), 11 bit exponent ; bits 3 to 7 least significant mantissa ; byte 2 lleast significant+1 mantissa ; ... increasingly significant mantissi ; byte 7, bits 0 to 6 most significant mantissa, implicit (base 2) 0.1 ; assumed ; bit 7 sign bit ; ; 15 or 16 decimal digits precision ; range: 4.19 * 10^-307 <= n <= 1.67 * 10^+308 ; ;examples: ; 0 all 64 bits 0 ; 1 00 04 00 00 00 00 00 00 ; -1 00 04 00 00 00 00 00 80 ; +2 01 04 00 ... ; -2 01 04 00 00 00 00 00 80 ; +3 01 04 00 00 00 00 00 40 ; -3 01 04 00 00 00 00 00 c0 ; 4 02 04 00 ... ; 5 02 04 00 00 00 00 00 20 ; 6 02 04 00 00 00 00 00 40 ; 7 02 04 00 00 00 00 00 60 ; 8 03 04 00 ... ; 9 03 04 00 00 00 00 00 10 ; 10 03 04 00 00 00 00 00 20 ; ; ORG 100H ; OPER1 DW 0 ; Force the following DS's to be stored DS 6 ; in the .COM file OPER2 DS 8 RESULT DS 8 SIGN DS 1 NORM DS 1 SAVESP DS 2 ; The routines MUL8, MUL16, MUL32, DIV8, DIV16, DIV32, and DIV56 are for ; multiplying and dividing binary fractions (as opposed to binary ; integers). ; MUL8 XOR A ; H = H * D LD B,8 ; $1 RR H JR NC,$A ADD A,D ; $A RRA DJNZ $1 LD H,A RET NC INC H ; Round RET ; MUL16 LD C,H ; HL = HL * DE LD A,L LD HL,0 CALL $+4 LD A,C ; M1 LD B,8 ; $1 RRA JR NC,$+3 ADD HL,DE RR H RR L DJNZ $1 RET NC INC HL ; Round RET ; MUL32 LD C,H ; HL,HL' = HL,HL' * DE,DE' LD A,L EX AF,AF' LD HL,0 EXX LD C,H LD A,L LD HL,0 EXX CALL M1 EXX LD A,C EXX CALL $_ EX AF,AF' CALL $_ LD A,C ; $_ LD B,8 ; $2 RRA JR NC,$A EXX ADD HL,DE EXX ADC HL,DE ; $A RR H RR L EXX RR H RR L EXX DJNZ $2 RET NC EXX INC L JR NZ,$A INC H ; $A EXX RET NZ INC HL RET ; $1 SUB D ; $2 SCF DEC B RET Z ; D1 RL C ADD A,A JR C,$1 SUB D JR NC,$2 ADD A,D OR A DJNZ D1 RET ; DIV8 LD A,H ; H = H / D LD B,9 CALL D1 LD H,C RET NC INC H ; Rounding RET ; $1 OR A SBC HL,DE ; $2 SCF DEC B RET Z ; D2 RLA ADD HL,HL JR C,$1 SBC HL,DE JR NC,$2 ADD HL,DE OR A DJNZ D2 RET ; DIV16 LD B,9 ; HL = HL / DE CALL D2 LD C,A LD B,3 CALL D2 LD L,C LD C,A LD A,H LD H,L LD B,5 CALL D1 LD L,C RET NC INC HL ; Rounding RET ; $1 OR A ; $2 EXX SBC HL,DE ; $3 EXX SBC HL,DE SCF DEC B RET Z ; D4 RL C EXX ADD HL,HL EXX ADC HL,HL JR C,$1 LD A,H CP D JR C,$_ JP NZ,$2 LD A,L CP E JR C,$_ JR NZ,$2 EXX SBC HL,DE JR NC,$3 ADD HL,DE EXX ; $_ OR A DJNZ D4 RET DIV32 LD B,9 ; HL,HL' = HL,HL' / DE,DE' CALL D4 DB 0FDH LD H,C LD B,8 CALL D4 DB 0FDH LD B,H PUSH BC LD B,3 CALL D4 LD A,C LD B,5 CALL D2 EXX LD H,A EXX LD B,3 CALL D2 LD C,A LD A,H LD B,5 CALL D1 POP HL LD A,C EXX LD L,A JR C,$A ; $1 EXX RET ; $A INC L ; Rounding JR NZ,$1 INC H EXX RET NZ INC HL RET ; $1 EXX ; $2 LD A,B DB 0FDH SUB H ; $3 LD B,A SBC HL,DE EXX SBC HL,DE SCF DEC B RET Z ; D5 RL C EXX SLA B ADC HL,HL EXX ADC HL,HL JR C,$1 LD A,H ; Do a compare to see if we should subtract CP D JR C,$_ JP NZ,$1 LD A,L CP E JR C,$_ JR NZ,$1 EXX LD A,H CP D JR C,$_ JR NZ,$2 LD A,L CP E JR C,$_ JR NZ,$2 LD A,B DB 0FDH SUB H JR NC,$3 ; $_ EXX ; $_ OR A DJNZ D5 RET ; $1 EXX ; $2 LD A,C DB 0FDH SUB L ; $3 LD C,A LD A,B DB 0FDH SBC A,H LD B,A SBC HL,DE EXX SBC HL,DE SCF DEC B RET Z ; D6 RL C ; Do a left shift EXX SLA C RL B ADC HL,HL EXX ADC HL,HL JR C,$1 LD A,H ; Do a compare to see if we should subtract CP D JR C,$_ JP NZ,$1 LD A,L CP E JR C,$_ JR NZ,$1 EXX LD A,H CP D JR C,$_ JR NZ,$2 LD A,L CP E JR C,$_ JR NZ,$2 LD A,B DB 0FDH CP H JR C,$_ JR NZ,$2 LD A,C DB 0FDH SUB L JR NC,$3 ; $_ $_ $_ EXX ; $_ $_ OR A DJNZ D6 RET ; $2 EXX ; $1 LD A,C SUB B ; $3 LD C,A EXX LD A,C DB 0FDH SBC A,L LD C,A LD A,B DB 0FDH SBC A,H LD B,A SBC HL,DE EXX SBC HL,DE EX AF,AF' SCF RET ; D7_8 CALL $+3 CALL $+3 CALL $+3 ; D7_1 RLA EX AF,AF' SLA C EXX RL C RL B ADC HL,HL EXX ADC HL,HL JR C,$1 ; COMP LD A,H ; Do a compare to see if we should subtract CP D JR C,$_ JP NZ,$1 LD A,L CP E JR C,$_ JR NZ,$1 EXX LD A,H CP D JR C,$_ JR NZ,$2 LD A,L CP E JR C,$_ JR NZ,$2 LD A,B DB 0FDH CP H JR C,$_ JR NZ,$2 LD A,C DB 0FDH CP L JR C,$_ JR NZ,$2 EXX LD A,C SUB B JR NC,$3 EXX ; $_ $_ $_ $_ EXX ; $_ $_ EX AF,AF' OR A RET ; RSHIFT SRL H RR L EXX RR H RR L RR B RR C EXX RR C RET ; DIV56 EQU $ ; HL,HL',BC',C = HL,HL',BC',C / DE,DE',IY,B ; CALL D7_1 ; Divisor is preserved ; DIV55 PUSH BC ; Save divisor lsbyte CALL D7_8 DB 0DDH LD H,A LD B,8 CALL D6 DB 0DDH LD L,C PUSH IX LD B,8 CALL D5 DB 0DDH LD H,C LD B,8 CALL D4 DB 0DDH LD L,C PUSH IX LD B,8 CALL D4 DB 0DDH LD H,C LD B,8 CALL D2 DB 0DDH LD L,A LD A,H LD B,8 CALL D1 EXX DB 0DDH LD C,L DB 0DDH LD B,H POP HL EXX POP HL LD A,C POP BC ; Restore divisor lsbyte LD C,A RET NC INC C ; Rounding RET NZ ; RIPPLE EXX INC C JR Z,$A ; $1 EXX RET ; $A INC B JR NZ,$1 INC L JR NZ,$1 INC H EXX RET NZ INC L RET NZ INC H RET ; DOVER LD A,7FH DB 0FEH ; DUNDER XOR A LD B,A LD A,(SIGN) OR B LD (IX+7),A RLA SRA A PUSH IX POP HL LD B,7 ; $1 LD (HL),A INC HL DJNZ $1 RET ; ; Floating point divide, 53-bit mantissa, 11-bit exponent ; DIV LD A,(DE) ; Dividend exponent lo INC DE SUB (HL) ; Divisor exponent lo INC HL DB 0FDH LD L,A EX AF,AF' ;save carry flag LD A,(HL) ; Divisor exponent hi AND 7 LD B,A LD A,(DE) ; Dividend exponent hi AND 7 LD C,A EX AF,AF' ;retrieve carry flag LD A,C SBC A,B DB 0FDH LD H,A PUSH IY ; Save exponent LD A,(DE) ; ;dividend mantissa ls 5 bits INC DE AND 0F8H LD C,A LD A,(HL) ; ;divisor mantissa ls 5 bits INC HL AND 0F8H LD B,A LD (SAVESP),SP LD SP,HL EX DE,HL POP IY ; Now get rest of divisor mantissa EXX POP DE EXX POP DE LD SP,HL EXX ; Now get rest of dividend mantissa POP BC POP HL EXX POP HL LD SP,(SAVESP) LD A,D ; Sign of divisor XOR H ; Sign of dividend AND 80H ; Clean the sign bit LD (SIGN),A ; Sign of result SET 7,D ; Make the implicit 1 explicit SET 7,H ; Ditto ; ; Begin the divide ; CALL COMP RLA LD (NORM),A ; Save normalization flag RRA JR C,$A CALL D7_1 ; $A PUSH IX CALL DIV55 POP IX LD A,C ADD A,4 ; Rounding bit LD C,A LD DE,400H ; Exponent correction JR NC,$A CALL RIPPLE ; Do ripple carry because of rounding JR NZ,$B ; Norm flag (no right shift needed INC DE ; because it's all 0's) ; $A $B RES 7,H ; Remove msbit LD A,(SIGN) OR H ; Append sign bit LD (IX+7),A LD (IX+6),L POP HL ; Exponent ADD HL,DE LD A,(NORM) RRA JR C,$A DEC HL ; $A BIT 7,H JP NZ,DUNDER ; Negative means underflow BIT 3,H ; See if overflow JP NZ,DOVER LD A,C ; Get lsbyte AND 0F8H OR H ; Append 3 hi bits of exponent LD (IX+1),A LD (IX+0),L EXX LD (IX+2),C LD (IX+3),B LD (IX+4),L LD (IX+5),H EXX RET ; MAXDE LD DE,0FFFFH EXX LD DE,0FFFFH EXX RET ; MAXHL LD HL,0FFFFH EXX LD HL,0FFFFH LD B,H LD C,L EXX LD C,H RET ; SQRT LD (SAVESP),SP ; Floating point square root, 53-bit LD SP,HL ; mantissa, 11-bit exponential POP BC EXX POP BC POP HL EXX POP HL LD SP,(SAVESP) PUSH DE ; Dest. addr. LD D,B ; Save mantissa lo byte LD A,B ; Get exponent hi byte AND 7 ; Clean exponent ADD A,4 ; Fix offset RRA ; Divide by 2 RR C ; Carry = 'odd exp.' LD B,A PUSH BC ; Save exponent EX AF,AF' ;save 'EXP ODD' flag LD A,D ; Get mantissa lsb AND 0F8H LD C,A SET 7,H ; Make the implicit 1 explicit CALL RSHIFT ; HalfX EX AF,AF' LD D,0D7H ; Y seed = 1.68... JR C,$A CALL RSHIFT LD D,98H ; Y seed = 1.189... ; $A PUSH BC PUSH HL CALL DIV8 ; H = halfX / Y SRL D ; D = Y / 2 LD A,H ADD A,D LD D,A ; D = new Y CALL C,MAXDE POP HL PUSH HL ; HL = halfX CALL DIV16 ; HL = halfX / Y SRL D RR E ; DE = Y/2 ADD HL,DE EX DE,HL ; DE = new Y CALL C,MAXDE POP HL PUSH HL EXX PUSH HL EXX CALL DIV32 ; HL,HL' = halfX / Y SRL D RR E EXX RR D RR E ; DE,DE' = Y/2 ADD HL,DE EX DE,HL POP HL EXX ADC HL,DE EX DE,HL ; DE,DE' = new Y CALL C,MAXDE POP HL POP BC CALL DIV56 SRL D RR E EXX RR D RR E DB 0FDH LD A,H RRA DB 0FDH LD H,A DB 0FDH LD A,L RRA DB 0FDH LD L,A EXX LD A,B RRA ADD A,C LD C,A EXX LD A,C DB 0FDH ADC A,L LD C,A LD A,B DB 0FDH ADC A,H LD B,A ADC HL,DE EXX ADC HL,DE CALL C,MAXHL LD A,C ADD A,4 ; Rounding LD C,A CALL C,RIPPLE CALL Z,MAXHL RES 7,H LD A,C POP BC ; Exponent AND 0F8H OR B LD B,A EX DE,HL POP HL ; Dest. addr. LD SP,HL PUSH DE EXX PUSH HL PUSH BC EXX PUSH BC LD SP,(SAVESP) RET ; M7_8 CALL $A ; M7_7 CALL $B CALL $+6 CALL $+3 CALL $+3 ; $B $A RRA JR NC,$A ; M7_0 EX AF,AF' LD A,C ADD A,B LD C,A EXX LD A,C DEFB 0FDH ADC A,L LD C,A LD A,B DEFB 0FDH ADC A,H LD B,A ADC HL,DE EXX ADC HL,DE ; M72 RR H RR L EXX RR H RR L RR B RR C EXX RR C EX AF,AF' RET ; $A SRL H RR L EXX RR H RR L RR B RR C EXX RR C RET ; M4 LD B,8 ; $1 RRA JR NC,$A EXX ADD HL,DE EXX ADC HL,DE ; $A RR H RR L EXX RR H RR L EXX DJNZ $1 RET ; UNDER LD A,D AND 80H JR $A ; OVER LD A,D OR 7FH ; $A POP HL ; Destination address DEC HL LD (HL),A RLA SRA A LD B,7 ; $1 DEC HL LD (HL),A DJNZ $1 RET ; MULT PUSH DE ; Floating point multiply, 53-bit LD (SAVESP),SP ; mantissa, 11-bit exponential LD SP,HL LD L,(IX+0) LD A,(IX+1) AND 7 LD H,A POP BC LD E,C LD A,B AND 7 LD D,A ADD HL,DE ; New exponent EXX POP IY POP DE EXX POP DE LD SP,(SAVESP) PUSH HL LD A,B AND 0F8H LD B,A LD A,(IX+7) XOR D AND 80H LD (SIGN),A SET 7,D ; Make implicit 1 explicit ; ; Zero the accumulator ; XOR A LD C,A EXX LD C,A LD B,A LD L,A LD H,A EXX LD L,A PUSH BC LD A,(IX+1) RRA RRA RRA LD H,A XOR A LD B,5 ; $1 RR H JR NC,$+3 ADD A,D RRA DJNZ $1 LD H,A LD A,(IX+2) LD B,8 ; $1 RRA JR NC,$+3 ADD HL,DE RR H RR L DJNZ $1 LD A,(IX+3) CALL M4 LD A,(IX+4) CALL M4 LD C,(IX+5) LD B,8 ; $1 RR C JR NC,$A EXX LD A,B DEFB 0FDH ADD A,H LD B,A ADC HL,DE EXX ADC HL,DE ; $A RR H RR L EXX RR H RR L RR B EXX DJNZ $1 LD C,(IX+6) LD B,8 ; $1 RR C JR NC,$A EXX LD A,C DEFB 0FDH ADD A,L LD C,A LD A,B DEFB 0FDH ADC A,H LD B,A ADC HL,DE EXX ADC HL,DE ; $A RR H RR L EXX RR H RR L RR B RR C EXX DJNZ $1 POP BC LD A,(IX+7) CALL M7_7 CALL M7_0 ; Skip the test because ms bit is always 1 LD B,1 ; Normalization counter BIT 7,H JR NZ,$A DEC B ; ; Shift left to normalize ; SLA C EXX RL C RL B ADC HL,HL EXX ADC HL,HL ; $A LD A,4 ; Round it to 53-bit precision instead ADD A,C ; of truncating LD C,A JR NC,$_ CALL RIPPLE JR NZ,$_ INC B ; Right shift not needed because it's all 0's ; $_ $_ EX DE,HL LD HL,SIGN LD A,D AND 7FH OR (HL) LD D,A LD A,C AND 0F8H LD H,A LD A,B ; Norm flag POP BC ; Get exponent ADD A,C ; Correct for norm. LD C,A LD A,0FCH ; Fix offset ADC A,B JP NC,UNDER BIT 3,A JP NZ,OVER OR H LD B,A POP HL ; Dest. addr. LD (SAVESP),SP LD SP,HL PUSH DE EXX PUSH HL PUSH BC EXX PUSH BC LD SP,(SAVESP) RET ; ; A driver to do 1000 multiplies for timing purposes ; MULTEST LD BC,1000 ; $1 PUSH BC ; ; Here is a segment which represents compiled code for a high level ; ; Statement like a = b * c ; LD IX,OPER1 ; Address of one operand LD HL,OPER2 ; Address of other operand LD DE,RESULT+8 CALL MULT POP BC DEC BC LD A,B OR C JR NZ,$1 RET ; ;Here is a driver to do 1000 divides for timing purposes ; DIVTEST LD BC,1000 ; $1 PUSH BC ; ; Here is a segment which represents compiled code for a high level ; ; Statement like a = b / c ; LD DE,OPER1 ; Addr of dividend LD HL,OPER2 ; Addr of divisor LD IX,RESULT CALL DIV POP BC DEC BC LD A,B OR C JR NZ,$1 RET ; ; Here is an empty loop for comparison. It loops 65536 times. ; EMPTY LD BC,0 ; $1 PUSH BC POP BC DEC BC LD A,B OR C JR NZ,$1 RET ; ; Here is a driver to do 1000 square roots for timing purposes ; SQRTTEST EQU $ ; LD BC,1000 ; $1 PUSH BC ; ; Here is a segment which represents compiled code for a high level ; ; Statement like a = sqrt(b) ; LD HL,OPER2 ; Address of operand LD DE,RESULT+8 CALL SQRT POP BC DEC BC LD A,B OR C JR NZ,$1 RET ; ; END