/*----------------------------------------------------------------
|
/*----------------------------------------------------------------
|
// //
|
// //
|
// libc_asm.S //
|
// libc_asm.S //
|
// //
|
// //
|
// This file is part of the Amber project //
|
// This file is part of the Amber project //
|
// http://www.opencores.org/project,amber //
|
// http://www.opencores.org/project,amber //
|
// //
|
// //
|
// Description //
|
// Description //
|
// Assembly routines for the mini-libc library. //
|
// Assembly routines for the mini-libc library. //
|
// //
|
// //
|
// Author(s): //
|
// Author(s): //
|
// - Conor Santifort, csantifort.amber@gmail.com //
|
// - Conor Santifort, csantifort.amber@gmail.com //
|
// //
|
// //
|
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
// //
|
// //
|
// Copyright (C) 2010 Authors and OPENCORES.ORG //
|
// Copyright (C) 2010 Authors and OPENCORES.ORG //
|
// //
|
// //
|
// This source file may be used and distributed without //
|
// This source file may be used and distributed without //
|
// restriction provided that this copyright statement is not //
|
// restriction provided that this copyright statement is not //
|
// removed from the file and that any derivative work contains //
|
// removed from the file and that any derivative work contains //
|
// the original copyright notice and the associated disclaimer. //
|
// the original copyright notice and the associated disclaimer. //
|
// //
|
// //
|
// This source file is free software; you can redistribute it //
|
// This source file is free software; you can redistribute it //
|
// and/or modify it under the terms of the GNU Lesser General //
|
// and/or modify it under the terms of the GNU Lesser General //
|
// Public License as published by the Free Software Foundation; //
|
// Public License as published by the Free Software Foundation; //
|
// either version 2.1 of the License, or (at your option) any //
|
// either version 2.1 of the License, or (at your option) any //
|
// later version. //
|
// later version. //
|
// //
|
// //
|
// This source is distributed in the hope that it will be //
|
// This source is distributed in the hope that it will be //
|
// useful, but WITHOUT ANY WARRANTY; without even the implied //
|
// useful, but WITHOUT ANY WARRANTY; without even the implied //
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
|
// PURPOSE. See the GNU Lesser General Public License for more //
|
// PURPOSE. See the GNU Lesser General Public License for more //
|
// details. //
|
// details. //
|
// //
|
// //
|
// You should have received a copy of the GNU Lesser General //
|
// You should have received a copy of the GNU Lesser General //
|
// Public License along with this source; if not, download it //
|
// Public License along with this source; if not, download it //
|
// from http://www.opencores.org/lgpl.shtml //
|
// from http://www.opencores.org/lgpl.shtml //
|
// //
|
// //
|
----------------------------------------------------------------*/
|
----------------------------------------------------------------*/
|
|
|
#include "amber_registers.h"
|
#include "amber_registers.h"
|
|
|
|
|
/* _testfail: Used to terminate execution in Verilog simulations */
|
/* _testfail: Used to terminate execution in Verilog simulations */
|
/* On the board just puts the processor into an infinite loop */
|
/* On the board just puts the processor into an infinite loop */
|
.section .text
|
.section .text
|
.globl _testfail
|
.globl _testfail
|
_testfail:
|
_testfail:
|
ldr r11, AdrTestStatus
|
ldr r11, AdrTestStatus
|
str r0, [r11]
|
str r0, [r11]
|
b _testfail
|
b _testfail
|
|
|
|
|
/* _testpass: Used to terminate execution in Verilog simulations */
|
/* _testpass: Used to terminate execution in Verilog simulations */
|
/* On the board just puts the processor into an infinite loop */
|
/* On the board just puts the processor into an infinite loop */
|
.globl _testpass
|
.globl _testpass
|
_testpass:
|
_testpass:
|
ldr r11, AdrTestStatus
|
ldr r11, AdrTestStatus
|
mov r10, #17
|
mov r10, #17
|
str r10, [r11]
|
str r10, [r11]
|
b _testpass
|
b _testpass
|
|
|
/* _outbyte: Output a single character through UART 0 */
|
/* _outbyte: Output a single character through UART 0 */
|
@ if the uart tx fifo is stuck full
|
@ if the uart tx fifo is stuck full
|
@ this routine will cycle forever
|
@ this routine will cycle forever
|
.globl _outbyte
|
.globl _outbyte
|
_outbyte:
|
_outbyte:
|
ldr r1, AdrUARTDR
|
ldr r1, AdrUARTDR
|
ldr r3, AdrUARTFR
|
ldr r3, AdrUARTFR
|
@ Check the tx_full flag
|
@ Check the tx_full flag
|
1: ldr r2, [r3]
|
1: ldr r2, [r3]
|
and r2, r2, #0x20
|
and r2, r2, #0x20
|
cmp r2, #0
|
cmp r2, #0
|
streqb r0, [r1]
|
streqb r0, [r1]
|
moveqs pc, lr @ return
|
moveqs pc, lr @ return
|
bne 1b
|
bne 1b
|
|
|
|
|
/* _inbyte: Input a single character from UART 0 */
|
/* _inbyte: Input a single character from UART 0 */
|
@ r0 is the timeout in mS
|
@ r0 is the timeout in mS
|
.globl _inbyte
|
.globl _inbyte
|
_inbyte:
|
_inbyte:
|
ldr r2, AdrUARTDR @ data
|
ldr r2, AdrUARTDR @ data
|
ldr r3, AdrUARTFR @ flags
|
ldr r3, AdrUARTFR @ flags
|
|
|
@ Multiple delay value by 2560
|
@ Multiple delay value by 2560
|
@ as the delay loop takes about 12 clock cycles running cached
|
@ as the delay loop takes about 12 clock cycles running cached
|
@ so that factor gives 1:1mS @33MHz
|
@ so that factor gives 1:1mS @33MHz
|
mov r1, r0, lsl #11
|
mov r1, r0, lsl #11
|
add r1, r1, r0, lsl #9
|
add r1, r1, r0, lsl #9
|
|
|
@ Check the r2 empty flag
|
@ Check the r2 empty flag
|
2: ldr r0, [r3]
|
2: ldr r0, [r3]
|
ands r0, r0, #0x10
|
ands r0, r0, #0x10
|
ldreqb r0, [r2]
|
ldreqb r0, [r2]
|
moveq pc, lr
|
moveq pc, lr
|
|
|
@ decrement timeout
|
@ decrement timeout
|
subs r1, r1, #1
|
subs r1, r1, #1
|
bne 2b
|
bne 2b
|
|
|
mov r0, #-1
|
mov r0, #-1
|
movs pc, lr
|
movs pc, lr
|
|
|
|
|
/* _div: Integer division function */
|
/* _div: Integer division function */
|
@ Divide r0 by r1
|
@ Divide r0 by r1
|
@ Answer returned in r1
|
@ Answer returned in r1
|
.globl _div
|
.globl _div
|
.globl __aeabi_idiv
|
.globl __aeabi_idiv
|
__aeabi_idiv:
|
__aeabi_idiv:
|
_div:
|
_div:
|
stmdb sp!, {r4, lr}
|
stmdb sp!, {r4, lr}
|
|
|
@ set r4 to 1 if one of the two inputs is negative
|
@ set r4 to 1 if one of the two inputs is negative
|
and r2, r0, #0x80000000
|
and r2, r0, #0x80000000
|
and r3, r1, #0x80000000
|
and r3, r1, #0x80000000
|
eor r4, r2, r3
|
eor r4, r2, r3
|
|
|
@ Invert negative numbers
|
@ Invert negative numbers
|
tst r0, #0x80000000
|
tst r0, #0x80000000
|
mvnne r0, r0
|
mvnne r0, r0
|
addne r0, r0, #1
|
addne r0, r0, #1
|
|
|
tst r1, #0x80000000
|
tst r1, #0x80000000
|
mvnne r1, r1
|
mvnne r1, r1
|
addne r1, r1, #1
|
addne r1, r1, #1
|
|
|
@ divide r1 by r2, also use registers r0 and r4
|
@ divide r1 by r2, also use registers r0 and r4
|
mov r2, r1
|
mov r2, r1
|
mov r1, r0
|
mov r1, r0
|
|
|
cmp r2, #0
|
cmp r2, #0
|
beq 3f
|
beq 3f
|
|
|
@ In order to divide r1 by r2, the first thing we need to do is to shift r2
|
@ In order to divide r1 by r2, the first thing we need to do is to shift r2
|
@ left by the necessary number of places. The easiest method of doing this
|
@ left by the necessary number of places. The easiest method of doing this
|
@ is simply by trial and error - shift until we discover that r2 has become
|
@ is simply by trial and error - shift until we discover that r2 has become
|
@ too big, then stop.
|
@ too big, then stop.
|
mov r0,#0 @ clear r0 to accumulate result
|
mov r0,#0 @ clear r0 to accumulate result
|
mov r3,#1 @ set bit 0 in r3, which will be
|
mov r3,#1 @ set bit 0 in r3, which will be
|
@ shifted left then right
|
@ shifted left then right
|
|
|
1: cmp r3, #0 @ escape on error
|
1: cmp r3, #0 @ escape on error
|
moveq r3, #0x10000000
|
moveq r3, #0x10000000
|
beq 2f
|
beq 2f
|
cmp r2,r1
|
cmp r2,r1
|
movls r2,r2,lsl#1
|
movls r2,r2,lsl#1
|
movls r3,r3,lsl#1
|
movls r3,r3,lsl#1
|
bls 1b
|
bls 1b
|
@ shift r2 left until it is about to be bigger than r1
|
@ shift r2 left until it is about to be bigger than r1
|
@ shift r3 left in parallel in order to flag how far we have to go
|
@ shift r3 left in parallel in order to flag how far we have to go
|
|
|
@ r0 will be used to hold the result. The role of r3 is more complicated.
|
@ r0 will be used to hold the result. The role of r3 is more complicated.
|
@ In effect, we are using r3 to mark where the right-hand end of r2 has got to
|
@ In effect, we are using r3 to mark where the right-hand end of r2 has got to
|
@ - if we shift r2 three places left, this will be indicated by a value of %1000
|
@ - if we shift r2 three places left, this will be indicated by a value of %1000
|
@ in r3. However, we also add it to r0 every time we manage a successful subtraction,
|
@ in r3. However, we also add it to r0 every time we manage a successful subtraction,
|
@ since it marks the position of the digit currently being calculated in the answer.
|
@ since it marks the position of the digit currently being calculated in the answer.
|
@ In the binary example (50 ÷ 10) above, we shifted the '10' two places left,
|
@ In the binary example (50 ÷ 10) above, we shifted the '10' two places left,
|
@ so at the time of the first subtraction, r3 would have been %100, at the time
|
@ so at the time of the first subtraction, r3 would have been %100, at the time
|
@ of the second (which failed) it would have been %10, and at the time of the
|
@ of the second (which failed) it would have been %10, and at the time of the
|
@ third %1. Adding it to r0 after each successful subtraction would have
|
@ third %1. Adding it to r0 after each successful subtraction would have
|
@ given us, once again, the answer of %101!
|
@ given us, once again, the answer of %101!
|
|
|
@ Now for the loop that actually does the work:
|
@ Now for the loop that actually does the work:
|
2: cmp r1,r2 @ carry set if r1>r2 (don't ask why)
|
2: cmp r1,r2 @ carry set if r1>r2 (don't ask why)
|
subcs r1,r1,r2 @ subtract r2 from r1 if this would
|
subcs r1,r1,r2 @ subtract r2 from r1 if this would
|
@ give a positive answer
|
@ give a positive answer
|
addcs r0,r0,r3 @ and add the current bit in r3 to
|
addcs r0,r0,r3 @ and add the current bit in r3 to
|
@ the accumulating answer in r0
|
@ the accumulating answer in r0
|
|
|
@ In subtraction (a cmp instruction simulates a subtraction in
|
@ In subtraction (a cmp instruction simulates a subtraction in
|
@ order to set the flags), if r1 - r2 gives a positive answer and no 'borrow'
|
@ order to set the flags), if r1 - r2 gives a positive answer and no 'borrow'
|
@ is required, the carry flag is set. This is required in order to make SBC
|
@ is required, the carry flag is set. This is required in order to make SBC
|
@ (Subtract with Carry) work properly when used to carry out a 64-bit subtraction,
|
@ (Subtract with Carry) work properly when used to carry out a 64-bit subtraction,
|
@ but it is confusing!
|
@ but it is confusing!
|
|
|
@ In this case, we are turning it to our advantage. The carry flag is set to
|
@ In this case, we are turning it to our advantage. The carry flag is set to
|
@ indicate that a successful subtraction is possible, i.e. one that doesn't
|
@ indicate that a successful subtraction is possible, i.e. one that doesn't
|
@ generate a negative result, and the two following instructions are carried
|
@ generate a negative result, and the two following instructions are carried
|
@ out only when the condition Carry Set applies. Note that the 'S' on the end
|
@ out only when the condition Carry Set applies. Note that the 'S' on the end
|
@ of these instructions is part of the 'CS' condition code and does not mean
|
@ of these instructions is part of the 'CS' condition code and does not mean
|
@ that they set the flags!
|
@ that they set the flags!
|
|
|
movs r3,r3,lsr #1 @ Shift r3 right into carry flag
|
movs r3,r3,lsr #1 @ Shift r3 right into carry flag
|
movcc r2,r2,lsr #1 @ and if bit 0 of r3 was zero, also
|
movcc r2,r2,lsr #1 @ and if bit 0 of r3 was zero, also
|
@ shift r2 right
|
@ shift r2 right
|
bcc 2b @ If carry not clear, r3 has shifted
|
bcc 2b @ If carry not clear, r3 has shifted
|
@ back to where it started, and we
|
@ back to where it started, and we
|
@ can end
|
@ can end
|
|
|
@ if one of the inputs is negetive then return a negative result
|
@ if one of the inputs is negetive then return a negative result
|
tst r4, #0x80000000
|
tst r4, #0x80000000
|
mvnne r0, r0
|
mvnne r0, r0
|
addne r0, r0, #1
|
addne r0, r0, #1
|
3: ldmia sp!, {r4, pc}^
|
3: ldmia sp!, {r4, pc}^
|
|
|
|
|
/* strcpy: String copy function
|
/* strcpy: String copy function
|
char * strcpy ( char * destination, const char * source );
|
char * strcpy ( char * destination, const char * source );
|
destination is returned
|
destination is returned
|
*/
|
*/
|
@ r0 points to destination
|
@ r0 points to destination
|
@ r1 points to source string which terminates with a 0
|
@ r1 points to source string which terminates with a 0
|
.globl strcpy
|
.globl strcpy
|
strcpy:
|
strcpy:
|
stmdb sp!, {r4-r7, lr}
|
stmdb sp!, {r4-r6, lr}
|
@ Use r6 to process the destination pointer.
|
@ Use r6 to process the destination pointer.
|
@ At the end of the function, r0 is returned, so need to preserve it
|
@ At the end of the function, r0 is returned, so need to preserve it
|
mov r6, r0
|
mov r6, r0
|
@ only if both strings are zero-aligned use the fast 'aligned' algorithm
|
@ only if both strings are zero-aligned use the fast 'aligned' algorithm
|
orr r2, r6, r1
|
orr r2, r6, r1
|
ands r2, r2, #3
|
tst r2, #3
|
bne strcpy_slow
|
bne strcpy_slow
|
|
|
strcpy_fast:
|
strcpy_fast:
|
@ process strings 12 bytes at a time
|
@ process strings 12 bytes at a time
|
ldmia r1!, {r2-r5}
|
ldmia r1!, {r2-r5}
|
|
|
@ check for a zero byte
|
@ check for a zero byte
|
@ only need to examine one of the strings because
|
@ only need to examine one of the strings because
|
@ they are equal up to this point!
|
@ they are equal up to this point!
|
ands r7, r2, #0xff
|
tst r2, #0xff
|
andnes r7, r2, #0xff00
|
tstne r2, #0xff00
|
andnes r7, r2, #0xff0000
|
tstne r2, #0xff0000
|
andnes r7, r2, #0xff000000
|
tstne r2, #0xff000000
|
strne r2, [r6], #4
|
strne r2, [r6], #4
|
subeq r1, r1, #4
|
subeq r1, r1, #4
|
|
|
andnes r7, r3, #0xff
|
tstne r3, #0xff
|
andnes r7, r3, #0xff00
|
tstne r3, #0xff00
|
andnes r7, r3, #0xff0000
|
tstne r3, #0xff0000
|
andnes r7, r3, #0xff000000
|
tstne r3, #0xff000000
|
strne r3, [r6], #4
|
strne r3, [r6], #4
|
subeq r1, r1, #4
|
subeq r1, r1, #4
|
|
|
andnes r7, r4, #0xff
|
tstne r4, #0xff
|
andnes r7, r4, #0xff00
|
tstne r4, #0xff00
|
andnes r7, r4, #0xff0000
|
tstne r4, #0xff0000
|
andnes r7, r4, #0xff000000
|
tstne r4, #0xff000000
|
strne r4, [r6], #4
|
strne r4, [r6], #4
|
subeq r1, r1, #4
|
subeq r1, r1, #4
|
|
|
andnes r7, r5, #0xff
|
tstne r5, #0xff
|
andnes r7, r5, #0xff00
|
tstne r5, #0xff00
|
andnes r7, r5, #0xff0000
|
tstne r5, #0xff0000
|
andnes r7, r5, #0xff000000
|
tstne r5, #0xff000000
|
strne r5, [r6], #4
|
strne r5, [r6], #4
|
subeq r1, r1, #4
|
subeq r1, r1, #4
|
|
|
@ loop back to look at next 12 bytes
|
@ loop back to look at next 12 bytes
|
bne strcpy_fast
|
bne strcpy_fast
|
|
|
@ the source string contains a zero character
|
@ the source string contains a zero character
|
|
|
|
|
|
strcpy_aligned_slow:
|
|
@ unroll the loop 4 times
|
|
ldr r3, [r1], #4
|
|
strb r3, [r6], #1
|
|
ands r4, r3, #0xff
|
|
ldmeqia sp!, {r4-r6, pc}^
|
|
|
|
lsr r3, r3, #8
|
|
strb r3, [r6], #1
|
|
ands r4, r3, #0xff
|
|
ldmeqia sp!, {r4-r6, pc}^
|
|
|
|
lsr r3, r3, #8
|
|
strb r3, [r6], #1
|
|
ands r4, r3, #0xff
|
|
ldmeqia sp!, {r4-r6, pc}^
|
|
|
|
lsr r3, r3, #8
|
|
strb r3, [r6], #1
|
|
ands r4, r3, #0xff
|
|
ldmeqia sp!, {r4-r6, pc}^
|
|
|
|
b strcpy_aligned_slow
|
|
|
|
|
strcpy_slow:
|
strcpy_slow:
|
@ unroll the loop 4 times
|
@ unroll the loop 4 times
|
ldrb r3, [r1], #1
|
ldrb r3, [r1], #1
|
strb r3, [r6], #1
|
strb r3, [r6], #1
|
cmp r3, #0
|
cmp r3, #0
|
ldmeqia sp!, {r4-r7, pc}^
|
ldmeqia sp!, {r4-r6, pc}^
|
|
|
ldrb r3, [r1], #1
|
ldrb r3, [r1], #1
|
strb r3, [r6], #1
|
strb r3, [r6], #1
|
cmp r3, #0
|
cmp r3, #0
|
ldmeqia sp!, {r4-r7, pc}^
|
ldmeqia sp!, {r4-r6, pc}^
|
|
|
ldrb r3, [r1], #1
|
ldrb r3, [r1], #1
|
strb r3, [r6], #1
|
strb r3, [r6], #1
|
cmp r3, #0
|
cmp r3, #0
|
ldmeqia sp!, {r4-r7, pc}^
|
ldmeqia sp!, {r4-r6, pc}^
|
|
|
ldrb r3, [r1], #1
|
ldrb r3, [r1], #1
|
strb r3, [r6], #1
|
strb r3, [r6], #1
|
cmp r3, #0
|
cmp r3, #0
|
ldmeqia sp!, {r4-r7, pc}^
|
ldmeqia sp!, {r4-r6, pc}^
|
|
|
b strcpy_slow
|
b strcpy_slow
|
|
|
|
|
/* int strcmp ( const char * str1, const char * str2 );
|
/* int strcmp ( const char * str1, const char * str2 );
|
A value greater than zero indicates that the first character
|
A value greater than zero indicates that the first character
|
that does not match has a greater value in str1 than in str2;
|
that does not match has a greater value in str1 than in str2;
|
And a value less than zero indicates the opposite.
|
And a value less than zero indicates the opposite.
|
*/
|
*/
|
.globl strcmp
|
.globl strcmp
|
strcmp:
|
strcmp:
|
stmdb sp!, {r4-r8, lr}
|
stmdb sp!, {r4-r8, lr}
|
|
|
@ only if both strings are zero-aligned use the fast 'aligned' algorithm
|
@ only if both strings are zero-aligned use the fast 'aligned' algorithm
|
orr r2, r0, r1
|
orr r2, r0, r1
|
ands r2, r2, #3
|
tst r2, #3
|
bne strcmp_slow
|
bne strcmp_slow
|
|
|
strcmp_fast:
|
strcmp_fast:
|
@ process strings 12 bytes at a time
|
@ process strings 12 bytes at a time
|
ldmia r0!, {r2-r4}
|
ldmia r0!, {r2-r4}
|
ldmia r1!, {r5-r7}
|
ldmia r1!, {r5-r7}
|
cmp r2, r5
|
cmp r2, r5
|
bne 1f
|
bne 1f
|
cmpeq r3, r6
|
cmpeq r3, r6
|
bne 2f
|
bne 2f
|
cmpeq r4, r7
|
cmpeq r4, r7
|
bne 3f
|
bne 3f
|
|
|
@ strings are equal - find a zero byte
|
@ strings are equal - find a zero byte
|
@ only need to examine one of the strings because
|
@ only need to examine one of the strings because
|
@ they are equal up to this point!
|
@ they are equal up to this point!
|
ands r8, r2, #0xff
|
tst r2, #0xff
|
andnes r8, r2, #0xff00
|
tstne r2, #0xff00
|
andnes r8, r2, #0xff0000
|
tstne r2, #0xff0000
|
andnes r8, r2, #0xff000000
|
tstne r2, #0xff000000
|
|
|
andnes r8, r3, #0xff
|
tstne r3, #0xff
|
andnes r8, r3, #0xff00
|
tstne r3, #0xff00
|
andnes r8, r3, #0xff0000
|
tstne r3, #0xff0000
|
andnes r8, r3, #0xff000000
|
tstne r3, #0xff000000
|
|
|
andnes r8, r4, #0xff
|
tstne r4, #0xff
|
andnes r8, r4, #0xff00
|
tstne r4, #0xff00
|
andnes r8, r4, #0xff0000
|
tstne r4, #0xff0000
|
andnes r8, r4, #0xff000000
|
tstne r4, #0xff000000
|
|
|
@ loop back to look at next 12 bytes
|
@ loop back to look at next 12 bytes
|
bne strcmp_fast
|
bne strcmp_fast
|
|
|
@ the first string contains a zero character
|
@ the first string contains a zero character
|
@ the strings are the same, so both strings end
|
@ the strings are the same, so both strings end
|
moveq r0, #0
|
moveq r0, #0
|
ldmeqia sp!, {r4-r8, pc}^
|
ldmeqia sp!, {r4-r8, pc}^
|
|
|
|
|
@ Roll back the string pointers to before the mismatch
|
@ Roll back the string pointers to before the mismatch
|
@ then handle the remaining part byte by byte
|
@ then handle the remaining part byte by byte
|
1: sub r0, r0, #12
|
1: sub r0, r0, #12
|
sub r1, r1, #12
|
sub r1, r1, #12
|
|
|
strcmp_slow:
|
strcmp_slow:
|
ldrb r2, [r0], #1
|
ldrb r2, [r0], #1
|
ldrb r3, [r1], #1
|
ldrb r3, [r1], #1
|
eors r4, r2, r3 @ are the bytes equal ?
|
eors r4, r2, r3 @ are the bytes equal ?
|
bne bytes_different
|
bne bytes_different
|
ldrb r5, [r0], #1
|
ldrb r5, [r0], #1
|
ldrb r6, [r1], #1
|
ldrb r6, [r1], #1
|
cmp r2, #0 @ are they equal and zero ?
|
cmp r2, #0 @ are they equal and zero ?
|
beq bytes_zero
|
beq bytes_zero
|
eors r7, r5, r6 @ are the bytes equal ?
|
eors r7, r5, r6 @ are the bytes equal ?
|
bne bytes_different
|
bne bytes_different
|
ldrb r2, [r0], #1
|
ldrb r2, [r0], #1
|
ldrb r3, [r1], #1
|
ldrb r3, [r1], #1
|
cmp r5, #0 @ are they equal and zero ?
|
cmp r5, #0 @ are they equal and zero ?
|
beq bytes_zero
|
beq bytes_zero
|
eors r4, r2, r3 @ are the bytes equal ?
|
eors r4, r2, r3 @ are the bytes equal ?
|
bne bytes_different
|
bne bytes_different
|
ldrb r5, [r0], #1
|
ldrb r5, [r0], #1
|
ldrb r6, [r1], #1
|
ldrb r6, [r1], #1
|
cmp r2, #0 @ are they equal and zero ?
|
cmp r2, #0 @ are they equal and zero ?
|
beq bytes_zero
|
beq bytes_zero
|
eors r7, r5, r6 @ are the bytes equal ?
|
eors r7, r5, r6 @ are the bytes equal ?
|
bne bytes_different
|
bne bytes_different
|
cmp r5, #0 @ are they equal and zero ?
|
cmp r5, #0 @ are they equal and zero ?
|
beq bytes_zero
|
beq bytes_zero
|
|
|
bne strcmp_slow
|
bne strcmp_slow
|
|
|
|
|
|
|
@ Skipping first 4 bytes so just check they
|
@ Skipping first 4 bytes so just check they
|
@ don't contain an end of string 0 character
|
@ don't contain an end of string 0 character
|
2: ands r8, r2, #0xff
|
2: tst r2, #0xff
|
andnes r8, r2, #0xff00
|
tstne r2, #0xff00
|
andnes r8, r2, #0xff0000
|
tstne r2, #0xff0000
|
andnes r8, r2, #0xff000000
|
tstne r2, #0xff000000
|
beq bytes_zero
|
beq bytes_zero
|
|
|
@ start looking at 5th byte
|
@ start looking at 5th byte
|
sub r0, r0, #8
|
sub r0, r0, #8
|
sub r1, r1, #8
|
sub r1, r1, #8
|
|
|
ldrb r2, [r0], #1
|
ldrb r2, [r0], #1
|
ldrb r3, [r1], #1
|
ldrb r3, [r1], #1
|
eors r4, r2, r3 @ are the bytes equal ?
|
eors r4, r2, r3 @ are the bytes equal ?
|
bne bytes_different
|
bne bytes_different
|
ldrb r5, [r0], #1
|
ldrb r5, [r0], #1
|
ldrb r6, [r1], #1
|
ldrb r6, [r1], #1
|
cmp r2, #0 @ are they equal and zero ?
|
cmp r2, #0 @ are they equal and zero ?
|
beq bytes_zero
|
beq bytes_zero
|
eors r7, r5, r6 @ are the bytes equal ?
|
eors r7, r5, r6 @ are the bytes equal ?
|
bne bytes_different
|
bne bytes_different
|
ldrb r2, [r0], #1
|
ldrb r2, [r0], #1
|
ldrb r3, [r1], #1
|
ldrb r3, [r1], #1
|
cmp r5, #0 @ are they equal and zero ?
|
cmp r5, #0 @ are they equal and zero ?
|
beq bytes_zero
|
beq bytes_zero
|
eors r4, r2, r3 @ are the bytes equal ?
|
eors r4, r2, r3 @ are the bytes equal ?
|
bne bytes_different
|
bne bytes_different
|
ldrb r5, [r0], #1
|
ldrb r5, [r0], #1
|
ldrb r6, [r1], #1
|
ldrb r6, [r1], #1
|
cmp r2, #0 @ are they equal and zero ?
|
cmp r2, #0 @ are they equal and zero ?
|
beq bytes_zero
|
beq bytes_zero
|
eors r7, r5, r6 @ are the bytes equal ?
|
eors r7, r5, r6 @ are the bytes equal ?
|
bne bytes_different
|
bne bytes_different
|
cmp r5, #0 @ are they equal and zero ?
|
cmp r5, #0 @ are they equal and zero ?
|
beq bytes_zero
|
beq bytes_zero
|
|
|
bne strcmp_slow
|
bne strcmp_slow
|
|
|
@ Skipping first 8 bytes so just check they
|
@ Skipping first 8 bytes so just check they
|
@ don't contain an end of string 0 character
|
@ don't contain an end of string 0 character
|
3: ands r8, r2, #0xff
|
3: tst r2, #0xff
|
andnes r8, r2, #0xff00
|
tstne r2, #0xff00
|
andnes r8, r2, #0xff0000
|
tstne r2, #0xff0000
|
andnes r8, r2, #0xff000000
|
tstne r2, #0xff000000
|
|
|
andnes r8, r3, #0xff
|
tstne r3, #0xff
|
andnes r8, r3, #0xff00
|
tstne r3, #0xff00
|
andnes r8, r3, #0xff0000
|
tstne r3, #0xff0000
|
andnes r8, r3, #0xff000000
|
tstne r3, #0xff000000
|
beq bytes_zero
|
beq bytes_zero
|
|
|
sub r0, r0, #4
|
sub r0, r0, #4
|
sub r1, r1, #4
|
sub r1, r1, #4
|
ldrb r2, [r0], #1
|
ldrb r2, [r0], #1
|
ldrb r3, [r1], #1
|
ldrb r3, [r1], #1
|
eors r4, r2, r3 @ are the bytes equal ?
|
eors r4, r2, r3 @ are the bytes equal ?
|
bne bytes_different
|
bne bytes_different
|
ldrb r5, [r0], #1
|
ldrb r5, [r0], #1
|
ldrb r6, [r1], #1
|
ldrb r6, [r1], #1
|
cmp r2, #0 @ are they equal and zero ?
|
cmp r2, #0 @ are they equal and zero ?
|
beq bytes_zero
|
beq bytes_zero
|
eors r7, r5, r6 @ are the bytes equal ?
|
eors r7, r5, r6 @ are the bytes equal ?
|
bne bytes_different
|
bne bytes_different
|
ldrb r2, [r0], #1
|
ldrb r2, [r0], #1
|
ldrb r3, [r1], #1
|
ldrb r3, [r1], #1
|
cmp r5, #0 @ are they equal and zero ?
|
cmp r5, #0 @ are they equal and zero ?
|
beq bytes_zero
|
beq bytes_zero
|
eors r4, r2, r3 @ are the bytes equal ?
|
eors r4, r2, r3 @ are the bytes equal ?
|
bne bytes_different
|
bne bytes_different
|
ldrb r5, [r0], #1
|
ldrb r5, [r0], #1
|
ldrb r6, [r1], #1
|
ldrb r6, [r1], #1
|
cmp r2, #0 @ are they equal and zero ?
|
cmp r2, #0 @ are they equal and zero ?
|
beq bytes_zero
|
beq bytes_zero
|
eors r7, r5, r6 @ are the bytes equal ?
|
eors r7, r5, r6 @ are the bytes equal ?
|
bne bytes_different
|
bne bytes_different
|
cmp r5, #0 @ are they equal and zero ?
|
cmp r5, #0 @ are they equal and zero ?
|
beq bytes_zero
|
beq bytes_zero
|
|
|
bne strcmp_slow
|
bne strcmp_slow
|
|
|
|
|
bytes_zero:
|
bytes_zero:
|
moveq r0, #0 @ if equal and zero, return zero
|
moveq r0, #0 @ if equal and zero, return zero
|
ldmeqia sp!, {r4-r8, pc}^
|
ldmeqia sp!, {r4-r8, pc}^
|
|
|
|
|
bytes_different:
|
bytes_different:
|
sub r0, r5, r6
|
sub r0, r5, r6
|
ldmia sp!, {r4-r8, pc}^
|
ldmia sp!, {r4-r8, pc}^
|
|
|
|
|
|
|
/* void *malloc(size_t size); */
|
/* void *malloc(size_t size); */
|
.globl malloc
|
.globl malloc
|
malloc:
|
malloc:
|
ldr r1, AdrMalloc
|
ldr r1, AdrMalloc
|
ldr r0, [r1]
|
ldr r0, [r1]
|
add r0, r0, #0x10000
|
add r0, r0, #0x10000
|
str r0, [r1]
|
str r0, [r1]
|
mov pc, lr
|
mov pc, lr
|
|
|
|
|
|
|
/* strncpy: String copy function */
|
/* strncpy: String copy function */
|
@ r0 points to destination
|
@ r0 points to destination
|
@ r1 points to source string
|
@ r1 points to source string
|
@ r2 is the number of bytes to copy
|
@ r2 is the number of bytes to copy
|
.globl strncpy
|
.globl strncpy
|
strncpy:
|
strncpy:
|
stmdb sp!, {r4, lr}
|
stmdb sp!, {r4, lr}
|
cmp r2, #0
|
cmp r2, #0
|
beq 2f
|
beq 2f
|
add r4, r0, r2 @ set r4 to the address of the last byte copied
|
add r4, r0, r2 @ set r4 to the address of the last byte copied
|
1: ldrb r3, [r1], #1
|
1: ldrb r3, [r1], #1
|
strb r3, [r0], #1
|
strb r3, [r0], #1
|
cmp r2, r4
|
cmp r2, r4
|
bne 1b
|
bne 1b
|
2: ldmia sp!, {r4, pc}^
|
2: ldmia sp!, {r4, pc}^
|
|
|
|
|
/* strncpy: String compare function */
|
/* strncpy: String compare function */
|
@ return the difference if the strings don't match
|
@ return the difference if the strings don't match
|
.globl strncmp
|
.globl strncmp
|
strncmp:
|
strncmp:
|
stmdb sp!, {r4, r5, r6, lr}
|
stmdb sp!, {r4, r5, r6, lr}
|
|
|
@ check for 0 length
|
@ check for 0 length
|
cmp r2, #0
|
cmp r2, #0
|
moveq r0, #1
|
moveq r0, #1
|
beq 2f
|
beq 2f
|
|
|
mov r3, #0
|
mov r3, #0
|
|
|
1: add r3, r3, #1
|
1: add r3, r3, #1
|
ldrb r4, [r0], #1
|
ldrb r4, [r0], #1
|
ldrb r5, [r1], #1
|
ldrb r5, [r1], #1
|
|
|
subs r6, r4, r5
|
subs r6, r4, r5
|
movne r0, r6
|
movne r0, r6
|
bne 2f
|
bne 2f
|
|
|
cmp r3, r2
|
cmp r3, r2
|
moveq r0, #0
|
moveq r0, #0
|
beq 2f
|
beq 2f
|
|
|
b 1b
|
b 1b
|
2: ldmia sp!, {r4, r5, r6, pc}^
|
2: ldmia sp!, {r4, r5, r6, pc}^
|
|
|
|
|
AdrMalloc: .word 0x7000000
|
AdrMalloc: .word 0x7000000
|
AdrTestStatus: .word ADR_AMBER_TEST_STATUS
|
AdrTestStatus: .word ADR_AMBER_TEST_STATUS
|
AdrUARTDR: .word ADR_AMBER_UART0_DR
|
AdrUARTDR: .word ADR_AMBER_UART0_DR
|
AdrUARTFR: .word ADR_AMBER_UART0_FR
|
AdrUARTFR: .word ADR_AMBER_UART0_FR
|
/* ========================================================================= */
|
/* ========================================================================= */
|
/* ========================================================================= */
|
/* ========================================================================= */
|
|
|
|
|
|
|