📄 vrtlib16.s
字号:
;----------------------------------------------------------------------------;
; div_core is used by __rt_sdiv and __rt_udiv, and corrupts a3, a4 and ip
div_core
CMP a3, a4
MOVHI a4, a4, ASL #1
BHI div_core
div_core2
CMP a2, a4
ADC ip, ip, ip
SUBHS a2, a2, a4
CMP a1, a4
MOVLO a4, a4, LSR #1
BLO div_core2
MOV a1, ip
RET
; Signed divide of a2 by a1: returns quotient in a1, remainder in a2
; Quotient is truncated (rounded towards zero).
; Sign of remainder = sign of dividend.
; Destroys a3, a4 and ip
; Negates dividend and divisor, then does an unsigned divide; signs
; get sorted out again at the end.
|__rt_sdiv|
MOVS a3, a1
BEQ dividebyzero ; ip now unwanted
RSBMI a1, a1, #0 ; absolute value of divisor
EOR a3, a3, a2
ANDS ip, a2, #&80000000
ORR a3, ip, a3, LSR #1
STMFD sp!,{a3,lr}
; saved a3:
; bit 31 sign of dividend (= sign of remainder)
; bit 30 sign of dividend EOR sign of divisor (= sign of quotient)
RSBNE a2, a2, #0 ; absolute value of dividend
MOV a3, a2
MOV a4, a1
MOV ip, #0
BL div_core
LDMFD sp!,{a3}
MOVS a3, a3, ASL #1
RSBMI a1, a1, #0
RSBCS a2, a2, #0
LDMFD sp!,{pc}
; Unsigned divide of a2 by a1: returns quotient in a1, remainder in a2
; Destroys a4, ip and r5
|__rt_udiv|
MOVS a4, a1
BEQ dividebyzero
MOV ip, #0
MOV a3, #&80000000
CMP a2, a3
MOVLO a3, a2
B div_core
;
; Fast unsigned divide by 10: dividend in a1, divisor in a2.
; Returns quotient in a1, remainder in a2.
; Also destroys a3.
;
; Calculate x / 10 as (x * 2**32/10) / 2**32.
; That is, we calculate the most significant word of the double-length
; product. In fact, we calculate an approximation which may be 1 off
; because we've ignored a carry from the least significant word we didn't
; calculate. We correct for this by insisting that the remainder < 10
; and by incrementing the quotient if it isn't.
|__rt_udiv10| ; udiv10 ;
MOV a2, a1
MOV a1, a1, LSR #1
ADD a1, a1, a1, LSR #1
ADD a1, a1, a1, LSR #4
ADD a1, a1, a1, LSR #8
ADD a1, a1, a1, LSR #16
MOV a1, a1, LSR #3
ADD a3, a1, a1, ASL #2
SUB a2, a2, a3, ASL #1
CMP a2, #10
ADDGE a1, a1, #1
SUBGE a2, a2, #10
RET
;
; Fast signed divide by 10: dividend in a1, divisor in a2.
; Returns quotient in a1, remainder in a2.
; Also destroys a3 and a4.
; Quotient is truncated (rounded towards zero).
; Make use of __rt_udiv10
|__rt_sdiv10| ; sdiv10
MOV ip, lr
MOVS a4, a1
RSBMI a1, a1, #0
BL __rt_udiv10
CMP a4, #0
RSBMI a1, a1, #0
RSBMI a2, a2, #0
MOV pc, ip
;
; Test for division by zero (used when division is voided).
|__rt_divtest| ; divtest
CMPS a1, #0
BEQ dividebyzero ;replaces original RET NE macro
RET
dividebyzero
ADR ip, DivideByZeroError
MOV a3,#DivideByZeroErrorLen
B save_regs_and_trap
DivideByZeroErrorLen EQU 12
DivideByZeroError
DCD 1
DCB "divide by 0", 0
ALIGN
CODE16
;----------------------------------------------------------------------------;
AREA |C$$code$$__16__divide|, CODE, READONLY, INTERWORK ;
; The code area containing __rt_sdiv, __rt_udiv, __rt_sdiv_10, __rt_udiv10 ;
;----------------------------------------------------------------------------;
|__16__rt_sdiv|
ASR a4, a2, #31
EOR a2, a4
SUB a2, a4
ASR a3, a1, #31
EOR a1, a3
SUB a1, a3
BEQ dividebyzero16
PUSH {a3, a4} ; Save so we can look at signs later on
LSR a4, a2, #1
MOV a3, a1
s_loop CMP a3, a4
BNLS %FT0
LSL a3, #1
0 BLO s_loop
MOV a4, #0
B %FT0
s_loop2 LSR a3, #1
0 CMP a2, a3
ADC a4, a4
CMP a2, a3
BCC %FT0
SUB a2, a3
0
CMP a3, a1
BNE s_loop2
MOV a1, a4
POP {a3, a4}
EOR a3, a4
EOR a1, a3
SUB a1, a3
EOR a2, a4
SUB a2, a4
RET
; Unsigned divide of a2 by a1: returns quotient in a1, remainder in a2
; Destroys a4, ip and r5
|__16__rt_udiv|
LSR a4, a2, #1
MOV a3, a1
BEQ dividebyzero16
u_loop CMP a3, a4
BNLS %FT0
LSL a3, #1
0 BLO u_loop
MOV a4, #0
B %FT0
u_loop2 LSR a3, #1
0 CMP a2, a3
ADC a4, a4
CMP a2, a3
BCC %FT0
SUB a2, a3
0
CMP a3, a1
BNE u_loop2
MOV a1, a4
RET
; Fast unsigned divide by 10: dividend in a1, divisor in a2.
; Returns quotient in a1, remainder in a2.
; Also destroys a3.
;
; Calculate x / 10 as (x * 2**32/10) / 2**32.
; That is, we calculate the most significant word of the double-length
; product. In fact, we calculate an approximation which may be 1 off
; because we've ignored a carry from the least significant word we didn't
; calculate. We correct for this by insisting that the remainder < 10
; and by incrementing the quotient if it isn't.
|__16__rt_udiv10| ; udiv10 ;
MOV a2, a1
LSR a1, #1
LSR a3, a1, #1
ADD a1, a3
LSR a3, a1, #4
ADD a1, a3
LSR a3, a1, #8
ADD a1, a3
LSR a3, a1, #16
ADD a1, a3
LSR a1, #3
ASL a3, a1, #2
ADD a3, a1
ASL a3, #1
SUB a2, a3
CMP a2, #10
BLT %FT0
ADD a1, #1
SUB a2, #10
0
RET
;
; Fast signed divide by 10: dividend in a1, divisor in a2.
; Returns quotient in a1, remainder in a2.
; Also destroys a3 and a4.
; Quotient is truncated (rounded towards zero).
; Make use of __rt_udiv10
|__16__rt_sdiv10|
ASR a4, a1, #31
EOR a1, a4
SUB a1, a4
MOV a2, a1
LSR a1, #1
LSR a3, a1, #1
ADD a1, a3
LSR a3, a1, #4
ADD a1, a3
LSR a3, a1, #8
ADD a1, a3
LSR a3, a1, #16
ADD a1, a3
LSR a1, #3
ASL a3, a1, #2
ADD a3, a1
ASL a3, #1
SUB a2, a3
CMP a2, #10
BLT %FT0
ADD a1, #1
SUB a2, #10
0
EOR a1, a4
SUB a1, a4
EOR a2, a4
SUB a2, a4
RET
;
; Test for division by zero (used when division is voided).
|__16__rt_divtest| ; divtest ;
CMPS a1, #0
BEQ dividebyzero16
RET
dividebyzero16
SUB sp, sp, #8*4 ; Room for R8..R15
PUSH {r0-r7}
MOV r7, lr
ADR r0, DivideByZeroError16
MOV r1,#DivideByZeroErrorLen
MOV r8,r1 ;r8 = rt_trap parameter containing length
BL save_regs_and_trap16
ALIGN
DivideByZeroError16
DCD 1
DCB "divide by 0", 0
ALIGN
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -