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 minilibc 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 


@ divide r1 by r2, also use registers r0 and r4

116 


mov r2, r1

117 


mov r1, r0

118 



119 


cmp r2, #0

120 


beq 3f

121 



122 


@ In order to divide r1 by r2, the first thing we need to do is to shift r2

123 


@ left by the necessary number of places. The easiest method of doing this

124 


@ is simply by trial and error  shift until we discover that r2 has become

125 


@ too big, then stop.

126 


mov r0,#0 @ clear r0 to accumulate result

127 


mov r3,#1 @ set bit 0 in r3, which will be

128 


@ shifted left then right

129 



130 


1: cmp r3, #0 @ escape on error

131 


moveq r3, #0x10000000

132 


beq 2f

133 


cmp r2,r1

134 


movls r2,r2,lsl#1

135 


movls r3,r3,lsl#1

136 


bls 1b

137 


@ shift r2 left until it is about to be bigger than r1

138 


@ shift r3 left in parallel in order to flag how far we have to go

139 



140 


@ r0 will be used to hold the result. The role of r3 is more complicated.

141 


@ In effect, we are using r3 to mark where the righthand end of r2 has got to

142 


@  if we shift r2 three places left, this will be indicated by a value of %1000

143 


@ in r3. However, we also add it to r0 every time we manage a successful subtraction,

144 


@ since it marks the position of the digit currently being calculated in the answer.

145 


@ In the binary example (50 ÷ 10) above, we shifted the '10' two places left,

146 


@ so at the time of the first subtraction, r3 would have been %100, at the time

147 


@ of the second (which failed) it would have been %10, and at the time of the

148 


@ third %1. Adding it to r0 after each successful subtraction would have

149 


@ given us, once again, the answer of %101!

150 



151 


@ Now for the loop that actually does the work:

152 


2: cmp r1,r2 @ carry set if r1>r2 (don't ask why)

153 


subcs r1,r1,r2 @ subtract r2 from r1 if this would

154 


@ give a positive answer

155 


addcs r0,r0,r3 @ and add the current bit in r3 to

156 


@ the accumulating answer in r0

157 



158 


@ In subtraction (a cmp instruction simulates a subtraction in

159 


@ order to set the flags), if r1  r2 gives a positive answer and no 'borrow'

160 


@ is required, the carry flag is set. This is required in order to make SBC

161 


@ (Subtract with Carry) work properly when used to carry out a 64bit subtraction,

162 


@ but it is confusing!

163 



164 


@ In this case, we are turning it to our advantage. The carry flag is set to

165 


@ indicate that a successful subtraction is possible, i.e. one that doesn't

166 


@ generate a negative result, and the two following instructions are carried

167 


@ out only when the condition Carry Set applies. Note that the 'S' on the end

168 


@ of these instructions is part of the 'CS' condition code and does not mean

169 


@ that they set the flags!

170 



171 


movs r3,r3,lsr #1 @ Shift r3 right into carry flag

172 


movcc r2,r2,lsr #1 @ and if bit 0 of r3 was zero, also

173 


@ shift r2 right

174 


bcc 2b @ If carry not clear, r3 has shifted

175 


@ back to where it started, and we

176 


@ can end

177 


3: ldmia sp!, {r4, pc}^

178 



179 



180 
31 
csantifort 
/* strcpy: String copy function

181 


char * strcpy ( char * destination, const char * source );

182 


destination is returned

183 


*/

184 
2 
csantifort 
@ r0 points to destination

185 


@ r1 points to source string which terminates with a 0

186 


.globl strcpy

187 
31 
csantifort 
strcpy:

188 


stmdb sp!, {r4r7, lr}

189 


mov r6, r0

190 


@ get relative alignment of strings

191 


and r2, r6, #3

192 


and r3, r1, #3

193 


@ only if both strings are zeroaligned use the fast 'aligned' algorithm

194 


orrs r2, r3

195 


bne strcpy_slow

196 



197 


strcpy_fast:

198 


@ process strings 12 bytes at a time

199 


ldmia r1!, {r2r5}

200 



201 


@ check for a zero byte

202 


@ only need to examine one of the strings because

203 


@ they are equal up to this point!

204 


ands r7, r2, #0xff

205 


andnes r7, r2, #0xff00

206 


andnes r7, r2, #0xff0000

207 


andnes r7, r2, #0xff000000

208 


strne r2, [r6], #4

209 


subeq r1, r1, #4

210 



211 


andnes r7, r3, #0xff

212 


andnes r7, r3, #0xff00

213 


andnes r7, r3, #0xff0000

214 


andnes r7, r3, #0xff000000

215 


strne r3, [r6], #4

216 


subeq r1, r1, #4

217 



218 


andnes r7, r4, #0xff

219 


andnes r7, r4, #0xff00

220 


andnes r7, r4, #0xff0000

221 


andnes r7, r4, #0xff000000

222 


strne r4, [r6], #4

223 


subeq r1, r1, #4

224 



225 


andnes r7, r5, #0xff

226 


andnes r7, r5, #0xff00

227 


andnes r7, r5, #0xff0000

228 


andnes r7, r5, #0xff000000

229 


strne r5, [r6], #4

230 


subeq r1, r1, #4

231 



232 


@ loop back to look at next 12 bytes

233 


bne strcpy_fast

234 



235 


@ the source string contains a zero character

236 



237 


strcpy_slow:

238 


@ unroll the loop 4 times

239 
2 
csantifort 
ldrb r3, [r1], #1

240 
31 
csantifort 
strb r3, [r6], #1

241 
2 
csantifort 
cmp r3, #0

242 
31 
csantifort 
ldmeqia sp!, {r4r7, pc}^

243 



244 


ldrb r3, [r1], #1

245 


strb r3, [r6], #1

246 


cmp r3, #0

247 


ldmeqia sp!, {r4r7, pc}^

248 



249 


ldrb r3, [r1], #1

250 


strb r3, [r6], #1

251 


cmp r3, #0

252 


ldmeqia sp!, {r4r7, pc}^

253 



254 


ldrb r3, [r1], #1

255 


strb r3, [r6], #1

256 


cmp r3, #0

257 


ldmeqia sp!, {r4r7, pc}^

258 



259 


b strcpy_slow

260 
2 
csantifort 

261 



262 
31 
csantifort 
/* int strcmp ( const char * str1, const char * str2 );

263 


A value greater than zero indicates that the first character

264 


that does not match has a greater value in str1 than in str2;

265 


And a value less than zero indicates the opposite.

266 


*/

267 


.globl strcmp

268 


strcmp:

269 


stmdb sp!, {r4r8, lr}

270 



271 


@ only if both strings are zeroaligned use the fast 'aligned' algorithm

272 


orr r2, r0, r1

273 


ands r2, r2, #3

274 


bne strcmp_slow

275 



276 


strcmp_fast:

277 


@ process strings 12 bytes at a time

278 


ldmia r0!, {r2r4}

279 


ldmia r1!, {r5r7}

280 


cmp r2, r5

281 


bne 1f

282 


cmpeq r3, r6

283 


bne 2f

284 


cmpeq r4, r7

285 


bne 3f

286 



287 


@ strings are equal  find a zero byte

288 


@ only need to examine one of the strings because

289 


@ they are equal up to this point!

290 


ands r8, r2, #0xff

291 


andnes r8, r2, #0xff00

292 


andnes r8, r2, #0xff0000

293 


andnes r8, r2, #0xff000000

294 



295 


andnes r8, r3, #0xff

296 


andnes r8, r3, #0xff00

297 


andnes r8, r3, #0xff0000

298 


andnes r8, r3, #0xff000000

299 



300 


andnes r8, r4, #0xff

301 


andnes r8, r4, #0xff00

302 


andnes r8, r4, #0xff0000

303 


andnes r8, r4, #0xff000000

304 



305 


@ loop back to look at next 12 bytes

306 


bne strcmp_fast

307 



308 


@ the first string contains a zero character

309 


@ the strings are the same, so both strings end

310 


moveq r0, #0

311 


ldmeqia sp!, {r4r8, pc}^

312 



313 



314 


@ Roll back the string pointers to before the mismatch

315 


@ then handle the remaining part byte by byte

316 


1: sub r0, r0, #12

317 


sub r1, r1, #12

318 



319 


strcmp_slow:

320 


ldrb r2, [r0], #1

321 


ldrb r3, [r1], #1

322 


eors r4, r2, r3 @ are the bytes equal ?

323 


bne bytes_different

324 


ldrb r5, [r0], #1

325 


ldrb r6, [r1], #1

326 


cmp r2, #0 @ are they equal and zero ?

327 


beq bytes_zero

328 


eors r7, r5, r6 @ are the bytes equal ?

329 


bne bytes_different

330 


ldrb r2, [r0], #1

331 


ldrb r3, [r1], #1

332 


cmp r5, #0 @ are they equal and zero ?

333 


beq bytes_zero

334 


eors r4, r2, r3 @ are the bytes equal ?

335 


bne bytes_different

336 


ldrb r5, [r0], #1

337 


ldrb r6, [r1], #1

338 


cmp r2, #0 @ are they equal and zero ?

339 


beq bytes_zero

340 


eors r7, r5, r6 @ are the bytes equal ?

341 


bne bytes_different

342 


cmp r5, #0 @ are they equal and zero ?

343 


beq bytes_zero

344 



345 


bne strcmp_slow

346 



347 



348 



349 


@ Skipping first 4 bytes so just check they

350 


@ don't contain an end of string 0 character

351 


2: ands r8, r2, #0xff

352 


andnes r8, r2, #0xff00

353 


andnes r8, r2, #0xff0000

354 


andnes r8, r2, #0xff000000

355 


beq bytes_zero

356 



357 


@ start looking at 5th byte

358 


sub r0, r0, #8

359 


sub r1, r1, #8

360 



361 


ldrb r2, [r0], #1

362 


ldrb r3, [r1], #1

363 


eors r4, r2, r3 @ are the bytes equal ?

364 


bne bytes_different

365 


ldrb r5, [r0], #1

366 


ldrb r6, [r1], #1

367 


cmp r2, #0 @ are they equal and zero ?

368 


beq bytes_zero

369 


eors r7, r5, r6 @ are the bytes equal ?

370 


bne bytes_different

371 


ldrb r2, [r0], #1

372 


ldrb r3, [r1], #1

373 


cmp r5, #0 @ are they equal and zero ?

374 


beq bytes_zero

375 


eors r4, r2, r3 @ are the bytes equal ?

376 


bne bytes_different

377 


ldrb r5, [r0], #1

378 


ldrb r6, [r1], #1

379 


cmp r2, #0 @ are they equal and zero ?

380 


beq bytes_zero

381 


eors r7, r5, r6 @ are the bytes equal ?

382 


bne bytes_different

383 


cmp r5, #0 @ are they equal and zero ?

384 


beq bytes_zero

385 



386 


bne strcmp_slow

387 



388 


@ Skipping first 8 bytes so just check they

389 


@ don't contain an end of string 0 character

390 


3: ands r8, r2, #0xff

391 


andnes r8, r2, #0xff00

392 


andnes r8, r2, #0xff0000

393 


andnes r8, r2, #0xff000000

394 



395 


andnes r8, r3, #0xff

396 


andnes r8, r3, #0xff00

397 


andnes r8, r3, #0xff0000

398 


andnes r8, r3, #0xff000000

399 


beq bytes_zero

400 



401 


sub r0, r0, #4

402 


sub r1, r1, #4

403 


ldrb r2, [r0], #1

404 


ldrb r3, [r1], #1

405 


eors r4, r2, r3 @ are the bytes equal ?

406 


bne bytes_different

407 


ldrb r5, [r0], #1

408 


ldrb r6, [r1], #1

409 


cmp r2, #0 @ are they equal and zero ?

410 


beq bytes_zero

411 


eors r7, r5, r6 @ are the bytes equal ?

412 


bne bytes_different

413 


ldrb r2, [r0], #1

414 


ldrb r3, [r1], #1

415 


cmp r5, #0 @ are they equal and zero ?

416 


beq bytes_zero

417 


eors r4, r2, r3 @ are the bytes equal ?

418 


bne bytes_different

419 


ldrb r5, [r0], #1

420 


ldrb r6, [r1], #1

421 


cmp r2, #0 @ are they equal and zero ?

422 


beq bytes_zero

423 


eors r7, r5, r6 @ are the bytes equal ?

424 


bne bytes_different

425 


cmp r5, #0 @ are they equal and zero ?

426 


beq bytes_zero

427 



428 


bne strcmp_slow

429 



430 



431 


bytes_zero:

432 


moveq r0, #0 @ if equal and zero, return zero

433 


ldmeqia sp!, {r4r8, pc}^

434 



435 



436 


bytes_different:

437 


sub r0, r5, r6

438 


ldmia sp!, {r4r8, pc}^

439 



440 



441 



442 


/* void *malloc(size_t size); */

443 


.globl malloc

444 


malloc:

445 


ldr r1, AdrMalloc

446 


ldr r0, [r1]

447 


add r0, r0, #0x10000

448 


str r0, [r1]

449 


mov pc, lr

450 



451 



452 


.globl times

453 


times:

454 


@ TODO

455 


mov r0, #0

456 


mov pc, lr

457 



458 



459 
2 
csantifort 
/* strncpy: String copy function */

460 


@ r0 points to destination

461 


@ r1 points to source string

462 


@ r2 is the number of bytes to copy

463 


.globl strncpy

464 


strncpy:

465 


stmdb sp!, {r4, lr}

466 


cmp r2, #0

467 


beq 2f

468 


mov r4, #0

469 


1: ldrb r3, [r1], #1

470 


strb r3, [r0], #1

471 


add r4, r4, #1

472 


cmp r2, r4

473 


beq 2f

474 


b 1b

475 


2: ldmia sp!, {r4, pc}^

476 



477 



478 


/* strncpy: String compare function */

479 


@ return the difference if the strings don't match

480 


.globl strncmp

481 


strncmp:

482 


stmdb sp!, {r4, r5, r6, lr}

483 



484 


@ check for 0 length

485 


cmp r2, #0

486 


moveq r0, #1

487 


beq 2f

488 



489 


mov r3, #0

490 



491 


1: add r3, r3, #1

492 


ldrb r4, [r0], #1

493 


ldrb r5, [r1], #1

494 



495 


subs r6, r4, r5

496 


movne r0, r6

497 


bne 2f

498 



499 


cmp r3, r2

500 


moveq r0, #0

501 


beq 2f

502 



503 


b 1b

504 


2: ldmia sp!, {r4, r5, r6, pc}^

505 



506 



507 
31 
csantifort 
AdrMalloc: .word 0x7000000

508 
2 
csantifort 
AdrTestStatus: .word ADR_AMBER_TEST_STATUS

509 


AdrUARTDR: .word ADR_AMBER_UART0_DR

510 


AdrUARTFR: .word ADR_AMBER_UART0_FR

511 


/* ========================================================================= */

512 


/* ========================================================================= */

513 



514 


