Decomp Academy – learn to decompile GameCube games into matching C
Decomp Academy MWCC GC/2.0
GitHubPlaygroundCurriculumSign in
stwu r1, -0x20(r1) mflr r0 stw r0, 0x24(r1) stw r31, 0x1c(r1) mr r31, r3 lwz r3, 0x8(r31) lfs f1, 0x40(r3) lfs f0, 0x44(r3) fmuls f1, f1, f1 fmadds f1, f0, f0, f1 frsqrte f0, f1 fmuls f2, f0, f0 fnmsubs f2, f2, f1, f13 fmadds f0, f0, f2, f0 cmplwi r4, 0 beq- .L_0x4c rlwinm r0, r5, 2, 0, 29 lwzx r6, r3, r0 add r6, r6, r0 stwx r6, r3, r0 bl Vec_Normalize li r3, 1 lwz r0, 0x24(r1) mtlr r0 blr stwu r1, -0x20(r1) mflr r0 stw r0, 0x24(r1) stw r31, 0x1c(r1) mr r31, r3 lwz r3, 0x8(r31) lfs f1, 0x40(r3) lfs f0, 0x44(r3) fmuls f1, f1, f1 fmadds f1, f0, f0, f1 frsqrte f0, f1 fmuls f2, f0, f0 fnmsubs f2, f2, f1, f13 fmadds f0, f0, f2, f0 cmplwi r4, 0 beq- .L_0x4c rlwinm r0, r5, 2, 0, 29 lwzx r6, r3, r0 add r6, r6, r0 stwx r6, r3, r0 bl Vec_Normalize li r3, 1 lwz r0, 0x24(r1) mtlr r0 blr stwu r1, -0x20(r1) mflr r0 stw r0, 0x24(r1) stw r31, 0x1c(r1) mr r31, r3 lwz r3, 0x8(r31) lfs f1, 0x40(r3) lfs f0, 0x44(r3) fmuls f1, f1, f1 fmadds f1, f0, f0, f1 frsqrte f0, f1 fmuls f2, f0, f0 fnmsubs f2, f2, f1, f13 fmadds f0, f0, f2, f0 cmplwi r4, 0 beq- .L_0x4c rlwinm r0, r5, 2, 0, 29 lwzx r6, r3, r0 add r6, r6, r0 stwx r6, r3, r0 bl Vec_Normalize li r3, 1 lwz r0, 0x24(r1) mtlr r0 blr
Learn to decompile GameCube assembly into byte-matching C.
Go from never having read a register to matching real Star Fox Adventures functions — instruction for instruction. You write C, the real 2001 compiler grades it live.
254
Lessons
0
Solved
Mastery 0%
Graded by the real mwcceppc.exeFunctions from the live SFA-Decomp project
match Vec_Normalize 100% byte-match
Target
Your output
lwz r0, 0x0(r3)
lwz r0, 0x0(r3)
lfs f1, 0x4(r3)
lfs f1, 0x4(r3)
fmuls f0, f0, f1
fmuls f0, f0, f1
fadds f0, f0, f2
fadds f0, f0, f2
stfs f0, 0x0(r4)
stfs f0, 0x0(r4)
blr
blr
The Curriculum
Read the asm · write the C · the compiler grades it byte-for-byte.
0 / 264 matched
functions reconstructed
0
in progress
0
XP
Recruit
[](https://decomp-academy.dev/lesson/foundations-welcome "Your First Match")[](https://decomp-academy.dev/lesson/foundations-identity "Arguments Live in Registers Too")[](https://decomp-academy.dev/lesson/foundations-add "Adding Two Registers")[](https://decomp-academy.dev/lesson/foundations-subtract "Subtraction Reverses Its Operands")[](https://decomp-academy.dev/lesson/foundations-immediate "Immediates: Math With Constants")[](https://decomp-academy.dev/lesson/foundations-negate "Negation and the Zero Register")[](https://decomp-academy.dev/lesson/arithmetic-add-sub "An Add Then a Subtract")[](https://decomp-academy.dev/lesson/arithmetic-two-adds "Two Adds, Reassociated")[](https://decomp-academy.dev/lesson/arithmetic-sub-add "A Subtract Then an Add")[](https://decomp-academy.dev/lesson/arithmetic-add-sub-add "A Three-Instruction Chain")[](https://decomp-academy.dev/lesson/arithmetic-mul "Multiplying Two Registers")[](https://decomp-academy.dev/lesson/arithmetic-mul-const-pow2 "Multiply by a Power of Two")[](https://decomp-academy.dev/lesson/arithmetic-mul-const "Multiply by a Small Constant")[](https://decomp-academy.dev/lesson/arithmetic-affine "An Affine Expression")[](https://decomp-academy.dev/lesson/arithmetic-div-pow2-unsigned "Unsigned Divide by a Power of Two")[](https://decomp-academy.dev/lesson/arithmetic-div-pow2-signed "Signed Divide by a Power of Two")[](https://decomp-academy.dev/lesson/arithmetic-div-var "Real Division")[](https://decomp-academy.dev/lesson/arithmetic-mod "Modulo Has No Instruction")[](https://decomp-academy.dev/lesson/arithmetic-mul-add "Multiply Then Add")[](https://decomp-academy.dev/lesson/arithmetic-add-mul "Precedence Changes the Order")[](https://decomp-academy.dev/lesson/arithmetic-two-products "Two Products, Subtracted")[](https://decomp-academy.dev/lesson/arithmetic-mul-add-sub "A Three-Instruction Mixed Chain")[](https://decomp-academy.dev/lesson/arithmetic-scale-sum "When a Multiply Is a Shift")[](https://decomp-academy.dev/lesson/arithmetic-scale-chain "A Shift Inside a Mixed Chain")[](https://decomp-academy.dev/lesson/arithmetic-div-add "Divide Then Add")[](https://decomp-academy.dev/lesson/arithmetic-shrink-sum "When a Divide Is a Shift")[](https://decomp-academy.dev/lesson/arithmetic-shrink-chain "A Shift-Divide in a Chain")[](https://decomp-academy.dev/lesson/arithmetic-div-sub-mul "Divide and Multiply, Then Subtract")[](https://decomp-academy.dev/lesson/arithmetic-mul-add-div "Multiply and Divide Combined")[](https://decomp-academy.dev/lesson/arithmetic-all-four-ops "All Four Arithmetic Operators")[](https://decomp-academy.dev/lesson/bitwise-and-mask "Masking Bits With AND")[](https://decomp-academy.dev/lesson/bitwise-or "Combining Bits With OR")[](https://decomp-academy.dev/lesson/bitwise-xor "Flipping Bits With XOR")[](https://decomp-academy.dev/lesson/bitwise-set-flag "Setting a Single Flag Bit")[](https://decomp-academy.dev/lesson/bitwise-clear-flag "Clearing a Bit: The rlwinm Surprise")[](https://decomp-academy.dev/lesson/bitwise-test-bit "Testing Whether a Bit Is Set")[](https://decomp-academy.dev/lesson/bitwise-shift-left "Shifting Left by a Constant")[](https://decomp-academy.dev/lesson/bitwise-shift-right-unsigned "Logical Right Shift (Unsigned)")[](https://decomp-academy.dev/lesson/bitwise-shift-right-signed "Arithmetic Right Shift (Signed)")[](https://decomp-academy.dev/lesson/bitwise-shift-variable "Shifting by a Variable Amount")[](https://decomp-academy.dev/lesson/bitwise-extract-field "Extracting a Bitfield in One rlwinm")[](https://decomp-academy.dev/lesson/bitwise-shift-or-pack "Packing Two Values with a Shift and OR")[](https://decomp-academy.dev/lesson/bitwise-merge-fields "Merging Two Fields: rlwinm + rlwimi")[](https://decomp-academy.dev/lesson/bitwise-xor-chain "Chaining XOR Across Three Values")[](https://decomp-academy.dev/lesson/bitwise-bit-select "Bit Select (Mux): AND, ANDC, OR")[](https://decomp-academy.dev/lesson/bitwise-pack-three "Capstone: Pack Three Values into One Word")[](https://decomp-academy.dev/lesson/control-eq-bool "Returning a Comparison as a Bool")[](https://decomp-academy.dev/lesson/control-ne-bool "Not-Equal Is Its Own Idiom")[](https://decomp-academy.dev/lesson/control-if-else "If / Else: The Compare Feeds a Branch")[](https://decomp-academy.dev/lesson/control-sign-masks "Two's Complement, srawi, and andc by Hand")[](https://decomp-academy.dev/lesson/control-clamp-low "Clamping to Zero, Branchlessly")[](https://decomp-academy.dev/lesson/control-cmp-signed "Signed Compare: cmpw")[](https://decomp-academy.dev/lesson/control-cmp-unsigned "Unsigned Compare: cmplw")[](https://decomp-academy.dev/lesson/control-cmp-immediate "Comparing Against a Constant: cmpwi vs cmplwi")[](https://decomp-academy.dev/lesson/control-guard "The Guard Clause / Early Return")[](https://decomp-academy.dev/lesson/control-ternary-max "Ternary Max")[](https://decomp-academy.dev/lesson/control-ternary-min "Ternary Min")[](https://decomp-academy.dev/lesson/control-short-circuit "Short-Circuit && and ||")[](https://decomp-academy.dev/lesson/control-switch "Switch: The Compare Chain")[](https://decomp-academy.dev/lesson/control-clamp-range "Clamping Between Two Bounds")[](https://decomp-academy.dev/lesson/control-nested-ladder "The if / else-if Ladder")[](https://decomp-academy.dev/lesson/control-range-and "A Range Test with &&")[](https://decomp-academy.dev/lesson/control-reject-or "Rejecting Out-of-Range with ||")[](https://decomp-academy.dev/lesson/control-guard-or "A Multi-Condition Guard")[](https://decomp-academy.dev/lesson/control-capstone-clamp-step "Capstone: A Guarded, Clamped Update")[](https://decomp-academy.dev/lesson/loops-for-sum "The Anatomy of a Counted Loop")[](https://decomp-academy.dev/lesson/loops-while-equivalence "While Is the Same Loop")[](https://decomp-academy.dev/lesson/loops-do-while "Do-While: The Tightest Loop")[](https://decomp-academy.dev/lesson/loops-countdown "Counting Down Is Cheaper")[](https://decomp-academy.dev/lesson/loops-array-sum "Walking an Array by Index")[](https://decomp-academy.dev/lesson/loops-array-max "Finding the Maximum")[](https://decomp-academy.dev/lesson/loops-strlen "Walking a Pointer to a Sentinel")[](https://decomp-academy.dev/lesson/loops-break "Breaking Out Early")[](https://decomp-academy.dev/lesson/loops-anatomy-model "A Mental Model: The Five Parts of a Loop")[](https://decomp-academy.dev/lesson/loops-strength-reduction "Strength-Reduced Induction")[](https://decomp-academy.dev/lesson/loops-weighted-sum "A Loop With More Work Inside")[](https://decomp-academy.dev/lesson/loops-nested "Nested Loops")[](https://decomp-academy.dev/lesson/loops-grid-sum "Nesting Over a 2-D Array")[](https://decomp-academy.dev/lesson/loops-triangular "When the Inner Bound Follows the Outer")[](https://decomp-academy.dev/lesson/loops-inversions "Capstone: Counting Pairs in a Grid Scan")[](https://decomp-academy.dev/lesson/types-load-u8 "Loading a Byte")[](https://decomp-academy.dev/lesson/types-load-u16 "Loading a Halfword")[](https://decomp-academy.dev/lesson/types-load-signed "Signed Loads Sign-Extend")[](https://decomp-academy.dev/lesson/types-store-byte "Storing a Byte Truncates")[](https://decomp-academy.dev/lesson/types-store-half "Storing a Halfword")[](https://decomp-academy.dev/lesson/types-u8-not-char "u8, Not char (The Spurious extsb)")[](https://decomp-academy.dev/lesson/types-widen-zero-vs-sign "Widening: Zero vs Sign Extend")[](https://decomp-academy.dev/lesson/types-truncate-mask "Truncating With a Mask")[](https://decomp-academy.dev/lesson/types-explicit-cast "Casts That Sign-Extend")[](https://decomp-academy.dev/lesson/types-cast-between-signed "Casting Between Signed Widths")[](https://decomp-academy.dev/lesson/types-compare-width "The Compare Opcode Follows the Type")[](https://decomp-academy.dev/lesson/types-counter-increment "Bumping a Byte Counter")[](https://decomp-academy.dev/lesson/types-rmw-scale "Read, Scale, Truncate")[](https://decomp-academy.dev/lesson/types-rmw-half "A Signed Halfword Read-Modify-Write")[](https://decomp-academy.dev/lesson/types-mix-widths "Combining Two Widths")[](https://decomp-academy.dev/lesson/types-mix-signs "Mixed Signedness in One Expression")[](https://decomp-academy.dev/lesson/types-capstone "Capstone: Widths and Signs in One Function")[](https://decomp-academy.dev/lesson/pointers-deref "Dereferencing a Pointer")[](https://decomp-academy.dev/lesson/pointers-store "Storing Through a Pointer")[](https://decomp-academy.dev/lesson/pointers-index-const "A Constant Index Becomes a Displacement")[](https://decomp-academy.dev/lesson/pointers-store-index-const "Writing at a Constant Index")[](https://decomp-academy.dev/lesson/pointers-arith "Pointer Arithmetic Is Scaled")[](https://decomp-academy.dev/lesson/pointers-index-var "A Variable Index Needs Scaling Then Indexing")[](https://decomp-academy.dev/lesson/pointers-u8-array "Byte Arrays Need No Shift")[](https://decomp-academy.dev/lesson/pointers-u16-array "Halfword Arrays Shift by One")[](https://decomp-academy.dev/lesson/pointers-strlen "Walking a String")[](https://decomp-academy.dev/lesson/pointers-compare "Comparing Two Pointers")[](https://decomp-academy.dev/lesson/pointers-null-check "Guarding Against NULL")[](https://decomp-academy.dev/lesson/pointers-swap "Swapping Through Pointers")[](https://decomp-academy.dev/lesson/pointers-sum-two "Reading Two Elements and Combining Them")[](https://decomp-academy.dev/lesson/pointers-weighted-elements "Scaling One Element Before Combining")[](https://decomp-academy.dev/lesson/pointers-deref-then-compute "Dereference, Then Compute With an Argument")[](https://decomp-academy.dev/lesson/pointers-computed-offset "Indexing Neighbors From a Computed Offset")[](https://decomp-academy.dev/lesson/pointers-two-arrays "Combining Two Arrays at the Same Index")[](https://decomp-academy.dev/lesson/pointers-capstone "Capstone: Several Dereferences in One Expression")[](https://decomp-academy.dev/lesson/structs-read-field "Reading a Struct Field")[](https://decomp-academy.dev/lesson/structs-write-field "Writing a Struct Field")[](https://decomp-academy.dev/lesson/structs-narrow-read "Narrow Fields: Byte and Halfword Loads")[](https://decomp-academy.dev/lesson/structs-narrow-write "Storing a Byte Field")[](https://decomp-academy.dev/lesson/structs-padding "Alignment Padding Shifts an Offset")[](https://decomp-academy.dev/lesson/structs-sum-fields "Combining Two Fields")[](https://decomp-academy.dev/lesson/structs-combine-fields "Computing Across Three Fields")[](https://decomp-academy.dev/lesson/structs-nested "Nested Structs Flatten to One Offset")[](https://decomp-academy.dev/lesson/structs-struct-of-structs "Combining Fields Across Nested Structs")[](https://decomp-academy.dev/lesson/structs-array-index "Arrays of Structs: Scaling the Index")[](https://decomp-academy.dev/lesson/structs-array-field "An Array Inside a Struct")[](https://decomp-academy.dev/lesson/structs-union "Unions Overlay the Same Bytes")[](https://decomp-academy.dev/lesson/structs-bitfield-set "A Single-Bit Flag: li; rlwimi")[](https://decomp-academy.dev/lesson/structs-bitfield-multi "Multi-Bit Bitfield Writes")[](https://decomp-academy.dev/lesson/structs-bitfield-read "Reading a Bitfield: rlwinm Extract")[](https://decomp-academy.dev/lesson/structs-linked-list "Walking a Linked List")[](https://decomp-academy.dev/lesson/structs-function-pointer "Calling Through a Function Pointer")[](https://decomp-academy.dev/lesson/structs-copy-whole "Copying a Whole Struct")[](https://decomp-academy.dev/lesson/structs-copy-aligned "Eight-Byte Alignment Copies Through Float Registers")[](https://decomp-academy.dev/lesson/structs-copy-large "Big Structs Copy in a Loop")[](https://decomp-academy.dev/lesson/structs-copy-chain "Combining a Copy With a Field Update")[](https://decomp-academy.dev/lesson/structs-capstone "Capstone: Reading a Whole Struct")[](https://decomp-academy.dev/lesson/floats-add "Floats Live in a Different Register File")[](https://decomp-academy.dev/lesson/floats-mul "Single-Precision Multiply")[](https://decomp-academy.dev/lesson/floats-sub "Subtraction Keeps Its Order")[](https://decomp-academy.dev/lesson/floats-div "Floating-Point Division Is Real")[](https://decomp-academy.dev/lesson/floats-div-const-reciprocal "Dividing by a Constant Becomes a Multiply")[](https://decomp-academy.dev/lesson/floats-double-add "Doubles Drop the 's'")[](https://decomp-academy.dev/lesson/floats-frsp-highlight "★ The Spurious frsp: f32 vs double Helpers")[](https://decomp-academy.dev/lesson/floats-literal "Loading a Float Constant from the SDA")[](https://decomp-academy.dev/lesson/floats-fmadds-highlight "★ Fused Multiply-Add")[](https://decomp-academy.dev/lesson/floats-int-to-float "Integer to Float: The Magic-Number Trick")[](https://decomp-academy.dev/lesson/floats-float-to-int "Float to Int: fctiwz and the Store/Load Dance")[](https://decomp-academy.dev/lesson/floats-compare-branch "Comparing Floats: fcmpo Feeding a Branch")[](https://decomp-academy.dev/lesson/floats-abs-neg "Absolute Value and Negation")[](https://decomp-academy.dev/lesson/floats-two-adds "Chaining Two Float Adds")[](https://decomp-academy.dev/lesson/floats-add-then-subtract "Mixing Add and Subtract in One Chain")[](https://decomp-academy.dev/lesson/floats-weighted-sum "A Weighted Sum Folds Into One fmadds")[](https://decomp-academy.dev/lesson/floats-lerp "The Lerp Idiom — fsubs Feeding fmadds")[](https://decomp-academy.dev/lesson/floats-dot-product-2d "Two Products Summed — the 2D Dot Product")[](https://decomp-academy.dev/lesson/floats-dot-product-3d "Accumulating Three Products — the 3D Dot Product")[](https://decomp-academy.dev/lesson/floats-max-via-compare "Picking the Larger: fcmpo + Conditional fmr")[](https://decomp-academy.dev/lesson/floats-two-sided-clamp "Clamping Between Two Constants")[](https://decomp-academy.dev/lesson/floats-f32-f64-mixing "Mixing f32 and f64 — Double Math, then frsp")[](https://decomp-academy.dev/lesson/floats-capstone-approach "★ Capstone: A Float Step With a Clamp")[](https://decomp-academy.dev/lesson/finale-scale-then-clamp "Scale, Then Clamp")[](https://decomp-academy.dev/lesson/finale-real-global-carry-chain "A 64-bit Global Accumulator")[](https://decomp-academy.dev/lesson/finale-masked-guarded-sum "A Masked, Guarded Accumulator")[](https://decomp-academy.dev/lesson/finale-real-framed-global-clamp "Call, Read a Global, Clamp")[](https://decomp-academy.dev/lesson/finale-build-a-bitmask "Building a Bitmask in a Loop")[](https://decomp-academy.dev/lesson/finale-real-scheduled-global-fmadds "Globals, Literals, and the Scheduler")[](https://decomp-academy.dev/lesson/finale-struct-field-sum-clamp "Sum a Struct Field, Then Clamp")[](https://decomp-academy.dev/lesson/finale-real-jumptable-volatile-dispatch "★ A Jump-Table of Volatile Reads")[](https://decomp-academy.dev/lesson/finale-guarded-float-accumulate "A Guarded Float Accumulator")[](https://decomp-academy.dev/lesson/finale-real-downcast-clamp-finale "★ 64-bit Globals, Downcast, Clamp")[](https://decomp-academy.dev/lesson/abi-arg-registers "The Integer Argument Registers")[](https://decomp-academy.dev/lesson/abi-fifth-arg "Reaching the Fifth Argument")[](https://decomp-academy.dev/lesson/abi-float-args "Floats Use Their Own Registers")[](https://decomp-academy.dev/lesson/abi-leaf-function "A Leaf Has No Stack Frame")[](https://decomp-academy.dev/lesson/abi-stack-frame "The Stack Frame and the Link Register")[](https://decomp-academy.dev/lesson/abi-arg-marshalling "Marshalling Arguments for a Call")[](https://decomp-academy.dev/lesson/abi-saved-registers "Surviving a Call: Saved Registers")[](https://decomp-academy.dev/lesson/abi-declaration-order "Declaration Order Colors the Registers")[](https://decomp-academy.dev/lesson/abi-tail-call "Returning a Called Result Directly")[](https://decomp-academy.dev/lesson/abi-stack-args "When Arguments Spill to the Stack")[](https://decomp-academy.dev/lesson/abi-keep-and-call "Chaining: Keep a Value, Marshal the Rest")[](https://decomp-academy.dev/lesson/abi-pipe-through "Chaining: Pipe One Call's Result Into the Next")[](https://decomp-academy.dev/lesson/abi-two-survivors-call "Chaining: Two Survivors Feeding a Final Call")[](https://decomp-academy.dev/lesson/abi-finale "Chaining: The Whole ABI in One Function")[](https://decomp-academy.dev/lesson/globals-read-int "Reading a Global Through the Small Data Area")[](https://decomp-academy.dev/lesson/globals-write-int "Writing a Global")[](https://decomp-academy.dev/lesson/globals-narrow-type "The Opcode Follows the Type")[](https://decomp-academy.dev/lesson/globals-read-float "A Global Float and the Second Small Data Area")[](https://decomp-academy.dev/lesson/globals-float-literal "Float Literals Become Pooled Constants")[](https://decomp-academy.dev/lesson/globals-address-of "Taking an Address: SDA li vs. the @ha/@l Pair")[](https://decomp-academy.dev/lesson/globals-array-index "Indexing a Global Array")[](https://decomp-academy.dev/lesson/globals-read-compute-write "Read Two Globals, Compute, Write Back")[](https://decomp-academy.dev/lesson/globals-float-global-literal "A Float Global Times a Pooled Literal")[](https://decomp-academy.dev/lesson/globals-scale-narrow-store "Read Wide, Store Narrow")[](https://decomp-academy.dev/lesson/globals-array-store "Writing Into a Global Array")[](https://decomp-academy.dev/lesson/globals-array-index-narrow "Index an Array, Narrow the Result")[](https://decomp-academy.dev/lesson/globals-array-rmw-scalar "Read-Modify-Write an Array Element")[](https://decomp-academy.dev/lesson/globals-float-array-literal-scalar "★ A Float Array Element, Scaled Into a Global")[](https://decomp-academy.dev/lesson/globals-capstone "★ Capstone: A Lighting-Update Function")[](https://decomp-academy.dev/lesson/optimization-o4p "What -O4,p Actually Does")[](https://decomp-academy.dev/lesson/optimization-scheduling "Instruction Scheduling: Hiding Latency")[](https://decomp-academy.dev/lesson/optimization-peephole-merge "The Peephole Optimizer: Dot-Form Merging")[](https://decomp-academy.dev/lesson/optimization-peephole-off "#pragma peephole off: Unfusing the Merge")[](https://decomp-academy.dev/lesson/optimization-scheduling-off "#pragma scheduling off: Freezing the Order")[](https://decomp-academy.dev/lesson/optimization-fp-scheduling "Scheduling Floating-Point Work")[](https://decomp-academy.dev/lesson/optimization-fp-contract "fp_contract: Fused Multiply-Add")[](https://decomp-academy.dev/lesson/optimization-strength-reduction "Strength Reduction in a Loop")[](https://decomp-academy.dev/lesson/optimization-cse "Common-Subexpression Elimination")[](https://decomp-academy.dev/lesson/optimization-cse-strength "Chaining: CSE Feeds Strength Reduction")[](https://decomp-academy.dev/lesson/optimization-schedule-peephole "Chaining: Scheduling Plus a Dot-Merge")[](https://decomp-academy.dev/lesson/optimization-fp-dot-chain "Chaining: FP Scheduling and fp_contract at Arity Three")[](https://decomp-academy.dev/lesson/optimization-fp-cse-contract "Chaining: A Reused Product Inside a Fused Multiply-Add")[](https://decomp-academy.dev/lesson/optimization-capstone "Capstone: Scheduling Meets fp_contract")[](https://decomp-academy.dev/lesson/advanced-switch-jumptable "Switch: The Jump Table")[](https://decomp-academy.dev/lesson/advanced-switch-decision "Table or Chain? The Density Rule")[](https://decomp-academy.dev/lesson/advanced-psq-callee-save "Paired-Single FPR Saves in the Prologue")[](https://decomp-academy.dev/lesson/advanced-psq-asm-exception "Where Inline asm{} Earns Its Place: psq_l / psq_st")[](https://decomp-academy.dev/lesson/advanced-enum-sizing "Enums Are int-Sized: Recovery Is Naming")[](https://decomp-academy.dev/lesson/advanced-volatile-cse "Volatile Defeats CSE: Two Reads, Two Loads")[](https://decomp-academy.dev/lesson/advanced-volatile-hwreg "Volatile Hardware Registers")[](https://decomp-academy.dev/lesson/advanced-enum-jumptable "Chain: An Enum Switched Through the Table")[](https://decomp-academy.dev/lesson/advanced-hwreg-switch "Chain: Switch on a Hardware Register")[](https://decomp-academy.dev/lesson/advanced-enum-volatile-guard "Chain: Enum Guard, Then a Volatile Sum")[](https://decomp-academy.dev/lesson/advanced-state-machine "Capstone: A Volatile-Guarded Enum State Machine")[](https://decomp-academy.dev/lesson/advanced-psq-switch-combine "Capstone II: Saved Floats Dispatched Through a Switch")[](https://decomp-academy.dev/lesson/int64-register-pairing "Two Registers Make a long long")[](https://decomp-academy.dev/lesson/int64-add "Adding 64-bit Integers (addc / adde)")[](https://decomp-academy.dev/lesson/int64-sub "Subtracting 64-bit Integers (subfc / subfe)")[](https://decomp-academy.dev/lesson/int64-register-alignment "The Odd-Register Alignment Rule")[](https://decomp-academy.dev/lesson/int64-downcast "The Downcast Fingerprint")[](https://decomp-academy.dev/lesson/int64-multiply "Multiplying 64-bit Integers")[](https://decomp-academy.dev/lesson/int64-divide "Division Calls an Intrinsic")[](https://decomp-academy.dev/lesson/int64-shift "Shifts Call an Intrinsic Too")[](https://decomp-academy.dev/lesson/int64-bitwise "Bitwise Ops Are Just Two Halves")[](https://decomp-academy.dev/lesson/int64-compare "Comparing 64-bit Integers")[](https://decomp-academy.dev/lesson/int64-carry-then-borrow "Chaining: Carry Into a Borrow")[](https://decomp-academy.dev/lesson/int64-bitwise-then-add "Chaining: A Bitwise Pair Feeds a Carry Chain")[](https://decomp-academy.dev/lesson/int64-downcast-chain "Chaining: A Downcast Prunes the Chain")[](https://decomp-academy.dev/lesson/int64-sum-then-compare "Chaining: A Sum Feeds a 64-bit Compare")[](https://decomp-academy.dev/lesson/int64-three-stage-fuse "Chaining: Carry, Borrow, and Mask in One Body")[](https://decomp-academy.dev/lesson/finale-scale-then-clamp "Scale, Then Clamp")[](https://decomp-academy.dev/lesson/finale-real-global-carry-chain "A 64-bit Global Accumulator")[](https://decomp-academy.dev/lesson/finale-masked-guarded-sum "A Masked, Guarded Accumulator")[](https://decomp-academy.dev/lesson/finale-real-framed-global-clamp "Call, Read a Global, Clamp")[](https://decomp-academy.dev/lesson/finale-build-a-bitmask "Building a Bitmask in a Loop")[](https://decomp-academy.dev/lesson/finale-real-scheduled-global-fmadds "Globals, Literals, and the Scheduler")[](https://decomp-academy.dev/lesson/finale-struct-field-sum-clamp "Sum a Struct Field, Then Clamp")[](https://decomp-academy.dev/lesson/finale-real-jumptable-volatile-dispatch "★ A Jump-Table of Volatile Reads")[](https://decomp-academy.dev/lesson/finale-guarded-float-accumulate "A Guarded Float Accumulator")[](https://decomp-academy.dev/lesson/finale-real-downcast-clamp-finale "★ 64-bit Globals, Downcast, Clamp")[](https://decomp-academy.dev/lesson/mastery-spellstone-setstate "A Real Setter: State, a Float Nudge, and a Boolean Return")[](https://decomp-academy.dev/lesson/mastery-fueltank-apply "Copying a Position With a Bias")[](https://decomp-academy.dev/lesson/mastery-fueltank-tick "A Flag Toggle Behind a Helper Call")[](https://decomp-academy.dev/lesson/mastery-clamp-health "Clamping a Float Into Range")[](https://decomp-academy.dev/lesson/mastery-cloudrace-oncomplete "A Loop Over an Event Array")[](https://decomp-academy.dev/lesson/mastery-asteroid-orbit "Orbital Math: fmadds, fdivs, and Saved Float Registers")[](https://decomp-academy.dev/lesson/mastery-race-advance "A Phase State Machine")[](https://decomp-academy.dev/lesson/mastery-spellstone-step "A Per-Frame Update: Rotation, a Flag, and a Branch")[](https://decomp-academy.dev/lesson/mastery-tank-hitdetect "Guarded Hit Detection: NULL Chains and a Type Check")[](https://decomp-academy.dev/lesson/mastery-mine-reset "The Capstone: A Full Reset-to-Idle")[](https://decomp-academy.dev/lesson/mastery-tumbler-integratespin "peephole off: When You Must Write the (s16) Cast Yourself")[](https://decomp-academy.dev/lesson/mastery-voxmap-choosedir "Two Running Sums, Woven by Hand: Steering the ,p Scheduler")[](https://decomp-academy.dev/lesson/mastery-targetblock-scorehit "Param Inversion: Who Gets the Saved Register")[](https://decomp-academy.dev/lesson/mastery-blend-accumulate "Declaration Order Is Register Order: Coloring Saved Regs by Hand")
Solved Attempted Not started Concept (reading) Difficulty 1–5
I
Warm-up
Learn to read the machine
0/6
1
Foundations Continue here
What decompilation is, PowerPC registers, and reading MWCC output.
~30 m 0/6
Your First Match ResumeArguments Live in Registers TooAdding Two RegistersSubtraction Reverses Its OperandsImmediates: Math With ConstantsNegation and the Zero Register
II
Core idioms
Every shape C compiles into
0/164
2
Integer Arithmetic
Add, subtract, multiply, divide, immediates and the bit-twiddling idioms.
~164 m 0/24
An Add Then a SubtractTwo Adds, ReassociatedA Subtract Then an AddA Three-Instruction ChainMultiplying Two RegistersMultiply by a Power of TwoMultiply by a Small ConstantAn Affine ExpressionUnsigned Divide by a Power of TwoSigned Divide by a Power of TwoReal DivisionModulo Has No InstructionMultiply Then AddPrecedence Changes the OrderTwo Products, SubtractedA Three-Instruction Mixed ChainWhen a Multiply Is a ShiftA Shift Inside a Mixed ChainDivide Then AddWhen a Divide Is a ShiftA Shift-Divide in a ChainDivide and Multiply, Then SubtractMultiply and Divide CombinedAll Four Arithmetic Operators
3
Bitwise & Shifts
AND/OR/XOR, masks, shifts, and the rlwinm family MWCC loves.
~122 m 0/16
Masking Bits With ANDCombining Bits With ORFlipping Bits With XORSetting a Single Flag BitClearing a Bit: The rlwinm SurpriseTesting Whether a Bit Is SetShifting Left by a ConstantLogical Right Shift (Unsigned)Arithmetic Right Shift (Signed)Shifting by a Variable AmountExtracting a Bitfield in One rlwinmPacking Two Values with a Shift and ORMerging Two Fields: rlwinm + rlwimiChaining XOR Across Three ValuesBit Select (Mux): AND, ANDC, ORCapstone: Pack Three Values into One Word
4
Control Flow
if/else, ternaries, switch, and the all-important signed-vs-unsigned compare.
~151 m 0/19
Returning a Comparison as a BoolNot-Equal Is Its Own IdiomIf / Else: The Compare Feeds a BranchTwo's Complement, srawi, and andc by Hand ConceptClamping to Zero, BranchlesslySigned Compare: cmpwUnsigned Compare: cmplwComparing Against a Constant: cmpwi vs cmplwiThe Guard Clause / Early ReturnTernary MaxTernary MinShort-Circuit && and ||Switch: The Compare ChainClamping Between Two BoundsThe if / else-if LadderA Range Test with &&Rejecting Out-of-Range with ||A Multi-Condition GuardCapstone: A Guarded, Clamped Update
5
Loops
for, while, do-while, induction variables and counted loops.
~125 m 0/15
The Anatomy of a Counted LoopWhile Is the Same LoopDo-While: The Tightest LoopCounting Down Is CheaperWalking an Array by IndexFinding the MaximumWalking a Pointer to a SentinelBreaking Out EarlyA Mental Model: The Five Parts of a Loop ConceptStrength-Reduced InductionA Loop With More Work InsideNested LoopsNesting Over a 2-D ArrayWhen the Inner Bound Follows the OuterCapstone: Counting Pairs in a Grid Scan
6
Types & Width
u8/s8/u16/s16 loads, sign vs zero extension, and width-driven matching, building up to mixed-width and mixed-sign expressions.
~141 m 0/17
Loading a ByteLoading a HalfwordSigned Loads Sign-ExtendStoring a Byte TruncatesStoring a Halfwordu8, Not char (The Spurious extsb)Widening: Zero vs Sign ExtendTruncating With a MaskCasts That Sign-ExtendCasting Between Signed WidthsThe Compare Opcode Follows the TypeBumping a Byte CounterRead, Scale, TruncateA Signed Halfword Read-Modify-WriteCombining Two WidthsMixed Signedness in One ExpressionCapstone: Widths and Signs in One Function
7
Pointers & Memory
Loads and stores, addressing modes, pointer arithmetic and arrays.
~148 m 0/18
Dereferencing a PointerStoring Through a PointerA Constant Index Becomes a DisplacementWriting at a Constant IndexPointer Arithmetic Is ScaledA Variable Index Needs Scaling Then IndexingByte Arrays Need No ShiftHalfword Arrays Shift by OneWalking a StringComparing Two PointersGuarding Against NULLSwapping Through PointersReading Two Elements and Combining ThemScaling One Element Before CombiningDereference, Then Compute With an ArgumentIndexing Neighbors From a Computed OffsetCombining Two Arrays at the Same IndexCapstone: Several Dereferences in One Expression
8
Structs, Unions & Bitfields
From single fields up to combining several across nested structs, member arrays, unions, and bitfields.
~168 m 0/22
Reading a Struct FieldWriting a Struct FieldNarrow Fields: Byte and Halfword LoadsStoring a Byte FieldAlignment Padding Shifts an OffsetCombining Two FieldsComputing Across Three FieldsNested Structs Flatten to One OffsetCombining Fields Across Nested StructsArrays of Structs: Scaling the IndexAn Array Inside a StructUnions Overlay the Same BytesA Single-Bit Flag: li; rlwimiMulti-Bit Bitfield WritesReading a Bitfield: rlwinm ExtractWalking a Linked ListCalling Through a Function PointerCopying a Whole StructEight-Byte Alignment Copies Through Float RegistersBig Structs Copy in a LoopCombining a Copy With a Field UpdateCapstone: Reading a Whole Struct
9
Floating Point
f32 vs f64, frsp, fused multiply-add, and float comparisons.
~183 m 0/23
Floats Live in a Different Register FileSingle-Precision MultiplySubtraction Keeps Its OrderFloating-Point Division Is RealDividing by a Constant Becomes a MultiplyDoubles Drop the 's'★ The Spurious frsp: f32 vs double HelpersLoading a Float Constant from the SDA★ Fused Multiply-AddInteger to Float: The Magic-Number TrickFloat to Int: fctiwz and the Store/Load DanceComparing Floats: fcmpo Feeding a BranchAbsolute Value and NegationChaining Two Float AddsMixing Add and Subtract in One ChainA Weighted Sum Folds Into One fmaddsThe Lerp Idiom — fsubs Feeding fmaddsTwo Products Summed — the 2D Dot ProductAccumulating Three Products — the 3D Dot ProductPicking the Larger: fcmpo + Conditional fmrClamping Between Two ConstantsMixing f32 and f64 — Double Math, then frsp★ Capstone: A Float Step With a Clamp
10
Putting It Together
Whole functions that combine arithmetic, bits, control, loops, types, pointers and structs into one realistic body.
~98 m 0/10
Scale, Then ClampA 64-bit Global AccumulatorA Masked, Guarded AccumulatorCall, Read a Global, ClampBuilding a Bitmask in a LoopGlobals, Literals, and the SchedulerSum a Struct Field, Then Clamp★ A Jump-Table of Volatile ReadsA Guarded Float Accumulator★ 64-bit Globals, Downcast, Clamp
III
The real ABI
Frames, globals, optimizer, 64-bit
0/80
11
Functions & the ABI
Arg registers, saved registers, stack frames and declaration-order coloring.
~118 m 0/14
The Integer Argument RegistersReaching the Fifth ArgumentFloats Use Their Own RegistersA Leaf Has No Stack FrameThe Stack Frame and the Link RegisterMarshalling Arguments for a CallSurviving a Call: Saved RegistersDeclaration Order Colors the RegistersReturning a Called Result DirectlyWhen Arguments Spill to the StackChaining: Keep a Value, Marshal the RestChaining: Pipe One Call's Result Into the NextChaining: Two Survivors Feeding a Final CallChaining: The Whole ABI in One Function
12
Globals, the SDA & Pools
r13/r2 small-data addressing, @sda21/@ha/@l relocations, and rodata pools.
~145 m 0/15
Reading a Global Through the Small Data AreaWriting a GlobalThe Opcode Follows the TypeA Global Float and the Second Small Data AreaFloat Literals Become Pooled ConstantsTaking an Address: SDA li vs. the @ha/@l PairIndexing a Global ArrayRead Two Globals, Compute, Write BackA Float Global Times a Pooled LiteralRead Wide, Store NarrowWriting Into a Global ArrayIndex an Array, Narrow the ResultRead-Modify-Write an Array Element★ A Float Array Element, Scaled Into a Global★ Capstone: A Lighting-Update Function
13
Optimization & Scheduling
-O4,p, peephole, instruction scheduling, and the pragmas that bend them.
~142 m 0/14
What -O4,p Actually DoesInstruction Scheduling: Hiding LatencyThe Peephole Optimizer: Dot-Form Merging#pragma peephole off: Unfusing the Merge#pragma scheduling off: Freezing the OrderScheduling Floating-Point Workfp_contract: Fused Multiply-AddStrength Reduction in a LoopCommon-Subexpression EliminationChaining: CSE Feeds Strength ReductionChaining: Scheduling Plus a Dot-MergeChaining: FP Scheduling and fp_contract at Arity ThreeChaining: A Reused Product Inside a Fused Multiply-AddCapstone: Scheduling Meets fp_contract
14
Advanced Idioms
Paired-singles, switch jump tables, enums, and volatile — the master's toolkit.
~128 m 0/12
Switch: The Jump TableTable or Chain? The Density RulePaired-Single FPR Saves in the PrologueWhere Inline asm{} Earns Its Place: psq_l / psq_stEnums Are int-Sized: Recovery Is NamingVolatile Defeats CSE: Two Reads, Two LoadsVolatile Hardware RegistersChain: An Enum Switched Through the TableChain: Switch on a Hardware RegisterChain: Enum Guard, Then a Volatile SumCapstone: A Volatile-Guarded Enum State MachineCapstone II: Saved Floats Dispatched Through a Switch
15
64-bit Integers
long long across two registers — carry chains, ABI pairing, downcast fingerprints, and intrinsics.
~125 m 0/15
Two Registers Make a long long ConceptAdding 64-bit Integers (addc / adde)Subtracting 64-bit Integers (subfc / subfe)The Odd-Register Alignment RuleThe Downcast FingerprintMultiplying 64-bit IntegersDivision Calls an IntrinsicShifts Call an Intrinsic TooBitwise Ops Are Just Two HalvesComparing 64-bit IntegersChaining: Carry Into a BorrowChaining: A Bitwise Pair Feeds a Carry ChainChaining: A Downcast Prunes the ChainChaining: A Sum Feeds a 64-bit CompareChaining: Carry, Borrow, and Mask in One Body
16
The Whole ABI at Once
Whole realistic function bodies that fuse frames, globals, the optimizer, and 64-bit work — every chapter of the tier converging in one symbol.
~98 m 0/10
Scale, Then ClampA 64-bit Global AccumulatorA Masked, Guarded AccumulatorCall, Read a Global, ClampBuilding a Bitmask in a LoopGlobals, Literals, and the SchedulerSum a Struct Field, Then Clamp★ A Jump-Table of Volatile ReadsA Guarded Float Accumulator★ 64-bit Globals, Downcast, Clamp
IV
Proving ground
Real Star Fox Adventures functions, start to finish
0/14
17
Real-World Mastery
Authentic Star Fox Adventures functions, from warm-ups to full capstones.
~162 m 0/14
A Real Setter: State, a Float Nudge, and a Boolean ReturnCopying a Position With a BiasA Flag Toggle Behind a Helper CallClamping a Float Into RangeA Loop Over an Event ArrayOrbital Math: fmadds, fdivs, and Saved Float RegistersA Phase State MachineA Per-Frame Update: Rotation, a Flag, and a BranchGuarded Hit Detection: NULL Chains and a Type CheckThe Capstone: A Full Reset-to-Idlepeephole off: When You Must Write the (s16) Cast YourselfTwo Running Sums, Woven by Hand: Steering the ,p SchedulerParam Inversion: Who Gets the Saved RegisterDeclaration Order Is Register Order: Coloring Saved Regs by Hand
Decomp Academy
Learn to decompile GameCube PowerPC assembly into byte-matching C — graded live by the real Metrowerks CodeWarrior GC/2.0 compiler.
Learn
Decomp projects
Lessons draw on real functions from open-source GameCube decompilations:
Community
Not affiliated with Nintendo, Rare, Retro Studios, or Hudson Soft. Star Fox Adventures, Pikmin, Metroid Prime, and Mario Party are trademarks of their respective owners. Linked decompilation projects are independent and community-run.