os/kernelhwsrv/kernel/eka/common/arm/cgcchelp.cia
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// e32\common\arm\cgcchelp.cia
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
#include "../common.h"
sl@0
    19
#ifdef __KERNEL_MODE__
sl@0
    20
#include "nkern.h"
sl@0
    21
#endif
sl@0
    22
sl@0
    23
extern "C" {
sl@0
    24
#ifdef __GCC32__
sl@0
    25
EXPORT_C __NAKED__ TInt __divsi3(TInt /*dividend*/,TInt /*divisor*/)
sl@0
    26
//
sl@0
    27
// Signed divide of r0 by r1: returns quotient in r0
sl@0
    28
// Quotient is truncated (rounded towards zero).
sl@0
    29
// Destroys r2, r3 and ip
sl@0
    30
// Negates dividend and divisor, then does an unsigned divide; signs
sl@0
    31
// get sorted out again at the end.
sl@0
    32
// 
sl@0
    33
// Have to calculate the sign of the result for the end of the calculation.
sl@0
    34
// Store this in the LSB of ip which also saves the old lr.
sl@0
    35
//
sl@0
    36
    {
sl@0
    37
sl@0
    38
	asm("STMFD	sp!, {lr} ");
sl@0
    39
    asm("ANDS    r3, r1, #0x80000000        ");	// r3 bit 31=sign of divisor, rest of r3=0
sl@0
    40
    asm("RSBMI   r1, r1, #0                 ");	// r1=ABS(divisor)
sl@0
    41
    asm("EORS    ip, r3, r0, ASR #32        ");	// ip bit 31=sign of quotient, all other bits=carry=sign of dividend
sl@0
    42
    asm("RSBCS   r0, r0, #0                 ");	// r0=ABS(dividend)
sl@0
    43
    asm(".EXTERN 			    ");
sl@0
    44
    asm("BL      __umodsi3_start            ");
sl@0
    45
    asm("MOV     r0, r3                     ");
sl@0
    46
    asm("CMP	 ip, #0						");	// test sign of quotient
sl@0
    47
    asm("RSBMI   r0, r0, #0                 ");	// negate if necessary
sl@0
    48
	__POPRET("");
sl@0
    49
	}
sl@0
    50
sl@0
    51
sl@0
    52
EXPORT_C __NAKED__ TInt __modsi3(TInt /*dividend*/,TInt /*divisor*/)
sl@0
    53
//
sl@0
    54
// Signed divide of r0 by r1: returns remainder in r0
sl@0
    55
// Sign of remainder = sign of dividend.
sl@0
    56
// Destroys r2, r3 and ip
sl@0
    57
// Negates dividend and divisor, then does an unsigned divide; signs
sl@0
    58
// get sorted out again at the end.
sl@0
    59
//
sl@0
    60
// Have to save sign of dividend in order to apply sign to remainder
sl@0
    61
// at the end of the calculation. Store this in the LSB of ip which also
sl@0
    62
// saves the old lr.
sl@0
    63
//
sl@0
    64
    {
sl@0
    65
sl@0
    66
	asm("STMFD	sp!, {lr} ");
sl@0
    67
    asm("MOVS    r1, r1                     ");
sl@0
    68
    asm("RSBMI   r1, r1, #0                 ");
sl@0
    69
    asm("MOVS    ip, r0 ");
sl@0
    70
    asm("RSBMI   r0, r0, #0                 ");
sl@0
    71
    asm(".EXTERN 			    ");
sl@0
    72
    asm("BL      __umodsi3_start            ");
sl@0
    73
    asm("MOVS    ip, ip	");
sl@0
    74
    asm("RSBMI   r0, r0, #0                 ");
sl@0
    75
	__POPRET("");
sl@0
    76
    }
sl@0
    77
sl@0
    78
EXPORT_C __NAKED__ TUint __udivsi3(TUint /*dividend*/,TUint /*divisor*/)
sl@0
    79
//
sl@0
    80
// Unsigned divide of r0 by r1: returns quotient in r0
sl@0
    81
// Quotient is truncated (rounded towards zero).
sl@0
    82
// Destroys r2, r3 and ip
sl@0
    83
// 
sl@0
    84
    {
sl@0
    85
sl@0
    86
    asm("MOV     ip, lr                     ");
sl@0
    87
    asm(".EXTERN 			    ");
sl@0
    88
    asm("BL      __umodsi3_start            ");
sl@0
    89
    asm("MOV     r0, r3                     ");
sl@0
    90
	__JUMP(,ip);
sl@0
    91
    }
sl@0
    92
sl@0
    93
sl@0
    94
EXPORT_C __NAKED__ long long __divdi3(long long /*dividend*/, long long /*divisor*/)
sl@0
    95
//
sl@0
    96
// Dividend in r1:r0, divisor in r3:r2, Return quotient in r1:r0
sl@0
    97
//
sl@0
    98
	{
sl@0
    99
	asm("stmfd sp!, {r4-r8,lr} ");
sl@0
   100
	asm("eor r8, r1, r3 ");				// sign of result into r8
sl@0
   101
	asm("movs r1, r1 ");
sl@0
   102
	asm("bpl 1f ");
sl@0
   103
	asm("rsbs r0, r0, #0 ");			// ABS(dividend)
sl@0
   104
	asm("rsc r1, r1, #0 ");
sl@0
   105
	asm("1: ");
sl@0
   106
	asm("movs r3, r3 ");
sl@0
   107
	asm("bpl 2f ");
sl@0
   108
	asm("rsbs r2, r2, #0 ");			// ABS(divisor)
sl@0
   109
	asm("rsc r3, r3, #0 ");
sl@0
   110
	asm("2: ");
sl@0
   111
	asm("bl UDiv01 ");					// do the division, result in r4,r5
sl@0
   112
	asm("eors r0, r4, r8, asr #32 ");	// quotient into r1:r0, inverted if quotient -ve
sl@0
   113
	asm("eors r1, r5, r8, asr #32 ");
sl@0
   114
	asm("adcs r0, r0, #0 ");		// if quotient -ve, add 1
sl@0
   115
	asm("adcs r1, r1, #0 ");
sl@0
   116
	__POPRET("r4-r8,");
sl@0
   117
	}
sl@0
   118
sl@0
   119
EXPORT_C __NAKED__ long long __moddi3(long long /*dividend*/, long long /*divisor*/)	/* signed */
sl@0
   120
	{
sl@0
   121
	asm("stmfd sp!, {r4-r8,lr} ");
sl@0
   122
	asm("movs r8, r1 ");				// sign of remainder (=sign of dividend) into r8
sl@0
   123
	asm("bpl 1f ");
sl@0
   124
	asm("rsbs r0, r0, #0 ");			// ABS(dividend)
sl@0
   125
	asm("rsc r1, r1, #0 ");
sl@0
   126
	asm("1: ");
sl@0
   127
	asm("movs r3, r3 ");
sl@0
   128
	asm("bpl 2f ");
sl@0
   129
	asm("rsbs r2, r2, #0 ");			// ABS(divisor)
sl@0
   130
	asm("rsc r3, r3, #0 ");
sl@0
   131
	asm("2: ");
sl@0
   132
	asm("bl UDiv01 ");					// do the division, remainder in r3,r6
sl@0
   133
	asm("eors r0, r3, r8, asr #32 ");	// remainder into r1:r0, inverted if dividend -ve
sl@0
   134
	asm("eors r1, r6, r8, asr #32 ");
sl@0
   135
	asm("adcs r0, r0, #0 ");			// if dividend -ve, add 1
sl@0
   136
	asm("adcs r1, r1, #0 ");
sl@0
   137
	__POPRET("r4-r8,");
sl@0
   138
	}
sl@0
   139
sl@0
   140
EXPORT_C __NAKED__ long long __umoddi3(unsigned long long /*dividend*/, unsigned long long /*divisor*/)	/* unsigned */
sl@0
   141
	{
sl@0
   142
	asm("stmfd sp!, {r4-r7,lr} ");
sl@0
   143
	asm("bl UDiv01 ");					// do the division, remainder in r6:r3
sl@0
   144
	asm("mov r0, r3 ");
sl@0
   145
	asm("mov r1, r6 ");
sl@0
   146
	__POPRET("r4-r7,");
sl@0
   147
	}
sl@0
   148
sl@0
   149
EXPORT_C __NAKED__ long long __ashrdi3(long long /*value*/, unsigned int /*count*/)
sl@0
   150
	{
sl@0
   151
	asm("cmp r2, #63 ");
sl@0
   152
	asm("movhi r2, #63 ");			// count>63 same as count=63
sl@0
   153
	asm("cmp r2, #32 ");
sl@0
   154
	asm("bcs Asr01 ");				// jump if shift count >=32
sl@0
   155
	asm("rsb r12, r2, #32 ");		// r12=32-shift count
sl@0
   156
	asm("mov r0, r0, lsr r2 ");		// shift ls word right
sl@0
   157
	asm("orr r0, r0, r1, lsl r12 ");	// or in bits shifted out of ms word
sl@0
   158
	asm("mov r1, r1, asr r2 ");		// shift ms word right
sl@0
   159
	__JUMP(,lr);
sl@0
   160
	asm("Asr01: ");
sl@0
   161
	asm("sub r2, r2, #32 ");		// r2=shift count-32
sl@0
   162
	asm("mov r0, r1, asr r2 ");		// ls word = ms word >> (count-32)
sl@0
   163
	asm("mov r1, r1, asr #32 ");	// ms word of result=sign extension of r1
sl@0
   164
	__JUMP(,lr);
sl@0
   165
	}
sl@0
   166
sl@0
   167
EXPORT_C __NAKED__ long long __ashldi3(long long /*value*/, unsigned int /*count*/)
sl@0
   168
	{
sl@0
   169
	asm("cmp r2, #63 ");
sl@0
   170
	asm("movhi r2, #64 ");			// count>63 same as count=64
sl@0
   171
	asm("cmp r2, #32 ");
sl@0
   172
	asm("bcs Asl01 ");				// jump if shift count >=32
sl@0
   173
	asm("rsb r12, r2, #32 ");		// r12=32-shift count
sl@0
   174
	asm("mov r1, r1, asl r2 ");		// shift ms word left
sl@0
   175
	asm("orr r1, r1, r0, lsr r12 ");	// or in bits shifted out of ls word
sl@0
   176
	asm("mov r0, r0, asl r2 ");		// shift ls word left
sl@0
   177
	__JUMP(,lr);
sl@0
   178
	asm("Asl01: ");
sl@0
   179
	asm("sub r2, r2, #32 ");		// r2=shift count-32
sl@0
   180
	asm("mov r1, r0, asl r2 ");		// result ms word = ls word << (count-32)
sl@0
   181
	asm("mov r0, #0 ");				// ls word of result is zero
sl@0
   182
	__JUMP(,lr);
sl@0
   183
	}
sl@0
   184
sl@0
   185
EXPORT_C __NAKED__ unsigned long long __lshrdi3(unsigned long long /*value*/, unsigned int /*count*/)
sl@0
   186
	{
sl@0
   187
	asm("cmp r2, #63 ");
sl@0
   188
	asm("movhi r2, #64 ");			// count>63 same as count=64
sl@0
   189
	asm("cmp r2, #32 ");
sl@0
   190
	asm("bcs Lsr01 ");				// jump if shift count >=32
sl@0
   191
	asm("rsb r12, r2, #32 ");		// r12=32-shift count
sl@0
   192
	asm("mov r0, r0, lsr r2 ");		// shift ls word right
sl@0
   193
	asm("orr r0, r0, r1, lsl r12 ");	// or in bits shifted out of ms word
sl@0
   194
	asm("mov r1, r1, lsr r2 ");		// shift ms word right
sl@0
   195
	__JUMP(,lr);
sl@0
   196
	asm("Lsr01: ");
sl@0
   197
	asm("sub r2, r2, #32 ");		// r2=shift count-32
sl@0
   198
	asm("mov r0, r1, lsr r2 ");		// ls word = ms word >> (count-32)
sl@0
   199
	asm("mov r1, #0 ");				// ms word of result = 0
sl@0
   200
	__JUMP(,lr);
sl@0
   201
	}
sl@0
   202
sl@0
   203
EXPORT_C __NAKED__ long long __muldi3(long long /*multiplicand*/, long long /*multiplier*/)
sl@0
   204
	{
sl@0
   205
	asm("mul r1, r2, r1 ");				// r1=low2*high1
sl@0
   206
	asm("mov ip, r0 ");					// ip=low1
sl@0
   207
	asm("mla r1, r0, r3, r1 ");			// r1+=low1*high2
sl@0
   208
	asm("mov r0, #0 ");
sl@0
   209
	asm("umlal r0, r1, r2, ip ");		// r1:r0 += high1*low1
sl@0
   210
	__JUMP(,lr);
sl@0
   211
	}
sl@0
   212
sl@0
   213
EXPORT_C __NAKED__ long long __negdi2(long long /*argument*/)
sl@0
   214
	{
sl@0
   215
	asm("rsbs r0, r0, #0 ");		// r0=0-r0, set carry
sl@0
   216
	asm("rscs r1, r1, #0 ");		// r1=0-r1-(1-C)
sl@0
   217
	__JUMP(,lr);
sl@0
   218
	}
sl@0
   219
sl@0
   220
EXPORT_C __NAKED__ unsigned long long __udivmoddi4 (unsigned long long /*dividend*/,
sl@0
   221
													unsigned long long /*divisor*/,
sl@0
   222
													unsigned long long* /*p_remainder*/)
sl@0
   223
	{
sl@0
   224
	asm("stmfd sp!, {r4-r7,lr} ");
sl@0
   225
	asm("bl UDiv01 ");					// do the division, quotient in r5:r4 remainder in r6:r3
sl@0
   226
	asm("ldr r7, [sp, #20] ");			// r7=p_remainder
sl@0
   227
	asm("mov r0, r4 ");					// r0=quotient low
sl@0
   228
	asm("stmia r7, {r3,r6} ");			// store remainder
sl@0
   229
	asm("mov r1, r5 ");					// r0=quotient high
sl@0
   230
	__POPRET("r4-r7,");
sl@0
   231
	}
sl@0
   232
sl@0
   233
EXPORT_C __NAKED__ int __cmpdi2(long long /*a*/, long long /*b*/)
sl@0
   234
	{
sl@0
   235
	// return 0 if a<b, 1 if a=b, 2 if a>b
sl@0
   236
	asm("subs r0, r2, r0 ");
sl@0
   237
	asm("sbcs r1, r3, r1 ");			// r1:r0 = b-a, set flags
sl@0
   238
	asm("movlt r0, #2 ");				// if b<a r0=2
sl@0
   239
	__JUMP(lt,lr);						// if b<a return
sl@0
   240
	asm("cmpeq r0, #0 ");				// if top word of difference=0, look at bottom
sl@0
   241
	asm("moveq r0, #1 ");				// if a=b, r0=1
sl@0
   242
	asm("movne r0, #0 ");				// else r=0
sl@0
   243
	__JUMP(,lr);
sl@0
   244
	}
sl@0
   245
sl@0
   246
EXPORT_C __NAKED__ int __ucmpdi2(unsigned long long /*a*/, unsigned long long /*b*/)
sl@0
   247
	{
sl@0
   248
	// return 0 if a<b, 1 if a=b, 2 if a>b
sl@0
   249
	asm("cmp r1, r3 ");
sl@0
   250
	asm("cmpeq r0, r2 ");				// compare r1:r0 - r3:r2
sl@0
   251
	asm("movhi r0, #2 ");				// r0=2 if a>b
sl@0
   252
	asm("moveq r0, #1 ");				// r0=1 if a=b
sl@0
   253
	asm("movlo r0, #0 ");				// r0=0 if a<b
sl@0
   254
	__JUMP(,lr);
sl@0
   255
	}
sl@0
   256
#endif
sl@0
   257
sl@0
   258
#if defined(__GCC32__)
sl@0
   259
void __division_by_zero();
sl@0
   260
#define DIV_BY_ZERO " __division_by_zero "
sl@0
   261
#elif defined(__ARMCC__)
sl@0
   262
void __rt_div0 (void);
sl@0
   263
#define DIV_BY_ZERO " __cpp(__rt_div0) "
sl@0
   264
#endif
sl@0
   265
sl@0
   266
EXPORT_C __NAKED__ TUint __umodsi3(TUint /*dividend*/,TUint /*divisor*/)
sl@0
   267
//
sl@0
   268
// Unsigned divide of r0 by r1: returns remainder in r0, quotient in r3
sl@0
   269
// Sign of remainder = sign of dividend.
sl@0
   270
// Destroys r2, r3
sl@0
   271
//
sl@0
   272
    {
sl@0
   273
sl@0
   274
    asm("__umodsi3_start:");
sl@0
   275
//
sl@0
   276
// Use lookup table for divisors less than 17, and jump to
sl@0
   277
// an optimised routine if available
sl@0
   278
// 
sl@0
   279
    asm("MOV     r3, #0                     ");
sl@0
   280
    asm("CMP     r1, #16                    ");
sl@0
   281
    asm("LDRLS   r3, [pc, #modtable - . - 8]");
sl@0
   282
    asm("LDRLS   r3, [r3, r1, asl #2]       ");
sl@0
   283
    asm("CMP     r3, #0                     ");
sl@0
   284
	__JUMP(NE,r3);
sl@0
   285
//
sl@0
   286
// r3 must be zero when entering this point
sl@0
   287
//
sl@0
   288
    asm("MOV     r2, r1                     ");
sl@0
   289
sl@0
   290
    asm("__umodsi3_loop:                    ");
sl@0
   291
    asm("CMP     r2, r0, LSR #8             ");
sl@0
   292
    asm("MOVLS   r2, r2, LSL #8             ");
sl@0
   293
    asm("BLO     __umodsi3_loop             ");
sl@0
   294
sl@0
   295
    asm("CMP     r2, r0, LSR #1             ");
sl@0
   296
    asm("BHI     __umodsi3_jump7            ");
sl@0
   297
    asm("CMP     r2, r0, LSR #2             ");
sl@0
   298
    asm("BHI     __umodsi3_jump6            ");
sl@0
   299
    asm("CMP     r2, r0, LSR #3             ");
sl@0
   300
    asm("BHI     __umodsi3_jump5            ");
sl@0
   301
    asm("CMP     r2, r0, LSR #4             ");
sl@0
   302
    asm("BHI     __umodsi3_jump4            ");
sl@0
   303
    asm("CMP     r2, r0, LSR #5             ");
sl@0
   304
    asm("BHI     __umodsi3_jump3            ");
sl@0
   305
    asm("CMP     r2, r0, LSR #6             ");
sl@0
   306
    asm("BHI     __umodsi3_jump2            ");
sl@0
   307
    asm("CMP     r2, r0, LSR #7             ");
sl@0
   308
    asm("BHI     __umodsi3_jump1            ");
sl@0
   309
sl@0
   310
    asm("__umodsi3_loop2:                   ");
sl@0
   311
    asm("MOVHI   r2, r2, LSR #8             ");
sl@0
   312
sl@0
   313
    asm("CMP     r0, r2, LSL #7             ");
sl@0
   314
    asm("ADC     r3, r3, r3                 ");
sl@0
   315
    asm("SUBCS   r0, r0, r2, LSL #7         ");
sl@0
   316
    asm("CMP     r0, r2, LSL #6             ");
sl@0
   317
sl@0
   318
    asm("__umodsi3_jump1:                   ");
sl@0
   319
    asm("ADC     r3, r3, r3                 ");
sl@0
   320
    asm("SUBCS   r0, r0, r2, LSL #6         ");
sl@0
   321
    asm("CMP     r0, r2, LSL #5             ");
sl@0
   322
    asm("__umodsi3_jump2:                   ");
sl@0
   323
    asm("ADC     r3, r3, r3                 ");
sl@0
   324
    asm("SUBCS   r0, r0, r2, LSL #5         ");
sl@0
   325
    asm("CMP     r0, r2, LSL #4             ");
sl@0
   326
    asm("__umodsi3_jump3:                   ");
sl@0
   327
    asm("ADC     r3, r3, r3                 ");
sl@0
   328
    asm("SUBCS   r0, r0, r2, LSL #4         ");
sl@0
   329
    asm("CMP     r0, r2, LSL #3             ");
sl@0
   330
    asm("__umodsi3_jump4:                   ");
sl@0
   331
    asm("ADC     r3, r3, r3                 ");
sl@0
   332
    asm("SUBCS   r0, r0, r2, LSL #3         ");
sl@0
   333
    asm("CMP     r0, r2, LSL #2             ");
sl@0
   334
    asm("__umodsi3_jump5:                   ");
sl@0
   335
    asm("ADC     r3, r3, r3                 ");
sl@0
   336
    asm("SUBCS   r0, r0, r2, LSL #2         ");
sl@0
   337
    asm("CMP     r0, r2, LSL #1             ");
sl@0
   338
    asm("__umodsi3_jump6:                   ");
sl@0
   339
    asm("ADC     r3, r3, r3                 ");
sl@0
   340
    asm("SUBCS   r0, r0, r2, LSL #1         ");
sl@0
   341
    asm("__umodsi3_jump7:                   ");
sl@0
   342
    asm("CMP     r0, r2                     ");
sl@0
   343
    asm("ADC     r3, r3, r3                 ");
sl@0
   344
    asm("SUBCS   r0, r0, r2                 ");
sl@0
   345
sl@0
   346
    asm("CMP     r2, r1                     ");
sl@0
   347
    asm("BNE     __umodsi3_loop2            ");
sl@0
   348
sl@0
   349
	__JUMP(,lr);
sl@0
   350
sl@0
   351
    asm("modtable:                          ");
sl@0
   352
    asm(".word   mod_jump_table             ");
sl@0
   353
//
sl@0
   354
// Lookup for optimised divide routines
sl@0
   355
//
sl@0
   356
    asm("mod_jump_table:                    ");
sl@0
   357
    asm(".word " DIV_BY_ZERO); // 0
sl@0
   358
    asm(".word   __mod1                     "); // 1
sl@0
   359
    asm(".word   __mod2                     "); // 2
sl@0
   360
    asm(".word   0                          "); // 3
sl@0
   361
    asm(".word   __mod4                     "); // 4
sl@0
   362
    asm(".word   __mod5                     "); // 5
sl@0
   363
    asm(".word   0                          "); // 6
sl@0
   364
    asm(".word   __mod7                     "); // 7
sl@0
   365
    asm(".word   __mod8                     "); // 8
sl@0
   366
    asm(".word   0                          "); // 9
sl@0
   367
    asm(".word   __mod10                    "); // 10
sl@0
   368
    asm(".word   0                          "); // 11
sl@0
   369
    asm(".word   0                          "); // 12
sl@0
   370
    asm(".word   0                          "); // 13
sl@0
   371
    asm(".word   0                          "); // 14
sl@0
   372
    asm(".word   0                          "); // 15
sl@0
   373
    asm(".word   __mod16                    "); // 16
sl@0
   374
sl@0
   375
    asm("__mod16:                           ");
sl@0
   376
    asm("MOV     r3,r0,LSR #4               ");
sl@0
   377
    asm("AND     r0,r0,#15                  ");
sl@0
   378
	__JUMP(,lr);
sl@0
   379
sl@0
   380
    asm("__mod1:                            ");
sl@0
   381
    asm("MOV     r3,r0                      ");
sl@0
   382
    asm("MOV     r0,#0                      ");
sl@0
   383
	__JUMP(,lr);
sl@0
   384
sl@0
   385
    asm("__mod2:                            ");
sl@0
   386
    asm("MOV     r3,r0,LSR #1               ");
sl@0
   387
    asm("AND     r0,r0,#1                   ");
sl@0
   388
	__JUMP(,lr);
sl@0
   389
sl@0
   390
    asm("__mod4:                            ");
sl@0
   391
    asm("MOV     r3,r0,LSR #2               ");
sl@0
   392
    asm("AND     r0,r0,#3                   ");
sl@0
   393
	__JUMP(,lr);
sl@0
   394
sl@0
   395
    asm("__mod8:                            ");
sl@0
   396
    asm("MOV     r3,r0,LSR #3               ");
sl@0
   397
    asm("AND     r0,r0,#7                   ");
sl@0
   398
	__JUMP(,lr);
sl@0
   399
sl@0
   400
    asm("__mod10:                           ");
sl@0
   401
    asm("MOV     r3, r0                     ");
sl@0
   402
    asm("SUB     r0, r3, #10                ");
sl@0
   403
    asm("SUB     r3, r3, r3, LSR #2         ");
sl@0
   404
    asm("ADD     r3, r3, r3, LSR #4         ");
sl@0
   405
    asm("ADD     r3, r3, r3, LSR #8         ");
sl@0
   406
    asm("ADD     r3, r3, r3, LSR #16        ");
sl@0
   407
    asm("MOV     r3, r3, LSR #3             ");
sl@0
   408
    asm("ADD     r2, r3, r3, ASL #2         ");
sl@0
   409
    asm("SUBS    r0, r0, r2, ASL #1         ");
sl@0
   410
    asm("ADDPL   r3, r3, #1                 ");
sl@0
   411
    asm("ADDMI   r0, r0, #10                ");
sl@0
   412
	__JUMP(,lr);
sl@0
   413
sl@0
   414
    asm("__mod7:                            ");
sl@0
   415
    asm("MOV     r3, r0                     ");
sl@0
   416
	asm("SUB     r0, r3, #7                 ");
sl@0
   417
	asm("MOV     r3, r3, lsr #1             ");
sl@0
   418
	asm("ADD     r3, r3, r3, lsr #3         ");
sl@0
   419
	asm("ADD     r3, r3, r3, lsr #6         ");
sl@0
   420
	asm("ADD     r3, r3, r3, lsr #12        ");
sl@0
   421
	asm("ADD     r3, r3, r3, lsr #24        ");
sl@0
   422
	asm("MOV     r3, r3, lsr #2             ");
sl@0
   423
	asm("RSB     r2, r3, r3, asl #3         ");
sl@0
   424
	asm("SUBS    r0, r0, r2, asl #0         ");
sl@0
   425
	asm("ADDPL   r3, r3, #1                 ");
sl@0
   426
	asm("ADDMI   r0, r0, #7                 ");
sl@0
   427
	__JUMP(,lr);
sl@0
   428
sl@0
   429
    asm("__mod5:                            ");
sl@0
   430
    asm("MOV     r3, r0                     ");
sl@0
   431
	asm("SUB     r0, r3, #5                 ");
sl@0
   432
	asm("SUB     r3, r3, r3, lsr #2         ");
sl@0
   433
	asm("ADD     r3, r3, r3, lsr #4         ");
sl@0
   434
	asm("ADD     r3, r3, r3, lsr #8         ");
sl@0
   435
	asm("ADD     r3, r3, r3, lsr #16        ");
sl@0
   436
	asm("MOV     r3, r3, lsr #2             ");
sl@0
   437
	asm("ADD     r2, r3, r3, asl #2         ");
sl@0
   438
	asm("SUBS    r0, r0, r2, asl #0         ");
sl@0
   439
	asm("ADDPL   r3, r3, #1                 ");
sl@0
   440
	asm("ADDMI   r0, r0, #5                 ");
sl@0
   441
	__JUMP(,lr);
sl@0
   442
    }
sl@0
   443
sl@0
   444
sl@0
   445
EXPORT_C __NAKED__ unsigned long long __udivdi3(unsigned long long /*dividend*/, unsigned long long /*divisor*/)
sl@0
   446
//
sl@0
   447
// Dividend in r1:r0, divisor in r3:r2, Return quotient in r1:r0
sl@0
   448
//
sl@0
   449
	{
sl@0
   450
	asm("stmfd sp!, {r4-r7,lr} ");
sl@0
   451
	asm("bl UDiv01 ");					// do the division, result in r4,r5
sl@0
   452
	asm("mov r0, r4 ");
sl@0
   453
	asm("mov r1, r5 ");
sl@0
   454
	__POPRET("r4-r7,");
sl@0
   455
sl@0
   456
	// Unsigned 64-bit division. Dividend in r0,r1, divisor in r2,r3
sl@0
   457
	// Quotient returned in r4,r5, Remainder in r3,r6
sl@0
   458
	// Registers r0-r7,r12 used, r8-r11 unmodified
sl@0
   459
	asm(".global UDiv01 ");
sl@0
   460
	asm("UDiv01: ");
sl@0
   461
	asm("movs r3, r3 ");				// check if divisor fits in 32 bits
sl@0
   462
	asm("bne udiv64a ");				// branch if not
sl@0
   463
	asm("movs r2, r2 ");				// check if divisor fits in 31 bits
sl@0
   464
	asm("bmi udiv64e ");				// branch if not
sl@0
   465
	asm("beq udiv64_divby0 ");			// if divisor=0, branch to error routine
sl@0
   466
sl@0
   467
	// Divisor is <0x80000000
sl@0
   468
	// This means that a 32-bit accumulator is sufficient
sl@0
   469
	asm("mov r4, #0 ");					// use r3 as acc, result in r4, r5
sl@0
   470
	asm("mov r5, #0 ");
sl@0
   471
	asm("mov r6, #8 ");					// do 2 set of 32 iterations
sl@0
   472
	asm("udiv64b: ");
sl@0
   473
	asm("adds r1, r1, r1 ");			// shift dividend left into acc
sl@0
   474
	asm("adcs r3, r3, r3 ");
sl@0
   475
	asm("subs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   476
	asm("adc r5, r5, r5 ");				// shift result bit left into quotient
sl@0
   477
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   478
	asm("adds r1, r1, r1 ");			// shift dividend left into acc
sl@0
   479
	asm("adcs r3, r3, r3 ");
sl@0
   480
	asm("subs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   481
	asm("adc r5, r5, r5 ");				// shift result bit left into quotient
sl@0
   482
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   483
	asm("adds r1, r1, r1 ");			// shift dividend left into acc
sl@0
   484
	asm("adcs r3, r3, r3 ");
sl@0
   485
	asm("subs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   486
	asm("adc r5, r5, r5 ");				// shift result bit left into quotient
sl@0
   487
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   488
	asm("adds r1, r1, r1 ");			// shift dividend left into acc
sl@0
   489
	asm("adcs r3, r3, r3 ");
sl@0
   490
	asm("subs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   491
	asm("adc r5, r5, r5 ");				// shift result bit left into quotient
sl@0
   492
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   493
	asm("subs r6, r6, #1 ");			// loop
sl@0
   494
	asm("bne udiv64b ");
sl@0
   495
	asm("mov r6, #8 ");					// 2nd set of 32 iterations
sl@0
   496
	asm("udiv64c: ");
sl@0
   497
	asm("adds r0, r0, r0 ");			// shift dividend left into acc
sl@0
   498
	asm("adcs r3, r3, r3 ");
sl@0
   499
	asm("subs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   500
	asm("adc r4, r4, r4 ");				// shift result bit left into quotient
sl@0
   501
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   502
	asm("adds r0, r0, r0 ");			// shift dividend left into acc
sl@0
   503
	asm("adcs r3, r3, r3 ");
sl@0
   504
	asm("subs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   505
	asm("adc r4, r4, r4 ");				// shift result bit left into quotient
sl@0
   506
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   507
	asm("adds r0, r0, r0 ");			// shift dividend left into acc
sl@0
   508
	asm("adcs r3, r3, r3 ");
sl@0
   509
	asm("subs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   510
	asm("adc r4, r4, r4 ");				// shift result bit left into quotient
sl@0
   511
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   512
	asm("adds r0, r0, r0 ");			// shift dividend left into acc
sl@0
   513
	asm("adcs r3, r3, r3 ");
sl@0
   514
	asm("subs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   515
	asm("adc r4, r4, r4 ");				// shift result bit left into quotient
sl@0
   516
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   517
	asm("subs r6, r6, #1 ");			// loop
sl@0
   518
	asm("bne udiv64c ");
sl@0
   519
	__JUMP(,lr);
sl@0
   520
sl@0
   521
	// 2^31 <= Divisor < 2^32
sl@0
   522
	// Need 33-bit accumulator - use carry flag as 33rd bit
sl@0
   523
	asm("udiv64e: ");
sl@0
   524
	asm("mov r4, #0 ");					// use r3 as acc, result in r4, r5
sl@0
   525
	asm("mov r5, #0 ");
sl@0
   526
	asm("mov r6, #8 ");					// do 2 set of 32 iterations
sl@0
   527
	asm("udiv64f: ");
sl@0
   528
	asm("adds r1, r1, r1 ");			// shift dividend left into acc
sl@0
   529
	asm("adcs r3, r3, r3 ");
sl@0
   530
	asm("subcs r3, r3, r2 ");
sl@0
   531
	asm("subccs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   532
	asm("adc r5, r5, r5 ");				// shift result bit left into quotient
sl@0
   533
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   534
	asm("adds r1, r1, r1 ");			// shift dividend left into acc
sl@0
   535
	asm("adcs r3, r3, r3 ");
sl@0
   536
	asm("subcs r3, r3, r2 ");
sl@0
   537
	asm("subccs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   538
	asm("adc r5, r5, r5 ");				// shift result bit left into quotient
sl@0
   539
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   540
	asm("adds r1, r1, r1 ");			// shift dividend left into acc
sl@0
   541
	asm("adcs r3, r3, r3 ");
sl@0
   542
	asm("subcs r3, r3, r2 ");
sl@0
   543
	asm("subccs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   544
	asm("adc r5, r5, r5 ");				// shift result bit left into quotient
sl@0
   545
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   546
	asm("adds r1, r1, r1 ");			// shift dividend left into acc
sl@0
   547
	asm("adcs r3, r3, r3 ");
sl@0
   548
	asm("subcs r3, r3, r2 ");
sl@0
   549
	asm("subccs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   550
	asm("adc r5, r5, r5 ");				// shift result bit left into quotient
sl@0
   551
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   552
	asm("subs r6, r6, #1 ");			// loop
sl@0
   553
	asm("bne udiv64f ");
sl@0
   554
	asm("mov r6, #8 ");					// 2nd set of 32 iterations
sl@0
   555
	asm("udiv64g: ");
sl@0
   556
	asm("adds r0, r0, r0 ");			// shift dividend left into acc
sl@0
   557
	asm("adcs r3, r3, r3 ");
sl@0
   558
	asm("subcs r3, r3, r2 ");
sl@0
   559
	asm("subccs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   560
	asm("adc r4, r4, r4 ");				// shift result bit left into quotient
sl@0
   561
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   562
	asm("adds r0, r0, r0 ");			// shift dividend left into acc
sl@0
   563
	asm("adcs r3, r3, r3 ");
sl@0
   564
	asm("subcs r3, r3, r2 ");
sl@0
   565
	asm("subccs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   566
	asm("adc r4, r4, r4 ");				// shift result bit left into quotient
sl@0
   567
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   568
	asm("adds r0, r0, r0 ");			// shift dividend left into acc
sl@0
   569
	asm("adcs r3, r3, r3 ");
sl@0
   570
	asm("subcs r3, r3, r2 ");
sl@0
   571
	asm("subccs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   572
	asm("adc r4, r4, r4 ");				// shift result bit left into quotient
sl@0
   573
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   574
	asm("adds r0, r0, r0 ");			// shift dividend left into acc
sl@0
   575
	asm("adcs r3, r3, r3 ");
sl@0
   576
	asm("subcs r3, r3, r2 ");
sl@0
   577
	asm("subccs r3, r3, r2 ");			// subtract divisor from acc
sl@0
   578
	asm("adc r4, r4, r4 ");				// shift result bit left into quotient
sl@0
   579
	asm("addcc r3, r3, r2 ");			// if borrow, add back
sl@0
   580
	asm("subs r6, r6, #1 ");			// loop
sl@0
   581
	asm("bne udiv64g ");
sl@0
   582
	__JUMP(,lr);
sl@0
   583
	
sl@0
   584
	// Divisor >= 2^32, so quotient < 2^32
sl@0
   585
	// Use 64 bit accumulator, 32 bit quotient
sl@0
   586
	asm("udiv64a: ");
sl@0
   587
	asm("mov r4, #0 ");					// quotient in r4, use r1, r6 as accumulator
sl@0
   588
	asm("mov r6, #0 ");
sl@0
   589
	asm("mov r5, #8 ");					// do 32 iterations
sl@0
   590
	asm("udiv64d: ");
sl@0
   591
	asm("adds r0, r0, r0 ");			// shift dividend left into acc
sl@0
   592
	asm("adcs r1, r1, r1 ");
sl@0
   593
	asm("adcs r6, r6, r6 ");
sl@0
   594
	asm("subs r7, r1, r2 ");			// subtract divisor from acc, result into r7,r12
sl@0
   595
	asm("sbcs r12, r6, r3 ");
sl@0
   596
	asm("adc r4, r4, r4 ");				// shift result bit left into quotient
sl@0
   597
	asm("movcs r1, r7 ");				// if no borrow, update acc
sl@0
   598
	asm("movcs r6, r12 ");
sl@0
   599
	asm("adds r0, r0, r0 ");			// shift dividend left into acc
sl@0
   600
	asm("adcs r1, r1, r1 ");
sl@0
   601
	asm("adcs r6, r6, r6 ");
sl@0
   602
	asm("subs r7, r1, r2 ");			// subtract divisor from acc, result into r7,r12
sl@0
   603
	asm("sbcs r12, r6, r3 ");
sl@0
   604
	asm("adc r4, r4, r4 ");				// shift result bit left into quotient
sl@0
   605
	asm("movcs r1, r7 ");				// if no borrow, update acc
sl@0
   606
	asm("movcs r6, r12 ");
sl@0
   607
	asm("adds r0, r0, r0 ");			// shift dividend left into acc
sl@0
   608
	asm("adcs r1, r1, r1 ");
sl@0
   609
	asm("adcs r6, r6, r6 ");
sl@0
   610
	asm("subs r7, r1, r2 ");			// subtract divisor from acc, result into r7,r12
sl@0
   611
	asm("sbcs r12, r6, r3 ");
sl@0
   612
	asm("adc r4, r4, r4 ");				// shift result bit left into quotient
sl@0
   613
	asm("movcs r1, r7 ");				// if no borrow, update acc
sl@0
   614
	asm("movcs r6, r12 ");
sl@0
   615
	asm("adds r0, r0, r0 ");			// shift dividend left into acc
sl@0
   616
	asm("adcs r1, r1, r1 ");
sl@0
   617
	asm("adcs r6, r6, r6 ");
sl@0
   618
	asm("subs r7, r1, r2 ");			// subtract divisor from acc, result into r7,r12
sl@0
   619
	asm("sbcs r12, r6, r3 ");
sl@0
   620
	asm("adc r4, r4, r4 ");				// shift result bit left into quotient
sl@0
   621
	asm("movcs r1, r7 ");				// if no borrow, update acc
sl@0
   622
	asm("movcs r6, r12 ");
sl@0
   623
	asm("subs r5, r5, #1 ");			// loop
sl@0
   624
	asm("bne udiv64d ");
sl@0
   625
	asm("mov r3, r1 ");					// remainder in r3,r6
sl@0
   626
	__JUMP(,lr);
sl@0
   627
sl@0
   628
	asm("udiv64_divby0: ");
sl@0
   629
	asm("stmfd sp!, {r11,lr} ");
sl@0
   630
	__EH_FRAME_PUSH2(r11,lr)
sl@0
   631
	asm("mov r11, sp ");
sl@0
   632
	asm("bic sp, sp, #4 ");
sl@0
   633
	asm("bl " DIV_BY_ZERO);
sl@0
   634
	asm("mov sp, r11 ");
sl@0
   635
	__POPRET("r11,");
sl@0
   636
	}
sl@0
   637
sl@0
   638
}
sl@0
   639