10.4.3. Sample code

Example 10.4. : init.s

;
; The AREA must have the attribute READONLY, otherwise the linker will not
; place it in ROM.
;
; The AREA must have the attribute CODE, otherwise the assembler will not
; allow any code in this AREA
;
; Note the '|' character is used to surround any symbols which contain
; non standard characters like '!'.
                AREA    Init, CODE, READONLY
; Now some standard definitions...
Mode_USR        EQU     0x10
Mode_IRQ        EQU     0x12
Mode_SVC        EQU     0x13
I_Bit           EQU     0x80
F_Bit           EQU     0x40
; Locations of various things in our memory system
RAM_Base				EQU     0x10000000      							; 64k RAM at this base
RAM_Limit				EQU     0x10010000
IRQ_Stack				EQU     RAM_Limit       							; 1K IRQ stack at top of memory
SVC_Stack 				EQU     RAM_Limit-1024  							; followed by SVC stack
USR_Stack				EQU 		SVC_Stack-1024					; followed by USR stack
; --- Define entry point
        EXPORT  __main  ; defined to ensure that C runtime system
__main                          											; is not linked in
        ENTRY
; --- Setup interrupt / exception vectors
    IF :DEF: ROM_AT_ADDRESS_ZERO
; If the ROM is at address 0 this is just a sequence of branches
        B       Reset_Handler
        B       Undefined_Handler
        B       SWI_Handler
        B       Prefetch_Handler
        B       Abort_Handler
        NOP             										; Reserved vector
        B       IRQ_Handler
        B       FIQ_Handler
    ELSE
; Otherwise, copy a sequence of LDR PC instructions over the vectors
; (Note: Copy LDR PC instructions because branch instructions
; could not simply be copied, the offset in the branch instruction
; would have to be modified so that it branched into ROM. Also, a
; branch instructions might not reach if the ROM is at an address
; > 32M).
        MOV     R8, #0
        ADR     R9, Vector_Init_Block
        LDMIA   R9!, {R0-R7}
        STMIA   R8!, {R0-R7}
        LDMIA   R9!, {R0-R7}
        STMIA   R8!, {R0-R7}
; Now fall into the LDR PC, Reset_Addr instruction which will continue
; execution at 'Reset_Handler'
Vector_Init_Block
        LDR     PC, Reset_Addr
        LDR     PC, Undefined_Addr
        LDR     PC, SWI_Addr
        LDR     PC, Prefetch_Addr
        LDR     PC, Abort_Addr
        NOP
        LDR     PC, IRQ_Addr
        LDR     PC, FIQ_Addr
Reset_Addr      DCD     Reset_Handler
Undefined_Addr  DCD     Undefined_Handler
SWI_Addr        DCD     SWI_Handler
Prefetch_Addr   DCD     Prefetch_Handler
Abort_Addr      DCD     Abort_Handler
				DCD     0       							; Reserved vector
IRQ_Addr        DCD     IRQ_Handler
FIQ_Addr        DCD     FIQ_Handler
    ENDIF
; The following handlers do not do anything useful in this example.
;
Undefined_Handler
        B       Undefined_Handler
SWI_Handler
        B       SWI_Handler
Prefetch_Handler
        B       Prefetch_Handler
Abort_Handler
        B       Abort_Handler
IRQ_Handler
        B       IRQ_Handler
FIQ_Handler
        B       FIQ_Handler
; The RESET entry point
Reset_Handler
; --- Initialize stack pointer registers
; Enter IRQ mode and set up the IRQ stack pointer
		MOV     R0, #Mode_IRQ:OR:I_Bit:OR:F_Bit 												; No interrupts
        MSR     CPSR_c, R0
        LDR     R13, =IRQ_Stack
; Set up other stack pointers if necessary
        ; ...
; Set up the SVC stack pointer last and return to SVC mode
		MOV     R0, #Mode_SVC:OR:I_Bit:OR:F_Bit 												; No interrupts
        MSR     CPSR_c, R0
        LDR     R13, =SVC_Stack
; --- Initialize memory system
        ; ...
; --- Initialize critical IO devices
        ; ...
; --- Initialize interrupt system variables here
        ; ...
; --- Initialize memory required by C code
		IMPORT  |Image$$RO$$Limit|								; End of ROM code (=start of ROM data)
		IMPORT  |Image$$RW$$Base|								; Base of RAM to initialize
		IMPORT  |Image$$ZI$$Base| 								; Base and limit of area
 		IMPORT  |Image$$ZI$$Limit|								; to zero initialize
		LDR     r0, =|Image$$RO$$Limit|								; Get pointer to ROM data
		LDR     r1, =|Image$$RW$$Base|								; and RAM copy
		LDR     r3, =|Image$$ZI$$Base|								; Zero init base => top of initialized data
		CMP     r0, r1								; Check that they are different
		BEQ     %F1
0		CMP     r1, r3								; Copy init data
		LDRCC   r2, [r0], #4
		STRCC   r2, [r1], #4
		BCC     %B0
1		LDR     r1, =|Image$$ZI$$Limit|								; Top of zero init segment
		MOV     r2, #0
2		CMP     r3, r1                  	; Zero init
		STRCC   r2, [r3], #4
		BCC     %B2
; --- Enable interrupts
; Now safe to enable interrupts, so do this and remain in SVC mode
        MOV     R0, #Mode_SVC:OR:F_Bit  ; Only IRQ enabled
        MSR     CPSR_c, R0
; --- Now change to User mode and set up User mode stack.
		MOV     R0, #Mode_USR:OR:I_Bit:OR:F_Bit
		MSR     CPSR_c, R0
		LDR     sp, =USR_Stack
; --- Now enter the C code
		IMPORT  C_Entry
	[ :DEF:THUMB
				ORR     lr, pc, #1
				BX      lr
				CODE16             						; Next instruction will be Thumb
    ]
		BL      C_Entry
; A real application wouldn't normally be expected to return, however
; in case it does, the debug monitor swi is used to halt the application.
		MOV     r0, #0x18 								; angel_SWIreason_ReportException
		LDR     r1, =0x20026								; ADP_Stopped_ApplicationExit
		[ :DEF: THUMB
				SWI 0xAB						; Angel semihosting Thumb SWI
		|
				SWI     0x123456						; Angel semihosting ARM SWI
		]
		END

Example 10.5. : ex.c

#ifdef __thumb
/* Define Angel Semihosting SWI to be Thumb one */
#define SemiSWI 0xAB
#else
/* Define Angel Semihosting SWI to be ARM one */
#define SemiSWI 0x123456
#endif
/* Use the following Debug Monitor SWIs to write things out
 * in this example
 */
/* Write a character */ 
__swi(SemiSWI) void _WriteC(unsigned op, const char *c);
#define WriteC(c) _WriteC (0x3,c)
/* Write a string */
__swi(SemiSWI)void _Write0(unsigned op, const char *string);
#define Write0(string) _Write0 (0x4,string)
/* Exit */
__swi(SemiSWI) void _Exit(unsigned op, unsigned except);
#define Exit() _Exit (0x18,0x20026)
/* The following symbols are defined by the linker and define
 * various memory regions which may need to be copied or initialized
 */
extern char Image$$RO$$Limit[];
extern char Image$$RW$$Base[];
/* Define some more meaningful names here */
#define rom_data_base Image$$RO$$Limit
#define ram_data_base Image$$RW$$Base
/* This is an example of a pre-initialized variable. */
static unsigned factory_id = 0xAA55AA55;  /* Factory set ID */
/* This is an example of an uninitialized (or zero-initialized) variable */
static char display[8][40];               /* Screen buffer */
static const char hex[17] = "0123456789ABCDEF";
static void pr_hex(unsigned n)
{
    int i;
    for (i = 0; i < 8; i++) {
        WriteC(&hex[n >> 28]);
        n <<= 4;
    }
}
void C_Entry(void)
{
  if (rom_data_base == ram_data_base) {
    Write0("Warning: Image has been linked as an application.\r\n");
    Write0("         To link as a ROM image, link with the options\r\n");    
	Write0("               -RO <rom-base> -RW <ram-base>\r\n");
  }
  Write0("'factory_id' is at address ");
  pr_hex((unsigned)&factory_id);
  Write0(", contents = ");
  pr_hex((unsigned)factory_id);
  Write0("\r\n");
  Write0("'display' is at address ");
  pr_hex((unsigned)display);
  Write0("\r\n");
  Exit();
}
Copyright © 1997, 1998 ARM Limited. All rights reserved.ARM DUI 0040D
Non-Confidential