rev |
line source |
nuclear@0
|
1 @********************************************************************
|
nuclear@0
|
2 @* crt0.S v1.28 by Jeff Frohwein *
|
nuclear@0
|
3 @********************************************************************
|
nuclear@0
|
4
|
nuclear@0
|
5 @ v1.0 - Original release
|
nuclear@0
|
6 @ v1.1 - Added proper .data section support
|
nuclear@0
|
7 @ v1.2 - Added support for c++, overlays, interrupts, and
|
nuclear@0
|
8 @ far calls (__FarFunction & __FarProcedure).
|
nuclear@0
|
9 @ - Some ideas from Jason Wilkins & Mike Heckenbach.
|
nuclear@0
|
10 @ v1.21- Killed the dumb test bug left in the code.
|
nuclear@0
|
11 @ v1.22- Killed dumb bug "numero dos" in multiple interrupts routine. Thanks Mike H. :)
|
nuclear@0
|
12 @ v1.23- Now correctly handles zero length .bss section.
|
nuclear@0
|
13 @ v1.24- Loop back to start_vector now works if main {} exits.
|
nuclear@0
|
14 @ v1.25- __FarProcedure now works. It was missing a .thumb_func directive.
|
nuclear@0
|
15 @ v1.26- Added missing Serial Interrupt processing to __MultipleInterrupts section.
|
nuclear@0
|
16 @ Added __FastInterrupt option for minimal interrupt processing.
|
nuclear@0
|
17 @ Optimized __MultipleInterrupts section to save 4 bytes of stack space.
|
nuclear@0
|
18 @ Added __ISRinIWRAM option that puts interrupt processing in IWRAM by default.
|
nuclear@0
|
19 @ Options passed to main() or AgbMain() are now set to 0. (Thanks to DarkFader)
|
nuclear@0
|
20 @ v1.27- Even though it might not cause any problems for anyone "as is",
|
nuclear@0
|
21 @ changed .SECTION .iwram to .SECTION .iwram,"ax",%progbits
|
nuclear@0
|
22 @ just to be safe. That is the more correct description/definition.
|
nuclear@0
|
23 @ Added warning below about small default interrupt stack.
|
nuclear@0
|
24 @ v1.28- Added force alignment (align 4) to CopyMem & ClearMem to
|
nuclear@0
|
25 @ prevent infinite loops in cases where LD (buggy?) fails
|
nuclear@0
|
26 @ to align(4). (Thanks to Mark Price & others.)
|
nuclear@0
|
27 @
|
nuclear@0
|
28 @ This file is released into the public domain for commercial
|
nuclear@0
|
29 @ or non-commercial usage with no restrictions placed upon it.
|
nuclear@0
|
30
|
nuclear@0
|
31 .TEXT
|
nuclear@0
|
32
|
nuclear@0
|
33 @ Comment out the next line ONLY if you plan to never support
|
nuclear@0
|
34 @ multiboot mode and want to save a few bytes by removing
|
nuclear@0
|
35 @ multiboot support code. Otherwise, leave it alone. It wont
|
nuclear@0
|
36 @ disturb code designed to run only on flash carts.
|
nuclear@0
|
37 @
|
nuclear@0
|
38 @ The normal way to enable generating code that works with
|
nuclear@0
|
39 @ both multiboot and flash carts is to add the following to
|
nuclear@0
|
40 @ your C code in your main project file AS A GLOBAL VARIABLE:
|
nuclear@0
|
41 @
|
nuclear@0
|
42 @ #define MULTIBOOT int __gba_multiboot;
|
nuclear@0
|
43 @ Then use it like this : MULTIBOOT
|
nuclear@0
|
44 @
|
nuclear@0
|
45 @ IT MUST BE A GLOBAL VARIABLE OR IT WILL NOT WORK!
|
nuclear@0
|
46 @ If this variable is not defined somewhere in your project
|
nuclear@0
|
47 @ then code will be generated to run out of ROM instead of
|
nuclear@0
|
48 @ EXRAM. The value of this variable is not important.
|
nuclear@0
|
49
|
nuclear@0
|
50 .equ __MultiBootInclude, 1
|
nuclear@0
|
51
|
nuclear@0
|
52 @ If you are compiling for multiboot dedicated (will not
|
nuclear@0
|
53 @ run in a cart) code then uncomment the following. Normally
|
nuclear@0
|
54 @ you should leave this commented out so that a multiboot
|
nuclear@0
|
55 @ image will run in a cart as well (by copying from ROM to RAM).
|
nuclear@0
|
56 @
|
nuclear@0
|
57 @ This sets the maker code to "MB " which is a key that
|
nuclear@0
|
58 @ some emulators look for to know to load the rom image
|
nuclear@0
|
59 @ at 0x2000000 instead of the standard 0x8000000.
|
nuclear@0
|
60
|
nuclear@0
|
61 @ .equ __MultibootDedicated, 1
|
nuclear@0
|
62
|
nuclear@0
|
63 @ There are two methods for clearing memory and
|
nuclear@0
|
64 @ copying appropriate setup data. The fast & bulky
|
nuclear@0
|
65 @ method is GBA DMA copy/clear but some emulators
|
nuclear@0
|
66 @ do not accurately do DMA. If you have an inaccurate
|
nuclear@0
|
67 @ emulator or want to conserve ROM space then comment
|
nuclear@0
|
68 @ out the following line. There is not much advantage
|
nuclear@0
|
69 @ gained by doing DMA copy/clear.
|
nuclear@0
|
70
|
nuclear@0
|
71 @ .equ __DMACopyClear, 1
|
nuclear@0
|
72
|
nuclear@0
|
73 @ Uncomment the following line to support C++ development.
|
nuclear@0
|
74 @ You also need to name your main C function the following:
|
nuclear@0
|
75 @ int main (void) ...instead of... int AgbMain (void)
|
nuclear@0
|
76 @ Doing so will cause ~5500 bytes of c++ support code to be
|
nuclear@0
|
77 @ linked in with your project so do not enable c++ support
|
nuclear@0
|
78 @ unless you plan to use it.
|
nuclear@0
|
79
|
nuclear@0
|
80 .equ __CPPSupport, 1
|
nuclear@0
|
81
|
nuclear@0
|
82 @ Comment out the following line to disable interrupt support
|
nuclear@0
|
83 @ in your code and to save some space in this file.
|
nuclear@0
|
84
|
nuclear@0
|
85 @ .equ __InterruptSupport, 1
|
nuclear@0
|
86
|
nuclear@0
|
87
|
nuclear@0
|
88 @ Comment out the following line to put interrupt support in
|
nuclear@0
|
89 @ ROM instead of IWRAM. Interrupt support in ROM will slow
|
nuclear@0
|
90 @ down interrupt execution and has no advantage other than
|
nuclear@0
|
91 @ saving a little bit of IWRAM.
|
nuclear@0
|
92
|
nuclear@0
|
93 .equ __ISRinIWRAM, 1
|
nuclear@0
|
94
|
nuclear@0
|
95 @ NOTE: Only ONE of the following 3 interrupt options may be
|
nuclear@0
|
96 @ uncommented. Also, __InterruptSupport above must be uncommented
|
nuclear@0
|
97 @ for any of the following to have an effect.
|
nuclear@0
|
98 @ If __InterruptSupport is uncommented then you MUST select ONE
|
nuclear@0
|
99 @ AND ONLY ONE of the following 3 interrupt options.
|
nuclear@0
|
100 @
|
nuclear@0
|
101 @ __FastInterrupts
|
nuclear@0
|
102 @ Uncomment this line for minimal interrupt processing.
|
nuclear@0
|
103 @ This allows 160 bytes of interrupt stack space with the
|
nuclear@0
|
104 @ default lnkscript.
|
nuclear@0
|
105 @
|
nuclear@0
|
106 @ __SingleInterrupts
|
nuclear@0
|
107 @ Uncomment this line if you wish to use a table of function
|
nuclear@0
|
108 @ pointers to process specific interrupts. This allows 160
|
nuclear@0
|
109 @ bytes of interrupt stack space with the default lnkscript.
|
nuclear@0
|
110 @
|
nuclear@0
|
111 @ __MultipleInterrupts
|
nuclear@0
|
112 @ Uncomment this line to allow multiple-interrupts-at-once
|
nuclear@0
|
113 @ support. If you have several interrupts where one can
|
nuclear@0
|
114 @ occur while another is being serviced then you need to
|
nuclear@0
|
115 @ enable this option. This option uses the main stack instead
|
nuclear@0
|
116 @ of the interrupt stack so you have access to a larger stack.
|
nuclear@0
|
117
|
nuclear@0
|
118 .equ __FastInterrupts, 1
|
nuclear@0
|
119 @ .equ __SingleInterrupts, 1
|
nuclear@0
|
120 @ .equ __MultipleInterrupts, 1
|
nuclear@0
|
121
|
nuclear@0
|
122
|
nuclear@0
|
123 @ Uncomment the following line to disable sound and enter an
|
nuclear@0
|
124 @ infinite loop if cart is removed during game play. You
|
nuclear@0
|
125 @ must have the cart interrupt enabled for this to work and
|
nuclear@0
|
126 @ __ISRinIWRAM, above, must be enabled (not commented out.)
|
nuclear@0
|
127
|
nuclear@0
|
128 @ .equ __HandleCartInterrupt, 1
|
nuclear@0
|
129
|
nuclear@0
|
130 @ The following prevents IRQ stack overflow by switching to
|
nuclear@0
|
131 @ System mode (User stack) when handling multiple interrupts.
|
nuclear@0
|
132 @ To force use of IRQ stack only, comment out the following line.
|
nuclear@0
|
133
|
nuclear@0
|
134 .equ __SwitchToUserStack, 1
|
nuclear@0
|
135
|
nuclear@0
|
136 @ !!!! NOTE: THE COPY ROUTINES IN THIS FILE WORK ON 4 BYTE
|
nuclear@0
|
137 @ BOUNDARIES. YOUR LINKER SCRIPT MUST ALIGN SECTION STARTS
|
nuclear@0
|
138 @ AND SECTION ENDS FOR SECTIONS THAT GET COPIED TO RAM WITH
|
nuclear@0
|
139 @ ALIGN(4) !!!!
|
nuclear@0
|
140
|
nuclear@0
|
141 .GLOBAL _start
|
nuclear@0
|
142 _start:
|
nuclear@0
|
143 .ALIGN
|
nuclear@0
|
144 .CODE 32
|
nuclear@0
|
145 @ Start Vector
|
nuclear@0
|
146
|
nuclear@0
|
147 b rom_header_end
|
nuclear@0
|
148
|
nuclear@0
|
149 @ Nintendo Logo Character Data (8000004h)
|
nuclear@0
|
150 @ .fill 156,1,0
|
nuclear@0
|
151 .long 0x51aeff24,0x21a29a69,0x0a82843d
|
nuclear@0
|
152 .long 0xad09e484,0x988b2411,0x217f81c0,0x19be52a3
|
nuclear@0
|
153 .long 0x20ce0993,0x4a4a4610,0xec3127f8,0x33e8c758
|
nuclear@0
|
154 .long 0xbfcee382,0x94dff485,0xc1094bce,0xc08a5694
|
nuclear@0
|
155 .long 0xfca77213,0x734d849f,0x619acaa3,0x27a39758
|
nuclear@0
|
156 .long 0x769803fc,0x61c71d23,0x56ae0403,0x008438bf
|
nuclear@0
|
157 .long 0xfd0ea740,0x03fe52ff,0xf130956f,0x85c0fb97
|
nuclear@0
|
158 .long 0x2580d660,0x03be63a9,0xe2384e01,0xff34a2f9
|
nuclear@0
|
159 .long 0x44033ebb,0xcb900078,0x943a1188,0x637cc065
|
nuclear@0
|
160 .long 0xaf3cf087,0x8be425d6,0x72ac0a38,0x07f8d421
|
nuclear@0
|
161
|
nuclear@0
|
162 @ Game Title (80000A0h)
|
nuclear@0
|
163 .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
nuclear@0
|
164 .byte 0x00,0x00,0x00,0x00
|
nuclear@0
|
165
|
nuclear@0
|
166 .ifdef __MultibootDedicated
|
nuclear@0
|
167 @ Game Code (80000ACh)
|
nuclear@0
|
168 .ascii "MB "
|
nuclear@0
|
169 .else
|
nuclear@0
|
170 @ Game Code (80000ACh)
|
nuclear@0
|
171 .byte 0x00,0x00,0x00,0x00
|
nuclear@0
|
172 .endif
|
nuclear@0
|
173
|
nuclear@0
|
174 @ Maker Code (80000B0h)
|
nuclear@0
|
175 .byte 0x30,0x31
|
nuclear@0
|
176
|
nuclear@0
|
177 @ Fixed Value (80000B2h)
|
nuclear@0
|
178 .byte 0x96
|
nuclear@0
|
179
|
nuclear@0
|
180 @ Main Unit Code (80000B3h)
|
nuclear@0
|
181 .byte 0x00
|
nuclear@0
|
182
|
nuclear@0
|
183 @ Device Type (80000B4h)
|
nuclear@0
|
184 .byte 0x00
|
nuclear@0
|
185
|
nuclear@0
|
186 @ Unused Data (7Byte) (80000B5h)
|
nuclear@0
|
187 .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
nuclear@0
|
188
|
nuclear@0
|
189 @ Software Version No (80000BCh)
|
nuclear@0
|
190 .byte 0x00
|
nuclear@0
|
191
|
nuclear@0
|
192 @ Complement Check (80000BDh)
|
nuclear@0
|
193 .byte 0xf0
|
nuclear@0
|
194
|
nuclear@0
|
195 @ Checksum (80000BEh)
|
nuclear@0
|
196 .byte 0x00,0x00
|
nuclear@0
|
197
|
nuclear@0
|
198 .ALIGN
|
nuclear@0
|
199 .ARM @ ..or you can use CODE 32 here
|
nuclear@0
|
200
|
nuclear@0
|
201 rom_header_end:
|
nuclear@0
|
202 b start_vector @ This branch must be here for proper
|
nuclear@0
|
203 @ positioning of the following header.
|
nuclear@0
|
204 @ DO NOT REMOVE IT.
|
nuclear@0
|
205
|
nuclear@0
|
206 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
nuclear@0
|
207 @ The following reserved bytes are used if the code is compiled for @
|
nuclear@0
|
208 @ multiboot mode. It does not hurt anything to leave this header in
|
nuclear@0
|
209 @ even if the code is not compiled for multiboot. The GBA BIOS will
|
nuclear@0
|
210 @ auto-patch the first two bytes with 0x03 and 0x01, respectively,
|
nuclear@0
|
211 @ before running any code if it is executed as multiboot.
|
nuclear@0
|
212 @
|
nuclear@0
|
213
|
nuclear@0
|
214 @ The following two bytes are included even for non-multiboot supporting
|
nuclear@0
|
215 @ builds to guarantee that any generic library code that depends on them
|
nuclear@0
|
216 @ will still be functional.
|
nuclear@0
|
217
|
nuclear@0
|
218 .GLOBAL __boot_method, __slave_number
|
nuclear@0
|
219
|
nuclear@0
|
220 __boot_method:
|
nuclear@0
|
221 .byte 0 @ boot method (0=ROM boot, 3=Multiplay boot)
|
nuclear@0
|
222 __slave_number:
|
nuclear@0
|
223 .byte 0 @ slave # (1=slave#1, 2=slave#2, 3=slave#3)
|
nuclear@0
|
224
|
nuclear@0
|
225 .ifdef __MultiBootInclude
|
nuclear@0
|
226
|
nuclear@0
|
227 .byte 0 @ reserved
|
nuclear@0
|
228 .byte 0 @ reserved
|
nuclear@0
|
229 .word 0 @ reserved
|
nuclear@0
|
230 .word 0 @ reserved
|
nuclear@0
|
231 .word 0 @ reserved
|
nuclear@0
|
232 .word 0 @ reserved
|
nuclear@0
|
233 .word 0 @ reserved
|
nuclear@0
|
234 .word 0 @ reserved
|
nuclear@0
|
235 .endif
|
nuclear@0
|
236 @ @
|
nuclear@0
|
237 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
nuclear@0
|
238
|
nuclear@0
|
239
|
nuclear@0
|
240 @@@@@@@@@@@@@@@@@@@@@@
|
nuclear@0
|
241 @ Reset @
|
nuclear@0
|
242 @@@@@@@@@@@@@@@@@@@@@@
|
nuclear@0
|
243
|
nuclear@0
|
244 .GLOBAL start_vector
|
nuclear@0
|
245 .ALIGN
|
nuclear@0
|
246 .ARM @ ..or you can use CODE 32 here
|
nuclear@0
|
247 start_vector:
|
nuclear@0
|
248 mov r0, #0x12 @ Switch to IRQ Mode
|
nuclear@0
|
249 msr cpsr, r0
|
nuclear@0
|
250 ldr sp,=__sp_irq @ Set SP_irq
|
nuclear@0
|
251 mov r0, #0x1f @ Switch to System Mode
|
nuclear@0
|
252 msr cpsr, r0
|
nuclear@0
|
253 ldr sp,=__sp_usr @ Set SP_usr
|
nuclear@0
|
254
|
nuclear@0
|
255 @ Enter Thumb mode
|
nuclear@0
|
256 adr r0,1f + 1 @ add r0,pc,#1 also works here
|
nuclear@0
|
257 @ for those that want to conserve labels.
|
nuclear@0
|
258 bx r0
|
nuclear@0
|
259
|
nuclear@0
|
260 .THUMB @ ..or you can use .CODE 16 here
|
nuclear@0
|
261 1:
|
nuclear@0
|
262
|
nuclear@0
|
263 .ifdef __InterruptSupport
|
nuclear@0
|
264 ldr r1, =__intr_vector_buf @ Set Interrupt Address
|
nuclear@0
|
265 ldr r0, =intr_main
|
nuclear@0
|
266 str r0, [r1]
|
nuclear@0
|
267 .endif
|
nuclear@0
|
268
|
nuclear@0
|
269 .ifdef __MultiBootInclude
|
nuclear@0
|
270
|
nuclear@0
|
271 @ *** Multiboot Copy Routine ***
|
nuclear@0
|
272 @ Check the Program Counter to see if code is running
|
nuclear@0
|
273 @ at 0x2000000 or 0x8000000. If it is running at 0x8000000
|
nuclear@0
|
274 @ then copy 256K bytes of it to 0x2000000 and then branch
|
nuclear@0
|
275 @ to 0x2000000.
|
nuclear@0
|
276 @ The reason for all this is to allow a program to be used
|
nuclear@0
|
277 @ "as is" with an flash cart/emulator or with an MBV2-style
|
nuclear@0
|
278 @ multiboot cable.
|
nuclear@0
|
279 @ NOTE: You can also detect if this ROM is running from
|
nuclear@0
|
280 @ 0x2000000 by checking the multiboot header above.
|
nuclear@0
|
281
|
nuclear@0
|
282 ldr r0,=__text_start
|
nuclear@0
|
283 lsl r0,#5 @ Was code compiled at 0x08000000 or higher?
|
nuclear@0
|
284 bcs DoEWRAMClear @ yes, you can not run it in external WRAM
|
nuclear@0
|
285
|
nuclear@0
|
286 @ Make sure we are in ExWRAM
|
nuclear@0
|
287
|
nuclear@0
|
288 mov r0,pc
|
nuclear@0
|
289 lsl r0,#5 @ Are we running from ROM (0x8000000 or higher) ?
|
nuclear@0
|
290 bcc SkipEWRAMClear @ No, so no need to do a copy.
|
nuclear@0
|
291
|
nuclear@0
|
292 @ We were started in ROM, silly emulators. :P
|
nuclear@0
|
293 @ So we need to copy to ExWRAM.
|
nuclear@0
|
294
|
nuclear@0
|
295 mov r3,#0x40
|
nuclear@0
|
296 lsl r3,#12 @ r3 = 0x40000
|
nuclear@0
|
297 lsl r2,r3,#7 @ r2 = 0x2000000
|
nuclear@0
|
298 mov r6,r2 @ r6 = 0x2000000
|
nuclear@0
|
299 lsl r1,r2,#2 @ r1 = 0x8000000
|
nuclear@0
|
300
|
nuclear@0
|
301 bl CopyMem
|
nuclear@0
|
302
|
nuclear@0
|
303 @ Jump to the code to execute
|
nuclear@0
|
304
|
nuclear@0
|
305 bx r6
|
nuclear@0
|
306 .endif
|
nuclear@0
|
307
|
nuclear@0
|
308 DoEWRAMClear:
|
nuclear@0
|
309 @ Clear External WRAM to 0x00
|
nuclear@0
|
310
|
nuclear@0
|
311 mov r1,#0x40
|
nuclear@0
|
312 lsl r1,#12 @ r1 = 0x40000
|
nuclear@0
|
313 lsl r0,r1,#7 @ r0 = 0x2000000
|
nuclear@0
|
314 bl ClearMem
|
nuclear@0
|
315
|
nuclear@0
|
316 SkipEWRAMClear:
|
nuclear@0
|
317 @ ldr r0,=AgbMain
|
nuclear@0
|
318 @ bx r0
|
nuclear@0
|
319
|
nuclear@0
|
320 @ Clear Internal WRAM to 0x00
|
nuclear@0
|
321 mov r0,#3
|
nuclear@0
|
322 lsl r0,#24 @ r0 = 0x3000000
|
nuclear@0
|
323 ldr r1,=__sp_usr_offset - 16
|
nuclear@0
|
324 bl ClearMem
|
nuclear@0
|
325
|
nuclear@0
|
326 .ifdef __MultiBootInclude
|
nuclear@0
|
327 @ Clear BSS section to 0x00
|
nuclear@0
|
328 @ (Sometimes BSS may be in External WRAM)
|
nuclear@0
|
329 ldr r0,=__bss_start
|
nuclear@0
|
330 ldr r1,=__bss_end
|
nuclear@0
|
331 sub r1,r0
|
nuclear@0
|
332 bl ClearMem
|
nuclear@0
|
333 .endif
|
nuclear@0
|
334
|
nuclear@0
|
335 @ Copy initialized data (data section) from LMA to VMA (ROM to RAM)
|
nuclear@0
|
336 ldr r1,=__data_lma
|
nuclear@0
|
337 ldr r2,=__data_start
|
nuclear@0
|
338 ldr r4,=__data_end
|
nuclear@0
|
339 bl CopyMemChk
|
nuclear@0
|
340
|
nuclear@0
|
341 @ Copy internal work ram (iwram section) from LMA to VMA (ROM to RAM)
|
nuclear@0
|
342 ldr r1,=__iwram_lma
|
nuclear@0
|
343 ldr r2,=__iwram_start
|
nuclear@0
|
344 ldr r4,=__iwram_end
|
nuclear@0
|
345 bl CopyMemChk
|
nuclear@0
|
346
|
nuclear@0
|
347 @ Copy internal work ram overlay 0 (iwram0 section) from LMA to VMA (ROM to RAM)
|
nuclear@0
|
348 ldr r2,=__load_stop_iwram0
|
nuclear@0
|
349 ldr r1,=__load_start_iwram0
|
nuclear@0
|
350 sub r3,r2,r1 @ Is there any data to copy?
|
nuclear@0
|
351 beq CIW0Skip @ no
|
nuclear@0
|
352
|
nuclear@0
|
353 ldr r2,=__iwram_overlay_start
|
nuclear@0
|
354 bl CopyMem
|
nuclear@0
|
355 CIW0Skip:
|
nuclear@0
|
356
|
nuclear@0
|
357 @ Copy external work ram (ewram section) from LMA to VMA (ROM to RAM)
|
nuclear@0
|
358 ldr r1,=__ewram_lma
|
nuclear@0
|
359 ldr r2,=__ewram_start
|
nuclear@0
|
360 ldr r4,=__ewram_end
|
nuclear@0
|
361 bl CopyMemChk
|
nuclear@0
|
362
|
nuclear@0
|
363 @ Copy external work ram overlay 0 (ewram0 section) from LMA to VMA (ROM to RAM)
|
nuclear@0
|
364 ldr r2,=__load_stop_ewram0
|
nuclear@0
|
365 ldr r1,=__load_start_ewram0
|
nuclear@0
|
366 sub r3,r2,r1 @ Is there any data to copy?
|
nuclear@0
|
367 beq CEW0Skip @ no
|
nuclear@0
|
368
|
nuclear@0
|
369 ldr r2,=__ewram_overlay_start
|
nuclear@0
|
370 bl CopyMem
|
nuclear@0
|
371 CEW0Skip:
|
nuclear@0
|
372
|
nuclear@0
|
373 @ Jump to user code
|
nuclear@0
|
374
|
nuclear@0
|
375 mov r0,#0 @ int argc
|
nuclear@0
|
376 mov r1,#0 @ char *argv[]
|
nuclear@0
|
377
|
nuclear@0
|
378 ldr r3,=start_vector
|
nuclear@0
|
379 mov lr,r3 @ Set start_vector as return address
|
nuclear@0
|
380
|
nuclear@0
|
381 .ifdef __CPPSupport
|
nuclear@0
|
382 ldr r3,=main
|
nuclear@0
|
383 .else
|
nuclear@0
|
384 ldr r3,=AgbMain
|
nuclear@0
|
385 .endif
|
nuclear@0
|
386 bx r3
|
nuclear@0
|
387
|
nuclear@0
|
388
|
nuclear@0
|
389 .GLOBAL __FarFunction,__FarProcedure
|
nuclear@0
|
390 .THUMB_FUNC
|
nuclear@0
|
391 __FarFunction:
|
nuclear@0
|
392 .THUMB_FUNC
|
nuclear@0
|
393 __FarProcedure:
|
nuclear@0
|
394 bx r0
|
nuclear@0
|
395 nop
|
nuclear@0
|
396 nop @ This nop is here to allow unmapped memory to be used as
|
nuclear@0
|
397 @ as a delay of almost 1 sec with a 1 cycle resolution.
|
nuclear@0
|
398 @ Read this for technical info:
|
nuclear@0
|
399 @ http://www.devrs.com/gba/files/gbadevfaqs.php#RepeatUses
|
nuclear@0
|
400
|
nuclear@0
|
401 @ Clear memory to 0x00 if length != 0
|
nuclear@0
|
402 @ r0 = Start Address
|
nuclear@0
|
403 @ r1 = Length
|
nuclear@0
|
404
|
nuclear@0
|
405 ClearMem:
|
nuclear@0
|
406 @ cmp r1,#0 @ Is length zero?
|
nuclear@0
|
407 @ beq ClearMX @ yes, exit
|
nuclear@0
|
408
|
nuclear@0
|
409 mov r2,#3 @ These commands are used in cases where
|
nuclear@0
|
410 add r1,r2 @ the length is not a multiple of 4,
|
nuclear@0
|
411 bic r1,r2 @ even though it should be.
|
nuclear@0
|
412
|
nuclear@0
|
413 beq ClearMX @ Length is zero so exit
|
nuclear@0
|
414
|
nuclear@0
|
415 .ifdef __DMACopyClear
|
nuclear@0
|
416 ldr r2,reg_base
|
nuclear@0
|
417 lsr r1,#2 @ r1 = (length/4) & 0xffff
|
nuclear@0
|
418
|
nuclear@0
|
419 adr r3,fill_val
|
nuclear@0
|
420 str r3,[r2,#0x4] @ Set source address (fill value)
|
nuclear@0
|
421 str r0,[r2,#0x8] @ Set destination address (fill dest address)
|
nuclear@0
|
422 strh r1,[r2,#0xc] @ Set DMA length
|
nuclear@0
|
423 ldr r1,=0x8500 @ dma_clrb
|
nuclear@0
|
424 strh r1,[r2,#0xe] @ Start DMA
|
nuclear@0
|
425 .else
|
nuclear@0
|
426 mov r2,#0
|
nuclear@0
|
427 ClrLoop:
|
nuclear@0
|
428 stmia r0!,{r2}
|
nuclear@0
|
429 sub r1,#4
|
nuclear@0
|
430 bne ClrLoop
|
nuclear@0
|
431 .endif
|
nuclear@0
|
432 ClearMX:
|
nuclear@0
|
433 bx lr
|
nuclear@0
|
434
|
nuclear@0
|
435 @ Copy memory if length != 0
|
nuclear@0
|
436 @ r1 = Source Address
|
nuclear@0
|
437 @ r2 = Dest Address
|
nuclear@0
|
438 @ r4 = Dest Address + Length
|
nuclear@0
|
439
|
nuclear@0
|
440 CopyMemChk:
|
nuclear@0
|
441 sub r3,r4,r2 @ Is there any data to copy?
|
nuclear@0
|
442 @ beq CIDExit @ no
|
nuclear@0
|
443
|
nuclear@0
|
444 @ Copy memory
|
nuclear@0
|
445 @ r1 = Source Address
|
nuclear@0
|
446 @ r2 = Dest Address
|
nuclear@0
|
447 @ r3 = Length
|
nuclear@0
|
448
|
nuclear@0
|
449 CopyMem:
|
nuclear@0
|
450 mov r0,#3 @ These commands are used in cases where
|
nuclear@0
|
451 add r3,r0 @ the length is not a multiple of 4,
|
nuclear@0
|
452 bic r3,r0 @ even though it should be.
|
nuclear@0
|
453
|
nuclear@0
|
454 beq CIDExit @ Length is zero so exit
|
nuclear@0
|
455
|
nuclear@0
|
456 .ifdef __DMACopyClear
|
nuclear@0
|
457 ldr r0,reg_base
|
nuclear@0
|
458 lsr r3,#2 @ r3 = (length/4) & 0xffff
|
nuclear@0
|
459
|
nuclear@0
|
460 str r1,[r0,#0x4] @ Set source address
|
nuclear@0
|
461 str r2,[r0,#0x8] @ Set destination address
|
nuclear@0
|
462 strh r3,[r0,#0xc] @ Set DMA length
|
nuclear@0
|
463 ldr r3,=0x8400 @ dma_copy
|
nuclear@0
|
464 strh r3,[r0,#0xe] @ Start DMA
|
nuclear@0
|
465 .else
|
nuclear@0
|
466 CIDLoop:
|
nuclear@0
|
467 ldmia r1!,{r0}
|
nuclear@0
|
468 stmia r2!,{r0}
|
nuclear@0
|
469 sub r3,#4
|
nuclear@0
|
470 bne CIDLoop
|
nuclear@0
|
471 .endif
|
nuclear@0
|
472 CIDExit:
|
nuclear@0
|
473 If_Undefined_Reference__rename_main_or_AgbMain_to_each_other_in_your_C_file:
|
nuclear@0
|
474 bx lr
|
nuclear@0
|
475
|
nuclear@0
|
476 .ALIGN
|
nuclear@0
|
477
|
nuclear@0
|
478 .ifdef __DMACopyClear
|
nuclear@0
|
479 fill_val: .word 0
|
nuclear@0
|
480 reg_base: .word 0x040000d0
|
nuclear@0
|
481 .endif
|
nuclear@0
|
482
|
nuclear@0
|
483 .ALIGN
|
nuclear@0
|
484 .POOL
|
nuclear@0
|
485
|
nuclear@0
|
486 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
nuclear@0
|
487 @ Interrupt Processing @
|
nuclear@0
|
488 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
nuclear@0
|
489
|
nuclear@0
|
490 .ifdef __ISRinIWRAM
|
nuclear@0
|
491 .SECTION .iwram,"ax",%progbits
|
nuclear@0
|
492 .endif
|
nuclear@0
|
493
|
nuclear@0
|
494 .EXTERN IntrTable
|
nuclear@0
|
495 .EXTERN InterruptProcess
|
nuclear@0
|
496 .GLOBAL intr_main
|
nuclear@0
|
497 .ALIGN
|
nuclear@0
|
498 .ARM
|
nuclear@0
|
499
|
nuclear@0
|
500 @ NOTE: Ifyou copy the following code (start: intr_main -
|
nuclear@0
|
501 @ end: intr_main_end) to internal WRAM then do not forget
|
nuclear@0
|
502 @ to copy everything between these two labels. The .POOL
|
nuclear@0
|
503 @ data must be copied since it is used by intr_main.
|
nuclear@0
|
504
|
nuclear@0
|
505 @ NOTE2: If __ISRinIWRAM is defined then the copy to
|
nuclear@0
|
506 @ IWRAM is done automatically for you.
|
nuclear@0
|
507
|
nuclear@0
|
508 .ifdef __InterruptSupport
|
nuclear@0
|
509
|
nuclear@0
|
510 .ifdef __FastInterrupts
|
nuclear@0
|
511 intr_main:
|
nuclear@0
|
512 ldr r0,=InterruptProcess
|
nuclear@0
|
513 bx r0
|
nuclear@0
|
514 .endif
|
nuclear@0
|
515
|
nuclear@0
|
516 .ifdef __SingleInterrupts
|
nuclear@0
|
517 intr_main:
|
nuclear@0
|
518 @ Single interrupts support
|
nuclear@0
|
519 mov r3, #0x4000000 @ REG_BASE
|
nuclear@0
|
520 ldr r2, [r3,#0x200]! @ Read REG_IE
|
nuclear@0
|
521 and r1, r2, r2, lsr #16 @ r1 = IE & IF
|
nuclear@0
|
522 ldr r2, =IntrTable
|
nuclear@0
|
523
|
nuclear@0
|
524 ands r0, r1, #1 @ V-Blank Interrupt
|
nuclear@0
|
525 bne jump_intr
|
nuclear@0
|
526 add r2, r2, #4
|
nuclear@0
|
527 ands r0, r1, #2 @ H-Blank Interrupt
|
nuclear@0
|
528 bne jump_intr
|
nuclear@0
|
529 add r2, r2, #4
|
nuclear@0
|
530 ands r0, r1, #4 @ V Counter Interrupt
|
nuclear@0
|
531 bne jump_intr
|
nuclear@0
|
532 add r2, r2, #4
|
nuclear@0
|
533 ands r0, r1, #8 @ Timer 0 Interrupt
|
nuclear@0
|
534 bne jump_intr
|
nuclear@0
|
535 add r2, r2, #4
|
nuclear@0
|
536 ands r0, r1, #0x10 @ Timer 1 Interrupt
|
nuclear@0
|
537 bne jump_intr
|
nuclear@0
|
538 add r2, r2, #4
|
nuclear@0
|
539 ands r0, r1, #0x20 @ Timer 2 Interrupt
|
nuclear@0
|
540 bne jump_intr
|
nuclear@0
|
541 add r2, r2, #4
|
nuclear@0
|
542 ands r0, r1, #0x40 @ Timer 3 Interrupt
|
nuclear@0
|
543 bne jump_intr
|
nuclear@0
|
544 add r2, r2, #4
|
nuclear@0
|
545 ands r0, r1, #0x80 @ Serial Communication Interrupt
|
nuclear@0
|
546 bne jump_intr
|
nuclear@0
|
547 add r2, r2, #4
|
nuclear@0
|
548 ands r0, r1, #0x100 @ DMA0 Interrupt
|
nuclear@0
|
549 bne jump_intr
|
nuclear@0
|
550 add r2, r2, #4
|
nuclear@0
|
551 ands r0, r1, #0x200 @ DMA1 Interrupt
|
nuclear@0
|
552 bne jump_intr
|
nuclear@0
|
553 add r2, r2, #4
|
nuclear@0
|
554 ands r0, r1, #0x400 @ DMA2 Interrupt
|
nuclear@0
|
555 bne jump_intr
|
nuclear@0
|
556 add r2, r2, #4
|
nuclear@0
|
557 ands r0, r1, #0x800 @ DMA3 Interrupt
|
nuclear@0
|
558 bne jump_intr
|
nuclear@0
|
559 add r2, r2, #4
|
nuclear@0
|
560 ands r0, r1, #0x1000 @ Key Interrupt
|
nuclear@0
|
561 bne jump_intr
|
nuclear@0
|
562 add r2, r2, #4
|
nuclear@0
|
563 ands r0, r1, #0x2000 @ Cart Interrupt
|
nuclear@0
|
564
|
nuclear@0
|
565 .ifdef __HandleCartInterrupt
|
nuclear@0
|
566 strneb r0, [r3, #0x84 - 0x200] @ Stop sound if cart removed (REG_SOUNDCNT_X)
|
nuclear@0
|
567 loop: bne loop @ Infinite loop if cart removed
|
nuclear@0
|
568 .endif
|
nuclear@0
|
569
|
nuclear@0
|
570 jump_intr:
|
nuclear@0
|
571 strh r0, [r3, #2] @ IF Clear
|
nuclear@0
|
572 ldr r0, [r2] @ Jump to user IRQ process
|
nuclear@0
|
573 bx r0
|
nuclear@0
|
574 .endif
|
nuclear@0
|
575
|
nuclear@0
|
576 .ifdef __MultipleInterrupts
|
nuclear@0
|
577 intr_main:
|
nuclear@0
|
578 @ Multiple interrupts support
|
nuclear@0
|
579 mov r2, #0x4000000 @ REG_BASE
|
nuclear@0
|
580 ldr r3, [r2,#0x200]! @ r2 = IE : r3 = IF|IE
|
nuclear@0
|
581 ldrh r1, [r2, #0x8] @ r1 = IME
|
nuclear@0
|
582 mrs r0, spsr
|
nuclear@0
|
583 stmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} // IF|IE
|
nuclear@0
|
584
|
nuclear@0
|
585 mov r0, #1 @ IME = 1 (To permit multiple interrupts if
|
nuclear@0
|
586 @ an interrupt occurs)
|
nuclear@0
|
587 strh r0, [r2, #0x8]
|
nuclear@0
|
588 and r1, r3, r3, lsr #16 @ r1 = IE & IF
|
nuclear@0
|
589 ldr r12, =IntrTable
|
nuclear@0
|
590
|
nuclear@0
|
591 ands r0, r1, #1 @ V-blank interrupt
|
nuclear@0
|
592 bne jump_intr
|
nuclear@0
|
593 add r12,r12, #4
|
nuclear@0
|
594 ands r0, r1, #2 @ H-blank interrupt
|
nuclear@0
|
595 bne jump_intr
|
nuclear@0
|
596 add r12,r12, #4
|
nuclear@0
|
597 ands r0, r1, #4 @ V-counter interrupt
|
nuclear@0
|
598 bne jump_intr
|
nuclear@0
|
599 add r12,r12, #4
|
nuclear@0
|
600 ands r0, r1, #8 @ Timer 0 interrupt
|
nuclear@0
|
601 bne jump_intr
|
nuclear@0
|
602 add r12,r12, #4
|
nuclear@0
|
603 ands r0, r1, #0x10 @ Timer 1 interrupt
|
nuclear@0
|
604 bne jump_intr
|
nuclear@0
|
605 add r12,r12, #4
|
nuclear@0
|
606 ands r0, r1, #0x20 @ Timer 2 interrupt
|
nuclear@0
|
607 bne jump_intr
|
nuclear@0
|
608 add r12,r12, #4
|
nuclear@0
|
609 ands r0, r1, #0x40 @ Timer 3 interrupt
|
nuclear@0
|
610 bne jump_intr
|
nuclear@0
|
611 add r12,r12, #4
|
nuclear@0
|
612 ands r0, r1, #0x80 @ Serial Communication Interrupt
|
nuclear@0
|
613 bne jump_intr
|
nuclear@0
|
614 add r12,r12, #4
|
nuclear@0
|
615 ands r0, r1, #0x100 @ DMA 0 interrupt
|
nuclear@0
|
616 bne jump_intr
|
nuclear@0
|
617 add r12,r12, #4
|
nuclear@0
|
618 ands r0, r1, #0x200 @ DMA 1 interrupt
|
nuclear@0
|
619 bne jump_intr
|
nuclear@0
|
620 add r12,r12, #4
|
nuclear@0
|
621 ands r0, r1, #0x400 @ DMA 2 interrupt
|
nuclear@0
|
622 bne jump_intr
|
nuclear@0
|
623 add r12,r12, #4
|
nuclear@0
|
624 ands r0, r1, #0x800 @ DMA 3 interrupt
|
nuclear@0
|
625 bne jump_intr
|
nuclear@0
|
626 add r12,r12, #4
|
nuclear@0
|
627 ands r0, r1, #0x1000 @ Key interrupt
|
nuclear@0
|
628 bne jump_intr
|
nuclear@0
|
629 add r12,r12, #4
|
nuclear@0
|
630 ands r0, r1, #0x2000 @ Cart interrupt
|
nuclear@0
|
631
|
nuclear@0
|
632 .ifdef __HandleCartInterrupt
|
nuclear@0
|
633 strneb r0, [r2, #0x84 - 0x200] @ Stop sound if cart removed (REG_SOUNDCNT_X)
|
nuclear@0
|
634 loop: bne loop @ Infinite loop if cart removed
|
nuclear@0
|
635 .endif
|
nuclear@0
|
636
|
nuclear@0
|
637 jump_intr:
|
nuclear@0
|
638 strh r0, [r2, #2] @ Clear IF
|
nuclear@0
|
639
|
nuclear@0
|
640 @ Enable multiple interrupts & switch to system
|
nuclear@0
|
641 @ mode if __SwitchToUserStack is defined.
|
nuclear@0
|
642
|
nuclear@0
|
643 mrs r3, cpsr
|
nuclear@0
|
644 .ifdef __SwitchToUserStack
|
nuclear@0
|
645 bic r3, r3, #0xdf @ \__
|
nuclear@0
|
646 orr r3, r3, #0x1f @ / --> Enable IRQ & FIQ. Set CPU mode to System.
|
nuclear@0
|
647 .else
|
nuclear@0
|
648 bic r3, r3, #0xc0 @ Enable IRQ & FIQ
|
nuclear@0
|
649 .endif
|
nuclear@0
|
650 msr cpsr, r3
|
nuclear@0
|
651
|
nuclear@0
|
652 ldr r0, [r12]
|
nuclear@0
|
653
|
nuclear@0
|
654 stmfd sp!, {lr}
|
nuclear@0
|
655 adr lr, IntrRet
|
nuclear@0
|
656 bx r0
|
nuclear@0
|
657 IntrRet:
|
nuclear@0
|
658 ldmfd sp!, {lr}
|
nuclear@0
|
659
|
nuclear@0
|
660 @ Disable multiple interrupts & switch to IRQ Mode
|
nuclear@0
|
661 @ if __SwitchToUserStack is defined.
|
nuclear@0
|
662
|
nuclear@0
|
663 mrs r3, cpsr
|
nuclear@0
|
664 .ifdef __SwitchToUserStack
|
nuclear@0
|
665 bic r3, r3, #0xdf @ \__
|
nuclear@0
|
666 orr r3, r3, #0x92 @ / --> Disable IRQ. Enable FIQ. Set CPU mode to IRQ.
|
nuclear@0
|
667 .else
|
nuclear@0
|
668 orr r3, r3, #0x80 @ Disable IRQ.
|
nuclear@0
|
669 .endif
|
nuclear@0
|
670 msr cpsr, r3
|
nuclear@0
|
671
|
nuclear@0
|
672 ldmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} //IF|IE
|
nuclear@0
|
673 @ strh r3, [r2] @ set IE
|
nuclear@0
|
674 strh r1, [r2, #0x8] @ restore REG_IME
|
nuclear@0
|
675 msr spsr, r0 @ restore spsr
|
nuclear@0
|
676 bx lr
|
nuclear@0
|
677
|
nuclear@0
|
678 .endif
|
nuclear@0
|
679
|
nuclear@0
|
680 .ALIGN
|
nuclear@0
|
681 .POOL @ Ifyou copy the intr_main routine, above, to internal
|
nuclear@0
|
682 @ RAM then copy the pool data as well because IntrTable
|
nuclear@0
|
683 @ address is stored here. Use intr_main_end as last address+1.
|
nuclear@0
|
684 intr_main_end:
|
nuclear@0
|
685 .endif
|
nuclear@0
|
686
|
nuclear@0
|
687 .ALIGN
|
nuclear@0
|
688 .POOL
|
nuclear@0
|
689
|
nuclear@0
|
690
|
nuclear@0
|
691 .END
|
nuclear@0
|
692
|