revive PC build, support Linux
[gpsp.git] / psp / mips_stub.S
CommitLineData
2823a4c8 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
210mips_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
236mips_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
244mips_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
252mips_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
2771:
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
3081:
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
4521:
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
5191:
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
5681:
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
6911:
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
7191:
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
7581:
759 jal read_memory32 # get instruction at PC
760 addu $4, $5, $4 # a0 = PC
761
7622: # 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
7871:
788 jal read_memory32 # get instruction at PC
789 addu $4, $5, $4 # a0 = PC
790
7912:
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
955execute_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
9671:
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
9722:
973 open_load8_core
974 nop
975
976
977execute_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
984execute_load_u8:
985execute_load_iwram_u8:
986 translate_region 3, patch_load_u8, (iwram + 0x8000), 0x7FFF
987 load_u8 (iwram + 0x8000)
988
989execute_load_io_u8:
990 translate_region 4, patch_load_u8, io_registers, 0x3FF
991 load_u8 io_registers
992
993execute_load_palette_u8:
994 translate_region 5, patch_load_u8, palette_ram, 0x3FF
995 load_u8 palette_ram
996
997execute_load_vram_u8:
998 translate_region_vram patch_load_u8
999 load_u8 vram
1000
1001execute_load_oam_u8:
1002 translate_region 7, patch_load_u8, oam_ram, 0x3FF
1003 load_u8 oam_ram
1004
1005execute_load_gamepak8_u8:
1006 translate_region_gamepak 8, patch_load_u8
1007 load_u8 0
1008
1009execute_load_gamepak9_u8:
1010 translate_region_gamepak 9, patch_load_u8
1011 load_u8 0
1012
1013execute_load_gamepakA_u8:
1014 translate_region_gamepak 10, patch_load_u8
1015 load_u8 0
1016
1017execute_load_gamepakB_u8:
1018 translate_region_gamepak 11, patch_load_u8
1019 load_u8 0
1020
1021execute_load_gamepakC_u8:
1022 translate_region_gamepak 12, patch_load_u8
1023 load_u8 0
1024
1025execute_load_eeprom_u8:
1026 eeprom_load patch_load_u8
1027
1028execute_load_backup_u8:
1029 backup_load patch_load_u8
1030 nop
1031
1032execute_load_open_u8:
1033 open_load8 patch_load_u8
1034 nop
1035
1036load_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
1054patch_load_u8:
1055 patch_handler load_u8_ftable, 0x01
1056
1057
1058
1059# Signed 8bit load handlers
1060
1061execute_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
10731:
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
10782:
1079 open_load8_core
1080 seb $2, $2
1081
1082
1083execute_load_ewram_s8:
1084 translate_region_ewram patch_load_s8
1085 load_s8 (ewram + 0x8000)
1086
1087execute_load_s8:
1088execute_load_iwram_s8:
1089 translate_region 3, patch_load_s8, (iwram + 0x8000), 0x7FFF
1090 load_s8 (iwram + 0x8000)
1091
1092execute_load_io_s8:
1093 translate_region 4, patch_load_s8, io_registers, 0x3FF
1094 load_s8 io_registers
1095
1096execute_load_palette_s8:
1097 translate_region 5, patch_load_s8, palette_ram, 0x3FF
1098 load_s8 palette_ram
1099
1100execute_load_vram_s8:
1101 translate_region_vram patch_load_s8
1102 load_s8 vram
1103
1104execute_load_oam_s8:
1105 translate_region 7, patch_load_s8, oam_ram, 0x3FF
1106 load_s8 oam_ram
1107
1108execute_load_gamepak8_s8:
1109 translate_region_gamepak 8, patch_load_s8
1110 load_s8 0
1111
1112execute_load_gamepak9_s8:
1113 translate_region_gamepak 9, patch_load_s8
1114 load_s8 0
1115
1116execute_load_gamepakA_s8:
1117 translate_region_gamepak 10, patch_load_s8
1118 load_s8 0
1119
1120execute_load_gamepakB_s8:
1121 translate_region_gamepak 11, patch_load_s8
1122 load_s8 0
1123
1124execute_load_gamepakC_s8:
1125 translate_region_gamepak 12, patch_load_s8
1126 load_s8 0
1127
1128execute_load_eeprom_s8:
1129 eeprom_load patch_load_s8
1130
1131execute_load_backup_s8:
1132 backup_load patch_load_s8
1133 seb $2, $2 # sign extend result (delay)
1134
1135execute_load_open_s8:
1136 open_load8 patch_load_s8
1137 seb $2, $2 # sign extend result (delay)
1138
1139load_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
1157patch_load_s8:
1158 patch_handler load_s8_ftable, 1
1159
1160
1161
1162# Unsigned aligned 16bit load handlers
1163
1164execute_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
11761:
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
11812:
1182 open_load16_core
1183 nop
1184
1185execute_load_ewram_u16:
1186 translate_region_ewram_load_align 1, 0, patch_load_u16
1187 load_u16 (ewram + 0x8000)
1188
1189execute_load_u16:
1190execute_load_iwram_u16:
1191 translate_region_align 3, 1, 0, patch_load_u16, (iwram + 0x8000), 0x7FFF
1192 load_u16 (iwram + 0x8000)
1193
1194execute_load_io_u16:
1195 translate_region_align 4, 1, 0, patch_load_u16, io_registers, 0x3FF
1196 load_u16 io_registers
1197
1198execute_load_palette_u16:
1199 translate_region_align 5, 1, 0, patch_load_u16, palette_ram, 0x3FF
1200 load_u16 palette_ram
1201
1202execute_load_vram_u16:
1203 translate_region_vram_load_align 1, 0, patch_load_u16
1204 load_u16 vram
1205
1206execute_load_oam_u16:
1207 translate_region_align 7, 1, 0, patch_load_u16, oam_ram, 0x3FF
1208 load_u16 oam_ram
1209
1210execute_load_gamepak8_u16:
1211 translate_region_gamepak_align 8, 1, 0, patch_load_u16
1212 load_u16 0
1213
1214execute_load_gamepak9_u16:
1215 translate_region_gamepak_align 9, 1, 0, patch_load_u16
1216 load_u16 0
1217
1218execute_load_gamepakA_u16:
1219 translate_region_gamepak_align 10, 1, 0, patch_load_u16
1220 load_u16 0
1221
1222execute_load_gamepakB_u16:
1223 translate_region_gamepak_align 11, 1, 0, patch_load_u16
1224 load_u16 0
1225
1226execute_load_gamepakC_u16:
1227 translate_region_gamepak_align 12, 1, 0, patch_load_u16
1228 load_u16 0
1229
1230execute_load_eeprom_u16:
1231 eeprom_load_align 1, 0, patch_load_u16
1232
1233execute_load_backup_u16:
1234 backup_load_align 1, 0, patch_load_u16
1235 nop
1236
1237execute_load_open_u16:
1238 open_load16_align 1, 0, patch_load_u16
1239 nop
1240
1241
1242# Unsigned unaligned 16bit load handlers
1243
1244execute_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
12561:
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
12622:
1263 open_load16_core
1264 ror $2, $2, 8
1265
1266
1267execute_load_ewram_u16u:
1268 translate_region_ewram_load_align16 1, 1, patch_load_u16
1269 load_u16_unaligned (ewram + 0x8000)
1270
1271execute_load_iwram_u16u:
1272 translate_region_align 3, 1, 1, patch_load_u16, (iwram + 0x8000), 0x7FFE
1273 load_u16_unaligned (iwram + 0x8000)
1274
1275execute_load_io_u16u:
1276 translate_region_align 4, 1, 1, patch_load_u16, io_registers, 0x3FE
1277 load_u16_unaligned io_registers
1278
1279execute_load_palette_u16u:
1280 translate_region_align 5, 1, 1, patch_load_u16, palette_ram, 0x3FE
1281 load_u16_unaligned palette_ram
1282
1283execute_load_vram_u16u:
1284 translate_region_vram_load_align16 1, 1, patch_load_u16
1285 load_u16_unaligned vram
1286
1287execute_load_oam_u16u:
1288 translate_region_align 7, 1, 1, patch_load_u16, oam_ram, 0x3FE
1289 load_u16_unaligned oam_ram
1290
1291execute_load_gamepak8_u16u:
1292 translate_region_gamepak_align16 8, 1, 1, patch_load_u16
1293 load_u16_unaligned 0
1294
1295execute_load_gamepak9_u16u:
1296 translate_region_gamepak_align16 9, 1, 1, patch_load_u16
1297 load_u16_unaligned 0
1298
1299execute_load_gamepakA_u16u:
1300 translate_region_gamepak_align16 10, 1, 1, patch_load_u16
1301 load_u16_unaligned 0
1302
1303execute_load_gamepakB_u16u:
1304 translate_region_gamepak_align16 11, 1, 1, patch_load_u16
1305 load_u16_unaligned 0
1306
1307execute_load_gamepakC_u16u:
1308 translate_region_gamepak_align16 12, 1, 1, patch_load_u16
1309 load_u16_unaligned 0
1310
1311execute_load_eeprom_u16u:
1312 eeprom_load_align16 1, 1, patch_load_u16
1313
1314execute_load_backup_u16u:
1315 backup_load_align16 1, 1, patch_load_u16
1316 ror $2, $2, 8 # rotate value by 8bits
1317
1318execute_load_open_u16u:
1319 open_load16_align16 1, 1, patch_load_u16
1320 ror $2, $2, 8 # rotate value by 8bits
1321
1322load_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
1395patch_load_u16:
1396 patch_handler_align load_u16_ftable, 1
1397
1398# Signed aligned 16bit load handlers
1399
1400execute_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
14121:
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
14172:
1418 open_load16_core
1419 seh $2, $2
1420
1421
1422execute_load_ewram_s16:
1423 translate_region_ewram_load_align 1, 0, patch_load_s16
1424 load_s16 (ewram + 0x8000)
1425
1426execute_load_s16:
1427execute_load_iwram_s16:
1428 translate_region_align 3, 1, 0, patch_load_s16, (iwram + 0x8000), 0x7FFF
1429 load_s16 (iwram + 0x8000)
1430
1431execute_load_io_s16:
1432 translate_region_align 4, 1, 0, patch_load_s16, io_registers, 0x3FF
1433 load_s16 io_registers
1434
1435execute_load_palette_s16:
1436 translate_region_align 5, 1, 0, patch_load_s16, palette_ram, 0x3FF
1437 load_s16 palette_ram
1438
1439execute_load_vram_s16:
1440 translate_region_vram_load_align 1, 0, patch_load_s16
1441 load_s16 vram
1442
1443execute_load_oam_s16:
1444 translate_region_align 7, 1, 0, patch_load_s16, oam_ram, 0x3FF
1445 load_s16 oam_ram
1446
1447execute_load_gamepak8_s16:
1448 translate_region_gamepak_align 8, 1, 0, patch_load_s16
1449 load_s16 0
1450
1451execute_load_gamepak9_s16:
1452 translate_region_gamepak_align 9, 1, 0, patch_load_s16
1453 load_s16 0
1454
1455execute_load_gamepakA_s16:
1456 translate_region_gamepak_align 10, 1, 0, patch_load_s16
1457 load_s16 0
1458
1459execute_load_gamepakB_s16:
1460 translate_region_gamepak_align 11, 1, 0, patch_load_s16
1461 load_s16 0
1462
1463execute_load_gamepakC_s16:
1464 translate_region_gamepak_align 12, 1, 0, patch_load_s16
1465 load_s16 0
1466
1467execute_load_eeprom_s16:
1468 eeprom_load_align 1, 0, patch_load_s16
1469
1470execute_load_backup_s16:
1471 backup_load_align 1, 0, patch_load_s16
1472 nop
1473
1474execute_load_open_s16:
1475 open_load16_align 1, 0, patch_load_s16
1476 nop
1477
1478
1479# Signed unaligned 16bit load handlers
1480
1481execute_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
14931:
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
14992:
1500 open_load16_core
1501 seb $2, $2
1502
1503execute_load_ewram_s16u:
1504 translate_region_ewram_load_align16 1, 1, patch_load_s16
1505 load_s16_unaligned (ewram + 0x8000)
1506
1507execute_load_iwram_s16u:
1508 translate_region_align 3, 1, 1, patch_load_s16, (iwram + 0x8000), 0x7FFE
1509 load_s16_unaligned (iwram + 0x8000)
1510
1511execute_load_io_s16u:
1512 translate_region_align 4, 1, 1, patch_load_s16, io_registers, 0x3FE
1513 load_s16_unaligned io_registers
1514
1515execute_load_palette_s16u:
1516 translate_region_align 5, 1, 1, patch_load_s16, palette_ram, 0x3FE
1517 load_s16_unaligned palette_ram
1518
1519execute_load_vram_s16u:
1520 translate_region_vram_load_align16 1, 1, patch_load_s16
1521 load_s16_unaligned vram
1522
1523execute_load_oam_s16u:
1524 translate_region_align 7, 1, 1, patch_load_s16, oam_ram, 0x3FE
1525 load_s16_unaligned oam_ram
1526
1527execute_load_gamepak8_s16u:
1528 translate_region_gamepak_align16 8, 1, 1, patch_load_s16
1529 load_s16_unaligned 0
1530
1531execute_load_gamepak9_s16u:
1532 translate_region_gamepak_align16 9, 1, 1, patch_load_s16
1533 load_s16_unaligned 0
1534
1535execute_load_gamepakA_s16u:
1536 translate_region_gamepak_align16 10, 1, 1, patch_load_s16
1537 load_s16_unaligned 0
1538
1539execute_load_gamepakB_s16u:
1540 translate_region_gamepak_align16 11, 1, 1, patch_load_s16
1541 load_s16_unaligned 0
1542
1543execute_load_gamepakC_s16u:
1544 translate_region_gamepak_align16 12, 1, 1, patch_load_s16
1545 load_s16_unaligned 0
1546
1547execute_load_eeprom_s16u:
1548 eeprom_load_align 1, 1, patch_load_s16
1549
1550execute_load_backup_s16u:
1551 backup_load_align 1, 1, patch_load_s16
1552 seb $2, $2 # sign extend result from 8bits
1553
1554execute_load_open_s16u:
1555 open_load16_align 1, 1, patch_load_s16
1556 seb $2, $2 # sign extend result from 8bits
1557
1558load_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
1593patch_load_s16:
1594 patch_handler_align load_s16_ftable, 1
1595
1596
1597
1598# Unsigned aligned 32bit load handlers
1599
1600execute_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
16121:
1613 lui $2, %hi(bios_read_protect) # generate upper address
1614 load_u32 bios_read_protect
1615
16162:
1617 open_load32_core
1618 nop
1619
1620
1621execute_load_ewram_u32:
1622 translate_region_ewram_load_align 2, 0, patch_load_u32
1623 load_u32 (ewram + 0x8000)
1624
1625execute_load_u32:
1626execute_load_iwram_u32:
1627 translate_region_align 3, 2, 0, patch_load_u32, (iwram + 0x8000), 0x7FFF
1628 load_u32 (iwram + 0x8000)
1629
1630execute_load_io_u32:
1631 translate_region_align 4, 2, 0, patch_load_u32, io_registers, 0x3FF
1632 load_u32 io_registers
1633
1634execute_load_palette_u32:
1635 translate_region_align 5, 2, 0, patch_load_u32, palette_ram, 0x3FF
1636 load_u32 palette_ram
1637
1638execute_load_vram_u32:
1639 translate_region_vram_load_align 2, 0, patch_load_u32
1640 load_u32 vram
1641
1642execute_load_oam_u32:
1643 translate_region_align 7, 2, 0, patch_load_u32, oam_ram, 0x3FF
1644 load_u32 oam_ram
1645
1646execute_load_gamepak8_u32:
1647 translate_region_gamepak_align 8, 2, 0, patch_load_u32
1648 load_u32 0
1649
1650execute_load_gamepak9_u32:
1651 translate_region_gamepak_align 9, 2, 0, patch_load_u32
1652 load_u32 0
1653
1654execute_load_gamepakA_u32:
1655 translate_region_gamepak_align 10, 2, 0, patch_load_u32
1656 load_u32 0
1657
1658execute_load_gamepakB_u32:
1659 translate_region_gamepak_align 11, 2, 0, patch_load_u32
1660 load_u32 0
1661
1662execute_load_gamepakC_u32:
1663 translate_region_gamepak_align 12, 2, 0, patch_load_u32
1664 load_u32 0
1665
1666execute_load_eeprom_u32:
1667 eeprom_load_align 2, 0, patch_load_u32
1668
1669execute_load_backup_u32:
1670 backup_load_align 2, 0, patch_load_u32
1671 nop
1672
1673execute_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
1680execute_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
16921:
1693 lui $2, %hi(bios_read_protect) # generate upper address
1694 load_u32_unaligned bios_read_protect, 1
1695
16962:
1697 open_load32_core
1698 ror $2, $2, 8
1699
1700execute_load_ewram_u32u1:
1701 translate_region_ewram_load_align32 2, 1, patch_load_u32
1702 load_u32_unaligned (ewram + 0x8000), 1
1703
1704execute_load_iwram_u32u1:
1705 translate_region_align 3, 2, 1, patch_load_u32, (iwram + 0x8000), 0x7FFC
1706 load_u32_unaligned (iwram + 0x8000), 1
1707
1708execute_load_io_u32u1:
1709 translate_region_align 4, 2, 1, patch_load_u32, io_registers, 0x3FC
1710 load_u32_unaligned io_registers, 1
1711
1712execute_load_palette_u32u1:
1713 translate_region_align 5, 2, 1, patch_load_u32, palette_ram, 0x3FC
1714 load_u32_unaligned palette_ram, 1
1715
1716execute_load_vram_u32u1:
1717 translate_region_vram_load_align32 2, 1, patch_load_u32
1718 load_u32_unaligned vram, 1
1719
1720execute_load_oam_u32u1:
1721 translate_region_align 7, 2, 1, patch_load_u32, oam_ram, 0x3FC
1722 load_u32_unaligned oam_ram, 1
1723
1724execute_load_gamepak8_u32u1:
1725 translate_region_gamepak_align32 8, 2, 1, patch_load_u32
1726 load_u32_unaligned 0, 1
1727
1728execute_load_gamepak9_u32u1:
1729 translate_region_gamepak_align32 9, 2, 1, patch_load_u32
1730 load_u32_unaligned 0, 1
1731
1732execute_load_gamepakA_u32u1:
1733 translate_region_gamepak_align32 10, 2, 1, patch_load_u32
1734 load_u32_unaligned 0, 1
1735
1736execute_load_gamepakB_u32u1:
1737 translate_region_gamepak_align32 11, 2, 1, patch_load_u32
1738 load_u32_unaligned 0, 1
1739
1740execute_load_gamepakC_u32u1:
1741 translate_region_gamepak_align32 12, 2, 1, patch_load_u32
1742 load_u32_unaligned 0, 1
1743
1744execute_load_eeprom_u32u1:
1745 eeprom_load_align32 2, 1, patch_load_u32
1746
1747execute_load_backup_u32u1:
1748 backup_load_align32 2, 1, patch_load_u32
1749 ror $2, $2, 8 # rotate value by 8bits
1750
1751execute_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
1758execute_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
17701:
1771 lui $2, %hi(bios_read_protect) # generate upper address
1772 load_u32_unaligned bios_read_protect, 2
1773
17742:
1775 open_load32_core
1776 ror $2, $2, 16
1777
1778execute_load_ewram_u32u2:
1779 translate_region_ewram_load_align32 2, 2, patch_load_u32
1780 load_u32_unaligned (ewram + 0x8000), 2
1781
1782execute_load_iwram_u32u2:
1783 translate_region_align 3, 2, 2, patch_load_u32, (iwram + 0x8000), 0x7FFC
1784 load_u32_unaligned (iwram + 0x8000), 2
1785
1786execute_load_io_u32u2:
1787 translate_region_align 4, 2, 2, patch_load_u32, io_registers, 0x3FC
1788 load_u32_unaligned io_registers, 2
1789
1790execute_load_palette_u32u2:
1791 translate_region_align 5, 2, 2, patch_load_u32, palette_ram, 0x3FC
1792 load_u32_unaligned palette_ram, 2
1793
1794execute_load_vram_u32u2:
1795 translate_region_vram_load_align32 2, 2, patch_load_u32
1796 load_u32_unaligned vram, 2
1797
1798execute_load_oam_u32u2:
1799 translate_region_align 7, 2, 2, patch_load_u32, oam_ram, 0x3FC
1800 load_u32_unaligned oam_ram, 2
1801
1802execute_load_gamepak8_u32u2:
1803 translate_region_gamepak_align32 8, 2, 2, patch_load_u32
1804 load_u32_unaligned 0, 2
1805
1806execute_load_gamepak9_u32u2:
1807 translate_region_gamepak_align32 9, 2, 2, patch_load_u32
1808 load_u32_unaligned 0, 2
1809
1810execute_load_gamepakA_u32u2:
1811 translate_region_gamepak_align32 10, 2, 2, patch_load_u32
1812 load_u32_unaligned 0, 2
1813
1814execute_load_gamepakB_u32u2:
1815 translate_region_gamepak_align32 11, 2, 2, patch_load_u32
1816 load_u32_unaligned 0, 2
1817
1818execute_load_gamepakC_u32u2:
1819 translate_region_gamepak_align32 12, 2, 2, patch_load_u32
1820 load_u32_unaligned 0, 2
1821
1822execute_load_eeprom_u32u2:
1823 eeprom_load_align32 2, 2, patch_load_u32
1824
1825execute_load_backup_u32u2:
1826 backup_load_align32 2, 2, patch_load_u32
1827 ror $2, $2, 16 # rotate value by 16bits
1828
1829execute_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
1835execute_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
18471:
1848 lui $2, %hi(bios_read_protect) # generate upper address
1849 load_u32_unaligned bios_read_protect, 3
1850
18512:
1852 open_load32_core
1853 ror $2, $2, 24
1854
1855execute_load_ewram_u32u3:
1856 translate_region_ewram_load_align32 2, 3, patch_load_u32
1857 load_u32_unaligned (ewram + 0x8000), 3
1858
1859execute_load_iwram_u32u3:
1860 translate_region_align 3, 2, 3, patch_load_u32, (iwram + 0x8000), 0x7FFC
1861 load_u32_unaligned (iwram + 0x8000), 3
1862
1863execute_load_io_u32u3:
1864 translate_region_align 4, 2, 3, patch_load_u32, io_registers, 0x3FC
1865 load_u32_unaligned io_registers, 3
1866
1867execute_load_palette_u32u3:
1868 translate_region_align 5, 2, 3, patch_load_u32, palette_ram, 0x3FC
1869 load_u32_unaligned palette_ram, 3
1870
1871execute_load_vram_u32u3:
1872 translate_region_vram_load_align32 2, 3, patch_load_u32
1873 load_u32_unaligned vram, 3
1874
1875execute_load_oam_u32u3:
1876 translate_region_align 7, 2, 3, patch_load_u32, oam_ram, 0x3FC
1877 load_u32_unaligned oam_ram, 3
1878
1879execute_load_gamepak8_u32u3:
1880 translate_region_gamepak_align32 8, 2, 3, patch_load_u32
1881 load_u32_unaligned 0, 3
1882
1883execute_load_gamepak9_u32u3:
1884 translate_region_gamepak_align32 9, 2, 3, patch_load_u32
1885 load_u32_unaligned 0, 3
1886
1887execute_load_gamepakA_u32u3:
1888 translate_region_gamepak_align32 10, 2, 3, patch_load_u32
1889 load_u32_unaligned 0, 3
1890
1891execute_load_gamepakB_u32u3:
1892 translate_region_gamepak_align32 11, 2, 3, patch_load_u32
1893 load_u32_unaligned 0, 3
1894
1895execute_load_gamepakC_u32u3:
1896 translate_region_gamepak_align32 12, 2, 3, patch_load_u32
1897 load_u32_unaligned 0, 3
1898
1899execute_load_eeprom_u32u3:
1900 eeprom_load_align32 2, 3, patch_load_u32
1901
1902execute_load_backup_u32u3:
1903 backup_load_align32 2, 3, patch_load_u32
1904 ror $2, $2, 24 # rotate value by 24bits
1905
1906execute_load_open_u32u3:
1907 open_load32_align32 2, 3, patch_load_u32
1908 ror $2, $2, 24 # rotate value by 24bits
1909
1910
1911load_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
1981patch_load_u32:
1982 patch_handler_align load_u32_ftable, 2
1983
1984
1985
1986# Unsigned always aligned 32bit load handlers
1987
1988execute_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
20001:
2001 lui $2, %hi(bios_read_protect) # generate upper address
2002 load_u32 bios_read_protect
2003
20042:
2005 open_load32_a
2006 nop
2007
2008execute_load_ewram_u32a:
2009 translate_region_ewram patch_load_u32a
2010 load_u32 (ewram + 0x8000)
2011
2012execute_aligned_load32:
2013execute_load_iwram_u32a:
2014 translate_region 3, patch_load_u32a, (iwram + 0x8000), 0x7FFF
2015 load_u32 (iwram + 0x8000)
2016
2017execute_load_io_u32a:
2018 translate_region 4, patch_load_u32a, io_registers, 0x3FF
2019 load_u32 io_registers
2020
2021execute_load_palette_u32a:
2022 translate_region 5, patch_load_u32a, palette_ram, 0x3FF
2023 load_u32 palette_ram
2024
2025execute_load_vram_u32a:
2026 translate_region_vram patch_load_u32a
2027 load_u32 vram
2028
2029execute_load_oam_u32a:
2030 translate_region 7, patch_load_u32a, oam_ram, 0x3FF
2031 load_u32 oam_ram
2032
2033execute_load_gamepak8_u32a:
2034 translate_region_gamepak_a 8, patch_load_u32a
2035 load_u32 0
2036
2037execute_load_gamepak9_u32a:
2038 translate_region_gamepak_a 9, patch_load_u32a
2039 load_u32 0
2040
2041execute_load_gamepakA_u32a:
2042 translate_region_gamepak_a 10, patch_load_u32a
2043 load_u32 0
2044
2045execute_load_gamepakB_u32a:
2046 translate_region_gamepak_a 11, patch_load_u32a
2047 load_u32 0
2048
2049execute_load_gamepakC_u32a:
2050 translate_region_gamepak_a 12, patch_load_u32a
2051 load_u32 0
2052
2053execute_load_eeprom_u32a:
2054 eeprom_load_a patch_load_u32a
2055
2056execute_load_backup_u32a:
2057 backup_load_a patch_load_u32a
2058 nop
2059
2060execute_load_open_u32a:
2061 open_load32_a patch_load_u32a
2062
2063load_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
2081patch_load_u32a:
2082 patch_handler load_u32a_ftable, 1
2083
2084
2085# Unsigned 8bit store handlers
2086
2087execute_store_ignore0_u8:
2088 ignore_region 0, patch_store_u8
2089
2090execute_store_ignore1_u8:
2091 ignore_region 1, patch_store_u8
2092
2093execute_store_ewram_u8:
2094 translate_region_ewram patch_store_u8
2095 store_u8_smc (ewram + 0x8000)
2096
2097execute_store_u8:
2098execute_store_iwram_u8:
2099 translate_region 3, patch_store_u8, (iwram + 0x8000), 0x7FFF
2100 store_u8_smc (iwram + 0x8000)
2101
2102execute_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
2115execute_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
2130execute_store_vram_u8:
2131 translate_region_vram_store_align16 patch_store_u8
2132 store_u8_double vram
2133
2134execute_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
2140execute_store_ignore8_u8:
2141 ignore_region 8, patch_store_u8
2142
2143execute_store_ignore9_u8:
2144 ignore_region 9, patch_store_u8
2145
2146execute_store_ignoreA_u8:
2147 ignore_region 10, patch_store_u8
2148
2149execute_store_ignoreB_u8:
2150 ignore_region 11, patch_store_u8
2151
2152execute_store_ignoreC_u8:
2153 ignore_region 12, patch_store_u8
2154
2155execute_store_eeprom_u8:
2156 store_function write_eeprom, 13, patch_store_u8, 0x3FF
2157
2158execute_store_backup_u8:
2159 store_function write_backup, 14, patch_store_u8, 0xFFFF
2160
2161execute_store_ignoreF_u8:
2162 ignore_high patch_store_u8
2163
2164store_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
2182patch_store_u8:
2183 patch_handler store_u8_ftable, 0x0F
2184
2185
2186# Unsigned 16bit store handlers
2187
2188execute_store_ignore0_u16:
2189 ignore_region 0, patch_store_u16
2190
2191execute_store_ignore1_u16:
2192 ignore_region 1, patch_store_u16
2193
2194execute_store_ewram_u16:
2195 translate_region_ewram_store_align16 patch_store_u16
2196 store_u16_smc (ewram + 0x8000)
2197
2198execute_store_u16:
2199execute_store_iwram_u16:
2200 translate_region 3, patch_store_u16, (iwram + 0x8000), 0x7FFE
2201 store_u16_smc (iwram + 0x8000)
2202
2203execute_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
2216execute_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
2230execute_store_vram_u16:
2231 translate_region_vram_store_align16 patch_store_u16
2232 store_u16 vram
2233
2234execute_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
2240execute_store_rtc_u16:
2241 store_function write_rtc, 8, patch_store_u16, 0xFE
2242
2243execute_store_ignore9_u16:
2244 ignore_region 9, patch_store_u16
2245
2246execute_store_ignoreA_u16:
2247 ignore_region 10, patch_store_u16
2248
2249execute_store_ignoreB_u16:
2250 ignore_region 11, patch_store_u16
2251
2252execute_store_ignoreC_u16:
2253 ignore_region 12, patch_store_u16
2254
2255execute_store_eeprom_u16:
2256 store_function write_eeprom, 13, patch_store_u16, 0x3FE
2257
2258execute_store_ignoreE_u16:
2259 ignore_region 14, patch_store_u16
2260
2261execute_store_ignoreF_u16:
2262 ignore_high patch_store_u16
2263
2264store_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
2283patch_store_u16:
2284 patch_handler store_u16_ftable, 0x0F
2285
2286
2287
2288
2289# Unsigned 32bit store handlers
2290
2291execute_store_ignore0_u32:
2292 ignore_region 0, patch_store_u32
2293
2294execute_store_ignore1_u32:
2295 ignore_region 1, patch_store_u32
2296
2297execute_store_ewram_u32:
2298 translate_region_ewram_store_align32 patch_store_u32
2299 store_u32_smc (ewram + 0x8000)
2300
2301execute_store_u32:
2302execute_store_iwram_u32:
2303 translate_region 3, patch_store_u32, (iwram + 0x8000), 0x7FFC
2304 store_u32_smc (iwram + 0x8000)
2305
2306execute_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
2319execute_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
2342execute_store_vram_u32:
2343 translate_region_vram_store_align32 patch_store_u32
2344 store_u32 vram
2345
2346execute_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
2352execute_store_ignore8_u32:
2353 ignore_region 8, patch_store_u32
2354
2355execute_store_ignore9_u32:
2356 ignore_region 9, patch_store_u32
2357
2358execute_store_ignoreA_u32:
2359 ignore_region 10, patch_store_u32
2360
2361execute_store_ignoreB_u32:
2362 ignore_region 11, patch_store_u32
2363
2364execute_store_ignoreC_u32:
2365 ignore_region 12, patch_store_u32
2366
2367execute_store_eeprom_u32:
2368 store_function write_eeprom, 13, patch_store_u32, 0x3FC
2369
2370execute_store_ignoreE_u32:
2371 ignore_region 14, patch_store_u32
2372
2373execute_store_ignoreF_u32:
2374 ignore_high patch_store_u32
2375
2376store_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
2395patch_store_u32:
2396 patch_handler store_u32_ftable, 0x0F
2397
2398
2399
2400# Unsigned always aligned, a2 safe 32bit store handlers
2401
2402execute_store_ignore0_u32a:
2403 ignore_region 0, patch_store_u32a
2404
2405execute_store_ignore1_u32a:
2406 ignore_region 1, patch_store_u32a
2407
2408execute_store_ewram_u32a:
2409 translate_region_ewram_store_align32 patch_store_u32a
2410 store_u32 (ewram + 0x8000)
2411
2412execute_aligned_store32:
2413execute_store_iwram_u32a:
2414 translate_region 3, patch_store_u32a, (iwram + 0x8000), 0x7FFC
2415 store_u32 (iwram + 0x8000)
2416
2417execute_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
2435execute_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
2458execute_store_vram_u32a:
2459 translate_region_vram_store_align32 patch_store_u32a
2460 store_u32 vram
2461
2462execute_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
2468execute_store_ignore8_u32a:
2469 ignore_region 8, patch_store_u32a
2470
2471execute_store_ignore9_u32a:
2472 ignore_region 9, patch_store_u32a
2473
2474execute_store_ignoreA_u32a:
2475 ignore_region 10, patch_store_u32a
2476
2477execute_store_ignoreB_u32a:
2478 ignore_region 11, patch_store_u32a
2479
2480execute_store_ignoreC_u32a:
2481 ignore_region 12, patch_store_u32a
2482
2483execute_store_eeprom_u32a:
2484 store_function_a write_eeprom, 13, patch_store_u32a, 0x3FC
2485
2486execute_store_ignoreE_u32a:
2487 ignore_region 14, patch_store_u32a
2488
2489execute_store_ignoreF_u32a:
2490 ignore_high patch_store_u32a
2491
2492store_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
2510patch_store_u32a:
2511 patch_handler store_u32a_ftable, 0x0F
2512
2513
2514
2515#execute_load_u8:
2516execute_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
2529ext_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:
2541execute_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
2554ext_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:
2567execute_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
2581ext_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:
2593execute_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
2607ext_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:
2620execute_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
2634ext_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
2658ext_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
2673ext_store_ignore:
2674 jr $ra # ignore these writes
2675 nop
2676
2677write_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
2687alert_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
2700irq_alert:
2701 restore_registers
2702 j lookup_pc # PC has changed, get a new one
2703 addiu $sp, $sp, 4 # fix the stack
2704
2705no_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
2711smc_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
2719ext_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
2733ext_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
2744ext_store_palette8:
2745 j ext_store_palette16b # perform 16bit palette write
2746 andi $4, $4, 0x3FE # wrap + align (delay)
2747
2748ext_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
2759ext_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
2764ext_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
2776ext_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
2789ext_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
2809ext_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
2843ext_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
2854ext_store_palette16:
2855 andi $4, 0x3FF # wrap address
2856
2857ext_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
2869ext_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
2878ext_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
2883ext_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
2894ext_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
2906ext_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
2923ext_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
2961ext_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
2971ext_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
2980ext_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
2989ext_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
2994ext_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
3005ext_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
3022ext_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:
3035execute_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
3054ext_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
3065ext_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
3074ext_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
3091ext_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
3116smc_write:
3117 save_registers
3118 jal flush_translation_cache_ram # flush translation cache
3119 sw $6, REG_PC($16) # save PC (delay slot)
3120
3121lookup_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
3127lookup_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
3134lookup_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
3143execute_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
3150execute_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
3161execute_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
3183execute_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
3205no_spsr_restore:
3206 jr $ra
3207 nop
3208
3209# $4: new cpsr
3210# $5: store mask
3211# $6: current PC
3212
3213execute_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
3235changed_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
3246execute_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
3262execute_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
3272lsl_shift_zero:
3273 jr $ra # return
3274 sllv $4, $4, $5 # return (value << shift) (delay)
3275
3276lsl_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
3283lsl_shift_done:
3284 jr $ra # return
3285 add $4, $0, $0 # value = 0 no matter what
3286
3287
3288execute_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
3297lsr_shift_zero:
3298 jr $ra # return
3299 srlv $4, $4, $5 # return (value >> shift) (delay)
3300
3301lsr_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
3308lsr_shift_done:
3309 jr $ra # return
3310 add $4, $0, $0 # value = 0 no matter what
3311
3312
3313execute_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
3322asr_shift_zero:
3323 jr $ra # return
3324 srav $4, $4, $5 # return (value >> shift) (delay)
3325
3326asr_shift_high:
3327 sra $4, $4, 31 # value >>= 31
3328 jr $ra # return
3329 andi $22, $4, 1 # c flag = value & 0x01
3330
3331
3332execute_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
3339ror_zero_shift:
3340 jr $ra # return
3341 rotrv $4, $4, $5 # return (value ror shift) delay
3342
3343# $4: cycle counter argument
3344
3345execute_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
33621:
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
3374invalidate_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
3381iir_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
3387done:
3388 jr $ra # return
3389 nop
3390
3391# Writes back dcache and invalidates icache.
3392
3393invalidate_all_cache:
3394 addu $4, $0, $0 # $4 = 0
3395 addiu $5, $0, 0x4000 # $5 = 0x4000
3396
3397iac_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
3407step_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
3419memory_map_read:
3420 .space 0x8000
3421
3422reg:
3423 .space 0x100
3424
3425memory_map_write:
3426 .space 0x8000
3427