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