; Copyright 1996 Acorn Computers Ltd ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; ; Things that compiled C needs when included as AAsm source. ; Must appear before any included C output. ; Branches out of this code go to: dividebyzero. ; -------------------------------------------------------------------------- ; Arrange to ignore spurious stack overflow warnings. ; sl register contains garbage, so ignore stack overflow. ; Just hope we have enough stack - we don't use much, so should be OK. |x$stack_overflow| |x$stack_overflow_1| |__main| MOV PC,LR ; We also define __main to allow for the spurious B to it at ; the front of the compiled code. ; These are the C register usages - the other ones are already ; defined. They're reproduced here because some code (eg. the divide ; routine) uses them. They must be deleted in some way from the ; assembler that the C compiler generates. a1 RN 0 a2 RN 1 a3 RN 2 a4 RN 3 v1 RN 4 v2 RN 5 v3 RN 6 v4 RN 7 v5 RN 8 v6 RN 9 ;sl RN 10 v8 RN 11 ;ip RN 12 ;sp RN 13 ;lr RN 14 ;pc RN 15 ; -------------------------------------------------------------------------- ; Signed divide, extracted directly from AppSource.RISC_OSLib.kernel.s.k_body, ; where it's called _kernel_sdiv. I use this rather than the conventional ; assembler version because I know it's precisely what C code expects. ; [ debug ; Only used in printing numbers, in the code as it is at the moment! ; No, JPEG stuff ends up using it a little. |x$divide| ;v5 of C compiler uses new name for _kernel_sdiv. __rt_sdiv |__rt_sdiv| |_kernel_sdiv| ; 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. ; Code mostly as for udiv, except that the justification part is slightly ; simplified by knowledge that the dividend is in the range [0..#x80000000] ; (one register may be gained thereby). MOVS ip, a1 BEQ dividebyzero RSBMI a1, a1, #0 ; absolute value of divisor EOR ip, ip, a2 ANDS a4, a2, #&80000000 ORR ip, a4, ip, LSR #1 ; ip 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, a1 MOV a4, #0 s_loop CMP a2, a3, ASL #0 BLS s_shifted0mod8 CMP a2, a3, ASL #1 BLS s_shifted1mod8 CMP a2, a3, ASL #2 BLS s_shifted2mod8 CMP a2, a3, ASL #3 BLS s_shifted3mod8 CMP a2, a3, ASL #4 BLS s_shifted4mod8 CMP a2, a3, ASL #5 BLS s_shifted5mod8 CMP a2, a3, ASL #6 BLS s_shifted6mod8 CMP a2, a3, ASL #7 MOVHI a3, a3, ASL #8 BHI s_loop s_loop2 CMP a2, a3, ASL #7 ADC a4, a4, a4 SUBHS a2, a2, a3, ASL #7 CMP a2, a3, ASL #6 s_shifted6mod8 ADC a4, a4, a4 SUBHS a2, a2, a3, ASL #6 CMP a2, a3, ASL #5 s_shifted5mod8 ADC a4, a4, a4 SUBHS a2, a2, a3, ASL #5 CMP a2, a3, ASL #4 s_shifted4mod8 ADC a4, a4, a4 SUBHS a2, a2, a3, ASL #4 CMP a2, a3, ASL #3 s_shifted3mod8 ADC a4, a4, a4 SUBHS a2, a2, a3, ASL #3 CMP a2, a3, ASL #2 s_shifted2mod8 ADC a4, a4, a4 SUBHS a2, a2, a3, ASL #2 CMP a2, a3, ASL #1 s_shifted1mod8 ADC a4, a4, a4 SUBHS a2, a2, a3, ASL #1 CMP a2, a3, ASL #0 s_shifted0mod8 ADC a4, a4, a4 SUBHS a2, a2, a3, ASL #0 CMP a1, a3, LSR #1 MOVLS a3, a3, LSR #8 BLS s_loop2 MOV a1, a4 TST ip, #&40000000 RSBNE a1, a1, #0 TST ip, #&80000000 RSBNE a2, a2, #0 MOV pc, r14 ; Signed remainder of a2 by a1: returns remainder in a1 |_kernel_srem| STR r14, [sp, #-4]! BL |_kernel_sdiv| MOV a1, a2 LDR pc, [sp], #4 |__rt_udiv| |_kernel_udiv| |x$udivide| ; Unsigned divide of a2 by a1: returns quotient in a1, remainder in a2 ; Destroys a3 and ip MOV a3, #0 RSBS ip, a1, a2, LSR #3 BCC u_sh2 RSBS ip, a1, a2, LSR #8 BCC u_sh7 MOV a1, a1, LSL #8 ORR a3, a3, #&FF000000 RSBS ip, a1, a2, LSR #4 BCC u_sh3 RSBS ip, a1, a2, LSR #8 BCC u_sh7 MOV a1, a1, LSL #8 ORR a3, a3, #&00FF0000 RSBS ip, a1, a2, LSR #8 MOVCS a1, a1, LSL #8 ORRCS a3, a3, #&0000FF00 RSBS ip, a1, a2, LSR #4 BCC u_sh3 RSBS ip, a1, #0 BCS dividebyzero u_loop MOVCS a1, a1, LSR #8 u_sh7 RSBS ip, a1, a2, LSR #7 SUBCS a2, a2, a1, LSL #7 ADC a3, a3, a3 u_sh6 RSBS ip, a1, a2, LSR #6 SUBCS a2, a2, a1, LSL #6 ADC a3, a3, a3 u_sh5 RSBS ip, a1, a2, LSR #5 SUBCS a2, a2, a1, LSL #5 ADC a3, a3, a3 u_sh4 RSBS ip, a1, a2, LSR #4 SUBCS a2, a2, a1, LSL #4 ADC a3, a3, a3 u_sh3 RSBS ip, a1, a2, LSR #3 SUBCS a2, a2, a1, LSL #3 ADC a3, a3, a3 u_sh2 RSBS ip, a1, a2, LSR #2 SUBCS a2, a2, a1, LSL #2 ADC a3, a3, a3 u_sh1 RSBS ip, a1, a2, LSR #1 SUBCS a2, a2, a1, LSL #1 ADC a3, a3, a3 u_sh0 RSBS ip, a1, a2 SUBCS a2, a2, a1 ADCS a3, a3, a3 BCS u_loop MOV a1, a3 MOV pc, r14 END