📄 crt0.s
字号:
#include "bios/linkage.h"#define CSR_BASE 0x42000000#define SDRAM_TIMING 0x10c#define SDRAM_ADDR_SZ0 0x110#define SDRAM_ADDR_SZ1 0x114#define SDRAM_ADDR_SZ2 0x118#define SDRAM_ADDR_SZ3 0x11c#define SDRAM_BASE 0x40000000#define SDRAM_NRARRAYS 4#define SDRAM_ARRAYOFF 0x00004000#define UARTDR 0x160#define BAUD_RATE_DIVISOR_300 2603#define BAUD_RATE_DIVISOR_2400 325#define BAUD_RATE_DIVISOR_9600 80#define BAUD_RATE_DIVISOR_19200 40#define BAUD_RATE_DIVISOR_38400 19#define BAUD_RATE_DIVISOR_56000 13#define BAUD_RATE_DIVISOR_115200 6#define BAUD_RATE_DIVISOR_128000 5#define BAUD_RATE_DIVISOR BAUD_RATE_DIVISOR_38400#define DEBUG_RAM/* * The CAS latency * Valid: 2 or 3 cycles */#define Tcas 2/* * The RAS cycle time in cycles (Tas + Trp) * Valid: 4 to 10 cycles */#define Trc 5/* * The RAS to CAS delay in cycles * Valid: 2 or 3 cycles */#define Trcd 2/* * Last data in to activate or refresh in cycles * Valid: 2 to 5 cycles */#define Tdal 3/* * Row precharge time * Valid: 1 to 4 cycles */#define Trp 2/* * Refresh time (in us) */#define Tref 64000/* * Add an extra cycle to the command drive time? */#define CmdDrv 0 .text@ Entry .globl _entry_entry: mrs r0, cpsr bic r0, r0, #0x1f orr r0, r0, #0xd3 msr cpsr, r0/* * switch the ROM memory map * so that we can access the SDRAM */ ldr pc, 1f1: .word switchswitch: mov r0, #0 mcr p15, 0, r0, c7, c7, 0 @ flush all caches /* * We need all caches off for the SDRAM initialisation - * we have s/w timing loops to time the SDRAM refresh * cycles in here, which must be synchronised to the bus * clock. */ mrc p15, 0, r0, c1, c0 @ Control reg bic r0, r0, #0x0d @ D-cache, wback & MMU off bic r0, r0, #1 << 12 @ I-cache off mcr p15, 0, r0, c1, c0 @ Control reg bl ser_init/* * Initialise SDRAM. This copes with the SDRAM in any state - * it does a complete initialisation and allocation of all * banks. We basically follow the sequence given in the * EBSA285 manual. * * Turn off SDRAM refresh */init_ram: mov r0, #0 mov ip, #CSR_BASE str r0, [ip, #SDRAM_TIMING] mov r4, #Tcas mov r5, #(CmdDrv & 1) << 1 orr r5, r5, #((Trc - 3) & 7) << 8 orr r5, r5, #(Trcd & 3) << 4 orr r5, r5, #((Tdal - 2) & 3) << 2 orr r5, r5, #(Trp - 1) & 3 orr r5, r5, r4, lsl #6 @ add in Tcas/* * Wait for any refresh cycles to complete */ mov r0, #641: subs r0, r0, #1 bgt 1b/* * All-banks precharge SDRAM arrays */ mov r0, #SDRAM_BASE mov r1, #SDRAM_NRARRAYS1: ldr r2, [r0] ldr r2, [r0] add r0, r0, #SDRAM_ARRAYOFF subs r1, r1, #1 bgt 1b/* * Write mode registers */ mov r0, #0x02 @ burst (4 words) orr r0, r0, r4, lsl #4 @ Tcas mov r0, r0, lsl #2 @ shift up two places orr r0, r0, #SDRAM_BASE mov r1, #SDRAM_NRARRAYS1: str r0, [r0] add r0, r0, #SDRAM_ARRAYOFF subs r1, r1, #1 bgt 1b/* * Turn on minimum SDRAM refresh */ orr r0, r5, #0x00010000 @ 640us refresh time str r0, [ip, #SDRAM_TIMING]/* * Set size to 64MB, space banks at 64MB intervals, with multiplexer mode 4 */ mov r1, #SDRAM_NRARRAYS add r2, ip, #SDRAM_ADDR_SZ0 mov r0, #0x4f1: str r0, [r2], #4 add r0, r0, #64*1024*1024 subs r1, r1, #1 bgt 1b/* * Wait for banks to be refreshed. We actually wait 2560 cycles (80 refreshes) */ mov r0, #10 mov r1, #01: subs r1, r1, #2 bgt 1b subs r0, r0, #1 bgt 1b/* * Set SDRAM refresh to normal */ orr r0, r5, #(Tref / 2621) << 16 str r0, [ip, #SDRAM_TIMING] mov r4, #0x000000001: mov r5, #0/* * Detect RAM multiplexer settings. * * Theory of operation: * There are 6 distinct multiplexer settings. It is possible to detect * which multiplexer settings are correct for the SDRAM array by testing * just four bits with the multiplexer set to mode 4: * row address 9 * row address 10 * row address 11 * bank address 1 * we test to see if toggling these address lines are used by the SDRAM, * and select the multiplexer setting from the result. * * Multiplexer BA1 RA11 RA10 RA9 code Max array size * 000 1 (08) - - - - 0 1MB * 000 0 (00) - - - used 1 2MB * 001 x (10) - - used used 3 16MB * 010 x (20) - used used used 7 64MB * 011 x (30) used - used used b 8MB * 100 x (40) used used used used f 64MB */#ifdef DEBUG_RAM bl debug_bank @ corrupts r2#endif mov r0, r4 @ check for presence add r1, r4, #64 bl testram#ifdef DEBUG_RAM bl debug_testres @ corrupts r1-r3,r6,r7#endif bne next_bank @ array not present - disable mov r0, r4 @ check bit 20 (BA1) orr r1, r0, #1 << 20 bl testram#ifdef DEBUG_RAM bl debug_testres @ corrupts r1-r3,r6,r7#endif orreq r5, r5, #8 @ bit 20 (BA1) has an effect mov r0, r4 @ check bit 22 (row 11) orr r1, r0, #1 << 22 bl testram#ifdef DEBUG_RAM bl debug_testres @ corrupts r1-r3,r6,r7#endif orreq r5, r5, #4 @ bit 22 (row 11) has an effect mov r0, r4 @ check bit 21 (row 10) orr r1, r0, #1 << 21 bl testram#ifdef DEBUG_RAM bl debug_testres @ corrupts r1-r3,r6,r7#endif orreq r5, r5, #2 @ bit 21 (row 10) has an effect mov r0, r4 @ check bit 18 (row 9) orr r1, r0, #1 << 18 bl testram#ifdef DEBUG_RAM bl debug_testres @ corrupts r1-r3,r6,r7#endif orreq r5, r5, #1 @ bit 18 (row 9) has an effect#ifdef DEBUG_RAM bl debug_result#endif adr r1, ram_modes @ convert test result to mux setting ldrb r6, [r1, r5] teq r6, #0xff @ was the test result illegal? moveq r5, #0 @ if it was, disable the array beq next_bank orr r6, r6, r4 @ incorporate address add r0, ip, #SDRAM_ADDR_SZ0 @ set mux correctly orr r5, r6, #7 @ leave array size at 64MB str r5, [r0, r4, lsr #24]/* * Detect RAM array size */ mov r5, #1 << 20 @ start at 1MB mov r7, #12: mov r0, r4 @ check bit (r7 + 19) add r1, r4, r5 bl testram bne 3f @ if bit (r7 + 19) doesnt work mov r5, r5, lsl #1 cmp r7, #7 addne r7, r7, #1 bne 2b3: orr r5, r6, r7next_bank: add r0, ip, #SDRAM_ADDR_SZ0 str r5, [r0, r4, lsr #24] @ set array size#ifdef DEBUG_RAM bl debug_size#endif add r4, r4, #0x04000000 @ next bank address teq r4, #0x10000000 bne 1b/* * Now that we know the size of each SDRAM array, allocate * their addresses, starting at the largest size and working * progressively smaller. * r4 is our "top of memory" */ mov r3, #7 @ start at largest size mov r4, #0x000000001: mov r5, #SDRAM_NRARRAYS add r2, ip, #SDRAM_ADDR_SZ02: ldr r0, [r2], #4 @ Read SDRAM size & addr and r1, r0, #7 teq r1, r3 bne 3f and r0, r0, #127 @ Preserve size etc orr r0, r0, r4 @ Add base address str r0, [r2, #-4] @ Write SDRAM size & addr mov r0, #524288 add r4, r4, r0, lsl r1 @ Next address3: subs r5, r5, #1 @ Next bank bgt 2b subs r3, r3, #1 @ Next size bgt 1b#ifdef DEBUG_RAM bl debug_totalsize#endif teq r4, #0 beq init_ram/* * Now setup caches */ mrc p15, 0, r0, c1, c0 @ read control reg bic r0, r0, #0x0d @ D-cache, wback & MMU off orr r0, r0, #1 << 12 @ I-cache on mcr p15, 0, r0, c1, c0 @ Control reg mov r0, #0 mcr p15, 0, r0, c15, c1, 2 @ clock switching on/* * Copy the data segment to the SDRAM */ ldr r1, =SYMBOL_NAME(_data) ldr r2, =SYMBOL_NAME(_etext) ldr r3, =SYMBOL_NAME(_data_sz)1: ldr r0, [r2], #4 str r0, [r1], #4 subs r3, r3, #4 bgt 1b/* * and zero the BSS */ mov r0, #0 ldr r1, =SYMBOL_NAME(_bss_start) ldr r2, =SYMBOL_NAME(_end)1: str r0, [r1], #4 cmp r1, r2 blt 1b/* * Allocate the stack 1MB below the very top of memory. * Memory above this is reserved for malloc() */ sub sp, r4, #1048576/* * initialise the vectors */ bl vec_init/* * Don't forget to update ram_size */ ldr r0, =SYMBOL_NAME(ram_size) str r4, [r0]/* * Now jump into the C code */ bl SYMBOL_NAME(start_main)l: b lram_modes: @ BA1 RA11 RA10 RA9 .byte 0x08 @ - - - - .byte 0x00 @ - - - x .byte 0xff @ - - x - (illegal) .byte 0x10 @ - - x x .byte 0xff @ - x - - (illegal) .byte 0xff @ - x - x (illegal) .byte 0xff @ - x x - (illegal) .byte 0x20 @ - x x x .byte 0xff @ x - - - (illegal) .byte 0xff @ x - - x (illegal) .byte 0xff @ x - x - (illegal) .byte 0x30 @ x - x x .byte 0xff @ x x - - (illegal) .byte 0xff @ x x - x (illegal) .byte 0xff @ x x x - (illegal) .byte 0x40 @ x x x x/* * Test to see if two RAM locations are aliases. * r0 = location 1 * r1 = location 2 */testram: mov r10, #0x55 orr r10, r10, #0xaa00 orr r10, r10, r10, lsl #16 @ r10 = 0xaa55aa55 str r10, [r0] @ store 0xaa55aa55 to [r0] mvn r10, r10 str r10, [r1] @ store 0x55aa55aa to [r1] mvn r10, r10 ldr r11, [r0] teq r10, r11 @ is [r0] 0xaa55aa55? bne 1f @ no - this means r1 is an alias of r0 mvn r10, r10 str r10, [r0] @ store 0x55aa55aa to [r0] mvn r10, r10 str r10, [r1] @ store 0xaa55aa55 to [r1] mvn r10, r10 ldr r11, [r0] teq r10, r11 @ is [r0] 0x55aa55aa?1: mov pc, lr#ifdef DEBUG_RAMdebug_bank: mov r2, lr adr r0, bankmsg bl ser_prints mov r0, r4 bl ser_printhex mov r0, #'\n' mov lr, r2 b ser_printcdebug_result: mov r2, lr adr r0, result bl ser_prints mov r0, r5 bl ser_printhexbyte mov r0, #'\n' mov lr, r2 b ser_printcdebug_size: mov r2, lr adr r0, size bl ser_prints mov r0, r5 bl ser_printhex mov r0, #'\n' mov lr, r2 b ser_printcdebug_totalsize: mov r2, lr adr r0, totalsize bl ser_prints mov r0, r4 bl ser_printhex mov r0, #'\n' mov lr, r2 b ser_printcdebug_testres: mrs r2, cpsr @ Save CPSR msr spsr, r2 mov r2, lr mov r3, r0 mov r6, r10 mov r7, r11 adr r0, testres1 bl ser_prints mov r0, r3 bl ser_printhex adr r0, testres2 bl ser_prints mov r0, r1 bl ser_printhex adr r0, testres3 bl ser_prints mov r0, r6 bl ser_printhex adr r0, testres4 bl ser_prints mov r0, r7 bl ser_printhex mov r0, #'\n' bl ser_printc movs pc, r2 @ restore CPSRbankmsg: .asciz "Bank address : 0x"result: .asciz " Detect result: 0x"size: .asciz " Bank size reg: 0x"totalsize: .asciz "Total RAM size : 0x"testres1: .asciz " Test result: 0x"testres2: .asciz " : 0x"testres3: .asciz ", wrote 0x"testres4: .asciz ", read 0x" .align#endifser_init: mov r0, #0x42000000 orr r0, r0, #0x160 mov r1, #0 str r1, [r0, #20] mov r2, #161: str r1, [r0, #0] @ write data ldr r3, [r0, #0] @ read data ldr r3, [r0, #4] @ read status subs r2, r2, #1 bne 1b mov r1, #1 str r1, [r0, #20] mov r1, #BAUD_RATE_DIVISOR str r1, [r0, #16] mov r1, #0 str r1, [r0, #12] mov r1, #3 << 5 str r1, [r0, #8] mov r2, #161: ldr r1, [r0, #4] subs r2, r2, #1 bne 1b mov pc, lrser_prints: mov r11, #0x42000000 orr r11, r11, #0x1601: ldrb r10, [r0], #1 teq r10, #0 moveq pc, lr2: str r10, [r11]3: ldr r9, [r11, #24] tst r9, #1 << 5 bne 3b teq r10, #'\n' moveq r10, #'\r' beq 2b b 1bser_printc: mov r11, #0x42000000 orr r11, r11, #0x1601: str r0, [r11]2: ldr r9, [r11, #24] tst r9, #1 << 5 bne 2b teq r0, #'\n' moveq r0, #'\r' beq 1b mov pc, lrser_printhexbyte: mov r11, #0x42000000 orr r11, r11, #0x160 mov r9, #2 mov r0, r0, lsl #24 b 1fser_printhex: mov r11, #0x42000000 orr r11, r11, #0x160 mov r9, #81: and r10, r0, #0xf0000000 mov r10, r10, lsr #28 cmp r10, #10 adccs r10, r10, #6 add r10, r10, #'0' str r10, [r11]2: ldr r10, [r11, #24] tst r10, #1 << 3 bne 2b mov r0, r0, lsl #4 subs r9, r9, #1 bne 1b mov pc, lr/* * void ser_write(const char *buffer, int nr) */ENTRY(ser_write) stmfd sp!, {r9 - r11, lr} bl ser_prints ldmfd sp!, {r9 - r11, pc}ENTRY(ser_stat) mov r3, #0x42000000 ldr r0, [r3, #0x160 + 24] and r0, r0, #1 << 4 mov pc, lr/* * extern struct timer { * unsigned int to; * unsigned int status; * void (*fn)(int); * } timers[]; *//* * int ser_read(char *buffer, int nr) */ENTRY(ser_read) mov ip, r0 mov r3, #0x42000000 orr r3, r3, #0x160 @ base address of UART1: ldr r2, [r3, #24] @ check status tst r2, #1 << 4 beq 2f ldr r2, =SYMBOL_NAME(timers) @ check timer ldr r2, [r2, #4] teq r2, #0 bne 3f b 1b2: ldr r2, [r3, #0] @ read character strb r2, [r0], #1 ldr r2, [r3, #4] @ read status subs r1, r1, #1 bne 1b sub r0, r0, ip mov pc, lr3: mov r0, #0 @ timed out mov pc, lr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -