p.enthalabs

Decomp Academy — Learn GameCube Decompilation (MWCC GC/2.0)

Decomp Academy MWCC GC/2.0

PlaygroundCurriculumSign in

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.

Start from zero

256

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 source · the compiler grades it byte-for-byte.

Jump back in →

GameCube 256

0 / 256 matched

functions reconstructed

0

in progress

0

XP

Recruit

[](https://decomp-academy.dev/courses/gamecube-c/lesson/foundations-what-is-matching "What Matching Decompilation Is")[](https://decomp-academy.dev/courses/gamecube-c/lesson/foundations-reading-assembly "How to Read PowerPC Assembly")[](https://decomp-academy.dev/courses/gamecube-c/lesson/foundations-welcome "Your First Match")[](https://decomp-academy.dev/courses/gamecube-c/lesson/foundations-identity "Arguments Live in Registers Too")[](https://decomp-academy.dev/courses/gamecube-c/lesson/foundations-add "Adding Two Registers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/foundations-subtract "Subtraction Reverses Its Operands")[](https://decomp-academy.dev/courses/gamecube-c/lesson/foundations-immediate "Immediates: Math With Constants")[](https://decomp-academy.dev/courses/gamecube-c/lesson/foundations-negate "Negation and the Zero Register")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-add-sub "An Add Then a Subtract")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-two-adds "Two Adds, Reassociated")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-sub-add "A Subtract Then an Add")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-add-sub-add "A Three-Instruction Chain")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-mul "Multiplying Two Registers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-mul-const-pow2 "Multiply by a Power of Two")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-mul-const "Multiply by a Small Constant")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-affine "An Affine Expression")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-div-pow2-unsigned "Unsigned Divide by a Power of Two")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-div-pow2-signed "Signed Divide by a Power of Two")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-div-var "Real Division")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-mod "Modulo Has No Instruction")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-mul-add "Multiply Then Add")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-add-mul "Precedence Changes the Order")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-two-products "Two Products, Subtracted")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-mul-add-sub "A Three-Instruction Mixed Chain")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-scale-sum "When a Multiply Is a Shift")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-scale-chain "A Shift Inside a Mixed Chain")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-div-add "Divide Then Add")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-shrink-sum "When a Divide Is a Shift")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-shrink-chain "A Shift-Divide in a Chain")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-div-sub-mul "Divide and Multiply, Then Subtract")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-mul-add-div "Multiply and Divide Combined")[](https://decomp-academy.dev/courses/gamecube-c/lesson/arithmetic-all-four-ops "All Four Arithmetic Operators")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-and-mask "Masking Bits With AND")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-or "Combining Bits With OR")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-xor "Flipping Bits With XOR")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-set-flag "Setting a Single Flag Bit")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-clear-flag "Clearing a Bit: The rlwinm Surprise")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-test-bit "Testing Whether a Bit Is Set")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-shift-left "Shifting Left by a Constant")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-shift-right-unsigned "Logical Right Shift (Unsigned)")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-shift-right-signed "Arithmetic Right Shift (Signed)")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-shift-variable "Shifting by a Variable Amount")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-extract-field "Extracting a Bitfield in One rlwinm")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-shift-or-pack "Packing Two Values with a Shift and OR")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-merge-fields "Merging Two Fields: rlwinm + rlwimi")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-xor-chain "Chaining XOR Across Three Values")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-bit-select "Bit Select (Mux): AND, ANDC, OR")[](https://decomp-academy.dev/courses/gamecube-c/lesson/bitwise-pack-three "Capstone: Pack Three Values into One Word")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-eq-bool "Returning a Comparison as a Bool")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-ne-bool "Not-Equal Is Its Own Idiom")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-if-else "If / Else: The Compare Feeds a Branch")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-sign-masks "Two's Complement, srawi, and andc by Hand")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-clamp-low "Clamping to Zero, Branchlessly")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-cmp-signed "Signed Compare: cmpw")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-cmp-unsigned "Unsigned Compare: cmplw")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-cmp-immediate "Comparing Against a Constant: cmpwi vs cmplwi")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-guard "The Guard Clause / Early Return")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-ternary-max "Ternary Max")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-ternary-min "Ternary Min")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-short-circuit "Short-Circuit && and ||")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-switch "Switch: The Compare Chain")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-clamp-range "Clamping Between Two Bounds")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-nested-ladder "The if / else-if Ladder")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-range-and "A Range Test with &&")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-reject-or "Rejecting Out-of-Range with ||")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-guard-or "A Multi-Condition Guard")[](https://decomp-academy.dev/courses/gamecube-c/lesson/control-capstone-clamp-step "Capstone: A Guarded, Clamped Update")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-for-sum "The Anatomy of a Counted Loop")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-while-equivalence "While Is the Same Loop")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-do-while "Do-While: The Tightest Loop")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-countdown "Counting Down Is Cheaper")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-array-sum "Walking an Array by Index")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-array-max "Finding the Maximum")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-strlen "Walking a Pointer to a Sentinel")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-break "Breaking Out Early")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-anatomy-model "A Mental Model: The Five Parts of a Loop")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-strength-reduction "Strength-Reduced Induction")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-weighted-sum "A Loop With More Work Inside")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-nested "Nested Loops")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-grid-sum "Nesting Over a 2-D Array")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-triangular "When the Inner Bound Follows the Outer")[](https://decomp-academy.dev/courses/gamecube-c/lesson/loops-inversions "Capstone: Counting Pairs in a Grid Scan")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-load-u8 "Loading a Byte")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-load-u16 "Loading a Halfword")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-load-signed "Signed Loads Sign-Extend")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-store-byte "Storing a Byte Truncates")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-store-half "Storing a Halfword")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-u8-not-char "u8, Not char (The Spurious extsb)")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-widen-zero-vs-sign "Widening: Zero vs Sign Extend")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-truncate-mask "Truncating With a Mask")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-explicit-cast "Casts That Sign-Extend")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-cast-between-signed "Casting Between Signed Widths")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-compare-width "The Compare Opcode Follows the Type")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-counter-increment "Bumping a Byte Counter")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-rmw-scale "Read, Scale, Truncate")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-rmw-half "A Signed Halfword Read-Modify-Write")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-mix-widths "Combining Two Widths")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-mix-signs "Mixed Signedness in One Expression")[](https://decomp-academy.dev/courses/gamecube-c/lesson/types-capstone "Capstone: Widths and Signs in One Function")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-deref "Dereferencing a Pointer")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-store "Storing Through a Pointer")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-index-const "A Constant Index Becomes a Displacement")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-store-index-const "Writing at a Constant Index")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-arith "Pointer Arithmetic Is Scaled")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-index-var "A Variable Index Needs Scaling Then Indexing")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-u8-array "Byte Arrays Need No Shift")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-u16-array "Halfword Arrays Shift by One")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-strlen "Walking a String")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-compare "Comparing Two Pointers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-null-check "Guarding Against NULL")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-swap "Swapping Through Pointers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-sum-two "Reading Two Elements and Combining Them")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-weighted-elements "Scaling One Element Before Combining")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-deref-then-compute "Dereference, Then Compute With an Argument")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-computed-offset "Indexing Neighbors From a Computed Offset")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-two-arrays "Combining Two Arrays at the Same Index")[](https://decomp-academy.dev/courses/gamecube-c/lesson/pointers-capstone "Capstone: Several Dereferences in One Expression")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-read-field "Reading a Struct Field")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-write-field "Writing a Struct Field")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-narrow-read "Narrow Fields: Byte and Halfword Loads")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-narrow-write "Storing a Byte Field")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-padding "Alignment Padding Shifts an Offset")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-sum-fields "Combining Two Fields")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-combine-fields "Computing Across Three Fields")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-nested "Nested Structs Flatten to One Offset")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-struct-of-structs "Combining Fields Across Nested Structs")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-array-index "Arrays of Structs: Scaling the Index")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-array-field "An Array Inside a Struct")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-union "Unions Overlay the Same Bytes")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-bitfield-set "A Single-Bit Flag: li; rlwimi")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-bitfield-multi "Multi-Bit Bitfield Writes")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-bitfield-read "Reading a Bitfield: rlwinm Extract")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-linked-list "Walking a Linked List")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-function-pointer "Calling Through a Function Pointer")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-copy-whole "Copying a Whole Struct")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-copy-aligned "Eight-Byte Alignment Copies Through Float Registers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-copy-large "Big Structs Copy in a Loop")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-copy-chain "Combining a Copy With a Field Update")[](https://decomp-academy.dev/courses/gamecube-c/lesson/structs-capstone "Capstone: Reading a Whole Struct")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-add "Floats Live in a Different Register File")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-mul "Single-Precision Multiply")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-sub "Subtraction Keeps Its Order")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-div "Floating-Point Division Is Real")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-div-const-reciprocal "Dividing by a Constant Becomes a Multiply")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-double-add "Doubles Drop the 's'")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-frsp-highlight "★ The Spurious frsp: f32 vs double Helpers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-literal "Loading a Float Constant from the SDA")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-fmadds-highlight "★ Fused Multiply-Add")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-int-to-float "Integer to Float: The Magic-Number Trick")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-float-to-int "Float to Int: fctiwz and the Store/Load Dance")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-compare-branch "Comparing Floats: fcmpo Feeding a Branch")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-abs-neg "Absolute Value and Negation")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-two-adds "Chaining Two Float Adds")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-add-then-subtract "Mixing Add and Subtract in One Chain")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-weighted-sum "A Weighted Sum Folds Into One fmadds")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-lerp "The Lerp Idiom — fsubs Feeding fmadds")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-dot-product-2d "Two Products Summed — the 2D Dot Product")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-dot-product-3d "Accumulating Three Products — the 3D Dot Product")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-max-via-compare "Picking the Larger: fcmpo + Conditional fmr")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-two-sided-clamp "Clamping Between Two Constants")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-f32-f64-mixing "Mixing f32 and f64 — Double Math, then frsp")[](https://decomp-academy.dev/courses/gamecube-c/lesson/floats-capstone-approach "★ Capstone: A Float Step With a Clamp")[](https://decomp-academy.dev/courses/gamecube-c/lesson/finale-scale-then-clamp "Scale, Then Clamp")[](https://decomp-academy.dev/courses/gamecube-c/lesson/finale-masked-guarded-sum "A Masked, Guarded Accumulator")[](https://decomp-academy.dev/courses/gamecube-c/lesson/finale-build-a-bitmask "Building a Bitmask in a Loop")[](https://decomp-academy.dev/courses/gamecube-c/lesson/finale-struct-field-sum-clamp "Sum a Struct Field, Then Clamp")[](https://decomp-academy.dev/courses/gamecube-c/lesson/finale-guarded-float-accumulate "A Guarded Float Accumulator")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-arg-registers "The Integer Argument Registers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-fifth-arg "Reaching the Fifth Argument")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-float-args "Floats Use Their Own Registers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-leaf-function "A Leaf Has No Stack Frame")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-stack-frame "The Stack Frame and the Link Register")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-arg-marshalling "Marshalling Arguments for a Call")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-saved-registers "Surviving a Call: Saved Registers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-declaration-order "Declaration Order Colors the Registers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-tail-call "Returning a Called Result Directly")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-stack-args "When Arguments Spill to the Stack")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-keep-and-call "Chaining: Keep a Value, Marshal the Rest")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-pipe-through "Chaining: Pipe One Call's Result Into the Next")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-two-survivors-call "Chaining: Two Survivors Feeding a Final Call")[](https://decomp-academy.dev/courses/gamecube-c/lesson/abi-finale "Chaining: The Whole ABI in One Function")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-read-int "Reading a Global Through the Small Data Area")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-write-int "Writing a Global")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-narrow-type "The Opcode Follows the Type")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-read-float "A Global Float and the Second Small Data Area")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-float-literal "Float Literals Become Pooled Constants")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-address-of "Taking an Address: SDA li vs. the @ha/@l Pair")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-array-index "Indexing a Global Array")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-read-compute-write "Read Two Globals, Compute, Write Back")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-float-global-literal "A Float Global Times a Pooled Literal")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-scale-narrow-store "Read Wide, Store Narrow")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-array-store "Writing Into a Global Array")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-array-index-narrow "Index an Array, Narrow the Result")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-array-rmw-scalar "Read-Modify-Write an Array Element")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-float-array-literal-scalar "★ A Float Array Element, Scaled Into a Global")[](https://decomp-academy.dev/courses/gamecube-c/lesson/globals-capstone "★ Capstone: A Lighting-Update Function")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-o4p "What -O4,p Actually Does")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-scheduling "Instruction Scheduling: Hiding Latency")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-peephole-merge "The Peephole Optimizer: Dot-Form Merging")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-peephole-off "#pragma peephole off: Unfusing the Merge")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-scheduling-off "#pragma scheduling off: Freezing the Order")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-fp-scheduling "Scheduling Floating-Point Work")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-fp-contract "fp_contract: Fused Multiply-Add")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-strength-reduction "Strength Reduction in a Loop")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-cse "Common-Subexpression Elimination")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-cse-strength "Chaining: CSE Feeds Strength Reduction")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-schedule-peephole "Chaining: Scheduling Plus a Dot-Merge")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-fp-dot-chain "Chaining: FP Scheduling and fp_contract at Arity Three")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-fp-cse-contract "Chaining: A Reused Product Inside a Fused Multiply-Add")[](https://decomp-academy.dev/courses/gamecube-c/lesson/optimization-capstone "Capstone: Scheduling Meets fp_contract")[](https://decomp-academy.dev/courses/gamecube-c/lesson/advanced-switch-jumptable "Switch: The Jump Table")[](https://decomp-academy.dev/courses/gamecube-c/lesson/advanced-switch-decision "Table or Chain? The Density Rule")[](https://decomp-academy.dev/courses/gamecube-c/lesson/advanced-psq-callee-save "Paired-Single FPR Saves in the Prologue")[](https://decomp-academy.dev/courses/gamecube-c/lesson/advanced-psq-asm-exception "Where Inline asm{} Earns Its Place: psq_l / psq_st")[](https://decomp-academy.dev/courses/gamecube-c/lesson/advanced-enum-sizing "Enums Are int-Sized: Recovery Is Naming")[](https://decomp-academy.dev/courses/gamecube-c/lesson/advanced-volatile-cse "Volatile Defeats CSE: Two Reads, Two Loads")[](https://decomp-academy.dev/courses/gamecube-c/lesson/advanced-volatile-hwreg "Volatile Hardware Registers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/advanced-enum-jumptable "Chain: An Enum Switched Through the Table")[](https://decomp-academy.dev/courses/gamecube-c/lesson/advanced-hwreg-switch "Chain: Switch on a Hardware Register")[](https://decomp-academy.dev/courses/gamecube-c/lesson/advanced-enum-volatile-guard "Chain: Enum Guard, Then a Volatile Sum")[](https://decomp-academy.dev/courses/gamecube-c/lesson/advanced-state-machine "Capstone: A Volatile-Guarded Enum State Machine")[](https://decomp-academy.dev/courses/gamecube-c/lesson/advanced-psq-switch-combine "Capstone II: Saved Floats Dispatched Through a Switch")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-register-pairing "Two Registers Make a long long")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-add "Adding 64-bit Integers (addc / adde)")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-sub "Subtracting 64-bit Integers (subfc / subfe)")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-register-alignment "The Odd-Register Alignment Rule")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-downcast "The Downcast Fingerprint")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-multiply "Multiplying 64-bit Integers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-divide "Division Calls an Intrinsic")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-shift "Shifts Call an Intrinsic Too")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-bitwise "Bitwise Ops Are Just Two Halves")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-compare "Comparing 64-bit Integers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-carry-then-borrow "Chaining: Carry Into a Borrow")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-bitwise-then-add "Chaining: A Bitwise Pair Feeds a Carry Chain")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-downcast-chain "Chaining: A Downcast Prunes the Chain")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-sum-then-compare "Chaining: A Sum Feeds a 64-bit Compare")[](https://decomp-academy.dev/courses/gamecube-c/lesson/int64-three-stage-fuse "Chaining: Carry, Borrow, and Mask in One Body")[](https://decomp-academy.dev/courses/gamecube-c/lesson/finale-real-global-carry-chain "A 64-bit Global Accumulator")[](https://decomp-academy.dev/courses/gamecube-c/lesson/finale-real-framed-global-clamp "Call, Read a Global, Clamp")[](https://decomp-academy.dev/courses/gamecube-c/lesson/finale-real-scheduled-global-fmadds "Globals, Literals, and the Scheduler")[](https://decomp-academy.dev/courses/gamecube-c/lesson/finale-real-jumptable-volatile-dispatch "★ A Jump-Table of Volatile Reads")[](https://decomp-academy.dev/courses/gamecube-c/lesson/finale-real-downcast-clamp-finale "★ 64-bit Globals, Downcast, Clamp")[](https://decomp-academy.dev/courses/gamecube-c/lesson/mastery-spellstone-setstate "A Real Setter: State, a Float Nudge, and a Boolean Return")[](https://decomp-academy.dev/courses/gamecube-c/lesson/mastery-fueltank-apply "Copying a Position With a Bias")[](https://decomp-academy.dev/courses/gamecube-c/lesson/mastery-fueltank-tick "A Flag Toggle Behind a Helper Call")[](https://decomp-academy.dev/courses/gamecube-c/lesson/mastery-clamp-health "Clamping a Float Into Range")[](https://decomp-academy.dev/courses/gamecube-c/lesson/mastery-cloudrace-oncomplete "A Loop Over an Event Array")[](https://decomp-academy.dev/courses/gamecube-c/lesson/mastery-asteroid-orbit "Orbital Math: fmadds, fdivs, and Saved Float Registers")[](https://decomp-academy.dev/courses/gamecube-c/lesson/mastery-race-advance "A Phase State Machine")[](https://decomp-academy.dev/courses/gamecube-c/lesson/mastery-spellstone-step "A Per-Frame Update: Rotation, a Flag, and a Branch")[](https://decomp-academy.dev/courses/gamecube-c/lesson/mastery-tank-hitdetect "Guarded Hit Detection: NULL Chains and a Type Check")[](https://decomp-academy.dev/courses/gamecube-c/lesson/mastery-mine-reset "The Capstone: A Full Reset-to-Idle")[](https://decomp-academy.dev/courses/gamecube-c/lesson/mastery-tumbler-integratespin "peephole off: When You Must Write the (s16) Cast Yourself")[](https://decomp-academy.dev/courses/gamecube-c/lesson/mastery-voxmap-choosedir "Two Running Sums, Woven by Hand: Steering the ,p Scheduler")[](https://decomp-academy.dev/courses/gamecube-c/lesson/mastery-targetblock-scorehit "Param Inversion: Who Gets the Saved Register")[](https://decomp-academy.dev/courses/gamecube-c/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/8

1

Foundations Continue here

What decompilation is, PowerPC registers, and reading MWCC output.

~36 m 0/8

What Matching Decompilation Is Resume ConceptHow to Read PowerPC Assembly ConceptYour First MatchArguments 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/159

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.

~41 m 0/5

Scale, Then ClampA Masked, Guarded AccumulatorBuilding a Bitmask in a LoopSum a Struct Field, Then ClampA Guarded Float Accumulator

III

The real ABI

Frames, globals, optimizer, 64-bit

0/75

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 Registers[Chain: An Enum Switched Through the Table](https://decomp-academy.dev/courses/gamecube-c/lesson/advanced