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

Subversion Repositories amber

[/] [amber/] [trunk/] [sw/] [boot-loader-ethmac/] [start.S] - Blame information for rev 81

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 61 csantifort
/*----------------------------------------------------------------
2
//                                                              //
3
//  start.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 boot-loader.                          //
10
//  As boot-loader is a stand-alone application, it needs a     //
11
//  simple start function written in assembly to call the       //
12
//  C code main() function.                                     //
13
//                                                              //
14
//  Author(s):                                                  //
15
//      - Conor Santifort, csantifort.amber@gmail.com           //
16
//                                                              //
17
//////////////////////////////////////////////////////////////////
18
//                                                              //
19
// Copyright (C) 2010 Authors and OPENCORES.ORG                 //
20
//                                                              //
21
// This source file may be used and distributed without         //
22
// restriction provided that this copyright statement is not    //
23
// removed from the file and that any derivative work contains  //
24
// the original copyright notice and the associated disclaimer. //
25
//                                                              //
26
// This source file is free software; you can redistribute it   //
27
// and/or modify it under the terms of the GNU Lesser General   //
28
// Public License as published by the Free Software Foundation; //
29
// either version 2.1 of the License, or (at your option) any   //
30
// later version.                                               //
31
//                                                              //
32
// This source is distributed in the hope that it will be       //
33
// useful, but WITHOUT ANY WARRANTY; without even the implied   //
34
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
35
// PURPOSE.  See the GNU Lesser General Public License for more //
36
// details.                                                     //
37
//                                                              //
38
// You should have received a copy of the GNU Lesser General    //
39
// Public License along with this source; if not, download it   //
40
// from http://www.opencores.org/lgpl.shtml                     //
41
//                                                              //
42
----------------------------------------------------------------*/
43
 
44
#include "amber_registers.h"
45
#include "address_map.h"
46
 
47
/* Defined in vmlinux/include/asm-arm/setup.h */
48
#define ATAG_CORE       0x54410001
49
#define ATAG_MEM        0x54410002
50
#define ATAG_INITRD     0x54410005
51
#define ATAG_RAMDISK    0x54410004
52
#define ATAG_NONE       0x00000000
53
 
54
#define ATAG_CORE_SIZE    ((2*4 + 3*4) >> 2)
55
#define ATAG_MEM_SIZE     ((2*4 + 2*4) >> 2)
56
#define ATAG_INITRD_SIZE  ((2*4 + 2*4) >> 2)
57
#define ATAG_RAMDISK_SIZE ((2*4 + 3*4) >> 2)
58
 
59
 
60
/* from vmlinux/arch/arm/kernel/compat.c */
61
#define FLAG_READONLY   1
62
 
63
/* from the list in wmlinux/arch/arm/tools/mach-types */
64
#define MACH_TYPE_A5K   11
65
 
66
 
67
 
68
        .section .text
69 78 csantifort
        .globl  start
70
start:
71 61 csantifort
        /* 0x00 Reset Interrupt vector address */
72
        b       startup
73
 
74
        /* 0x04 Undefined Instruction Interrupt vector address */
75
        b       _testfail
76 78 csantifort
 
77 61 csantifort
        /* 0x08 SWI Interrupt vector address */
78
        b       _testfail
79 78 csantifort
 
80 61 csantifort
        /* 0x0c Prefetch abort Interrupt vector address */
81
        b       _testfail
82 78 csantifort
 
83 61 csantifort
        /* 0x10 Data abort Interrupt vector address */
84
        b       _testfail
85
        b       _testfail
86 78 csantifort
 
87 61 csantifort
        /* 0x18 IRQ vector address */
88
        b       service_irq
89 78 csantifort
 
90 61 csantifort
        /* 0x1c FIRQ vector address */
91
        b       _testfail
92
 
93 78 csantifort
 
94 61 csantifort
        .global _restart
95
_restart:
96
        @ jump to address 0 in irq mode
97
        mov     pc, #0x00000002
98
        nop
99
        nop
100
        nop
101
 
102
 
103
startup:
104
        /* copy program to exec space */
105
        mov     r0, #0
106
        ldr     r1, AdrExecBase
107
1:      ldm     r0!, {r2-r9}
108 78 csantifort
        stm     r1!, {r2-r9}
109 61 csantifort
        cmp     r0, #0x4000
110
        bne     1b
111
 
112
        /* Fix the interrupt jump pointers */
113 78 csantifort
        ldr     r0, AdrExecBase
114 61 csantifort
        mov     r1, r0, lsr #2
115
        mov     r2, #0
116 78 csantifort
 
117 61 csantifort
2:      ldr     r3, [r2]
118
        orr     r3, r3, r1
119
        str     r3, [r2], #4
120
        cmp     r2, #0x1c
121
        bne     2b
122 78 csantifort
 
123 61 csantifort
        /* Jump to 2f but offset from ExecBase not current location */
124 78 csantifort
3:      ldr     r0, AdrExecBase
125 61 csantifort
        ldr     r1, AdrJumpPoint
126
        orr     r0, r0, r1
127
        mov     pc, r0
128
 
129
_jump_point:
130
 
131
        /* Switch to IRQ Mode */
132
        mov     r0, #0x00000002
133 78 csantifort
        teqp    pc, r0
134 61 csantifort
        /* Set IRQ Mode stack pointer */
135
        ldr     sp, AdrIRQStack
136
 
137
        /* Switch to SVC mode and Unset interrupt mask bits */
138
        mov     r0, #0x00000003
139 78 csantifort
        teqp    pc, r0
140
 
141 61 csantifort
        @ Enable the cache
142
        @ set region 24 to be uncached. Used for packet buffers
143
        mov     r0, #0xfeffffff
144 78 csantifort
        mcr     15, 0, r0, cr3, cr0, 0   @ cacheable area
145 61 csantifort
        mov     r0, #1
146 78 csantifort
        mcr     15, 0, r0, cr2, cr0, 0   @ cache enable
147
 
148 61 csantifort
        @ init SP
149
        ldr     sp, AdrStack
150
 
151
        @ Set 32MB memory mode
152
        ldr     r0, AdrMemCtrl
153
        mov     r1, #1
154
        str     r1, [r0]
155 78 csantifort
 
156 61 csantifort
        .extern main
157
        bl      main
158 78 csantifort
 
159 61 csantifort
        @ jump to program at r0
160 78 csantifort
        .globl _jump_to_program
161 61 csantifort
_jump_to_program:
162
 
163 78 csantifort
 
164 61 csantifort
        @ ----------------------------------------------
165
        @ Copy ATAG structure to AdrBootParams
166
        @ ----------------------------------------------
167
        ldr     r1, AdrBootParams
168
        ldr     r2, AdrATAGBase
169
        ldr     r3, AdeEndATAG
170 78 csantifort
 
171 61 csantifort
1:      cmp     r2, r3
172
        beq     2f
173
        ldr     r4, [r2], #4
174
        str     r4, [r1], #4
175
        b       1b
176 78 csantifort
 
177 61 csantifort
        @ Set memc page tables
178 78 csantifort
2:      ldr     r2, AdrPageTabes
179 61 csantifort
        mov     r3, #0
180
        mov     r4, #40
181
3:      str     r3,[r2],#4
182
        subs    r4, r4, #1
183
        bne     3b
184 78 csantifort
 
185 61 csantifort
        @ ----------------------------------------------
186
        @ jump to start of program in svc mode with interrupts disabled
187
        @ ----------------------------------------------
188
        mov     r4, r0
189
        orr     r4, #0x0c000003
190 78 csantifort
        mov     r0, #0
191 61 csantifort
        mov     pc, r4
192
 
193 78 csantifort
 
194 61 csantifort
service_irq:
195 81 csantifort
        @ As this is an interrupt, need to save all registers to the stack
196
        @ that will be used here
197 78 csantifort
        stmfd   sp!, {r0-r3, lr}
198 61 csantifort
 
199
        @ is it a timer interrupt ?
200
        ldr     r0, AdrInterruptStatus
201 78 csantifort
        ldr     r3, [r0]
202
        ands    r2, r3, #0x20
203 61 csantifort
        beq     1f  @ not timer int, jump
204 78 csantifort
        @ Remember that registers r0 to r2 can be changed by this function
205 61 csantifort
        .extern timer_interrupt
206 78 csantifort
        bl timer_interrupt
207
 
208 61 csantifort
        @ is it an ethernet interrupt ?
209 78 csantifort
1:      ands    r2, r3, #0x100
210
        beq     2f  @ not ethmac int, jump
211 61 csantifort
        .extern ethmac_interrupt
212 78 csantifort
        @ Remember that registers r0 to r2 can be changed by this function
213 61 csantifort
        bl ethmac_interrupt
214
 
215 78 csantifort
 
216 61 csantifort
2:      @ Restore all registers from the stack
217 78 csantifort
        ldmfd   sp!, {r0-r3, lr}
218
 
219 61 csantifort
        @ Jump straight back to normal execution
220
        subs    pc, lr, #4
221
 
222
 
223
 
224
/* _testfail: Used to terminate execution in Verilog simulations */
225
/* On the board just puts the processor into an infinite loop    */
226 78 csantifort
        .globl _testfail
227 61 csantifort
_testfail:
228
        ldr     r11, AdrTestStatus
229
        str     r0, [r11]
230
        b       _testfail
231
 
232 78 csantifort
 
233 61 csantifort
/* _testpass: Used to terminate execution in Verilog simulations */
234
/* On the board just puts the processor into an infinite loop    */
235 78 csantifort
        .globl _testpass
236
_testpass:
237 61 csantifort
        ldr     r11, AdrTestStatus
238
        mov     r10, #17
239
        str     r10, [r11]
240
        b       _testpass
241
 
242
 
243
 
244 78 csantifort
 
245 61 csantifort
/* _div: Integer division function */
246
        @ Divide r0 by r1
247
        @ Answer returned in r1
248
        .globl _div
249
        .globl __aeabi_idiv
250
__aeabi_idiv:
251
_div:
252
        stmdb   sp!, {r4, lr}
253
 
254
        @ set r4 to 1 if one of the two inputs is negative
255
        and     r2, r0, #0x80000000
256
        and     r3, r1, #0x80000000
257
        eor     r4, r2, r3
258
 
259
        @ Invert negative numbers
260
        tst     r0, #0x80000000
261
        mvnne   r0, r0
262 78 csantifort
        addne   r0, r0, #1
263 61 csantifort
 
264
        tst     r1, #0x80000000
265
        mvnne   r1, r1
266 78 csantifort
        addne   r1, r1, #1
267 61 csantifort
 
268
        @ divide r1 by r2, also use registers r0 and r4
269
        mov     r2, r1
270
        mov     r1, r0
271 78 csantifort
 
272 61 csantifort
        cmp      r2, #0
273
        beq      3f
274
 
275 78 csantifort
        @ In order to divide r1 by r2, the first thing we need to do is to shift r2
276
        @ left by the necessary number of places. The easiest method of doing this
277
        @ is simply by trial and error - shift until we discover that r2 has become
278 61 csantifort
        @ too big, then stop.
279
        mov      r0,#0     @ clear r0 to accumulate result
280
        mov      r3,#1     @ set bit 0 in r3, which will be
281
                           @ shifted left then right
282
 
283
1:      cmp      r3, #0    @ escape on error
284
        moveq    r3, #0x10000000
285
        beq      2f
286
        cmp      r2,r1
287
        movls    r2,r2,lsl#1
288
        movls    r3,r3,lsl#1
289
        bls      1b
290
        @ shift r2 left until it is about to be bigger than r1
291
        @ shift r3 left in parallel in order to flag how far we have to go
292
 
293
        @ r0 will be used to hold the result. The role of r3 is more complicated.
294 78 csantifort
        @ In effect, we are using r3 to mark where the right-hand end of r2 has got to
295
        @ - if we shift r2 three places left, this will be indicated by a value of %1000
296
        @ in r3. However, we also add it to r0 every time we manage a successful subtraction,
297
        @ since it marks the position of the digit currently being calculated in the answer.
298
        @ In the binary example (50  10) above, we shifted the '10' two places left,
299
        @ so at the time of the first subtraction, r3 would have been %100, at the time
300
        @ of the second (which failed) it would have been %10, and at the time of the
301
        @ third %1. Adding it to r0 after each successful subtraction would have
302 61 csantifort
        @ given us, once again, the answer of %101!
303
 
304
        @ Now for the loop that actually does the work:
305
2:      cmp       r1,r2      @ carry set if r1>r2 (don't ask why)
306
        subcs     r1,r1,r2   @ subtract r2 from r1 if this would
307
                             @ give a positive answer
308
        addcs     r0,r0,r3   @ and add the current bit in r3 to
309
                             @ the accumulating answer in r0
310
 
311 78 csantifort
        @ In subtraction (a cmp instruction simulates a subtraction in
312
        @ order to set the flags), if r1 - r2 gives a positive answer and no 'borrow'
313
        @ is required, the carry flag is set. This is required in order to make SBC
314
        @ (Subtract with Carry) work properly when used to carry out a 64-bit subtraction,
315 61 csantifort
        @ but it is confusing!
316 78 csantifort
 
317
        @ In this case, we are turning it to our advantage. The carry flag is set to
318
        @ indicate that a successful subtraction is possible, i.e. one that doesn't
319
        @ generate a negative result, and the two following instructions are carried
320
        @ out only when the condition Carry Set applies. Note that the 'S' on the end
321
        @ of these instructions is part of the 'CS' condition code and does not mean
322 61 csantifort
        @ that they set the flags!
323 78 csantifort
 
324 61 csantifort
        movs      r3,r3,lsr #1    @ Shift r3 right into carry flag
325
        movcc     r2,r2,lsr #1    @ and if bit 0 of r3 was zero, also
326
                                  @ shift r2 right
327
        bcc       2b              @ If carry not clear, r3 has shifted
328
                                  @ back to where it started, and we
329
                                  @ can end
330 78 csantifort
 
331
        @ if one of the inputs is negetive then return a negative result
332 61 csantifort
        tst     r4, #0x80000000
333
        mvnne   r0, r0
334 78 csantifort
        addne   r0, r0, #1
335 61 csantifort
3:      ldmia   sp!, {r4, pc}^
336
 
337
 
338 78 csantifort
/* strcpy: String copy function
339 61 csantifort
    char * strcpy ( char * destination, const char * source );
340
    destination is returned
341 78 csantifort
*/
342 61 csantifort
        @ r0 points to destination
343 78 csantifort
        @ r1 points to source string which terminates with a 0
344 61 csantifort
        .globl strcpy
345
strcpy:
346
        stmdb   sp!, {r4-r6, lr}
347
        @ Use r6 to process the destination pointer.
348
        @ At the end of the function, r0 is returned, so need to preserve it
349
        mov     r6, r0
350
 
351
strcpy_main:
352
        @ unroll the loop 4 times
353
        ldrb    r3, [r1], #1
354
        strb    r3, [r6], #1
355
        cmp     r3, #0
356
        ldmeqia sp!, {r4-r6, pc}^
357 78 csantifort
 
358 61 csantifort
        ldrb    r3, [r1], #1
359
        strb    r3, [r6], #1
360
        cmp     r3, #0
361
        ldmeqia sp!, {r4-r6, pc}^
362 78 csantifort
 
363 61 csantifort
        ldrb    r3, [r1], #1
364
        strb    r3, [r6], #1
365
        cmp     r3, #0
366
        ldmeqia sp!, {r4-r6, pc}^
367 78 csantifort
 
368 61 csantifort
        ldrb    r3, [r1], #1
369
        strb    r3, [r6], #1
370
        cmp     r3, #0
371
        ldmeqia sp!, {r4-r6, pc}^
372 78 csantifort
 
373 61 csantifort
        b       strcpy_main
374
 
375
 
376
 
377
/* strncpy: String copy function */
378
        @ r0 points to destination
379
        @ r1 points to source string
380
        @ r2 is the number of bytes to copy
381
        .globl strncpy
382 78 csantifort
strncpy:
383 61 csantifort
        stmdb   sp!, {r4, lr}
384
        cmp     r2, #0
385
        beq     2f
386
        add     r4, r0, r2    @ set r4 to the address of the last byte copied
387
1:      ldrb    r3, [r1], #1
388
        strb    r3, [r0], #1
389
        cmp     r0,  r4
390
        bne     1b
391
2:      ldmia   sp!, {r4, pc}^
392
 
393
 
394
 
395
/* strncpy: String compare function */
396
        @ r0 points to first string
397
        @ r1 points to second string
398
        @ r2 is the number of bytes to compare
399
        @ return the difference if the strings don't match
400
        .globl strncmp
401
strncmp:
402
        stmdb   sp!, {r4, r5, r6, lr}
403 78 csantifort
 
404 61 csantifort
        @ check for 0 length
405
        cmp     r2, #0
406
        moveq   r0, #1
407
        beq     2f
408 78 csantifort
 
409 61 csantifort
        mov     r3, #0
410 78 csantifort
 
411 61 csantifort
1:      add     r3, r3,   #1
412
        ldrb    r4, [r0], #1
413
        ldrb    r5, [r1], #1
414 78 csantifort
 
415 61 csantifort
        subs    r6, r4, r5
416
        movne   r0, r6
417
        bne     2f
418 78 csantifort
 
419 61 csantifort
        cmp     r3, r2
420
        moveq   r0, #0
421
        beq     2f
422 78 csantifort
 
423 61 csantifort
        b       1b
424
2:      ldmia   sp!, {r4, r5, r6, pc}^
425
 
426
 
427
 
428
        .globl init_malloc
429
init_malloc:
430
        ldr     r0, AdrMallocBase
431
        ldr     r1, AdrMallocPointer
432
        str     r0, [r1]
433 78 csantifort
 
434 61 csantifort
        @ initialize the counter to 0
435
        ldr     r1, AdrMallocCount
436
        mov     r2, #0
437
        str     r2, [r1]
438 78 csantifort
 
439 61 csantifort
        mov     pc, lr
440
 
441
 
442
        /* void *malloc(size_t size); */
443
        .globl malloc
444
malloc:
445
        /* r0 contains the size of the object in bytes */
446
        ldr     r1, AdrMallocPointer
447
        ldr     r2, [r1]    /* r2 now containts the starting address of the next memory block to use */
448
        add     r3, r0, r2  /* r3 contains the address after the end of the new object */
449 78 csantifort
 
450 61 csantifort
        /* Round r3 up to the nearest 0x100 to keep memory aligned */
451
        tst     r3, #0xff
452
        beq     1f
453
        bic     r3, r3, #0xff
454
        add     r3, r3, #0x100
455 78 csantifort
 
456 61 csantifort
1:      str     r3, [r1]    /* Update the malloc pointer */
457
        mov     r0, r2      /* Return the address from before the pointer was updated */
458 78 csantifort
 
459 61 csantifort
        @ Update the block count
460
        ldr     r1, AdrMallocCount
461
        ldr     r2, [r1]
462
        add     r2, r2, #1
463
        str     r2, [r1]
464 78 csantifort
 
465 61 csantifort
        mov     pc, lr
466
 
467
 
468 78 csantifort
        .global serial_putchar_
469
serial_putchar_:
470
        ldr     r1, AdrUARTDR
471
        ldr     r3, AdrUARTFR
472
        @ Check the tx_full flag
473
1:      ldr     r2, [r3]
474
        and     r2, r2, #0x20
475
        cmp     r2, #0
476
        streqb  r0, [r1]
477
        moveqs  pc, lr          @ return
478
        bne     1b
479
 
480
 
481 61 csantifort
/* stack at top of ddr3 memory space */
482
AdrJumpPoint:               .word _jump_point
483
AdrExecBase:                .word ADR_EXEC_BASE
484
AdrStack:                   .word ADR_STACK
485
AdrIRQStack:                .word ADR_IRQ_STACK
486
AdrMallocPointer:           .word ADR_MALLOC_POINTER
487
AdrMallocCount:             .word ADR_MALLOC_COUNT
488
AdrMallocBase:              .word ADR_MALLOC_BASE
489
 
490
AdrMemCtrl:                 .word ADR_AMBER_TEST_MEM_CTRL
491
AdrTestStatus:              .word ADR_AMBER_TEST_STATUS
492
AdrInterruptStatus:         .word ADR_AMBER_IC_IRQ0_STATUS
493
 
494 78 csantifort
AdrUARTDR:                  .word ADR_AMBER_UART0_DR
495
AdrUARTFR:                  .word ADR_AMBER_UART0_FR
496
 
497 61 csantifort
                            .align 2
498
AdrATAGBase:                .word ATAGBase
499
AdeEndATAG:                 .word EndATAG
500
 
501
ATAGBase:                   .word ATAG_CORE_SIZE
502
                            .word ATAG_CORE
503
                            .word FLAG_READONLY     @ flags
504
                            .word 4096              @ page size
505
                            .word 0x0               @ rootdev
506 78 csantifort
 
507 61 csantifort
                            .word ATAG_MEM_SIZE
508
                            .word ATAG_MEM
509
                            .word 32*1024*1024      @ size - 32MB
510
                            .word 0x0               @ start
511
 
512
                            .word ATAG_RAMDISK_SIZE
513
                            .word ATAG_RAMDISK
514
                            .word 1                 @ flags: bit 0 = load, bit 1 = prompt
515
                            .word 0x000000d0        @ size in 1k blocks
516
                            .word 0x00800000        @ physical address of start of ramdisk
517
 
518
                            .word ATAG_INITRD_SIZE
519
                            .word ATAG_INITRD
520
                            .word 0x02800000        @ virtual address of start of initrd image
521
                            .word 0x00032000        @ size = 200k
522 78 csantifort
 
523 61 csantifort
                            .word ATAG_NONE
524
                            .word 0x0
525
EndATAG:                    .word 0x0
526
 
527
AdrBootParams:              .word 0x7c000
528
AdrPageTabes:               .word 0x3f01000

powered by: WebSVN 2.1.0

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