gbasys

annotate samples/fonts/crt0.s @ 0:875ef6085efc

gbasys mercurial repository
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 04 Mar 2012 04:04:25 +0200
parents
children
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