Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
aaf780179This file is pinned to the selected release. Download the original to open it in your design tool.
;
;;=============================================================================
;; The collection of math related functions starts here
;;=============================================================================
;
;******************************************************************************
;*
;* MTH$MULS performs a signed 16 x 16 multiplication of the form
;* R11(H)/R10(L) = R8 * R9. It is merely an interface to the EAE.
;*
;******************************************************************************
;
MTH$MULS INCRB
MOVE IO$EAE_OPERAND_0, R0
MOVE R8, @R0++ ; R0 now points to OPERAND_1
MOVE R9, @R0
MOVE IO$EAE_CSR, R0
MOVE EAE$MULS, @R0
#ifndef EAE_NO_WAIT
_MTH$MULS_BUSY MOVE @R0, R1 ; Test busy bit
AND 0x8000, R1
RBRA _MTH$MULS_BUSY, !Z ; Still busy, wait...
#endif
MOVE IO$EAE_RESULT_LO, R0
MOVE @R0++, R10
MOVE @R0, R11
DECRB
RET
;
;******************************************************************************
;*
;* MTH$MULU performs an unsigned 16 x 16 multiplication of the form
;* R11(H)/R10(L) = R8 * R9. It is merely an interface to the EAE.
;*
;******************************************************************************
;
MTH$MULU INCRB
MOVE IO$EAE_OPERAND_0, R0
MOVE R8, @R0++ ; R0 now points to OPERAND_1
MOVE R9, @R0
MOVE IO$EAE_CSR, R0
MOVE EAE$MULU, @R0
#ifndef EAE_NO_WAIT
_MTH$MULU_BUSY MOVE @R0, R1 ; Test busy bit
AND 0x8000, R1
RBRA _MTH$MULU_BUSY, !Z ; Still busy, wait...
#endif
MOVE IO$EAE_RESULT_LO, R0
MOVE @R0++, R10
MOVE @R0, R11
DECRB
RET
;
;******************************************************************************
;*
;* MTH$DIVS performs a signed 16 / 16 division of the form
;* R11 = R8 % R9 and R10 = (int) (R8 / 10)
;*
;******************************************************************************
;
MTH$DIVS INCRB
MOVE IO$EAE_OPERAND_0, R0
MOVE R8, @R0++ ; R0 now points to OPERAND_1
MOVE R9, @R0
MOVE IO$EAE_CSR, R0
MOVE EAE$DIVS, @R0
#ifndef EAE_NO_WAIT
_MTH$DIVS_BUSY MOVE @R0, R1 ; Test busy bit
AND 0x8000, R1
RBRA _MTH$DIVS_BUSY, !Z ; Still busy, wait...
#endif
MOVE IO$EAE_RESULT_LO, R0
MOVE @R0++, R10
MOVE @R0, R11
DECRB
RET
;
;******************************************************************************
;*
;* MTH$DIVU performs an unsigned 16 / 16 division of the form
;* R11 = R8 % R9 and R10 = (int) (R8 / 9)
;*
;******************************************************************************
;
MTH$DIVU INCRB
MOVE IO$EAE_OPERAND_0, R0
MOVE R8, @R0++ ; R0 now points to OPERAND_1
MOVE R9, @R0
MOVE IO$EAE_CSR, R0
MOVE EAE$DIVU, @R0
#ifndef EAE_NO_WAIT
_MTH$DIVU_BUSY MOVE @R0, R1 ; Test busy bit
AND 0x8000, R1
RBRA _MTH$DIVU_BUSY, !Z ; Still busy, wait...
#endif
MOVE IO$EAE_RESULT_LO, R0
MOVE @R0++, R10
MOVE @R0, R11
DECRB
RET
;
;******************************************************************************
;* MTH$MULU32 multiplies two 32bit unsigned values and returns a 64bit unsigned
;*
;* INPUT: R8/R9 = LO/HI of unsigned multiplicant 1
;* R10/R11 = LO/HI of unsigned multiplicant 2
;* OUTPUT: R11/R10/R9/R8 = HI .. LO of 64bit result
;******************************************************************************
;
MTH$MULU32 INCRB ; registers R3..R0 = result ..
INCRB ; .. therefore two INCRBs
; save arguments as in R1|R0 * R3|R2
MOVE R8, R0
MOVE R9, R1
MOVE R10, R2
MOVE R11, R3
; algorithm:
; R1R0
; x R3R2
; ----------
; R2R0
; + R2R1
; + R3R0
; + R3R1
; ----------
MOVE R0, R8 ; R2 * R0
MOVE R2, R9
RSUB MTH$MULU, 1 ; result in R11|R10
DECRB
MOVE R10, R0
MOVE R11, R1
XOR R2, R2
XOR R3, R3
INCRB
MOVE R1, R8 ; R2 * R1
MOVE R2, R9
RSUB MTH$MULU, 1
DECRB
ADD R10, R1
ADDC R11, R2
ADDC 0, R3
INCRB
MOVE R0, R8 ; R3 * R0
MOVE R3, R9
RSUB MTH$MULU, 1
DECRB
ADD R10, R1
ADDC R11, R2
ADDC 0, R3
INCRB
MOVE R1, R8 ; R3 * R1
MOVE R3, R9
RSUB MTH$MULU, 1
DECRB
ADD R10, R2
ADDC R11, R3
MOVE R3, R11 ; store result (return values)
MOVE R2, R10
MOVE R1, R9
MOVE R0, R8
DECRB
RET
;
;******************************************************************************
;* MTH$DIVU32 divides 32bit dividend by 32bit divisor and returns
;* a 32bit quotient and a 32bit modulo
;* warning: no division by zero warning; instead, the function
;* returns zero as result and as modulo
;*
;* INPUT: R8/R9 = LO|HI of unsigned dividend
;* R10/R11 = LO|HI of unsigned divisor
;* OUTPUT: R8/R9 = LO|HI of unsigned quotient
;* R10/R11 = LO|HI of unsigned modulo
;******************************************************************************
;
MTH$DIVU32 INCRB
; perform the division by using the following algorithm, where
; N = dividend = HI|LO = R9|R8
; D = divisor = HI|LO = R11|R10
; Q = quotient = HI|LO = R1|R0
; R = remainder (modulo) = HI|LO = R3|R2
;
; Q := 0 quotient and remainder = 0
; R := 0
; for i = n-1...0 do where n is number of bits in N
; R := R << 1 left-shift R by 1 bit
; R(0) := N(i) set the least-significant bit
; of R equal to bit i of the divisor
; if R >= D then
; R := R - D
; Q(i) := 1
; end
; end
XOR R0, R0 ; HI|LO = R1|R0 = quotient
XOR R1, R1
XOR R2, R2 ; HI|LO = R3|R2 = reminder
XOR R3, R3
; division by zero
; as we have no interrupts and no additional error flag,
; we return zero on a division by zero
CMP R11, R0
RBRA _MTH$DIVU32_ST, !Z
CMP R10, R0
RBRA _MTH$DIVU32_ST, !Z
RBRA _MTH$DIVU32_END, 1
_MTH$DIVU32_ST MOVE 31, R4 ; R4 = bit counter: 31 .. 0
; R := R << 1: 32bit shift-left of R
_MTH$DIVU32_NBT AND 0xFFFD, SR ; clear X (shift in '0')
SHL 1, R2 ; MSB of lo word shifts to C
RBRA _MTH$DIVU32_SL0, !C ; C=0 => X=0
OR 0x0002, SR ; C=1 => X=1
SHL 1, R3 ; hi word (shifts in X=1)
RBRA _MTH$DIVU32_RNI, 1
_MTH$DIVU32_SL0 AND 0xFFFD, SR ; C=0 => X=0
SHL 1, R3 ; hi word (shifts in X=0)
; R(0) := N(i)
_MTH$DIVU32_RNI MOVE R4, R6
CMP R4, 15 ; R4 <= 15?
RBRA _MTH$DIVU32_RNL, !N ; yes: consider low word of R
MOVE R9, R5 ; high word of N
SUB 16, R6 ; correct index b/c of hi word
RBRA _MTH$DIVU32_RNH, 1
_MTH$DIVU32_RNL MOVE R8, R5 ; low word of N
_MTH$DIVU32_RNH AND 0xFFFB, SR ; clear C
SHR R6, R5 ; extract bit by SHR to the ..
AND 1, R5 ; ..LSB pos. and and-ing 1
AND 0xFFFE, R2 ; clear target bit and ...
OR R5, R2 ; ... set it again, if needed
; if R >= D then
; done by doing 32bit R - D and checking:
; if MSB = 1, then R < D, else R >= D
; hint: MSB in this case is the 33th bit, i.e. bit #32 = carry
MOVE R2, R5 ; R5 = low word of R
MOVE R3, R6 ; R6 = high word of R
SUB R10, R5 ; R6|R5 = 32bit (R := R - D)
SUBC R11, R6
RBRA _MTH$DIVU32_ITR, C ; bit #32 is "negative"
; when reaching this code, R is >= D
; if R >= D then
; R := R - D
; Q(i) := 1
; end
MOVE R6, R3 ; R = R6|R5 = (R := R - D)
MOVE R5, R2
MOVE 1, R7 ; Q(i) := 1 by shifting a "1"
CMP R4, 15 ; R4 <= 15?
RBRA _MTH$DIVU32_QL, !N ; yes: consider low word of Q
MOVE R4, R6 ; R6 := i
SUB 16, R6 ; adjust for high word
AND 0xFFFD, SR ; clear X
SHL R6, R7 ; move "1" to the right place
OR R7, R1 ; R1:= hi Q(i) := 1
RBRA _MTH$DIVU32_ITR, 1
_MTH$DIVU32_QL AND 0xFFFD, SR ; clear X
SHL R4, R7 ; move "1" to the right place
OR R7, R0 ; R0 := low Q(i) := 1
; for i = n-1...0 do (i.e. also one loop for the case i=0)
_MTH$DIVU32_ITR SUB 1, R4
RBRA _MTH$DIVU32_NBT, !N ; !N includes a round for i=0
; return results
_MTH$DIVU32_END MOVE R1, R9 ; hi Q
MOVE R0, R8 ; lo Q
MOVE R3, R11 ; hi R
MOVE R2, R10 ; lo R
DECRB
RET