📄 divide.s
字号:
; Issue: 0.02/25-Nov-91
;
; Purpose: Minimal, standalone, C-library kernel.
;
; Copyright (C) 1991 Advanced RISC Machines Limited. All rights reserved.
;
; Advanced RISC Machines Limited does not assume any liability arising out
; of this program or use thereof neither does it convey any licence under
; its intellectual property rights.
;
; Conditions of use:
;
; The terms and conditions under which this software is supplied to you and
; under which you may use it are described in your licence agreement with
; your supplier.
;
;----------------------------------------------------------------------------;
; ABOUT THIS CODE ;
; ;
; This code shows you how to write your own minimal, standalone, run-time ;
; support system for code compiled by Advanced RISC Machines's C Compiler. ;
; It can be assembled using Advanced RISC Machines's ARM assembler (ARMasm) ;
; or any assembler comaptible with it. ;
; ;
; This example code has been written to run under Advanced RISC Machines's ;
; ARM emulation system (ARMulator). It can also run without modification ;
; under Acorm Computer's "RISC OS" operating system for its ARM-based ;
; personal workstations. ;
; ;
; In fact, this code depends hardly at all on its target environment and is ;
; designed to be very easy to adapt to your particular ARM-based system. ;
; You can expect it to take about a couple of hours to re-target. ;
; ;
; Much of the code below is generic to the ARM processor and is completely ;
; independent of your ARM-based hardware or any operating system kernel that ;
; may run on it. To get going, you need write only 4 simple fns. ;
; ;
; WHAT THIS CODE PROVIDES: ;
; ;
; - Divide (and remainder) functions. ;
; ;
; WHAT THIS CODE DOES NOT PROVIDE ;
; ;
; Support for handling traps, faults, escapes, exceptions or interrupts. ;
; ;
;----------------------------------------------------------------------------;
;----------------------------------------------------------------------------;
; And, finally, generic ARM functions, referred to by the C compiler. ;
; You should not need to alter any of these unless you wish to incorporate ;
; them in your operating system kernel. See also later comments. ;
;----------------------------------------------------------------------------;
IF :LNOT: :DEF: USE_C_LIBRARY
EXPORT |__rt_udiv|
EXPORT |__rt_udiv10|
EXPORT |__rt_sdiv|
EXPORT |__rt_sdiv10|
EXPORT |__rt_divtest|
ENDIF
IMPORT PutString
IMPORT |__rt_exit|
IMPORT |__err_handler|, WEAK
;----------------------------------------------------------------------------;
; If __err_handler exists, errors are passed to it; otherwise, we print a ;
; simple diagnostic message and exit. ;
;----------------------------------------------------------------------------;
AREA |C$$code|, CODE, READONLY ; This module's code area. ;
;----------------------------------------------------------------------------;
; This code has to run in but 26-bit ARM modes and 32-bit modes. To allow ;
; for this, the code is carefully written so that all PSR restoration in ;
; 26-bit mode is via the following macro. ;
;----------------------------------------------------------------------------;
MACRO
RET $cond
IF {CONFIG} = 26
MOV$cond.S pc, lr
ELSE
MOV$cond pc, lr
ENDIF
MEND
;----------------------------------------------------------------------------;
; Support for low-level failures - currently stack overflow, divide by 0 and ;
; floating-point exceptions. If there is a higher level handler, call it; ;
; otherwise, print a message and exit gracefully. ;
; ;
; NOTES ;
; ;
; typedef struct { unsigned code; char message[252];} __rt_error; ;
; typedef struct { unsigned r[16];} __rt_registers; ;
; ;
;----------------------------------------------------------------------------;
|__rt_trap|
;
; void __rt_trap(__rt_error *e, __rt_registers *r);
STMFD sp!, {a1} ; save e in case handler returns...
LDR ip, err_handler
CMP ip, #0
MOVNE lr, pc
IF {CONFIG} = 26
MOVNES pc, ip ; if got a handler, use it and
ELSE
MOVNE pc, ip ; if got a handler, use it and
ENDIF
LDMFD sp!, {v1} ; hope not to return...
ADR a1, RTErrorHead
BL PutString ; write preamble...
ADD a1, v1, #4
BL PutString ; write error diagnosis
ADR a1, RTErrorTail
BL PutString ; write postlude
MOV a1, #255
B |__rt_exit| ; and terminate with non-zero exit code
err_handler
DCD |__err_handler|
save_regs_and_trap
STMFD sp!, {sp, lr, pc}
STMFD sp!, {r0-r12}
STR lr, [sp, #4*15] ; caller's pc is my lr
MOV a2, sp
MOV a1, ip
B |__rt_trap|
dividebyzero
ADR ip, DivideByZeroError
B save_regs_and_trap
stackoverflow
ADR ip, StackOverflowError
B save_regs_and_trap
DivideByZeroError
DCD 1
DCB "divide by 0", 0
ALIGN
StackOverflowError
DCD 3
DCB "stack overflow", 0
ALIGN
RTErrorHead
DCB 10, 13, "run time error: ", 0
RTErrorTail
DCB 10, 13, "program terminated", 10, 13, 10, 13, 0
ALIGN
;----------------------------------------------------------------------------;
; 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/ In each of these implementations we make a careful compromise between ;
; fastest and smallest. In some cases (e.g. divide), further unrolling of ;
; loops will yield a speed-up. However, this affects cache and working- ;
; set locality and can result in a slow-down for some applications on ;
; some hardware. You are advised not to unroll further before considering ;
; carefully your application and its interaction with your hardware. ;
; (e.g. ARM-2 vs ARM-3, external cache vs no external cache, fraction of ;
; run-time spent executing divide, etc.). ;
; ;
;----------------------------------------------------------------------------;
|__rt_udiv| ; udiv ;
;
; Unsigned divide of a2 by a1: returns quotient in a1, remainder in a2.
; Also destroys a3, a4 and ip
MOVS a3, a1
BEQ dividebyzero
MOV a4, #0
MOV ip, #&80000000
CMP a2, ip
MOVLO ip, a2
u_loop
CMP ip, a3, ASL #0
BLS u_shifted0mod8
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -