Instruction Breakpoint [Vega]
#1
EDIT (7/25/2022): For unknown reasons, this code is having issues on MKWii (problems of IABR being set and 'overusing' Resume button). Code works fine on DBZ BT3. Code will reside in this forum for the time being.

Instruction Breakpoint [Vega]



GCN Port 1 Only

Works for all Wii Games that implement GCN usage. Obviously meant only for real Hardware, code is useless on Dolphin.

This code allows you to set an Instruction Breakpoint on any *Virtual* Address (for noobs: Virtual just means any plain jane address). Once the Breakpoint has been triggered, the game will be halted. At this point, you can press your "Resume" button to continue from the Instruction Breakpoint until you hit the Breakpoint again, thus the game now halts again. The code also has the feature of turning on/off the Instruction BP at any time.

With this code, you can set up an Instruction BP on an address that occurs once every frame, thus having the ability to "Frame-Step" on real Hardware.
  • XXXXXXXX = Instruction BP Address
  • WWWW = Button to Turn On Breakpoint
  • TTTT = Button to Turn Off Breakpoint (there are two TTTT values to fill in, make sure they both match)
  • RRRR = Resume Button (resume Game after a BP hit, but keep the BP on)

Use the WAVEBIRD button values! - https://mariokartwii.com/showthread.php?tid=44

READ THIS: This code is finicky (well at least on MKWii, works perfectly with 0 bugs in DBZ BT3). Sometimes the Instruction BP will refuse to be set (programmer's note: even though I have an isync after all IABR mods in the code...). Best tip to prevent this issue from ever occurring is to never press the Resume or Off button at anytime before you press the On button for its very first time use. Also, none of the buttons have a "one-shot" feature meaning if held down, they are read like "rapid fire". If you hold down the Resume button for "Frame Stepping", you will essentially start corrupting the game. Simply press and quickly release the Resume Button for situations like this, don't hold it down (on DBZ this doesn't matter, I can spam the hell out of the Resume button). If I ever get motivated enough, I'll change all the buttons to be "one-shot". Finally, if the code cannot find the PADRead function for GCN implementation, it will set the screen to a violet color and halt the Wii.

NOTE: This code makes use of the following...
  • Address's 0x800002FE & 800002F4
  • Address's 0x800009EC thru 0x80000A2F
  • Address's 0x80001500 thru 0x8000158F
  • Instruction Address BP Exception Vector
  • Program Exception Vector
  • Decrementer Exception Vector

Make sure no other codes you have equipped are using those items!

Region-Free
040009F0 XXXXXXXX
C0000000 0000000D
3C60CBFE 6063FCB1
3D808000 618C4000
3C00005F 6000B000
7C0903A6 854C0004
816C0004 7D405A78
7C001800 4182001C
4200FFEC 3C60CD80
3C007FFF 6000FF01
90030024 48000000
3C608000 398C0014
918309EC 3C004E80
60000020 900F0000
4E800020 00000000
C0000000 00000015
3C608000 380F0068
900309FC 9421FF80
7D8802A6 BC810008
800309EC 7C0803A6
60630A00 4E800021
3C608000 A0A30A00
70A0WWWW 40820014
70A0TTTT 41A2001C
38000000 4800000C
800309F0 60000003
7C12FBA6 4C00012C
B8810008 7D8803A6
38210080 4E800020
3C608000 800309EC
7C0803A6 60630A00
4E800021 3C608000
A0A30A00 70A0RRRR
40820018 70A0TTTT
4182FFD8 38000001
3C608000 980302FF
7FE00008 4E800020
06000700 0000005C
880002FF 2C000001
38000000 980002FF
41820014 38000001
980002FE 38000064
7C1603A6 38000000
7C12FBA6 800009F4
7C1A03A6 800009F8
7C1B03A6 BB801580
7F8103A6 7FA903A6
7FCFF120 7FE803A6
B8201504 80001500
4C000064 00000000
C2000900 00000007
7C9043A6 7C800026
7C9143A6 888002FE
2C040001 40820018
38800000 988002FE
808009F0 60840003
7C92FBA6 7C9142A6
7C8FF120 00000000
06001300 00000034
BC001500 7FE802A6
7FC00026 7FA902A6
7F8102A6 BF801580
7C1A02A6 900009F4
7C1B02A6 900009F8
800009FC 7C1A03A6
4C000064 00000000

Code creator: Vega

Sources~

======================

#RAM Write (place Instruction BP at EVA 0x800009F0)

======================

#START ASSEMBLY (C0)

#This C0 ASM (only executed once) will use a crude XOR checksum mechanism to find the game's PADRead function

#Set crude/nooby XOR checksum
lis r3, 0xCBFE
ori r3, r3, 0xFCB1

#Set Start Address for Search
lis r12, 0x8000
ori r12, r12, 0x4000

#Set Search Loop Ammount
#817F0000 - 80004000 = 17EC000
#17EC000 / 4 = 5FB000 amount of words to search
lis r0, 0x005F
ori r0, r0, 0xB000
mtctr r0

#Search Loop
search_loop:
lwzu r10, 0x4 (r12)
lwz r11, 0x4 (r12)
xor r0, r10, r11
cmpw r0, r3
beq- found

#Not yet found
bdnz+ search_loop

#If not found, make the screen violet
lis r3, 0xCD80
lis r0, 0x7FFF
ori r0, r0, 0xFF01
stw r0, 0x0024 (r3)
b 0x0 #Halt

#Found it
found:
lis r3, 0x8000
addi r12, r12, 0x14
stw r12, 0x09EC (r3)

#Make it to where this C0 only executes once. We don't need to update the cache. Once next frame occurs and this C0 is executed again, cache will be updated by that time. Thus, C0 code will simply execute just a blr and return back to the Gecko Code Handler
lis r0, 0x4E80
ori r0, r0, 0x0020
stw r0, 0 (r15)

#Typical C0 ending blr. Uncomment this if NOT compiling with PyiiASMH.
#blr

======================

#START ASSEMBLY (C0)

#This C0 ASM will allow the user to turn on/off the IABR. Also there is a 'packet' of code within this C0 code that serves as a landing point (from the IABR exception routine). This packet of code will keep the game 'frozen' and constantly read the output of PADRead to see if the user presses the Resume or Turn-off-IABR button.

#User Fill in Values (FILL THESE IN FOR YOUR NEEDS!!!)
.set button_act, 0x0010 #Z button used for default compilation
.set button_deact, 0x0400 #X button used for default compilation
.set button_resume, 0x0800 #Y button used for default compilation

#IBAR SPR Number, and BE+TE updates for BreakPoint Address
.set IABR, 1010

#Store Location of this C0's Fake exception vector
_start:
lis r3, 0x8000
addi r0, r15, fake_vector_entrypoint_margin #r15 points to start of current C0 which is typical Gecko Code Handler protocol
stw r0, 0x09FC (r3)

#Make Frame
stwu sp, -0x80 (sp)
mflr r12 #r12 doesn't need to be preserved in C0 Codes
stmw r4, 0x8 (sp) #r0 and r3 don't need to be preserved in C0 Codes

#Check IABR Activator/Deactivator; load PADRead func
lwz r0, 0x9EC (r3)
mtlr r0
ori r3, r3, 0x0A00 #Only arg for PADRead, where to dump contents
blrl

#Was activator/de-act at least pressed?
lis r3, 0x8000
lhz r5, 0x0A00 (r3)
andi. r0, r5, button_act
bne- turn_on_iabr
andi. r0, r5, button_deact
beq+ pop_frame

#Deact was pressed. Turn off IABR
li r0, 0
b update_iabr

#Act was pressed. Turn on IABR
turn_on_iabr:
lwz r0, 0x09F0 (r3) #r3 already 0x80000000
ori r0, r0, 3

#Write to IABR
update_iabr:
mtspr IABR, r0
isync

#Pop Frame
pop_frame:
lmw r4, 0x8 (sp)
mtlr r12
addi sp, sp, 0x80

#End C0 (rest of C0 code acts as a fake exception vector for IABR, code below will get executed if IABR gets trigged
blr

#--

#Assembler Macro Equation to get 16-bit Immediate Value for the earlier addi instruction
fake_vector_entrypoint_margin = fake_vector_entrypoint - _start

#Fake exception vector called by IABR
fake_vector_entrypoint:
#Setup Arg and call PADRead
call_pread:
lis r3, 0x8000
lwz r0, 0x9EC (r3)
mtlr r0
ori r3, r3, 0x0A00
blrl

#Was Resume Button at least pressed?
lis r3, 0x8000
lhz r5, 0x0A00 (r3)
andi. r0, r5, button_resume
bne- invoke_program_exc

#Was Deact Button at least pressed?
andi. r0, r5, button_deact
beq+ call_pread

#Set special flag (KEEP IABR OFF) to make sure IABR isnt auto turned back on later after be temped turned off in the Program Exception Vector
li r0, 1
lis r3, 0x8000
stb r0, 0x2FF (r3)

#Button was at least pressed, invoke the Program Exception handler
#This instruction is really neat!
invoke_program_exc:
trap

==========

#START ASSEMBLY (06 String Write)

#This 06 String Write is the code that will be executed in the Program Exception Vector due to the trap instruction from the above C0 code. It will temp turn off IABR, so the instruction (that was BP'd) can be executed. If the user pressed Resume, it will set a special flag for the Decrementer Exception to handle. The Decrementer is set and will break shortly after thee Program Execption has ended.

#Address
#0x700 (Program Exception Vector)

#We arrive here if resume button was pressed because we need zero interrupts plus an ability to jump to other addresses w/o having to use the CTR or LR. Since program exception never gets called under regular circumstances, we can freely write to it in any arbritary sense for w/e we need to do

#SPR Variable Names
.set IABR, 1010

#Check Keep IABR OFF EVA flag if IABR was turned off during fake exception C0 vector
lbz r0, 0x2FF (r0)
cmpwi r0, 1
li r0, 0
stb r0, 0x2FF (r0) #Auto reset flag
beq- skip_dec_stuff

#Set DEC flag in EVA and set Decrementer amount to alarm, which will re-turn on IABR
li r0, 1
stb r0, 0x02FE (r0)
li r0, 100 #Should be enough to where it won't flag before this interrupt ends
mtdec r0

#Temp turn off Instruction BP until DEC exception is called
skip_dec_stuff:
li r0, 0
mtspr IABR, r0 #We don't need as isync afterwards as rfi is instruction-synchronizing

#Place back in address to resume game at (the address IABR/DAR broke on)
lwz r0, 0x09F4 (r0)
mtsrr0 r0

#Place back in original MSR
lwz r0, 0x09F8 (r0)
mtsrr1 r0

#Epilogue for the IABR exception call, restore everything
lmw r28, 0x1580 (r0)
mtxer r28
mtctr r29
mtcr r30
mtlr r31
lmw sp, 0x1504 (r0) #Can't due lmw r0 with a source register of 0
lwz r0, 0x1500 (r0)

#End exception, resume game!
rfi

====================================

#START ASSEMBLY (C2 Insert ASM)

#Yes! this is a C2 Insert ASM Code. This C2 ASM (injected at the Decrementer Exception) will see if the special flag (from Resume button being pressed) is present. If so, it will flip back the IABR on.

#Address
#0x900 (Decrementer Exception Vector)

#This gets called sometime after the Program Exception has ended
#We need a way (w/o interference per say) to turn back on the Instruction BP shortly after the Trap Exception has ended
#We can't do this during the Program Exception or else IABR will just keep re-triggering the moment we leave the Program Exception, thus we end up in an infinite loop
#We can use the Decrementer Exception Vector as long as we have a flag check of some sorts
#SPR Variable Names
.set IABR, 1010

#Default/Original Instruction, backup r4 into spare register #0
mtsprg0 r4

#Backup CR into spare register #1
mfcr r4
mtsprg1 r4

#Check DEC flag in EVA
lbz r4, 0x2FE (r0)
cmpwi r4, 1
bne- end_code

#Reset flag
li r4, 0
stb r4, 0x02FE (r0)

#Turn back on IABR, we don't need as isync afterwards as rfi is instruction-synchronizing
lwz r4, 0x09F0 (r0)
ori r4, r4, 3
mtspr IABR, r4

#Recover CR, don't recover r4 due to original instruction saving it in sprg0, r4 is being overwritten later anyways
end_code:
mfsprg1 r4
mtcr r4

====================================

#START ASSEMBLY (06 String Write)

#This ASM occurs when the BP is hit, and it will save/backup everything, then jump to the 'packet' of code in the C0 code that was explained earlier.

#Address
#0x1300 (IABR Exception Vector)

#Note:
#r0 as source register for load/stores is treated as literal zero

#Backup everything that can be effected
stmw r0, 0x1500 (r0)
mflr r31
mfcr r30
mfctr r29
mfxer r28
stmw r28, 0x1580 (r0)

#Save srr0 (BP address) to 0x800009F4 (physically)
mfsrr0 r0
stw r0, 0x09F4 (r0)

#Save srr1 (breakpoint MSR) to 0x800009F8 (physically)
mfsrr1 r0
stw r0, 0x09F8 (r0)

#Load address to jump to Fake Exception Vector of C0 that initially setup the IABR
lwz r0, 0x09FC (r0)
mtsrr0 r0

#Call fake Vector! Pretty cool to call a function via rfi, ha.
rfi

=====================================
Reply
#2
Short question of curiosity: Would it technically be possible to make a "Memory Breakpoint" Code? Because it seems like I was using MBP feature for most of my codes. I guess this type of Breakpoint is more important when you want to create new codes.
Reply
#3
Yes for sure. I was going to make that too but didn't want to solve the bugs on this code beforehand. The code is buggy because I probably should poll the controller "from scratch" instead of calling PADRead and I should probably be disabling interrupts.

The better solution would be to hijack the console buttons, that way you don't need a GCN. Not too sure how to do that, Palapeli/Scruffy would know how.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)