Decompile retro-game assembly into byte-matching C.
Go from never having read a register to matching real functions from GameCube and Game Boy Advance games — instruction for instruction. You write C, the original compiler grades it live.
Start from zero
267
Lessons
0
Solved
Mastery0%
Graded by the original compilersFunctions from real open-source decomps
The Curriculum
Read the asm · write the source · the compiler grades it byte-for-byte.
Solved Attempted Not started Concept (reading)
Difficulty 1–5
I0/9
Warm-up
Learn to read the machine
II0/161
Core idioms
Every shape C compiles into
Adding Two Registers
Subtraction Reverses Its Operands
An Add Then a Subtract
Two Adds, Reassociated
A Subtract Then an Add
A Three-Instruction Chain
Multiplying Two Registers
Multiply by a Power of Two
An Affine Expression
Unsigned Divide by a Power of Two
Signed Divide by a Power of Two
Division Without a Divide
Real Division
Modulo Has No Instruction
Multiply Then Add
Precedence Changes the Order
Two Products, Subtracted
A Three-Instruction Mixed Chain
When a Multiply Is a Shift
A Shift Inside a Mixed Chain
Divide Then Add
When a Divide Is a Shift
A Shift-Divide in a Chain
Divide and Multiply, Then Subtract
Multiply and Divide Combined
All Four Arithmetic Operators
Masking Bits With AND
Combining Bits With OR
Flipping Bits With XOR
Setting a Single Flag Bit
Clearing a Bit: The rlwinm Surprise
Testing Whether a Bit Is Set
Shifting Left by a Constant
Logical Right Shift (Unsigned)
Arithmetic Right Shift (Signed)
Shifting by a Variable Amount
Extracting a Bitfield in One rlwinm
Packing Two Values with a Shift and OR
Merging Two Fields: rlwinm + rlwimi
Chaining XOR Across Three Values
Bit Select (Mux): AND, ANDC, OR
Capstone: Pack Three Values into One Word
Returning a Comparison as a Bool
Not-Equal Is Its Own Idiom
If / Else: The Compare Feeds a Branch
Two's Complement, srawi, and andc by HandConceptClamping to Zero, Branchlessly
Signed Compare: cmpw
Unsigned Compare: cmplw
Comparing Against a Constant: cmpwi vs cmplwi
The Guard Clause / Early Return
Ternary Max
Ternary Min
Short-Circuit && and ||
Switch: The Compare Chain
Clamping Between Two Bounds
The if / else-if Ladder
A Range Test with &&
Rejecting Out-of-Range with ||
A Multi-Condition Guard
Capstone: A Guarded, Clamped Update
The Anatomy of a Counted Loop
While Is the Same Loop
Do-While: The Tightest Loop
Counting Down Is Cheaper
Walking an Array by Index
Finding the Maximum
Walking a Pointer to a Sentinel
Breaking Out Early
A Mental Model: The Five Parts of a LoopConceptStrength-Reduced Induction
A Loop With More Work Inside
Nested Loops
Nesting Over a 2-D Array
When the Inner Bound Follows the Outer
Capstone: Counting Pairs in a Grid Scan
Loading a Byte
Loading a Halfword
Signed Loads Sign-Extend
Storing a Byte Truncates
Storing a Halfword
u8, Not char (The Spurious extsb)
Widening: Zero vs Sign Extend
Truncating With a Mask
Casts That Sign-Extend
Casting Between Signed Widths
The Compare Opcode Follows the Type
Bumping a Byte Counter
Read, Scale, Truncate
A Signed Halfword Read-Modify-Write
Combining Two Widths
Mixed Signedness in One Expression
Capstone: Widths and Signs in One Function
Dereferencing a Pointer
Storing Through a Pointer
A Constant Index Becomes a Displacement
Writing at a Constant Index
Pointer Arithmetic Is Scaled
A Variable Index Needs Scaling Then Indexing
Byte Arrays Need No Shift
Halfword Arrays Shift by One
Walking a String
Comparing Two Pointers
Guarding Against NULL
Swapping Through Pointers
Reading Two Elements and Combining Them
Scaling One Element Before Combining
Dereference, Then Compute With an Argument
Indexing Neighbors From a Computed Offset
Combining Two Arrays at the Same Index
Capstone: Several Dereferences in One Expression
Reading a Struct Field
Writing a Struct Field
Narrow Fields: Byte and Halfword Loads
Storing a Byte Field
Alignment Padding Shifts an Offset
Combining Two Fields
Computing Across Three Fields
Nested Structs Flatten to One Offset
Combining Fields Across Nested Structs
Arrays of Structs: Scaling the Index
An Array Inside a Struct
Unions Overlay the Same Bytes
A Single-Bit Flag: li; rlwimi
Multi-Bit Bitfield Writes
Reading a Bitfield: rlwinm Extract
Walking a Linked List
Calling Through a Function Pointer
Copying a Whole Struct
Eight-Byte Alignment Copies Through Float Registers
Big Structs Copy in a Loop
Combining a Copy With a Field Update
Capstone: Reading a Whole Struct
Floats Live in a Different Register File
Single-Precision Multiply
Subtraction Keeps Its Order
Floating-Point Division Is Real
Dividing by a Constant Becomes a Multiply
Doubles Drop the 's'
★ The Spurious frsp: f32 vs double Helpers
Loading a Float Constant from the SDA
★ Fused Multiply-Add
Integer to Float: The Magic-Number Trick
Float to Int: fctiwz and the Store/Load Dance
Comparing Floats: fcmpo Feeding a Branch
Absolute Value and Negation
Chaining Two Float Adds
Mixing Add and Subtract in One Chain
A Weighted Sum Folds Into One fmadds
The Lerp Idiom — fsubs Feeding fmadds
Two Products Summed — the 2D Dot Product
Accumulating Three Products — the 3D Dot Product
Picking the Larger: fcmpo + Conditional fmr
Clamping Between Two Constants
Mixing f32 and f64 — Double Math, then frsp
★ Capstone: A Float Step With a Clamp
III0/75
The real ABI
Frames, globals, optimizer, 64-bit
The Integer Argument Registers
Reaching the Fifth Argument
Floats Use Their Own Registers
A Leaf Has No Stack Frame
The Stack Frame and the Link Register
Marshalling Arguments for a Call
Surviving a Call: Saved Registers
Declaration Order Colors the Registers
Returning a Called Result Directly
When Arguments Spill to the Stack
Chaining: Keep a Value, Marshal the Rest
Chaining: Pipe One Call's Result Into the Next
Chaining: Two Survivors Feeding a Final Call
Chaining: The Whole ABI in One Function
Reading a Global Through the Small Data Area
Writing a Global
The Opcode Follows the Type
A Global Float and the Second Small Data Area
Float Literals Become Pooled Constants
Taking an Address: SDA li vs. the @ha/@l Pair
Indexing a Global Array
Read Two Globals, Compute, Write Back
A Float Global Times a Pooled Literal
Read Wide, Store Narrow
Writing Into a Global Array
Index an Array, Narrow the Result
Read-Modify-Write an Array Element
★ A Float Array Element, Scaled Into a Global
★ Capstone: A Lighting-Update Function
What -O4,p Actually Does
Instruction Scheduling: Hiding Latency
The Peephole Optimizer: Dot-Form Merging
#pragma peephole off: Unfusing the Merge
#pragma scheduling off: Freezing the Order
Scheduling Floating-Point Work
fp_contract: Fused Multiply-Add
Strength Reduction in a Loop
Common-Subexpression Elimination
Chaining: CSE Feeds Strength Reduction
Chaining: Scheduling Plus a Dot-Merge
Chaining: FP Scheduling and fp_contract at Arity Three
Chaining: A Reused Product Inside a Fused Multiply-Add
Capstone: Scheduling Meets fp_contract
Switch: The Jump Table
Table or Chain? The Density Rule
Paired-Single FPR Saves in the Prologue
Where Inline asm{} Earns Its Place: psq_l / psq_st
Enums Are int-Sized: Recovery Is Naming
Volatile Defeats CSE: Two Reads, Two Loads
Volatile Hardware Registers
Chain: An Enum Switched Through the Table
Chain: Switch on a Hardware Register
Chain: Enum Guard, Then a Volatile Sum
Capstone: A Volatile-Guarded Enum State Machine
Capstone II: Saved Floats Dispatched Through a Switch
Two Registers Make a long longConceptAdding 64-bit Integers (addc / adde)
Subtracting 64-bit Integers (subfc / subfe)
The Odd-Register Alignment Rule
The Downcast Fingerprint
Multiplying 64-bit Integers
Division Calls an Intrinsic
Shifts Call an Intrinsic Too
Bitwise Ops Are Just Two Halves
Comparing 64-bit Integers
Chaining: Carry Into a Borrow
Chaining: A Bitwise Pair Feeds a Carry Chain
Chaining: A Downcast Prunes the Chain
Chaining: A Sum Feeds a 64-bit Compare
Chaining: Carry, Borrow, and Mask in One Body
IV0/14
Proving ground
Real Star Fox Adventures functions, start to finish
A Real Setter: State, a Float Nudge, and a Boolean Return
Copying a Position With a Bias
A Flag Toggle Behind a Helper Call
Clamping a Float Into Range
A Loop Over an Event Array
Orbital Math: fmadds, fdivs, and Saved Float Registers
A Phase State Machine
A Per-Frame Update: Rotation, a Flag, and a Branch
Guarded Hit Detection: NULL Chains and a Type Check
The Capstone: A Full Reset-to-Idle
peephole off: When You Must Write the (s16) Cast Yourself
Two Running Sums, Woven by Hand: Steering the ,p Scheduler
Param Inversion: Who Gets the Saved Register
Declaration Order Is Register Order: Coloring Saved Regs by Hand