Welcome, Guest |
You have to register before you can post on our site.
|
Online Users |
There are currently 95 online users. » 1 Member(s) | 92 Guest(s) Bing, Google, _Ro
|
Latest Threads |
Show Ice Cube on Online P...
Forum: Online Non-Item
Last Post: _Ro
25 minutes ago
» Replies: 0
» Views: 6
|
CPU Control Cycler [Ro]
Forum: Offline Non-Item
Last Post: _Ro
52 minutes ago
» Replies: 7
» Views: 983
|
Thunder Cloud Effect Modi...
Forum: Offline; Item
Last Post: JerryHatrick
9 hours ago
» Replies: 11
» Views: 1,056
|
MKW Coder/Developer of th...
Forum: Coding & Hacking General Discussion
Last Post: Vega
11 hours ago
» Replies: 10
» Views: 13,797
|
Make it to 10,000
Forum: General Discussion
Last Post: Vega
Yesterday, 08:15 PM
» Replies: 7,338
» Views: 5,668,679
|
Miniturbos and Inside Dri...
Forum: Coding & Hacking General Discussion
Last Post: JerryHatrick
Yesterday, 09:54 AM
» Replies: 1
» Views: 856
|
Code request???
Forum: Code Support / Help / Requests
Last Post: DrTap
01-09-2025, 06:06 PM
» Replies: 3
» Views: 4,946
|
CPUs/Online Players Have ...
Forum: Visual & Sound Effects
Last Post: Zeraora
01-09-2025, 02:26 AM
» Replies: 2
» Views: 501
|
Offline Hide and Seek
Forum: Code Support / Help / Requests
Last Post: FelX
01-08-2025, 03:43 PM
» Replies: 11
» Views: 727
|
Show Nametags During Coun...
Forum: Visual & Sound Effects
Last Post: _Ro
01-08-2025, 07:48 AM
» Replies: 1
» Views: 666
|
|
|
Gain/Lose XX Amount of VR/BR Every Race [TheNinjaKingOW] |
Posted by: Zeraora - 06-17-2022, 02:25 AM - Forum: Online Non-Item
- Replies (2)
|
|
This code (as the name implies) sets the amount of VR/BR you gain/lose every race to a custom value.
NTSC-U:
C2528e00 00000002
3880XXXX 7C002214
60000000 00000000
PAL:
C252D274 00000002
3880XXXX 7C002214
60000000 00000000
NTSC-J:
C252CBF4 00000002
3880XXXX 7C002214
60000000 00000000
NTSC-K:
C251B2CC 00000002
3880XXXX 7C002214
60000000 00000000
XXXX = The amount you want
|
|
|
Late Trick Bot [Vega] |
Posted by: Vega - 06-06-2022, 02:47 PM - Forum: Offline Non-Item
- No Replies
|
|
Late Trick Bot [Vega]
Video~
Works for every controller.
Always get a perfect last frame trick. There's 2 different configurations to this code.
1st Config: Literally no action required on your behalf. Just launch off any ramp (don't even have to press anything / swing remote) and the late trick is auto generated. However, you can't choose what style of tricks you perform.
2nd Config: Simply removes the nop (1st line) of 1st config. This means you still need to legitimately initiate the trick, but you no longer need to try to time it for that perfect late trick. That way you can still choose your trick styles.
1st Config Codes~
NTSC-U
0456F344 60000000
0456F374 2805000A
PAL
04575BA8 60000000
04575BD8 2805000A
NTSC-J
04575528 60000000
04575558 2805000A
NTSC-K
04563C00 60000000
04563C30 2805000A
2nd Config Codes~
NTSC-U
0456F374 2805000A
PAL
04575BD8 2805000A
NTSC-J
04575558 2805000A
NTSC-K
04563C30 2805000A
Code creator: Vega
Code credits: Stebler and Seeky (player.h and mkw-structures github repo)
Sources for RAM Writes
First 32-bit RAM Write replaces 'beq 0x64' with a nop. The conditional branch would be taken if the player did not press their trick button within the correct time/frame window to initiate a trick. By nopping this, we always do a trick off any trickable surface.
Second 32-bit RAM Write replaces 'cmplwi r5, 3' with 'cmplwi r5, 10'. It's important to explain that if you hit trick button after 10 frames already being in air, you can't trick. There is also a lower bound Air frame check for when the trick can start animation. It's normally 3. This means that if you press your trick button at 3 frames already in air or earlier, the end result is the same --- quickest trick off ramp is done. Think of it like a Trick Animation Starter. By making this change from 3 to 10 via the cmplwi instruction modification, we force the game to only start tricks at the same exact frame that is required for latest possible trick. Thus, if you pair this with the 1st RAM Write (i.e. 1st config), you get an auto generated late trick bot. If you don't pair with 1st RAM Write (i.e. 2nd config), you still need to legitimately initiate the trick, but if you get that done, you will always get the late trick.
|
|
|
Trick Timing + Difficulty Modifier [Vega] |
Posted by: Vega - 06-06-2022, 02:44 PM - Forum: Offline Non-Item
- No Replies
|
|
Trick Timing + Difficulty Modifier [Vega]
Video~
This code edits 3 variables of the Trick:
- Frame Window required to be within from the time of pressing your Trick Button (or swinging remote) while on Trickable Surface to the time of when you get into Air
- Latest Possible Frame in Air that you can still get a Trick performed
- When the Trick Animation will Start
This may not make sense at first, so please be sure to also read the explanation below.
Under normal conditions, once you are on a trickable surface and you press your trick button (or swing remote), you have to be within 14 frames to the point of getting airtime or else the trick won't occur.
At this point the game will wait til the 3rd frame you are suspended in the air to generate your trick. So this means if you press your Trick Button (or swing remote) before the 4th air-frame, you will execute the earliest trick animation possible.
Obviously a player can wait to do 'late tricks'. You can wait up to 10 frames being suspended in the air. Once you go past 10 frames, you can no longer be able to generate a trick.
The reason I'm explaining all of this is for you to understand how to use this code correctly and how each value will effect your Tricks. With all of that being said here for Code values and their ranges
XXXX = Button Trickable Surface Frame Window (Default is 000E aka 14)
YYYY = Button Air Frame Window Upper Bound (Default is 000A aka 10)
ZZZZ = Button Trick Animation Frame Start Value (Default is 0003)
XXXX can be anything from 0001 thru 7FFF (8000+ are treated as negative numbers, can't use those values)
YYYY & ZZZZ can be anything from 0000 thru FFFF (8000+ are still treated as positive numbers)
ZZZZ must be lower than YYYY, and ZZZZ cannot be zero. XXXX also cannot be 0 or else you simply disable tricks entirely, lol.
NTSC-U
0456F31C 3800XXXX
0456F348 2805YYYY
0456F374 2805ZZZZ
PAL
04575B80 3800XXXX
04575BAC 2805YYYY
04575BD8 2805ZZZZ
NTSC-J
04575500 3800XXXX
0457552C 2805YYYY
04575558 2805ZZZZ
NTSC-K
04563BD8 3800XXXX
04563C04 2805YYYY
04563C30 2805ZZZZ
Code creator: Vega
Code credits: Stebler (player.h), Seeky (mkw-structures github repo)
Sources~
1st RAM Write: 'li r0, 0x000E' has its 16-big signed value changed. This sets the Trickable Surface Frame Window which gets decremented til it hits 0
2nd RAM Write: 'cmplwi r5, 0x000A' has its 16-bit logical/unsigned value changed. This is the upper bound check for longest allow time you've been in the Air (frames)
3rd RAM Write: 'cmplwi r5, 0x0003' has its 16-bit logical/unsigned value changed. This is the earliest the game can start a trick animation in regards to how long it waits for you to stay suspended in the air.
|
|
|
Trick Anywhere Anytime [Vega] |
Posted by: Vega - 06-05-2022, 02:44 AM - Forum: Offline Non-Item
- Replies (2)
|
|
Trick Anywhere Anytime [Vega]
Video~
You can *almost* trick anywhere at anytime. There are still a few instances where you can't (such as after already being mid air by Halfpipe Ramps on DKS).
Here's a list of some of the new scenarios where you can now trick
- Can trick in cannons (trick sparkles and sound will work, but can't change cannon tradjectory)
- Can trick multiple times in the air during one jump
- Can trick w/o hopping
- Can trick w/o any speed or in reverse
- Can trick on any surface
- Can trick during the countdown (only sparkles and sound work)
Yes you 'trick' while in a Bullet Bill, but once you do that, your Bill will have a mind of its own and will travel to god knows where, lol.
You also have the ability to use something other than the trick button for tricks, so that way you can do both normal tricks and 'hacked' tricks.
Not only that, this also serves as a proxy 'Rapid Trick' code. Simple hold down your ZZZZ button and you will be tricking every frame.
NTSC-U
0456F538 80850004
0456F330 80A4001C
2834XXXX YYYYZZZZ
C256F538 00000007
80850004 817C0000
816B0000 896B0010
3D80809C 818C8F68
898C0B84 7C0B6000
40A20014 3D608056
616BF610 7D6803A6
4E800020 00000000
C256F330 00000007
80A4001C 817C0000
816B0000 896B0010
3D80809C 818C8F68
898C0B84 7C0B6000
40A20014 3D608056
616BF37C 7D6803A6
4E800020 00000000
E0000000 80008000
PAL
04575D9C 80850004
04575B94 80A4001C
2834XXXX YYYYZZZZ
C2575D9C 00000007
80850004 817C0000
816B0000 896B0010
3D80809C 818CD728
898C0B84 7C0B6000
40A20014 3D608057
616B5E74 7D6803A6
4E800020 00000000
C2575B94 00000007
80A4001C 817C0000
816B0000 896B0010
3D80809C 818CD728
898C0B84 7C0B6000
40A20014 3D608057
616B5BE0 7D6803A6
4E800020 00000000
E0000000 80008000
NTSC-J
0457571C 80850004
04575514 80A4001C
2834XXXX YYYYZZZZ
C257571C 00000007
80850004 817C0000
816B0000 896B0010
3D80809C 818CC788
898C0B84 7C0B6000
40A20014 3D608057
616B57F4 7D6803A6
4E800020 00000000
C2575514 00000007
80A4001C 817C0000
816B0000 896B0010
3D80809C 818CC788
898C0B84 7C0B6000
40A20014 3D608057
616B5560 7D6803A6
4E800020 00000000
E0000000 80008000
NTSC-K
04563DF4 80850004
04563BEC 80A4001C
2833XXXX YYYYZZZZ
C2563DF4 00000007
80850004 817C0000
816B0000 896B0010
3D80809B 818CBD68
898C0B84 7C0B6000
40A20014 3D608056
616B3ECC 7D6803A6
4E800020 00000000
C2563BEC 00000007
80A4001C 817C0000
816B0000 896B0010
3D80809B 818CBD68
898C0B84 7C0B6000
40A20014 3D608056
616B3C38 7D6803A6
4E800020 00000000
E0000000 80008000
Code creator: Vega
Code credits: Stebler (player.h and slot checking mechanism), Seeky (player.h, mkw_structures github repo)
#NOTE FOR BOTH ASM's
#1st ASM skips over the check for the game seeign if you are already in a trick (PAL 80575e5c, gets executed every frame) and skips over the speed check (PAL 80575e70)
#2nd ASM skips over..
#Airtime = 0 frames
#Airtime > 10 frames
#Airtime < 3 frames
#Trick Button hit within 14-frame window of when youre already on surface to when you're in air at 10 frames or less
#Trickable Surface
#Already in Trick (this check is also present in what's skipped in first ASM; keep in my mind not the same exact instruction at same address)
#First frame of Trick
#Over a Zipper
#START ASSEMBLY
#Address Ports
#PAL = 80575D9C
#NTSC-U = 8056F538
#NTSC-J = 8057571C
#NTSC-K = 80563DF4
#Region Compilation Setting
.set region, '' #Fill in P, E, J, or K (case sensitive)
.if (region == 'P')
.set ptr_raceData, 0x809bd728
.set landing_spot, 0x80575E74
.elseif (region == 'E')
.set ptr_raceData, 0x809b8f68
.set landing_spot, 0x8056F610
.elseif (region == 'J')
.set ptr_raceData, 0x809bc788
.set landing_spot, 0x805757F4
.elseif (region == 'K')
.set ptr_raceData, 0x809abd68
.set landing_spot, 0x80563ECC
.else
.err
.endif
#Register Notes
#LR = safe
#r28 is w/e pointer that can be used for slot checking (idk the name, lol)
#Original Instruction
lwz r4, 0x0004 (r5)
#Get Slot function is hooked on
lwz r11, 0 (r28)
lwz r11, 0 (r11)
lbz r11, 0x10 (r11)
#Get Your Slot (added this so code works on both offline and online)
lis r12, ptr_raceData@ha
lwz r12, ptr_raceData@l (r12)
lbz r12, 0xb84 (r12)
#Check em'
cmpw r11, r12
bne+ end_code
#Jump 0xD4 ahead
lis r11, landing_spot@h
ori r11, r11, landing_spot@l
mtlr r11
blr
#End code
end_code:
#END ASSEMBLY
=====
#START ASSEMBLY
#Address Ports
#PAL = 80575B94
#NTSC-U = 8056F330
#NTSC-J = 80575514
#NTSC-K = 80563BEC
#Region Compilation Setting
.set region, '' #Fill in P, E, J, or K (case sensitive)
.if (region == 'P')
.set ptr_raceData, 0x809bd728
.set landing_spot, 0x80575BE0
.elseif (region == 'E')
.set ptr_raceData, 0x809b8f68
.set landing_spot, 0x8056F37C
.elseif (region == 'J')
.set ptr_raceData, 0x809bc788
.set landing_spot, 0x80575560
.elseif (region == 'K')
.set ptr_raceData, 0x809abd68
.set landing_spot, 0x80563C38
.else
.err
.endif
#Register Notes
#LR = safe
#r28 & r29 is w/e pointer that can be used for slot checking (idk the name, lol)
#Original Instruction; load bitfield1 (line 431 of player.h)
lwz r5, 0x001C (r4)
#Get Slot function is hooked on
lwz r11, 0 (r28)
lwz r11, 0 (r11)
lbz r11, 0x10 (r11)
#Get Your Slot (added this so code works on both offline and online)
lis r12, ptr_raceData@ha
lwz r12, ptr_raceData@l (r12)
lbz r12, 0xb84 (r12)
#Check em'
cmpw r11, r12
bne+ end_code
#Jump 0x4C ahead
lis r11, landing_spot@h
ori r11, r11, landing_spot@l
mtlr r11
blr
#End code
end_code:
#END ASSEMBLY
|
|
|
Hop Anywhere Anytime [Vega] |
Posted by: Vega - 05-26-2022, 02:14 PM - Forum: Offline Non-Item
- Replies (1)
|
|
Hop Anywhere Anytime [Vega]
Video~
Can Hop anywhere at anytime, you can hop multiple times while in the air. Thus you can keep hopping up and up into the sky. Won't work in cannons (hop sound will still occur) but you can't change the cannon trajectory.
You also have the ability to use something other than the Hop button for Hops, so that way you can do both normal hops and 'hacked' hops.
Not only that, this code serves as a proxy 'Rapid Hop' code. Simple hold down your ZZZZ button and you will be hopping every frame.
Press ZZZZ to hop at anytime regardless of where you are at.
W (PAL only) values:
4 = Non-GCN
5 = GCN
XXXX = Controller Address
ZZZZ = Button for Universal Hop (must be a single button that is chosen, no double/triple/etc button combos)
If using GCN, use the Wavebird values for the ZZZZ values.
NTSC-U
C2577668 00000008
3D808034 A18CXXXX
718CZZZZ 41820028
819D0000 818C0000
898C0010 3D60809C
816B8F68 896B0B84
7C0B6000 40A20008
38600001 2C030000
60000000 00000000
PAL
C257DECC 00000008
3D80803W A18CXXXX
718CZZZZ 41820028
819D0000 818C0000
898C0010 3D60809C
816BD728 896B0B84
7C0B6000 40A20008
38600001 2C030000
60000000 00000000
NTSC-J
C257D84C 00000008
3D808034 A18CXXXX
718CZZZZ 41820028
819D0000 818C0000
898C0010 3D60809C
816BC788 896B0B84
7C0B6000 40A20008
38600001 2C030000
60000000 00000000
NTSC-K
C256BF24 00000008
3D808033 A18CXXXX
718CZZZZ 41820028
819D0000 818C0000
898C0010 3D60809B
816BBD68 896B0B84
7C0B6000 40A20008
38600001 2C030000
60000000 00000000
Code creator: Vega
Code credits: Stebler (get slot function code, ptr_race data code and addresses; also used his documentation on Seeky's mkw-structure github of 'virtual boot canHop() to go back into the Callstack to find Hook Address), Seeky (mkw-structure github page)
#START ASSEMBLY (C2)
#Address Ports
#NTSC-U = 80577668
#PAL = 8057DECC
#NTSC-J = 8057D84C
#NTSC-K = 8056BF24
#Region Compilation Setting
.set region, '' #Fill in P, E, J, or K (case sensitive)
.if (region == 'P')
.set ptr_raceData, 0x809bd728
.elseif (region == 'E')
.set ptr_raceData, 0x809b8f68
.elseif (region == 'J')
.set ptr_raceData, 0x809bc788
.elseif (region == 'K')
.set ptr_raceData, 0x809abd68
.else
.err
.endif
#Load current Button Halfword combo
lis r12, 0x8035 #PAL GCN used for compilation, adjust this accordingly
lhz r12, 0xFFFF8200 (r12) #PAL GCN port 1 used, adjust accordingly
#Check it for B button activation, feel free to adjust the button activator
andi. r12, r12, 0x0200
beq- original_instruction
#Get Slot function is hooked on
lwz r12, 0x0 (r29)
lwz r12, 0x0 (r12)
lbz r12, 0x10 (r12)
#Get Your Slot (added this so code works on both offline and online)
lis r11, ptr_raceData@ha
lwz r11, ptr_raceData@l (r11)
lbz r11, 0xb84 (r11)
#Check em'
cmpw r11, r12
bne+ original_instruction
#Force universal Hop
li r3, 1
#Original Instruction; check return value from previous function call (Can Hop? Function call). r3 = can't hop. r3 = can hop
original_instruction:
cmpwi r3, 0
#END ASSEMBLY
|
|
|
All About BATs |
Posted by: Vega - 05-23-2022, 02:11 PM - Forum: PowerPC Assembly
- Replies (4)
|
|
All About BATs
For advanced ASM coders/devs.
This won't be useful for Wii Gecko Codes, but I've made this thread due to the Broadway Manual lacking detail on the BAT Registers and how to configure them. There are other PPC-based manuals that explain it, but said explanations are not all that "user-friendly".
Chapter 1: Intro
The BAT Registers are responsible for taking a Virtual Address and translating (converting) it to its Physical Address. As an Advanced ASM Coder/Dev, you should already know that mem1 and mem2 operate as Virtual Memory. Broadway needs to be 'told' how to convert any Virtual Memory Address to its Physical Address equivalent.
BAT stands for Block Address Translation. There are 16 total BAT registers. There are 8 BATs available for areas of memory containing instructions (known as IBATs), and 8 BATs available for memory containing data (known as DBATs). Each BAT is 64 bits (double-word) in length and is split into upper 32 bit and lower 32 bit portions.
Any area or region of memory that a BAT is responsible for is known as a Block. The BATs are mostly configured sometime shortly after the game is booted and a final BAT (DBAT3 for the Locked Cache) is configured after the bootstrap screen. From personal limited testing, it appears all Wii games setup the BATs in the same universal way.
Here's a picture of the BATs while having the emulation randomly paused in MKWii at the Main Menu
NOTE: Older Dolphin Dev Versions (such as 11xxx series and earlier) will not show proper values for the BATs! Use a newer version!
Here's a list of SPR numbers for all the BATs. The list is formatted to directly be placed into an ASM Code assembler (i.e. PyiiASMH)
Code: .set IBAT0U, 528
.set IBAT0L, 529
.set IBAT1U, 530
.set IBAT1L, 531
.set IBAT2U, 532
.set IBAT2L, 533
.set IBAT3U, 534
.set IBAT3L, 535
.set IBAT4U, 560
.set IBAT4L, 561
.set IBAT5U, 562
.set IBAT5L, 563
.set IBAT6U, 564
.set IBAT6L, 565
.set IBAT7U, 566
.set IBAT7L, 567
.set DBAT0U, 536
.set DBAT0L, 537
.set DBAT1U, 538
.set DBAT1L, 539
.set DBAT2U, 540
.set DBAT2L, 541
.set DBAT3U, 542
.set DBAT3L, 543
.set DBAT4U, 568
.set DBAT4L, 569
.set DBAT5U, 570
.set DBAT5L, 571
.set DBAT6U, 572
.set DBAT6L, 573
.set DBAT7U, 574
.set DBAT7L, 585
Chapter 2: BAT Structure Upper 32 bits
Upper Portion:- Bits 0 - 14: BEPI
- Bits 15 - 18: Unused
- Bits 19 - 29: BL
- Bit 30: Vs
- Bit 31: Vp
BEPI: Block Effective Page Index. This is simply the beginning Virtual Address that you choose to use for the translation. If desired, you can set this to exactly match the Physical Address. The ending Virtual Address is determined by the memory block size in the BL field.
BL: Block Length. This sets the amount (region/block) of Memory that the BAT will cover using BEPI as the starting address. Use the bit map below to determine the size.
BL Bit Map:- 128KB = 000 0000 0000
- 256KB = 000 0000 0001
- 512KB = 000 0000 0011
- 1MB = 000 0000 0111
- 2MB = 000 0000 1111
- 4MB = 000 0001 1111
- 8MB = 000 0011 1111
- 16MB = 000 0111 1111
- 32MB = 000 1111 1111
- 64MB = 001 1111 1111
- 128MB = 011 1111 1111
- 256MB = 111 1111 1111
Setting an invalid bit combo will corrupt the BAT and cause undefined behavior. If the exact size you want is not listed, then you need round up or split the sizes and use multiple BATs.
Vs: Supervisor Valid Bit. If you are in Supervisor Mode (Machine State Register PR Bit Low), this bit will determine whether or not you are allowed to access that memory.
Vp: User Valid Bit. If you are in User Mode (Machine State Register PR bit High), this bit will determine whether or not you are allowed to access that memory.
Cheat Sheet for Upper Portion of BAT if using Vs & Vp as both set high.
XXXXzzzz
XXXX = Upper 16 bits of the starting Virtual Address (i.e. 0x8000 represents 0x80000000)
zzzz = BL + Vs&Vp combo (whenever Vs and Vp are set high)
zzzz value map (assumes Vs and Vp are set high)- 0003 = 128KB
- 0007 = 256KB
- 000F = 512KB
- 001F = 1MB
- 003F = 2MB
- 007F = 4MB
- 00FF = 8MB
- 01FF = 16MB
- 03FF = 32MB
- 07FF = 64MB
- 0FFF = 128MB
- 1FFF = 256MB
Here's an example BAT Upper 32-bit Value using 8MB and 0x81000000 as the virtual start address; Vs and Vp both set high
0x810000FF
Btw here's a handy memory size cheat sheet to help calculate the zzzz values. Take the end address minus the start address, then add 1. All calculations are in Hex obviously..
Example: (0x80FFFFFF - 0x80000000) + 1 = 0x01000000 (size of 16MB; use zzzz value of 01FF)- 0x10000000 = 256MB
- 0x08000000 = 128MB
- 0x04000000 = 64MB
- 0x02000000 = 32MB
- 0x01000000 = 16MB
- 0x00800000 = 8MB
- 0x00400000 = 4MB
- 0x00200000 = 2MB
- 0x00100000 = 1MB (1,024KB actual)
- 0x00080000 = 512KB
- 0x00040000 = 256KB
- 0x00020000 = 128KB
- 0x00010000 = 64KB
- 0x00008000 = 32KB
- 0x00004000 = 16KB
- 0x00002000 = 8KB
- 0x00001000 = 4KB
- 0x00000800 = 2KB
- 0x00000400 = 1KB (1,024 bytes actual; 0x400 in hex is 1,024 in decimal)
Chapter 3: BAT Structure Lower 32 bits
Bits 0 - 14: BRPN
Bits 15 - 24: Unused
Bit 25: W
Bit 26: I
Bit 27: M
Bit 28: G
Bit 29: Unused
Bits 30 & 31: PP
BRPN: Block Register Page Number. This is the physical address that is used in conjuction to your Virtual Address, this must be a legit physical address.
W: Write Through. If this bit is high, any store operations to cached memory are also written to physical memory, think of this like a dcbst instruction. If the bit is low, this is known as 'write-back'. In Write-Back mode, when store operations update cached memory, they do not instantly update physical memory.
I: Cache-Inhibited. If this bit is high, no cache-ing of any kind shall occur for the specified block of memory. Blocks of memory that include access to something such as an I/O device should have the I bit set high.
M: Memory coherence: When this bit is high, other devices or processors will be notified whenever the specified region of memory is accessed. Considering Broadway runs on 'its own' and doesn't need to notify other processors, M bit is set low on every BAT by every Wii menu, channel, game, etc.
G: Guarded: This bit should be high if there are missing gaps in the specified memory block. This bit should also be set high for any memory that is not "well behaved". "Well behaved" simply means if the block of memory includes access to something such as an I/O device. I'm not sure on this but you may also need the G bit high if you had to roundup the BL bits. That would technically cause gaps in the memory block. Also G bit should be set high if you want to stop out-of-order operations (i.e loads, fetches, etc). Fyi, stores on Broadway are never done out-of-order in relation to each other. Finally, Store Gathering is automatically disabled (regardless of SGE bit value in HID0) whenever G bit is high.
PP: Page Protection. Responsible for allowing access to the block of memory. Think of it like a firewall. See bit map below.
PP bit map:- 00 = No access (can't read or write)
- x1 = Read only (x = don't care value)
- 10 = Read & Write
There is no available bit combo for Write only!
If you are wanting a block of memory to allow full access in any 'situation', set both the Vs and Vp bits high in the upper portion of the BAT, and then set the PP bit combo to 10 for the lower portion.
Here's an example of a BAT with its lower portion using a physical start address 0x01000000 with WIMG all low, and PP set to 10. We will use the upper portion example from Chapter 2 that used Virtual Start Address 0x81000000. The BAT will have Vs+Vp high with PP as 10 which means both user and supervisor have read+write access to the block of memory
BAT value: 0x810000FF 01000002
Virtual Start Address: 0x81000000
Block Length: 8MB
Vs and Vp high
Physical Start Address: 0x01000000
WIMG all low
PP = 10 (0x2); Read & Write
IMPORTANT NOTEs: The IBATs can NEVER have the W and/or G bit set high. Doing so will corrupt the IBAT. Undefined behavior will occur. Also, regarding DBATs, whenever I bit is high, there is zero need to set W bit high. Having both W and I bit high (only applicable to DBATs) is considered as an invalid combo and should not be used. If you want to set any DBAT to simply be a representative of Physical Memory (but with the ability to use it Virtually), set I and G bits high, with W low.
Chapter 4: Getting In & Out of Real Mode
You must be in Real Mode when doing any invalidations/modifications to the BATs. Real Mode simply means you are executing in Physical Memory that is NOT part of an Exception. However, you do NOT need to be in Real Mode if you are simply copying BAT Register Data to the GPRs (maybe for something such as a Debug Report type code/source). Also, interrupts need to be disabled the entire time you are invalidating and/or modifying the BATs.
Example Routine to get into Physical Mode~
Code: mfmsr r3 #Backup original MSR to some safe place if necessary
rlwinm r4, r3, 0, 17, 15
mtmsr r4
bl get_pc #Get Program counter
get_pc:
mflr r3
margin = real_mode - get_pc
addi r3, r3, margin #This points to instruction right after rfi
clrlwi r3, r3, 1 #Change address to physical
mtspr srr0, r3 #Place physical address into srr0
rlwinm r4, r4, 0, 28, 25 #Flip off IR and DR bits
mtspr srr1, r3 #Place updated MSR into srr1
rfi #Go into real mode
real_mode:
Example Routine to get back into Virtual Mode~
Code: bl get_pc #Get Program Counter
get_pc:
mflr r4
margin = virtual_mode - get_pc
mfmsr r3 #Get MSR
ori r3, r3, 0x8030 #Flip IR and DR bits high, turn back on Interrupts
mtspr srr1, r3 #Place updated MSR into srr1
addi r3, r4, margin #Points to instruction right after rfi
oris r3, r3, 0x8000 #Change address to Virtual, mem80 used for this example
mtspr srr0, r3 #Place virtual address into srr0
rfi #End real mode
virtual_mode:
Alternatively instead of placing the address in srr0 and MSR into srr1, you could do something like this (do NOT use this for Exceptions btw)...
Code: lis r0 #Will be your physical or virtual address
ori r0, r0, 0xXXXX
mtlr r0 #or mtctr if you want to use the CTR
mfmsr r0
rlwinm / ori using r0 #Depends on if you are setting IR+DR high or low
mtmsr r0
isync** #This is NEEDED!
blr #or bctr if you chose to use the CTR
**isync is needed to update the instruction context. If isync isn't used (remember Broadway is an out-of-order execution-type CPU), Broadway may fetch and execute instructions meant for virtual mode as real mode, and vice versa. The earlier two sources that use rfi do not need an isync because rfi, by design, is instruction synchronizing.
Chapter 5: Invalidating BATs
To modify a BAT, it MUST be invalidated first. Also when Broadway is powered on, the BATs are in an unknown state. All BATs should be marked invalid before configuring them (necessary for something such as writing a boot sequence code).
To invalidate a BAT, both Vs and Vp bits of the Upper Portion must be set low. Super simple. The quickest way to invalidate a BAT is this...
Code: li rX, 0
mtspr ZZZU, rX
rX = Safe GPR to use for your code/source
ZZZ = the SPR number of the BAT
U = reminding you the write needs to be done the the UPPER portion
Any modification/invalidation to an IBAT requires an isync instruction AFTERWARDS (Reference: PowerPC Microprocessor Family: The Programming Environments, table 2-22 (page 2-42))
Any modification/invalidation to a DBAT requires isync instructions BEFORE and AFTER (Reference: PowerPC Microprocessor Family: The Programming Environments, table 2-23 (page 2-43))
If you are invalidating a group of IBATS or DBATS, you do not need an isync after every single individual BAT invalidation.
Example: Invalidate DBATS 2 thru 4~
Code: li r0, 0
isync
mtspr r0, DBAT2U
mtspr r0, DBAT3U
mtspr r0, DBAT4U
isync
Since IBAT invalidation doesn't require an isync beforehand, if you are writing a boot sequence code, you can invalidate all BATs simply like this...
Code: li r0, 0
mtspr IBAT0U, r0
mtspr IBAT1U, r0
mtspr IBAT2U, r0
mtpsr IBAT3U, r0
mtspr IBAT4U, r0
mtspr IBAT5U, r0
mtspr IBAT6U, r0
mtspr IBAT7U, r0
isync
mtspr DBAT0U, r0
mtspr DBAT1U, r0
mtspr DBAT2U, r0
mtspr DBAT3U, r0
mtpsr DBAT4U, r0
mtspr DBAT5U, r0
mtpsr DBAT6U, r0
mtspr DBAT7U, r0
isync
Chapter 6: Modifying BATs Correctly
Assuming you have invalidated a BAT correctly, you can now modify it. The Lower 32-bits of the BAT MUST ALWAYS BE WRITTEN FIRST! Another rule is that you can only modify one BAT at a time.
Example: Configure the 5th IBAT to have virtual address 0x80000000 represent physical address 0x00000000. 0x80000000 thru 0x80FFFFFF is 16MB in total size which is a perfect size match for setting the BL bits. Vs, Vp both High. PP = 10 (0x2). WIMG is all low.
Code: #Pretend the IBAT was properly invalidated some time ago. Fyi no isync required beforehand since this is an IBAT
#Set r0 as lower portion
li r0, 2
#Set r3 as upper portion
lis r3, 0x8000
ori r3, r3, 0x01FF
#Write lower portion
mtspr IBAT5L, r0
#Write upper portion
mtspr IBAT5U, r0
#isync required now
isync
One more example, set one BAT (DBAT2) to cover Virtual Uncached Mem2 (aka mem9). Mem9's full size is 64MB which is a perfect size match once again for the BL bits. Assume DBAT2 was properly invalidated beforehand.
Code: #W = low
#I = high! (cache must be blocked)
#M = low
#G = high! (prevent out-of-order operations)
#PP = 10 (read & write)
lis r0, 0x1000
ori r0, r0, 0x002A
#Upper Portion config
#Virtual Start Addr = 0xD0000000
#Block size = 64MB
#Vs and Vp both set high
lis r3, 0xD000
ori r3, r3, 0x07FF
#Modify the BAT
isync
mtspr DBAT2L, r0
mtspr DBAT2L, r3
isync
Chapter 7: More Rules to Follow
You cannot have multiple BATs (for the BAT same type; instruction or data), that do a translation to the same physical address.
Example: You have IBAT0 translate 0x80000000 to physical 0x00000000 and IBAT6 translate 0x70000000 to physical 0x00000000. That's a no-go.
Also, you cannot have memory blocks overlap from multiple BATs (for the same BAT type: instruction or data).
Example: You have DBAT2 for 0x90000000 using block-length of 64MB (so this covers all of mem9 which is 0x90000000 thru 0x93FFFFFF. You then also have DBAT4 for 0x93000000 using block length of 16MB (so this covers just 0x93000000 thru 0x93FFFFFF). As a result memory addresses 0x93000000 thru 0x93FFFFFF are both part of DBAT2 and DBAT4.
Whenever BATs are incorrectly invalidated and/or modified, the processor may enter into what is known as a Checkstop Condition. In simple terms, the processor halts without any Exception Routine being taken.
Chapter 8: Hardware Register Notes
By default (Broadway from a powered-on state), IBATs & DBATs 4 thru 7 are disabled. To enable these extra BATs, you need to set Bit 6 (SBE) of HID4 high. From personal limited testing, it appears all Wii applications that make modifications to HID4 will always set/keep this bit high
All BAT M bits (for instruction fetching) can be overridden by setting bit 23 (IFEM) low on HID0. From personal limited testing, it appears all Wii applications set/keep this bit low.
Please note that the I bit setting in a BAT will override the ICE, DCE, ILOCK, & DLOCK bits of HID0!!! (reference: Broadway User Manual pages 136 & 137)
Chapter 9: Example Code of Messing Around with the BATs
Here is a code I've clobbered together really quick that will run a couple of instructions in 0x50XXXXXX memory. This will most likely crash on most versions of Dolphin, because Dolphin is Dolphin. The code runs fine on real Hardware.
If Dolphin does work for you then you will see (by stepping thru the code) that you will arrive at 0x50XXXXXX memory to execute two instructions. They set r4 to 0, then increment it by 1. In Dolphin's code view it will say something like.... "No RAM Contents Here". You won't be able to see the instructions in the Code View, but as you are stepping, you will see r4 get the proper updates in the Register tab/window.
Code is hooked at old historical Shared Item Code Address (MKWii game ofc, credits to Guru for original Shared Item Code). Hit (or let a CPU) hit an item box for the code to execute.
Btw to know that the code works on real Hardware, a Fib is set to be received from the Item Box when you (or the CPU) hits said item box.
PAL
C27BA164 0000001C
7D8000A6 5583045E
7C600124 48000005
7D6802A6 386B0020
5463007E 7C7A03A6
7C6000A6 54630732
7C7B03A6 4C000064
38000000 7C1083A6
4C00012C 38000002
3C605000 606301FF
7C1183A6 7C7083A6
4C00012C 7C6000A6
60630030 7C7B03A6
5563007E 64635000
38630064 7C7A03A6
4C000064 38800000
38840001 386B0088
5463013E 7C7A03A6
7C6000A6 54630732
7C7B03A6 4C000064
38000000 7C1083A6
4C00012C 38000002
3C608000 606301FF
7C1183A6 7C7083A6
4C00012C 7D9B03A6
5563013E 64638000
386300C4 7C7A03A6
4C000064 38600003
90770020 00000000
Code: #START ASSEMBLY
#Address
#PAL = 807BA164
#Register Notes
#r0, r3, r4, & LR are safe
#Disable interrupts
mfmsr r12
rlwinm r3, r12, 0, 17, 15
mtmsr r3
#Go into real Mode
bl get_pc #Get Program counter
get_pc:
mflr r11 #Will need this value later to get back to Virtual Mode
margin = real_mode - get_pc
addi r3, r11, margin #This points to instruction right after rfi
clrlwi r3, r3, 1 #Change address to physical
mtspr srr0, r3 #Place physical address into srr0
mfmsr r3 #Get MSR
rlwinm r3, r3, 0, 28, 25 #Flip off IR and DR bits
mtspr srr1, r3 #Place updated MSR into srr1
rfi #Go into real mode
#############################
real_mode:
#Invalidate IBAT0 (Vs and Vp of Upper portion must be low)
li r0, 0
mtibatu 0, r0
isync
#Set r0 as lower portion
li r0, 2 #PP bits as 10, WIMG all low
#Set r3 as upper portion
lis r3, 0x5000 #Start block at EA 0x50000000
ori r3, r3, 0x01FF #Size of 16MB
#Modify the IBAT!, lower portion (r0) must be written first
mtibatl 0, r0
mtibatu 0, r3
isync
#Go to Vritual Mode
virt_margin = virtual_mode - get_pc
#Turn back on IR and DR, do not turn on EE just yet!
mfmsr r3
ori r3, r3, 0x0030
mtspr srr1, r3
#Clear bit 0 of r11
clrlwi r3, r11, 1
#OR it with 0x5000
oris r3, r3, 0x5000
addi r3, r3, virt_margin
mtspr srr0, r3
rfi
#############################
#We are now executing in 0x50xxxxxx memory!!!
virtual_mode:
#Execute random instructions to prove to Dolphin User this is working
li r4, 0
addi r4, r4, 1
#Go back into real mode again
second_phys_margin = second_real_mode - get_pc
addi r3, r11, second_phys_margin
clrlwi r3, r3, 4 #Change address to physical
mtspr srr0, r3 #Place physical address into srr0
mfmsr r3 #Get MSR
rlwinm r3, r3, 0, 28, 25 #Flip off IR and DR bits
mtspr srr1, r3 #Place updated MSR into srr1
rfi #Go into real mode
#############################
second_real_mode:
#Invalidate IBAT0 again
li r0, 0
mtibatu 0, r0
isync
#Set r0 as lower portion
li r0, 2
#Set r3 as upper portion
lis r3, 0x8000
ori r3, r3, 0x01FF
#Modify the IBAT!, lower portion (r0) must be written first
mtibatl 0, r0
mtibatu 0, r3
isync
#Go to Vritual Mode
second_virt_margin = second_virtual_mode - get_pc
#Restore very first original MSR (r12)
mtspr srr1, r12
#Clear bits 0 thru 3 of r11
clrlwi r3, r11, 4
#OR it with 0x8000
oris r3, r3, 0x8000
addi r3, r3, second_virt_margin
mtspr srr0, r3
rfi
#############################
second_virtual_mode:
#Set fib
li r3, 3
#Default/Original Instruction
stw r3, 0x0020 (r23)
Chapter 10: Example Source of Setting Up all BATs for Wii; Conclusion
Here is a template you can use to invalidate then properly setup all BATs that the Wii needs to use. It assumes you are already in Real Mode and that r0 & r3 are safe to use.
Code: #Invalidate all BATs
li r0, 0
mtspr IBAT0U, r0
mtspr IBAT1U, r0
mtspr IBAT2U, r0
mtspr IBAT3U, r0
mtspr IBAT4U, r0
mtspr IBAT5U, r0
mtspr IBAT6U, r0
mtspr IBAT7U, r0
isync
mtspr DBAT0U, r0
mtspr DBAT1U, r0
mtspr DBAT2U, r0
mtspr DBAT3U, r0
mtspr DBAT4U, r0
mtspr DBAT5U, r0
mtspr DBAT6U, r0
mtspr DBAT7U, r0
isync
#Setup BATs, all BATs will be enabled read+write for both user+supervisor
#Setup IBATs for...
#Cached Mem80; 16MB; WIMG 0000
#Cached Mem81; 8MB; WIMG 0000
#Cached Mem9; 64MB; WIMG 0000
#Uncached Mem80 (MemC); 16MB; WIMG 0101
#Uncached Mem81 (MemC1); 8 MB; WIMG 0101
#Uncached Mem9 (MemD); 64MB; WIMG 0101
#Setup DBATs for...
#Cached Mem80; 16MB; WIMG 0000
#Cached Mem81; 8MB; WIMG 0000
#Cached Mem9; 64MB; WIMG 0000
#Uncached Mem80; Mem81; Mem9; Hardware Memory (all of MemC)); 256MB; WIMG 0101
#Guarded Locked Cache (MemE); 256KB; WIMG 0001
#First 16MB of Cache MEM1; WIMG 0000
lis r0, 0x8000
ori r0, r0, 0x01FF
li r3, 0x0002
mtspr IBAT0L, r3
mtspr IBAT0U, r0
isync
mtspr DBAT0L, r3
mtspr DBAT0U, r0
isync
#Second 8MB of Cache MEM1; WIMG 0000
lis r0, 0x8100
ori r0, r0, 0x00FF
#Change 0x00000002 to 0x01000002
oris r3, r3, 0x0100
mtspr IBAT2L, r3
mtspr IBAT2U, r0
isync
mtspr DBAT2L, r3
mtspr DBAT2U, r0
isync
#64MB of Cache MEM2; WIMG 0000
lis r0, 0x9000
ori r0, r0, 0x07FF
lis r3, 0x1000
ori r3, r3, 0x0002
mtspr IBAT4L, r3
mtspr IBAT4U, r0
isync
mtspr DBAT4L, r3
mtspr DBAT4U, r0
isync
#64MB of Uncache MEM2; WIMG 0101 (Cache Inhibited, Guarded)
#Change 0x900007FF to 0xD00007FF
oris r0, r0, 0xD000
ori r3, r3, 0x002A
mtspr DBAT5L, r3
mtspr DBAT5U, r0
isync
#Uncache MEM1 & Hardware Memory; WIMG 0101 (Cache Inhibited, Guarded)
#Lower 32-bits already present in r3 (0x0000002A)
lis r0, 0xC000
ori r0, r0, 0x1FFF
li r3, 0x002A
mtspr DBAT1L, r3
mtspr DBAT1U, r0
isync
#DBAT for the Locked Cache (identical translation used)
lis r0, 0xE000 #Virtual Addr is same as Physical Addr
ori r0, r0, 0x0003 #Locked Cache is 16KB in size; set usage by both User and Supervisor
lis r3, 0xE000
ori r3, r3, 0x0002
mtspr DBAT3L, r3
mtspr DBAT3U, r0
isync
The source uses certain specific BATs so it can be compatible with being 'injected' at any point in a Wii Game/Title or in a Boot Sequence. Keep in mind that Wii Games setup the Locked Cache BAT immediately *after* the Strap Screen, which will override the DBAT3 config of the above source if you inject it before that moment. But it doesn't really matter because the Locked Cache BAT (DBAT3) can be any size due to 2 reasons: The 16KB locked Cache size is covered by the bare minimum bat size config, and the size of this BAT can be anything due to the nature of how Locked Cache operates. Locked Cache is a very 'odd' feature of Broadway, such as it uses a fake Physical Address in the BAT. It's hard to explain why. Maybe one day, I'll make a tutorial about that to clear some confusion.
|
|
|
Basic GVR Usage in ASM Codes |
Posted by: Vega - 05-21-2022, 11:04 PM - Forum: PowerPC Assembly
- No Replies
|
|
Basic GVR Usage in ASM Codes
For Beginner ASM Coders.
Chapter 1: Intro; Explaining more about C2 Codes
C2 'Insert ASM' Codes are executed by the Code Handler when its Hook Address is executed by Broadway. For a full refresher regarding this, reread Chapter 3 of this thread -> https://mariokartwii.com/showthread.php?tid=1383
A C2 ASM Code can be executed for game specific list/cycle of circumstances. What do I mean by that?
Well for Mario Kart Wii, many addresses that are used by C2 Codes will be executed in a cycle for each player/CPU. An address will be executed for Player 1. Then next time that the game executes said address, it will be for Player 2. Then Player 3, 4, 5, etc etc.
For a game like Dragon Ball Z Budokai Tenkaichi 3 (where a match is typically Player 1 vs Player 2/COM), an address can be executed first for Player 1, then next time it will be for Player 2/COM.
Understanding this is crucial to reaching to that 'next level' of ASM Coding. This may not seem important at first, but this will open up a variety of possibilities for your future Codes.
Chapter 2: What is a GVR? Why do values in the GVRs matter?
GVR = Global Variable Register
It is any General Purpose Register that is r14 thru r31. GVRs will contain values such as...
- Player Number/Slot
- CPU Number/Slot
- Course Number/Slot
- Position Value
- Menu/Mode Type Number/Slot
- etc
Therefore, during the time when your ASM Code is executing, the GVRs may contain data that is relevant to improving your Code. By the way, the term "slot" is preferred by most Coders over the term "number". Regarding Player Slots, for the majority of cases, Slot value of 0 represents Player 1 (1st non-CPU Player).
By figuring out which GVR contains a specific slot value, you can modify your ASM Codes to only execute when said GVR has a certain value. A big issue for new Coders is creating a code and running into an issue where it applies to both the Human Player and the CPU (when the Coder only wants their Code to execute for the Human Player). At this point, if said Coder isn't familiar with GVR data, he/she will have literally zero idea on how to fix their code.
Chapter 3: Let's Make a Code using GVR Data; Part 1
We will use the old historical version of the Mario Kart Wii Shared Item Code (PAL) for demonstrating GVR fundamentals
Code: C27BA164 00000002
386000WW 90770020
60000000 00000000
This code simply changes what item you receive from the item box when you pick it up. WW = Item to Receive, we will set this to 00 (Green Shell) for this GVR tutorial.
Code: C27BA164 00000002
38600000 90770020
60000000 00000000
Now let's inspect the source...
Code: li r3, 0 #Set Item (green shell)
stw r3, 0x0020 (r23) #Default/Original Instruction of Hook Address. This stores the Item to Dynamic Memory.
At this moment we have no idea what data is represented in any of the GVRs. If you have MKWii, launch it on Dolphin. Do NOT apply the Shared Item Code. If you don't have MKWii, be sure to examine the following screenshots closely to follow along. Once you have launched MKWii, do a normal Offline Race. Simply pick Luigi Circuit (as that is the track I did for the exercise, and this plays an important role to the explanation of the final screenshot in this Chapter). Character+Vehicle combo doesn't matter, pick anything. Sometime before the Race begins, pause the emulation & set an Instruction BP on Address 807BA164.
Once you have the Breakpoint set go ahead and start the race, but sit at the start line. When the first CPU hits the item box, the BP will break/hit. Note down the r14 thru r31 data that you see.
Once you have that all noted down, while keeping the Breakpoint ON, resume the emulation. It will pause again once another CPU hits an item box. Take a look at r14 thru r31. If any values changed from the previous Instruction BP hit, they will be in Red font. Note down the Red font GVR values only.
While still keeping the Breakpoint ON, resume the emulation again. It will pause again after another Item Box hit. Take a look at the previous BP-hit Red font GVR values. How do they differ from the previous BP-hit vs the latest BP-hit? Note this all down (including their new current values).
In the above screen shot, there is something that sort of has a pattern to it. It's r25. We see that it has been incrementing (1 to 2 to 4). Fyi this WILL differ slightly on your own test. But you will see that r25 is indeed incrementing.
Go ahead and repeat the process until all CPUs have passed the first row of item boxes. Once they have pass that first row, go ahead and manually pause the emulation to prevent any further item box hits. Be sure to pause the emulation before any of the CPU players hit the next Item Box row.
Here are the rest of my screenshots of all BP-hits for once the CPU's got passed the first row of Items. Keep your mind your r25 values will differ, but they should be incrementing.
You can see that r25 is definitely incrementing. What could it be? Could this value be the Player's/CPU's assigned slot value. Well the odds of Slot Value increasing every BP hit is pretty low. So r25 is probably not a slot value.
Well we know the first CPU to hit the box is very likely to be in first place. In fact, said CPU WILL be 1st place unless said CPU somehow missed picking up the very first box in the race, which is essentially impossible.
Thus, we can safely conclude that r25 represents the Player's/CPU's Position in the Race (at the time when they picked up the Item Box).
To further prove this is true, here is the next screenshot of once the 1st place CPU has made contact with the next Item Box Row (when I did this exercise). All CPUs have already went past the first row of boxes (on Luigi Circuit ofc), and now we can see from the screenshot that 1st Place CPU has picked up the first box on the next item box row on the track.
And the screenshot proves to us that r25 is 1, as expected. So now we know for near 100% certainty that r25 = Position. 1 = 1st Place, 2 = 2nd Place, etc etc til C = 12th (last) Place.
Chapter 4: Let's Make a Code using GVR Data; Part 2
Awesome, we have some GVR data in which we can make a code with. Let's say you only wanted the Shared Item Code to execute whenever the Player/CPU is in last (12th place). Before we have anything at all execute in this new code we are writing, the 'check' for r25's value needs to be placed in first.
We will use a simple Compare Word Immediate (cmpwi) instruction. Now, since we only want the Code to execute when Player/CPU is in 12th place, we will obviously check r25's value against the value of 0xC (12).
We have a comparison instruction written out. Let's now write the Branch instruction. Well, we know that we do NOT want the code to execute if r25 isn't 12, so we will be using a Branch-If-Not-Equal (bne) instruction.
Since there are 12 different total positions, the odds of r25 NOT being 12 is high, thus we can supply a + symbol to the branch instruction to give a small hint to Broadway that the Branch Instruction will most likely occur. The branch hint is optional.
Now we need a label name. We will simply call it jump_code.
Code: cmpwi r25, 0xC
bne+ jump_code
Underneath the branch instruction, we will put the instructions from the original Shared Item Code. Therefore if r25 is equal to 0xC (12), it will NOT take the branch jump and execute the instructions directly below the bne instruction.
Code: cmpwi r25, 0xC #Check if in Last Place
bne+ jump_code #If not, take branch and don't execute code
li r3, 0 #Set Green Shell
stw r3, 0x0020 (r23) #Default/original instruction
At this point, you may be thinking to place the branch's jump 'landing spot' label at the very end, and the code is complete. However that would be wrong, we will write it out below and I will explain why that is incorrect.
Code: cmpwi r25, 0xC #Check if in Last Place
bne+ jump_code #If not, take branch and don't execute code
li r3, 0 #Set Green Shell
stw r3, 0x0020 (r23) #Default/original instruction
jump_code:
Why is this wrong? Well, what happens if r25 isn't 12 and the branch is taken? You will completely skip over the Default Instruction. We need that instruction to always be executed. This is because we must always have the r3 value be stored to Dynamic Memory. With that al being said, we need the 'jump_code:' label right before the Default instruction. Like this...
Code: cmpwi r25, 0xC #Check if in Last Place
bne+ jump_code #If not, take branch and don't execute code
li r3, 0 #Set Green Shell
jump_code:
stw r3, 0x0020 (r23) #Default/original instruction
Now assemble that code in your Assembler using Address (PAL) 0x807BA164. You should get the following code...
Code: C27AB704 00000003
2C19000C 40A20008
38600000 90770020
60000000 00000000
We know from earlier that the '38600000' line of the Code is the 'li r3, 0' instruction. We can change that back to 38600WW to allow the end user to set a custom Item Value for the Code.
The first instruction of our new code is the cmpwi r25, 0xC. We can also configure that assembled line of code to filled in by the User, we will implement a P value for that.
PAL Positional Shared Item Code
P = Position Required
WW = Item to Receive
C27AB704 00000003
2C19000P 40A20008
386000WW 90770020
60000000 00000000
Congrats, you've just remade Star's Positional Shared Item Code! Link - https://mariokartwii.com/showthread.php?tid=536
|
|
|
|