Start work on floating point library for calculator.asm

This commit is contained in:
Juhani Krekelä 2022-09-15 03:49:03 +03:00
parent bafaef9c44
commit 37f487ae3f
1 changed files with 561 additions and 0 deletions

View File

@ -1,5 +1,18 @@
org 0
cleq r0, r0, normalize
load r0, fResultPtr+0
load r1, fResultPtr+1
cleq r0, r0, pushWord
cleq r0, r0, fPack
cleq r0, r0, fPrint
cleq r0, r0, newline
halt
cleq r0, r0, readline
load r0, linelen+0
@ -227,6 +240,467 @@ readline:
store ffff, r3
breq r0, r0, readlineLoop
; ==================================================================
; Floating point
; ==================================================================
; ------------------------------------------------------------------
; Format conversion
; ------------------------------------------------------------------
; When on-stack, a floating point number uses an 8-byte packed BCD format
; 0 1 2 3 4 5 6 7
; seee mmmm mmmm mmmm
; |\_/ \____________/
; | | |
; | | mantissa, first digit being before and rest after the point
; | exponent, with a bias of 500 (i.e. value of 0 means ×10⁻⁵⁰⁰)
; sign, 00 for non-negative, 01 for negative, 02 for overflow
; For operation, the format is instead an 18-byte unpacked BCD format
; 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11
; 0s 0e 0e 0e 0o 0m 0m 0m 0m 0m 0m 0m 0m 0m 0m 0m 0m 0r
; | \______/ | \_________________________________/ |
; | | | | extra digit for rounding
; | | | mantissa
; | | extra digit for overflow
; | exponent
; sign
; f ptr --
fUnpack:
; Start from the end
xor r0, r0
load r1, #11
cleq r0, r0, pushWord
cleq r0, r0, stAdd
; Zero out rounding digit
xor r0, r0
xor r1, r1
cleq r0, r0, pushWord
cleq r0, r0, stOver
cleq r0, r0, stStoreByte
cleq r0, r0, stDec
; Mantissa
cleq r0, r0, fUnpackWord
cleq r0, r0, fUnpackWord
cleq r0, r0, fUnpackWord
; Zero out overflow digit
xor r0, r0
xor r1, r1
cleq r0, r0, pushWord
cleq r0, r0, stOver
cleq r0, r0, stStoreByte
cleq r0, r0, stDec
; Sign and exponent
cleq r0, r0, fUnpackWord
; Clear off the pointer from the stack
breq r0, r0, popWord
; w ptr -- ptr-4
fUnpackWord:
; Low nybble of low byte
cleq r0, r0, stOver
cleq r0, r0, stLowNybble
cleq r0, r0, stOver
cleq r0, r0, stStoreByte
cleq r0, r0, stDec
; High nybble of low byte
cleq r0, r0, stOver
cleq r0, r0, stShr4
cleq r0, r0, stLowNybble
cleq r0, r0, stOver
cleq r0, r0, stStoreByte
cleq r0, r0, stDec
; Low nybble of high byte
cleq r0, r0, stOver
cleq r0, r0, stShr8
cleq r0, r0, stLowNybble
cleq r0, r0, stOver
cleq r0, r0, stStoreByte
cleq r0, r0, stDec
; High nybble of high byte
cleq r0, r0, stSwap ; Clear off the word from the stack
cleq r0, r0, stShr8
cleq r0, r0, stShr4
cleq r0, r0, stLowNybble
cleq r0, r0, stOver
cleq r0, r0, stStoreByte
cleq r0, r0, stDec
ret
; ptr -- f
fPack:
; Sign and exponent
cleq r0, r0, fPackWord
; Skip over the overflow digit
cleq r0, r0, stInc
; Mantissa
cleq r0, r0, fPackWord
cleq r0, r0, fPackWord
cleq r0, r0, fPackWord
; Clean off the pointer from stack
breq r0, r0, popWord
; ptr -- w ptr+4
fPackWord:
; High nybble of high byte
cleq r0, r0, stDup
cleq r0, r0, stLoadByte
cleq r0, r0, stShl8
cleq r0, r0, stShl4
cleq r0, r0, stSwap
cleq r0, r0, stInc
cleq r0, r0, stSwap
; Low nybble of high byte
cleq r0, r0, stOver
cleq r0, r0, stLoadByte
cleq r0, r0, stShl8
cleq r0, r0, stOr
cleq r0, r0, stSwap
cleq r0, r0, stInc
cleq r0, r0, stSwap
; High nybble of low byte
cleq r0, r0, stOver
cleq r0, r0, stLoadByte
cleq r0, r0, stShl4
cleq r0, r0, stOr
cleq r0, r0, stSwap
cleq r0, r0, stInc
cleq r0, r0, stSwap
; Low nybble of low byte
cleq r0, r0, stOver
cleq r0, r0, stLoadByte
cleq r0, r0, stOr
cleq r0, r0, stSwap
cleq r0, r0, stInc
ret
; ------------------------------------------------------------------
; Unpacked floating point variables
; ------------------------------------------------------------------
fArg1Ptr: addr fArg1
fArg1:
data 00 ; sign
data 00 ; exponent
data 00
data 00
data 00 ; overflow
data 00 ; mantissa
data 00
data 00
data 00
data 00
data 00
data 00
data 00
data 00
data 00
data 00
data 00
data 00 ; rounding
fResultPtr: addr fResult
fResult:
data 01 ; sign
data 04 ; exponent
data 09
data 09
data 00 ; overflow
data 01 ; mantissa
data 00
data 00
data 00
data 00
data 00
data 00
data 00
data 00
data 00
data 00
data 01
data 00 ; rounding
; ------------------------------------------------------------------
; Arithmetic
; ------------------------------------------------------------------
; x y -- tens(x+y) ones(x+y)
bcdDigitAdd:
cleq r0, r0, stAdd
cleq r0, r0, stDup
xor r0, r0
load r1, #a
cleq r0, r0, pushWord
cleq r0, r0, stGtEq
breq r0, r1, bcdDigitAddNoAdjust
; Adjust so that carry is in the high nybble
; Basically we want 9+1=a₁₆ to become 10₁₆
xor r0, r0
load r1, #6
cleq r0, r0, pushWord
cleq r0, r0, stAdd
bcdDigitAddNoAdjust:
cleq r0, r0, stDup
cleq r0, r0, stShr4
cleq r0, r0, stSwap
breq r0, r0, stLowNybble
; x -- 9-x
bcdDigit9sComplement:
xor r0, r0
load r1, #9
cleq r0, r0, pushWord
cleq r0, r0, stSwap
breq r0, r0, stSub
; --
normalize:
; Is extended mantissa all zeroes?
load r0, fResult+4
load r1, fResult+5
or r0, r1
load r1, fResult+6
or r0, r1
load r1, fResult+7
or r0, r1
load r1, fResult+8
or r0, r1
load r1, fResult+9
or r0, r1
load r1, fResult+a
or r0, r1
load r1, fResult+b
or r0, r1
load r1, fResult+c
or r0, r1
load r1, fResult+d
or r0, r1
load r1, fResult+e
or r0, r1
load r1, fResult+f
or r0, r1
load r1, fResult+10
or r0, r1
load r1, fResult+11
or r0, r1
xor r1, r1
breq r0, r1, normalizeZero
; XXX: Implement rest
ret
normalizeZero:
; Zero out the entire number
; This causes sign to be 0 (non-negative), exponent -500, and
; extended mantissa 00.000000000000
load r0, fResultPtr+0
load r1, fResultPtr+1
cleq r0, r0, pushWord
xor r0, r0
load r1, #12
cleq r0, r0, pushWord
breq r0, r0, stZeroMem
; ------------------------------------------------------------------
; Output
; ------------------------------------------------------------------
fPrint:
load r0, fArg1Ptr+0
load r1, fArg1Ptr+1
cleq r0, r0, pushWord
cleq r0, r0, fUnpack
; Overflow?
load r0, fArg1+0
load r1, #2
breq r0, r1, fPrintOverflow
; Negative?
load r1, #1
brneq r0, r1, fPrintMantissa
load r0, #2d ; -
store ffff, r0
fPrintMantissa:
load r0, fArg1+5
cleq r0, r0, writehexNybble
load r0, #2e ; .
store ffff, r0
load r0, fArg1+6
cleq r0, r0, writehexNybble
load r0, fArg1+7
cleq r0, r0, writehexNybble
load r0, fArg1+8
cleq r0, r0, writehexNybble
load r0, fArg1+9
cleq r0, r0, writehexNybble
load r0, fArg1+a
cleq r0, r0, writehexNybble
load r0, fArg1+b
cleq r0, r0, writehexNybble
load r0, fArg1+c
cleq r0, r0, writehexNybble
load r0, fArg1+d
cleq r0, r0, writehexNybble
load r0, fArg1+e
cleq r0, r0, writehexNybble
load r0, fArg1+f
cleq r0, r0, writehexNybble
load r0, fArg1+10
cleq r0, r0, writehexNybble
fPrintExponent:
load r0, #65 ; e
store ffff, r0
; Adjust the hundreds digit for the bias
xor r0, r0,
load r1, fArg1+1
cleq r0, r0, pushWord
xor r0, r0
load r1, #5
cleq r0, r0, pushWord
cleq r0, r0, bcdDigitAdd
; Is the exponent negative?
cleq r0, r0, stSwap
cleq r0, r0, popWord
breq r0, r1, fPrintNegativeExponent
cleq r0, r0, popWord
xor r0, r0
or r0, r1
cleq r0, r0, writehexNybble
load r0, fArg1+2
cleq r0, r0, writehexNybble
load r0, fArg1+3
cleq r0, r0, writehexNybble
ret
fPrintNegativeExponent:
cleq r0, r0, popWord ; Remove result we don't need
load r0, #2d ; -
store ffff, r0
; The exponent is stored with a bias of 500
; unbiased + 500 = biased
; By this point we know unbiased < 0 and have printed the minus
; sign, so we want to print the negative of unbiased
; unbiased + 500 = biased
; unbiased = -500 + biased
; -unbiased = 500 - biased
; We implement subtraction using 9's complement, where each
; digit of the subtrahend is subtracted from 9 before being
; added to the corresponding minuend. This by itself gives a
; result that is one too small, so we add one to it (c.f. binary
; subtraction, where we negate the subtrahend and then add one).
; Normally we'd have to split subtraction into two rounds, one
; to add the complemented subtrahend and one to add the 1, but
; since our minuend is a constant, we can add 1 to it instead.
; 501 + 999 - biased
; = 500 + 1 + 999 - biased
; = 500 + 1000 - biased (1000 = 0 mod 1000)
; = 500 - biased
; Ones
xor r0, r0
load r1, #1
cleq r0, r0, pushWord
xor r0, r0
load r1, fArg1+3
cleq r0, r0, pushWord
cleq r0, r0, bcdDigit9sComplement
cleq r0, r0, bcdDigitAdd
cleq r0, r0, stSwap
; Tens
xor r0, r0
load r1, fArg1+2
cleq r0, r0, pushWord
cleq r0, r0, bcdDigit9sComplement
cleq r0, r0, bcdDigitAdd
cleq r0, r0, stSwap
; Hundreds
xor r0, r0
load r1, #5
cleq r0, r0, pushWord
cleq r0, r0, bcdDigitAdd
cleq r0, r0, stSwap
cleq r0, r0, popWord
xor r0, r0
load r1, fArg1+1
cleq r0, r0, pushWord
cleq r0, r0, bcdDigit9sComplement
cleq r0, r0, bcdDigitAdd
cleq r0, r0, stSwap
cleq r0, r0, popWord
; Print
cleq r0, r0, popWord
xor r0, r0
or r0, r1
cleq r0, r0, writehexNybble
cleq r0, r0, popWord
xor r0, r0
or r0, r1
cleq r0, r0, writehexNybble
cleq r0, r0, popWord
xor r0, r0
or r0, r1
cleq r0, r0, writehexNybble
ret
fPrintOverflow:
load r0, #4f ; O
store ffff, r0
load r0, #76 ; v
store ffff, r0
load r0, #65 ; e
store ffff, r0
load r0, #72 ; r
store ffff, r0
load r0, #66 ; f
store ffff, r0
load r0, #6c ; l
store ffff, r0
load r0, #6f ; o
store ffff, r0
load r0, #77 ; w
store ffff, r0
ret
; ==================================================================
; Stack-based functions
; ==================================================================
@ -265,6 +739,62 @@ stDec:
cleq r0, r0, decWord
breq r0, r0, pushWord
; a b -- a|b
stOr:
cleq r0, r0, popWord
cleq r0, r0, tmpStoreWord01
cleq r0, r0, popWord
cleq r0, r0, tmpLoadWord23
or r0, r2
or r1, r3
breq r0, r0, pushWord
; a -- a<<8
stShl8:
cleq r0, r0, popWord
xor r0, r0
or r0, r1
xor r1, r1
breq r0, r0, pushWord
; a -- a>>8
stShr8:
cleq r0, r0, popWord
xor r1, r1
or r1, r0
xor r0, r0
breq r0, r0, pushWord
; a -- a<<4
stShl4:
cleq r0, r0, popWord
shl r0, 4
xor r2, r2
or r2, r1
shr r2, 4
or r0, r2
shl r1, 4
breq r0, r0, pushWord
; a -- a>>4
stShr4:
cleq r0, r0, popWord
shr r1, 4
xor r2, r2
or r2, r0
shl r2, 4
or r1, r2
shr r0, 4
breq r0, r0, pushWord
; a -- a&f
stLowNybble:
cleq r0, r0, popWord
xor r0, r0
load r2, #f
and r1, r2
breq r0, r0, pushWord
; a b --
; if a >= b then r0:r1 = 0001
; else r0:r1 = 0000
@ -393,6 +923,28 @@ stLoadWord:
or r1, r2
breq r0, r0, pushWord
; ptr n --
stZeroMem:
cleq r0, r0, peekWord
or r0, r1
xor r2, r2
breq r0, r2, stZeroMemDone
cleq r0, r0, stDec
cleq r0, r0, stSwap
cleq r0, r0, stDup
xor r0, r0
xor r1, r1
cleq r0, r0, pushWord
cleq r0, r0, stSwap
cleq r0, r0, stStoreByte
cleq r0, r0, stInc
cleq r0, r0, stSwap
breq r0, r0, stZeroMem
stZeroMemDone:
ret
; ==================================================================
; Low-level functions
; ==================================================================
@ -981,6 +1533,15 @@ writehexByte:
ret
; in:
; r0 = nybble
; clobbers:
; r3
writehexNybble:
cleq r0, r0, nybble2hex
store ffff, r0
ret
; ------------------------------------------------------------------
; Common output routines
; ------------------------------------------------------------------