OpenCores
URL https://opencores.org/ocsvn/amber/amber/trunk

Subversion Repositories amber

[/] [amber/] [trunk/] [sw/] [mini-libc/] [libc_asm.S] - Blame information for rev 42

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 csantifort
/*----------------------------------------------------------------
2
//                                                              //
3
//  libc_asm.S                                                  //
4
//                                                              //
5
//  This file is part of the Amber project                      //
6
//  http://www.opencores.org/project,amber                      //
7
//                                                              //
8
//  Description                                                 //
9
//  Assembly routines for the mini-libc library.                //
10
//                                                              //
11
//  Author(s):                                                  //
12
//      - Conor Santifort, csantifort.amber@gmail.com           //
13
//                                                              //
14
//////////////////////////////////////////////////////////////////
15
//                                                              //
16
// Copyright (C) 2010 Authors and OPENCORES.ORG                 //
17
//                                                              //
18
// This source file may be used and distributed without         //
19
// restriction provided that this copyright statement is not    //
20
// removed from the file and that any derivative work contains  //
21
// the original copyright notice and the associated disclaimer. //
22
//                                                              //
23
// This source file is free software; you can redistribute it   //
24
// and/or modify it under the terms of the GNU Lesser General   //
25
// Public License as published by the Free Software Foundation; //
26
// either version 2.1 of the License, or (at your option) any   //
27
// later version.                                               //
28
//                                                              //
29
// This source is distributed in the hope that it will be       //
30
// useful, but WITHOUT ANY WARRANTY; without even the implied   //
31
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
32
// PURPOSE.  See the GNU Lesser General Public License for more //
33
// details.                                                     //
34
//                                                              //
35
// You should have received a copy of the GNU Lesser General    //
36
// Public License along with this source; if not, download it   //
37
// from http://www.opencores.org/lgpl.shtml                     //
38
//                                                              //
39
----------------------------------------------------------------*/
40
 
41
#include "amber_registers.h"
42
 
43
 
44
/* _testfail: Used to terminate execution in Verilog simulations */
45
/* On the board just puts the processor into an infinite loop    */
46
        .section .text
47
        .globl _testfail
48
_testfail:
49
        ldr     r11, AdrTestStatus
50
        str     r0, [r11]
51
        b       _testfail
52
 
53
 
54
/* _testpass: Used to terminate execution in Verilog simulations */
55
/* On the board just puts the processor into an infinite loop    */
56
        .globl _testpass
57
_testpass:
58
        ldr     r11, AdrTestStatus
59
        mov     r10, #17
60
        str     r10, [r11]
61
        b       _testpass
62
 
63
/* _outbyte: Output a single character through UART 0 */
64
        @ if the uart tx fifo is stuck full
65
        @ this routine will cycle forever
66
        .globl _outbyte
67
_outbyte:
68
        ldr     r1, AdrUARTDR
69
        ldr     r3, AdrUARTFR
70
        @ Check the tx_full flag
71
1:      ldr     r2, [r3]
72
        and     r2, r2, #0x20
73
        cmp     r2, #0
74
        streqb  r0, [r1]
75
        moveqs  pc, lr          @ return
76
        bne     1b
77
 
78
 
79
/* _inbyte: Input a single character from UART 0 */
80
        @ r0 is the timeout in mS
81
        .globl _inbyte
82
_inbyte:
83
        ldr     r2, AdrUARTDR @ data
84
        ldr     r3, AdrUARTFR @ flags
85
 
86
        @ Multiple delay value by 2560
87
        @ as the delay loop takes about 12 clock cycles running cached
88
        @ so that factor gives 1:1mS @33MHz
89
        mov     r1, r0, lsl #11
90
        add     r1, r1, r0, lsl #9
91
 
92
        @ Check the r2 empty flag
93
2:      ldr     r0, [r3]
94
        ands    r0, r0, #0x10
95
        ldreqb  r0, [r2]
96
        moveq   pc, lr
97
 
98
        @ decrement timeout
99
        subs    r1, r1, #1
100
        bne     2b
101
 
102
        mov     r0, #-1
103
        movs    pc, lr
104
 
105
 
106
/* _div: Integer division function */
107
        @ Divide r0 by r1
108
        @ Answer returned in r1
109
        .globl _div
110 31 csantifort
        .globl __aeabi_idiv
111
__aeabi_idiv:
112 2 csantifort
_div:
113
        stmdb   sp!, {r4, lr}
114
 
115 33 csantifort
        @ set r4 to 1 if one of the two inputs is negative
116
        and     r2, r0, #0x80000000
117
        and     r3, r1, #0x80000000
118
        eor     r4, r2, r3
119
 
120
        @ Invert negative numbers
121
        tst     r0, #0x80000000
122
        mvnne   r0, r0
123
        addne   r0, r0, #1
124
 
125
        tst     r1, #0x80000000
126
        mvnne   r1, r1
127
        addne   r1, r1, #1
128
 
129 2 csantifort
        @ divide r1 by r2, also use registers r0 and r4
130
        mov     r2, r1
131
        mov     r1, r0
132
 
133
        cmp      r2, #0
134
        beq      3f
135
 
136
        @ In order to divide r1 by r2, the first thing we need to do is to shift r2
137
        @ left by the necessary number of places. The easiest method of doing this
138
        @ is simply by trial and error - shift until we discover that r2 has become
139
        @ too big, then stop.
140
        mov      r0,#0     @ clear r0 to accumulate result
141
        mov      r3,#1     @ set bit 0 in r3, which will be
142
                           @ shifted left then right
143
 
144
1:      cmp      r3, #0    @ escape on error
145
        moveq    r3, #0x10000000
146
        beq      2f
147
        cmp      r2,r1
148
        movls    r2,r2,lsl#1
149
        movls    r3,r3,lsl#1
150
        bls      1b
151
        @ shift r2 left until it is about to be bigger than r1
152
        @ shift r3 left in parallel in order to flag how far we have to go
153
 
154
        @ r0 will be used to hold the result. The role of r3 is more complicated.
155
        @ In effect, we are using r3 to mark where the right-hand end of r2 has got to
156
        @ - if we shift r2 three places left, this will be indicated by a value of %1000
157
        @ in r3. However, we also add it to r0 every time we manage a successful subtraction,
158
        @ since it marks the position of the digit currently being calculated in the answer.
159
        @ In the binary example (50 ÷ 10) above, we shifted the '10' two places left,
160
        @ so at the time of the first subtraction, r3 would have been %100, at the time
161
        @ of the second (which failed) it would have been %10, and at the time of the
162
        @ third %1. Adding it to r0 after each successful subtraction would have
163
        @ given us, once again, the answer of %101!
164
 
165
        @ Now for the loop that actually does the work:
166
2:      cmp       r1,r2      @ carry set if r1>r2 (don't ask why)
167
        subcs     r1,r1,r2   @ subtract r2 from r1 if this would
168
                             @ give a positive answer
169
        addcs     r0,r0,r3   @ and add the current bit in r3 to
170
                             @ the accumulating answer in r0
171
 
172
        @ In subtraction (a cmp instruction simulates a subtraction in
173
        @ order to set the flags), if r1 - r2 gives a positive answer and no 'borrow'
174
        @ is required, the carry flag is set. This is required in order to make SBC
175
        @ (Subtract with Carry) work properly when used to carry out a 64-bit subtraction,
176
        @ but it is confusing!
177
 
178
        @ In this case, we are turning it to our advantage. The carry flag is set to
179
        @ indicate that a successful subtraction is possible, i.e. one that doesn't
180
        @ generate a negative result, and the two following instructions are carried
181
        @ out only when the condition Carry Set applies. Note that the 'S' on the end
182
        @ of these instructions is part of the 'CS' condition code and does not mean
183
        @ that they set the flags!
184
 
185
        movs      r3,r3,lsr #1    @ Shift r3 right into carry flag
186
        movcc     r2,r2,lsr #1    @ and if bit 0 of r3 was zero, also
187
                                  @ shift r2 right
188
        bcc       2b              @ If carry not clear, r3 has shifted
189
                                  @ back to where it started, and we
190
                                  @ can end
191 33 csantifort
 
192
        @ if one of the inputs is negetive then return a negative result
193
        tst     r4, #0x80000000
194
        mvnne   r0, r0
195
        addne   r0, r0, #1
196 2 csantifort
3:      ldmia   sp!, {r4, pc}^
197
 
198
 
199 31 csantifort
/* strcpy: String copy function
200
    char * strcpy ( char * destination, const char * source );
201
    destination is returned
202
*/
203 2 csantifort
        @ r0 points to destination
204
        @ r1 points to source string which terminates with a 0
205
        .globl strcpy
206 31 csantifort
strcpy:
207 34 csantifort
        stmdb   sp!, {r4-r6, lr}
208 33 csantifort
        @ Use r6 to process the destination pointer.
209
        @ At the end of the function, r0 is returned, so need to preserve it
210 31 csantifort
        mov     r6, r0
211
        @ only if both strings are zero-aligned use the fast 'aligned' algorithm
212 33 csantifort
        orr     r2, r6, r1
213 34 csantifort
        tst     r2, #3
214 31 csantifort
        bne     strcpy_slow
215
 
216
strcpy_fast:
217
        @ process strings 12 bytes at a time
218
        ldmia   r1!, {r2-r5}
219
 
220
        @ check for a zero byte
221
        @ only need to examine one of the strings because
222
        @ they are equal up to this point!
223 34 csantifort
        tst     r2, #0xff
224
        tstne   r2, #0xff00
225
        tstne   r2, #0xff0000
226
        tstne   r2, #0xff000000
227 31 csantifort
        strne   r2, [r6], #4
228
        subeq   r1, r1, #4
229
 
230 34 csantifort
        tstne   r3, #0xff
231
        tstne   r3, #0xff00
232
        tstne   r3, #0xff0000
233
        tstne   r3, #0xff000000
234 31 csantifort
        strne   r3, [r6], #4
235
        subeq   r1, r1, #4
236
 
237 34 csantifort
        tstne   r4, #0xff
238
        tstne   r4, #0xff00
239
        tstne   r4, #0xff0000
240
        tstne   r4, #0xff000000
241 31 csantifort
        strne   r4, [r6], #4
242
        subeq   r1, r1, #4
243
 
244 34 csantifort
        tstne   r5, #0xff
245
        tstne   r5, #0xff00
246
        tstne   r5, #0xff0000
247
        tstne   r5, #0xff000000
248 31 csantifort
        strne   r5, [r6], #4
249
        subeq   r1, r1, #4
250
 
251
        @ loop back to look at next 12 bytes
252
        bne     strcpy_fast
253
 
254
        @ the source string contains a zero character
255
 
256 34 csantifort
 
257
strcpy_aligned_slow:
258
        @ unroll the loop 4 times
259
        ldr     r3, [r1], #4
260
        strb    r3, [r6], #1
261
        ands    r4, r3,   #0xff
262
        ldmeqia sp!, {r4-r6, pc}^
263
 
264
        lsr     r3, r3, #8
265
        strb    r3, [r6], #1
266
        ands    r4, r3,   #0xff
267
        ldmeqia sp!, {r4-r6, pc}^
268
 
269
        lsr     r3, r3, #8
270
        strb    r3, [r6], #1
271
        ands    r4, r3,   #0xff
272
        ldmeqia sp!, {r4-r6, pc}^
273
 
274
        lsr     r3, r3, #8
275
        strb    r3, [r6], #1
276
        ands    r4, r3,   #0xff
277
        ldmeqia sp!, {r4-r6, pc}^
278
 
279
        b       strcpy_aligned_slow
280
 
281
 
282 31 csantifort
strcpy_slow:
283
        @ unroll the loop 4 times
284 2 csantifort
        ldrb    r3, [r1], #1
285 31 csantifort
        strb    r3, [r6], #1
286 2 csantifort
        cmp     r3, #0
287 34 csantifort
        ldmeqia sp!, {r4-r6, pc}^
288 31 csantifort
 
289
        ldrb    r3, [r1], #1
290
        strb    r3, [r6], #1
291
        cmp     r3, #0
292 34 csantifort
        ldmeqia sp!, {r4-r6, pc}^
293 31 csantifort
 
294
        ldrb    r3, [r1], #1
295
        strb    r3, [r6], #1
296
        cmp     r3, #0
297 34 csantifort
        ldmeqia sp!, {r4-r6, pc}^
298 31 csantifort
 
299
        ldrb    r3, [r1], #1
300
        strb    r3, [r6], #1
301
        cmp     r3, #0
302 34 csantifort
        ldmeqia sp!, {r4-r6, pc}^
303 31 csantifort
 
304
        b       strcpy_slow
305 2 csantifort
 
306
 
307 31 csantifort
/* int strcmp ( const char * str1, const char * str2 );
308
   A value greater than zero indicates that the first character
309
   that does not match has a greater value in str1 than in str2;
310
   And a value less than zero indicates the opposite.
311
*/
312
        .globl strcmp
313
strcmp:
314
        stmdb   sp!, {r4-r8, lr}
315
 
316
        @ only if both strings are zero-aligned use the fast 'aligned' algorithm
317
        orr     r2, r0, r1
318 34 csantifort
        tst     r2, #3
319 31 csantifort
        bne     strcmp_slow
320
 
321
strcmp_fast:
322
        @ process strings 12 bytes at a time
323
        ldmia   r0!, {r2-r4}
324
        ldmia   r1!, {r5-r7}
325
        cmp     r2, r5
326
        bne     1f
327
        cmpeq   r3, r6
328
        bne     2f
329
        cmpeq   r4, r7
330
        bne     3f
331
 
332
        @ strings are equal - find a zero byte
333
        @ only need to examine one of the strings because
334
        @ they are equal up to this point!
335 34 csantifort
        tst     r2, #0xff
336
        tstne   r2, #0xff00
337
        tstne   r2, #0xff0000
338
        tstne   r2, #0xff000000
339 31 csantifort
 
340 34 csantifort
        tstne   r3, #0xff
341
        tstne   r3, #0xff00
342
        tstne   r3, #0xff0000
343
        tstne   r3, #0xff000000
344 31 csantifort
 
345 34 csantifort
        tstne   r4, #0xff
346
        tstne   r4, #0xff00
347
        tstne   r4, #0xff0000
348
        tstne   r4, #0xff000000
349 31 csantifort
 
350
        @ loop back to look at next 12 bytes
351
        bne     strcmp_fast
352
 
353
        @ the first string contains a zero character
354
        @ the strings are the same, so both strings end
355
        moveq   r0, #0
356
        ldmeqia sp!, {r4-r8, pc}^
357
 
358
 
359
        @ Roll back the string pointers to before the mismatch
360
        @ then handle the remaining part byte by byte
361
1:      sub     r0, r0, #12
362
        sub     r1, r1, #12
363
 
364
strcmp_slow:
365
        ldrb    r2, [r0], #1
366
        ldrb    r3, [r1], #1
367
        eors    r4, r2, r3          @ are the bytes equal ?
368
        bne     bytes_different
369
        ldrb    r5, [r0], #1
370
        ldrb    r6, [r1], #1
371
        cmp     r2, #0              @ are they equal and zero ?
372
        beq     bytes_zero
373
        eors    r7, r5, r6          @ are the bytes equal ?
374
        bne     bytes_different
375
        ldrb    r2, [r0], #1
376
        ldrb    r3, [r1], #1
377
        cmp     r5, #0              @ are they equal and zero ?
378
        beq     bytes_zero
379
        eors    r4, r2, r3          @ are the bytes equal ?
380
        bne     bytes_different
381
        ldrb    r5, [r0], #1
382
        ldrb    r6, [r1], #1
383
        cmp     r2, #0              @ are they equal and zero ?
384
        beq     bytes_zero
385
        eors    r7, r5, r6          @ are the bytes equal ?
386
        bne     bytes_different
387
        cmp     r5, #0              @ are they equal and zero ?
388
        beq     bytes_zero
389
 
390
        bne     strcmp_slow
391
 
392
 
393
 
394
@ Skipping first 4 bytes so just check they
395
@ don't contain an end of string 0 character
396 34 csantifort
2:      tst    r2, #0xff
397
        tstne  r2, #0xff00
398
        tstne  r2, #0xff0000
399
        tstne  r2, #0xff000000
400 31 csantifort
        beq     bytes_zero
401
 
402
        @ start looking at 5th byte
403
        sub     r0, r0, #8
404
        sub     r1, r1, #8
405
 
406
        ldrb    r2, [r0], #1
407
        ldrb    r3, [r1], #1
408
        eors    r4, r2, r3          @ are the bytes equal ?
409
        bne     bytes_different
410
        ldrb    r5, [r0], #1
411
        ldrb    r6, [r1], #1
412
        cmp     r2, #0              @ are they equal and zero ?
413
        beq     bytes_zero
414
        eors    r7, r5, r6          @ are the bytes equal ?
415
        bne     bytes_different
416
        ldrb    r2, [r0], #1
417
        ldrb    r3, [r1], #1
418
        cmp     r5, #0              @ are they equal and zero ?
419
        beq     bytes_zero
420
        eors    r4, r2, r3          @ are the bytes equal ?
421
        bne     bytes_different
422
        ldrb    r5, [r0], #1
423
        ldrb    r6, [r1], #1
424
        cmp     r2, #0              @ are they equal and zero ?
425
        beq     bytes_zero
426
        eors    r7, r5, r6          @ are the bytes equal ?
427
        bne     bytes_different
428
        cmp     r5, #0              @ are they equal and zero ?
429
        beq     bytes_zero
430
 
431
        bne     strcmp_slow
432
 
433
@ Skipping first 8 bytes so just check they
434
@ don't contain an end of string 0 character
435 34 csantifort
3:      tst     r2, #0xff
436
        tstne   r2, #0xff00
437
        tstne   r2, #0xff0000
438
        tstne   r2, #0xff000000
439 31 csantifort
 
440 34 csantifort
        tstne   r3, #0xff
441
        tstne   r3, #0xff00
442
        tstne   r3, #0xff0000
443
        tstne   r3, #0xff000000
444 31 csantifort
        beq     bytes_zero
445
 
446
        sub     r0, r0, #4
447
        sub     r1, r1, #4
448
        ldrb    r2, [r0], #1
449
        ldrb    r3, [r1], #1
450
        eors    r4, r2, r3          @ are the bytes equal ?
451
        bne     bytes_different
452
        ldrb    r5, [r0], #1
453
        ldrb    r6, [r1], #1
454
        cmp     r2, #0              @ are they equal and zero ?
455
        beq     bytes_zero
456
        eors    r7, r5, r6          @ are the bytes equal ?
457
        bne     bytes_different
458
        ldrb    r2, [r0], #1
459
        ldrb    r3, [r1], #1
460
        cmp     r5, #0              @ are they equal and zero ?
461
        beq     bytes_zero
462
        eors    r4, r2, r3          @ are the bytes equal ?
463
        bne     bytes_different
464
        ldrb    r5, [r0], #1
465
        ldrb    r6, [r1], #1
466
        cmp     r2, #0              @ are they equal and zero ?
467
        beq     bytes_zero
468
        eors    r7, r5, r6          @ are the bytes equal ?
469
        bne     bytes_different
470
        cmp     r5, #0              @ are they equal and zero ?
471
        beq     bytes_zero
472
 
473
        bne     strcmp_slow
474
 
475
 
476
bytes_zero:
477
        moveq   r0, #0              @ if equal and zero, return zero
478
        ldmeqia sp!, {r4-r8, pc}^
479
 
480
 
481
bytes_different:
482
        sub     r0, r5, r6
483
        ldmia   sp!, {r4-r8, pc}^
484
 
485
 
486
 
487
        /* void *malloc(size_t size); */
488
        .globl malloc
489
malloc:
490
        ldr     r1, AdrMalloc
491
        ldr     r0, [r1]
492
        add     r0, r0, #0x10000
493
        str     r0, [r1]
494
        mov     pc, lr
495
 
496
 
497
 
498 2 csantifort
/* strncpy: String copy function */
499
        @ r0 points to destination
500
        @ r1 points to source string
501
        @ r2 is the number of bytes to copy
502
        .globl strncpy
503
strncpy:
504
        stmdb   sp!, {r4, lr}
505
        cmp     r2, #0
506
        beq     2f
507 33 csantifort
        add     r4, r0, r2    @ set r4 to the address of the last byte copied
508 2 csantifort
1:      ldrb    r3, [r1], #1
509
        strb    r3, [r0], #1
510
        cmp     r2,  r4
511 33 csantifort
        bne     1b
512 2 csantifort
2:      ldmia   sp!, {r4, pc}^
513
 
514
 
515
/* strncpy: String compare function */
516
        @ return the difference if the strings don't match
517
        .globl strncmp
518
strncmp:
519
        stmdb   sp!, {r4, r5, r6, lr}
520
 
521
        @ check for 0 length
522
        cmp     r2, #0
523
        moveq   r0, #1
524
        beq     2f
525
 
526
        mov     r3, #0
527
 
528
1:      add     r3, r3,   #1
529
        ldrb    r4, [r0], #1
530
        ldrb    r5, [r1], #1
531
 
532
        subs    r6, r4, r5
533
        movne   r0, r6
534
        bne     2f
535
 
536
        cmp     r3, r2
537
        moveq   r0, #0
538
        beq     2f
539
 
540
        b       1b
541
2:      ldmia   sp!, {r4, r5, r6, pc}^
542
 
543
 
544 31 csantifort
AdrMalloc:      .word  0x7000000
545 2 csantifort
AdrTestStatus:  .word  ADR_AMBER_TEST_STATUS
546
AdrUARTDR:      .word  ADR_AMBER_UART0_DR
547
AdrUARTFR:      .word  ADR_AMBER_UART0_FR
548
/* ========================================================================= */
549
/* ========================================================================= */
550
 
551
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.