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

📄 vrtlib.s

📁 VRTX操作系统
💻 S
📖 第 1 页 / 共 2 页
字号:
; MUST NOT RETURN.

  IF EnsureNoFPSupport = {FALSE}
        LDR     a2, fp_finalise            ; finalise FP code if present
        CMP     a2, #0
        MOVNE   lr, pc
        MOVNE   pc, a2
  ENDIF
	LDR	r3, =_user_exit
	LDR	r3,[r3]
	CMP	r3, #0
	BNE	user_exit	;jump to user exit handler if present
	MOV	lr, pc		;else loop forever
	NOP			
	NOP
	MOV	pc, lr		;loop forever

  IF EnsureNoFPSupport = {FALSE}
fp_initialise
        DCD     |__fp_initialise|
fp_finalise
        DCD     |__fp_finalise|
  ENDIF

;----------------------------------------------------------------------------;
;        AREA    |C$$code$$__rt_fpavailable|, CODE, READONLY				 ;
; The code area containing __rt_fpavailable                                  ;
;----------------------------------------------------------------------------;

|__rt_fpavailable|
;
; int __rt_fpavailable(); return non-0 if FP support code linked.

  IF EnsureNoFPSupport = {FALSE}
        LDR     a1, fp_initialise
  ELSE
        MOV     a1, #0
  ENDIF
        RET

;----------------------------------------------------------------------------;
;       AREA    |C$$code$$__jmp|, CODE, READONLY							 ;
; The code area containing setjmp, longjmp                                   ;
;----------------------------------------------------------------------------;
; Setjmp and longjmp support.                                                ;
;                                                                            ;
; NOTES                                                                      ;
;                                                                            ;
; 1/ Specific to C and not implementable in C.                               ;
;                                                                            ;
; 2/ Interacts with stack management and possibly with memory management.    ;
;    e.g. on a chunked stack, longjmp must de-allocate jumped-over chunks.   ;
;                                                                            ;
; 3/ Must know whether the floating-point instruction-set is supported!      ;
;    (DEPENDS ON __rt_fpavailable to discover this).                         ;
;                                                                            ;
;----------------------------------------------------------------------------;

        MAP 0                 ; This structure maps the jmp_buf
sj_v1   #       4             ; data type assumed by the C compiler.
sj_v2   #       4             ; First, space to save the v-registers...
sj_v3   #       4
sj_v4   #       4
sj_v5   #       4
sj_v6   #       4
sj_sl   #       4             ; then the frame registers sl, fp, sp (ap),
sj_fp   #       4             ; and pc/lr...
sj_ap   #       4
sj_pc   #       4
sj_f4   #       3*4           ; and finally the floating-point reisters,
sj_f5   #       3*4           ; used only if floating point support is
sj_f6   #       3*4           ; available.
sj_f7   #       3*4


|setjmp|                      ; setjmp
;
; int setjmp(jmp_buf env);
; Saves everything that might count as a register variable in 'env'.

        STMIA   a1!, {v1-v6, r10, fp, sp, lr}
        MOV     v6, a1                 ; v6 safe in env - use to point past
                                       ; saved lr (at 1st FP slot)
        BL      |__rt_fpavailable|
        CMP     a1, #0
        BEQ     setjmp_return          ; no fp
        STFE    f4, [v6, #sj_f4-sj_f4]
        STFE    f5, [v6, #sj_f5-sj_f4]
        STFE    f6, [v6, #sj_f6-sj_f4]
        STFE    f7, [v6, #sj_f7-sj_f4]
        MOV     a1, #0                 ; must return 0 from a direct call
setjmp_return
        LDMDB   v6, {v6, r10, fp, sp, lr}
        RET

|longjmp|                                                          ; longjmp ;
; int longjmp(jmp_buf env, int val);

        MOV     v1, a1                 ; save env ptr over call to fpavailable
        MOVS    v6, a2                 ; ensure non-0 return value...
        MOVEQ   v6, #1                 ; (must NOT return 0 on longjmp(env, 0))
        BL      |__rt_fpavailable|
        CMP     a1, #0
        BEQ     longjmp_return
        LDFE    f7, [v1, #sj_f7]
        LDFE    f6, [v1, #sj_f6]
        LDFE    f5, [v1, #sj_f5]
        LDFE    f4, [v1, #sj_f4]
longjmp_return
        MOV     a1, v6
        LDMIA   v1, {v1-v6, r10, fp, sp, lr}
        RET

;----------------------------------------------------------------------------;
       AREA    |C$$code$$__divide|, CODE, READONLY							 ;
; The code area containing __rt_sdiv, __rt_udiv, __rt_sdiv_10, __rt_udiv10   ;
;----------------------------------------------------------------------------;
; GENERIC ARM FUNCTIONS - divide and remainder.                              ;
;                                                                            ;
; NOTES                                                                      ;
;                                                                            ;
; 1/ You may wish to make these functions part of your O/S kernel, replacing ;
;    the implementations here by branches to the relevant entry addresses.   ;
;                                                                            ;
; 2/ Each divide function is a div-rem function, returning the quotient in   ;
;    r0 and the remainder in r1. Thus (r0, r1) -> (r0/r1, r0%r1). This is    ;
;    understood by the C compiler.                                           ;
;                                                                            ;
; 3/ Because of its importance in many applications, divide by 10 is treated ;
;    as a special case. The C compiler recognises divide by 10 and generates ;
;    calls to __rt_{u,s}div10, as appropriate.                               ;
;                                                                            ;
; 4/ Each of the implementations below has been coded with smallness as a    ;
;    higher priority than speed.  Unrolling the loops will allow faster      ;
;    execution, but will produce much larger code.  If the speed of divides  ;
;    is critical then unrolled versions can be extracted from the ARM ANSI C ;
;    Library.                                                                ;
;                                                                            ;
;----------------------------------------------------------------------------;

; 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
        RET     NE
dividebyzero
        ADR     ip, DivideByZeroError
	MOV	a3,#DivideByZeroErrorLen
        B       save_regs_and_trap

DivideByZeroErrorLen	EQU	11
DivideByZeroError
        DCD     1
        DCB     "divide by 0", 0
        ALIGN

        END

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -