; AT91 board bootstrap and dispatch code ; [JNZ] Modified 20-Mar-2003 ; Should review all timing setups for production - prob. okay ; ; Add self-test and various diagnostics ; ; Write verification in Flash programmer ; Flash programmer should initially listen to both serial ports ; ; Both serial ports initialised to 19.2kbaud ; Maker EQU 1 Version EQU 2 day EQU 9 month EQU 1 year EQU 03 ; [JNZ] Use a 32MHz clock, not 24MHz MHz EQU 32 ;MHz EQU 24 clock_rate EQU &10000 * MHz ; 16.16 bit fixed point number (MHz) GET header.s ; Register definitions etc. GET link_addresses.s ; Addresses (etc.) of programmes Watchdogged_code EQU &53 ; Chip's record of reset No_boot_SW_delay EQU &20000 ; LCD_int_SW_delay EQU 100 ; ;------------------------------------------------------------------------------ ; Cold boot from ROM AREA boot, CODE, READONLY ENTRY ;Start ldr r1, Lit_PIO_base ; Read DIP switches <7:4> ldr r12, [r1,#PIO_PDSR] ; & power-up state <0> adr lr, Start1 ; `Return' address b Device_init ; Initialise on-chip I/O DCB "AT91 Boot code version 0.2 " DCB "J. Garside, (c) University of Manchester " DCB "January 2003" ALIGN ; Pack version & date into 32 bits Version_ID DCD Maker*&1000000 + Version*&10000 + day*&800 + month*&80 + year CIDR_table DCD &04040000, &00001000 ; 40400, 4K DCD &04080000, &00002000 ; 40800, 8K DCD &04080700, &00002000 ; 40807, 8K DCD &04000800, &00040000 ; 40008, 256K DCD &00000000, &00000100 ; Unknown, 256bytes - for now @@@ Start1 ldr r1, Lit_EBI_base ; mov r0, #1 ; str r0, [r1, #EBI_RCR] ; Remap memory add pc, pc, #ROM_base ; This instruction will be ; in the prefetch buffer nop ; Jump will also add 8 nop ; So pad ; The on-chip RAM is now at address 00000000 and we are running in the ROM ; starting at ROM_base. ; R12<7:4> holds the boot DIP switch reading; <0> holds the power-up bit ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; On-chip RAM size can be interpreted from chip ID ldr r13, Lit_SF_base ; Sort out a stack at the ldr r13, [r13, #SF_CIDR] ; top of the internal RAM bic r13, r13, #&000000FF ; Lose version et alia bic r13, r13, #&F0000000 ; adr r8, CIDR_table ; CIDR_loop ldr r4, [r8], #8 ; Read tag and move to next cmp r4, #0 ; Zero is CIDR table terminator beq CIDR_loop_out ; cmp r4, r13 ; Check our ID bne CIDR_loop ; no - not this one CIDR_loop_out ldr sp, [r8, #-4] ; Back to last data field ; So default supervisor stack ; @@@ If device not recognised we should do something special ; Supervisor stack pointer now set up ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; See how much RAM we have on the current board ; This assumes that and all RAM chips are 512KB mov r8, #RAM_base ; Count the amount of RAM ldr r4, Lit_RAM_test_val ; mvn r5, r4 ; Inverse value mov r3, #8 ; Maximum number of chips RAM_tally_loop ldmia r8, {r6, r7} ; Read old values stmia r8, {r4, r5} ; Try new values ; (Scramble bus if floating) ldr r0, [r8] ; cmp r0, r4 ; Loads stored value? bne RAM_tally_done ; No! stmia r8, {r6, r7} ; Restore original contents add r8, r8, #RAM_chip_size ; Move to next chip subs r3, r3, #1 ; bhi RAM_tally_loop ; ; Fall out if RAM address -space- completely occupied mov r4, #RAM_base ; Check for aliasing add r5, r4, #RAM_chip_size ; Move up to second(?) chip ldr r6, [r4] ; Read value from RAM #0 ldr r7, [r5] ; Read value from RAM #1 (?) cmp r6, r7 ; bne RAM_tally_done ; R8 still set correctly mvn r0, r6 ; Values same - coincidence? str r0, [r4] ; Store different value ldr r7, [r5] ; Read value from RAM #1 (?) str r6, [r4] ; Restore old value cmp r0, r7 ; Aliasing? moveq r8, r5 ; Yes - just one RAM after all RAM_tally_done sub r8, r8, #RAM_base ; R8 now holds RAM size ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; R8 now holds length of off-chip RAM bl init_LCD ; R0 indicates LCD presence mov r9, r0 ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; R12 still holds startup option ldr r11, Lit_PIO_base ; Point at PIO ands r6, r12, #&F0 ; Get boot option w/o unwanted bits bne standard_boot ; ldr r0, [r11, #PIO_PDSR] ; If boot #0 tst r0, #AT91_Spartan_init ; Test right hand button beq ROM_loader_emergency ; If pressed ... ; This allows the user to start the ROM loader ; even if "boot_table" has been corrupted. standard_boot mov r10, #boot_table_address; Offset in the Flash add r10, r10, #ROM_base ; add r10, r10, r6, lsl #(boot_table_shifts - 4) ; <7:4> ; See: "boot_table_entry_length" ldr r2, Lit_code ; "Magic Number" ldr r1, [r10] ; cmp r1, r2 ; bne Boot_not_found ; Magic number not discovered ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; Begin customising system for selected application ldr r7, [r10, #Btab_flags] ; Get startup options mov r0, #0 ; LEDs disabled by default tst r7, #BtFlg_LED_on ; from startup tables orrne r0, r0, #AT91_LED_En ; LED enable tst r7, #BtFlg_LCD_light ; orrne r0, r0, #AT91_LCD_light ; LCD backlight enable str r0, [r11, #PIO_CODR] ; Clear outputs to enable ; Checksum ROM block if required ldr r1, [r10, #Btab_ROM_start] ldr r2, [r10, #Btab_ROM_length] add r1, r1, #ROM_base ; True address of ROM block start tst r7, #BtFlg_ROM_check ; blne ROM_checksum ; Returns Validity in R0 ; What do we do (/flash) on an error? @@@ ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; Check for FPGA configurations ldr r0, [r10, #Btab_spartan_data] ; Spartan definition block add r0, r0, #ROM_base ; Offset => pointer ldr r1, [r0] ; "Magic number" ldr r2, Lit_FPGA ; cmp r1, r2 ; bleq spartan_load ; ldr r0, [r10, #Btab_virtex_data] ; Virtex definition block add r0, r0, #ROM_base ; Offset => pointer ldr r1, [r0] ; "Magic number" ldr r2, Lit_FPGA ; cmp r1, r2 ; bleq virtex_load ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; Maybe clear off-chip RAM ; Takes significant time so placed before startup message printed tst r7, #BtFlg_RAM_clr_ext ; Requested by user? tsteq r12, #1 ; Power up reset? blne RAM_clr_ext ; Clear off-chip RAM if either ; Send LCD message tst r7, #BtFlg_LCD_message ; LCD message required? cmpne r9, #FALSE ; Check for LCD absence addne r0, r10, #Btab_LCD_message blne print_str_LCD ; If flag set and LCD present ; Maybe clear on-chip RAM ; Placed here to be after any stack usage tst r7, #BtFlg_RAM_clr_int ; Requested by user? tsteq r12, #1 ; Power up reset? blne RAM_clr_int ; ; Implant any on chip RAM image ldr r1, [r10, #Btab_RAM_start] ; RAM image start offset add r1, r1, #ROM_base ; RAM image start address mov r2, #FASTRAM_base ; (a.k.a. 00000000) ldr r3, [r10, #Btab_RAM_length] ; RAM image length cmp r3, #0 ; blne Copy_to_RAM ; Copies whole words (stackless) ldr r1, Lit_PIO_base ; This sets nice default mov r0, #&FF ; after LCD print str r0, [r1, #PIO_CODR] ; PIO outputs [7:0] to 0 str r0, [r1, #PIO_OER] ; and enable them ; Set up stack pointers ; R1 = size of internal RAM (= top of internal RAM) mrs r0, cpsr ; bic r0, r0, #Mode_bits ; Clear mode bits mov r1, sp ; Default Supervisor SP sub r1, r1, #Supervisor_stack ; Reserve space orr r2, r0, #FIQ_mode ; msr cpsr_c, r2 ; nop ; mov sp, r1 ; Default FIQ SP sub r1, r1, #FIQ_stack ; orr r2, r0, #IRQ_mode ; msr cpsr_c, r2 ; nop ; mov sp, r1 ; Default IRQ SP sub r1, r1, #IRQ_stack ; orr r2, r0, #Abort_mode ; msr cpsr_c, r2 ; nop ; mov sp, r1 ; Default abort SP sub r1, r1, #Abort_stack ; orr r2, r0, #Undefined_mode ; msr cpsr_c, r2 ; nop ; mov sp, r1 ; Default undef. SP sub r1, r1, #Undefined_stack; orr r2, r0, #System_mode ; msr cpsr_c, r2 ; nop ; mov sp, r1 ; Default User SP ; No space specified orr r2, r0, #Supervisor_mode; We need an SPSR msr cpsr_c, r2 ; nop ; ldr r11, [r10, #Btab_exec_CPSR] ; R11 read again below msr spsr_fc, r11 ; Save user's mode, flags etc. mov r0, r10 ; R10 points at config. table mov r1, sp ; SP is at top of RAM mov r2, #RAM_base ; mov r3, r8 ; Off-chip RAM length ldr r4, [r10, #Btab_spartan_data] ; Spartan definition block ldr r5, [r10, #Btab_virtex_data] ; Virtex definition block mov r7, #0 ; cmp r9, #TRUE ; orreq r7, r7, #LCD_present_flag ; Flag LCD presence ; @@@ More flags? tst r12, #1 ; Power up reset? orrne r7, r7, #Power_up_flag ; Flag Power up reset ldr r8, Lit_SF_base ; Check if watchdog reset ldr r8, [r8, #SF_RSR] ; cmp r8, #Watchdogged_code ; orreq r7, r7, #Watchdogged_flag ; Flag Watchdog reset ldr r6, Version_ID ; Boot code version number ldr r8, [r10, #Btab_ROM_start] ; ROM code start address ldr r9, [r10, #Btab_exec_offset] ; Code entry offset ldr r10, [r10, #Btab_flags] ; Get startup options again tst r10, #BtFlg_RAM_boot ; addeq r10, r8, r9 ; Starting in ROM addeq r10, r10, #ROM_base ; ROM code start address movne r10, r9 ; Starting in RAM - use offset only mrs r12, cpsr ; Keep current mode and r11, r11, #Mode_bits ; R11 still holds app's CPSR cmp r11, #FIQ_mode ; Is a different R8 wanted? orreq r11, r11, #&D0 ; Keep other bits sensible msreq cpsr_c, r11 ; Flip to FIQ mode if required nop ; ldr r8, serial_no_ptr ; Get pointer to serial number ldr r8, [r8] ; Get serial number ldr r9, clock_speed ; Get the processor speed msr cpsr_c, r12 ; Restore supervisor mode nop ; (just in case app. = FIQ) movs pc, r10 ; Go! also `restore' CPSR serial_no_ptr DCD ROM_base + Serial_number_addr clock_speed DCD clock_rate ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; At dispatch to application the registers are set up as follows: ; ; R0 = Boot configuration table entry address ; R1 = Size of internal RAM ; R2 = Base address of external RAM ; R3 = Length of external RAM ; R4 = Spartan definition block ; R5 = Virtex definition block ; R6 = Boot code version number Developer (8 bits) ; Version (8 bits) ; Date (5/4/7 bits) ; R7 = Bit coded flags <0> = LCD present ; Ethernet, Spartan, Virtex presence ... @@@ ; <8> = Power up reset ; <9> = Watchdog reset ; R8 = Board serial number ; R9 = Processor clock speed (hard coded in this programme) ; SPs = All set in internal RAM with stack sizes specified by the header file ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; R9 still holds LCD presence flag Boot_not_found cmp r9, #TRUE ; Check for LCD presence adr r0, No_boot_message ; bleq print_str_LCD ; Print message if possible ldr r11, Lit_PIO_base ; mov r0, #AT91_LED_En ; LEDs on str r0, [r11, #PIO_CODR] ; Low to enable mov r0, #&FF ; All LEDs str r0, [r11, #PIO_OER] ; Bottom eight bits as outputs Boot_not_found1 str r0, [r11, #PIO_SODR] ; Set LEDs bl No_boot_delay ; str r0, [r11, #PIO_CODR] ; Clear LEDs bl No_boot_delay ; b Boot_not_found1 ; No_boot_delay mov r1, #No_boot_SW_delay ; Really should use timer ... No_boot_delay1 subs r1, r1, #1 ; @@@ bhi No_boot_delay1 ; mov pc, lr No_boot_message DCB cFF,"No boot found",ttr ;------------------------------------------------------------------------------ ; Copy memory from R1 to R2 length R3 bytes (whole words only) ; Corrupts R0-R3 Copy_to_RAM add r3, r3, #3 ; In case of partial words mov r3, r3, lsr #2 ; Number of words Copy_to_RAM1 ldr r0, [r1], #4 ; str r0, [r2], #4 ; subs r3, r3, #1 ; bhi Copy_to_RAM1 ; mov pc, lr ; ;------------------------------------------------------------------------------ ; R1 is (true) address, R2 is length in bytes ; Returns pass/fail in R0 ; Corrupts R1-R3 ROM_checksum mov r0, #0 ; Accumulator ROM_checksum1 ldrb r3, [r1], #1 ; subs r2, r2, #1 ; Here in case of load delay add r0, r0, r3 ; Accumulate bhi ROM_checksum1 ; tst r0, #&FF ; Totals to 00? moveq r0, #TRUE ; movne r0, #FALSE ; mov pc, lr ; ;------------------------------------------------------------------------------ ; Zero any off- or on- chip RAM. ; On entry R8/R13 (respectively) holds RAM length ; Corrupts R1-R3 RAM_clr_ext movs r2, r8, lsr #2 ; Length in words moveq pc, lr ; Return if no RAM b RAM_clr ; RAM_clr_int mov r2, r13, lsr #2 ; Length in words RAM_clr mov r1, #0 ; mov r3, #RAM_base ; RAM_clr_1 str r1, [r3], #4 ; subs r2, r2, #1 ; bhi RAM_clr_1 ; mov pc, lr ; ; Needs testing @@@ ; Needs speeding up too - Try an STM @@@ ;------------------------------------------------------------------------------ ; Initialise on-chip I/O ; This routine runs RAMless ; Corrupts R0-R3, R13, R14 Device_init mov r13, lr ; Save return address adr r1, EBI_setup ; Definitions table bl dev_init ; Set up EBI adr r1, PIO_setup ; Definitions table bl dev_init ; Set up PIO adr r1, PS_setup ; Definitions table bl dev_init ; Set up PS adr r1, WD_setup ; Definitions table bl dev_init ; Set up WD adr r1, US0_setup ; Definitions table bl dev_init ; Set up US0 adr r1, US1_setup ; Definitions table bl dev_init ; Set up US1 mov pc, r13 ; Return ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; R4 is true to indicate UART - calculate baud rate ; Corrupts R0-R3 dev_init ldr r3, [r1], #4 ; Get base address ; Pass setup data in R1 dev_loop ldr r2, [r1], #4 ; Register offset movs r2, r2 ; See if negative movmi pc, lr ; yes - terminate ldr r0, [r1], #4 ; Get data value str r0, [r3, r2] ; Store value b dev_loop ; and repeat ... ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; ROM speed set too tight for writes @32MHz - Flash loader slows this down ; Chip select bus addresses and region widths & speeds EBI_setup DCD EBI_base DCD EBI_CSR0 ; Chip select 0 DCD (ROM_base :AND: &FFF00000) :OR: CSEN :OR: TDF1 :OR: Pg64M :OR: NWS6 :OR: DBW16 ; DCD (ROM_base :AND: &FFF00000) :OR: CSEN :OR: TDF1 :OR: Pg64M :OR: NWS4 :OR: DBW16 ; ROM set to 4 wait states; okay for writing, sub-optimal for reading. ; Fix in Flash download option @@@ DCD EBI_CSR1 ; Chip select 1 DCD (RAM_base :AND: &FFF00000) :OR: CSEN :OR: BAT :OR: TDF1 :OR: Pg64M :OR: NWS5 :OR: DBW16 DCD EBI_CSR2 ; Chip select 2 DCD (VIRTEX_base :AND: &FFF00000) :OR: CSEN :OR: BAT :OR: TDF1 :OR: Pg64M :OR: DBW8 DCD EBI_CSR3 ; Chip select 3 DCD (ETHERNET_base :AND: &FFF00000) :OR: CSEN :OR: BAT :OR: TDF2 :OR: Pg1M :OR: NWS8 :OR: DBW16 DCD EBI_CSR4 ; Chip select 4 DCD (SPARTAN_base :AND: &FFF00000) :OR: CSEN :OR: BAT :OR: TDF1 :OR: Pg1M :OR: NWS5 :OR: DBW8 DCD EBI_CSR5, &50000000 ; Chip select 5 DCD EBI_CSR6, &60000000 ; Chip select 6 DCD EBI_CSR7, &70000000 ; Chip select 7 DCD EBI_MCR, &00000004 ; Memory Control ; A[22:20], CS4 DCD DEV_TERMINATE ; `Original' bit patterns ; DCD EBI_CSR0, (ROM_base :AND: &FFF00000) :OR: &021BD ; DCD EBI_CSR1, (RAM_base :AND: &FFF00000) :OR: &031A5 ; DCD EBI_CSR2, (VIRTEX_base :AND: &FFF00000) :OR: &03382 ; DCD EBI_CSR4, (SPARTAN_base :AND: &FFF00000) :OR: &03226 ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PIO_setup DCD PIO_base DCD PIO_SODR, &40930000 ; Set Output Data ; Xilinx program lines inactive DCD PIO_CODR, &010000FF ; Clear Output Data ; DCD PIO_OER, &439300FF ; Output Enable DCD PIO_ODR, &000C3E00 ; Output Disable DCD PIO_PER, &439F3EFF ; PIO Enable DCD PIO_PDR, &BC60C100 ; PIO Disable DCD PIO_IFER, &00000000 ; Input Filter Enable DCD PIO_IFDR, &00000000 ; Input Filter Disable DCD PIO_IER, &00000000 ; Interrupt Enable DCD PIO_IDR, &FFFFFFFF ; Interrupt Disable DCD DEV_TERMINATE ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PS_setup DCD PS_base DCD DEV_TERMINATE DCD PS_CR, &00000000 ; CPU Clock Stop DCD PS_PCER, &0000014C ; Peripheral Clock Enable DCD PS_PCSR, &00000030 ; Peripheral Clock Disable DCD DEV_TERMINATE ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WD_setup DCD WD_base DCD DEV_TERMINATE DCD WD_OMR, &00002340 ; Overflow Mode DCD WD_CMR, &00006E00 ; Clock Mode DCD DEV_TERMINATE ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - US0_setup DCD US0_base DCD US_CR, &0000055C ; USART Control Register DCD US_MR, &000408C0 ; USART Mode DCD US_IER, &00000000 ; USART Interrupt Enable DCD US_IDR, &FFFFFFFF ; USART Interrupt Disable DCD US_BRGR ; Baud Rate Generator (CD) DCD (2*clock_rate/baud19k2 + 1)/2 DCD US_RTOR, &00000000 ; Receiver Time Out DCD US_TTGR, &00000000 ; Transmitter Time Out DCD DEV_TERMINATE ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - US1_setup DCD US1_base DCD US_CR, &0000055C ; USART Control Register DCD US_MR, &000008C0 ; USART Mode DCD US_IER, &00000000 ; USART Interrupt Enable DCD US_IDR, &FFFFFFFF ; USART Interrupt Disable DCD US_BRGR ; Baud Rate Generator (CD) DCD (2*clock_rate/baud19k2 + 1)/2 DCD US_RTOR, &00000000 ; Receiver Time Out DCD US_TTGR, &00000000 ; Transmitter Time Out DCD DEV_TERMINATE ;------------------------------------------------------------------------------ ; Literal pool Lit_PIO_base DCD PIO_base ; Lit_EBI_base DCD EBI_base ; Lit_SF_base DCD SF_base ; Lit_Spartan_base DCD SPARTAN_base ; Lit_Virtex_base DCD VIRTEX_base ; ;Lit_boot_table DCD boot_table_address ; Lit_code DCB "CODE" ; Lit_FPGA DCB "FPGA" ; Lit_RAM_test_val DCD &55AA55AA ; ;------------------------------------------------------------------------------ ; R0 points at config. block spartan_load stmfd sp!, {r0,r1,r3,r11,r12,lr} mov r11, r0 ; Configuration definition ; Force other PIO bits to correct state before resetting Spartan ldr r0, Lit_PIO_base ; mov r1, #AT91_Spartan_CS1 ; str r1, [r0, #PIO_SODR] ; Output high (always PIO output) mov r1, #(AT91_Spartan_HDC :OR: AT91_FPGA_baud) str r1, [r0, #PIO_ODR] ; Output disabled str r1, [r0, #PIO_PER] ; Ensure PIO is used ; Sensitive signals floated mov r1, #AT91_Spartan_prog ; Reset Spartan str r1, [r0, #PIO_CODR] ; Programme pin low (pulse >300ns) str r1, [r0, #PIO_SODR] ; Programme pin high again spartan_wtr ldr r1, [r0, #PIO_PDSR] ; PIO pin state tst r1, #AT91_Spartan_init ; beq spartan_wtr ; Wait for Spartan to be ready mov r1, #50 ; Want >5us delay here spartan_wtr1 subs r1, r1, #1 ; 100ns/loop if in 40MHz 32-bit RAM bne spartan_wtr1 ; ldr r0, [r11, #FPGA_offset] ; Offset ldr r1, [r11, #FPGA_length] ; Length add r11, r11, r0 ; Start of stream ldr r12, Lit_Spartan_base ; Spartan address spartan_strip ldrb r3, [r11], #1 ; Strip header message sub r1, r1, #1 ; cmp r3, #&FF ; until FF found bne spartan_strip ; strb r3, [r12] ; First byte of configuration ; Throw config. stream at device spartan_loop ldrb r3, [r11], #1 ; Fetch byte & increment address strb r3, [r12] ; & programme FPGA subs r1, r1, #1 ; Loop count bne spartan_loop ; ldmfd sp!, {r0,r1,r3,r11,r12,pc} ;------------------------------------------------------------------------------ ; R0 points at config. block virtex_load stmfd sp!, {r0,r1,r3,r11,r12,lr} mov r11, r0 ; Configuration definition ; Force other PIO bits to correct state before resetting Virtex ldr r0, Lit_PIO_base ; mov r1, #AT91_Virtex_prog ; Reset Virtex str r1, [r0, #PIO_CODR] ; Programme pin low (pulse width min? @@@) str r1, [r0, #PIO_SODR] ; Programme pin high again virtex_wtr ldr r1, [r0, #PIO_PDSR] ; PIO pin state tst r1, #AT91_Virtex_init ; beq virtex_wtr ; Wait for Virtex to be ready ; Next delay necessary ??? @@@ mov r1, #50 ; Want >5us delay here virtex_wtr1 subs r1, r1, #1 ; 100ns/loop if in 40MHz 32-bit RAM bne virtex_wtr1 ; ldr r0, [r11, #FPGA_offset] ; Offset ldr r1, [r11, #FPGA_length] ; Length add r11, r11, r0 ; Start of stream ldr r12, Lit_Virtex_base ; Virtex address virtex_strip ldrb r3, [r11], #1 ; Strip header message sub r1, r1, #1 ; cmp r3, #&FF ; until FF found bne virtex_strip ; strb r3, [r12] ; First byte of configuration ; Throw config. stream at device virtex_loop ldrb r3, [r11], #1 ; Fetch byte & increment address strb r3, [r12] ; & programme FPGA subs r1, r1, #1 ; Loop count bne virtex_loop ; ldmfd sp!, {r0,r1,r3,r11,r12,pc} ;------------------------------------------------------------------------------ init_LCD stmfd sp!, {r2-r4, lr} ; ldr r4, Lit_PIO_base ; mov r0, #&FF ; Data bus bits str r0, [r4, #PIO_ODR] ; Disable data output bus mov r0, #(AT91_LCD_RS :OR: AT91_LCD_En :OR: AT91_LCD_RW) ; All control bits strb r0, [r4, #PIO_CODR] ; Control bits inactive strb r0, [r4, #PIO_OER] ; Control out adr r3, LCD_init_table ; init_LCD_1 ldrb r0, [r3], #1 ; Address cmp r0, #&FF ; Table terminator? beq init_LCD_done ; tst r0, #1 ; Control or data? ldrb r0, [r3], #1 ; Data bne init_LCD_1a ; bl LCD_ctrl_wr ; Send byte to LCD control reg. b init_LCD_1b ; init_LCD_1a bl LCD_data_wr ; Send byte to LCD data reg. init_LCD_1b ldrb r2, [r3], #1 ; Delay init_LCD_2 bl init_LCD_delay ; Bide a while subs r2, r2, #1 ; Count from table bhi init_LCD_2 ; b init_LCD_1 ; init_LCD_done bl LCD_data_rd ; cmp r0, #&5A ; See if test character present movne r0, #FALSE ; ldmnefd sp!, {r2-r4, pc} ; Zero flag clear if LCD absent bl LCD_wtr ; Can now do this properly mov r0, #&01 ; Clear screen bl LCD_ctrl_wr ; Send byte to LCD control reg. bl LCD_wtr ; mov r0, #&48 ; Point at CGRAM character #1 bl LCD_ctrl_wr ; Send byte to LCD control reg. adr r1, character_defns ; ldrb r2, [r1], #1 ; Get length CGRAM_load ldrb r0, [r1], #1 ; Get byte bl LCD_wtr ; bl LCD_data_wr ; subs r2, r2, #1 ; bhi CGRAM_load ; bl LCD_wtr ; mov r0, #&80 ; Point at DDRAM (start) bl LCD_ctrl_wr ; Send byte to LCD control reg. bl LCD_wtr ; mov r0, #&0C ; Display on, cursor off bl LCD_ctrl_wr ; Send byte to LCD control reg. mov r0, #TRUE ; Signal LCD present ldmfd sp!, {r2-r4, pc} ; init_LCD_delay mov r0, #LCD_int_SW_delay ; Each iteration ~100us (100ns ROM) init_LCD_dly1 subs r0, r0, #1 ; 5 instructions fetched/loop movls pc, lr ; b init_LCD_dly1 ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; LCD initialisation table ; Uses a specified delay (iteration >~1us from ROM) in case LCD not present LCD_init_table DCB 0, &30, 1 ; Use 8-bit interface DCB 0, &30, 1 ; Use 8-bit interface DCB 0, &30, 1 ; Use 8-bit interface DCB 0, &00, 1 ; NOP - seems to help DCB 0, &3C, 1 ; 8-bit interface, 2 lines DCB 0, &08, 1 ; Display off, cursor off DCB 0, &06, 1 ; Cursor moves right, no scroll DCB 0, &80, 1 ; RAM address 0 DCB 1, &5A, 1 ; Test character #0 DCB 1, &75, 1 ; Test character #1 DCB 0, &80, 1 ; RAM address 0 again DCB &FF ; Dog kennel definition character_defns DCB 5 * 8 ; Length DCB &01,&03,&0E,&0C,&18,&19,&19,&19 ; Top left DCB &10,&08,&15,&03,&11,&15,&15,&15 ; Top right DCB &18,&18,&19,&1A,&1A,&18,&18,&08 ; Bottom left DCB &00,&18,&0C,&06,&06,&06,&06,&02 ; Bottom right DCB &01,&02,&02,&0F,&16,&0A,&02,&04 ; "of" ALIGN ;------------------------------------------------------------------------------ print_str_LCD stmfd sp!, {r0-r1,lr} ; mov r1, r0 ; String pointer print_str_LCD_1 ldrb r0, [r1], #1 ; Load, auto-increment cmp r0, #ttr ; ldmeqfd sp!, {r0-r1,pc} ; Conditional return bl print_ch_LCD ; b print_str_LCD_1 ; print_ch_LCD stmfd sp!, {lr} ; bl LCD_wtr ; cmp r0, #cCR ; beq print_ctrl_ch1 ; cmp r0, #cFF ; beq print_ctrl_ch2 ; cmp r0, #cLF ; beq print_ctrl_ch3 ; bl LCD_data_wr ; ldmfd sp!, {pc} ; print_ctrl_ch1 stmfd sp!, {r0} ; mov r0, #&02 ; Home cursor bl LCD_ctrl_wr ; ldmfd sp!, {r0, pc} ; print_ctrl_ch2 stmfd sp!, {r0} ; mov r0, #&01 ; Clear screen bl LCD_ctrl_wr ; ldmfd sp!, {r0, pc} ; print_ctrl_ch3 stmfd sp!, {r0} ; Swap text lines & CR bl LCD_ctrl_rd ; Get current DDRAM address eor r0, r0, #&40 ; Other line bic r0, r0, #&3F ; at the start orr r0, r0, #&80 ; Command bl LCD_ctrl_wr ; ldmfd sp!, {r0, pc} ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LCD_wtr stmfd sp!, {r0, r4, lr} ; ldr r4, Lit_PIO_base ; mov r0, #AT91_LCD_RS ; Data bus defaults to input str r0, [r4, #PIO_CODR] ; Control register mov r0, #AT91_LCD_RW ; str r0, [r4, #PIO_SODR] ; Read mov r0, #AT91_LCD_En ; LCD Enable pin LCD_wtr1 str r0, [r4, #PIO_SODR] ; Strobe Enable ldr r14, [r4, #PIO_PDSR] ; Read pin data str r0, [r4, #PIO_CODR] ; tst r14, #AT91_LCD_busy ; See if busy bne LCD_wtr1 ; Yes - keep trying ldmfd sp!, {r0, r4, pc} ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LCD_data_wr stmfd sp!, {r1, lr} ; Write R0 to LCD data register ldr r14, Lit_PIO_base ; mov r1, #AT91_LCD_RS ; str r1, [r14, #PIO_SODR] ; Data register b LCD_wr ; Jump to write ... LCD_ctrl_wr stmfd sp!, {r1, lr} ; Write R0 to LCD control register ldr r14, Lit_PIO_base ; mov r1, #AT91_LCD_RS ; str r1, [r14, #PIO_CODR] ; Control register ; Fall into write ... LCD_wr and r1, r0, #&FF ; Just the bottom byte str r1, [r14, #PIO_SODR] ; Set LCD data bus "1"s eor r1, r1, #&FF ; str r1, [r14, #PIO_CODR] ; Reset LCD data bus "0"s mov r1, #AT91_LCD_RW ; str r1, [r14, #PIO_CODR] ; Write mov r1, #&FF ; str r1, [r14, #PIO_OER] ; Drive LCD data bus mov r1, #AT91_LCD_En str r1, [r14, #PIO_SODR] ; Strobe Enable str r1, [r14, #PIO_CODR] ; mov r1, #&FF ; str r1, [r14, #PIO_ODR] ; Disable the data outputs ldmfd sp!, {r1, pc} ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LCD_ctrl_rd stmfd sp!, {r1, lr} ; Read R0 from LCD control register ldr r14, Lit_PIO_base ; mov r1, #AT91_LCD_RS ; str r1, [r14, #PIO_CODR] ; Control register b LCD_rd ; Jump to read ... LCD_data_rd stmfd sp!, {r1, lr} ; Read R0 from LCD data register ldr r14, Lit_PIO_base ; mov r1, #AT91_LCD_RS ; str r1, [r14, #PIO_SODR] ; Data register ; Fall into ... LCD_rd mov r1, #AT91_LCD_RW ; str r1, [r14, #PIO_SODR] ; Read mov r1, #&FF ; str r1, [r14, #PIO_ODR] ; Float LCD data bus mov r1, #AT91_LCD_En str r1, [r14, #PIO_SODR] ; Strobe Enable mov r0, #100 ; Each iteration ~100us (100ns ROM) LCD_rd_1 nop ; 5 instructions fetched/loop subs r0, r0, #1 ; bhi LCD_rd_1 ; ldr r0, [r14, #PIO_PDSR] ; Read pins str r1, [r14, #PIO_CODR] ; Remove strobe and r0, r0, #&FF ; Mask off unwanted bits ldmfd sp!, {r1, pc} ; ;------------------------------------------------------------------------------ ; In `emergency' copy image to RAM directly ROM_loader_emergency ldr r1, ROM_loader_emergency_start add r1, r1, #ROM_base ; RAM image start address mov r2, #FASTRAM_base ; (a.k.a. 00000000) ldr r3, ROM_loader_emergency_length bl Copy_to_RAM ; Copies whole words b ROM_loader_ROM ; Definable address ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ROM_loader_emergency_start DCD ROM_loader_image_start - Start ; RAM start ROM_loader_emergency_length DCD ROM_loader_image_end - ROM_loader_image_start ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; Moved up to leave room for boot code development ; Address defined externally in link_addresses.s ALIGN ROM_loader_image_position, -ROM_loader_branch_space ROM_loader_ROM mov pc, #(ROM_loader_RAM - ROM_loader_image_start) ; Dispatch into RAM image ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ALIGN ROM_loader_image_position ROM_loader_image_start ; Start of RAM image 98 DCD EBI_base ; Chip select 0 97 ; ROM set to 4 wait states; okay for writing, sub-optimal for reading. DCD (ROM_base :AND: &FFF00000) :OR: CSEN :OR: TDF1 :OR: Pg64M :OR: NWS4 :OR: DBW16 Prog_host_link DCD US0_base ;Prog_host_link DCD US1_base ROM_loader_RAM ldr r0, %b98 ; EBI_base ldr r1, %b97 ; New setting str r1, [r0, #EBI_CSR0] ; Downcheck the Flash bus speed ; @@@ Really ... ; Set the two ports to different baud rates (115k2, 9600?) ; Listen to each and lock onto one (into R11) mov r9, #flash_protected ; Protect self from erase/write mov r10, #ROM_base ; Point at flash memory ldr r11, Prog_host_link ; Pointer to UART GET fp1.s ; Main body of code ;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------ ; Send character in R0 to serial line #0 Prog_Host_out stmfd sp!, {r2, lr} ; Prog_Host_out1 ldr r2, [r11, #US_CSR] ; Pass byte to transmit in R0 tst r2, #TxRdy ; Test if ready to transmit beq Prog_Host_out1 ; Prog_Host_out2 str r0, [r11, #US_THR] ; Send character ldmfd sp!, {r2, pc} ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; Get character from serial line #0 into R0 Prog_Host_in stmfd sp!, {lr} ; Prog_Host_in1 ldr r0, [r11, #US_CSR] ; tst r0, #RxRdy ; Receiver ready? beq Prog_Host_in1 ; Prog_Host_in_rdy ldr r0, [r11, #US_RHR] ; Upper bits read as 0 ldmfd sp!, {pc} ; Return byte in r0 ;------------------------------------------------------------------------------ ; Device driving routines ;------------------------------------------------------------------------------ ; Wait for addressed location/R1 to contain R0 ; Timeout count in R5 ; Returns R5 = 0 if timeout, else R5 <> 0 ; Corrupts R2 flash_wtr ldrb r2, [r10, r1] ; subs r5, r5, #1 ; Decrement timeout cmpne r2, r0 ; bne flash_wtr ; Wait for values to match mov pc, lr ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - flash_w_hword strh r0, [r10, r1] ; mov pc, lr ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; Remote flash memory read routine ; Byte data into R0, address in R1 flash_r_byte ldrb r0, [r10, r1] ; mov pc, lr ; ;------------------------------------------------------------------------------ ROM_loader_image_end ; End of RAM image ;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------ ; Default RAM image ; This version is simply an error trap/indicator ; ;RAM_image ; B Whoops ; Reset ; B Undefined ; Undefined ; B SWI ; SWI ; B Pabt ; Pabt ; B Dabt ; Dabt ; B Nothing ; Nothing! ; B IRQ ; IRQ ; B FIQ ; FIQ ; ;Whoops sub r0, r14, #4 ; Fault address ; bl Print_word ; ; mov r0, #&01 ; Identify fault ; b Error ; Park! ; ;Undefined sub r0, r14, #4 ; Fault address ; bl Print_word ; ; mov r0, #&02 ; Identify fault ; b Error ; Park! ; ;SWI sub r0, r14, #4 ; Fault address ; bl Print_word ; ; mov r0, #&04 ; Identify fault ; b Error ; Park! ; ;Pabt sub r0, r14, #4 ; Fault address ; bl Print_word ; ; mov r0, #&08 ; Identify fault ; b Error ; Park! ; ;Dabt sub r0, r14, #4 ; Fault address ; bl Print_word ; ; mov r0, #&10 ; Identify fault ; b Error ; Park! ; ;Nothing sub r0, r14, #4 ; Fault address ; bl Print_word ; ; mov r0, #&20 ; Identify fault ; b Error ; Park! ; ;IRQ sub r0, r14, #4 ; Fault address ; bl Print_word ; ; mov r0, #&40 ; Identify fault ; b Error ; Park! ; ;FIQ sub r0, r14, #4 ; Fault address ; bl Print_word ; ; mov r0, #&80 ; Identify fault ; b Error ; Park! ; ; ;Error mov r1, #(PIO_base :AND: byte3) ; orr r1, r1, #(PIO_base :AND: byte2) ; ; str r0, [r1,#PIO_CODR] ; str r0, [r1,#PIO_SODR] ; b Error ; ;;------------------------------------------------------------------------------ ;; Serial output of word in R0 - intended for RAMless operation ;; Corrupts R1-R2, R13, R14 ; ;Print_word mov r13, r14 ; Send a 32 bit value ; bl Put_byte ; `Stack' return address ; mov r0, r0, ror #8 ; ; bl Put_byte ; Shift by 8 each send ; mov r0, r0, ror #8 ; Repeat 4 times ; bl Put_byte ; ; mov r0, r0, ror #8 ; ; bl Put_byte ; ; mov r0, r0, ror #8 ; Restores R0 ; mov pc, r13 ; Return ; ;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;; Output R0 - corrupts R1, R2 ; ;Put_byte ldr r1, RAM_US0_base ; ;Put_byte1 ldr r2, [r1, #US_CSR] ; Pass byte to transmit in R0 ; tst r2, #TxRdy ; Test if ready to transmit ; beq Put_byte1 ; If not then loop ; str r0, [r1,#US_THR] ; ; mov pc, lr ; Return ; ;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;; Input R0 - corrupts R1 ; ;Get_byte ldr r1, RAM_US0_base ; ;Get_byte1 ldr r0, [r1, #US_CSR] ; Pass serial port base in r1 ; tst r0, #RxRdy ; Test if byte received ; beq Get_byte1 ; If not then loop ; ldr r0, [r1,#US_RHR] ; mov pc, lr ; Return byte in r0 ; ;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; ;RAM_US0_base DCD US0_base ; ; ;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; ;RAM_image_end ; ;------------------------------------------------------------------------------ END