original source from gpsp09-2xb_src.tar.bz2
[gpsp.git] / psp / mips_stub.S
1 # gameplaySP
2 #
3 # Copyright (C) 2006 Exophase <exophase@gmail.com>
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License as
7 # published by the Free Software Foundation; either version 2 of
8 # the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19 .align 4
20
21 .global mips_update_gba
22 .global mips_indirect_branch_arm
23 .global mips_indirect_branch_thumb
24 .global mips_indirect_branch_dual
25 .global execute_load_u8
26 .global execute_load_u16
27 .global execute_load_u32
28 .global execute_load_s8
29 .global execute_load_s16
30 .global execute_store_u8
31 .global execute_store_u16
32 .global execute_store_u32
33 .global execute_aligned_load32
34 .global execute_aligned_store32
35 .global execute_read_cpsr
36 .global execute_read_spsr
37 .global execute_swi
38 .global execute_spsr_restore
39 .global execute_store_cpsr
40 .global execute_store_spsr
41 .global execute_lsl_flags_reg
42 .global execute_lsr_flags_reg
43 .global execute_asr_flags_reg
44 .global execute_ror_flags_reg
45 .global execute_arm_translate
46 .global invalidate_icache_region
47 .global invalidate_all_cache
48 .global step_debug_mips
49 .global reg_check
50
51 .global memory_map_read
52 .global memory_map_write
53 .global reg
54
55 .extern reg
56 .extern spsr
57
58 # MIPS register layout:
59
60 # $0 - constant zero
61 # $1 - temporary
62 # $2 - temporary / return value
63 # $3 - ARM r0 (not saved)
64 # $4 - temporary / function argument 0
65 # $5 - temporary / function argument 1
66 # $6 - temporary / function argument 2
67 # $7 - ARM r1 (not saved)
68 # $8 - ARM r2 (not saved)
69 # $9 - ARM r3 (not saved)
70 # $10 - ARM r4 (not saved)
71 # $11 - ARM r5 (not saved)
72 # $12 - ARM r6 (not saved)
73 # $13 - ARM r7 (not saved)
74 # $14 - ARM r8 (not saved)
75 # $15 - ARM r9 (not saved)
76 # $16 - ARM machine state pointer (saved)
77 # $17 - cycle counter (saved)
78 # $18 - ARM r10 (saved)
79 # $19 - block start address (roughly r15) (saved)
80 # $20 - ARM negative register (saved)
81 # $21 - ARM zero register (saved)
82 # $22 - ARM carry register (saved)
83 # $23 - ARM overflow register (saved)
84 # $24 - ARM r11 (not saved)
85 # $25 - ARM r12 (not saved)
86 # $26 - kernel temporary 0
87 # $27 - kernel temporary 1
88 # $28 - ARM r13 (saved)
89 # $29 - stack pointer
90 # $30 - ARM r14 (saved)
91 # $31 - return address
92
93 .equ REG_R0,              (0 * 4)
94 .equ REG_R1,              (1 * 4)
95 .equ REG_R2,              (2 * 4)
96 .equ REG_R3,              (3 * 4)
97 .equ REG_R4,              (4 * 4)
98 .equ REG_R5,              (5 * 4)
99 .equ REG_R6,              (6 * 4)
100 .equ REG_R7,              (7 * 4)
101 .equ REG_R8,              (8 * 4)
102 .equ REG_R9,              (9 * 4)
103 .equ REG_R10,             (10 * 4)
104 .equ REG_R11,             (11 * 4)
105 .equ REG_R12,             (12 * 4)
106 .equ REG_R13,             (13 * 4)
107 .equ REG_R14,             (14 * 4)
108 .equ REG_LR,              (14 * 4)
109 .equ REG_PC,              (15 * 4)
110 .equ REG_N_FLAG,          (16 * 4)
111 .equ REG_Z_FLAG,          (17 * 4)
112 .equ REG_C_FLAG,          (18 * 4)
113 .equ REG_V_FLAG,          (19 * 4)
114 .equ REG_CPSR,            (20 * 4)
115 .equ REG_SAVE,            (21 * 4)
116 .equ REG_SAVE2,           (22 * 4)
117 .equ REG_SAVE3,           (23 * 4)
118 .equ CPU_MODE,            (29 * 4)
119 .equ CPU_HALT_STATE,      (30 * 4)
120 .equ CHANGED_PC_STATUS,   (31 * 4)
121 .equ GP_SAVE,             (32 * 4)
122
123 .equ SUPERVISOR_LR,       (reg_mode + (3 * (7 * 4)) + (6 * 4))
124 .equ SUPERVISOR_SPSR,     (spsr + (3 * 4))
125
126 .set noat
127 .set noreorder
128
129 # make sure $16 has the register base for these macros
130
131 .macro collapse_flag flag_reg, shift
132   ins $2, $\flag_reg, \shift, 1    # insert flag into CPSR
133 .endm
134
135 .macro collapse_flags
136   lw $2, REG_CPSR($16)            # load CPSR
137   andi $2, $2, 0xFF               # isolate lower 8bits
138   collapse_flag 20, 31            # store flags
139   collapse_flag 21, 30
140   collapse_flag 22, 29
141   collapse_flag 23, 28
142   sw $2, REG_CPSR($16)            # store CPSR
143 .endm
144
145 .macro extract_flag shift, flag_reg
146   ext $\flag_reg, $1, \shift, 1   # extract flag from CPSR
147 .endm
148
149 .macro extract_flags_body         # extract flags from $1
150   extract_flag 31, 20             # load flags
151   extract_flag 30, 21
152   extract_flag 29, 22
153   extract_flag 28, 23
154 .endm
155
156 .macro extract_flags
157   lw $1, REG_CPSR($16)            # load CPSR
158   extract_flags_body
159 .endm
160
161 .macro save_registers
162   sw $3, REG_R0($16)
163   sw $7, REG_R1($16)
164   sw $8, REG_R2($16)
165   sw $9, REG_R3($16)
166   sw $10, REG_R4($16)
167   sw $11, REG_R5($16)
168   sw $12, REG_R6($16)
169   sw $13, REG_R7($16)
170   sw $14, REG_R8($16)
171   sw $15, REG_R9($16)
172   sw $24, REG_R11($16)
173   sw $25, REG_R12($16)
174
175   sw $18, REG_R10($16)
176   sw $28, REG_R13($16)
177   sw $30, REG_R14($16)
178
179   lw $28, GP_SAVE($16)
180 .endm
181
182 .macro restore_registers
183   lw $3, REG_R0($16)
184   lw $7, REG_R1($16)
185   lw $8, REG_R2($16)
186   lw $9, REG_R3($16)
187   lw $10, REG_R4($16)
188   lw $11, REG_R5($16)
189   lw $12, REG_R6($16)
190   lw $13, REG_R7($16)
191   lw $14, REG_R8($16)
192   lw $15, REG_R9($16)
193   lw $24, REG_R11($16)
194   lw $25, REG_R12($16)
195
196   lw $18, REG_R10($16)
197   lw $28, REG_R13($16)
198   lw $30, REG_R14($16)
199 .endm
200
201 # Process a hardware event. Since an interrupt might be
202 # raised we have to check if the PC has changed.
203
204 # $4: next address
205 # $16: register base
206 # $17: cycle counter
207
208 .balign 64
209
210 mips_update_gba:
211   sw $4, REG_PC($16)              # current PC = $4
212
213   addiu $sp, $sp, -4              # make room on the stack
214   sw $ra,($sp)                    # save return address
215   collapse_flags                  # update cpsr
216   save_registers                  # save registers
217   jal update_gba                  # process the next event
218   sw $0, CHANGED_PC_STATUS($16)
219
220   lw $ra, ($sp)                   # restore return address
221   addiu $sp, $sp, 4               # fix stack
222
223   lw $1, CHANGED_PC_STATUS($16)
224   bne $1, $0, lookup_pc
225   addu $17, $2, $0                # $17 = new cycle count (delay slot)
226
227   restore_registers
228
229   jr $ra                          # if not, go back to caller
230   nop
231
232 # Perform an indirect branch.
233
234 # $4: GBA address to branch to
235
236 mips_indirect_branch_arm:
237   save_registers
238   jal block_lookup_address_arm    # $2 = MIPS address to jump to
239   nop
240   restore_registers
241   jr $2                           # jump to it
242   nop
243
244 mips_indirect_branch_thumb:
245   save_registers
246   jal block_lookup_address_thumb  # $2 = MIPS address to jump to
247   nop
248   restore_registers
249   jr $2                           # jump to it
250   nop
251
252 mips_indirect_branch_dual:
253   save_registers
254   jal block_lookup_address_dual   # $2 = MIPS address to jump to
255   nop
256   restore_registers
257   jr $2                           # jump to it
258   nop
259
260
261 # $4: address to write to
262 # $5: current PC
263
264 # Will patch the return address with a call to the correct handler as
265 # listed in the given table.
266
267 # Value will be set to force_open if it's open
268
269 .macro patch_handler ftable, force_open
270   srl $1, $4, 24                  # $1 = address region
271   sltu $2, $1, 0x0F               # check if the value is open
272   bne $2, $0, 1f
273   sll $1, $1, 2                   # make address word indexed (delay)
274
275   addiu $1, $0, (\force_open * 4)
276
277 1:
278   lui $2, %hi(\ftable)
279   addu $2, $2, $1
280   lw $2, %lo(\ftable)($2)         # new function handler is in $2
281   srl $2, $2, 2                   # remove lower two bits
282
283   lui $1, %hi(3 << 26)            # $1 = 3 (JAL opcode)
284   ins $1, $2, 0, 26               # insert offset into jal
285
286   addiu $ra, $ra, -8              # rewind return address to function call
287   sw $1, ($ra)                    # modify to call new handler
288
289   cache 0x1a, ($ra)               # hit writeback dcache line
290   cache 0x08, ($ra)               # hit invalidate icache line
291
292   jr $ra                          # return
293   nop                             # wary of putting cache here
294 .endm
295
296
297 # Like the above, but will use the table of the proper alignment,
298 # The tables should be ordered by alignment
299
300 .macro patch_handler_align ftable, alignment
301   srl $1, $4, 24                  # $1 = address region
302   sltu $2, $1, 0x0F               # check if the value is open
303   bne $2, $0, 1f
304   sll $1, $1, 2                   # make address word indexed (delay)
305
306   addiu $1, $0, 4                 # force address to 0x1 (open)
307
308 1:
309   ins $1, $4, 6, \alignment       # place alignment bits into offset
310   lui $2, %hi(\ftable)
311
312   addu $2, $2, $1
313   lw $2, %lo(\ftable)($2)         # new function handler is in $2
314
315   srl $2, $2, 2                   # remove lower two bits
316
317   lui $1, %hi(3 << 26)            # $1 = 3 (JAL opcode)
318   ins $1, $2, 0, 26               # insert offset into jal
319
320   addiu $ra, $ra, -8              # rewind return address to function call
321   sw $1, ($ra)                    # modify to call new handler
322
323   cache 0x1a, ($ra)               # hit writeback dcache line
324   cache 0x08, ($ra)               # hit invalidate icache line
325
326   jr $ra                          # return
327   nop                             # wary of putting cache here
328 .endm
329
330
331 .macro region_check region, patch_handler
332   srl $1, $4, 24                  # check upper 8bits of address
333   xor $1, $1, \region             # see if it is the given region
334   bne $1, $0, \patch_handler      # if not repatch/try again
335 .endm
336
337 .macro region_check_open patch_handler
338   srl $1, $4, 24                  # check upper 8bits of address
339   sltiu $2, $1, 0x0F              # true if it is a low address
340   addiu $1, $1, -1                # non-zero if it is not a low open
341   sltu $1, $0, $1                 # true if lower bits != 1
342   and $1, $1, $2                  # true if low address and not open
343   bne $1, $0, \patch_handler      # if above is true, patch
344 .endm
345
346
347 .macro region_check_align region, align_bits, alignment, patch_handler
348   srl $1, $4, 24                  # check upper 8bits of address
349   ins $1, $4, 8, \align_bits      # look at lower bits of address too
350   # See if it is the given region and alignment
351   xori $1, $1, (\region | (\alignment << 8))
352   bne $1, $0, \patch_handler      # if not repatch/try again
353 .endm
354
355 .macro region_check_open_align align_bits, alignment, patch_handler
356   srl $1, $4, 24                  # check upper 8bits of address
357   sltiu $2, $1, 0x0F              # true if it is a low address
358   addiu $1, $1, -1                # non-zero if it is not a low open
359   sltu $1, $0, $1                 # true if $1 != 0
360   and $1, $1, $2                  # true if low address and not open
361   ext $2, $4, 0, \align_bits      # $2 = low bits of 4
362   xori $2, $2, \alignment         # true if alignment doesn't match
363   or $1, $1, $2                   # align failure will trigger too
364   bne $1, $0, \patch_handler      # if above is true, patch
365 .endm
366
367
368 .macro ignore_region region, patch_handler
369   region_check \region, \patch_handler
370   nop
371   jr $ra
372   nop
373 .endm
374
375 .macro ignore_high patch_handler
376   srl $1, $4, 24                  # check upper 8bits of address
377   sltiu $1, $1, 0x0F              # see if it is not high
378   bne $1, $0, \patch_handler      # if not repatch/try again
379   nop
380   jr $ra
381   nop
382 .endm
383
384
385 .macro translate_region_core base, size
386   lui $2, %hi(\base)              # generate upper address
387   andi $4, $4, \size              # generate offset
388   addu $2, $2, $4                 # add ptr upper and offset
389 .endm
390
391 .macro translate_region region, patch_handler, base, size
392   region_check \region, \patch_handler
393   translate_region_core \base, \size
394 .endm
395
396 # I refuse to have > 80 char lines, and GAS has a problem with the param
397 # list spilling over (grumble)
398
399 .macro translate_region_align region, a_b, alignment, p_h, base, size
400   region_check_align \region, \a_b, \alignment, \p_h
401   translate_region_core \base, \size
402 .endm
403
404
405 .macro translate_region_ewram_core mask
406   lui $2, %hi(ewram + 0x8000)     # generate upper address (delay)
407   andi $1, $4, \mask              # generate 15bit offset
408   ext $4, $4, 15, 3               # isolate top 3 bits of offset
409   ins $1, $4, 16, 3               # reinsert into top 4 bits
410   addu $2, $2, $1
411 .endm
412
413 .macro translate_region_ewram patch_handler
414   region_check 2, \patch_handler
415   translate_region_ewram_core 0x7FFF
416 .endm
417
418 .macro translate_region_ewram_load_align align_bits, alignment, patch_handler
419   region_check_align 2, \align_bits, \alignment, \patch_handler
420   translate_region_ewram_core 0x7FFF
421 .endm
422
423 .macro translate_region_ewram_load_align16 align_bits, alignment, patch_handler
424   region_check_align 2, \align_bits, \alignment, \patch_handler
425   translate_region_ewram_core 0x7FFE
426 .endm
427
428 .macro translate_region_ewram_load_align32 align_bits, alignment, patch_handler
429   region_check_align 2, \align_bits, \alignment, \patch_handler
430   translate_region_ewram_core 0x7FFC
431 .endm
432
433 .macro translate_region_ewram_store_align16 patch_handler
434   region_check 2, \patch_handler
435   translate_region_ewram_core 0x7FFE
436 .endm
437
438 .macro translate_region_ewram_store_align32 patch_handler
439   region_check 2, \patch_handler
440   translate_region_ewram_core 0x7FFC
441 .endm
442
443
444 .macro translate_region_vram_core
445   addiu $2, $2, -3                # see if it's 3
446   ext $4, $4, 0, 17               # generate 17bit offset
447   bne $2, $0, 1f
448   lui $1, %hi(vram)               # start loading vram address (delay)
449
450   addiu $4, $4, -0x8000           # move address into VRAM region
451
452 1:
453   addu $2, $1, $4                 # $2 = (hi)vram + address
454 .endm
455
456 .macro translate_region_vram patch_handler
457   region_check 6, \patch_handler
458   ext $2, $4, 15, 2               # $2 = bits 15 and 16 of address (delay)
459   translate_region_vram_core
460 .endm
461
462 .macro translate_region_vram_load_align align_bits, alignment, patch_handler
463   region_check_align 6, \align_bits, \alignment, \patch_handler
464   ext $2, $4, 15, 2               # $2 = bits 15 and 16 of address (delay)
465   translate_region_vram_core
466 .endm
467
468 .macro translate_region_vram_load_align16 align_bits, alignment, patch_handler
469   region_check_align 6, \align_bits, \alignment, \patch_handler
470   ext $2, $4, 15, 2               # $2 = bits 15 and 16 of address (delay)
471   ins $4, $0, 0, 1                # mask out lower bit of address
472   translate_region_vram_core
473 .endm
474
475 .macro translate_region_vram_load_align32 align_bits, alignment, patch_handler
476   region_check_align 6, \align_bits, \alignment, \patch_handler
477   ext $2, $4, 15, 2               # $2 = bits 15 and 16 of address (delay)
478   ins $4, $0, 0, 2                # mask out lower two bits of address
479   translate_region_vram_core
480 .endm
481
482 .macro translate_region_vram_store_align16 patch_handler
483   region_check 6, \patch_handler
484   ext $2, $4, 15, 2               # $2 = bits 15 and 16 of address (delay)
485   ins $4, $0, 0, 1                # mask out lower bit of address
486   translate_region_vram_core
487 .endm
488
489 .macro translate_region_vram_store_align32 patch_handler
490   region_check 6, \patch_handler
491   ext $2, $4, 15, 2               # $2 = bits 15 and 16 of address (delay)
492   ins $4, $0, 0, 2                # mask out lower two bits of address
493   translate_region_vram_core
494 .endm
495
496
497
498 .macro translate_region_gamepak_core mask
499   srl $2, $4, 15                  # $2 = page number of address (delay)
500   sll $2, $2, 2                   # adjust to word index
501   addu $2, $2, $16                # $2 = memory_map_read[address >> 15]
502   lw $2, -32768($2)
503   bne $2, $0, 1f                  # if it's non-NULL continue
504   andi $1, $4, \mask              # $1 = low 15bits of address (delay slot)
505
506   sw $ra, REG_SAVE2($16)          # save return address
507
508   save_registers                  # save the registers
509   ext $4, $4, 15, 10              # $4 = (address >> 15) & 0x3FF
510
511   jal load_gamepak_page           # get page in $2
512   sw $1, REG_SAVE($16)            # save offset (delay)
513   lw $1, REG_SAVE($16)            # restore offset (delay)
514
515   restore_registers               # restore the other registers
516
517   lw $ra, REG_SAVE2($16)          # restore return address
518
519 1:
520   addu $2, $2, $1                 # add the memory map offset
521 .endm
522
523 .macro translate_region_gamepak region, patch_handler
524   region_check \region, \patch_handler
525   translate_region_gamepak_core 0x7FFF
526 .endm
527
528 .macro translate_region_gamepak_align region, a_b, alignment, patch_handler
529   region_check_align \region, \a_b, \alignment, \patch_handler
530   translate_region_gamepak_core 0x7FFF
531 .endm
532
533 .macro translate_region_gamepak_align16 region, a_b, alignment, patch_handler
534   region_check_align \region, \a_b, \alignment, \patch_handler
535   translate_region_gamepak_core 0x7FFE
536 .endm
537
538 .macro translate_region_gamepak_align32 region, a_b, alignment, patch_handler
539   region_check_align \region, \a_b, \alignment, \patch_handler
540   translate_region_gamepak_core 0x7FFC
541 .endm
542
543
544 .macro translate_region_gamepak_a region, patch_handler
545   region_check \region, \patch_handler
546   srl $2, $4, 15                  # $2 = page number of address (delay)
547   sll $2, $2, 2                   # adjust to word index
548   addu $2, $2, $16                # $2 = memory_map_read[address >> 15]
549   lw $2, -32768($2)
550   bne $2, $0, 1f                  # if it's non-NULL continue
551   andi $1, $4, 0x7FFF             # $1 = low 15bits of address (delay slot)
552
553   sw $ra, REG_SAVE2($16)          # save return address
554   sw $6, REG_SAVE3($16)           # save a2
555
556   save_registers                  # save the registers
557   ext $4, $4, 15, 10              # $4 = (address >> 15) & 0x3FF
558
559   jal load_gamepak_page           # get page in $2
560   sw $1, REG_SAVE($16)            # save offset (delay)
561   lw $1, REG_SAVE($16)            # restore offset (delay)
562
563   restore_registers               # restore the other registers
564
565   lw $ra, REG_SAVE2($16)          # restore return address
566   lw $6, REG_SAVE3($16)           # restore a2
567
568 1:
569   addu $2, $2, $1                 # add the memory map offset
570 .endm
571
572
573 .macro eeprom_load_a patch_handler
574   region_check 0xD, \patch_handler
575
576   sw $ra, REG_SAVE($16)           # save the return address (delay)
577   sw $6, REG_SAVE2($16)           # save a2
578
579   save_registers                  # save the registers
580
581   jal read_eeprom                 # get eeprom value in $2
582   nop
583
584   restore_registers               # restore the other registers
585
586   lw $ra, REG_SAVE($16)           # restore return address
587   jr $ra                          # return
588   lw $6, REG_SAVE2($16)           # restore a2
589 .endm
590
591
592 .macro eeprom_load_core
593   sw $ra, REG_SAVE($16)           # save the return address (delay)
594
595   save_registers                  # save the registers
596
597   jal read_eeprom                 # get eeprom value in $2
598   nop
599
600   restore_registers               # restore the other registers
601
602   lw $ra, REG_SAVE($16)           # restore return address
603   jr $ra                          # return
604   nop
605 .endm
606
607 .macro eeprom_load patch_handler
608   region_check 0xD, \patch_handler
609   eeprom_load_core
610 .endm
611
612 .macro eeprom_load_align align_bits, alignment, patch_handler
613   region_check_align 0xD, \align_bits, \alignment, \patch_handler
614   eeprom_load_core
615 .endm
616
617 .macro eeprom_load_align16 align_bits, alignment, patch_handler
618   eeprom_load_align \align_bits, \alignment, \patch_handler
619 .endm
620
621 .macro eeprom_load_align32 align_bits, alignment, patch_handler
622   eeprom_load_align \align_bits, \alignment, \patch_handler
623 .endm
624
625
626 .macro backup_load_core
627   save_registers                  # save the registers
628
629   jal read_backup                 # get backup value in $2
630   ext $4, $4, 0, 16               # address &= 0xFFFF
631
632   restore_registers               # restore the other registers
633
634   lw $ra, REG_SAVE($16)           # restore return address
635   jr $ra                          # return
636 .endm
637
638 .macro backup_load_a patch_handler
639   region_check 0xE, \patch_handler
640   sw $ra, REG_SAVE($16)           # save return address (delay)
641   sw $6, REG_SAVE2($16)           # save a2
642
643   save_registers                  # save the registers
644
645   jal read_backup                 # get backup value in $2
646   ext $4, $4, 0, 16               # address &= 0xFFFF
647
648   restore_registers               # restore the other registers
649
650   lw $ra, REG_SAVE($16)           # restore return address
651   jr $ra                          # return
652   lw $6, REG_SAVE2($16)           # restore a2
653 .endm
654
655
656 .macro backup_load patch_handler
657   region_check 0xE, \patch_handler
658   sw $ra, REG_SAVE($16)           # save the return address (delay)
659   backup_load_core
660 .endm
661
662 .macro backup_load_align align_bits, alignment, patch_handler
663   region_check_align 0xE, \align_bits, \alignment, \patch_handler
664   sw $ra, REG_SAVE($16)           # save the return address (delay)
665   backup_load_core
666 .endm
667
668 .macro backup_load_align16 align_bits, alignment, patch_handler
669   region_check_align 0xE, \align_bits, \alignment, \patch_handler
670   sw $ra, REG_SAVE($16)           # save the return address (delay)
671   ins $4, $0, 0, 1                # mask out lower bit
672   backup_load_core
673 .endm
674
675 .macro backup_load_align32 align_bits, alignment, patch_handler
676   region_check_align 0xE, \align_bits, \alignment, \patch_handler
677   sw $ra, REG_SAVE($16)           # save the return address (delay)
678   ins $4, $0, 0, 2                # mask out lower two bits
679   backup_load_core
680 .endm
681
682
683 .macro open_load8_core
684   lw $2, REG_CPSR($16)            # $2 = CPSR (delay)
685   andi $2, $2, 0x20               # test T bit
686   beq $2, $0, 1f                  # branch if ARM mode
687   andi $4, $4, 0x03               # isolate lower 3bits from address (delay)
688
689   andi $4, $4, 0x01               # in Thumb mode, isolate one more bit
690
691 1:
692   sw $ra, REG_SAVE($16)           # save the return address (delay)
693   save_registers                  # save the registers
694
695   jal read_memory8                # get instruction at PC
696   addu $4, $5, $4                 # a0 = PC + low bits of address
697
698   restore_registers               # restore the other registers
699
700   lw $ra, REG_SAVE($16)           # restore return address
701   jr $ra                          # return
702 .endm
703
704 .macro open_load8 patch_handler
705   region_check_open \patch_handler
706   open_load8_core
707 .endm
708
709
710
711 .macro open_load16_core
712   lw $2, REG_CPSR($16)            # $2 = CPSR (delay)
713   andi $2, $2, 0x20               # test T bit
714   beq $2, $0, 1f                  # branch if ARM mode
715   andi $4, $4, 0x02               # isolate bit 1 from address (delay)
716
717   addu $4, $0, $0                 # zero out address bit
718
719 1:
720   sw $ra, REG_SAVE($16)           # save the return address (delay)
721   save_registers                  # save the registers
722
723   jal read_memory16               # get instruction at PC
724   addu $4, $5, $4                 # a0 = PC + low bits of address
725
726   restore_registers               # restore the other registers
727
728   lw $ra, REG_SAVE($16)           # restore return address
729   jr $ra                          # return
730 .endm
731
732 .macro open_load16_align align_bits, alignment, patch_handler
733   region_check_open_align \align_bits, \alignment, \patch_handler
734   open_load16_core
735 .endm
736
737 .macro open_load16_align16 align_bits, alignment, patch_handler
738   open_load16_align \align_bits, \alignment, \patch_handler
739 .endm
740
741
742
743 .macro open_load32_core
744   lw $2, REG_CPSR($16)            # $2 = CPSR (delay)
745   andi $2, $2, 0x20               # test T bit
746
747   save_registers                  # save the registers
748
749   beq $2, $0, 1f                  # branch if ARM mode
750   sw $ra, REG_SAVE($16)           # save the return address (delay)
751
752   jal read_memory16               # get instruction at PC
753   addu $4, $5, $0                 # a0 = PC
754
755   j 2f
756   ins $2, $2, 16, 16              # result = (result << 16) | result (delay)
757
758 1:
759   jal read_memory32               # get instruction at PC
760   addu $4, $5, $4                 # a0 = PC
761
762 2:                                # join point
763   restore_registers               # restore the other registers
764
765   lw $ra, REG_SAVE($16)           # restore return address
766   jr $ra                          # return
767 .endm
768
769 .macro open_load32_a patch_handler
770   region_check_open \patch_handler
771
772   lw $2, REG_CPSR($16)            # $2 = CPSR (delay)
773   andi $2, $2, 0x20               # test T bit
774
775   save_registers                  # save the registers
776   sw $6, REG_SAVE2($16)           # save a2
777
778   beq $2, $0, 1f                  # branch if ARM mode
779   sw $ra, REG_SAVE($16)           # save the return address (delay)
780
781   jal read_memory16               # get instruction at PC
782   addu $4, $5, $0                 # a0 = PC
783
784   j 2f
785   ins $2, $2, 16, 16              # result = (result << 16) | result (delay)
786
787 1:
788   jal read_memory32               # get instruction at PC
789   addu $4, $5, $4                 # a0 = PC
790
791 2:
792   restore_registers               # restore the other registers
793
794   lw $ra, REG_SAVE($16)           # restore return address
795   jr $ra                          # return
796   lw $6, REG_SAVE2($16)           # restore a2 (delay)
797 .endm
798
799 .macro open_load32_align align_bits, alignment, patch_handler
800   region_check_open_align \align_bits, \alignment, \patch_handler
801   open_load32_core
802 .endm
803
804 .macro open_load32_align32 align_bits, alignment, patch_handler
805   open_load32_align \align_bits, \alignment, \patch_handler
806 .endm
807
808
809 .macro store_function function, region, patch_handler, mask
810   region_check \region, \patch_handler
811   sw $ra, REG_SAVE($16)           # save the return address (delay)
812
813   save_registers                  # save the registers
814
815   jal \function                   # store value out
816   andi $4, $4, \mask              # mask address
817
818   restore_registers               # restore the other registers
819
820   lw $ra, REG_SAVE($16)           # restore return address
821   jr $ra                          # return
822   nop
823 .endm
824
825
826 .macro store_function_a function, region, patch_handler, mask
827   region_check \region, \patch_handler
828   sw $ra, REG_SAVE($16)           # save the return address (delay)
829
830   save_registers                  # save the registers
831
832   jal \function                   # store value out
833   andi $4, $4, \mask              # mask address
834
835   restore_registers               # restore the other registers
836
837   lw $ra, REG_SAVE($16)           # restore return address
838   jr $ra                          # return
839   nop
840 .endm
841
842
843
844 .macro load_u8 base
845   jr $ra                          # return
846   lbu $2, %lo(\base)($2)          # return base[offset]
847 .endm
848
849 .macro load_s8 base
850   jr $ra                          # return
851   lb $2, %lo(\base)($2)           # return base[offset]
852 .endm
853
854 .macro load_u16 base
855   jr $ra                          # return
856   lhu $2, %lo(\base)($2)          # return base[offset]
857 .endm
858
859 .macro load_s16 base
860   jr $ra                          # return
861   lh $2, %lo(\base)($2)           # return base[offset]
862 .endm
863
864 .macro load_u32 base
865   jr $ra                          # return
866   lw $2, %lo(\base)($2)           # return base[offset]
867 .endm
868
869
870 # 16bit unaligned load will always have a 1 in the LSB;
871 # should have already been taken care of in indexing.
872
873 .macro load_u16_unaligned base
874   lhu $2, %lo(\base)($2)          # load base[offset]
875   jr $ra                          # return
876   ror $2, $2, 8                   # rotate value by 8bits
877 .endm
878
879 # This is technically the same as load_s8, but kept to
880 # avoid confusion.
881
882 .macro load_s16_unaligned base
883   jr $ra                          # return
884   lb $2, %lo(\base)($2)           # return base[offset]
885 .endm
886
887 # Unalignment must be known statically (use the tables to
888 # patch correctly)
889
890 .macro load_u32_unaligned base, alignment
891   lw $2, %lo(\base)($2)           # load base[offset]
892   jr $ra                          # return
893   ror $2, $2, (\alignment * 8)    # rotate value by 8bits
894 .endm
895
896
897 .macro store_u8 base
898   jr $ra                          # return
899   sb $5, %lo(\base)($2)           # store value at base[offset]
900 .endm
901
902 .macro store_u16 base
903   jr $ra                          # return
904   sh $5, %lo(\base)($2)           # store value at base[offset]
905 .endm
906
907 .macro store_u32 base
908   jr $ra                          # return
909   sw $5, %lo(\base)($2)           # store value at base[offset]
910 .endm
911
912
913 # Store the value double mirrored (u16)
914
915 .macro store_u8_double base
916   ins $5, $5, 8, 8                # value = (value << 8) | value
917   jr $ra                          # return
918   sh $5, %lo(\base)($2)           # store value at base[offset]
919 .endm
920
921
922 # Store the values and check if it overwrote code there
923
924 .macro store_u8_smc base
925   addiu $2, $2, %lo(\base)        # offset the address
926   lb $1, -32768($2)               # load the SMC status
927   bne $1, $0, smc_write           # is there code there?
928   sb $5, ($2)                     # store value at base[offset] (delay)
929   jr $ra                          # return
930   nop
931 .endm
932
933 .macro store_u16_smc base
934   addiu $2, $2, %lo(\base)        # offset the address
935   lh $1, -32768($2)               # load the SMC status
936   bne $1, $0, smc_write           # is there code there?
937   sh $5, ($2)                     # store value at base[offset] (delay)
938   jr $ra                          # return
939   nop
940 .endm
941
942 .macro store_u32_smc base
943   addiu $2, $2, %lo(\base)        # offset the address
944   lw $1, -32768($2)               # load the SMC status
945   bne $1, $0, smc_write           # is there code there?
946   sw $5, ($2)                     # store value at base[offset] (delay)
947   jr $ra                          # return
948   nop
949 .endm
950
951
952
953 # Unsigned 8bit load handlers
954
955 execute_load_bios_u8:
956   region_check 0, patch_load_u8
957   srl $2, $4, 14                  # check if address is in BIOS region
958   bne $2, $0, 2f                  # if not, perform open read
959   srl $1, $5, 14                  # check if PC is in BIOS region
960   bne $1, $0, 1f                  # if not, perform BIOS protected read
961   lui $2, %hi(bios_rom)           # generate upper address (delay)
962
963   andi $4, $4, 0x3FFF             # generate offset
964   addu $2, $2, $4
965   load_u8 bios_rom
966
967 1:
968   lui $2, %hi(bios_read_protect)  # generate upper address
969   ins $2, $4, 0, 2                # lower 2 bits address contributes
970   load_u8 bios_read_protect
971
972 2:
973   open_load8_core
974   nop
975
976
977 execute_load_ewram_u8:
978   translate_region_ewram patch_load_u8
979   load_u8 (ewram + 0x8000)
980
981 # Put the generic address over the handler you want to be default
982 # IWRAM is typically the most frequently read and written to.
983
984 execute_load_u8:
985 execute_load_iwram_u8:
986   translate_region 3, patch_load_u8, (iwram + 0x8000), 0x7FFF
987   load_u8 (iwram + 0x8000)
988
989 execute_load_io_u8:
990   translate_region 4, patch_load_u8, io_registers, 0x3FF
991   load_u8 io_registers
992
993 execute_load_palette_u8:
994   translate_region 5, patch_load_u8, palette_ram, 0x3FF
995   load_u8 palette_ram
996
997 execute_load_vram_u8:
998   translate_region_vram patch_load_u8
999   load_u8 vram
1000
1001 execute_load_oam_u8:
1002   translate_region 7, patch_load_u8, oam_ram, 0x3FF
1003   load_u8 oam_ram
1004
1005 execute_load_gamepak8_u8:
1006   translate_region_gamepak 8, patch_load_u8
1007   load_u8 0
1008
1009 execute_load_gamepak9_u8:
1010   translate_region_gamepak 9, patch_load_u8
1011   load_u8 0
1012
1013 execute_load_gamepakA_u8:
1014   translate_region_gamepak 10, patch_load_u8
1015   load_u8 0
1016
1017 execute_load_gamepakB_u8:
1018   translate_region_gamepak 11, patch_load_u8
1019   load_u8 0
1020
1021 execute_load_gamepakC_u8:
1022   translate_region_gamepak 12, patch_load_u8
1023   load_u8 0
1024
1025 execute_load_eeprom_u8:
1026   eeprom_load patch_load_u8
1027
1028 execute_load_backup_u8:
1029   backup_load patch_load_u8
1030   nop
1031
1032 execute_load_open_u8:
1033   open_load8 patch_load_u8
1034   nop
1035
1036 load_u8_ftable:
1037   .long execute_load_bios_u8      # 0x00 BIOS
1038   .long execute_load_open_u8      # 0x01 open address
1039   .long execute_load_ewram_u8     # 0x02 EWRAM
1040   .long execute_load_iwram_u8     # 0x03 IWRAM
1041   .long execute_load_io_u8        # 0x04 I/O registers
1042   .long execute_load_palette_u8   # 0x05 Palette RAM
1043   .long execute_load_vram_u8      # 0x06 VRAM
1044   .long execute_load_oam_u8       # 0x07 OAM RAM
1045   .long execute_load_gamepak8_u8  # 0x08 gamepak
1046   .long execute_load_gamepak9_u8  # 0x09 gamepak
1047   .long execute_load_gamepakA_u8  # 0x0A gamepak
1048   .long execute_load_gamepakB_u8  # 0x0B gamepak
1049   .long execute_load_gamepakC_u8  # 0x0C gamepak
1050   .long execute_load_eeprom_u8    # 0x0D gamepak/eeprom
1051   .long execute_load_backup_u8    # 0x0E Flash ROM/SRAM
1052   .long execute_load_open_u8      # 0x0F open address
1053
1054 patch_load_u8:
1055   patch_handler load_u8_ftable, 0x01
1056
1057
1058
1059 # Signed 8bit load handlers
1060
1061 execute_load_bios_s8:
1062   region_check 0, patch_load_s8
1063   srl $2, $4, 14                  # check if address is in BIOS region
1064   bne $2, $0, 2f
1065   srl $1, $5, 14                  # check if PC is in BIOS region
1066   bne $1, $0, 1f                  # if not, perform BIOS protected read
1067   lui $2, %hi(bios_rom)           # generate upper address (delay)
1068
1069   andi $4, $4, 0x3FFF             # generate offset
1070   addu $2, $2, $4
1071   load_s8 bios_rom
1072
1073 1:
1074   lui $2, %hi(bios_read_protect)  # generate upper address
1075   ins $2, $4, 0, 2                # lower 2 bits contribute
1076   load_s8 bios_read_protect
1077
1078 2:
1079   open_load8_core
1080   seb $2, $2
1081
1082
1083 execute_load_ewram_s8:
1084   translate_region_ewram patch_load_s8
1085   load_s8 (ewram + 0x8000)
1086
1087 execute_load_s8:
1088 execute_load_iwram_s8:
1089   translate_region 3, patch_load_s8, (iwram + 0x8000), 0x7FFF
1090   load_s8 (iwram + 0x8000)
1091
1092 execute_load_io_s8:
1093   translate_region 4, patch_load_s8, io_registers, 0x3FF
1094   load_s8 io_registers
1095
1096 execute_load_palette_s8:
1097   translate_region 5, patch_load_s8, palette_ram, 0x3FF
1098   load_s8 palette_ram
1099
1100 execute_load_vram_s8:
1101   translate_region_vram patch_load_s8
1102   load_s8 vram
1103
1104 execute_load_oam_s8:
1105   translate_region 7, patch_load_s8, oam_ram, 0x3FF
1106   load_s8 oam_ram
1107
1108 execute_load_gamepak8_s8:
1109   translate_region_gamepak 8, patch_load_s8
1110   load_s8 0
1111
1112 execute_load_gamepak9_s8:
1113   translate_region_gamepak 9, patch_load_s8
1114   load_s8 0
1115
1116 execute_load_gamepakA_s8:
1117   translate_region_gamepak 10, patch_load_s8
1118   load_s8 0
1119
1120 execute_load_gamepakB_s8:
1121   translate_region_gamepak 11, patch_load_s8
1122   load_s8 0
1123
1124 execute_load_gamepakC_s8:
1125   translate_region_gamepak 12, patch_load_s8
1126   load_s8 0
1127
1128 execute_load_eeprom_s8:
1129   eeprom_load patch_load_s8
1130
1131 execute_load_backup_s8:
1132   backup_load patch_load_s8
1133   seb $2, $2                      # sign extend result (delay)
1134
1135 execute_load_open_s8:
1136   open_load8 patch_load_s8
1137   seb $2, $2                      # sign extend result (delay)
1138
1139 load_s8_ftable:
1140   .long execute_load_bios_s8      # 0x00 BIOS
1141   .long execute_load_open_s8      # 0x01 open address
1142   .long execute_load_ewram_s8     # 0x02 EWRAM
1143   .long execute_load_iwram_s8     # 0x03 IWRAM
1144   .long execute_load_io_s8        # 0x04 I/O registers
1145   .long execute_load_palette_s8   # 0x05 Palette RAM
1146   .long execute_load_vram_s8      # 0x06 VRAM
1147   .long execute_load_oam_s8       # 0x07 OAM RAM
1148   .long execute_load_gamepak8_s8  # 0x08 gamepak
1149   .long execute_load_gamepak9_s8  # 0x09 gamepak
1150   .long execute_load_gamepakA_s8  # 0x0A gamepak
1151   .long execute_load_gamepakB_s8  # 0x0B gamepak
1152   .long execute_load_gamepakC_s8  # 0x0C gamepak
1153   .long execute_load_eeprom_s8    # 0x0D gamepak/eeprom
1154   .long execute_load_backup_s8    # 0x0E Flash ROM/SRAM
1155   .long execute_load_open_s8      # 0x0F open address
1156
1157 patch_load_s8:
1158   patch_handler load_s8_ftable, 1
1159
1160
1161
1162 # Unsigned aligned 16bit load handlers
1163
1164 execute_load_bios_u16:
1165   region_check_align 0, 1, 0, patch_load_u16
1166   srl $2, $4, 14                  # check if address is in BIOS region
1167   bne $2, $0, 2f                  # if not, perform open read
1168   srl $1, $5, 14                  # check if PC is in BIOS region
1169   bne $1, $0, 1f                  # if not, perform BIOS protected read
1170   lui $2, %hi(bios_rom)           # generate upper address (delay)
1171
1172   andi $4, $4, 0x3FFF             # generate offset
1173   addu $2, $2, $4
1174   load_u16 bios_rom
1175
1176 1:
1177   lui $2, %hi(bios_read_protect)  # generate upper address
1178   ins $2, $4, 0, 2                # bit 1 contributes
1179   load_u16 bios_read_protect
1180
1181 2:
1182   open_load16_core
1183   nop
1184
1185 execute_load_ewram_u16:
1186   translate_region_ewram_load_align 1, 0, patch_load_u16
1187   load_u16 (ewram + 0x8000)
1188
1189 execute_load_u16:
1190 execute_load_iwram_u16:
1191   translate_region_align 3, 1, 0, patch_load_u16, (iwram + 0x8000), 0x7FFF
1192   load_u16 (iwram + 0x8000)
1193
1194 execute_load_io_u16:
1195   translate_region_align 4, 1, 0, patch_load_u16, io_registers, 0x3FF
1196   load_u16 io_registers
1197
1198 execute_load_palette_u16:
1199   translate_region_align 5, 1, 0, patch_load_u16, palette_ram, 0x3FF
1200   load_u16 palette_ram
1201
1202 execute_load_vram_u16:
1203   translate_region_vram_load_align 1, 0, patch_load_u16
1204   load_u16 vram
1205
1206 execute_load_oam_u16:
1207   translate_region_align 7, 1, 0, patch_load_u16, oam_ram, 0x3FF
1208   load_u16 oam_ram
1209
1210 execute_load_gamepak8_u16:
1211   translate_region_gamepak_align 8, 1, 0, patch_load_u16
1212   load_u16 0
1213
1214 execute_load_gamepak9_u16:
1215   translate_region_gamepak_align 9, 1, 0, patch_load_u16
1216   load_u16 0
1217
1218 execute_load_gamepakA_u16:
1219   translate_region_gamepak_align 10, 1, 0, patch_load_u16
1220   load_u16 0
1221
1222 execute_load_gamepakB_u16:
1223   translate_region_gamepak_align 11, 1, 0, patch_load_u16
1224   load_u16 0
1225
1226 execute_load_gamepakC_u16:
1227   translate_region_gamepak_align 12, 1, 0, patch_load_u16
1228   load_u16 0
1229
1230 execute_load_eeprom_u16:
1231   eeprom_load_align 1, 0, patch_load_u16
1232
1233 execute_load_backup_u16:
1234   backup_load_align 1, 0, patch_load_u16
1235   nop
1236
1237 execute_load_open_u16:
1238   open_load16_align 1, 0, patch_load_u16
1239   nop
1240
1241
1242 # Unsigned unaligned 16bit load handlers
1243
1244 execute_load_bios_u16u:
1245   region_check_align 0, 1, 1, patch_load_u16
1246   srl $2, $4, 14                  # check if address is in BIOS region
1247   bne $2, $0, 2f                  # if not, perform open read
1248   srl $1, $5, 14                  # check if PC is in BIOS region
1249   bne $1, $0, 1f                  # if not, perform BIOS protected read
1250   lui $2, %hi(bios_rom)           # generate upper address (delay)
1251
1252   andi $4, $4, 0x3FFE             # generate offset
1253   addu $2, $2, $4
1254   load_u16_unaligned bios_rom
1255
1256 1:
1257   lui $2, %hi(bios_read_protect)  # generate upper address
1258   ext $1, $4, 1, 1
1259   ins $2, $1, 1, 1                # bit 1 contributes
1260   load_u16_unaligned bios_read_protect
1261
1262 2:
1263   open_load16_core
1264   ror $2, $2, 8
1265
1266
1267 execute_load_ewram_u16u:
1268   translate_region_ewram_load_align16 1, 1, patch_load_u16
1269   load_u16_unaligned (ewram + 0x8000)
1270
1271 execute_load_iwram_u16u:
1272   translate_region_align 3, 1, 1, patch_load_u16, (iwram + 0x8000), 0x7FFE
1273   load_u16_unaligned (iwram + 0x8000)
1274
1275 execute_load_io_u16u:
1276   translate_region_align 4, 1, 1, patch_load_u16, io_registers, 0x3FE
1277   load_u16_unaligned io_registers
1278
1279 execute_load_palette_u16u:
1280   translate_region_align 5, 1, 1, patch_load_u16, palette_ram, 0x3FE
1281   load_u16_unaligned palette_ram
1282
1283 execute_load_vram_u16u:
1284   translate_region_vram_load_align16 1, 1, patch_load_u16
1285   load_u16_unaligned vram
1286
1287 execute_load_oam_u16u:
1288   translate_region_align 7, 1, 1, patch_load_u16, oam_ram, 0x3FE
1289   load_u16_unaligned oam_ram
1290
1291 execute_load_gamepak8_u16u:
1292   translate_region_gamepak_align16 8, 1, 1, patch_load_u16
1293   load_u16_unaligned 0
1294
1295 execute_load_gamepak9_u16u:
1296   translate_region_gamepak_align16 9, 1, 1, patch_load_u16
1297   load_u16_unaligned 0
1298
1299 execute_load_gamepakA_u16u:
1300   translate_region_gamepak_align16 10, 1, 1, patch_load_u16
1301   load_u16_unaligned 0
1302
1303 execute_load_gamepakB_u16u:
1304   translate_region_gamepak_align16 11, 1, 1, patch_load_u16
1305   load_u16_unaligned 0
1306
1307 execute_load_gamepakC_u16u:
1308   translate_region_gamepak_align16 12, 1, 1, patch_load_u16
1309   load_u16_unaligned 0
1310
1311 execute_load_eeprom_u16u:
1312   eeprom_load_align16 1, 1, patch_load_u16
1313
1314 execute_load_backup_u16u:
1315   backup_load_align16 1, 1, patch_load_u16
1316   ror $2, $2, 8                   # rotate value by 8bits
1317
1318 execute_load_open_u16u:
1319   open_load16_align16 1, 1, patch_load_u16
1320   ror $2, $2, 8                   # rotate value by 8bits
1321
1322 load_u16_ftable:
1323 #  .long execute_load_full_u16
1324   .long execute_load_bios_u16     # 0x00 BIOS
1325   .long execute_load_open_u16     # 0x01 open address
1326   .long execute_load_ewram_u16    # 0x02 EWRAM
1327   .long execute_load_iwram_u16    # 0x03 IWRAM
1328   .long execute_load_io_u16       # 0x04 I/O registers
1329   .long execute_load_palette_u16  # 0x05 Palette RAM
1330   .long execute_load_vram_u16     # 0x06 VRAM
1331   .long execute_load_oam_u16      # 0x07 OAM RAM
1332   .long execute_load_gamepak8_u16 # 0x08 gamepak
1333   .long execute_load_gamepak9_u16 # 0x09 gamepak
1334   .long execute_load_gamepakA_u16 # 0x0A gamepak
1335   .long execute_load_gamepakB_u16 # 0x0B gamepak
1336   .long execute_load_gamepakC_u16 # 0x0C gamepak
1337
1338   .long execute_load_eeprom_u16   # 0x0D gamepak/eeprom
1339   .long execute_load_backup_u16   # 0x0E Flash ROM/SRAM
1340   .long execute_load_open_u16     # 0x0F open
1341
1342   .long execute_load_bios_u16u    # 0x00 BIOS unaligned
1343   .long execute_load_open_u16u    # 0x01 open address unaligned
1344   .long execute_load_ewram_u16u   # 0x02 EWRAM unaligned
1345   .long execute_load_iwram_u16u   # 0x03 IWRAM unaligned
1346   .long execute_load_io_u16u      # 0x04 I/O registers unaligned
1347   .long execute_load_palette_u16u # 0x05 Palette RAM unaligned
1348   .long execute_load_vram_u16u    # 0x06 VRAM unaligned
1349   .long execute_load_oam_u16u     # 0x07 OAM RAM unaligned
1350   .long execute_load_gamepak8_u16u# 0x08 gamepak unaligned
1351   .long execute_load_gamepak9_u16u# 0x09 gamepak unaligned
1352   .long execute_load_gamepakA_u16u# 0x0A gamepak unaligned
1353   .long execute_load_gamepakB_u16u# 0x0B gamepak unaligned
1354   .long execute_load_gamepakC_u16u# 0x0C gamepak unaligned
1355   .long execute_load_eeprom_u16u  # 0x0D gamepak/eeprom unaligned
1356   .long execute_load_backup_u16u  # 0x0E Flash ROM/SRAM unaligned
1357   .long execute_load_open_u16u    # 0x0F open unaligned
1358
1359
1360   .long execute_load_full_u16
1361   .long execute_load_full_u16
1362   .long execute_load_full_u16
1363   .long execute_load_full_u16
1364   .long execute_load_full_u16
1365   .long execute_load_full_u16
1366   .long execute_load_full_u16
1367   .long execute_load_full_u16
1368   .long execute_load_full_u16
1369   .long execute_load_full_u16
1370   .long execute_load_full_u16
1371   .long execute_load_full_u16
1372   .long execute_load_full_u16
1373   .long execute_load_full_u16
1374   .long execute_load_full_u16
1375
1376   .long execute_load_full_u16
1377   .long execute_load_full_u16
1378   .long execute_load_full_u16
1379   .long execute_load_full_u16
1380   .long execute_load_full_u16
1381   .long execute_load_full_u16
1382   .long execute_load_full_u16
1383   .long execute_load_full_u16
1384   .long execute_load_full_u16
1385   .long execute_load_full_u16
1386   .long execute_load_full_u16
1387   .long execute_load_full_u16
1388   .long execute_load_full_u16
1389   .long execute_load_full_u16
1390   .long execute_load_full_u16
1391   .long execute_load_full_u16
1392
1393
1394
1395 patch_load_u16:
1396   patch_handler_align load_u16_ftable, 1
1397
1398 # Signed aligned 16bit load handlers
1399
1400 execute_load_bios_s16:
1401   region_check_align 0, 1, 0, patch_load_s16
1402   srl $2, $4, 14                  # check if address is in BIOS region
1403   bne $2, $0, 2f                  # if not, perform open read
1404   srl $1, $5, 14                  # check if PC is in BIOS region
1405   bne $1, $0, 1f                  # if not, perform BIOS protected read
1406   lui $2, %hi(bios_rom)           # generate upper address (delay)
1407
1408   andi $4, $4, 0x3FFF             # generate offset
1409   addu $2, $2, $4
1410   load_s16 bios_rom
1411
1412 1:
1413   lui $2, %hi(bios_read_protect)  # generate upper address
1414   ins $2, $4, 0, 2                # bit 1 contributes
1415   load_s16 bios_read_protect
1416
1417 2:
1418   open_load16_core
1419   seh $2, $2
1420
1421
1422 execute_load_ewram_s16:
1423   translate_region_ewram_load_align 1, 0, patch_load_s16
1424   load_s16 (ewram + 0x8000)
1425
1426 execute_load_s16:
1427 execute_load_iwram_s16:
1428   translate_region_align 3, 1, 0, patch_load_s16, (iwram + 0x8000), 0x7FFF
1429   load_s16 (iwram + 0x8000)
1430
1431 execute_load_io_s16:
1432   translate_region_align 4, 1, 0, patch_load_s16, io_registers, 0x3FF
1433   load_s16 io_registers
1434
1435 execute_load_palette_s16:
1436   translate_region_align 5, 1, 0, patch_load_s16, palette_ram, 0x3FF
1437   load_s16 palette_ram
1438
1439 execute_load_vram_s16:
1440   translate_region_vram_load_align 1, 0, patch_load_s16
1441   load_s16 vram
1442
1443 execute_load_oam_s16:
1444   translate_region_align 7, 1, 0, patch_load_s16, oam_ram, 0x3FF
1445   load_s16 oam_ram
1446
1447 execute_load_gamepak8_s16:
1448   translate_region_gamepak_align 8, 1, 0, patch_load_s16
1449   load_s16 0
1450
1451 execute_load_gamepak9_s16:
1452   translate_region_gamepak_align 9, 1, 0, patch_load_s16
1453   load_s16 0
1454
1455 execute_load_gamepakA_s16:
1456   translate_region_gamepak_align 10, 1, 0, patch_load_s16
1457   load_s16 0
1458
1459 execute_load_gamepakB_s16:
1460   translate_region_gamepak_align 11, 1, 0, patch_load_s16
1461   load_s16 0
1462
1463 execute_load_gamepakC_s16:
1464   translate_region_gamepak_align 12, 1, 0, patch_load_s16
1465   load_s16 0
1466
1467 execute_load_eeprom_s16:
1468   eeprom_load_align 1, 0, patch_load_s16
1469
1470 execute_load_backup_s16:
1471   backup_load_align 1, 0, patch_load_s16
1472   nop
1473
1474 execute_load_open_s16:
1475   open_load16_align 1, 0, patch_load_s16
1476   nop
1477
1478
1479 # Signed unaligned 16bit load handlers
1480
1481 execute_load_bios_s16u:
1482   region_check_align 0, 1, 1, patch_load_s16
1483   srl $2, $4, 14                  # check if address is in BIOS region
1484   bne $2, $0, 2f                  # if not, perform open read
1485   srl $1, $5, 14                  # check if PC is in BIOS region
1486   bne $1, $0, 1f                  # if not, perform BIOS protected read
1487   lui $2, %hi(bios_rom)           # generate upper address (delay)
1488
1489   andi $4, $4, 0x3FFE             # generate offset
1490   addu $2, $1, $4
1491   load_s16_unaligned bios_rom
1492
1493 1:
1494   lui $2, %hi(bios_read_protect)  # generate upper address
1495   ext $1, $4, 1, 1
1496   ins $2, $1, 1, 1                # bit 1 contributes
1497   load_s16_unaligned bios_read_protect
1498
1499 2:
1500   open_load16_core
1501   seb $2, $2
1502
1503 execute_load_ewram_s16u:
1504   translate_region_ewram_load_align16 1, 1, patch_load_s16
1505   load_s16_unaligned (ewram + 0x8000)
1506
1507 execute_load_iwram_s16u:
1508   translate_region_align 3, 1, 1, patch_load_s16, (iwram + 0x8000), 0x7FFE
1509   load_s16_unaligned (iwram + 0x8000)
1510
1511 execute_load_io_s16u:
1512   translate_region_align 4, 1, 1, patch_load_s16, io_registers, 0x3FE
1513   load_s16_unaligned io_registers
1514
1515 execute_load_palette_s16u:
1516   translate_region_align 5, 1, 1, patch_load_s16, palette_ram, 0x3FE
1517   load_s16_unaligned palette_ram
1518
1519 execute_load_vram_s16u:
1520   translate_region_vram_load_align16 1, 1, patch_load_s16
1521   load_s16_unaligned vram
1522
1523 execute_load_oam_s16u:
1524   translate_region_align 7, 1, 1, patch_load_s16, oam_ram, 0x3FE
1525   load_s16_unaligned oam_ram
1526
1527 execute_load_gamepak8_s16u:
1528   translate_region_gamepak_align16 8, 1, 1, patch_load_s16
1529   load_s16_unaligned 0
1530
1531 execute_load_gamepak9_s16u:
1532   translate_region_gamepak_align16 9, 1, 1, patch_load_s16
1533   load_s16_unaligned 0
1534
1535 execute_load_gamepakA_s16u:
1536   translate_region_gamepak_align16 10, 1, 1, patch_load_s16
1537   load_s16_unaligned 0
1538
1539 execute_load_gamepakB_s16u:
1540   translate_region_gamepak_align16 11, 1, 1, patch_load_s16
1541   load_s16_unaligned 0
1542
1543 execute_load_gamepakC_s16u:
1544   translate_region_gamepak_align16 12, 1, 1, patch_load_s16
1545   load_s16_unaligned 0
1546
1547 execute_load_eeprom_s16u:
1548   eeprom_load_align 1, 1, patch_load_s16
1549
1550 execute_load_backup_s16u:
1551   backup_load_align 1, 1, patch_load_s16
1552   seb $2, $2                      # sign extend result from 8bits
1553
1554 execute_load_open_s16u:
1555   open_load16_align 1, 1, patch_load_s16
1556   seb $2, $2                      # sign extend result from 8bits
1557
1558 load_s16_ftable:
1559   .long execute_load_bios_s16     # 0x00 BIOS
1560   .long execute_load_open_s16     # 0x01 open address
1561   .long execute_load_ewram_s16    # 0x02 EWRAM
1562   .long execute_load_iwram_s16    # 0x03 IWRAM
1563   .long execute_load_io_s16       # 0x04 I/O registers
1564   .long execute_load_palette_s16  # 0x05 Palette RAM
1565   .long execute_load_vram_s16     # 0x06 VRAM
1566   .long execute_load_oam_s16      # 0x07 OAM RAM
1567   .long execute_load_gamepak8_s16 # 0x08 gamepak
1568   .long execute_load_gamepak9_s16 # 0x09 gamepak
1569   .long execute_load_gamepakA_s16 # 0x0A gamepak
1570   .long execute_load_gamepakB_s16 # 0x0B gamepak
1571   .long execute_load_gamepakC_s16 # 0x0C gamepak
1572   .long execute_load_eeprom_s16   # 0x0D gamepak/eeprom
1573   .long execute_load_backup_s16   # 0x0E Flash ROM/SRAM
1574   .long execute_load_open_s16     # 0x0F open unaligned
1575
1576   .long execute_load_bios_s16u    # 0x00 BIOS unaligned
1577   .long execute_load_open_s16u    # 0x01 open address unaligned
1578   .long execute_load_ewram_s16u   # 0x02 EWRAM unaligned
1579   .long execute_load_iwram_s16u   # 0x03 IWRAM unaligned
1580   .long execute_load_io_s16u      # 0x04 I/O registers unaligned
1581   .long execute_load_palette_s16u # 0x05 Palette RAM unaligned
1582   .long execute_load_vram_s16u    # 0x06 VRAM unaligned
1583   .long execute_load_oam_s16u     # 0x07 OAM RAM unaligned
1584   .long execute_load_gamepak8_s16u# 0x08 gamepak unaligned
1585   .long execute_load_gamepak9_s16u# 0x09 gamepak unaligned
1586   .long execute_load_gamepakA_s16u# 0x0A gamepak unaligned
1587   .long execute_load_gamepakB_s16u# 0x0B gamepak unaligned
1588   .long execute_load_gamepakC_s16u# 0x0C gamepak unaligned
1589   .long execute_load_eeprom_s16u  # 0x0D gamepak/eeprom unaligned
1590   .long execute_load_backup_s16u  # 0x0E Flash ROM/SRAM unaligned
1591   .long execute_load_open_s16u    # 0x0F open unaligned
1592
1593 patch_load_s16:
1594   patch_handler_align load_s16_ftable, 1
1595
1596
1597
1598 # Unsigned aligned 32bit load handlers
1599
1600 execute_load_bios_u32:
1601   region_check_align 0, 2, 0, patch_load_u32
1602   srl $2, $4, 14                  # check if address is in BIOS region
1603   bne $2, $0, 2f                  # if not, perform open read
1604   srl $1, $5, 14                  # check if PC is in BIOS region
1605   bne $1, $0, 1f                  # if not, perform BIOS protected read
1606   lui $2, %hi(bios_rom)           # generate upper address (delay)
1607
1608   andi $4, $4, 0x3FFF             # generate offset
1609   addu $2, $2, $4
1610   load_u32 bios_rom
1611
1612 1:
1613   lui $2, %hi(bios_read_protect)  # generate upper address
1614   load_u32 bios_read_protect
1615
1616 2:
1617   open_load32_core
1618   nop
1619
1620
1621 execute_load_ewram_u32:
1622   translate_region_ewram_load_align 2, 0, patch_load_u32
1623   load_u32 (ewram + 0x8000)
1624
1625 execute_load_u32:
1626 execute_load_iwram_u32:
1627   translate_region_align 3, 2, 0, patch_load_u32, (iwram + 0x8000), 0x7FFF
1628   load_u32 (iwram + 0x8000)
1629
1630 execute_load_io_u32:
1631   translate_region_align 4, 2, 0, patch_load_u32, io_registers, 0x3FF
1632   load_u32 io_registers
1633
1634 execute_load_palette_u32:
1635   translate_region_align 5, 2, 0, patch_load_u32, palette_ram, 0x3FF
1636   load_u32 palette_ram
1637
1638 execute_load_vram_u32:
1639   translate_region_vram_load_align 2, 0, patch_load_u32
1640   load_u32 vram
1641
1642 execute_load_oam_u32:
1643   translate_region_align 7, 2, 0, patch_load_u32, oam_ram, 0x3FF
1644   load_u32 oam_ram
1645
1646 execute_load_gamepak8_u32:
1647   translate_region_gamepak_align 8, 2, 0, patch_load_u32
1648   load_u32 0
1649
1650 execute_load_gamepak9_u32:
1651   translate_region_gamepak_align 9, 2, 0, patch_load_u32
1652   load_u32 0
1653
1654 execute_load_gamepakA_u32:
1655   translate_region_gamepak_align 10, 2, 0, patch_load_u32
1656   load_u32 0
1657
1658 execute_load_gamepakB_u32:
1659   translate_region_gamepak_align 11, 2, 0, patch_load_u32
1660   load_u32 0
1661
1662 execute_load_gamepakC_u32:
1663   translate_region_gamepak_align 12, 2, 0, patch_load_u32
1664   load_u32 0
1665
1666 execute_load_eeprom_u32:
1667   eeprom_load_align 2, 0, patch_load_u32
1668
1669 execute_load_backup_u32:
1670   backup_load_align 2, 0, patch_load_u32
1671   nop
1672
1673 execute_load_open_u32:
1674   open_load32_align 2, 0, patch_load_u32
1675   nop
1676
1677
1678 # Unsigned unaligned (by 1) 32bit load handlers
1679
1680 execute_load_bios_u32u1:
1681   region_check_align 0, 2, 1, patch_load_u32
1682   srl $2, $4, 14                  # check if address is in BIOS region
1683   bne $2, $0, 2f                  # if not, perform open read
1684   srl $1, $5, 14                  # check if PC is in BIOS region
1685   bne $1, $0, 1f                  # if not, perform BIOS protected read
1686   lui $2, %hi(bios_rom)           # generate upper address (delay)
1687
1688   andi $4, $4, 0x3FFC             # generate offset
1689   addu $2, $2, $4
1690   load_u32_unaligned bios_rom, 1
1691
1692 1:
1693   lui $2, %hi(bios_read_protect)  # generate upper address
1694   load_u32_unaligned bios_read_protect, 1
1695
1696 2:
1697   open_load32_core
1698   ror $2, $2, 8
1699
1700 execute_load_ewram_u32u1:
1701   translate_region_ewram_load_align32 2, 1, patch_load_u32
1702   load_u32_unaligned (ewram + 0x8000), 1
1703
1704 execute_load_iwram_u32u1:
1705   translate_region_align 3, 2, 1, patch_load_u32, (iwram + 0x8000), 0x7FFC
1706   load_u32_unaligned (iwram + 0x8000), 1
1707
1708 execute_load_io_u32u1:
1709   translate_region_align 4, 2, 1, patch_load_u32, io_registers, 0x3FC
1710   load_u32_unaligned io_registers, 1
1711
1712 execute_load_palette_u32u1:
1713   translate_region_align 5, 2, 1, patch_load_u32, palette_ram, 0x3FC
1714   load_u32_unaligned palette_ram, 1
1715
1716 execute_load_vram_u32u1:
1717   translate_region_vram_load_align32 2, 1, patch_load_u32
1718   load_u32_unaligned vram, 1
1719
1720 execute_load_oam_u32u1:
1721   translate_region_align 7, 2, 1, patch_load_u32, oam_ram, 0x3FC
1722   load_u32_unaligned oam_ram, 1
1723
1724 execute_load_gamepak8_u32u1:
1725   translate_region_gamepak_align32 8, 2, 1, patch_load_u32
1726   load_u32_unaligned 0, 1
1727
1728 execute_load_gamepak9_u32u1:
1729   translate_region_gamepak_align32 9, 2, 1, patch_load_u32
1730   load_u32_unaligned 0, 1
1731
1732 execute_load_gamepakA_u32u1:
1733   translate_region_gamepak_align32 10, 2, 1, patch_load_u32
1734   load_u32_unaligned 0, 1
1735
1736 execute_load_gamepakB_u32u1:
1737   translate_region_gamepak_align32 11, 2, 1, patch_load_u32
1738   load_u32_unaligned 0, 1
1739
1740 execute_load_gamepakC_u32u1:
1741   translate_region_gamepak_align32 12, 2, 1, patch_load_u32
1742   load_u32_unaligned 0, 1
1743
1744 execute_load_eeprom_u32u1:
1745   eeprom_load_align32 2, 1, patch_load_u32
1746
1747 execute_load_backup_u32u1:
1748   backup_load_align32 2, 1, patch_load_u32
1749   ror $2, $2, 8                   # rotate value by 8bits
1750
1751 execute_load_open_u32u1:
1752   open_load32_align32 2, 1, patch_load_u32
1753   ror $2, $2, 8                   # rotate value by 8bits
1754
1755
1756 # Unsigned unaligned (by 2) 32bit load handlers
1757
1758 execute_load_bios_u32u2:
1759   region_check_align 0, 2, 2, patch_load_u32
1760   srl $2, $4, 14                  # check if address is in BIOS region
1761   bne $2, $0, 2f                  # if not, perform open read
1762   srl $1, $5, 14                  # check if PC is in BIOS region
1763   bne $1, $0, 1f                  # if not, perform BIOS protected read
1764   lui $2, %hi(bios_rom)           # generate upper address (delay)
1765
1766   andi $4, $4, 0x3FFC             # generate offset
1767   addu $2, $2, $4
1768   load_u32_unaligned bios_rom, 2
1769
1770 1:
1771   lui $2, %hi(bios_read_protect)  # generate upper address
1772   load_u32_unaligned bios_read_protect, 2
1773
1774 2:
1775   open_load32_core
1776   ror $2, $2, 16
1777
1778 execute_load_ewram_u32u2:
1779   translate_region_ewram_load_align32 2, 2, patch_load_u32
1780   load_u32_unaligned (ewram + 0x8000), 2
1781
1782 execute_load_iwram_u32u2:
1783   translate_region_align 3, 2, 2, patch_load_u32, (iwram + 0x8000), 0x7FFC
1784   load_u32_unaligned (iwram + 0x8000), 2
1785
1786 execute_load_io_u32u2:
1787   translate_region_align 4, 2, 2, patch_load_u32, io_registers, 0x3FC
1788   load_u32_unaligned io_registers, 2
1789
1790 execute_load_palette_u32u2:
1791   translate_region_align 5, 2, 2, patch_load_u32, palette_ram, 0x3FC
1792   load_u32_unaligned palette_ram, 2
1793
1794 execute_load_vram_u32u2:
1795   translate_region_vram_load_align32 2, 2, patch_load_u32
1796   load_u32_unaligned vram, 2
1797
1798 execute_load_oam_u32u2:
1799   translate_region_align 7, 2, 2, patch_load_u32, oam_ram, 0x3FC
1800   load_u32_unaligned oam_ram, 2
1801
1802 execute_load_gamepak8_u32u2:
1803   translate_region_gamepak_align32 8, 2, 2, patch_load_u32
1804   load_u32_unaligned 0, 2
1805
1806 execute_load_gamepak9_u32u2:
1807   translate_region_gamepak_align32 9, 2, 2, patch_load_u32
1808   load_u32_unaligned 0, 2
1809
1810 execute_load_gamepakA_u32u2:
1811   translate_region_gamepak_align32 10, 2, 2, patch_load_u32
1812   load_u32_unaligned 0, 2
1813
1814 execute_load_gamepakB_u32u2:
1815   translate_region_gamepak_align32 11, 2, 2, patch_load_u32
1816   load_u32_unaligned 0, 2
1817
1818 execute_load_gamepakC_u32u2:
1819   translate_region_gamepak_align32 12, 2, 2, patch_load_u32
1820   load_u32_unaligned 0, 2
1821
1822 execute_load_eeprom_u32u2:
1823   eeprom_load_align32 2, 2, patch_load_u32
1824
1825 execute_load_backup_u32u2:
1826   backup_load_align32 2, 2, patch_load_u32
1827   ror $2, $2, 16                   # rotate value by 16bits
1828
1829 execute_load_open_u32u2:
1830   open_load32_align32 2, 2, patch_load_u32
1831   ror $2, $2, 16                   # rotate value by 16bits
1832
1833 # Unsigned unaligned (by 1) 32bit load handlers
1834
1835 execute_load_bios_u32u3:
1836   region_check_align 0, 2, 3, patch_load_u32
1837   srl $2, $4, 14                  # check if address is in BIOS region
1838   bne $2, $0, 2f                  # if not, perform open read
1839   srl $1, $5, 14                  # check if PC is in BIOS region
1840   bne $1, $0, 1f                  # if not, perform BIOS protected read
1841   lui $2, %hi(bios_rom)           # generate upper address (delay)
1842
1843   andi $4, $4, 0x3FFC             # generate offset
1844   addu $2, $2, $4
1845   load_u32_unaligned bios_rom, 3
1846
1847 1:
1848   lui $2, %hi(bios_read_protect)  # generate upper address
1849   load_u32_unaligned bios_read_protect, 3
1850
1851 2:
1852   open_load32_core
1853   ror $2, $2, 24
1854
1855 execute_load_ewram_u32u3:
1856   translate_region_ewram_load_align32 2, 3, patch_load_u32
1857   load_u32_unaligned (ewram + 0x8000), 3
1858
1859 execute_load_iwram_u32u3:
1860   translate_region_align 3, 2, 3, patch_load_u32, (iwram + 0x8000), 0x7FFC
1861   load_u32_unaligned (iwram + 0x8000), 3
1862
1863 execute_load_io_u32u3:
1864   translate_region_align 4, 2, 3, patch_load_u32, io_registers, 0x3FC
1865   load_u32_unaligned io_registers, 3
1866
1867 execute_load_palette_u32u3:
1868   translate_region_align 5, 2, 3, patch_load_u32, palette_ram, 0x3FC
1869   load_u32_unaligned palette_ram, 3
1870
1871 execute_load_vram_u32u3:
1872   translate_region_vram_load_align32 2, 3, patch_load_u32
1873   load_u32_unaligned vram, 3
1874
1875 execute_load_oam_u32u3:
1876   translate_region_align 7, 2, 3, patch_load_u32, oam_ram, 0x3FC
1877   load_u32_unaligned oam_ram, 3
1878
1879 execute_load_gamepak8_u32u3:
1880   translate_region_gamepak_align32 8, 2, 3, patch_load_u32
1881   load_u32_unaligned 0, 3
1882
1883 execute_load_gamepak9_u32u3:
1884   translate_region_gamepak_align32 9, 2, 3, patch_load_u32
1885   load_u32_unaligned 0, 3
1886
1887 execute_load_gamepakA_u32u3:
1888   translate_region_gamepak_align32 10, 2, 3, patch_load_u32
1889   load_u32_unaligned 0, 3
1890
1891 execute_load_gamepakB_u32u3:
1892   translate_region_gamepak_align32 11, 2, 3, patch_load_u32
1893   load_u32_unaligned 0, 3
1894
1895 execute_load_gamepakC_u32u3:
1896   translate_region_gamepak_align32 12, 2, 3, patch_load_u32
1897   load_u32_unaligned 0, 3
1898
1899 execute_load_eeprom_u32u3:
1900   eeprom_load_align32 2, 3, patch_load_u32
1901
1902 execute_load_backup_u32u3:
1903   backup_load_align32 2, 3, patch_load_u32
1904   ror $2, $2, 24                  # rotate value by 24bits
1905
1906 execute_load_open_u32u3:
1907   open_load32_align32 2, 3, patch_load_u32
1908   ror $2, $2, 24                  # rotate value by 24bits
1909
1910
1911 load_u32_ftable:
1912   .long execute_load_bios_u32     # 0x00 BIOS
1913   .long execute_load_open_u32     # 0x01 open address
1914   .long execute_load_ewram_u32    # 0x02 EWRAM
1915   .long execute_load_iwram_u32    # 0x03 IWRAM
1916   .long execute_load_io_u32       # 0x04 I/O registers
1917   .long execute_load_palette_u32  # 0x05 Palette RAM
1918   .long execute_load_vram_u32     # 0x06 VRAM
1919   .long execute_load_oam_u32      # 0x07 OAM RAM
1920   .long execute_load_gamepak8_u32 # 0x08 gamepak
1921   .long execute_load_gamepak9_u32 # 0x09 gamepak
1922   .long execute_load_gamepakA_u32 # 0x0A gamepak
1923   .long execute_load_gamepakB_u32 # 0x0B gamepak
1924   .long execute_load_gamepakC_u32 # 0x0C gamepak
1925
1926   .long execute_load_eeprom_u32   # 0x0D gamepak/eeprom
1927   .long execute_load_backup_u32   # 0x0E Flash ROM/SRAM
1928   .long execute_load_open_u32     # 0x0F open
1929
1930   .long execute_load_bios_u32u1     # 0x00 BIOS unaligned (1b)
1931   .long execute_load_open_u32u1     # 0x01 open address unaligned (1b)
1932   .long execute_load_ewram_u32u1    # 0x02 EWRAM unaligned (1b)
1933   .long execute_load_iwram_u32u1    # 0x03 IWRAM unaligned (1b)
1934   .long execute_load_io_u32u1       # 0x04 I/O registers unaligned (1b)
1935   .long execute_load_palette_u32u1  # 0x05 Palette RAM unaligned (1b)
1936   .long execute_load_vram_u32u1     # 0x06 VRAM unaligned (1b)
1937   .long execute_load_oam_u32u1      # 0x07 OAM RAM unaligned (1b)
1938   .long execute_load_gamepak8_u32u1 # 0x08 gamepak unaligned (1b)
1939   .long execute_load_gamepak9_u32u1 # 0x09 gamepak unaligned (1b)
1940   .long execute_load_gamepakA_u32u1 # 0x0A gamepak unaligned (1b)
1941   .long execute_load_gamepakB_u32u1 # 0x0B gamepak unaligned (1b)
1942   .long execute_load_gamepakC_u32u1 # 0x0C gamepak unaligned (1b)
1943   .long execute_load_eeprom_u32u1   # 0x0D gamepak/eeprom unaligned (1b)
1944   .long execute_load_backup_u32u1   # 0x0E Flash ROM/SRAM unaligned (1b)
1945   .long execute_load_open_u32u1     # 0x0F open unaligned (1b)
1946
1947   .long execute_load_bios_u32u2     # 0x00 BIOS unaligned (2b)
1948   .long execute_load_open_u32u2     # 0x01 open address unaligned (2b)
1949   .long execute_load_ewram_u32u2    # 0x02 EWRAM unaligned (2b)
1950   .long execute_load_iwram_u32u2    # 0x03 IWRAM unaligned (2b)
1951   .long execute_load_io_u32u2       # 0x04 I/O registers unaligned (2b)
1952   .long execute_load_palette_u32u2  # 0x05 Palette RAM unaligned (2b)
1953   .long execute_load_vram_u32u2     # 0x06 VRAM unaligned (2b)
1954   .long execute_load_oam_u32u2      # 0x07 OAM RAM unaligned (2b)
1955   .long execute_load_gamepak8_u32u2 # 0x08 gamepak unaligned (2b)
1956   .long execute_load_gamepak9_u32u2 # 0x09 gamepak unaligned (2b)
1957   .long execute_load_gamepakA_u32u2 # 0x0A gamepak unaligned (2b)
1958   .long execute_load_gamepakB_u32u2 # 0x0B gamepak unaligned (2b)
1959   .long execute_load_gamepakC_u32u2 # 0x0C gamepak unaligned (2b)
1960   .long execute_load_eeprom_u32u2   # 0x0D gamepak/eeprom unaligned (2b)
1961   .long execute_load_backup_u32u2   # 0x0E Flash ROM/SRAM unaligned (2b)
1962   .long execute_load_open_u32u2     # 0x0F open unaligned (2b)
1963
1964   .long execute_load_bios_u32u3     # 0x00 BIOS unaligned (3b)
1965   .long execute_load_open_u32u3     # 0x01 open address unaligned (3b)
1966   .long execute_load_ewram_u32u3    # 0x02 EWRAM unaligned (3b)
1967   .long execute_load_iwram_u32u3    # 0x03 IWRAM unaligned (3b)
1968   .long execute_load_io_u32u3       # 0x04 I/O registers unaligned (3b)
1969   .long execute_load_palette_u32u3  # 0x05 Palette RAM unaligned (3b)
1970   .long execute_load_vram_u32u3     # 0x06 VRAM unaligned (3b)
1971   .long execute_load_oam_u32u3      # 0x07 OAM RAM unaligned (3b)
1972   .long execute_load_gamepak8_u32u3 # 0x08 gamepak unaligned (3b)
1973   .long execute_load_gamepak9_u32u3 # 0x09 gamepak unaligned (3b)
1974   .long execute_load_gamepakA_u32u3 # 0x0A gamepak unaligned (3b)
1975   .long execute_load_gamepakB_u32u3 # 0x0B gamepak unaligned (3b)
1976   .long execute_load_gamepakC_u32u3 # 0x0C gamepak unaligned (3b)
1977   .long execute_load_eeprom_u32u3   # 0x0D gamepak/eeprom unaligned (3b)
1978   .long execute_load_backup_u32u3   # 0x0E Flash ROM/SRAM unaligned (3b)
1979   .long execute_load_open_u32u3     # 0x0F open unaligned (3b)
1980
1981 patch_load_u32:
1982   patch_handler_align load_u32_ftable, 2
1983
1984
1985
1986 # Unsigned always aligned 32bit load handlers
1987
1988 execute_load_bios_u32a:
1989   region_check 0, patch_load_u32a
1990   srl $2, $4, 14                  # check if address is in BIOS region
1991   bne $2, $0, 2f                  # if not, perform open read
1992   srl $1, $5, 14                  # check if PC is in BIOS region
1993   bne $1, $0, 1f                  # if not, perform BIOS protected read
1994   lui $2, %hi(bios_rom)           # generate upper address (delay)
1995
1996   andi $4, $4, 0x3FFF             # generate offset
1997   addu $2, $2, $4
1998   load_u32 bios_rom
1999
2000 1:
2001   lui $2, %hi(bios_read_protect)  # generate upper address
2002   load_u32 bios_read_protect
2003
2004 2:
2005   open_load32_a
2006   nop
2007
2008 execute_load_ewram_u32a:
2009   translate_region_ewram patch_load_u32a
2010   load_u32 (ewram + 0x8000)
2011
2012 execute_aligned_load32:
2013 execute_load_iwram_u32a:
2014   translate_region 3, patch_load_u32a, (iwram + 0x8000), 0x7FFF
2015   load_u32 (iwram + 0x8000)
2016
2017 execute_load_io_u32a:
2018   translate_region 4, patch_load_u32a, io_registers, 0x3FF
2019   load_u32 io_registers
2020
2021 execute_load_palette_u32a:
2022   translate_region 5, patch_load_u32a, palette_ram, 0x3FF
2023   load_u32 palette_ram
2024
2025 execute_load_vram_u32a:
2026   translate_region_vram patch_load_u32a
2027   load_u32 vram
2028
2029 execute_load_oam_u32a:
2030   translate_region 7, patch_load_u32a, oam_ram, 0x3FF
2031   load_u32 oam_ram
2032
2033 execute_load_gamepak8_u32a:
2034   translate_region_gamepak_a 8, patch_load_u32a
2035   load_u32 0
2036
2037 execute_load_gamepak9_u32a:
2038   translate_region_gamepak_a 9, patch_load_u32a
2039   load_u32 0
2040
2041 execute_load_gamepakA_u32a:
2042   translate_region_gamepak_a 10, patch_load_u32a
2043   load_u32 0
2044
2045 execute_load_gamepakB_u32a:
2046   translate_region_gamepak_a 11, patch_load_u32a
2047   load_u32 0
2048
2049 execute_load_gamepakC_u32a:
2050   translate_region_gamepak_a 12, patch_load_u32a
2051   load_u32 0
2052
2053 execute_load_eeprom_u32a:
2054   eeprom_load_a patch_load_u32a
2055
2056 execute_load_backup_u32a:
2057   backup_load_a patch_load_u32a
2058   nop
2059
2060 execute_load_open_u32a:
2061   open_load32_a patch_load_u32a
2062
2063 load_u32a_ftable:
2064   .long execute_load_bios_u32a      # 0x00 BIOS unaligned (3b)
2065   .long execute_load_open_u32a      # 0x01 open address unaligned (3b)
2066   .long execute_load_ewram_u32a     # 0x02 EWRAM unaligned (3b)
2067   .long execute_load_iwram_u32a     # 0x03 IWRAM unaligned (3b)
2068   .long execute_load_io_u32a        # 0x04 I/O registers unaligned (3b)
2069   .long execute_load_palette_u32a   # 0x05 Palette RAM unaligned (3b)
2070   .long execute_load_vram_u32a      # 0x06 VRAM unaligned (3b)
2071   .long execute_load_oam_u32a       # 0x07 OAM RAM unaligned (3b)
2072   .long execute_load_gamepak8_u32a  # 0x08 gamepak unaligned (3b)
2073   .long execute_load_gamepak9_u32a  # 0x09 gamepak unaligned (3b)
2074   .long execute_load_gamepakA_u32a  # 0x0A gamepak unaligned (3b)
2075   .long execute_load_gamepakB_u32a  # 0x0B gamepak unaligned (3b)
2076   .long execute_load_gamepakC_u32a  # 0x0C gamepak unaligned (3b)
2077   .long execute_load_eeprom_u32a    # 0x0D gamepak/eeprom unaligned (3b)
2078   .long execute_load_backup_u32a    # 0x0E Flash ROM/SRAM unaligned (3b)
2079   .long execute_load_open_u32a      # 0x0F open unaligned (3b)
2080
2081 patch_load_u32a:
2082   patch_handler load_u32a_ftable, 1
2083
2084
2085 # Unsigned 8bit store handlers
2086
2087 execute_store_ignore0_u8:
2088   ignore_region 0, patch_store_u8
2089
2090 execute_store_ignore1_u8:
2091   ignore_region 1, patch_store_u8
2092
2093 execute_store_ewram_u8:
2094   translate_region_ewram patch_store_u8
2095   store_u8_smc (ewram + 0x8000)
2096
2097 execute_store_u8:
2098 execute_store_iwram_u8:
2099   translate_region 3, patch_store_u8, (iwram + 0x8000), 0x7FFF
2100   store_u8_smc (iwram + 0x8000)
2101
2102 execute_store_io_u8:
2103   region_check 4, patch_store_u8
2104   andi $5, $5, 0xFF               # make value 8bit
2105   andi $4, $4, 0x3FF              # wrap around address
2106   addiu $sp, $sp, -4              # make room on the stack for $ra
2107   sw $ra, ($sp)
2108
2109   save_registers
2110   jal write_io_register8          # write the value out
2111   sw $6, REG_PC($16)              # save the PC (delay slot)
2112   j write_io_epilogue             # handle any state changes
2113   nop
2114
2115 execute_store_palette_u8:
2116   region_check 5, patch_store_u8
2117   lui $2, %hi(palette_ram)        # start loading palette_ram address (delay)
2118   ins $5, $5, 8, 8                # double value
2119   andi $4, $4, 0x3FE              # align palette address
2120   addu $2, $2, $4
2121   sh $5, %lo(palette_ram)($2)     # palette_ram[address] = value
2122   sll $1, $5, 1                   # make green 6bits
2123   ins $1, $0, 0, 6                # make bottom bit 0
2124   ins $1, $5, 0, 5                # insert red channel into $1
2125   lui $2, %hi(palette_ram_converted)
2126   addu $2, $2, $4
2127   jr $ra                          # return
2128   sh $1, %lo(palette_ram_converted)($2)
2129
2130 execute_store_vram_u8:
2131   translate_region_vram_store_align16 patch_store_u8
2132   store_u8_double vram
2133
2134 execute_store_oam_u8:
2135   translate_region 7, patch_store_u8, oam_ram, 0x3FE
2136   lui $1, %hi(oam_update)         # write non-zero to oam_update
2137   sw $1, %lo(oam_update)($1)      # cheap, but this is non-zero
2138   store_u8_double oam_ram
2139
2140 execute_store_ignore8_u8:
2141   ignore_region 8, patch_store_u8
2142
2143 execute_store_ignore9_u8:
2144   ignore_region 9, patch_store_u8
2145
2146 execute_store_ignoreA_u8:
2147   ignore_region 10, patch_store_u8
2148
2149 execute_store_ignoreB_u8:
2150   ignore_region 11, patch_store_u8
2151
2152 execute_store_ignoreC_u8:
2153   ignore_region 12, patch_store_u8
2154
2155 execute_store_eeprom_u8:
2156   store_function write_eeprom, 13, patch_store_u8, 0x3FF
2157
2158 execute_store_backup_u8:
2159   store_function write_backup, 14, patch_store_u8, 0xFFFF
2160
2161 execute_store_ignoreF_u8:
2162   ignore_high patch_store_u8
2163
2164 store_u8_ftable:
2165   .long execute_store_ignore0_u8  # 0x00 BIOS
2166   .long execute_store_ignore1_u8  # 0x01 open address
2167   .long execute_store_ewram_u8    # 0x02 EWRAM
2168   .long execute_store_iwram_u8    # 0x03 IWRAM
2169   .long execute_store_io_u8       # 0x04 I/O registers
2170   .long execute_store_palette_u8  # 0x05 Palette RAM
2171   .long execute_store_vram_u8     # 0x06 VRAM
2172   .long execute_store_oam_u8      # 0x07 OAM RAM
2173   .long execute_store_ignore8_u8  # 0x08 gamepak
2174   .long execute_store_ignore9_u8  # 0x09 gamepak
2175   .long execute_store_ignoreA_u8  # 0x0A gamepak
2176   .long execute_store_ignoreB_u8  # 0x0B gamepak
2177   .long execute_store_ignoreC_u8  # 0x0C gamepak
2178   .long execute_store_eeprom_u8   # 0x0D gamepak/eeprom
2179   .long execute_store_backup_u8   # 0x0E Flash ROM/SRAM
2180   .long execute_store_ignoreF_u8  # 0x0F open address
2181
2182 patch_store_u8:
2183   patch_handler store_u8_ftable, 0x0F
2184
2185
2186 # Unsigned 16bit store handlers
2187
2188 execute_store_ignore0_u16:
2189   ignore_region 0, patch_store_u16
2190
2191 execute_store_ignore1_u16:
2192   ignore_region 1, patch_store_u16
2193
2194 execute_store_ewram_u16:
2195   translate_region_ewram_store_align16 patch_store_u16
2196   store_u16_smc (ewram + 0x8000)
2197
2198 execute_store_u16:
2199 execute_store_iwram_u16:
2200   translate_region 3, patch_store_u16, (iwram + 0x8000), 0x7FFE
2201   store_u16_smc (iwram + 0x8000)
2202
2203 execute_store_io_u16:
2204   region_check 4, patch_store_u16
2205   andi $5, $5, 0xFFFF             # make value 16bit
2206   andi $4, $4, 0x3FE              # wrap around/align address
2207   addiu $sp, $sp, -4              # make room on the stack for $ra
2208   sw $ra, ($sp)
2209
2210   save_registers
2211   jal write_io_register16         # write the value out
2212   sw $6, REG_PC($16)              # save the PC (delay slot)
2213   j write_io_epilogue             # handle any state changes
2214   nop
2215
2216 execute_store_palette_u16:
2217   region_check 5, patch_store_u16
2218   lui $2, %hi(palette_ram)        # start loading palette_ram address (delay)
2219   andi $4, $4, 0x3FE              # wrap/align palette address
2220   addu $2, $2, $4
2221   sh $5, %lo(palette_ram)($2)     # palette_ram[address] = value
2222   sll $1, $5, 1                   # make green 6bits
2223   ins $1, $0, 0, 6                # make bottom bit 0
2224   ins $1, $5, 0, 5                # insert red channel into $1
2225   lui $2, %hi(palette_ram_converted)
2226   addu $2, $2, $4
2227   jr $ra                          # return
2228   sh $1, %lo(palette_ram_converted)($2)
2229
2230 execute_store_vram_u16:
2231   translate_region_vram_store_align16 patch_store_u16
2232   store_u16 vram
2233
2234 execute_store_oam_u16:
2235   translate_region 7, patch_store_u16, oam_ram, 0x3FE
2236   lui $1, %hi(oam_update)         # write non-zero to oam_update
2237   sw $1, %lo(oam_update)($1)      # cheap, but this is non-zero
2238   store_u16 oam_ram
2239
2240 execute_store_rtc_u16:
2241   store_function write_rtc, 8, patch_store_u16, 0xFE
2242
2243 execute_store_ignore9_u16:
2244   ignore_region 9, patch_store_u16
2245
2246 execute_store_ignoreA_u16:
2247   ignore_region 10, patch_store_u16
2248
2249 execute_store_ignoreB_u16:
2250   ignore_region 11, patch_store_u16
2251
2252 execute_store_ignoreC_u16:
2253   ignore_region 12, patch_store_u16
2254
2255 execute_store_eeprom_u16:
2256   store_function write_eeprom, 13, patch_store_u16, 0x3FE
2257
2258 execute_store_ignoreE_u16:
2259   ignore_region 14, patch_store_u16
2260
2261 execute_store_ignoreF_u16:
2262   ignore_high patch_store_u16
2263
2264 store_u16_ftable:
2265   .long execute_store_ignore0_u16 # 0x00 BIOS
2266   .long execute_store_ignore1_u16 # 0x01 open address
2267   .long execute_store_ewram_u16   # 0x02 EWRAM
2268   .long execute_store_iwram_u16   # 0x03 IWRAM
2269   .long execute_store_io_u16      # 0x04 I/O registers
2270   .long execute_store_palette_u16 # 0x05 Palette RAM
2271   .long execute_store_vram_u16    # 0x06 VRAM
2272   .long execute_store_oam_u16     # 0x07 OAM RAM
2273   .long execute_store_rtc_u16     # 0x08 gamepak
2274   .long execute_store_ignore9_u16 # 0x09 gamepak
2275   .long execute_store_ignoreA_u16 # 0x0A gamepak
2276   .long execute_store_ignoreB_u16 # 0x0B gamepak
2277   .long execute_store_ignoreC_u16 # 0x0C gamepak
2278   .long execute_store_eeprom_u16  # 0x0D gamepak/eeprom
2279   .long execute_store_ignoreE_u16 # 0x0E Flash ROM/SRAM
2280   .long execute_store_ignoreF_u16 # 0x0F open address
2281
2282
2283 patch_store_u16:
2284   patch_handler store_u16_ftable, 0x0F
2285
2286
2287
2288
2289 # Unsigned 32bit store handlers
2290
2291 execute_store_ignore0_u32:
2292   ignore_region 0, patch_store_u32
2293
2294 execute_store_ignore1_u32:
2295   ignore_region 1, patch_store_u32
2296
2297 execute_store_ewram_u32:
2298   translate_region_ewram_store_align32 patch_store_u32
2299   store_u32_smc (ewram + 0x8000)
2300
2301 execute_store_u32:
2302 execute_store_iwram_u32:
2303   translate_region 3, patch_store_u32, (iwram + 0x8000), 0x7FFC
2304   store_u32_smc (iwram + 0x8000)
2305
2306 execute_store_io_u32:
2307   region_check 4, patch_store_u32
2308   nop
2309   andi $4, $4, 0x3FC              # wrap around/align address
2310   addiu $sp, $sp, -4              # make room on the stack for $ra
2311   sw $ra, ($sp)
2312
2313   save_registers
2314   jal write_io_register32         # write the value out
2315   sw $6, REG_PC($16)              # save the PC (delay slot)
2316   j write_io_epilogue             # handle any state changes
2317   nop
2318
2319 execute_store_palette_u32:
2320   region_check 5, patch_store_u32
2321   lui $2, %hi(palette_ram)        # start loading palette_ram address (delay)
2322   andi $4, $4, 0x3FC              # wrap/align palette address
2323   addu $2, $2, $4
2324   sw $5, %lo(palette_ram)($2)     # palette_ram[address] = value
2325
2326   sll $1, $5, 1                   # make green 6bits
2327   ins $1, $0, 0, 6                # make bottom bit 0
2328   ins $1, $5, 0, 5                # insert red channel into $1
2329   lui $2, %hi(palette_ram_converted)
2330   addu $2, $2, $4
2331   addiu $2, $2, %lo(palette_ram_converted)
2332   sh $1, ($2)
2333
2334   srl $5, $5, 16                  # shift down to next palette value
2335   sll $1, $5, 1                   # make green 6bits
2336   ins $1, $0, 0, 6                # make bottom bit 0
2337   ins $1, $5, 0, 5                # insert red channel into $1
2338
2339   jr $ra                          # return
2340   sh $1, 2($2)
2341
2342 execute_store_vram_u32:
2343   translate_region_vram_store_align32 patch_store_u32
2344   store_u32 vram
2345
2346 execute_store_oam_u32:
2347   translate_region 7, patch_store_u32, oam_ram, 0x3FC
2348   lui $1, %hi(oam_update)         # write non-zero to oam_update
2349   sw $1, %lo(oam_update)($1)      # cheap, but this is non-zero
2350   store_u32 oam_ram
2351
2352 execute_store_ignore8_u32:
2353   ignore_region 8, patch_store_u32
2354
2355 execute_store_ignore9_u32:
2356   ignore_region 9, patch_store_u32
2357
2358 execute_store_ignoreA_u32:
2359   ignore_region 10, patch_store_u32
2360
2361 execute_store_ignoreB_u32:
2362   ignore_region 11, patch_store_u32
2363
2364 execute_store_ignoreC_u32:
2365   ignore_region 12, patch_store_u32
2366
2367 execute_store_eeprom_u32:
2368   store_function write_eeprom, 13, patch_store_u32, 0x3FC
2369
2370 execute_store_ignoreE_u32:
2371   ignore_region 14, patch_store_u32
2372
2373 execute_store_ignoreF_u32:
2374   ignore_high patch_store_u32
2375
2376 store_u32_ftable:
2377   .long execute_store_ignore0_u32 # 0x00 BIOS
2378   .long execute_store_ignore1_u32 # 0x01 open address
2379   .long execute_store_ewram_u32   # 0x02 EWRAM
2380   .long execute_store_iwram_u32   # 0x03 IWRAM
2381   .long execute_store_io_u32      # 0x04 I/O registers
2382   .long execute_store_palette_u32 # 0x05 Palette RAM
2383   .long execute_store_vram_u32    # 0x06 VRAM
2384   .long execute_store_oam_u32     # 0x07 OAM RAM
2385   .long execute_store_ignore8_u32 # 0x08 gamepak
2386   .long execute_store_ignore9_u32 # 0x09 gamepak
2387   .long execute_store_ignoreA_u32 # 0x0A gamepak
2388   .long execute_store_ignoreB_u32 # 0x0B gamepak
2389   .long execute_store_ignoreC_u32 # 0x0C gamepak
2390   .long execute_store_eeprom_u32  # 0x0D gamepak/eeprom
2391   .long execute_store_ignoreE_u32 # 0x0E Flash ROM/SRAM
2392   .long execute_store_ignoreF_u32 # 0x0F open address
2393
2394
2395 patch_store_u32:
2396   patch_handler store_u32_ftable, 0x0F
2397
2398
2399
2400 # Unsigned always aligned, a2 safe 32bit store handlers
2401
2402 execute_store_ignore0_u32a:
2403   ignore_region 0, patch_store_u32a
2404
2405 execute_store_ignore1_u32a:
2406   ignore_region 1, patch_store_u32a
2407
2408 execute_store_ewram_u32a:
2409   translate_region_ewram_store_align32 patch_store_u32a
2410   store_u32 (ewram + 0x8000)
2411
2412 execute_aligned_store32:
2413 execute_store_iwram_u32a:
2414   translate_region 3, patch_store_u32a, (iwram + 0x8000), 0x7FFC
2415   store_u32 (iwram + 0x8000)
2416
2417 execute_store_io_u32a:
2418   region_check 4, patch_store_u32a
2419   nop
2420   sw $6, REG_SAVE($16)            # save a2
2421   sw $ra, REG_SAVE2($16)          # save ra
2422
2423   andi $4, $4, 0x3FC              # wrap around/align address
2424
2425   save_registers
2426   jal write_io_register32         # write the value out
2427   nop
2428
2429   restore_registers
2430
2431   lw $ra, REG_SAVE2($16)          # restore ra
2432   jr $ra
2433   lw $6, REG_SAVE($16)            # restore a2
2434
2435 execute_store_palette_u32a:
2436   region_check 5, patch_store_u32a
2437   lui $2, %hi(palette_ram)        # start loading palette_ram address (delay)
2438   andi $4, $4, 0x3FC              # wrap/align palette address
2439   addu $2, $2, $4
2440   sw $5, %lo(palette_ram)($2)     # palette_ram[address] = value
2441
2442   sll $1, $5, 1                   # make green 6bits
2443   ins $1, $0, 0, 6                # make bottom bit 0
2444   ins $1, $5, 0, 5                # insert red channel into $1
2445   lui $2, %hi(palette_ram_converted)
2446   addu $2, $2, $4
2447   addiu $2, $2, %lo(palette_ram_converted)
2448   sh $1, ($2)
2449
2450   srl $5, $5, 16                  # shift down to next palette value
2451   sll $1, $5, 1                   # make green 6bits
2452   ins $1, $0, 0, 6                # make bottom bit 0
2453   ins $1, $5, 0, 5                # insert red channel into $1
2454
2455   jr $ra                          # return
2456   sh $1, 2($2)
2457
2458 execute_store_vram_u32a:
2459   translate_region_vram_store_align32 patch_store_u32a
2460   store_u32 vram
2461
2462 execute_store_oam_u32a:
2463   translate_region 7, patch_store_u32a, oam_ram, 0x3FC
2464   lui $1, %hi(oam_update)         # write non-zero to oam_update
2465   sw $1, %lo(oam_update)($1)      # cheap, but this is non-zero
2466   store_u32 oam_ram
2467
2468 execute_store_ignore8_u32a:
2469   ignore_region 8, patch_store_u32a
2470
2471 execute_store_ignore9_u32a:
2472   ignore_region 9, patch_store_u32a
2473
2474 execute_store_ignoreA_u32a:
2475   ignore_region 10, patch_store_u32a
2476
2477 execute_store_ignoreB_u32a:
2478   ignore_region 11, patch_store_u32a
2479
2480 execute_store_ignoreC_u32a:
2481   ignore_region 12, patch_store_u32a
2482
2483 execute_store_eeprom_u32a:
2484   store_function_a write_eeprom, 13, patch_store_u32a, 0x3FC
2485
2486 execute_store_ignoreE_u32a:
2487   ignore_region 14, patch_store_u32a
2488
2489 execute_store_ignoreF_u32a:
2490   ignore_high patch_store_u32a
2491
2492 store_u32a_ftable:
2493   .long execute_store_ignore0_u32a# 0x00 BIOS
2494   .long execute_store_ignore1_u32a# 0x01 open address
2495   .long execute_store_ewram_u32a  # 0x02 EWRAM
2496   .long execute_store_iwram_u32a  # 0x03 IWRAM
2497   .long execute_store_io_u32a     # 0x04 I/O registers
2498   .long execute_store_palette_u32a# 0x05 Palette RAM
2499   .long execute_store_vram_u32a   # 0x06 VRAM
2500   .long execute_store_oam_u32a    # 0x07 OAM RAM
2501   .long execute_store_ignore8_u32a# 0x08 gamepak
2502   .long execute_store_ignore9_u32a# 0x09 gamepak
2503   .long execute_store_ignoreA_u32a# 0x0A gamepak
2504   .long execute_store_ignoreB_u32a# 0x0B gamepak
2505   .long execute_store_ignoreC_u32a# 0x0C gamepak
2506   .long execute_store_eeprom_u32a # 0x0D gamepak/eeprom
2507   .long execute_store_ignoreE_u32a# 0x0E Flash ROM/SRAM
2508   .long execute_store_ignoreF_u32a# 0x0F open address
2509
2510 patch_store_u32a:
2511   patch_handler store_u32a_ftable, 0x0F
2512
2513
2514
2515 #execute_load_u8:
2516 execute_load_full_u8:
2517   srl $1, $4, 28                  # check if the address is out of range
2518   bne $1, $0, ext_load_u8         # if it is, perform an extended read
2519   srl $2, $4, 15                  # $1 = page number of address
2520   sll $2, $2, 2                   # adjust to word index
2521   addu $2, $2, $16                # $1 = memory_map_read[address >> 15]
2522   lw $1, -32768($2)
2523   beq $1, $0, ext_load_u8         # if it's NULL perform an extended read
2524   andi $2, $4, 0x7FFF             # $2 = low 15bits of address (delay slot)
2525   addu $1, $1, $2                 # add the memory map offset
2526   jr $ra                          # return
2527   lbu $2, ($1)                    # read the value
2528
2529 ext_load_u8:
2530   addiu $sp, $sp, -4              # make room on the stack for $ra
2531   sw $ra, ($sp)                   # store return address
2532   save_registers
2533   jal read_memory8                # read the value
2534   nop
2535   restore_registers
2536   lw $ra, ($sp)                   # restore return address
2537   jr $ra                          # return
2538   addiu $sp, $sp, 4               # fix stack (delay slot)
2539
2540 #execute_load_s8:
2541 execute_load_full_s8:
2542   srl $1, $4, 28                  # check if the address is out of range
2543   bne $1, $0, ext_load_s8         # if it is, perform an extended read
2544   srl $2, $4, 15                  # $1 = page number of address
2545   sll $2, $2, 2                   # adjust to word index
2546   addu $2, $2, $16                # $1 = memory_map_read[address >> 15]
2547   lw $1, -32768($2)
2548   beq $1, $0, ext_load_s8         # if it's NULL perform an extended read
2549   andi $2, $4, 0x7FFF             # $2 = low 15bits of address (delay slot)
2550   addu $1, $1, $2                 # add the memory map offset
2551   jr $ra                          # return
2552   lb $2, ($1)                     # read the value
2553
2554 ext_load_s8:
2555   addiu $sp, $sp, -4              # make room on the stack for $ra
2556   sw $ra, ($sp)                   # store return address
2557   save_registers
2558   jal read_memory8                # read the value
2559   nop
2560   restore_registers
2561   seb $2, $2                      # sign extend the read value
2562   lw $ra, ($sp)                   # restore return address
2563   jr $ra                          # return
2564   addiu $sp, $sp, 4               # fix stack (delay slot)
2565
2566 #execute_load_u16:
2567 execute_load_full_u16:
2568   srl $1, $4, 28                  # check if the address is out of range
2569   ins $1, $4, 4, 1                # or unaligned (bottom bit)
2570   bne $1, $0, ext_load_u16        # if it is, perform an extended read
2571   srl $2, $4, 15                  # $1 = page number of address
2572   sll $2, $2, 2                   # adjust to word index
2573   addu $2, $2, $16                # $1 = memory_map_read[address >> 15]
2574   lw $1, -32768($2)
2575   beq $1, $0, ext_load_u16        # if it's NULL perform an extended read
2576   andi $2, $4, 0x7FFF             # $2 = low 15bits of address (delay slot)
2577   addu $1, $1, $2                 # add the memory map offset
2578   jr $ra                          # return
2579   lhu $2, ($1)                    # read the value
2580
2581 ext_load_u16:
2582   addiu $sp, $sp, -4              # make room on the stack for $ra
2583   sw $ra, ($sp)                   # store return address
2584   save_registers
2585   jal read_memory16               # read the value
2586   nop
2587   restore_registers
2588   lw $ra, ($sp)                   # restore return address
2589   jr $ra                          # return
2590   addiu $sp, $sp, 4               # fix stack (delay slot)
2591
2592 #execute_load_s16:
2593 execute_load_full_s16:
2594   srl $1, $4, 28                  # check if the address is out of range
2595   ins $1, $4, 4, 1                # or unaligned (bottom bit)
2596   bne $1, $0, ext_load_s16        # if it is, perform an extended read
2597   srl $2, $4, 15                  # $1 = page number of address
2598   sll $2, $2, 2                   # adjust to word index
2599   addu $2, $2, $16                # $1 = memory_map_read[address >> 15]
2600   lw $1, -32768($2)
2601   beq $1, $0, ext_load_s16        # if it's NULL perform an extended read
2602   andi $2, $4, 0x7FFF             # $2 = low 15bits of address (delay slot)
2603   addu $1, $1, $2                 # add the memory map offset
2604   jr $ra                          # return
2605   lh $2, ($1)                     # read the value
2606
2607 ext_load_s16:
2608   addiu $sp, $sp, -4              # make room on the stack for $ra
2609   sw $ra, ($sp)                   # store return address
2610   save_registers
2611   jal read_memory16_signed        # read the value
2612   nop
2613   restore_registers
2614   seh $2, $2                      # sign extend the return value
2615   lw $ra, ($sp)                   # restore return address
2616   jr $ra                          # return
2617   addiu $sp, $sp, 4               # fix stack (delay slot)
2618
2619 #execute_load_u32:
2620 execute_load_full_u32:
2621   srl $1, $4, 28                  # check if the address is out of range
2622   ins $1, $4, 4, 2                # or unaligned (bottom two bits)
2623   bne $1, $0, ext_load_u32        # if it is, perform an extended read
2624   srl $2, $4, 15                  # $1 = page number of address
2625   sll $2, $2, 2                   # adjust to word index
2626   addu $2, $2, $16                # $1 = memory_map_read[address >> 15]
2627   lw $1, -32768($2)
2628   beq $1, $0, ext_load_u32        # if it's NULL perform an extended read
2629   andi $2, $4, 0x7FFF             # $2 = low 15bits of address (delay slot)
2630   addu $1, $1, $2                 # add the memory map offset
2631   jr $ra                          # return
2632   lw $2, ($1)                     # read the value
2633
2634 ext_load_u32:
2635   addiu $sp, $sp, -4              # make room on the stack for $ra
2636   sw $ra, ($sp)                   # store return address
2637   save_registers
2638   jal read_memory32               # read the value
2639   nop
2640   restore_registers
2641   lw $ra, ($sp)                   # restore return address
2642   jr $ra                          # return
2643   addiu $sp, $sp, 4               # fix stack (delay slot)
2644
2645 #execute_aligned_load32:
2646   srl $2, $4, 28                  # check if the address is out of range
2647   bne $2, $0, ext_aligned_load32  # if it is, perform an extended load
2648   srl $1, $4, 15                  # $1 = page number of address
2649   sll $1, $1, 2                   # adjust to word index
2650   addu $1, $1, $16                # $1 = memory_map_read[address >> 15]
2651   lw $1, -32768($1)
2652   beq $1, $0, ext_aligned_load32  # if it's NULL perform an extended read
2653   andi $2, $4, 0x7FFF             # $2 = low 15bits of address (delay slot)
2654   addu $1, $1, $2                 # add the memory map offset
2655   jr $ra                          # return
2656   lw $2, ($1)                     # read the value
2657
2658 ext_aligned_load32:
2659   addiu $sp, $sp, -8              # make room on the stack for $ra
2660   sw $6, 4($sp)
2661   sw $ra, ($sp)                   # store return address
2662   save_registers
2663   jal read_memory32               # read the value
2664   nop
2665   restore_registers
2666   lw $6, 4($sp)
2667   lw $ra, ($sp)                   # restore return address
2668   jr $ra                          # return
2669   addiu $sp, $sp, 8               # fix stack (delay slot)
2670
2671 # General ext memory routines
2672
2673 ext_store_ignore:
2674   jr $ra                          # ignore these writes
2675   nop
2676
2677 write_io_epilogue:
2678   beq $2, $0, no_alert            # 0 means nothing happened
2679   addiu $4, $2, -2                # see if return value is 2 (delay slot)
2680   beq $4, $0, smc_dma             # is it an SMC alert? (return value = 2)
2681   nop
2682   addiu $4, $2, -3                # see if return value is 3
2683   beq $4, $0, irq_alert           # is it an IRQ alert? (return value = 3)
2684   nop
2685   collapse_flags                  # make sure flags are good for update_gba
2686
2687 alert_loop:
2688   jal update_gba                  # process the next event
2689   nop
2690   lw $1, CPU_HALT_STATE($16)      # check if CPU is sleeping
2691   bne $1, $0, alert_loop          # see if it hasn't changed
2692   nop
2693
2694   addu $17, $2, $0                # $17 = new cycle counter
2695   lw $4, REG_PC($16)              # $4 = new PC
2696
2697   j lookup_pc
2698   addiu $sp, $sp, 4               # fix the stack (delay slot)
2699
2700 irq_alert:
2701   restore_registers
2702   j lookup_pc                     # PC has changed, get a new one
2703   addiu $sp, $sp, 4               # fix the stack
2704
2705 no_alert:
2706   restore_registers
2707   lw $ra, ($sp)                   # restore return address
2708   jr $ra                          # we can return
2709   addiu $sp, $sp, 4               # fix the stack
2710
2711 smc_dma:
2712   addiu $sp, $sp, 4               # fix the stack
2713   jal flush_translation_cache_ram # flush translation cache
2714   nop
2715   j lookup_pc
2716   nop
2717
2718
2719 ext_store_eeprom:
2720   addiu $sp, $sp, -4              # make room on the stack for $ra
2721   sw $ra, ($sp)
2722   save_registers
2723   jal write_eeprom                # write the value out
2724   sw $6, REG_PC($16)              # save the PC (delay slot)
2725   restore_registers
2726   lw $ra, ($sp)                   # restore return address
2727   jr $ra                          # we can return
2728   addiu $sp, $sp, 4               # fix the stack
2729
2730
2731 # 8bit ext memory routines
2732
2733 ext_store_io8:
2734   andi $5, $5, 0xFF               # make value 8bit
2735   andi $4, $4, 0x3FF              # wrap around address
2736   addiu $sp, $sp, -4              # make room on the stack for $ra
2737   sw $ra, ($sp)
2738   save_registers
2739   jal write_io_register8          # write the value out
2740   sw $6, REG_PC($16)              # save the PC (delay slot)
2741   j write_io_epilogue             # handle any state changes
2742   nop
2743
2744 ext_store_palette8:
2745   j ext_store_palette16b          # perform 16bit palette write
2746   andi $4, $4, 0x3FE              # wrap + align (delay)
2747
2748 ext_store_vram8:
2749   ins $5, $5, 8, 8                # value = (value << 8) | value
2750   ext $4, $4, 0, 17               # address = adress & 0x1FFFF
2751   ins $4, $0, 0, 1                # align out bottom bit
2752   lui $1, %hi(0x18000)            # $1 = 0x18000
2753   sltu $1, $4, $1                 # see if address < 0x18000
2754   bne $1, $0, ext_store_vram8b
2755   lui $2, %hi(vram)               # start loading vram address (delay)
2756
2757   addiu $4, $4, -0x8000           # move address into VRAM region
2758
2759 ext_store_vram8b:
2760   addu $2, $2, $4                 # $2 = (hi)vram + address
2761   jr $ra                          # return
2762   sh $5, %lo(vram)($2)            # vram[address] = value (delay)
2763
2764 ext_store_oam8:
2765   lui $1, %hi(oam_update)         # $1 = oam_update
2766   addiu $1, %lo(oam_update)
2767   li $2, 1                        # $2 = 1
2768   sw $2, ($1)                     # *oam_update = 1
2769   andi $4, $4, 0x3FE              # wrap around address and align to 16bits
2770   ins $5, $5, 8, 8                # value = (value << 8) | value
2771   lui $1, %hi(oam_ram)            # $1 = (hi)oam_ram
2772   addu $1, $1, $4                 # $1 = (hi)oam_ram + address
2773   jr $ra                          # return
2774   sh $5, %lo(oam_ram)($1)         # oam_ram[address] = value (delay)
2775
2776 ext_store_backup:
2777   andi $5, $5, 0xFF               # make value 8bit
2778   andi $4, $4, 0xFFFF             # mask value
2779   addiu $sp, $sp, -4              # make room on the stack for $ra
2780   sw $ra, ($sp)
2781   save_registers
2782   jal write_backup                # write the value out
2783   sw $6, REG_PC($16)              # save the PC (delay slot)
2784   restore_registers
2785   lw $ra, ($sp)                   # restore return address
2786   jr $ra                          # we can return
2787   addiu $sp, $sp, 4               # fix the stack
2788
2789 ext_store_u8_jtable:
2790   .long ext_store_ignore  # 0x00 BIOS
2791   .long ext_store_ignore  # 0x01 invalid
2792   .long ext_store_ignore    # 0x02 EWRAM
2793   .long ext_store_ignore    # 0x03 IWRAM
2794   .long ext_store_io8       # 0x04 I/O registers
2795   .long ext_store_palette8  # 0x05 Palette RAM
2796   .long ext_store_vram8     # 0x06 VRAM
2797   .long ext_store_oam8      # 0x07 OAM RAM
2798   .long ext_store_ignore  # 0x08 gamepak (no RTC accepted in 8bit)
2799   .long ext_store_ignore  # 0x09 gamepak, ignore
2800   .long ext_store_ignore  # 0x0A gamepak, ignore
2801   .long ext_store_ignore  # 0x0B gamepak, ignore
2802   .long ext_store_ignore  # 0x0C gamepak, ignore
2803   .long ext_store_eeprom   # 0x0D EEPROM (possibly)
2804   .long ext_store_backup   # 0x0E Flash ROM/SRAM
2805   .long ext_store_ignore  # 0x0F invalid
2806
2807
2808
2809 ext_store_u8:
2810   srl $1, $4, 24                  # $1 = address >> 24
2811   sltu $2, $1, 16                 # check if the value is out of range
2812   beq $2, $0, ext_store_ignore
2813   sll $1, $1, 2                   # make address word indexed (delay)
2814   lui $2, %hi(ext_store_u8_jtable)
2815   addu $2, $2, $1
2816   # $2 = ext_store_u8_jtable[address >> 24]
2817   lw $2, %lo(ext_store_u8_jtable)($2)
2818   jr $2                           # jump to table location
2819   nop
2820
2821 # $4: address to write to
2822 # $5: value to write
2823 # $6: current PC
2824
2825 #execute_store_u8:
2826   srl $1, $4, 28                  # check if the address is out of range
2827   bne $1, $0, ext_store_u8        # if it is, perform an extended write
2828   srl $2, $4, 15                  # $1 = page number of address (delay slot)
2829   sll $2, $2, 2                   # adjust to word index
2830   addu $2, $2, $16
2831   lw $1, 256($2)                  # $1 = memory_map_write[address >> 15]
2832   beq $1, $0, ext_store_u8        # if it's NULL perform an extended write
2833   andi $2, $4, 0x7FFF             # $2 = low 15bits of address (delay slot)
2834   addu $1, $1, $2                 # add the memory map offset
2835   lb $2, -32768($1)               # load the SMC status
2836   bne $2, $0, smc_write           # is there code there?
2837   sb $5, ($1)                     # store the value (delay slot)
2838   jr $ra                          # return
2839   nop
2840
2841 # 16bit ext memory routines
2842
2843 ext_store_io16:
2844   andi $4, $4, 0x3FF              # wrap around address
2845   andi $5, $5, 0xFFFF             # make value 16bit
2846   addiu $sp, $sp, -4              # make room on the stack for $ra
2847   sw $ra, ($sp)
2848   save_registers
2849   jal write_io_register16         # write the value out
2850   sw $6, REG_PC($16)              # save the PC (delay slot)
2851   j write_io_epilogue             # handle any state changes
2852   nop
2853
2854 ext_store_palette16:
2855   andi $4, 0x3FF                  # wrap address
2856
2857 ext_store_palette16b:
2858   lui $2, %hi(palette_ram)
2859   addu $2, $2, $4
2860   sh $5, %lo(palette_ram)($2)     # palette_ram[address] = value
2861   sll $1, $5, 1                   # make green 6bits
2862   ins $1, $0, 0, 6                # make bottom bit 0
2863   ins $1, $5, 0, 5                # insert red channel into $1
2864   lui $2, %hi(palette_ram_converted)
2865   addu $2, $2, $4
2866   jr $ra                          # return
2867   sh $1, %lo(palette_ram_converted)($2)
2868
2869 ext_store_vram16:
2870   ext $4, $4, 0, 17               # address = adress & 0x1FFFF
2871   lui $1, %hi(0x18000)            # $1 = 0x18000
2872   sltu $1, $4, $1                 # see if address < 0x18000
2873   bne $1, $0, ext_store_vram16b
2874   lui $2, %hi(vram)               # start loading vram address (delay)
2875
2876   addiu $4, $4, -0x8000           # move address into VRAM region
2877
2878 ext_store_vram16b:
2879   addu $2, $2, $4                 # $2 = (hi)vram + address
2880   jr $ra                          # return
2881   sh $5, %lo(vram)($2)            # vram[address] = value (delay)
2882
2883 ext_store_oam16:
2884   lui $1, %hi(oam_update)         # $1 = oam_update
2885   addiu $1, %lo(oam_update)
2886   li $2, 1                        # $2 = 1
2887   sw $2, ($1)                     # *oam_update = 1
2888   andi $4, $4, 0x3FF              # wrap around address
2889   lui $1, %hi(oam_ram)            # $1 = (hi)oam_ram
2890   addu $1, $1, $4                 # $1 = (hi)oam_ram + address
2891   jr $ra                          # return
2892   sh $5, %lo(oam_ram)($1)         # oam_ram[address] = value (delay)
2893
2894 ext_store_rtc:
2895   andi $5, $5, 0xFFFF             # make value 16bit
2896   addiu $sp, $sp, -4              # make room on the stack for $ra
2897   sw $ra, ($sp)
2898   save_registers
2899   jal write_rtc                   # write the value out
2900   sw $6, REG_PC($16)              # save the PC (delay slot)
2901   restore_registers
2902   lw $ra, ($sp)                   # restore return address
2903   jr $ra                          # we can return
2904   addiu $sp, $sp, 4               # fix the stack
2905
2906 ext_store_u16_jtable:
2907   .long ext_store_ignore          # 0x00 BIOS, ignore
2908   .long ext_store_ignore          # 0x01 invalid, ignore
2909   .long ext_store_ignore          # 0x02 EWRAM, should have been hit already
2910   .long ext_store_ignore          # 0x03 IWRAM, should have been hit already
2911   .long ext_store_io16            # 0x04 I/O registers
2912   .long ext_store_palette16       # 0x05 Palette RAM
2913   .long ext_store_vram16          # 0x06 VRAM
2914   .long ext_store_oam16           # 0x07 OAM RAM
2915   .long ext_store_rtc             # 0x08 gamepak, RTC
2916   .long ext_store_ignore          # 0x09 gamepak, ignore
2917   .long ext_store_ignore          # 0x0A gamepak, ignore
2918   .long ext_store_ignore          # 0x0B gamepak, ignore
2919   .long ext_store_ignore          # 0x0C gamepak, ignore
2920   .long ext_store_eeprom          # 0x0D EEPROM (possibly)
2921   .long ext_store_ignore          # 0x0E Flash ROM/SRAM
2922
2923 ext_store_u16:
2924   srl $1, $4, 24                  # $1 = address >> 24
2925   sltu $2, $1, 16                 # check if the value is out of range
2926   beq $2, $0, ext_store_ignore
2927   sll $1, $1, 2                   # make address word indexed (delay)
2928   lui $2, %hi(ext_store_u16_jtable)
2929   addu $2, $2, $1
2930   # $2 = ext_store_u16_jtable[address >> 24]
2931   lw $2, %lo(ext_store_u16_jtable)($2)
2932   jr $2                           # jump to table location
2933   nop
2934
2935
2936 #execute_store_u16:
2937   srl $1, $4, 28                  # check if the address is out of range
2938   bne $1, $0, ext_store_u16       # if it is, perform an extended write
2939   srl $2, $4, 15                  # $1 = page number of address (delay slot)
2940   sll $2, $2, 2                   # adjust to word index
2941   addu $2, $2, $16
2942   lw $1, 256($2)                  # $1 = memory_map_write[address >> 15]
2943   beq $1, $0, ext_store_u16       # if it's NULL perform an extended write
2944   andi $2, $4, 0x7FFE             # $2 = low 15bits of address (delay slot)
2945   addu $1, $1, $2                 # add the memory map offset
2946   lh $2, -32768($1)               # load the SMC status
2947   bne $2, $0, smc_write           # is there code there?
2948   sh $5, ($1)                     # store the value (delay slot)
2949   jr $ra                          # return
2950   nop
2951
2952
2953
2954
2955
2956
2957
2958
2959 # 32bit ext memory routines
2960
2961 ext_store_io32:
2962   andi $4, $4, 0x3FF              # wrap around address
2963   addiu $sp, $sp, -4              # make room on the stack for $ra
2964   sw $ra, ($sp)
2965   save_registers
2966   jal write_io_register32         # write the value out
2967   sw $6, REG_PC($16)              # save the PC (delay slot)
2968   j write_io_epilogue             # handle any state changes
2969   nop
2970
2971 ext_store_palette32:
2972   addu $6, $ra, $0                # save return address in $6
2973   jal ext_store_palette16b        # write out palette entry
2974   andi $4, 0x3FF                  # wrap address (delay)
2975   addiu $4, $4, 2                 # go to next location
2976   srl $5, $5, 16                  # shift to next 16bit value
2977   j ext_store_palette16b          # write out next palette entry
2978   addu $ra, $6, $0                # restore return address (delay)
2979
2980 ext_store_vram32:
2981   ext $4, $4, 0, 17               # address = adress & 0x1FFFF
2982   lui $1, %hi(0x18000)            # $1 = 0x18000
2983   sltu $1, $4, $1                 # see if address < 0x18000
2984   bne $1, $0, ext_store_vram32b
2985   lui $2, %hi(vram)               # start loading vram address (delay)
2986
2987   addiu $4, $4, -0x8000           # move address into VRAM region
2988
2989 ext_store_vram32b:
2990   addu $2, $2, $4                 # $2 = (hi)vram + address
2991   jr $ra                          # return
2992   sw $5, %lo(vram)($2)            # vram[address] = value (delay)
2993
2994 ext_store_oam32:
2995   lui $1, %hi(oam_update)         # $1 = oam_update
2996   addiu $1, %lo(oam_update)
2997   li $2, 1                        # $2 = 1
2998   sw $2, ($1)                     # *oam_update = 1
2999   andi $4, $4, 0x3FF              # wrap around address
3000   lui $1, %hi(oam_ram)            # $1 = (hi)oam_ram
3001   addu $1, $1, $4                 # $1 = (hi)oam_ram + address
3002   jr $ra                          # return
3003   sw $5, %lo(oam_ram)($1)         # oam_ram[address] = value (delay)
3004
3005 ext_store_u32_jtable:
3006   .long ext_store_ignore          # 0x00 BIOS, ignore
3007   .long ext_store_ignore          # 0x01 invalid, ignore
3008   .long ext_store_ignore          # 0x02 EWRAM, should have been hit already
3009   .long ext_store_ignore          # 0x03 IWRAM, should have been hit already
3010   .long ext_store_io32            # 0x04 I/O registers
3011   .long ext_store_palette32       # 0x05 Palette RAM
3012   .long ext_store_vram32          # 0x06 VRAM
3013   .long ext_store_oam32           # 0x07 OAM RAM
3014   .long ext_store_ignore          # 0x08 gamepak, ignore
3015   .long ext_store_ignore          # 0x09 gamepak, ignore
3016   .long ext_store_ignore          # 0x0A gamepak, ignore
3017   .long ext_store_ignore          # 0x0B gamepak, ignore
3018   .long ext_store_ignore          # 0x0C gamepak, ignore
3019   .long ext_store_eeprom          # 0x0D EEPROM (possibly)
3020   .long ext_store_ignore          # 0x0E Flash ROM/SRAM
3021
3022 ext_store_u32:
3023   srl $1, $4, 24                  # $1 = address >> 24
3024   sltu $2, $1, 16                 # check if the value is out of range
3025   beq $2, $0, ext_store_ignore
3026   sll $1, $1, 2                   # make address word indexed (delay)
3027   lui $2, %hi(ext_store_u32_jtable)
3028   addu $2, $2, $1
3029   # $2 = ext_store_u32_jtable[address >> 24]
3030   lw $2, %lo(ext_store_u32_jtable)($2)
3031   jr $2                           # jump to table location
3032   nop
3033
3034 #execute_store_u32:
3035 execute_store_full_u32:
3036   srl $1, $4, 28                  # check if the address is out of range
3037   bne $1, $0, ext_store_u32       # if it is, perform an extended write
3038   srl $2, $4, 15                  # $1 = page number of address (delay slot)
3039   sll $2, $2, 2                   # adjust to word index
3040   addu $2, $2, $16
3041   lw $1, 256($2)                  # $1 = memory_map_write[address >> 15]
3042   beq $1, $0, ext_store_u32       # if it's NULL perform an extended write
3043   andi $2, $4, 0x7FFC             # $2 = low 15bits of address (delay slot)
3044   addu $1, $1, $2                 # add the memory map offset
3045   lw $2, -32768($1)               # load the SMC status
3046   bne $2, $0, smc_write           # is there code there?
3047   sw $5, ($1)                     # store the value (delay slot)
3048   jr $ra                          # return
3049   nop
3050
3051
3052 # 32bit ext aligned, non a2 destroying routines
3053
3054 ext_store_io32a:
3055   andi $4, $4, 0x3FF              # wrap around address
3056   addiu $sp, $sp, -4              # make room on the stack for $ra
3057   sw $ra, ($sp)
3058   save_registers
3059   jal write_io_register32         # write the value out
3060   sw $6, REG_SAVE($16)            # save a2
3061   lw $6, REG_SAVE($16)            # restore a2
3062   j write_io_epilogue             # handle any state changes
3063   nop
3064
3065 ext_store_palette32a:
3066   sw $ra, REG_SAVE($16)           # save return address
3067   jal ext_store_palette16b        # write out palette entry
3068   andi $4, 0x3FF                  # wrap address (delay)
3069   addiu $4, $4, 2                 # go to next location
3070   srl $5, $5, 16                  # shift to next 16bit value
3071   j ext_store_palette16b          # write out next palette entry
3072   lw $ra, REG_SAVE($16)           # restore return address (delay)
3073
3074 ext_store_u32a_jtable:
3075   .long ext_store_ignore          # 0x00 BIOS, ignore
3076   .long ext_store_ignore          # 0x01 invalid, ignore
3077   .long ext_store_ignore          # 0x02 EWRAM, should have been hit already
3078   .long ext_store_ignore          # 0x03 IWRAM, should have been hit already
3079   .long ext_store_io32a           # 0x04 I/O registers
3080   .long ext_store_palette32a      # 0x05 Palette RAM
3081   .long ext_store_vram32          # 0x06 VRAM
3082   .long ext_store_oam32           # 0x07 OAM RAM
3083   .long ext_store_ignore          # 0x08 gamepak, ignore
3084   .long ext_store_ignore          # 0x09 gamepak, ignore
3085   .long ext_store_ignore          # 0x0A gamepak, ignore
3086   .long ext_store_ignore          # 0x0B gamepak, ignore
3087   .long ext_store_ignore          # 0x0C gamepak, ignore
3088   .long ext_store_ignore          # 0x0D EEPROM (nothing will write this)
3089   .long ext_store_ignore          # 0x0E Flash ROM/SRAM
3090
3091 ext_aligned_store32:
3092   srl $1, $4, 24                  # $1 = address >> 24
3093   sltu $2, $1, 16                 # check if the value is out of range
3094   beq $2, $0, ext_store_ignore
3095   sll $1, $1, 2                   # make address word indexed (delay)
3096   lui $2, %hi(ext_store_u32a_jtable)
3097   addu $2, $2, $1
3098   # $2 = ext_store_u32a_jtable[address >> 24]
3099   lw $2, %lo(ext_store_u32a_jtable)($2)
3100   jr $2                           # jump to table location
3101   nop
3102
3103 #execute_aligned_store32:
3104   srl $2, $4, 28                  # check if the address is out of range
3105   bne $2, $0, ext_aligned_store32 # if it is, perform an extended load
3106   srl $1, $4, 15                  # $1 = page number of address
3107   sll $1, $1, 2                   # adjust to word index
3108   addu $1, $1, $16                # $1 = memory_map_write[address >> 15]
3109   lw $1, 256($1)
3110   beq $1, $0, ext_aligned_store32 # if it's NULL perform an extended write
3111   andi $2, $4, 0x7FFF             # $2 = low 15bits of address (delay slot)
3112   addu $1, $1, $2                 # add the memory map offset
3113   jr $ra                          # return
3114   sw $5, ($1)                     # write the value
3115
3116 smc_write:
3117   save_registers
3118   jal flush_translation_cache_ram # flush translation cache
3119   sw $6, REG_PC($16)              # save PC (delay slot)
3120
3121 lookup_pc:
3122   lw $2, REG_CPSR($16)            # $2 = cpsr
3123   andi $2, $2, 0x20               # isolate mode bit
3124   beq $2, $0, lookup_pc_arm       # if T bit is zero use arm handler
3125   nop
3126
3127 lookup_pc_thumb:
3128   jal block_lookup_address_thumb  # get Thumb address
3129   lw $4, REG_PC($16)              # load PC as arg 0 (delay slot)
3130   restore_registers
3131   jr $2                           # jump to result
3132   nop
3133
3134 lookup_pc_arm:
3135   jal block_lookup_address_arm    # get ARM address
3136   lw $4, REG_PC($16)              # load PC as arg 0 (delay slot)
3137   restore_registers
3138   jr $2                           # jump to result
3139   nop
3140
3141 # Return the current cpsr
3142
3143 execute_read_cpsr:
3144   collapse_flags                  # fold flags into cpsr, put cpsr into $2
3145   jr $ra                          # return
3146   nop
3147
3148 # Return the current spsr
3149
3150 execute_read_spsr:
3151   lw $1, CPU_MODE($16)            # $1 = cpu_mode
3152   lui $2, %hi(spsr)
3153   sll $1, $1, 2                   # adjust to word offset size
3154   addu $2, $2, $1
3155   jr $ra                          # return
3156   lw $2, %lo(spsr)($2)            # $2 = spsr[cpu_mode] (delay slot)
3157
3158 # Switch into SWI, has to collapse flags
3159 # $4: Current pc
3160
3161 execute_swi:
3162   add $sp, $sp, -4                # push $ra
3163   sw $ra, ($sp)
3164   lui $1, %hi(SUPERVISOR_LR)
3165   sw $4, %lo(SUPERVISOR_LR)($1)   # store next PC in the supervisor's LR
3166   collapse_flags                  # get cpsr in $2
3167   lui $5, %hi(SUPERVISOR_SPSR)
3168   sw $2, %lo(SUPERVISOR_SPSR)($5) # save cpsr in SUPERVISOR_CPSR
3169   ins $2, $0, 0, 6                # zero out bottom 6 bits of CPSR
3170   ori $2, 0x13                    # set mode to supervisor
3171   sw $2, REG_CPSR($16)            # write back CPSR
3172   save_registers
3173   jal set_cpu_mode                # set the CPU mode to supervisor
3174   li $4, 3                        # 3 is supervisor mode (delay slot)
3175   restore_registers
3176   lw $ra, ($sp)                   # pop $ra
3177   jr $ra                          # return
3178   add $sp, $sp, 4                 # fix stack (delay slot)
3179
3180 # $4: pc to restore to
3181 # returns in $4
3182
3183 execute_spsr_restore:
3184   lw $1, CPU_MODE($16)            # $1 = cpu_mode
3185
3186   beq $1, $0, no_spsr_restore     # only restore if the cpu isn't usermode
3187   lui $2, %hi(spsr)               # start loading SPSR (delay)
3188
3189   sll $1, $1, 2                   # adjust to word offset size
3190   addu $2, $2, $1
3191   lw $1, %lo(spsr)($2)            # $1 = spsr[cpu_mode]
3192   sw $1, REG_CPSR($16)            # cpsr = spsr[cpu_mode]
3193   extract_flags_body              # extract flags from $1
3194   addiu $sp, $sp, -4
3195   sw $ra, ($sp)
3196   save_registers
3197   jal execute_spsr_restore_body   # do the dirty work in this C function
3198   nop
3199   restore_registers
3200   addu $4, $2, $0                 # move return value to $4
3201   lw $ra, ($sp)
3202   jr $ra
3203   addiu $sp, $sp, 4
3204
3205 no_spsr_restore:
3206   jr $ra
3207   nop
3208
3209 # $4: new cpsr
3210 # $5: store mask
3211 # $6: current PC
3212
3213 execute_store_cpsr:
3214   and $1, $4, $5                  # $1 = new_cpsr & store_mask
3215   lw $2, REG_CPSR($16)            # $2 = current cpsr
3216   nor $4, $5, $0                  # $4 = ~store_mask
3217   and $2, $2, $4                  # $2 = (cpsr & (~store_mask))
3218   or $1, $1, $2                   # $1 = new cpsr combined with old
3219   extract_flags_body              # extract flags from $1
3220   addiu $sp, $sp, -4
3221   sw $ra, ($sp)
3222   save_registers
3223   jal execute_store_cpsr_body     # do the dirty work in this C function
3224   addu $4, $1, $0                 # load the new CPSR (delay slot)
3225
3226   bne $2, $0, changed_pc_cpsr     # this could have changed the pc
3227   nop
3228
3229   restore_registers
3230
3231   lw $ra, ($sp)
3232   jr $ra
3233   addiu $sp, $sp, 4
3234
3235 changed_pc_cpsr:
3236   jal block_lookup_address_arm    # GBA address is in $4
3237   addu $4, $2, $0                 # load new address in $4 (delay slot)
3238   restore_registers               # restore registers
3239   jr $2                           # jump to the new address
3240   addiu $sp, $sp, 4               # get rid of the old ra (delay slot)
3241
3242
3243 # $4: new spsr
3244 # $5: store mask
3245
3246 execute_store_spsr:
3247   lw $1, CPU_MODE($16)            # $1 = cpu_mode
3248   lui $2, %hi(spsr)
3249   sll $1, $1, 2                   # adjust to word offset size
3250   addu $1, $2, $1
3251   lw $2, %lo(spsr)($1)            # $2 = spsr[cpu_mode]
3252   and $4, $4, $5                  # $4 = new_spsr & store_mask
3253   nor $5, $5, $0                  # $5 = ~store_mask
3254   and $2, $2, $5                  # $2 = (spsr & (~store_mask))
3255   or $4, $4, $2                   # $4 = new spsr combined with old
3256   jr $ra                          # return
3257   sw $4, %lo(spsr)($1)            # spsr[cpu_mode] = $4 (delay slot)
3258
3259 # $4: value
3260 # $5: shift
3261
3262 execute_lsl_flags_reg:
3263   beq $5, $0, lsl_shift_zero      # is the shift zero?
3264   sltiu $1, $5, 32                # $1 = (shift < 32) (delay)
3265   beq $1, $0, lsl_shift_high      # is the shift >= 32?
3266   li $2, 32
3267
3268   subu $2, $2, $5                 # $2 = (32 - shift)
3269   srlv $2, $4, $2                 # $2 = (value >> (32 - shift))
3270   andi $22, $2, 1                 # c flag = (value >> (32 - shift)) & 0x01
3271
3272 lsl_shift_zero:
3273   jr $ra                          # return
3274   sllv $4, $4, $5                 # return (value << shift) (delay)
3275
3276 lsl_shift_high:
3277   sltiu $1, $5, 33                # $1 = (shift < 33) (delay)
3278   bne $1, $0, lsl_shift_done      # jump if shift == 32
3279   andi $22, $4, 1                 # c flag = value & 0x01 (delay)
3280
3281   add $22, $0, $0                 # c flag = 0 otherwise
3282
3283 lsl_shift_done:
3284   jr $ra                          # return
3285   add $4, $0, $0                  # value = 0 no matter what
3286
3287
3288 execute_lsr_flags_reg:
3289   beq $5, $0, lsr_shift_zero      # is the shift zero?
3290   sltiu $1, $5, 32                # $1 = (shift < 32) (delay)
3291   beq $1, $0, lsr_shift_high      # is the shift >= 32?
3292   addiu $2, $5, -1                # $2 = shift - 1 (delay)
3293
3294   srlv $2, $4, $2                 # $2 = (value >> (shift - 1))
3295   andi $22, $2, 1                 # c flag = (value >> (32 - shift)) & 0x01
3296
3297 lsr_shift_zero:
3298   jr $ra                          # return
3299   srlv $4, $4, $5                 # return (value >> shift) (delay)
3300
3301 lsr_shift_high:
3302   sltiu $1, $5, 33                # $1 = (shift < 33) (delay)
3303   bne $1, $0, lsr_shift_done      # jump if shift == 32
3304   srl $22, $4, 31                 # c flag = value >> 31 (delay)
3305
3306   add $22, $0, $0                 # c flag = 0 otherwise
3307
3308 lsr_shift_done:
3309   jr $ra                          # return
3310   add $4, $0, $0                  # value = 0 no matter what
3311
3312
3313 execute_asr_flags_reg:
3314   beq $5, $0, asr_shift_zero      # is the shift zero?
3315   sltiu $1, $5, 32                # $1 = (shift < 32) (delay)
3316   beq $1, $0, asr_shift_high      # is the shift >= 32?
3317   addiu $2, $5, -1                # $2 = shift - 1 (delay)
3318
3319   srlv $2, $4, $2                 # $2 = (value >> (shift - 1))
3320   andi $22, $2, 1                 # c flag = (value >> (32 - shift)) & 0x01
3321
3322 asr_shift_zero:
3323   jr $ra                          # return
3324   srav $4, $4, $5                 # return (value >> shift) (delay)
3325
3326 asr_shift_high:
3327   sra $4, $4, 31                  # value >>= 31
3328   jr $ra                          # return
3329   andi $22, $4, 1                 # c flag = value & 0x01
3330
3331
3332 execute_ror_flags_reg:
3333   beq $5, $0, ror_zero_shift      # is the shift zero?
3334   addiu $1, $5, -1                # $1 = (shift - 1) (delay)
3335
3336   srav $1, $4, $1                 # $1 = (value >> (shift - 1))
3337   andi $22, $1, 1                 # c flag = $1 & 1
3338
3339 ror_zero_shift:
3340   jr $ra                          # return
3341   rotrv $4, $4, $5                # return (value ror shift) delay
3342
3343 # $4: cycle counter argument
3344
3345 execute_arm_translate:
3346   addu $17, $4, $0                # load cycle counter register
3347   lui $16, %hi(reg)               # load base register
3348   addiu $16, %lo(reg)
3349   extract_flags                   # load flag variables
3350
3351   and $1, $1, 0x20                # see if Thumb bit is set in flags
3352
3353   bne $1, $0, 1f
3354   lw $4, REG_PC($16)              # load PC into $4 (delay)
3355
3356   jal block_lookup_address_arm    # lookup initial jump address
3357   nop
3358   restore_registers               # load initial register values
3359   jr $2                           # jump to return
3360   nop
3361
3362 1:
3363   jal block_lookup_address_thumb  # lookup initial jump address
3364   nop
3365   restore_registers               # load initial register values
3366   jr $2                           # jump to return
3367   nop
3368
3369 # sceKernelInvalidateIcacheRange gives me problems, trying this instead
3370 # Invalidates an n byte region starting at the start address
3371 # $4: start location
3372 # $5: length
3373
3374 invalidate_icache_region:
3375   ins $4, $0, 0, 6                # align to 64 bytes
3376   addiu $2, $5, 63                # align up to 64 bytes
3377   srl $2, $2, 6                   # divide by 64
3378   beq $2, $0, done                # exit early on 0
3379   nop
3380
3381 iir_loop:
3382   cache 0x08, ($4)                # hit invalidate icache line
3383   addiu $2, $2, -1                # next loop iteration
3384   bne $2, $0, iir_loop            # loop
3385   addiu $4, $4, 64                # go to next cache line (delay slot)
3386
3387 done:
3388   jr $ra                          # return
3389   nop
3390
3391 # Writes back dcache and invalidates icache.
3392
3393 invalidate_all_cache:
3394   addu $4, $0, $0                 # $4 = 0
3395   addiu $5, $0, 0x4000            # $5 = 0x4000
3396
3397 iac_loop:
3398   cache 0x14, 0($4)               # index invalidate/writeback dcache index
3399   addiu $4, $4, 0x40              # goto next cache line
3400   bne $4, $5, iac_loop            # next iteration
3401   cache 0x04, -0x40($4)           # index invalidate icache index.. maybe?
3402
3403   jr $ra                          # return
3404   nop
3405
3406
3407 step_debug_mips:
3408   addiu $sp, $sp, -4
3409   sw $ra, ($sp)
3410   collapse_flags
3411   save_registers
3412   jal step_debug
3413   addiu $5, $17, 0
3414   restore_registers
3415   lw $ra, ($sp)
3416   jr $ra
3417   addiu $sp, $sp, 4
3418
3419 memory_map_read:
3420   .space 0x8000
3421
3422 reg:
3423   .space 0x100
3424
3425 memory_map_write:
3426   .space 0x8000
3427