Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- .NoHeader
- ;; INSERT THIS AT 0x1000
- ;; 3C08B07D lui t0, 0xB07D
- ;; 01006009 jalr t0, t4
- ;; 00000000 nop
- ;; INSERT BELOW AT 0x7CFFFC
- patcher_start:
- dw 0xB07D02C0 ;;! <address of cheat_list>
- ;; 0x7D0000
- ;; Installs general exception handler, router, and code engine
- patcher:
- lui t5, 0xB07D ;; Start of temporary patcher location
- lui t6, 0x8000 ;; Start of cached memory
- li t7, 0x007FFFFF ;; Address mask
- li t8, 0x807C5C00 ;; Permanent code engine location
- addiu t9, t5, -4
- lw t9, 0x0000(t9) ;; Get temporary code lists location (stored before patcher)
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; BOOT-TIME CHEATS
- load_next_boot_cheat:
- ;; Apply boot-time cheats
- lw v0, 0x0000(t9)
- bnez v0, boot_cheat_type ;; if it's equal to zero, we're done with the pre-boot cheats.
- lw v1, 0x0004(t9) ;; t9 = code list location
- beqz v1, install_geh ;; Only gets here if first branch doesn't happen (cheat addr = 0)
- boot_cheat_type:
- addiu t9, t9, 0x0008 ;; t9 = 2 words after code list location
- srl t2, v0, 24 ;; t2 = code type
- addiu at, zero, 0xEE
- beq t2, at, boot_cheat_ee
- addiu at, zero, 0xF0
- and v0, v0, t7
- beq t2, at, boot_cheat_f0
- or v0, v0, t6
- addiu at, zero, 0xF1
- beq t2, at, boot_cheat_f1
- nop
- ;; Fall through, assume FF
- ;; Apply FF code type
- addiu at, zero, 0xFFFC ;; Mask address
- b load_next_boot_cheat
- and t8, v0, at ;; Update permanent code engine location
- boot_cheat_f1:
- ;; Apply F1 code type
- b load_next_boot_cheat
- sh v1, 0x0000(v0)
- boot_cheat_f0:
- ;; Apply F0 code type
- b load_next_boot_cheat
- sb v1, 0x0000(v0)
- boot_cheat_ee:
- ;; Apply EE code type
- lui v0, 0x0040
- sw v0, 0x0318(t6)
- b load_next_boot_cheat
- sw v0, 0x03F0(t6)
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; INSTALLATION
- install_geh:
- ;; Install General Exception Handler
- srl at, t8, 2
- and v0, at, t7
- lui at, 0x0800
- or v0, v0, at
- ;; Installs a jump to the code engine at 0x80000180
- sw v0, 0x0180(t6) ;; v0 = 0x081F1700 -> j 0x807c5c00
- sw zero, 0x0184(t6) ;; nop
- ;; Install code engine to permanent location
- sw t8, 0x0188(t6) ;; Save permanent code engine location
- addiu at, zero, 0x0000 ;;! <lower addr of patcher>
- addiu v0, zero, 0x0158 ;;! <lower addr of code_engine_start>
- addiu v1, zero, 0x02C4 ;;! <lower addr of code_engine_end>
- subu at, v0, at ;; at = patcher length
- subu v1, v1, v0 ;; v1 = code engine length
- addu v0, t5, at ;; v0 = temporary code engine location
- loop_copy_code_engine: ;; Actually do the copying of the code engine to its permanent locatoin
- lw at, 0x0000(v0)
- addiu v1, v1, -4
- sw at, 0x0000(t8)
- addiu v0, v0, 4
- dw 0x1C60FFFB ;; hex for "bgtz v1, 0xFFFB" because our assembler is shit
- addiu t8, t8, 4
- sw t8, 0x018C(t6) ;; Save permanent code list location
- ;; comes right after the nop after the jump to the code engine at the GEH
- loop_copy_code_list:
- ;; Install in-game code list
- lw v0, 0x0000(t9) ;; t9 points to temporary code list location for in-game codes
- lw v1, 0x0004(t9)
- addiu t9, t9, 8
- sw v0, 0x0000(t8) ;; store code list after code engine
- sw v1, 0x0004(t8) ;; ^
- bnez v0, loop_copy_code_list
- addiu t8, t8, 8
- bnez v1, loop_copy_code_list
- nop ;; only continue if both address and data are zero
- ;; Write cache to physical memory and invalidate (GEH)
- ori t0, t6, 0x0180
- addiu at, zero, 0x0010
- loop_cache_invalidate_geh: ;; Iterates 4 times, so 0180 - 018F get updated
- cache 0x19, 0x0000(t0) ;; Data cache hit writeback
- cache 0x10, 0x0000(t0) ;; Instruction cache hit invalidate
- addiu at, at, -4
- bnez at, loop_cache_invalidate_geh
- addiu t0, t0, 4
- ;; Write cache to physical memory and invalidate (code engine + list)
- lw t0, 0x0188(t6)
- subu at, t8, t0
- loop_cache_invalidate_code_engine:
- cache 0x19, 0x0000(t0) ;; Data cache hit writeback
- cache 0x10, 0x0000(t0) ;; Instruction cache hit invalidate
- addiu at, at, -4
- bnez at, loop_cache_invalidate_code_engine
- addiu t0, t0, 4
- ;; Protect GEH via WatchLo/WatchHi
- addiu t0, zero, 0x0181 ;; Watch 0x80000180 for writes
- mtc0 t0, 18 ;; Cp0 WatchLo
- nop
- mtc0 zero, 19 ;; Cp0 WatchHi
- ;; Start game!
- dw 0x3C088034 ;; replace with instructions we replaced
- dw 0x3C090002 ;; ^^
- jr t4
- dw 0x2508A580 ;; ^^
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; CODE ENGINE
- code_engine_start:
- mfc0 k0, 13 ;; Cp0 Cause
- andi k1, k0, 0x1000 ;; Pre-NMI
- bnezl k1, not_nmi ;; If this is an NMI interrupt... do nothing different? (delay slots)
- mtc0 zero, 18 ;; Cp0 WatchLo
- not_nmi:
- andi k0, k0, 0x7C
- addiu k1, zero, 0x5C ;; Watchpoint
- bne k0, k1, run_code_engine
- ;; Watch exception; manipulate register contents
- ;; Changes things to be stored at 0x80000120 instead of GEH assuming they
- mfc0 k1, 14 ;; Cp0 EPC
- lw k1, 0x0000(k1) ;; Load cause instruction
- lui k0, 0x03E0
- and k1, k1, k0 ;; Mask (base) register ;; Register holding offset
- srl k1, k1, 5 ;; Shift it to the "rt" position ;; Upper half of k1 now contains register number
- lui k0, 0x3740 ;; Upper half "ori <reg number contained in k1>, k0, 0x0120"
- or k1, k1, k0
- ori k1, k1, 0x0120 ;; Lower half "ori <reg number contained in k1>, k0, 0x0120"
- lui k0, 0x8000
- lw k0, 0x0188(k0) ;; Load permanent code engine location ;; Stored during installation
- sw k1, 0x0060(k0) ;; Self-modifying code FTW! ;; Place the modified instruction at the placeholder below
- cache 0x19, 0x0060(k0) ;; Data cache hit writeback ;; Cache hit our updated instruction below
- cache 0x10, 0x0060(k0) ;; Instruction cache hit invalidate ;; ^
- lui k0, 0x8000
- nop ;; Short delay for cache sync
- nop
- nop
- nop ;; Placeholder for self-modifying code ;; Offset reg is changed to 0x80000120 here
- dw 0x42000018 ;; Back to game
- run_code_engine:
- ;; Run code engine
- lui k0, 0x8000
- lw k0, 0x0188(k0) ;; k0 now contains the address of the code engine
- addiu k0, k0, -40 ;; We're storing things in the 28 bytes before the code engine (which is safe, I guess...)
- sd v1, 0x0000(k0) ;; Back up registers we clobber
- sd v0, 0x0008(k0)
- sd t9, 0x0010(k0)
- sd t8, 0x0018(k0)
- sd t7, 0x0020(k0)
- ;; Handle cheats
- lui t9, 0x8000
- lw t9, 0x018C(t9) ;; Get code list location
- load_next_ingame_cheat:
- lw v0, 0x0000(t9) ;; Load address
- bnez v0, address_not_zero
- lw v1, 0x0004(t9) ;; Load value
- beqz v1, both_are_zero
- nop
- ;; Address == 0 (TODO)
- b load_next_ingame_cheat
- address_not_zero:
- ;; Address != 0
- addiu t9, t9, 0x0008
- srl t7, v0, 24
- sltiu k1, t7, 0xD0 ;; Code type < 0xD0 ?
- sltiu t8, t7, 0xD4 ;; Code type < 0xD4 ?
- xor k1, k1, t8 ;; k1 = (0xD0 >= code_type < 0xD4)
- addiu t8, zero, 0x50
- bne t7, t8, not_repeater;; Code type != 0x50 ? -> 3
- ;; GS Patch/Repeater
- srl t8, v0, 8
- andi t8, t8, 0x00FF ;; Get address count
- andi t7, v0, 0x00FF ;; Get address increment
- lw v0, 0x0000(t9) ;; Load address
- lw k1, 0x0004(t9) ;; Load value
- addiu t9, t9, 0x0008
- repeater_write_loop:
- sh k1, 0x0000(v0) ;; Repeater/Patch write
- addiu t8, t8, -1
- addu v0, v0, t7
- bnez t8, repeater_write_loop
- addu k1, k1, v1
- b load_next_ingame_cheat
- not_repeater:
- ;; GS RAM write or Conditional
- lui t7, 0x0300
- and t7, v0, t7 ;; Test for 8-bit or 16-bit code type
- li t8, 0xA07FFFFF
- and v0, v0, t8
- lui t8, 0x8000
- beqz k1, gs_ram_write
- or v0, v0, t8 ;; Mask address
- ;; GS Conditional
- sll k1, t7, 7
- beqzl k1, skip_word_write1
- lbu t8, 0x0000(v0) ;; 8-bit conditional
- lhu t8, 0x0000(v0) ;; 16-bit conditional
- skip_word_write1:
- srl t7, t7, 22
- andi t7, t7, 8 ;; Test for equal-to or not-equal-to
- beql v1, t8, load_next_ingame_cheat
- add t9, t9, t7 ;; Add if equal
- xori t7, t7, 8
- b load_next_ingame_cheat
- add t9, t9, t7 ;; Add if not-equal
- gs_ram_write:
- ;; GS RAM write
- sll k1, t7, 7
- beqzl k1, skip_word_write2
- sb v1, 0x0000(v0) ;; Constant 8-bit write
- sh v1, 0x0000(v0) ;; Constant 16-bit write
- skip_word_write2:
- b load_next_ingame_cheat
- both_are_zero:
- ;; Restore registers from our temporary stack, and back to the game!
- ld t7, 0x0020(k0)
- ld t8, 0x0018(k0)
- ld t9, 0x0010(k0)
- ld v0, 0x0008(k0)
- j 0x80000120
- ld v1, 0x0000(k0)
- code_engine_end:
- patcher_end:
- cheat_list:
- ;; BEGIN PRE-BOOT CODES
- dw 0x00000000 ;; END OF LIST
- dw 0x0000
- ;; BEGIN IN-GAME CODES
- dw 0x8133B4D6 ;; Play as glove in Super Mario 64
- dw 0x3C4C
- dw 0x00000000 ;; END OF LIST
- dw 0x0000
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement