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 |
|
|
_div:
|
111 |
|
|
stmdb sp!, {r4, lr}
|
112 |
|
|
|
113 |
|
|
@ divide r1 by r2, also use registers r0 and r4
|
114 |
|
|
mov r2, r1
|
115 |
|
|
mov r1, r0
|
116 |
|
|
|
117 |
|
|
cmp r2, #0
|
118 |
|
|
beq 3f
|
119 |
|
|
|
120 |
|
|
@ In order to divide r1 by r2, the first thing we need to do is to shift r2
|
121 |
|
|
@ left by the necessary number of places. The easiest method of doing this
|
122 |
|
|
@ is simply by trial and error - shift until we discover that r2 has become
|
123 |
|
|
@ too big, then stop.
|
124 |
|
|
mov r0,#0 @ clear r0 to accumulate result
|
125 |
|
|
mov r3,#1 @ set bit 0 in r3, which will be
|
126 |
|
|
@ shifted left then right
|
127 |
|
|
|
128 |
|
|
1: cmp r3, #0 @ escape on error
|
129 |
|
|
moveq r3, #0x10000000
|
130 |
|
|
beq 2f
|
131 |
|
|
cmp r2,r1
|
132 |
|
|
movls r2,r2,lsl#1
|
133 |
|
|
movls r3,r3,lsl#1
|
134 |
|
|
bls 1b
|
135 |
|
|
@ shift r2 left until it is about to be bigger than r1
|
136 |
|
|
@ shift r3 left in parallel in order to flag how far we have to go
|
137 |
|
|
|
138 |
|
|
@ r0 will be used to hold the result. The role of r3 is more complicated.
|
139 |
|
|
@ In effect, we are using r3 to mark where the right-hand end of r2 has got to
|
140 |
|
|
@ - if we shift r2 three places left, this will be indicated by a value of %1000
|
141 |
|
|
@ in r3. However, we also add it to r0 every time we manage a successful subtraction,
|
142 |
|
|
@ since it marks the position of the digit currently being calculated in the answer.
|
143 |
|
|
@ In the binary example (50 ÷ 10) above, we shifted the '10' two places left,
|
144 |
|
|
@ so at the time of the first subtraction, r3 would have been %100, at the time
|
145 |
|
|
@ of the second (which failed) it would have been %10, and at the time of the
|
146 |
|
|
@ third %1. Adding it to r0 after each successful subtraction would have
|
147 |
|
|
@ given us, once again, the answer of %101!
|
148 |
|
|
|
149 |
|
|
@ Now for the loop that actually does the work:
|
150 |
|
|
2: cmp r1,r2 @ carry set if r1>r2 (don't ask why)
|
151 |
|
|
subcs r1,r1,r2 @ subtract r2 from r1 if this would
|
152 |
|
|
@ give a positive answer
|
153 |
|
|
addcs r0,r0,r3 @ and add the current bit in r3 to
|
154 |
|
|
@ the accumulating answer in r0
|
155 |
|
|
|
156 |
|
|
@ In subtraction (a cmp instruction simulates a subtraction in
|
157 |
|
|
@ order to set the flags), if r1 - r2 gives a positive answer and no 'borrow'
|
158 |
|
|
@ is required, the carry flag is set. This is required in order to make SBC
|
159 |
|
|
@ (Subtract with Carry) work properly when used to carry out a 64-bit subtraction,
|
160 |
|
|
@ but it is confusing!
|
161 |
|
|
|
162 |
|
|
@ In this case, we are turning it to our advantage. The carry flag is set to
|
163 |
|
|
@ indicate that a successful subtraction is possible, i.e. one that doesn't
|
164 |
|
|
@ generate a negative result, and the two following instructions are carried
|
165 |
|
|
@ out only when the condition Carry Set applies. Note that the 'S' on the end
|
166 |
|
|
@ of these instructions is part of the 'CS' condition code and does not mean
|
167 |
|
|
@ that they set the flags!
|
168 |
|
|
|
169 |
|
|
movs r3,r3,lsr #1 @ Shift r3 right into carry flag
|
170 |
|
|
movcc r2,r2,lsr #1 @ and if bit 0 of r3 was zero, also
|
171 |
|
|
@ shift r2 right
|
172 |
|
|
bcc 2b @ If carry not clear, r3 has shifted
|
173 |
|
|
@ back to where it started, and we
|
174 |
|
|
@ can end
|
175 |
|
|
3: ldmia sp!, {r4, pc}^
|
176 |
|
|
|
177 |
|
|
|
178 |
|
|
/* strcpy: String copy function */
|
179 |
|
|
@ r0 points to destination
|
180 |
|
|
@ r1 points to source string which terminates with a 0
|
181 |
|
|
.globl strcpy
|
182 |
|
|
strcpy:
|
183 |
|
|
ldrb r3, [r1], #1
|
184 |
|
|
cmp r3, #0
|
185 |
|
|
beq 1f
|
186 |
|
|
strb r3, [r0], #1
|
187 |
|
|
b strcpy
|
188 |
|
|
1: moveqs pc, lr
|
189 |
|
|
|
190 |
|
|
|
191 |
|
|
/* strncpy: String copy function */
|
192 |
|
|
@ r0 points to destination
|
193 |
|
|
@ r1 points to source string
|
194 |
|
|
@ r2 is the number of bytes to copy
|
195 |
|
|
.globl strncpy
|
196 |
|
|
strncpy:
|
197 |
|
|
stmdb sp!, {r4, lr}
|
198 |
|
|
cmp r2, #0
|
199 |
|
|
beq 2f
|
200 |
|
|
mov r4, #0
|
201 |
|
|
1: ldrb r3, [r1], #1
|
202 |
|
|
strb r3, [r0], #1
|
203 |
|
|
add r4, r4, #1
|
204 |
|
|
cmp r2, r4
|
205 |
|
|
beq 2f
|
206 |
|
|
b 1b
|
207 |
|
|
2: ldmia sp!, {r4, pc}^
|
208 |
|
|
|
209 |
|
|
|
210 |
|
|
/* strncpy: String compare function */
|
211 |
|
|
@ return the difference if the strings don't match
|
212 |
|
|
.globl strncmp
|
213 |
|
|
strncmp:
|
214 |
|
|
stmdb sp!, {r4, r5, r6, lr}
|
215 |
|
|
|
216 |
|
|
@ check for 0 length
|
217 |
|
|
cmp r2, #0
|
218 |
|
|
moveq r0, #1
|
219 |
|
|
beq 2f
|
220 |
|
|
|
221 |
|
|
mov r3, #0
|
222 |
|
|
|
223 |
|
|
1: add r3, r3, #1
|
224 |
|
|
ldrb r4, [r0], #1
|
225 |
|
|
ldrb r5, [r1], #1
|
226 |
|
|
|
227 |
|
|
subs r6, r4, r5
|
228 |
|
|
movne r0, r6
|
229 |
|
|
bne 2f
|
230 |
|
|
|
231 |
|
|
cmp r3, r2
|
232 |
|
|
moveq r0, #0
|
233 |
|
|
beq 2f
|
234 |
|
|
|
235 |
|
|
b 1b
|
236 |
|
|
2: ldmia sp!, {r4, r5, r6, pc}^
|
237 |
|
|
|
238 |
|
|
|
239 |
|
|
AdrTestStatus: .word ADR_AMBER_TEST_STATUS
|
240 |
|
|
AdrUARTDR: .word ADR_AMBER_UART0_DR
|
241 |
|
|
AdrUARTFR: .word ADR_AMBER_UART0_FR
|
242 |
|
|
/* ========================================================================= */
|
243 |
|
|
/* ========================================================================= */
|
244 |
|
|
|
245 |
|
|
|