Start work on floating point library for calculator.asm
This commit is contained in:
parent
bafaef9c44
commit
37f487ae3f
561
calculator.asm
561
calculator.asm
|
@ -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
|
||||
; ------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue