⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vrtlib16.s

📁 VRTX操作系统
💻 S
📖 第 1 页 / 共 3 页
字号:
;----------------------------------------------------------------------------;

; 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 + -