Phase 1a (boot slice): 30 instructions at 0xBFC00000, compiles clean. Phase 1b (instruction coverage): 54 opcodes implemented in strict_translator, 44,629 walker-reachable instructions covered, 0 missing. Phase 1c (function discovery): 76 functions from 2 seeds, 2,988 instructions, 199 call edges, 27 indirect jumps. All validated through StrictTranslator. Phase 1d (indirect control flow): 27 sites classified — 21 A0/B0/C0 dispatch stubs, 4 computed calls, 2 computed tail calls. Ghidra cross-referenced with 0 disagreements. Phase 1e (relocation): ROM-to-RAM copy at FUN_bfc00420 proven with both Ghidra (static) and DuckStation (runtime). 69 address aliases, 68/69 function entries match byte-for-byte in RAM. Normalization rule documented. Includes PRINCIPLES.md and DEBUG.md adapted from recomp-template. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3.0 KiB
Address Normalization Rule — Phase 1e
Rule
A function's identity is its canonical physical address, computed in two steps:
Step 1: KSEG strip
physical = virtual_address & 0x1FFFFFFF
This removes the MIPS KSEG segment prefix. All four segments map to the same physical address space:
| Segment | Virtual range | Physical range |
|---|---|---|
| KUSEG | 0x00000000-0x7FFFFFFF | 0x00000000-0x1FFFFFFF |
| KSEG0 | 0x80000000-0x9FFFFFFF | 0x00000000-0x1FFFFFFF |
| KSEG1 | 0xA0000000-0xBFFFFFFF | 0x00000000-0x1FFFFFFF |
| KSEG2 | 0xC0000000-0xFFFFFFFF | (memory-mapped I/O) |
Step 2: ROM-to-RAM copy offset
If the physical address falls within the BIOS ROM copy source range, map it to the RAM destination:
if 0x1FC10000 <= physical <= 0x1FC18BEF:
physical = physical - 0x1FC10000 + 0x00000500
This accounts for the single proven ROM-to-RAM copy performed by
FUN_bfc00420 during BIOS init:
| Property | Value |
|---|---|
| Source | ROM 0xBFC10000 (physical 0x1FC10000) |
| Dest | RAM 0xA0000500 (physical 0x00000500) |
| Length | 0x8BF0 bytes (35,824 bytes) |
| Proof | generated/relocation_proofs/primary_copy/proof.json |
Combined formula
normalize(addr):
phys = addr & 0x1FFFFFFF
if 0x1FC10000 <= phys <= 0x1FC18BEF:
phys = phys - 0x1FC10000 + 0x00000500
return phys
Examples
| Input address | After KSEG strip | After ROM-to-RAM | Canonical |
|---|---|---|---|
| 0xBFC10C74 | 0x1FC10C74 | 0x00001174 | 0x00001174 |
| 0x80001174 | 0x00001174 | (not in ROM range) | 0x00001174 |
| 0xA0001174 | 0x00001174 | (not in ROM range) | 0x00001174 |
| 0xBFC00420 | 0x1FC00420 | (not in copy range) | 0x1FC00420 |
| 0xBFC06EC4 | 0x1FC06EC4 | (not in copy range) | 0x1FC06EC4 |
Evidence
- The copy parameters (source, destination, length) are all immediate constants in the BIOS code. No runtime computation is involved.
- Ghidra decompilation confirms the loop structure and parameters.
- 69 Ghidra-known functions fall within the copy source range.
- The normalization formula maps all 69 ROM-source functions to their RAM-destination equivalents, producing 69 alias pairs.
- No alias was added without tracing back to the proof artifact at
generated/relocation_proofs/primary_copy/proof.json.
Scope limitation
This rule covers only the single ROM-to-RAM copy identified in Phase 1e. If additional copies are discovered in later phases (e.g., from RAM-side code that runs after the initial copy), the rule must be extended with new proof artifacts.
The exception vector trampoline at 0x80000080 is installed by intra-RAM code at ROM 0xBFC109B0 (RAM 0x80000EB0) which copies 16 bytes from RAM 0x00000F0C to RAM 0x80000080. This is an intra-RAM copy (not ROM-to-RAM) and does not require a normalization entry because both addresses are already in RAM physical space.