No description
  • C++ 96.7%
  • Shell 1.2%
  • Python 0.7%
  • C 0.6%
  • CMake 0.4%
  • Other 0.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
zclaude a8ea61e030 Merge WI-CPRING: wire the XVR-100's DMA, and hardware OpenGL comes up
HARDWARE-ACCELERATED OPENGL NOW RUNS ON THE EMULATED SUN XVR-100:

    OpenGL renderer string: Mesa DRI R100 (RV100 5159) SPARC DRI2
    OpenGL version string:  1.3 Mesa 21.3.9 Amber
    direct rendering: Yes      Accelerated: yes

mesa-amber's classic radeon driver, on the emulated GPU, on an emulated UltraSPARC IIIi.
The ring test and IB test pass, r100_cp_init returns 0, accel_working is true, and an
UNMODIFIED xf86-video-ati 22.0.0 comes up with EXA + DRI2 + direct rendering. Xorg loads
the same driver server-side: "AIGLX: Loaded and initialized radeon".

PAIRED with rv100 5437f10. Either half alone leaves the ring test failing with the
identical symptom; merging one without the other is not useful.

NEITHER BUG WAS "THE RING", which is why checking first was worth it. rv100 already had
a complete ring walk, GART walk, PACKET0/1/2/3 decode and IB submission, and its own
handoff records the test passing under QEMU. What was missing was on either side of it.

THIS HALF: softsparc never wired the card's DMA. dev/xvr100.cpp handed rv100 an all-null
HostOps, with a comment saying as much --

    rv100::HostOps host{};  // all null: the FCode path does registers and DDC, no
                            // bus mastering. ... DMA gets wired when Linux radeon needs it.

-- and that day arrived. With sysmem_read null, rv100's dev_cp_sysmem_read zero-fills,
so the CP walked the ring, decoded zero dwords and stopped. The addresses are not
physical either: they are DVMA out of the Fire leaf's IOMMU aperture
(dma_alloc_coherent for the GART table, dma_map_page for each page it points at). The
driver names one itself -- "PCI GART of 512M enabled (table at 0x00000000C4DBC000)",
which is not RAM on a 2 GB machine.

sysmem_read/sysmem_write now go through a new Xvr100State::bus and translate every
access through the leaf-A Fire IOMMU, using the same find_fire_state() walk, the same
leaf and the same raw-DVMA fallback that dev/mpt.cpp and dev/rtl8139.cpp already use,
split at 8 KiB IOMMU page boundaries. No new mechanism -- the third user of an existing
one.

THE OTHER HALF (rv100 5437f10) is the big-endian one: CP_RB_CNTL[17:16] is a byte-swap
field, and r100_cp_init sets RADEON_BUF_SWAP_32BIT under `#ifdef __BIG_ENDIAN` -- the
only such hit in the entire radeon driver. Unmodelled, a sparc64 guest's first ring
packet decodes as garbage.

irq_set IS LEFT NULL, deliberately and measured, not overlooked: r100 runs with
writeback disabled (radeon_device.c:503-505; the guest prints "WB disabled"), so fences
are read from a scratch register over MMIO and radeon_fence_check_lockup()'s delayed
work polls them. Ring test, IB test and a full X session all pass with no interrupt. Not
established for anything that genuinely waits on vblank.

TESTS THAT PROVE THE SEAM, one per side. tests/test_xvr100.cpp drives r100_ring_test()'s
sequence through softsparc's OWN BAR callbacks and BusState -- not rv100's vector-backed
harness -- with a big-endian ring, the swap bit set, and a little-endian GART entry in
the same run. With only the HostOps wiring removed it fails on both the register value
AND on dma_reads not advancing; dma_reads is the discriminator, because the register
value alone would not prove DMA happened.

EVIDENCE. A sorted diff of every [drm] line, before vs after, is exactly: +ring test
succeeded, +ib test succeeded, -ring test failed, -cp isn't working, -cp finalized,
-Unable to find PCI I/O BAR (that last already fixed by WI-DRMBIND). Zero [W cp]/[E cp]
lines in the whole run. Xorg goes from "Acceleration disabled" / "Direct rendering
disabled" / "Screen 0 is not DRI2 capable" to "Acceleration enabled" / "Direct rendering
enabled" / "[DRI2] Setup complete" / "Render acceleration enabled for R100 type cards".

Verified independently on the MERGED tree: gate 39b8b81c57e9bee9e0391ed315b0f73f on
default and every stick-divisor form; ctest 61/61 with the slow tests actually running
(233/240/268/303/602 s, not 0.00 s); rv100 ctest 15/15 after its own merge, and 15/15
again cross-compiled BIG-ENDIAN (s390x + qemu-user), which is the right way to test a
byte-order fix.

HOW FAR SHORT, stated plainly. glxgears ABORTS THE X SERVER, reproducibly, ~300 s after
DRI2 initialises:

    Xorg: ../../../../include/privates.h:122: dixGetPrivateAddr:
          Assertion `key->initialized' failed.

glxinfo -- context creation and queries, no window -- works in the same session, so the
failure sits between "a GL context exists" and "the first frame is drawn". The kernel
reports nothing: no CS rejection, no GPU lockup, no reset, and rv100 logs zero halts.
TWO HYPOTHESES WERE TESTED AND ELIMINATED rather than argued: no vblank interrupt
(disabling EnablePageFlip and SwapbuffersWait changes nothing) and AIGLX lacking a DRI2
provider (fixing that outright leaves the abort unchanged). It is NOT diagnosed, and no
claim is made either way about whether the device model is at fault. The stock-Mesa
control arm does not settle it either -- X survives glxgears there only because that
stack never gets a GL context on this card at all ("radeon: Invalid PCI ID.").

One userspace addition was needed for amber's libGL: libxcb-dri2.so.0, which Debian 13
does not ship.

No screenshot of hardware-rendered 3D exists: --gpu-screenshot only writes on a clean
exit and these runs end in an interactive shell.

TWO TRAPS WORTH CARRYING. disks/drm-y.img has a DIRTY EXT4 JOURNAL: a debugfs edit of
/drmtest verifies correctly on the host (stat, and a dump+cmp round trip both agree) and
is then SILENTLY TRUNCATED to 3122 bytes by the guest's own journal replay -- 3122 being
the length of WI-DRMBIND's drmtest2.sh, which owns that inode in the journal. Two guest
runs were lost to it; e2fsck cannot repair it. And `rc=$?` after a pipeline reports
head's status, not the command's, which made a batch of "glxgears rc=0" lines meaningless.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHazRUnQUw1PpsqVjzcH7K
2026-09-07 12:42:03 -04:00
docs WI-68: land MMU demap fix (JPS1 F.10.11) + model ebus PCF8584 i2c@3,80; honest boot to the 'SD'-segment frontier 2026-08-23 23:05:40 -04:00
fcode WI-NET: host networking for the emulated NIC, and boot net from OBP 2026-09-05 15:34:41 -04:00
include/softsparc WI-CPRING: the XVR-100 is a bus master, and nothing had wired its DMA 2026-09-07 01:26:51 -04:00
investigation WI-CPRING: the investigation notes and the guest evidence 2026-09-07 04:15:57 -04:00
scripts WI-11: diff-test battery harness (format, generator, native runner, roundtrip) 2026-08-21 22:33:31 -04:00
src WI-CPRING: the XVR-100 is a bus master, and nothing had wired its DMA 2026-09-07 01:26:51 -04:00
tests WI-CPRING: the XVR-100 is a bus master, and nothing had wired its DMA 2026-09-07 01:26:51 -04:00
third_party/softfloat WI-14: vendor Berkeley SoftFloat 3e + bit-exact FPU kernel layer 2026-08-21 23:10:38 -04:00
tools WI-JITDEV: give the JIT WI-CHAIN's device-access proof, and it stops losing to the chained interpreter 2026-09-06 15:43:49 -04:00
.gitignore Untrack a stray __pycache__ .pyc and gitignore bytecode caches 2026-08-30 10:20:39 -04:00
AGENTS.md WI-01: project scaffold + common module (bytes, log, check, inventory) 2026-08-21 21:40:40 -04:00
CMakeLists.txt WI-JIT: a native x86-64 code generator behind --jit, exact and opt-in 2026-09-05 17:56:41 -04:00
PERFORMANCE.md WI-JITDEV: give the JIT WI-CHAIN's device-access proof, and it stops losing to the chained interpreter 2026-09-06 15:43:49 -04:00
README.md WI-PBMFIX: add a Linux boot to the gate set, since nothing else reads OBP's tree 2026-09-05 21:20:16 -04:00
ROADMAP.md WI-38: clear Fire host-bridge-init regs + cache-array init ASIs; boot reaches the DCUCR MMU-enable gate 2026-08-22 09:48:35 -04:00

softsparc

An architecturally-exact SPARC64 full-system emulator, written in C++17.

The first target is a Sun Ultra 25 workstation (UltraSPARC IIIi), booting the machine's real 2 MiB OpenBoot PROM (OBP) firmware dump — 4.25.9 — from cold reset through the ok prompt and beyond. The bus scope for this target is PCI/PCIe only (no ISA, no SBus). A T4-1 / sun4v target is a deliberately deferred stretch goal: sun4v has a different MMU/trap architecture and blocks direct ROM access on real hardware, so it is out of scope until the UltraSPARC IIIi path is solid.

"Architecturally exact" means: correctness is measured against the SPARC V9 architecture manual, the JPS1 commonality specification, and the UltraSPARC-IIIi processor user's manual — not against "good enough to run some code". See include/softsparc/common/inventory.h for the running ledger of which instructions, ASIs, and traps are implemented, and against which manual section each was verified.

Building

cmake -B build -S .
cmake --build build -j

Requires a C++17 compiler and CMake >= 3.16. No third-party dependencies are required to build; a later work item vendors Berkeley SoftFloat 3e under third_party/softfloat for IEEE-754 semantics matching real UltraSPARC IIIi hardware (see the guarded stanza at the bottom of CMakeLists.txt).

For stricter warnings-as-errors builds (used in CI):

cmake -B build -S . -DSOFTSPARC_WERROR=ON
cmake --build build -j

Testing

ctest --test-dir build --output-on-failure

That is the fast tier: every tests/test_*.cpp is registered automatically and the whole set runs in a few seconds. Some cases inside it are gated on environment variables and skip silently without them, printing a SKIP line that names what is missing — a 0.00 s pass on one of those proves nothing, so read the skip lines.

The gate set

Three tiers, in increasing cost. All three should be green before a branch is merged.

1. Fast unit tests — the ctest line above. No environment needed.

2. Slow real-ROM and real-OS gates — need the real Ultra 25 OBP dump, and SOFTSPARC_SLOW_TESTS=1 to acknowledge the minutes they cost:

env SOFTSPARC_SLOW_TESTS=1 \
    SOFTSPARC_U25_ROM=/path/to/ultra25-obp.rom \
    SOFTSPARC_LINUX_BOOT_MEDIA=/path/to/dbn10-instB.iso \
    ctest --test-dir build --output-on-failure

SOFTSPARC_U25_ROM alone unlocks the ROM decode/FCode sweeps; adding SOFTSPARC_SLOW_TESTS=1 unlocks the full boot-to-ok gates (test_real_rom_console, test_real_rom_pci_probe, test_pci_config_boot, test_machine's clean-ok case). SOFTSPARC_LINUX_BOOT_MEDIA additionally unlocks test_linux_boot_pbm, which boots a real Debian 10 sparc64 kernel until it has enumerated both Fire PCIe leaves — the only gate in the tree that exercises what a kernel reads out of OBP's device tree, and the one that would have caught WI-BRIDGED3's missing IO PBM range regression. See that file's header for exactly which strings it requires and forbids, and why its step budget is tight.

3. The OBP equivalence gate — every execution lane must produce a byte-identical console transcript over a 200M-step OBP boot. --trace-ring 0 is required: without it the run takes ~18 minutes instead of ~30 seconds and hashes differently.

./build/softsparc --rom /path/to/ultra25-obp.rom \
  --ram-mb 2048 --trace-ring 0 --serial-stdout --steps 200000000 2>&1 | md5sum

Run it six times — plain, --dynarec, SOFTSPARC_NO_OPT=1, --dynarec with SOFTSPARC_NO_BUSFAST=1, --jit, and --jit with SOFTSPARC_NO_OPT=1 — and all six hashes must match. PERFORMANCE.md records the current expected value and the reasoning behind each arm. Always pass --ram-mb 2048: below that OBP still believes it has 2 GB, so the machine is misconfigured rather than smaller.

Running

./build/softsparc              # prints current status
./build/softsparc --inventory  # prints the instruction/ASI/trap accuracy ledger

Nothing is emulated yet — WI-01 is scaffold plus the common module only.

Where to look next

  • AGENTS.md — house style and working rules for anyone (human or agent) implementing a module.
  • docs/SOURCES.md — index of every reference manual under docs/, with provenance and integrity hashes.
  • ROADMAP.md — work item sequencing (added as work items land; not present in WI-01).