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 를 실행하면,

  1. MMU, Icache, Dcache,write buffer 를 disable
  2. ARM CORE의 CPSR를 통해 IRQ,FIRQ 를 disable
  3. Clock 초기화 및 Timer 초기화
  4. GPIO 초기화 (※ 필수적이지 않음)
  5. SDRAM 초기화
  6. 각 모드(mode) 의 stack pointer 설정
  7. SVC (supervisory mode)로 동작모드를 설정
  8. 루프를 돌면서, 메모리 상에 복사
  9. 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
  • computer/rtcclab/microc_os-ii_realtime_kernel_-_부트로더_분석.txt
  • Last modified: 3 years ago
  • by likewind