MicroC/OS-II Realtime Kernel - 부트로더 분석
PXA255 로 포팅된 MicroC/OS-II Realtime Kernel 을 분석했다. 여기서 초점을 맞추고 있는 것은, 기존의 X86 기반에서 MicroC/OS-II Realtime Kernel 이 PXA255 로 아키텍처가 바뀌면서 달라진 것들이다.
수행이 되는 순서에 따라서 하나 하나씩 살펴보도록 하겠다.
부팅 초기화 부분
가장 먼저 수행이 되는 파일로 start_up.S 이 있다.
/* start up code
*/
.file "rom_reset.s"
#include "pxa255.h"
#define SDRAM_BASE_ADDRESS 0xa0000000 /* SDRAM Base Address */
#define CFG_MECR_VAL 0x00000000
#define CFG_MCMEM0_VAL 0x00004204
#define CFG_MCMEM1_VAL 0x00000000
#define CFG_MCATT0_VAL 0x00010504
#define CFG_MCATT1_VAL 0x00000000
#define CFG_MCIO0_VAL 0x00008407
#define CFG_MCIO1_VAL 0x00000000
.equ MonStackSz, (0x10000*3) /* Bigger because enet rcv buffer uses stack */
.equ FiqStackSz, 0x10000
.equ IrqStackSz, 0x10000
.equ AbtStackSz, 0x10000
.equ UndStackSz, 0x10000
.equ SysStackSz, 0x10000
/* 스텍 name 선언 */
.global MonStack
.global FiqStack
.global IrqStack
.global AbtStack
.global UndStack
.global SysStack
/* 스텍 할당 */
.comm MonStack, MonStackSz /* for the SVC mode */
.comm FiqStack, FiqStackSz /* for the FIQ mode */
.comm IrqStack, IrqStackSz /* for the IRQ mode */
.comm AbtStack, AbtStackSz /* for the Abort mode */
.comm UndStack, UndStackSz /* for the Undef mode */
.comm SysStack, SysStackSz /* for the System mode */
.global reset
.global coldstart
.global warmstart
.extern SWIHandler
.extern IRQHandler
.extern FIQHandler
.text
/*
* 0x00000000 번지의 Exception table (Flash Area)
*/
reset:
b coldstart
b undefined_instruction
b SWIHandler
b abort_prefetch
b abort_data
b not_used
b IRQHandler
b FIQHandler
.align 4
undefined_instruction:
b undefined_instruction
software_interrupt:
b software_interrupt
abort_prefetch:
b abort_prefetch
abort_data:
b abort_data
not_used:
b not_used
interrupt_request:
ldr pc , =0xa0000004
fast_interrupt_request:
ldr pc , =0xa0000008
coldstart:
/*
* MMU, Icache, Dcache,write buffer 를 disable한다.
* ARM CORE의 CPSR를 통해 IRQ,FIRQ를 disable한다.
* SVC (supervisory mode)로 동작모드를 설정한다.
* reset이 되면 직접 이 위치로 PC가 옮겨진다.
*
*/
ldr r0, =0x2001 /* 모든 coprocessors에 접근을 허용한다 */
mcr p15,0,r0,c15,c1,0
nop
nop
nop
ldr r0, =0x00000078 /* Disable MMU, caches, write buffer */
mcr p15,0,r0,c1,c0,0
nop
nop
nop
ldr r0, =0x00000000
mcr p15,0,r0,c8,c7,0 /* flush TLB's */
mcr p15,0,r0,c7,c7,0 /* flush Caches */
mcr p15,0,r0,c7,c10,4 /* Flush Write Buffer */
nop
nop
nop
mvn r0, #0 /* grant manager access to all domains */
mcr p15,0,r0,c3,c0,0
/*
* PXA250 interrupt controller 를 초기화 한다.
*/
/* Mask off all IRQs and FIQs */
ldr r1, =(INT_BASE | INT_ICMR)
ldr r2, =0x0 /* 모든 interrupt를 mask off 시킨다 */
str r2, [r1]
/*
* PXA250 Clock Register 를 초기화 한다.
*/
ldr r1, =CLK_BASE /* base of clock registers */
ldr r2, =0x00000241 /* memory clock:100MHz, nomal core clock:200MHz, turbo mode:400MHz */
str r2, [r1, #CLK_CCCR]
/*
* PXA250 Core Clock를 Turbo Mode로 설정한다.
*/
ldr r0,=0
mrc p14,0,r0,c6,c0,0
ldr r0,=3
mcr p14,0,r0,c6,c0,0
/* OS Timer를 초기화 한다. */
ldr r1, =TMR_BASE /* reset the OS Timer Count to zero */
mov r2, #0
str r2, [r1, #TMR_OSCR]
ldr r4, =0x300 /* really 0x2E1 (0.27uS * 0x2E1 = 198uS) is about 200usec, */
/* so 0x300 should be plenty :Wait OS Timer Stabilize */
1:
ldr r2, [r1, #TMR_OSCR]
cmp r4, r2
bgt 1b
init_gpio:
// FFUART
ldr r12, =FFUART_BASE
ldr r0, =0x00000000
str r0, [r12, #FFLCR]
ldr r0, =0x00000000
str r0, [r12, #FFIER]
ldr r0, =0x00000080
str r0, [r12, #FFLCR]
ldr r0, =0x00000018
str r0, [r12, #FFDLL]
ldr r0, =0x00000000
str r0, [r12, #FFDLH]
ldr r0, =0x00000000
str r0, [r12, #FFLCR]
ldr r0, =0x00000003
str r0, [r12, #FFLCR]
ldr r0, =0x00000001
str r0, [r12, #FFFCR]
ldr r0, =0x00000007
str r0, [r12, #FFFCR]
ldr r0, =0x00000000
str r0, [r12, #FFIER]
ldr r0, =0x00000000
str r0, [r12, #FFMCR]
ldr r0, =FFISR_VALUE
str r0, [r12, #FFISR]
ldr r12, =FFUART_BASE
ldr r0, =0x00000040
str r0, [r12, #FFIER]
// clear the rx fifo errors
ldr r0, =FFFCR_VALUE
and r0, r0, #0x00000002
str r0, [r12, #FFFCR]
// First set the output values to a safe/disabled state before we change
// any GPIO's outputs
// start by settings all of them high which is the safest for most signals
ldr r12, =GPIO_BASE
ldr r0, =0xffffffff
str r0, [r12, #GPIO_GPSR0]
str r0, [r12, #GPIO_GPSR1]
str r0, [r12, #GPIO_GPSR2]
// GPCR0
// Now clear any high true outputs that need to start low
ldr r0, =(GPIO_7 | GPIO_13 | GPIO_17 | GPIO_27) // USB speed = high
// PRST = deasserted
// BKL_ON
// Passive LCD enable = off
str r0, [r12, #GPIO_GPCR0]
// Next, set the correct direction for out functions. A one meas output.
ldr r0, =(GPIO_3 | GPIO_4 | GPIO_6 | GPIO_7 | GPIO_11 | GPIO_13 | GPIO_15 | GPIO_17 | GPIO_23 | GPIO_24 | GPIO_25 | GPIO_27 | GPIO_30 | GPIO_31)
// GPDR0
str r0, [r12, #GPIO_GPDR0]
ldr r0, =(GPIO_32 | GPIO_33 | GPIO_39 | GPIO_40 | GPIO_41 | GPIO_43 | GPIO_45 | GPIO_47 | GPIO_48 | GPIO_49 | GPIO_50 | GPIO_51 | GPIO_52 | GPIO_53 | GPIO_54 | GPIO_55 | GPIO_58 | GPIO_59 | GPIO_60 | GPIO_61 | GPIO_62 | GPIO_63)
//GPDR1
str r0, [r12, #GPIO_GPDR1]
ldr r0, =(GPIO_64 | GPIO_65 | GPIO_66 | GPIO_67 | GPIO_68 | GPIO_69 | GPIO_70 | GPIO_71 | GPIO_72 | GPIO_73 | GPIO_74 | GPIO_75 | GPIO_76 | GPIO_77 | GPIO_78 | GPIO_79 | GPIO_80 | GPIO_81 | GPIO_84)
// GPDR2
str r0, [r12, #GPIO_GPDR2]
// Finally, set the alternate function registers to the correct state
ldr r0, =GPIO_15_AF_CS1;
str r0, [r12, #GPIO_GAFR0L]
ldr r0, =(GPIO_18_AF_RDY | GPIO_23_AF_SSP_CLK | GPIO_24_AF_SSP_FRM | GPIO_25_AF_SSP_TXD | GPIO_26_AF_SSP_RXD | GPIO_28_AF_AC97_BCLK_IN | GPIO_29_AF_AC97_SDIN0 | GPIO_30_AF_AC97_SDOUT | GPIO_31_AF_AC97_SYNC)
str r0, [r12, #GPIO_GAFR0U]
ldr r0, =(GPIO_33_AF_CS5 | GPIO_34_AF_FF_RXD | GPIO_35_AF_FF_CTS | GPIO_36_AF_FF_DCD | GPIO_37_AF_FF_DSR | GPIO_38_AF_FF_RI | GPIO_39_AF_FF_TXD | GPIO_40_AF_FF_DTR | GPIO_41_AF_FF_RTS | GPIO_42_AF_BT_RXD | GPIO_43_AF_BT_TXD | GPIO_44_AF_BT_CTS | GPIO_45_AF_BT_RTS | GPIO_46_AF_IR_RXD | GPIO_47_AF_IR_TXD)
str r0, [r12, #GPIO_GAFR1L]
ldr r0, =(GPIO_48_AF_POE | GPIO_49_AF_PWE | GPIO_50_AF_PIOR | GPIO_51_AF_PIOW | GPIO_52_AF_PCE1 | GPIO_53_AF_PCE2 | GPIO_54_AF_PSKTSEL | GPIO_55_AF_PREG | GPIO_56_AF_PWAIT | GPIO_57_AF_IOIS16 | GPIO_58_AF_LDD0 | GPIO_59_AF_LDD1 | GPIO_60_AF_LDD2 | GPIO_61_AF_LDD3 | GPIO_62_AF_LDD4 | GPIO_63_AF_LDD5)
str r0, [r12, #GPIO_GAFR1U]
ldr r0, =(GPIO_64_AF_LDD6 | GPIO_65_AF_LDD7 | GPIO_66_AF_LDD8 | GPIO_67_AF_LDD9 | GPIO_68_AF_LDD10 | GPIO_69_AF_LDD11 | GPIO_70_AF_LDD12 | GPIO_71_AF_LDD13 | GPIO_72_AF_LDD14 | GPIO_73_AF_LDD15 | GPIO_74_AF_LCD_FCLK | GPIO_75_AF_LCD_LCLK | GPIO_76_AF_LCD_PCLK | GPIO_77_AF_LCD_BIAS | GPIO_78_AF_CS2 | GPIO_79_AF_CS3)
str r0, [r12, #GPIO_GAFR2L]
ldr r0, =GPIO_80_AF_CS4
str r0, [r12, #GPIO_GAFR2U]
// // turn on the boot led
// ldr r0, =0x00000010
// str r0, [r12, #GPSR0]
// Clear the peripheral control registers bits
ldr r12, =PSSR
ldr r0, =(PSSR_RDH | PSSR_PH)
str r0, [r12]
////////////////////////////////////////////////////////////////////////////////////////////////////
/*
* PXA250 Memory Controller를 초기화 한다.
*/
ldr r1, =MSC_BASE /* base of memory controller */
/* static memory controller를 초기화 한다 */
ldr r2, =0x123412c0 /* CS0 : flash , CS1 : SMSC LAN91C1111 */
str r2, [r1, #MSC_MSC0]
ldr r3, [r1, #MSC_MSC0]
ldr r2, =0x3ff923e9 /* CS2 : TD242(USB2.0) , CS3 : 확장 보드(fpga board,iom board) */
str r2, [r1, #MSC_MSC1]
ldr r3, [r1, #MSC_MSC1]
ldr r2, =0x3ff97ff9 /* CS4 : SL811HS(USB1.0) , CS5 : KEY PAD */
str r2, [r1, #MSC_MSC2]
ldr r3, [r1, #MSC_MSC2]
/* MECR: Memory Expansion Card Register */
ldr r2, =CFG_MECR_VAL
str r2, [r1, #MSC_MECR]
ldr r2, [r1, #MSC_MECR]
/* MCMEM0: Card Interface slot 0 timing */
ldr r2, =CFG_MCMEM0_VAL
str r2, [r1, #MSC_MCMEM0]
ldr r2, [r1, #MSC_MCMEM0]
/* MCMEM1: Card Interface slot 1 timing */
ldr r2, =CFG_MCMEM1_VAL
str r2, [r1, #MSC_MCMEM1]
ldr r2, [r1, #MSC_MCMEM1]
/* MCATT0: Card Interface Attribute Space Timing, slot 0 */
ldr r2, =CFG_MCATT0_VAL
str r2, [r1, #MSC_MCATT0]
ldr r2, [r1, #MSC_MCATT0]
/* MCATT1: Card Interface Attribute Space Timing, slot 1 */
ldr r2, =CFG_MCATT1_VAL
str r2, [r1, #MSC_MCATT1]
ldr r2, [r1, #MSC_MCATT1]
/* MCIO0: Card Interface I/O Space Timing, slot 0 */
ldr r2, =CFG_MCIO0_VAL
str r2, [r1, #MSC_MCIO0]
ldr r2, [r1, #MSC_MCIO0]
/* MCIO1: Card Interface I/O Space Timing, slot 1 */
ldr r2, =CFG_MCIO1_VAL
str r2, [r1, #MSC_MCIO1]
ldr r2, [r1, #MSC_MCIO1]
/* SDRAM Controller를 100MHz 로 초기화 한다 */
ldr r2, =0x03c00fff /* build MDREFR in a specific order */
str r2, [r1, #MSC_MDREFR]
ldr r2, =0x03c00018 /* REF Rate = (64MS/8192 Rows) * 100MHz /32 = 24 */
str r2, [r1, #MSC_MDREFR]
ldr r2, =0x03c52018 /* Set K0RUN, K1RUN and K2RUN */
str r2, [r1, #MSC_MDREFR]
ldr r2, =0x03852018 /* Clear Self Refresh */
str r2, [r1, #MSC_MDREFR]
ldr r2, =0x0385b018 /* Set E0PIN and E1PIN */
str r2, [r1, #MSC_MDREFR]
ldr r2, =0x0ac80ac8 /* Set CNFG, but don't enable just yet,CL =3,tRP=3clk,tRC=10clk,tRAS=7clk,tRCD=3clk */
str r2, [r1, #MSC_MDCNFG]
/* SDRAM Controller를 50MHz 로 초기화 한다 */
/* pause for ~200usec for SDRAM to init */
ldr r1, =TMR_BASE /* reset the OS Timer Count to zero */
mov r2, #0
str r2, [r1, #TMR_OSCR]
ldr r4, =0x300 /* really 0x2E1 (0.27uS * 0x2E1 = 198uS) is about 200usec, */
/* so 0x300 should be plenty */
1:
ldr r2, [r1, #TMR_OSCR]
cmp r4, r2
bgt 1b
/* force 9 cycles to SDRAM : 모든 sdram bank에 CBR(refrash cycle)이 발생한다. */
ldr r2, =SDRAM_BASE_ADDRESS
str r2, [r2]
str r2, [r2]
str r2, [r2]
str r2, [r2]
str r2, [r2]
str r2, [r2]
str r2, [r2]
str r2, [r2]
str r2, [r2]
ldr r1, =MSC_BASE /* base of memory controller */
ldr r2, =0x0acb0acb /* now enable SDRAM */
str r2, [r1, #MSC_MDCNFG]
/* and do an MRS */
ldr r2, =0x00000000
str r2, [r1, #MSC_MDMRS]
/* sdram initialize 완료 */
#if 1
/*
* 동작 모드를 SVC 모드로 설정하고 stack pointer
* 를 설정한다
*/
stack_pointer_set:
/* FIQ mode */
mrs r0, cpsr /* move CPSR to r0 */
bic r0, r0, #0x1f /* clear all mode bits */
orr r0, r0, #0xd1 /* set FIQ mode bits */
msr CPSR_c, r0 /* move back to CPSR */
ldr sp, =(FiqStack + FiqStackSz - 4) /* initialize the stack ptr */
/* IRQ mode */
mrs r0, cpsr /* move CPSR to r0 */
bic r0, r0, #0x1f /* clear all mode bits */
orr r0, r0, #0xd2 /* set IRQ mode bits */
msr CPSR_c, r0 /* move back to CPSR */
ldr sp, =(IrqStack + IrqStackSz - 4) /* initialize the stack ptr */
/* Abort mode */
mrs r0, cpsr /* move CPSR to r0 */
bic r0, r0, #0x1f /* clear all mode bits */
orr r0, r0, #0xd7 /* set Abort mode bits */
msr CPSR_c, r0 /* move back to CPSR */
ldr sp, =(AbtStack + AbtStackSz - 4) /* initialize the stack ptr */
/* Undef mode */
mrs r0, cpsr /* move CPSR to r0 */
bic r0, r0, #0x1f /* clear all mode bits */
orr r0, r0, #0xdb /* set Undef mode bits */
msr CPSR_c, r0 /* move back to CPSR */
ldr sp, =(UndStack + UndStackSz - 4) /* initialize the stack ptr */
/* System mode */
mrs r0, cpsr /* move CPSR to r0 */
bic r0, r0, #0x1f /* clear all mode bits */
orr r0, r0, #0xdf /* set System mode bits */
msr CPSR_c, r0 /* move back to CPSR */
ldr sp, =(SysStack + SysStackSz - 4) /* initialize the stack ptr */
/* 'warmstart' will take us back to SVC mode
stack for SVC mode will also be setup in warmstart */
#endif
.align 4
warmstart:
/* Change (back) to SVC mode */
mrs r0, cpsr /* move CPSR to r0 */
bic r0, r0, #0x1f /* clear all mode bits */
orr r0, r0, #0xd3 /* set System mode bits */
msr CPSR_c, r0 /* move back to CPSR */
/* Reset the stack pointer for the SVC mode (our current mode) */
// ldr sp, =(MonStack + MonStackSz - 4)
ldr sp, =(0xa4000000 - 4);
/*
* 이제 C function 인 cstart()로 jump 한다.
*/
.align 4
relocate:
adr r0, reset
// relocate the second stage loader
add r2, r0, #(1024 * 1024) // blob maximum size is 64kB
ldr r1, =0xa0000000
// r0 = source address
// r1 = target address
// r2 = source end address
//
copy_loop:
ldmia r0!, {r3-r10}
stmia r1!, {r3-r10}
cmp r0, r2
ble copy_loop
jump_to_c:
bl C_Entry
/* the C code should never return */
b reset
.align 4
코드에 추가된 주석을 보면, 이해할 수 있을 것이다. 실행순서는 처음부터 순차적으로 쭈~욱 수행된다.
처음에 coldstart 를 실행하면,
- MMU, Icache, Dcache,write buffer 를 disable
- ARM CORE의 CPSR를 통해 IRQ,FIRQ 를 disable
- Clock 초기화 및 Timer 초기화
- GPIO 초기화 (※ 필수적이지 않음)
- SDRAM 초기화
- 각 모드(mode) 의 stack pointer 설정
- SVC (supervisory mode)로 동작모드를 설정
- 루프를 돌면서, 메모리 상에 복사
- C 언어 레벨인 C_Entry() 호출
위와 같은 순서로 수행된다.
인터럽트 핸들러 부분
다음은 OS 의 핵심적인 부분이라고 할 수 있는 인터럽트 핸들러, 컨텍스트 스위칭 루틴이 어셈블러 레벨로 구현되어 있다.
//주의 : include는 사용할수 없다.
//-------------------------------------------------------------------
// Interrupt Controller Register
////////// PXA255인 경우
#define ICR_BASE_REGISTER 0x40d00000
////////// SA1110인 경우
#if 0 // pjk 050502
//ICR_BASE_REGISTER 0x90050000
#define ICIP_OFFSET 0x00000000
#define ICMR_OFFSET 0x00000004
#define ICLR_OFFSET 0x00000008
#define ICFP_OFFSET 0x00000010
#define ICPR_OFFSET 0x00000020
#define ICCR_OFFSET 0x0000000C
#else
#define ICIP_OFFSET 0x00000000
#define ICMR_OFFSET 0x00000004
#define ICLR_OFFSET 0x00000008
#define ICFP_OFFSET 0x0000000C
#define ICPR_OFFSET 0x00000000
#define ICCR_OFFSET 0x00000014
#endif
// Timer Register and Period Setting Value
////////// PXA255인 경우
#define OSTIME_BASE_REGISTER 0x40a00000
////////// SA1110인 경우
//OSTIME_BASE_REGISTER EQU 0x90000000
#define OSMR0_OFFSET 0x00000000
#define OSMR1_OFFSET 0x00000004
#define OSMR2_OFFSET 0x00000008
#define OSMR3_OFFSET 0x0000000C
#define OSCR_OFFSET 0x00000010
#define OSSR_OFFSET 0x00000014
#define OWER_OFFSET 0x00000018
#define OIER_OFFSET 0x0000001C
#define PERIOD_VALUE_1MS 3686
#define PERIOD_VALUE_10MS 36864
#define PERIOD_VALUE_100MS 368640
#define PERIOD_VALUE_1000MS 3686400
//-------------------------------------------------------------------
.text
//*****************************************************************************
//
// The undefined instruction handler. This is called when an instruction
// reaches the execute stage of the ARM pipeline, but is not an instruction
// which is recognized by the ARM processor. We don't do anything special to
// try and recover.
//
//*****************************************************************************
.global UndefHandler
.global SWIHandler
.global PAbortHandler
.global DAbortHandler
.global UnusedHandler
.global IRQHandler
.global FIQHandler
UndefHandler:
//////////////////////////////////////////////////////////////////////////////////////
//push
//pop
//////////////////////////////////////////////////////////////////////////////////////////
movs pc, lr
//*****************************************************************************
//
// The software interrupt handler. 0x00 value is uC/OS-II Kernel Interrupt.
//
//*****************************************************************************
SWIHandler:
//////////////////////////////////////////////////////////////////////////////////////
//push
// stmfd sp!, {r0}
// mov r0, #'k'
// bl print_byte
// ldmfd sp!, {r0}
//pop
//////////////////////////////////////////////////////////////////////////////////////////
stmfd sp!, {r0,lr}
mrs r0, SPSR
stmfd sp!, {r0}
ldr r0, [lr, #-4]
bic r0, r0, #0xff000000
cmp r0, #0x00
bne Return_SWIHandler
UCOSII_KERNEL:
//////////////////////////////////////////////////////////////////////////////////////
//push
// .extern print_byte
// stmfd sp!, {r0}
// mov r0, #'b'
// bl print_byte
// ldmfd sp!, {r0}
//pop
//////////////////////////////////////////////////////////////////////////////////////////
ldmfd sp!, {r0}
msr SPSR, r0
ldmfd sp!, {r0,lr}
b OSCtxSw
Return_SWIHandler:
//////////////////////////////////////////////////////////////////////////////////////
//push
//pop
//////////////////////////////////////////////////////////////////////////////////////////
ldmfd sp!, {r0}
msr SPSR, r0
ldmfd sp!, {r0, lr}
movs pc, lr
//*****************************************************************************
//
// The instruction pre-fetch abort handler. This is called when an instruction
// reaches the execute state of the ARM pipeline, but the pre-fetch of the
// instruction failed due to a MMU error. This doesn't need to do a whole lot
// unless we are implementing virtual memory.
//
//*****************************************************************************
PAbortHandler:
//////////////////////////////////////////////////////////////////////////////////////
//push
//pop
//////////////////////////////////////////////////////////////////////////////////////////
subs pc, lr, #4
//*****************************************************************************
//
// The data abort handler. This is called when a load or store instruction is
// executed and the memory access failed due to a MMU error. This doesn't need
// to do a whole lot unless we are implementing virtual memory.
//
//*****************************************************************************
DAbortHandler:
//////////////////////////////////////////////////////////////////////////////////////
//push
//pop
//////////////////////////////////////////////////////////////////////////////////////////
subs pc, lr, #8
//*****************************************************************************
//
// The unused vector handler. This is a legacy vector which existed on older
// ARM processors but is unused by the ARM7 processor. This vector should
// never be called.
//
//*****************************************************************************
UnusedHandler:
movs pc, lr
//*****************************************************************************
//
// The IRQ interrupt handler. This is called when the IRQ line going into the
// ARM processor goes high, indicating an external device is requesting the
// attention of the processor.
//
//*****************************************************************************
IRQHandler:
//추가된 부분 시작
mrs r8, SPSR
ldr r12,=ICR_BASE_REGISTER
ldr r11,[r12, #ICPR_OFFSET]
ldr r10, =0x04000000
tst r10, r11
// .extern OSTimer0IRQ
bne OSTimer0IRQ
msr SPSR, r8
//추가된 부분 끝
subs pc,lr,#4
//*****************************************************************************
//
// The FIQ interrupt handler.
//
//*****************************************************************************
FIQHandler:
mrs r8, SPSR
ldr r12,=ICR_BASE_REGISTER
ldr r11,[r12, #ICFP_OFFSET]
ldr r10, =0x04000000
tst r10, r11
// .extern OSTimer0FIQ
bne OSTimer0FIQ
//-------- 초가되는 부분 시작 ---------------------
stmfd sp!, {r0-r12,lr} //// push
//----RTC와 비교
ldr r11,[r12, #ICFP_OFFSET]
ldr r10, =0x80000000 //RTC
tst r10, r11
// .extern RTC_IRQ
// blne RTC_IRQ
ldr r12,=0x90040018 ////GEDR : Edge dectect register
mov r11, #0x0ff
str r11,[r12]
ldmfd sp!, {r0-r12,lr} //// pop
msr SPSR, r8
subs pc,lr,#4
//-------- 초가되는 부분 끝 ---------------------
msr SPSR, r8
subs pc,lr,#4
//**** SWI_Interrupt_OS_Task_Sw ****************************************************
// This Function is OS_TASK_SW. It is setting F bit to CPSR. SWI interrupt don't
// change F bit. OSTickISR is setting FIQ Interrupt.
//
.global SWI_Interrupt_OS_Task_Sw
SWI_Interrupt_OS_Task_Sw:
stmfd sp!, {r0,lr}
mrs r0, CPSR // r0 <- CPSR
// orr r0, r0, #0x40 // F bit set
orr r0, r0, #0x80 // I bit set
msr CPSR_c,r0 // Control field of CPSR updata
//////////////////////////////////////////////////////////////////////////////////////
//push
// stmfd sp!, {r0}
// .extern print_byte
// mov r0, #'a'
// bl print_byte
// ldmfd sp!, {r0}
//pop
//////////////////////////////////////////////////////////////////////////////////////////
swi 0x00 // uC/OS-II call
//////////////////////////////////////////////////////////////////////////////////////
//push
// stmfd sp!, {r0}
// .extern print_byte
// mov r0, #'s'
// bl print_byte
// ldmfd sp!, {r0}
//pop
//////////////////////////////////////////////////////////////////////////////////////////
ldmfd sp!, {r0,pc}
//**** OSTimer0 ************************************************************
//
//
// .global OSTimer0IRQ
OSTimer0IRQ:
ldr r12, =OSTIME_BASE_REGISTER
//OSTimer Interrupt Source Bit Clear
mov r11, #0x01
str r11, [r12, #OSSR_OFFSET]
ldr r11, [r12, #OSCR_OFFSET]
ldr r10, =PERIOD_VALUE_10MS
add r10, r10, r11
str r10, [r12, #OSMR0_OFFSET]
stmfd sp!, {r0-r3}
mov r2,sp // copy IRQ's sp -> r2
add sp,sp,#16 // recover IRQ's sp
sub r3,lr,#4 // copy return address -> r3
mov r1, r8 // copy SPSR -> r1 (SPSR=r8)
orr r1, r1, #0x80 // I bit Setting
msr SPSR, r1 // update SPSR
ldr r0,=OSTickISR_IRQ
movs pc,r0 // Mode Change from IRQ mode to SVC mode
// .global OSTimer0FIQ
OSTimer0FIQ:
ldr r12, =OSTIME_BASE_REGISTER
//OSTimer Interrupt Source Bit Clear
mov r11, #0x01
str r11, [r12, #OSSR_OFFSET]
ldr r11, [r12, #OSCR_OFFSET]
ldr r10, =PERIOD_VALUE_10MS
add r10, r10, r11
str r10, [r12, #OSMR0_OFFSET]
stmfd sp!, {r0-r3}
mov r2,sp // copy FIQ's sp -> r2
add sp,sp,#16 // recover FIQ's sp
sub r3,lr,#4 // copy return address -> r3
mov r1, r8 // copy SPSR -> r1 (SPSR=r8)
orr r1, r1, #0x40 // F bit Setting
msr SPSR, r1 // update SPSR
ldr r0,=OSTickISR
movs pc,r0 // Mode Change from FIQ mode to SVC mode
//*** OSTickISR ****************************************************************
//
// The mode of OSTickISR is SVC. This Routine is Critical section of code.
// Then, F and I bit of CPSR is set.
//
.extern OSIntNesting
.extern OSTimeTick
.extern OSIntExit
OSTickISR:
stmfd sp!,{r3} // push SVC's pc
stmfd sp!,{r4-r12,lr} // push SVC's r14, r12-r4
mov r4,r2 // copy FIQ's sp -> r4
ldmfd r4!,{r0-r3} // pop SVC's r3-r0
stmfd sp!,{r0-r3} // push SVC's r3-r0
mrs r5,CPSR // copy CPSR -> r5
bic r5, r5, #0x40 // F bit clear
stmfd sp!,{r5} // push SVC's CPSR
ldr r0,=OSIntNesting // Notify uC/OS-II of ISR
ldrb r1,[r0]
ADD r1,r1,#1
strb r1,[r0]
bl OSTimeTick // Process system tick
bl OSIntExit // Notify uC/OS-II of end of ISR
ldmfd sp!,{r0}
msr SPSR,r0
ldmfd sp!,{r0 - r12, lr , pc}^
OSTickISR_IRQ:
stmfd sp!,{r3} // push SVC's pc
stmfd sp!,{r4-r12,lr} // push SVC's r14, r12-r4
mov r4,r2 // copy IRQ's sp -> r4
ldmfd r4!,{r0-r3} // pop SVC's r3-r0
stmfd sp!,{r0-r3} // push SVC's r3-r0
mrs r5,CPSR // copy CPSR -> r5
bic r5, r5, #0x80 // I bit clear
stmfd sp!,{r5} // push SVC's CPSR
ldr r0,=OSIntNesting // Notify uC/OS-II of ISR
ldrb r1,[r0]
ADD r1,r1,#1
strb r1,[r0]
bl OSTimeTick // Process system tick
bl OSIntExit // Notify uC/OS-II of end of ISR
//////////////////////////////////////////////////////////////////////////////////////
//push
// stmfd sp!, {r0}
// .extern print_byte
// mov r0, #'o'
// bl print_byte
// ldmfd sp!, {r0}
//pop
//////////////////////////////////////////////////////////////////////////////////////////
ldmfd sp!,{r0}
// msr SPSR,r0
msr SPSR,r0
ldmfd sp!,{r0 - r12, lr , pc}^
//**** OS Timer Setting ********************************************************
//
//
.global OSTimer0_Period_Setting
OSTimer0_Period_Setting:
stmfd sp!, {r1-r2,lr}
//////////////////////////////////////////////////////////////////////////////////////
//push
// .extern print_byte
// stmfd sp!, {r0}
// mov r0, #'z'
// bl print_byte
// ldmfd sp!, {r0}
//pop
//////////////////////////////////////////////////////////////////////////////////////////
ldr r2, =OSTIME_BASE_REGISTER
mov r1, #0x00
str r1, [r2, #OSCR_OFFSET]
ldr r1, =PERIOD_VALUE_10MS
str r1, [r2, #OSMR0_OFFSET]
mov r1, #0x01
str r1, [r2, #OIER_OFFSET]
mov r1, #0x00
str r1, [r2, #OWER_OFFSET]
//OSTimer Interrupt Source Bit Clear
mov r1, #0x01
str r1, [r2, #OSSR_OFFSET]
mov r1, #0x02
str r1, [r2, #OSSR_OFFSET]
mov r1, #0x04
str r1, [r2, #OSSR_OFFSET]
mov r1, #0x08
str r1, [r2, #OSSR_OFFSET]
ldmfd sp!, {r1-r2,pc}
//**** OStimer0_Interrupt Setting *******************************************************
//
//
.global OSTimer0_Interrupt_Setting
OSTimer0_Interrupt_Setting:
stmfd sp!, {r1-r2, lr}
ldr r2, =ICR_BASE_REGISTER
//////////////////////////////////////////////////////////////////////////////////////
//push
// .extern print_byte
// stmfd sp!, {r0}
// mov r0, #'y'
// bl print_byte
// ldmfd sp!, {r0}
//pop
//////////////////////////////////////////////////////////////////////////////////////////
//
mov r1, #0x00
str r1, [r2, #ICCR_OFFSET]
//---------- FIQ모드인 경우
// ldr r1, [r2, #ICLR_OFFSET]
// //OS Timer Interrupt is set FIQ
// orr r1, r1, #0x04000000
// str r1, [r2, #ICLR_OFFSET]
//---------- IRQ모드인 경우
ldr r1, [r2, #ICLR_OFFSET]
//OS Timer Interrupt is set IRQ
bic r1, r1, #0x04000000
str r1, [r2, #ICLR_OFFSET]
//OS Timer Interrupt Mask Register Set
ldr r1, =0x04000000
str r1, [r2, #ICMR_OFFSET]
ldmfd sp!, {r1-r2, pc}
//**** Interrupt Mask Service Routine ******************************************
//
//
.global OSTimer0_Interrupt_Mask_Disable
.global OSTimer0_Interrupt_Mask_Enable
OSTimer0_Interrupt_Mask_Disable:
stmfd sp!, {r0-r2,lr}
ldr r2, =ICR_BASE_REGISTER
//OS Timer Interrupt Mask Register is Clear
ldr r0, =0x04000000
ldr r1, [r2, #ICMR_OFFSET]
bic r1, r1, r0
str r1, [r2, #ICMR_OFFSET]
ldmfd sp!, {r0-r2,pc}
OSTimer0_Interrupt_Mask_Enable:
stmfd sp!, {r0-r2,lr}
ldr r2, =ICR_BASE_REGISTER
//OS Timer Interrupt Mask Register is Set
ldr r0, =0x04000000
ldr r1, [r2,#ICMR_OFFSET]
orr r1, r1, r0
str r1, [r2,#ICMR_OFFSET]
ldmfd sp!, {r0-r2,pc}
//***** uC/OS Porting Core Function : OSCtxSw *********************************
//
//
.extern OSTCBCur
.extern OSTaskSwHook
.extern OSTCBHighRdy
.extern OSPrioCur
.extern OSPrioHighRdy
.global OSCtxSw
OSCtxSw:
stmfd sp!,{lr} // push resume address
stmfd sp!,{r0 - r12, lr} // push rest context
mrs r0,SPSR
// bic r0, r0, #0x40 // F bit Clear
bic r0, r0, #0x80 // I bit Clear
stmfd sp!,{r0} // push CPSR
ldr r0,=OSTCBCur // r0 <= &OSTCBCur
ldr r0,[r0] // r0 <= OSTCBCur
str sp,[r0] // OSTCBCur->OSTCBStkPtr = sp
bl OSTaskSwHook // Call user defined task switch hook
ldr r0,=OSTCBCur // r0 <= &OSTCBCur
ldr r1,=OSTCBHighRdy // r1 <= &OSTCBHighRdy
ldr r2,[r1] // r2 <= OSTCBHighRdy
str r2,[r0] // OSTCBCur = OSTCBHighRdy
//////////////////////////////////////////////////////////////////////////////////////
//push
// stmfd sp!, {r0}
// .extern print_byte
// mov r0, #'c'
// bl print_byte
// ldmfd sp!, {r0}
//pop
//////////////////////////////////////////////////////////////////////////////////////////
ldr r0,=OSPrioCur // r0 <= &OSPrioCur
ldr r1,=OSPrioHighRdy // r1 <= &OSPrioHighRdy
ldrb r3,[r1] // r3 <= OSPrioHighRdy
strb r3,[r0] // OSPrioCur = OSPrioHighRdy
ldr sp,[r2] // sp <= OSTCBHighRdy->OSTCBStkPtr
ldmfd sp!,{r0} // restore SP...
msr SPSR,r0
ldmfd sp!,{r0 - r12, lr,pc}^ // Load task's context & SPSR-> CPSR & Run task
//**** uC/OS Porting Core Function : OSIntCtxSw *************************************
//
//
.extern OSTCBCur
.extern OSTaskSwHook
.extern OSTCBHighRdy
.extern OSPrioCur
.extern OSPrioHighRdy
.global OSIntCtxSw
OSIntCtxSw:
ADD sp,sp,#4
ldr r0,=OSTCBCur // r0 <= &OSCTBCur
ldr r0,[r0] // r0 <= OSCTBCur
str sp,[r0] // OSTCBCur->OSTCBStkPtr = sp
bl OSTaskSwHook // Call user defined task switch hook
ldr r0,=OSTCBCur // r0 <= &OSTCBCur
ldr r1,=OSTCBHighRdy // r1 <= &OSTCBHighRdy
ldr r2,[r1] // r2 <= OSTCBHighRdy
str r2,[r0] // OSTCBCur = OSTCBHighRdy
ldr r0,=OSPrioCur // r0 <= &OSPrioCur
ldr r1,=OSPrioHighRdy // r1 <= &OSPrioHighRdy
ldrb r3,[r1] // r3 <= OSPrioHighRdy
strb r3,[r0] // OSPrioCur = OSPrioHighRdy
ldr sp,[r2] // sp <= OSTCBHighRdy->OSTCBStkPtr
ldmfd sp!,{r0} // restore SP...
msr SPSR,r0
ldmfd sp!,{r0 - r12, lr , pc}^ // Load task's context & Run task
//**** uC/OS Porting Core Function : OSStartHighRdy *********************************
//
//
.extern OSTaskSwHook
.extern OSRunning
.extern OSTCBHighRdy
.global OSStartHighRdy
OSStartHighRdy:
bl OSTaskSwHook // Call user defined task switch hook
ldr r0,=OSRunning // Indicate that multitasking has started
mov r1,#1
strb r1,[r0]
// .extern print_hex
// bl print_hex
ldr r0,=OSTCBHighRdy // r0 <= &OSTCBHighRdy
ldr r0,[r0] // r0 <= OSTCBHighRdy
// bl print_hex
ldr sp,[r0] // sp <= OSTCBHighRdy->OSTCBStkPtr
ldmfd sp!,{r0} // restore SP...
msr CPSR,r0 // CPSR <- R0
ldmfd sp!,{r0 - r12, lr , pc} // Load task's context & Run task
//****** Interrupt Disable ************************************
//
.global GPIO_Interrupt_Disable
GPIO_Interrupt_Disable:
stmfd sp!, {r1-r2, lr} ////push
//-------------초기화 시작------------
ldr r2,=0x90050000
mov r1, #0x0
str r1, [r2, #0x04]
//-------------초기화 끝------------
ldmfd sp!, {r1-r2, pc}
//****** RTC_Interrupt_Settint ************************************
//
.global RTC_Interrupt_Setting
RTC_Interrupt_Setting:
stmfd sp!, {r1-r2, lr} ////push
//-------------초기화 시작------------
ldr r2, =0x90050000
ldr r1, [r2, #0x04] //
orr r1, r1, #0x80000000
str r1, [r2, #0x04] //
ldr r1, [r2, #0x08] //
orr r1, r1, #0x80000000
str r1, [r2, #0x08] //
ldr r2, =0x90010000
// RTTR &= 0x0000// // RTTR Register Clock Divider Count = 0 , RTC Clock is 32.768 KHz
mov r1, #0x0
str r1, [r2, #0x08] //RTTR, [9001 0008] <- 0
//RTSR |= RTSR_ALE//
ldr r1, [r2, #0x10] //
orr r1, r1, #0x04
str r1, [r2, #0x10] //
//RCNR = 0//
mov r1, #0x0
str r1, [r2, #0x04] //
//time_value = 32768//
//RTAR = time_value//
//mov r1, 32768 // 1초
mov r1, r0 // 2초
str r1, [r2, #0x00] //
//-------------초기화 끝------------
ldmfd sp!, {r1-r2, pc}
///////////////////////////////////////////////
//****** RTC_Interrupt_Disable ************************************
//
.global RTC_Interrupt_Disable
RTC_Interrupt_Disable:
stmfd sp!, {r1-r2, lr} ////push
//-------------초기화 시작------------
ldr r2, =0x90010000
//RTSR &= ~RTSR_ALE//
ldr r1, [r2, #0x10] //
bic r1, r1, #0x04
str r1, [r2, #0x10] //
//-------------초기화 끝------------
ldmfd sp!, {r1-r2, pc}
.align 4