openpcd/openpicc/os/boot/boot.s

338 lines
10 KiB
ArmAsm

/* Sample initialization file */
.extern main
.extern exit
.extern AT91F_LowLevelInit
.extern pio_irq_isr_value
.extern ssc_tx_pending
.extern ssc_tx_fiq_fdt_cdiv
.extern ssc_tx_fiq_fdt_ssc
.text
.code 32
.align 0
.extern __stack_end__
.extern __bss_beg__
.extern __bss_end__
.extern __data_beg__
.extern __data_end__
.extern __data+beg_src__
.global start
.global endless_loop
/* Stack Sizes */
.set UND_STACK_SIZE, 0x00000004
.set ABT_STACK_SIZE, 0x00000004
.set FIQ_STACK_SIZE, 0x00000400
.set IRQ_STACK_SIZE, 0X00000400
.set SVC_STACK_SIZE, 0x00000400
/* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs */
.set MODE_USR, 0x10 /* User Mode */
.set MODE_FIQ, 0x11 /* FIQ Mode */
.set MODE_IRQ, 0x12 /* IRQ Mode */
.set MODE_SVC, 0x13 /* Supervisor Mode */
.set MODE_ABT, 0x17 /* Abort Mode */
.set MODE_UND, 0x1B /* Undefined Mode */
.set MODE_SYS, 0x1F /* System Mode */
.equ I_BIT, 0x80 /* when I bit is set, IRQ is disabled */
.equ F_BIT, 0x40 /* when F bit is set, FIQ is disabled */
.equ AT91C_BASE_AIC, (0xFFFFF000)
.equ AT91C_BASE_MC, (0xFFFFFF00)
.equ AT91C_BASE_PIOA, 0xFFFFF400
.equ AT91C_BASE_TC0, 0xFFFA0000
.equ AT91C_BASE_SSC, 0xFFFD4000
.equ SSC_CR, 0x0
.equ SSC_RCMR, 0x10
.equ SSC_CR_TXEN, 0x100
.equ AT91C_TC_SWTRG, (1 << 2)
.equ AT91C_TC_CLKEN, (1 << 0)
.equ PIO_DATA, (1 << 27)
.equ PIO_FRAME, (1 << 20)
.equ PIO_SSC_TF, (1 << 15)
.equ PIOA_SODR, 0x30
.equ PIOA_CODR, 0x34
.equ PIOA_PDSR, 0x3c
.equ PIOA_IDR, 0x44
.equ PIOA_ISR, 0x4c
.equ TC_CCR, 0x00
.equ TC2_CV, (0x80+0x10)
.equ AIC_EOICR, (304)
.equ PIO_LED1, (1 << 25)
.equ PIO_LED2, (1 << 12)
.equ MC_RCR, 0xFFFFFF00
.equ AIC_ISCR, (0x12C)
.equ PIO_SECONDARY_IRQ, 31
.equ PIO_SECONDARY_IRQ_BIT, (1 << PIO_SECONDARY_IRQ)
start:
_start:
_mainCRTStartup:
/* Setup a stack for each mode - note that this only sets up a usable stack
for system/user, SWI and IRQ modes. Also each mode is setup with
interrupts initially disabled. */
ldr r0, .LC6
msr CPSR_c, #MODE_UND|I_BIT|F_BIT /* Undefined Instruction Mode */
mov sp, r0
sub r0, r0, #UND_STACK_SIZE
msr CPSR_c, #MODE_ABT|I_BIT|F_BIT /* Abort Mode */
mov sp, r0
sub r0, r0, #ABT_STACK_SIZE
msr CPSR_c, #MODE_FIQ|I_BIT|F_BIT /* FIQ Mode */
/* Preload registers for FIQ handler */
ldr r10, =AT91C_BASE_PIOA
ldr r12, =AT91C_BASE_TC0
ldr r8, =AT91C_BASE_AIC
mov r9, #AT91C_TC_SWTRG
/*ldr r9, =AT91C_BASE_SSC*/
mov sp, r0
sub r0, r0, #FIQ_STACK_SIZE
msr CPSR_c, #MODE_IRQ|I_BIT|F_BIT /* IRQ Mode */
mov sp, r0
sub r0, r0, #IRQ_STACK_SIZE
msr CPSR_c, #MODE_SVC|I_BIT|F_BIT /* Supervisor Mode */
mov sp, r0
sub r0, r0, #SVC_STACK_SIZE
msr CPSR_c, #MODE_SYS|I_BIT|F_BIT /* System Mode */
mov sp, r0
/* We want to start in supervisor mode. Operation will switch to system
mode when the first task starts. */
msr CPSR_c, #MODE_SVC|I_BIT|F_BIT
bl AT91F_LowLevelInit
/* Clear BSS. */
mov a2, #0 /* Fill value */
mov fp, a2 /* Null frame pointer */
mov r7, a2 /* Null frame pointer for Thumb */
ldr r1, .LC1 /* Start of memory block */
ldr r3, .LC2 /* End of memory block */
subs r3, r3, r1 /* Length of block */
beq .end_clear_loop
mov r2, #0
.clear_loop:
strb r2, [r1], #1
subs r3, r3, #1
bgt .clear_loop
.end_clear_loop:
/* Initialise data. */
ldr r1, .LC3 /* Start of memory block */
ldr r2, .LC4 /* End of memory block */
ldr r3, .LC5
subs r3, r3, r1 /* Length of block */
beq .end_set_loop
.set_loop:
ldrb r4, [r2], #1
strb r4, [r1], #1
subs r3, r3, #1
bgt .set_loop
.end_set_loop:
/* call main */
mov r0, #0 /* no arguments */
mov r1, #0 /* no argv either */
ldr lr, =main
bx lr
endless_loop:
b endless_loop
.align 0
.LC1:
.word __bss_beg__
.LC2:
.word __bss_end__
.LC3:
.word __data_beg__
.LC4:
.word __data_beg_src__
.LC5:
.word __data_end__
.LC6:
.word __stack_end__
/* Setup vector table. Note that undf, pabt, dabt, fiq just execute
a null loop. */
.section .startup,"ax"
.code 32
.align 0
b _start /* reset - _start */
ldr pc, _undf /* undefined - _undf */
ldr pc, _swi /* SWI - _swi */
ldr pc, _pabt /* program abort - _pabt */
ldr pc, _dabt /* data abort - _dabt */
nop /* reserved */
ldr pc, [pc,#-0xF20] /* IRQ - read the AIC */
/* ldr pc, [pc,#-0xF20] /* FIQ - fall through to fiq_handler */
/* Following is modified from openpcd/firmware/src/start/Cstartup_app.S */
#define LED_TRIGGER
.global fiq_handler
.func fiq_handler
my_fiq_handler:
/* code that uses pre-initialized FIQ reg */
/* r8 tmp
r9 AT91C_TC_SWTRG
r10 AT91C_BASE_PIOA
r11 tmp
r12 AT91C_BASE_TC0
r13 stack
r14 lr
*/
#ifdef LED_TRIGGER
mov r11, #PIO_LED1
str r11, [r10, #PIOA_CODR] /* enable LED */
#endif
ldr r8, [r10, #PIOA_ISR]
/* Store the retrieved PIO ISR value into pio_irq_isr_value */
ldr r11, =pio_irq_isr_value
str r8, [r11]
tst r8, #PIO_DATA /* check for PIO_DATA change */
ldrne r11, [r10, #PIOA_PDSR]
tstne r11, #PIO_DATA /* check for PIO_DATA == 1 */
strne r9, [r12, #TC_CCR] /* software trigger */
movne r11, #PIO_DATA
strne r11, [r10, #PIOA_IDR] /* disable further PIO_DATA FIQ */
beq .no_pio_data
/* .loop_high:
ldr r11, [r10, #PIOA_PDSR]
tst r11, #PIO_DATA
bne .loop_high
str r9, [r12, #TC_CCR] /* software trigger */
.no_pio_data:
tst r8, #PIO_SSC_TF /* check for SSC Transmit Frame signal */
ldrne r11, [r10, #PIOA_PDSR]
tstne r11, #PIO_SSC_TF /* check for SSC_TF == 1 */
movne r11, #PIO_SSC_TF
strne r11, [r10, #PIOA_IDR] /* disable further SSC_TF FIQ */
ldrne r11, =ssc_tx_pending
ldrne r8, [r11]
tstne r8, #0x01 /* Check whether a TX is pending */
beq .no_ssc
mov r8, #PIO_LED1
str r8, [r10, #PIOA_SODR] /* disable LED */
mov r8, #0x00
str r8, [r11] /* Set ssc_tx_pending to 0 */
ldr r11, =ssc_tx_fiq_fdt_cdiv
ldr r11, [r11] /* r11 == ssc_tx_fiq_fdt_cdiv */
/* Problem: LDR from the timer still takes too long and causes us to miss the exact time.
* Strategy: Spin on TC2 till we are very near the actual time. Then load the timer value, calculate
* the difference to the target, then do a countdown spin without reading the timer.
*
* At 47.923200 MHz 7 processor cycles are 2 carrier cycles of the 13.56MHz carrier
*/
.equ SUB_TIME, 20 /* subtract 20 carrier cycles == 70 processor cycles */
.equ ADD_TIME, (70-20) /* Add x processor cycles */
mov r8, #SUB_TIME
sub r11, r11, r8
.wait_for_fdt_cdiv:
ldr r8, [r12, #TC2_CV]
cmp r8, r11
bmi .wait_for_fdt_cdiv /* spin while TC2.CV is less fdt_cdiv-SUB_TIM */
ldr r8, [r12, #TC2_CV]
sub r11, r11, r8 /* r11 == fdt_cdiv-SUB_TIME - TC2.CV */
mov r8, #0x07
mul r11, r8, r11 /* r11 = r11 * 7 */
mov r11, r11, ASR #1 /* r11 = r11 / 2 */
mov r8, #ADD_TIME
add r11, r11, r8 /* r11 = r11 + ADD_TIME */
mov r11, r11, ASR #2 /* r11 = r11 / 4 (4 is the number of cycles per loop run below) */
mov r8, #1
.wait_for_my_time:
subs r11, r11, r8
bge .wait_for_my_time
str r9, [r12, #TC_CCR] /* SWTRG on TC0 */
ldr r11, =ssc_tx_fiq_fdt_ssc
ldr r11, [r11] /* r11 == ssc_tx_fiq_fdt_ssc */
.wait_for_fdt_ssc:
ldr r8, [r12, #TC2_CV]
cmp r8, r11
bmi .wait_for_fdt_ssc /* spin while TC2.CV is less fdt_ssc */
mov r11, #PIO_LED1
str r11, [r10, #PIOA_CODR] /* enable LED */
ldr r11, =AT91C_BASE_SSC
mov r8, #SSC_CR_TXEN
str r8, [r11, #SSC_CR] /* Write TXEN to SSC_CR, enables tx */
.no_ssc:
/* Trigger PIO_SECONDARY_IRQ */
mov r11, #PIO_SECONDARY_IRQ_BIT
ldr r8, =AT91C_BASE_AIC
str r11, [r8, #AIC_ISCR]
#ifdef LED_TRIGGER
mov r11, #PIO_LED1
str r11, [r10, #PIOA_SODR] /* disable LED */
#endif
/*- Mark the End of Interrupt on the AIC */
ldr r11, =AT91C_BASE_AIC
str r11, [r11, #AIC_EOICR]
/*- Restore the Program Counter using the LR_fiq directly in the PC */
subs pc, lr, #4
.size my_fiq_handler, . - my_fiq_handler
.endfunc
_undf: .word __undf /* undefined */
_swi: .word swi_handler /* SWI */
_pabt: .word __pabt /* program abort */
_dabt: .word __dabt /* data abort */
_fiq: .word __fiq /* FIQ */
__undf: b . /* undefined */
__pabt: b . /* program abort */
__dabt: b . /* data abort */
__fiq: b . /* FIQ */
.end