1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
;
; 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
; let us put 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_IRQ EQU 0x12
Mode_SVC EQU 0x13
I_Bit EQU 0x80
F_Bit EQU 0x40
SWI_Exit EQU 0x11
; 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
; --- Define __main & set entry point
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 we copy a sequence of LDR PC instructions over the vectors
; (Note: We 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
; --- Initialise 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, 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, R0
LDR R13, =SVC_Stack
; --- Initialise memory system
; ...
; --- Initialise critical IO devices
; ...
; --- Initialise interrupt system variables here
; ...
; --- 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, R0
; --- Initialise 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 initialise
IMPORT |Image$$ZI$$Base| ; Base and limit of area
IMPORT |Image$$ZI$$Limit| ; to zero initialise
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 initialised data
CMP r0, r1 ; Check that they are different
BEQ %1
0 CMP r1, r3 ; Copy init data
LDRCC r2, [r0], #4
STRCC r2, [r1], #4
BCC %0
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 %2
; --- Now we enter the C code
IMPORT C_Entry
[ :DEF:THUMB
ORR lr, pc, #1
BX lr
CODE16 ; Next instruction will be Thumb
]
BL C_Entry
; In a real application we wouldn't normally expect to return, however
; this example does so the debug monitor swi SWI_Exit is used to halt the
; application.
SWI SWI_Exit
END
|