Skip to content

fayalalebrun/SpinalVoodoo

Repository files navigation

SpinalVoodoo

SpinalHDL implementation of the 3dfx Voodoo Graphics GPU.

Simulation Gallery

3dfx logo trace
Logo
Screamer 2 trace
Screamer 2
Quake trace
Quake
Valley of Ra trace
Valley of Ra

Implementation Status

FBI (Frame Buffer Interface)

  • Rasterization
    • Triangle setup (bounding-box scan + edge function testing)
    • Span generation (serpentine scan)
    • Scissor clipping (clipLeftRight, clipLowYHighY)
    • Y-origin transform (fbzMode bit 17, fbiInit3[31:22])
    • Stipple patterns
  • Gradient Interpolation
    • Color (R, G, B, A) - 12.12 fixed-point
    • Depth (Z) - 20.12 fixed-point
    • Texture coordinates (S, T, W) - 14.18 / 2.30 fixed-point
    • Parameter adjustment for sub-pixel vertices (fbzColorPath bit 26)
  • Color Combine Unit (CCU)
    • c_other source selection (iterated, texture, color1, LFB)
    • c_local source selection (iterated, color0)
    • cc_localselect_override (texture alpha bit 7 selects color0)
    • zero_other, sub_clocal
    • All mselect modes (ZERO, CLOCAL, AOTHER, ALOCAL, TEXTURE_ALPHA, TEXTURE_RGB)
    • reverse_blend (factor inversion)
    • Add modes (NONE, CLOCAL, ALOCAL)
    • Invert output
  • Alpha Combine Unit (ACU)
    • a_other source selection (iterated, texture, color1, LFB)
    • a_local source selection (iterated, color0, iterated_z)
    • alpha_zero_other, alpha_sub_clocal
    • All alpha mselect modes
    • alpha_reverse_blend, alpha_add, alpha_invert_output
  • Fog
    • W-based fog table lookup
    • Iterated fog (alpha/Z based)
    • Fog color blending
  • Alpha Test
    • Comparison functions (never, <, ==, <=, >, !=, >=, always)
    • Reference alpha
  • Depth Buffer
    • Z-buffer read/compare
    • Depth function selection
    • Z-buffer write
    • W-buffer mode
    • Depth bias
    • Depth source select (iterated Z or W)
  • Alpha Blending
    • Source blend factors (10 modes)
    • Destination blend factors (10 modes)
    • Framebuffer read for blending (fork-queue-join BMB pattern)
  • Chroma Key
    • Color key comparison (post color-combine, matching real hardware)
    • Chroma range
  • Dithering
    • 4x4 ordered dither (86Box ground-truth LUTs)
    • 2x2 ordered dither (86Box ground-truth LUTs)
  • Framebuffer Write
    • 16-bit RGB565 output
    • Draw buffer selection
    • Depth/alpha planes selection (fbzMode bit 18)
    • RGB write mask
    • Aux write mask
  • Linear Frame Buffer (LFB)
    • Direct CPU writes (bypass mode, all write formats)
    • Pixel format conversion (RGB565, RGB555, ARGB1555, XRGB8888, ARGB8888, Depth+color, Depth-only)
    • Dual-pixel (16-bit formats) and single-pixel (32-bit formats) modes
    • RGBA lane swizzle (ARGB, ABGR, RGBA, BGRA)
    • Word swap and byte swizzle
    • Dithering support
    • Pipeline routing option (pixelPipelineEnable=1)
    • LFB reads
  • Commands
    • triangleCMD / ftriangleCMD
    • fastfillCMD (screen clear via clip rectangle, color1/zaColor, with dithering)
    • nopCMD
    • swapbufferCMD (immediate + vsync-synchronized, swapsPending tracking)

TMU (Texture Mapping Unit)

  • Texture Coordinates
    • S/T/W interpolation
    • Perspective correction (S/W, T/W division via 257-entry reciprocal LUT)
  • LOD (Level of Detail)
    • LOD calculation from gradients (max gradient MSB position)
    • Mipmap base offset calculation (per-LOD cumulative sizes)
    • LOD bias (tLOD bits 17:12)
    • LOD clamping (lodmin, lodmax)
    • Per-pixel LOD adjustment (perspective-corrected W)
    • Aspect ratio / non-square textures (tLOD lodAspect + lodSIsWider)
    • Trilinear blending (lod_frac)
  • Texture Address
    • texBaseAddr register
    • Texel address generation (row-major, 8/16-bit stride)
    • Clamp and wrap modes (per-axis, textureMode bits 6-7)
    • Clamp W (negative W forces S=T=0, textureMode bit 3)
    • texBaseAddr_1/2/3_8 (per-LOD base addresses)
  • Texture Filtering
    • Point sampling (nearest)
    • Bilinear filtering (min/mag)
  • Texture Formats (decode logic)
    • RGB332 (8-bit)
    • A8 (8-bit, alpha only)
    • I8 (8-bit, intensity)
    • AI44 (8-bit, alpha + intensity)
    • ARGB8332 (16-bit)
    • RGB565 (16-bit)
    • ARGB1555 (16-bit)
    • ARGB4444 (16-bit)
    • AI88 (16-bit, alpha + intensity)
    • YIQ422 / AYIQ8422 (NCC compressed)
    • P8 / AP88 (palettized)
  • Texture Combine
    • Texture output to color combine unit
    • Multi-texture (TMU chaining)
    • NCC table decode
    • Palette RAM (256-entry, loaded via NCC table 0 I/Q registers)
    • LOD dither
    • Data swizzle/swap

Bus Interface / Register System

  • BMB bus adapter (BmbBusInterface)
  • 64-entry PCI FIFO with categorized routing (fifoBypass / syncRequired)
  • Pipeline drain blocking for sync registers (triangleCMD, swapbufferCMD, etc.)
  • Address remapping (fbiInit3 bit 0, external bit 21)
  • CPU bus address decode (PCI BAR regions: registers, LFB, texture)
  • texBaseAddr write relocation (SST-1 spec 5.53)
  • PCI configuration space (initEnable, busSnoop)
  • Memory FIFO (off-screen framebuffer extension)

Display Controller

  • Video timing generator (hSync, vSync, backPorch, videoDimensions)
  • Framebuffer scan-out
  • Gamma correction CLUT (clutData)
  • DAC programming (dacData)
  • vRetrace is currently an external input (no internal generation)

Scala CLI Commands

# Run tests
scala-cli test .

# Format code
scalafmt

# Compile
scala-cli compile .

Glide Simulation Tests

Run the Glide2x test suite against the Verilator model:

make native/sim/run/test00      # single test
make native/sim/run-all         # all screenshot tests
TRACE=1 make native/sim/run/test00  # with FST waveform dump

Screenshots are saved to output/<test>/screenshot.png.

Environment variables (set at runtime):

Variable Description
SIM_FST Path for FST waveform output (requires TRACE=1 build)
SIM_CYCLE_LIMIT Max simulation ticks before clean exit (0 = unlimited)
SIM_FBWRITE_LOG Path to log framebuffer writes
SIM_TMU_LOG Path to log TMU/rasterizer activity

DOSBox-X (32-bit Glide Path)

The sim backend builds a 32-bit libglide2x, so DOSBox-X must also be 32-bit to dlopen() it.

# Linux-hosted sim test
make native/sim/run/test00

# Linux-hosted trace capture
make native/trace/run/df00sim

# Build and run a DOS guest binary inside DOSBox-X through its built-in GLIDE2X.OVL
make dos/sim/run/df00sdk

# Headless DOS guest variant
make dos/sim/headless/df00sdk

# DOS guest with trace backend
make dos/trace/run/df00sdk

# Launch a raw DOSBox-X session with the sim Glide backend injected
make dos/dosbox

Common top-level commands:

  • make native/help prints the Linux-hosted and trace command surface.
  • make native/sim/build builds all Linux-hosted Glide test binaries.
  • make native/sim/build/<name> builds one Linux-hosted test binary.
  • make native/sim/run/<name> runs one Linux-hosted test and writes screenshot output under output/.
  • make native/trace/run/<name> rebuilds the host Glide runtime with the trace harness and captures traces/<name>.bin.
  • make native/sim/check/<name> replays an existing trace through the check pipeline.
  • make native/sim/test/<name> captures and checks in one step.
  • make native/sim/check-all replays every existing trace under traces/.
  • make dos/help prints the DOS and Tomb command surface.
  • make dos/sim/build builds all DOS SDK-style test binaries from emu/glide/glide2x/sst1/glide/tests/Makefile.sdkwat.
  • make dos/sim/build/<name> builds one DOS SDK-style binary, for example make dos/sim/build/df00sdk.
  • make dos/sim/run/<name> mounts emu/glide/glide2x/sst1/glide/tests as C: in DOSBox-X and runs <name>.exe with the sim backend.
  • make dos/sim/headless/<name> does the same with DOSBOXX32_HEADLESS=1.
  • make dos/trace/run/<name> runs a DOS guest against the trace-capture Glide runtime and writes traces/dos/<name>.bin.
  • make dos/trace/headless/<name> does the same headlessly.
  • make dos/dosbox ARGS='...' launches DOSBox-X with the sim Glide backend and forwards extra DOSBox-X arguments.
  • make tomb/help prints the Tomb Raider setup requirements.
  • make tomb/prepare ARGS='--game-dir ... --patch ... --iso ...' prepares a reusable Tomb Raider source tree from your game files and 3dfx patch assets.
  • make tomb/sim/run, make tomb/sim/headless, and make tomb/sim/capture run Tomb Raider against the sim backend.
  • make tomb/sim/trace runs Tomb Raider against the live sim runtime and also dumps a trace to traces/tomb_live/trace.bin.
  • make tomb/sim/trace/check replays traces/tomb_live/trace.bin into output/tomb/trace_replay_live/.
  • make tomb/trace/run and make tomb/trace/headless run Tomb Raider against the trace runtime and write traces/tomb/trace.bin automatically.
  • make tomb/trace/check replays traces/tomb/trace.bin directly into output/tomb/trace_replay/ without pulling in any stale state.bin from an old trace directory.

The hierarchy is intentional:

  • native/<runtime>/<action>[/<name>] is for Linux-hosted test binaries.
  • dos/<runtime>/<action>[/<name>] is for DOS guest binaries inside DOSBox-X.
  • tomb/<runtime>/<action> is for Tomb Raider convenience flows.
  • de10/<action> is for board-oriented workflows using the de10 runtime.

Runtimes are explicit and non-stateful:

  • sim means the normal in-process Verilator-backed Glide runtime.
  • trace means the trace-capture Glide runtime.
  • de10 means the board/MMIO-backed Glide runtime.

In practice:

  • native/... and dos/... currently expose sim and trace directly in the command path.
  • de10/... keeps the runtime implicit in the namespace because every de10 command already targets the board runtime.
  • SIM_INTERFACE=de10 is the closest host-side reproduction of the board interface: it still uses the sim runtime, but swaps the Verilated top-level from CoreSim to CoreDe10 and drives the DE10-style MMIO plus Avalon memory ports from the host harness.

Examples:

make native/sim/run/test00 SIM_INTERFACE=de10
make dos/sim/run/df00sdk SIM_INTERFACE=de10

Tomb Raider Setup

The Tomb helper scripts expect a prepared source tree at DOSBOX_TOMB_SRC. By default that is /tmp/tr1-3dfx.

The easiest way to create it is:

make tomb/prepare ARGS='--game-dir /path/to/TOMBRAID --patch /path/to/3dfx-patch.zip --iso /path/to/tr1disc01.iso'

That helper:

  • copies your source game directory into DOSBOX_TOMB_SRC/TOMBRAID
  • copies the ISO into DOSBOX_TOMB_SRC/tr1disc01.iso if provided
  • overlays the supplied 3dfx patch directory or archive onto the game directory

It accepts either a patch directory or a .zip/tar archive. Add --output /path/to/tree to prepare somewhere other than DOSBOX_TOMB_SRC, and --force to replace an existing tree.

Expected layout by default:

/tmp/tr1-3dfx/
  tr1disc01.iso
  TOMBRAID/
    TOMB.EXE
    ... game files ...

Typical flow:

  • Prepare the tree with make tomb/prepare ..., or assemble the layout manually.
  • Run make tomb/help to print the current assumptions.
  • Run make tomb/sim/run or make tomb/sim/headless.

At launch time the helper scripts copy the source tree into DOSBOX_TOMB_STAGE_ROOT (default /tmp/tr1-run) and automatically rename any bundled glide2x.ovl so that DOSBox-X's built-in GLIDE2X.OVL guest bridge is used instead.

You can override the defaults with these environment variables:

  • DOSBOX_TOMB_SRC
  • DOSBOX_TOMB_STAGE_ROOT
  • DOSBOX_TOMB_GAME_DIR
  • DOSBOX_TOMB_ISO
  • DOSBOX_TOMB_EXE

Notes:

  • scripts/run-dosboxx32-glide prefers DOSBOXX32_BIN if set.
  • If dosbox-x on PATH is already 32-bit, it uses that.
  • Otherwise it auto-resolves Nix pkgsi686Linux.dosbox-x.
  • The script appends scripts/dosboxx32-glide.conf (enables glide=true, voodoo_card=false, lfb=full_noaux).
  • For low-level manual control you can still use scripts/run-dosboxx32-glide directly.

Trace-Based Testing

Glide trace files (.bin) capture PCI bus operations for offline replay against both the RTL simulation and a software reference model:

# Capture a trace from a Linux-hosted test
make native/trace/run/test_alphabet

# Replay one trace through the reference model and RTL simulator
make native/sim/check/test_alphabet

# Capture and replay in one step
make native/sim/test/test_alphabet

# Replay every existing trace
make native/sim/check-all

Replay outputs are written to test-output/<trace>/ as <trace>_ref.png, <trace>_sim.png, and <trace>_diff.png.

Trace files are stored in traces/ and compared pixel-by-pixel against a reference model.

DE10-Nano

The DE10-Nano flow is meant for three practical tasks:

  • generate FPGA-ready RTL and bitstreams
  • program or deploy a board
  • run workloads on real hardware

Common commands:

make de10/help

# Generate RTL / FPGA build inputs
make de10/rtl
make de10/qsys
make de10/bitstream

# Program or deploy to the default board (fpga@debian-fpga.local)
make de10/setup/program
make de10/setup/deploy

# Basic board validation
make de10/check/mmio

# Run workloads on hardware
make de10/run/dos/df00sdk
make de10/run/tomb

Useful defaults and assumptions:

  • Default board target is fpga@debian-fpga.local unless DE10_HOST or DE10_USER override it.
  • Default deployed runtime prefix is /home/fpga/spinalvoodoo unless DE10_REMOTE_PREFIX overrides it.
  • make de10/run/dos/<name> uses the deployed launcher on the board and mounts DE10_RUNTIME_DIR (default /home/fpga/de10-cross) as C:.
  • make de10/run/tomb expects a prepared remote Tomb tree at DE10_TOMB_SRC (default /home/fpga/tr1-3dfx) containing the game directory and ISO.

Extra DE10 helpers live in scripts/ and tools/ for board capture, replay, and bring-up.

About

SpinalHDL implementation of the 3dfx Voodoo Graphics GPU

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages