- C++ 80.8%
- Shell 9.8%
- C 7.7%
- Python 1.2%
- CMake 0.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Half of what makes Linux's radeon DRM reach hardware direct rendering on the emulated
XVR-100. The other half is softsparc's, and the two are a PAIR -- either one alone
leaves the ring test failing with the identical symptom.
THE BUG. CP_RB_CNTL bits [17:16] are a byte-swap field. radeon_reg.h defines exactly one
value for it, RADEON_BUF_SWAP_32BIT == (2 << 16) (radeon_reg.h:3302), and r100_cp_init
(r100.c:1198-1204) is the ONLY place in the entire radeon driver that ever sets it for
this chip family:
tmp = (REG_SET(RADEON_RB_BUFSZ, rb_bufsz) | ...);
#ifdef __BIG_ENDIAN
tmp |= RADEON_BUF_SWAP_32BIT;
#endif
WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_NO_UPDATE);
A grep of drivers/gpu/drm/radeon for __BIG_ENDIAN returns exactly one hit in r100.c --
that one. Every other hit is r300+, ATOM or fbdev. So this bit, and nothing else, is the
whole big-endian story for an R100.
WHY IT MATTERS. A driver builds the ring with plain CPU stores: radeon_ring_write() is
`ring->ring[ring->wptr++] = v` into an ordinary kmap of the GTT buffer object, and an IB
is filled the same way -- userspace's own native stores, copied in verbatim by the CS
ioctl, with radeon_get_ib_value() reading them back as a plain `ib[idx]` and no
byte-order helper anywhere. On a big-endian host every one of those dwords lands in
memory MSB-first, and the CP is told to byte-reverse each as it fetches it. Unmodelled,
a sparc64 guest's very first ring packet decodes as garbage: PACKET0(0x15e4, 0) ==
0x00000579 is fetched as 0x79050000, a PACKET1, and the CP halts on ring dword 0. That
is precisely the guest symptom -- r100_ring_test() failing with the scratch register
still holding its 0xCAFEDEAD sentinel.
read_cmd_dword() is now the single point every CP fetch of DRIVER-AUTHORED data goes
through: ring, IB, vertex and index.
DELIBERATELY NOT APPLIED to the GART page table, which keeps read_le32():
r100_pci_gart_set_page() writes those entries with an explicit cpu_to_le32()
(r100.c:709-714), so they are little-endian on the wire on every host regardless of this
bit. Getting that distinction wrong would have broken the GART walk instead.
Only field value 2 is decoded. Values 1 and 3 exist but the driver never emits them and
no fetched source states what they mean, so they are treated as no-swap and recorded
under "Not implemented" rather than guessed at.
TESTS, and the counter-arm is the point. New scenario 1b reproduces the guest's symptom
as a unit test -- against unmodified cp.cpp it fails with the scratch register reading
0xcafedead, the CP halted, and RPTR stuck at 1. Scenario 1c is the arm that keeps the
fix honest: swap bit CLEAR plus a big-endian ring must NOT swap, must halt, and must
record header 0x79050000. It fails if the swap is ever made unconditional.
Verified: rv100 ctest 15/15, and 15/15 again cross-compiled BIG-ENDIAN (s390x + qemu-user
via rig/run-ctest-bigendian.sh, with readelf -h confirming "2's complement, big endian" /
"IBM S/390") -- which is the right way to test a byte-order fix.
UNCERTAIN, recorded rather than smoothed over: the swap is applied to vertex and index
fetches too, which is inferred from this being the driver's only big-endian
accommodation for the chip, not measured -- no big-endian 3D draw has been run. Pixel
and surface data (framebuffer, textures, depth) are untouched here; that is
RADEON_SURFACE_CNTL's business and is unexercised big-endian.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHazRUnQUw1PpsqVjzcH7K
|
||
| docs | ||
| frontend/qemu | ||
| include/rv100 | ||
| rig | ||
| roms | ||
| src | ||
| tests | ||
| tools | ||
| .gitignore | ||
| CMakeLists.txt | ||
| HANDOFF_2026-09-05.md | ||
| README.md | ||
| ROADMAP.md | ||
rv100 — a device model of the ATI RV100 (Radeon 7000 / Sun XVR-100)
An architecturally-exact, host-independent emulation of the ATI RV100 graphics chip: PCI config space, MMIO register file, memory controller, CRTC/scanout, the CP command processor, the 2D engine and the fixed-function 3D pipeline.
The chip shipped under several names. They are the same silicon, PCI ID
1002:5159 (RV100 "QY"):
- ATI Radeon 7000 / Radeon VE — the retail x86 card.
- Sun XVR-100 (part 375-3290) — the SPARC workstation card, whose only
difference is the expansion ROM: an IEEE-1275 FCode image instead of an x86
BIOS. Confirmed by dumping the ROM off a real Sun Ultra 25: one image,
PCIR code type 1,
SUNW,XVR-100.
Why this chip
RV100 is the last generation before programmable shading. It has no
transform-and-lighting unit at all (the T&L block the full R100 carried is
fused off), so the driver submits vertices already in screen space, and the
fragment stage is a configurable texture-combiner state machine rather than a
shader core. That makes it small enough to model exactly while still sharing
the CP PACKET0/PACKET3 command model and much of the register layout with
every later Radeon up to R5xx.
Not tied to one host
The core is a plain library with no knowledge of any emulator. It reaches the
outside world only through HostOps callbacks (system-memory read/write for
DMA, interrupt raise, scanout notify). Front-ends planned:
- softsparc — the Sun Ultra 25 emulator, the original motivation.
- QEMU — a PCI device model, which is also how we drive a real Linux
guest with the real
radeonkernel driver and Mesa Amber'sr100. - standalone — command-stream replay for deterministic regression tests.
Build
cmake -B build -S .
cmake --build build -j
ctest --test-dir build --output-on-failure