Files
retroDE_ps2/docs/wave3_bios_iop_sbus_recon.md
T
thejayman77 ec82764bef Initial commit: retroDE_ps2 — first-of-its-kind PS2 GS FPGA core (DE25-Nano / Agilex 5)
RTL (GS rasterizer, EE core stub, platform bridge, LPDDR4B path), sim regression
(272 TBs), docs, and tooling. Copyrighted PS2 content (BIOS, game code, GS dumps,
and all dump-derived textures/traces) is excluded via .gitignore and stays local.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 20:10:50 -04:00

27 KiB
Raw Blame History

Wave 3 — BIOS / IOP / SBUS reconnaissance + probe arc (Ch256Ch260)

Status: CLOSED MILESTONE (Ch260). The Ch256-Ch259 probe arc exhausted single-register approaches to breaking the Ch215 longjmp treadmill. The next BIOS attempt does NOT start with another hardcode — it starts with IOP-side state-machine modeling. See "Milestone closeout" section below for the full conclusion + Ch261+ pivot.

The earlier sections of this document are preserved for posterity; the chapter-by-chapter notes below reflect what was actually learned during the arc, not what we initially hypothesised.


Milestone closeout (Ch260)

Four chapters of probe-arc work produced four concrete facts:

  1. Ch256 recon → "primary hypothesis: EE timers." Wrong. tb_ee_core_bios_long observer eventually surfaced the real pattern — see Ch257.
  2. Ch257 Ch218 observer landed. After seven iterations (six more than necessary, lesson captured in feedback-pause-for-codex-on-iteration-loops) the observer was able to attribute reads to the JAL callee in the longjmp-return path. Surfaced IOP DMAC PCR + IOP INTC pair as the recurring polled MMIO targets. Timer hypothesis didn't survive contact.
  3. Ch258 IOP DMAC PCR realism stub (0xBF8010F0 → 0x07654321) — PCR was not the gate. The hardcode landed cleanly (verified via sim/traces/rtl/ee_bios_smoke_core.trace showing lw $14, 0x10f0($14) retiring with $14 = 0x07654321), BIOS reads-then-writes the value back as part of a save/modify/restore pattern, but the treadmill behaviour is byte-identical pre- vs. post-Ch258.
  4. Ch259 named IOP INTC behavior at 0x1F801070/0x1F801074 + sticky source injection — INTC alone is not enough.
    • Phase 1 (no synthetic source): proper W1C/mask semantics landed. BIOS exercises the full 14-instruction INTC dance every pass: probes I_MASK, W1C's I_STAT, polls I_STAT three times, sets up mask bits 0 and 3, repeats. Every I_STAT read returns 0. Verdict: intc_quiet. Treadmill persists.
    • Phase 2 (+IOP_INTC_BOOT_SRC=0001): the sticky source IS reaching the EE (verdict flipped to intc_pending_observed — at least one I_STAT read returned non-zero). BIOS sees the pending bit but still loops 8 passes with byte-identical retire count (24,029,051). Pending bit alone is necessary but not sufficient — the dispatch-through-handler doesn't reach a state where the longjmp restoration sees changed inputs.

Conclusion: the Ch215 treadmill requires multi-state IOP/SBUS/kernel activity — a real IOP responder that produces firmware-visible side effects (kernel globals written, SIF mailbox flags toggled, INTC sources asserted in response to actual events). Single-register hardcodes and single-bit synthetic sources do not suffice. Ch260 closes the BIOS-mmio probe arc.

What landed in the tree (kept)

  • rtl/ee/ee_bootstrap_mmio_stub.sv — three named MMIO behaviors promoted out of the anonymous regfile, all in production-shaped form with default-safe semantics:
    • 0x1814 (Ch202) — hardcoded 0xFFFFFFFF (RDRAM-init ready polling bit).
    • 0x10F0 (Ch258) — hardcoded 0x07654321 (IOP DMAC PCR realism stub, real PS1/IOP reset value).
    • 0x1070 / 0x1074 (Ch259) — named IOP INTC view with W1C on I_STAT, plain-write on I_MASK, sticky iop_intc_inject_src_i diagnostic injection port (default 0).
  • sim/tb/integration/tb_ee_core_bios_smoke.sv — Ch218 observer preserved as a compact INTC transaction log, gated behind \ifdef CH259_INTC_DIAGso routine builds are silent. Re-enable viamake tb_ee_core_bios_long_intc_diag`.
  • sim/Makefile — new tb_ee_core_bios_long_intc_diag target.

Where the next attempt starts (Ch261+)

Do not open Ch261 as another ee_bootstrap_mmio_stub hardcode. The probe-arc has demonstrated empirically that no single MMIO ready bit is the gate. The Ch261+ arc opens IOP-side modeling:

  • Phase 1 (Ch261 candidate): a tiny synthetic IOP/SIF responder in the TB that produces ONE meaningful kernel-visible side effect per Ch215 pass. The simplest plausible "real side effect" is a monotonic counter at a fixed kernel-data address (e.g., 0x80030000 — the kdata region BIOS scans every pass per the Ch218 v5 capture). If BIOS's longjmp callee polls that counter and it advances, the treadmill should break. If it doesn't, we've isolated which side-effect shape BIOS actually needs.
  • Phase 2 (later): flesh out the IOP-side stubs (already exist in rtl/iop/, none currently in production) into a responder that can take SIF mailbox commands and emit INTC pulses. This is the multi-chapter "real IOP" arc.

Three structural rules captured from the arc, to apply during Ch261+ (recorded as memory entries):


Purpose: before re-opening the BIOS treadmill, lock down what the EE / IOP / SIF / INTC / DMAC stack actually models today versus what the real BIOS expects, so the next chapter targets a specific dependency rather than chasing the BIOS opcode-of-the-week.


TL;DR

The real BIOS, run under tb_ee_core_bios_smoke with +BIOS=, exhibits two distinct failure modes that both blocked the Ch215-Ch218 arc:

  1. The Ch215 longjmp-return treadmill. After the Ch215 jmp_buf restore FSM rehydrates 12 GPRs from 0xA000B1E0, BIOS resumes at the restored $ra and loops 5 times through 0xBFC52340..0xBFC52360. The Ch217 verdict captures the smoking gun: across passes, $a0, $a1, and the JAL callee's $v0 are bit-identical. The kernel is asking the same question and getting the same answer every cycle. "BIOS has no escape signal from this callee" — external state that should flip between passes is not flipping because our stack does not model it.

  2. The DEADBEEF wedge in EE-RAM code. Independent of the longjmp loop, BIOS code executing from EE RAM at pc=0x000014C4 issues an LW with a base pointer derived from an earlier UNMAPPED read. The first UNMAPPED read's return value (the EE map's sentinel for unmapped regions) ends up in $6, the wedge fires lw $2, 0($6) on a poisoned base, that read is also UNMAPPED, and the resulting value keeps the loop alive forever. The TB has a lineage_poison_addr / retire_ring diagnostic that captures the first-unmapped read's PC + EA on every run.

Both failures share a root cause: the EE memory map has decode holes in regions BIOS reaches. The treadmill is one symptom; the DEADBEEF wedge is another. Ch257 picks the most likely missing region and lands a minimal model.


Layer inventory — what exists today

SIF (Sub-system Interface) — rtl/sif/

All 8 SIF modules are functional in simulation, none are instantiated in the production hierarchy (top_psmct32_raster_demo, de25_nano_psmct32_raster_demo_top). They live in TBs only.

Module Models Faked / TODO
sif_mailbox_stub 4-reg MSCOM / SMCOM / MSFLG / SMFLG @ EE 0x1000F200 / IOP 0x1D000000 No directional / W1C / set-clear semantics; no IRQ; plain RW
sif_mailbox_peer_stub TB-side IOP responder: command-echo FSM watching MSFLG TB only; no real IOP execution
sif_dma_stub Qword receive endpoint (128-bit ready/valid) No consume path; buffer fills and stays full
sif_dma_ack_peer_stub EE→IOP combined ctrl+data terminator One-shot S_DONE; no re-arm
sif_dma_iop_ram_bridge_stub 128→32 width adapter, qword → 4×32-bit writes DEST_BASE_ADDR hardcoded; no ack upstream
sif_dma_ee_ram_bridge_stub 32→128 width adapter, accumulates 4 beats DEST_BASE_ADDR hardcoded; Ch239 rewind for single-slot pads
sif_dma_ee_ack_peer_stub IOP→EE combined ctrl+data terminator One-shot
boot_install_agent_stub Synthetic exception-handler streamer → EE RAM NOT BIOS code; canned MFC0 / ADDIU / JR / RFE payload only

Critical gap: the EE memory map has no decode region for 0x1000F200-0x1000F2FF, so sceSifInit()'s mailbox accesses go to UNMAPPED. Even if the stubs were instantiated, the EE core could not reach them. The IOP-side map does have the SIF decode (0x1D000000 block), but the IOP CPU is not running any real firmware.

IOP — rtl/iop/

Module Models Faked / TODO
iop_core_stub Minimal R3000 (11 opcodes), COP0 Status/Cause/EPC triple-stack, async exception entry, STRICT_UNSUPPORTED trap+latch, reset vector 0xBFC00000 (BIOS) No TLB, cache, HI/LO, R-type ALU, shifts, mul, div, BD bit, kernel/user enforcement
iop_memory_map_stub IOP RAM 0-2 MiB, BIOS ROM 0x1FC00000+, IOP DMAC ch9 0x1F801520, IOP INTC 0x1F801070, SIF 0x1D000000, retroDE pad I/O 0x1F808500 All other IOP I/O unmapped (SPU2, timers, other DMAC channels, real SIO2); UNMAPPED reads return 0xDEADBEEF
iop_ram_stub 2 MiB SRAM (default 16 KiB in TBs) None
iop_fetch_stub Sequential fetcher (trace-only; superseded by iop_core_stub)
iop_exec_stub 5-opcode micro-op script engine (HALT/WRITE/READ/WAIT_IRQ/BNE; superseded by iop_core_stub)
iop_dmac_reg_stub IOP DMAC ch9 (SIF0 IOP→EE): MADR/BCR/CHCR/DONE_COUNT, 32-bit beats from IOP RAM via memory master Only ch9 wired; no error reporting
sio2_input_stub Sony pad word @ retroDE 0x1F808500; 2-FF CDC from bridge domain No real SIO2 FIFO at 0x1F808200; no DMAC ch11

Critical gap: the IOP has no real BIOS image and never executes beyond synthetic test programs. Real BIOS boot expects the IOP to fetch from 0xBFC00000 (shared BIOS ROM), execute its bootstrap, parse IOPBTCONF, load IRX modules, and signal readiness back to the EE via SIF. None of that is happening — the IOP-side mailbox writes that would unstick the EE never come.

INTC — rtl/intc/intc_stub.sv

Generic 16-source controller, reused on both EE (0x1000F000) and IOP (0x1F801070) sides. W1C status, plain-write mask. Aggregate cpu_irq = |(STAT & MASK).

Faked: write-to-toggle (XOR) mask semantics not implemented (real PS2 INTC uses XOR for atomic bit-flip — BIOS code that XORs a mask bit will see unexpected behavior).

Wired sources: only DMAC completion pulses (dmac_reg_stub.irq_completion_o, iop_dmac_reg_stub.irq_completion_o). Unwired: VBLANK_START, VBLANK_END, GS_FINISH, TIMER0..3, SBUS, VIF/VU, SIF0/SIF1 done, real SIO2, CDVD, USB, FW, IPU. The PCRTC's frame_seen toggle exists in the demo wrapper but is not routed to INTC.

DMAC — rtl/dmac/dmac_reg_stub.sv

EE-side per-channel register shell + state machine. MADR / QWC / CHCR / TADR / DONE_COUNT at offsets 0/0x10/0x20/0x30/0x40 within a channel bank. Real 128-bit qword transfers from ee_ram_stub via memory master.

Faked: chain mode (TADR recorded but never consulted), all errors report code 0 (OK), no memory-contention throttling. Only ch2 (GIF) and ch5 (SIF0) are instantiated in the production demo; channels 0, 1, 3, 4, 6-12 are register-only or absent.

EE-side MMIO stubs — rtl/ee/ee_*_mmio_stub.sv

Stub Range Behavior
ee_biu_mmio_stub 0x1FFE0000-0x1FFE0FFF (4 KiB) Latched RW. Real BIOS writes 0x1FFE0130 for cache/BIU config (Ch9).
ee_bootstrap_mmio_stub 0x1F800000-0x1F80FFFF (64 KiB) Latched RW + one special-case: offset 0x1814 returns hardcoded 0xFFFFFFFF (Ch202 RDRAM-init ready bit).

ee_bootstrap_mmio_stub's Ch202 special-case is the canonical pattern for "BIOS polls a hardware register expecting a ready bit; real RDRAM init never happens; hardcode the return."


The Ch215 longjmp-return treadmill — what the TB knows

tb_ee_core_bios_smoke runs the real BIOS dump (4 MiB at /home/ubuntu/Downloads/bios.hex, passed via +BIOS= plusarg).

What BIOS gets through

  1. EE reset @ 0xBFC00000, ROM bootstrap.
  2. BIU/cache config writes to 0x1FFE0130 (BIU stub absorbs them).
  3. 0x1F80xxxx MCH/SBUS reads (bootstrap MMIO stub absorbs, special- case 0x1814 returns 0xFFFFFFFF).
  4. Memory copies from BIOS ROM into EE RAM.
  5. Kernel exception-handler install (handled by either boot_install_agent_stub or direct memory writes).
  6. First SYSCALL #8 (_ReturnFromException with $a0=2) — triggers the Ch215 jmp_buf restore FSM. 12 GPRs ($ra, $sp, $fp, $s0..$s7, $gp) are loaded from 0xA000B1E0, $v0 set to 1 (longjmp-return marker), PC restored from $ra.

Where BIOS stalls

After the Ch215 restore, BIOS resumes at the restored $ra and loops through 0xBFC52340..0xBFC52360. The TB's Ch217 task captures every pass through the JAL at 0xBFC52358 (the longjmp-return-handler call). Across 5 observed passes:

  • $a0 and $a1 to the callee are bit-identical.
  • The callee's returned $v0 is bit-identical.

Ch217 verdict (from the TB itself):

longjmp_return_repeats_due_to_static_state — BIOS has no escape signal from this callee. The callee must be modifying something we are missing, OR the BIOS expects some external state (MMIO ready, timer, or kernel global) to flip between passes — but our model is not providing it.

The JAL target is computed dynamically by the TB ({4'hB, instr[25:0], 2'b00}) and the callee's first 16 instructions are dumped to the log via Ch217's CALLED_FUNCTION dump. The specific addresses the callee READS inside its body have not been captured by the existing TB diagnostic.

Parallel to the longjmp loop, BIOS code running in EE RAM at pc=0x000014C4 issues an LW with base = $6 = 0xDEADBEEF (or a derivative). The effective address 0x3084_FFFF lands in an unmapped region; the EE map returns the unmapped-sentinel; the value re-poisons $2; the loop self-perpetuates millions of times.

The TB has full diagnostic for this: lineage_poison_addr, lineage_poison_data, lineage_pc, lineage_instr, plus a 32-deep retire ring (retire_ring_pc[*], retire_ring_r2[*], retire_ring_r6[*]) that captures the 32 instructions preceding the first UNMAPPED read. The lineage capture identifies where $6's poison originated, but the corresponding fix has not landed — presumably because the ORIGINATING unmapped read's address class has not yet been claimed by any stub.


What's documented vs. what the kernel actually needs

Existing contracts under docs/contracts/ are all Draft:

  • sif.md — mailbox/flag exchange + SIF DMA shape; no detailed boot sequence.
  • iop.md — IOP as separate peer subsystem; notes IOPBOOT / module- load NOT modeled.
  • memory.md — emphasizes BIOS ROM mapping; explicitly does not own BIOS boot sequencing.
  • intc.md, dmac.md, ee.md, gif_gs.md, peripherals.md, platform.md, vif_vu.md, sio2_pad.md, spu2.md — system contracts, no BIOS/kernel detail.

The wave2*_plan.md documents are all DMA/GIF focused and explicitly defer SIF/IOP/BIOS. No existing doc covers the kernel's setjmp / longjmp / _ReturnFromException path. Ch214-Ch217 reverse- engineered the layout (12-GPR frame at 0xA000B1E0, setjmp at 0xBFC4DB50, post-setjmp checkpoint at 0xBFC52358) but only embedded the findings in the TB itself.


Where the missing signal most likely lives

Cross-referencing the Ch217 verdict's three candidate categories ("MMIO ready, timer, or kernel global") against the layer inventory:

Kernel global (RAM at 0xA000xxxx). Unlikely. The callee at 0xBFC52358 is in BIOS ROM and reads $a0/$a1 from the restored GPRs. If the callee polls a kernel global, that global would be in EE RAM. EE RAM is bidirectionally accessible; if the callee both READS and WRITES the global, the value would change pass-to-pass. The Ch217 verdict says it does not — so either the callee writes nothing, or the global lives in an unmapped region.

Timer (0x10000000-0x10001FFF, T0/T1/T2/T3 COUNT/MODE/COMP/HOLD). Plausible. PS2 kernel uses one of T0-T3 for the scheduler tick. The counter is read at fixed addresses; the count value advances with hardware clocks regardless of CPU activity. The EE memory map has NO decode for 0x10000000-0x10001FFF — all four timers are unmapped. A read returns the unmapped sentinel, the kernel reads the same sentinel every pass, sees no time elapsed, loops.

MMIO ready bit (EE INTC, SIF mailbox, or bootstrap MMIO). Also plausible.

  • EE INTC 0x1000F000 is mapped (status/mask), but no sources fire periodically. If the callee polls INTC_STAT[VBLANK_START] waiting for a frame tick, the bit never sets.
  • SIF mailbox 0x1000F200 is not mapped at all on the EE side. A read returns the unmapped sentinel; if the callee polls SMFLG[IOP_READY] waiting for IOP boot completion, that read is pure UNMAPPED — and would also trigger the DEADBEEF wedge if the sentinel is 0xDEADBEEF.
  • Bootstrap MMIO 0x1F80xxxx is mapped (latched + Ch202 special- case at 0x1814). If the callee polls a different offset expecting a ready bit, hardcoded special-case is the proven fix pattern.

Ch257 — scoped callee-body memory-read observer (landed)

Implementation: sim/tb/integration/tb_ee_core_bios_smoke.sv gains a Ch218 observer + verdict-emitter:

  • ch218_jal_target — dynamically decoded from peek_instr(0xBFC52358) (the JAL whose callee Ch217 already characterized as static-state). Pattern matches Ch217's own decode.
  • ch218_pc_in_body — combinational gate, fires when the live core_pc is in [jal_target, jal_target + 0x80).
  • Capture array of depth 64. Each entry records {pass_idx (from ch217_count), pc, instr, ea, data, rt} per qualifying EE memory READ event (ee_map_ev_valid && EV_READ && SUBSYS_MEM && ch218_pc_in_body). Sampled on every clock so reads within a single pass through the callee are all captured.
  • Print task ch218_print_callee_reads dumps every captured read with its instruction mnemonic, then sweeps the array for an EA that appears across multiple distinct passes and returns identical data. That EA is the static-poll candidate.
  • Verdict classifier with six labels, each one naming the Ch258 target region directly:
Verdict label EA range Ch258 action
timer_poll_static 0x10000000 0x10001FFF Land ee_timer_stub (PRIMARY)
sif_mailbox_static 0x1000F200 0x1000F2FF Route sif_mailbox_stub ee-side into EE map decode
ee_intc_static 0x1000F000 0x1000F1FF Wire VBLANK / TIMER / SIF source(s) into intc_stub.irq_src
bootstrap_mmio_static 0x1F800000 0x1F80FFFF Add Ch202-style hardcoded ready at the polled offset
ee_ram_static 0x00000000 0x01FFFFFF Preload kernel global via boot_install_agent_stub
named_region_static (any other range) Report verbatim; pick the next Ch258 hypothesis
no_repeated_read_across_passes Not enough passes captured, or callee uses scratch only
no_callee_reads Synthetic-CI mode (callee never reached); not applicable
  • Wiring: the print task is called from both the long-run halt path (after ch217_print_longjmp_path) and the timeout path (the one real-BIOS mode exits through). Synthetic CI mode skips both call sites because they sit inside ch213_sc8_seen-gated blocks — no regression noise, no behavior change to existing TBs.

No RTL change. No production-RTL change. No new TB. Pure TB-side diagnostic add to an existing TB. The full sim regression stays at 155 PASS / 0 FAIL with the observer dormant in every TB except the one real-BIOS run that the operator triggers manually.

How to use Ch218 — operator command

cd sim
make tb_ee_core_bios_smoke BIOS=/home/ubuntu/Downloads/bios.hex

This runs tb_ee_core_bios_smoke with +BIOS=... so the real 4 MiB BIOS dump is loaded. The TB will eventually hit the Ch215 longjmp treadmill, loop the Ch217 callee multiple times, and timeout. The timeout-path prints:

[ch217] LONGJMP_PATH_DECODE 0xBFC52350..0xBFC52390:
[ch217]   ...
[ch217] verdict=longjmp_return_repeats_due_to_static_state ...
[ch218] CALLEE_BODY_READS jal_target=0x?????.??..0x?????.?? captured=N (cap=64)
[ch218]   [0] pass=0 pc=0x... instr=0x... ea=0x... data=0x... rt=$.  <mnemonic>
[ch218]   [1] pass=0 pc=0x... ...
[ch218]   ...
[ch218] verdict=<label> (...)

Report the [ch218] verdict= line. Ch258 picks the table row.

Ch258 proposal — one narrow next state to model

Driven by the Ch218 verdict; no decision required before observer data lands.

Primary hypothesis: EE Timer block 0x10000000-0x10001FFF. PS2 BIOS kernels rely heavily on T0-T3 for scheduler ticks; the entire region is completely unmapped on the EE side (no decode entry in ee_memory_map_stub). Both the longjmp treadmill AND the DEADBEEF wedge are explained by a single root cause if the kernel polls a timer count and the unmapped read returns the sentinel that becomes the DEADBEEF poison.

If Ch218 verdict = timer_poll_static: land rtl/ee/ee_timer_stub.sv with 4 channels × {T_COUNT, T_MODE, T_COMP, T_HOLD} at base addresses 0x10000000, 0x10000800, 0x10001000, 0x10001800. T_COUNT is RO and ticks at parameterized rate (default: design_clk / 16 ≈ 3 MHz at 50 MHz, matching PS2 BUSCLK / 16). Writes latch T_MODE/T_COMP/T_HOLD. No IRQ wired yet ( deferred to Ch259 if needed). Wire into ee_memory_map_stub between the BIU and bootstrap MMIO decode regions.

If Ch218 verdict is anything else: follow the table in the Ch257 section above. The verdict label names the Ch258 action directly.

Why not chase SIF/IOP first: the SIF gap is real and known but it's a multi-chapter project (EE decode → mailbox in production hierarchy → IOP BIOS → IOP CPU exercises → mailbox writes land). The timer gap is a single self-contained stub with one parameter (tick rate) and four registers per channel. If observation shows the callee is a timer poll, this unsticks the treadmill in one chapter. If observation shows otherwise, the named region is the Ch258 target.

Acceptance for Ch258 (whichever path):

  1. The Ch218 verdict line drives the chapter choice — no judgment call without data.
  2. The chosen stub lands cleanly + the full regression stays 155 PASS / 0 FAIL.
  3. Running tb_ee_core_bios_smoke +BIOS=... produces observable forward motion: either Ch217's caller-passes count diverges (BIOS exited the loop), or a new UNMAPPED region surfaces (BIOS made progress but hit the next gap).

Open questions deferred to Ch258+

  • IOP BIOS execution: does the IOP need a real BIOS dump, or is a synthetic IOP bootloader plus IOPBTCONF parsing enough?
  • Real PS2 INTC XOR mask semantics: BIOS code that XORs a mask bit will misbehave on plain-write intc_stub. Lower priority — wait until BIOS demonstrably hits it.
  • VBLANK source wiring (PCRTC frame_seen toggle → intc_stub.irq_src): near-term if the treadmill turns out to be VBLANK-driven, but defer until the observer confirms.
  • SIF mailbox in production hierarchy: instantiate sif_mailbox_stub alongside intc_stub at the EE-side 0x1000F200 decode region; ALSO wire IOP-side EE-write port through to the IOP's memory map for bidirectional handshake.
  • Kernel global modeling: if the callee turns out to poll a RAM address that some IOP-side write should mutate, that's the trigger to land the IOP in production hierarchy (also a multi- chapter project).

Files referenced

RTL:

  • rtl/sif/sif_mailbox_stub.sv (all 8 SIF stubs in rtl/sif/)
  • rtl/iop/iop_core_stub.sv, iop_memory_map_stub.sv, iop_dmac_reg_stub.sv, sio2_input_stub.sv
  • rtl/intc/intc_stub.sv
  • rtl/dmac/dmac_reg_stub.sv
  • rtl/ee/ee_biu_mmio_stub.sv, ee_bootstrap_mmio_stub.sv, ee_memory_map_stub.sv, ee_core_stub.sv (Ch215 jmp_buf FSM, STRICT_UNSUPPORTED latch)

TBs:

  • sim/tb/integration/tb_ee_core_bios_smoke.sv (Ch214/216/217 diagnostics, lineage capture, DEADBEEF wedge characterization)
  • sim/tb/integration/tb_iop_core_bios_smoke.sv (IOP-side mirror, STRICT_UNSUPPORTED)

Real BIOS dump:

  • /home/ubuntu/Downloads/bios.hex (9 MiB ASCII, ~4 MiB binary, $readmemh-ready)