📄 fpp04.s43
字号:
ELSE ; End of software multiplication loop
;
; Hardware Multiplication sequences:
;
; 31 0
; +----+----+----+----+
; | mid1 x lsb2 |
; +----+----+----+----+
; +----+----+----+----+
; | lsb1 x mid2 |
; 47 +----+----+----+----+
; +----+----+----+----+
; | 00 | msb1 x lsb2 |
; +----+----+----+----+
; +----+----+----+----+
; | 00 | lsb1 x msb2 |
; +----+----+----+----+
; +----+----+----+----+
; | mid1 x mid2 |
; 63 +----+----+----+----+
; +----+----+----+----+
; | 00 | msb1 x mid2 |
; +----+----+----+----+
; +----+----+----+----+
; | 00 | mid1 x msb2 |
; +----+----+----+----+
; +----+----+
; |msb1xmsb2|
; +----+----+
; ----------------------------------------------------
; +----+----+----+----+----+----+
; | MSB | MID | LSB | RESULT_xxx
; +----+----+----+----+----+----+
;
IF DOUBLE = 1 ; .DOUBLE MPY sequence
MPY ARG2_LSB,ARG1_MID ; XXXX XXXX
MAC ARG1_LSB,ARG2_MID ; c XXXX XXXX
ADD &ResHi,RESULT_LSB ;
ADDC &SumExt,RESULT_MID ;
MPY ARG1_MSB,ARG2_LSB ; 00XX XXXX
MAC ARG1_LSB,ARG2_MSB ; 0XXX XXXX
MAC ARG1_MID,ARG2_MID ; c XXXX XXXX
ADD &ResLo,RESULT_LSB ;
ADDC &ResHi,RESULT_MID ;
ADDC &SumExt,RESULT_MSB ;
MPY ARG1_MSB,ARG2_MID ; 00XX XXXX
MAC ARG2_MSB,ARG1_MID ; 0XXX XXXX
ADD &ResLo,RESULT_MID ;
ADDC &ResHi,RESULT_MSB ;
MPY ARG1_MSB,ARG2_MSB ;0000 XXXX
ADD &ResLo,RESULT_MSB ; MSB MID LSB ---
;
ELSE ; .FLOAT MPY sequence
;
; 31 0
; +----+----+----+----+
; | lsb1 x lsb2 |
; 47 +----+----+----+----+
; +----+----+----+----+
; | 00 | lsb1 x msb2 |
; +----+----+----+----+
; +----+----+----+----+
; | 00 | msb1 x lsb2 |
; +----+----+----+----+
; +----+----+
; |msb1xmsb2|
; +----+----+
; ------------------------------------------
; +----+----+----+----+
; | MSB | LSB | RESULT_xxx
; +----+----+----+----+
;
; NOTE: The MPY ARG1_LSB,ARG2_MSB is replaced by a
; MOV ARG2_MSB,&0138h due to speed reasons
;
MPY ARG1_LSB,ARG2_LSB ; XXXX XXXX
MOV &ResHi,RESULT_LSB ;
MOV ARG2_MSB,&0138h ;!! 00XX XXXX
MAC ARG2_LSB,ARG1_MSB ; 0XXX XXXX
ADD &ResLo,RESULT_LSB ;
ADDC &ResHi,RESULT_MSB ;
MPY ARG1_MSB,ARG2_MSB ; 0000 XXXX
ADD &ResLo,RESULT_MSB ; MSB LSB ---
ENDIF
;
; The hardware multiplier result is located falsely:
; Shift right result 8 bits to get FPP mantissa format (shown for .DOUBLE):
; .FLOAT 1234 5678 -> 0012 3456 xx__
; .DOUBLE 1234 5678 9ABC -> 0012 3456 789A xx__ (xx in HELP for rounding)
;
SWPB RESULT_LSB ; 9ABC -> BC9A
MOV RESULT_LSB,HELP ; BC9A (contains LSB-1, LSB-2)
MOV.B RESULT_LSB,RESULT_LSB ; 009A
IF DOUBLE = 1
MOV.B RESULT_MID,COUNTER ; 0078 -> COUNTER
SWPB COUNTER ; 7800
ADD COUNTER,RESULT_LSB ; 789A -> RESULT_LSB
SWPB RESULT_MID ; 7856
MOV.B RESULT_MID,RESULT_MID ; 0056
MOV.B RESULT_MSB,COUNTER ; 0034 -> COUNTER
SWPB COUNTER ; 3400
ADD COUNTER,RESULT_MID ; 3456 -> RESULT_MID
ELSE
MOV.B RESULT_MSB,COUNTER ;
SWPB COUNTER ;
ADD COUNTER,RESULT_LSB ;
ENDIF
SWPB RESULT_MSB ; 3412
MOV.B RESULT_MSB,RESULT_MSB ; 0012 -> RESULT_MSB
ENDIF ; End of hardware MPY sequence
;
; Common completion part:
; Result in RESULT: 40 0000 to FF FFFE (40 0000 0000 to FF FFFF FFFE
; Normalization is made to get MSB = 1 and rounding with LSB-1
;
TST.B RESULT_MSB ; If hidden Bit is not set
JGE FM5 ; then jump
INC.B 3(SP) ; New RESULT-exponent: hidden bit = 1
JNC FM6
JMP DBL_OVERFLOW ; Exponent-overflow (FF to 00)
FM5 RLC HELP ; LSB-1 of RESULT to carry
RLC RESULT_LSB ; to format the mantissa
IF DOUBLE=1
RLC RESULT_MID
ENDIF
RLC.B RESULT_MSB
; round with LSB-1 resp. LSB-2
FM6 RLC HELP ; Next LSB-1 to CARRY
JMP NORMLZ ; Go to common completion part
;=============================================================================
; Floating Point Division Result on TOS = @RPRES/@RPARG
; Check if dividend is zero: result is zero
; Check if divisor is zero: result is signed max. number (overflow error)
FLT_DIV CALL #INIMD ; Read arguments, zero test, sign prep.
; MOV.B HELP,2(SP) ; Sign of result in HELP.7
BIT #1,COUNTER ; If argument1 is zero:
JNZ EXIT ; Result is zero
BIT #2,COUNTER ; If argument2 is zero:
JNZ DIV_BY_ZERO ; signed overflow
; Calculate the exponent of the result by subtraction of the exponents
; of argument1 and argument2
MOV ARG1_MSB,HELP ; Fetch exponent of argument 1
BIS #0FFh,HELP ; Avoid influence from mantissa
SUB ARG2_MSB,HELP ; argument 1 - argument 2 -> HELP
JC FD1 ;
ADD #8000h,HELP ; Toggle sign bit of exponent
JC FD2 ;
JMP DBL_UNDERFLOW ; Underflow: result = 0
FD1 ADD #8000h,HELP ; Toggle sign bit of exponent
JC DBL_OVERFLOW ; Overflow: largest signed number
FD2 SWPB HELP ;
MOV.B HELP,3(SP) ; Save exponent of result
; Division-loop for mantissa calculation
;
BIS.B #80h,ARG2_MSB ; Set hidden bit argument 2
BIS.B #80h,ARG1_MSB ; Set hidden bit argument 2
MOV.B #ML,COUNTER ; Mantissa length to COUNTER
FD4 SUB ARG2_LSB,ARG1_LSB ; ARG1 - ARG2
IF DOUBLE=1
SUBC ARG2_MID,ARG1_MID ;
ENDIF
SUBC ARG2_MSB,ARG1_MSB ;
JC FD3 ; ARG1 >= ARG2
ADD ARG2_LSB,ARG1_LSB ; ARG1 < ARG2: restore ARG1
IF DOUBLE=1
ADDC ARG2_MID,ARG1_MID ;
ENDIF
ADDC ARG2_MSB,ARG1_MSB ;
CLRC ;
FD3 RLC RESULT_LSB ; Carry to result
IF DOUBLE=1
RLC RESULT_MID
ENDIF
RLC RESULT_MSB
RLA ARG1_LSB ;
IF DOUBLE=1
RLC ARG1_MID ;
ENDIF
RLC ARG1_MSB ;
DEC.B COUNTER ; If division is not finished:
JNZ FD4 ; continue loop
TST.B RESULT_MSB ; Hidden bit set (normalized)?
JN FD5 ; Yes
INC.B COUNTER ; No, go through loop once more
DEC.B 3(SP) ; Correct exponent
JHS FD4 ;
JMP DBL_UNDERFLOW ; Underflow: result = 0
;
; Result in RESULT: 80 0000 to FF FFFE (80 0000 0000 to FF FFFF FFFE)
; Rounding is made with LSB-1
;
FD5 SUBC ARG2_LSB,ARG1_LSB ; Calculate LSB-1
IF DOUBLE=1
SUBC ARG2_MID,ARG1_MID ;
ENDIF
SUBC ARG2_MSB,ARG1_MSB ; Rounding info in Carry
;==============================================================================
; Common completion part: Mantissa in RESULT_xxx
; Sign in 2(SP) MSB (hidden bit)
; Exponent in 3(SP)
; LSB-1 in Carry for rounding
;
; Rounding info in carry, no error, sign and exponent get inserted
;
NORMLZ ADC RESULT_LSB ; Round mantissa with LSB-1
IF DOUBLE=1
ADC RESULT_MID
ENDIF
ADC.B RESULT_MSB
ADC.B 3(SP) ; Round exponent with Carry
JC DBL_OVERFLOW ; Exponent overflow 0FFh to 00h
;
; No rounding, no error, sign and exponent get inserted
;
DDRNZ BIC.B #80h,RESULT_MSB ; Clear hidden Bit (and higher byte)
BIS 2(SP),RESULT_MSB ; Insert exponent and sign bit
;
; All done, result is placed on top of stack (TOS)
;
EXIT CLR HELP ; N=0, no error
EXITE MOV RESULT_MSB,2(SP) ; Result (RESULT) to Stack
IF DOUBLE=1
MOV RESULT_MID,4(SP) ;
MOV RESULT_LSB,6(SP) ;
ELSE
MOV RESULT_LSB,4(SP) ;
ENDIF
;
; Termination subroutine: error code in HELP (0 = no error)
; Subroutine can be used by user written FP subroutines
;
FLT_END MOV SP,RPRES ; Result pointer to result
ADD #2,RPRES ; Correction (SP points to return addr.)
MOV RPRES,RPARG ; Argument pointer to result
BIC #FN+FZ+FC,SR ; Clear N,Z and C in SR
BIS HELP,SR ; Set SR according to error status
RET ; Stored in HELP
;==============================================================================
; Floating Point Error Handling: underflow, overflow, division by zero
;
; +--------------------+-------------------+------------------------+
; | Error | Statusregister | Result |
; +--------------------+-------------------+------------------------+
; | No error | N=0, C=x, Z=x | xxxx xxxx xxxx |
; | Overflow positive | N=1, C=1, Z=1 | FF7F FFFF FFFF |
; | Overflow negative | N=1, C=1, Z=0 | FFFF FFFF FFFF |
; | Underflow | N=1, C=0, Z=0 | 0000 0000 0000 |
; | Division by zero | N=1, C=0, Z=1 | FF7F FFFF FFFF or |
; | | | FFFF FFFF FFFF |
; +--------------------+-------------------+------------------------+
;
DBL_UNDERFLOW ; Underflow: Result = 0
IF SW_UFLOW=1 ; Error only if SW_UFLOW = 1
MOV #FN,HELP ; Error code N=1, C=0, Z=0
JMP RES01
ENDIF
RES0 CLR HELP ; Result is 0: N = 0 (No error)
RES01 CLR RESULT_MSB ; Errorfree zero result
IF DOUBLE=1
CLR RESULT_MID
ENDIF
CLR RESULT_LSB
JMP EXITE ; To normal completion
DBL_OVERFLOW ; Overflow: Insert largest signed number
MOV #FN+FC,HELP ; Error code N=1, C=1, Z=Sign
TST.B 2(SP) ; Sign of result is stored here
JN L$1 ; Neg. sign: Z=0
BIS #FZ,HELP ; Pos. sign: Z=1
L$1 MOV #0FF7Fh,RESULT_MSB
BIS 2(SP),RESULT_MSB ; Insert sign
IF DOUBLE=1
MOV #0FFFFh,RESULT_MID ;
ENDIF
MOV #0FFFFh,RESULT_LSB ;
JMP EXITE ;
DIV_BY_ZERO ; Division by 0: Insert largest signed number
MOV #FN+FZ,HELP ; Error code N=1, C=0, Z=1
JMP L$1 ; Result like overflow
;=============================================================================
; Floating Point Comparison
;
; Call of the Comparison:
;
; MOV #ARG1,RPRES ; Pointer to Argument 1 MSBs
; MOV #ARG2,RPARG ; Pointer to Argument 2 MSBs
; CALL #FLT_CMP ; Comparison call
; JEQ EQUAL ; If arg1 = arg2
; JHS A1_GT_A2 ; If arg1 > arg2
; ... ... ; If arg1 < arg2
;
; The result of the compare is written to the status register SR and HELP
; RPARG and RPRES point with SP to actual result area (normal return)
;
; +--------------------------+------------------------------+
; | Condition | Statusregister |
; +--------------------------+------------------------------+
; | Argument 1 = Argument 2 | ZERO = 1, CARRY = 1, NEG = 0 |
; | Argument 1 < Argument 2 | ZERO = 0, CARRY = 0, NEG = 0 |
; | Argument 1 > Argument 2 | ZERO = 0, CARRY = 1, NEG = 0 |
; +--------------------------+------------------------------+
;
FLT_CMP EQU $
IF DOUBLE=1
MOV @R5+,ARG2_MSB ; Copy argument 2 to regs
MOV @R5+,ARG2_MID
MOV @R5+,ARG2_LSB
MOV @R11+,ARG1_MSB ; Copy argument 1 to regs
MOV @R11+,ARG1_MID
MOV @R11+,ARG1_LSB
ELSE
MOV @R5+,ARG2_MSB ; Copy argument 2 to regs
MOV @R5+,ARG2_LSB
MOV @R9+,ARG1_MSB ; Copy argument 1 to regs
MOV @R9+,ARG1_LSB
ENDIF
;
TST.B ARG2_MSB ; Arg1, Arg2: check signs
JN FC2 ; Arg2 = neg.
TST.B ARG1_MSB ; Arg2 = pos.
JN A1LTA2 ; Arg2 = +, Arg1 = -: A1 < A2
CMP ARG2_MSB,ARG1_MSB ; Arg1 = +, Arg2 = +
JNE FC4 ; Check values
IF DOUBLE=1
CMP ARG2_MID,ARG1_MID
JNE FC4
ENDIF
CMP ARG2_LSB,ARG1_LSB
JEQ A1EQA2 ; Arg1 = Arg2
FC4 JLO A1LTA2 ; Arg1 < Arg2
A1GTA2 MOV #FC,HELP ; Carry = 1, Zero = 0
JMP FLT_END ; To completion part
;
FC2 TST.B ARG1_MSB ; Arg2 = -
JGE A1GTA2 ; Arg1 = +: A1 > A2
CMP ARG2_MSB,ARG1_MSB ; Arg1 = -, Arg2 = -
JNE FC5 ; Check values
IF DOUBLE=1
CMP ARG2_MID,ARG1_MID
JNE FC5
ENDIF
CMP ARG2_LSB,ARG1_LSB
JEQ A1EQA2 ; Arg1 = Arg2
FC5 JLO A1GTA2 ; Arg1 > Arg2
A1LTA2 CLR HELP ; Carry = 0, Zero = 0
JMP FLT_END ; Modify SR with HELP
A1EQA2 MOV #FZ+FC,HELP ; Arg1 = Arg2: Z = C = 1
JMP FLT_END ; To completion part
;=============================================================================
; Floating Point Subroutines
;
; INIMD creates the sign of the result for MPY and DIV in HELP.7
; INIAS is used too
INIMD EQU $
IF DOUBLE=1
MOV.B @R11,HELP ; Calculate sign of result:
ELSE
MOV.B @R9,HELP
ENDIF
XOR.B @R5,HELP ; Sign arg2 .xor. sign arg1
AND.B #080h,HELP ; Leave only the calculated sign
; INIAS loads the arguments to ARG1_xxx and ARG2_xxx
; clears the variables RESULT_xxx
; tests the arguments to zero and stores the result in
; COUNTER - if argument1 is zero: COUNTER.0 is 1
; if argument2 is zero: COUNTER.1 is 1
; else COUNTER is 0
INIAS EQU $
IF DOUBLE=1
MOV @R5+,ARG2_MSB ; Copy argument 2 to regs
MOV @R5+,ARG2_MID
MOV @R5,ARG2_LSB
MOV @R11+,ARG1_MSB ; Copy argument 1 to regs
MOV @R11+,ARG1_MID
MOV @R11,ARG1_LSB
ELSE
MOV @R5+,ARG2_MSB ; Copy argument 2 to regs
MOV @R5,ARG2_LSB
MOV @R9+,ARG1_MSB ; Copy argument 1 to regs
MOV @R9,ARG1_LSB
ENDIF
MOV.B HELP,4(SP) ; Insert sign
CLR RESULT_MSB ; Clear RESULT
IF DOUBLE=1
CLR RESULT_MID ;
ENDIF
CLR RESULT_LSB ;
;
CLR COUNTER ; Clear COUNTER
TST ARG1_MSB ; If ARG1 = 0:
JNZ FNZ1 ; set LSB of COUNTER
IF DOUBLE=1
TST ARG1_MID ;
JNZ FNZ1 ;
ENDIF
TST ARG1_LSB ;
JNZ FNZ1 ;
BIS #1,COUNTER ; ARG1 = 0
;
FNZ1 TST ARG2_MSB ; If ARG2 = 0:
JNZ FNZ2 ; set LSB+1 of COUNTER
IF DOUBLE=1
TST ARG2_MID ;
JNZ FNZ2 ;
ENDIF
TST ARG2_LSB ;
JNZ FNZ2 ;
BIS #2,COUNTER ; ARG2 = 0
FNZ2 RET ; Zero info in COUNTER, sign in HELP
;
; END OF THE FLOATING POINT BASIC ARITHMETIC OPERATIONS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -