Skip to content
 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

125 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

doomgeneric

Fork of ozkl/doomgeneric — adapted for the Unheaded Protocol Computer (UPC)

DOOM over IPv6

DOOM over IPv6 — BPF compute engine running in browser

30 FPS. 393M packets. 50.3B instructions executed. BPF compute engine — Unheaded.

DOOM running entirely inside the Linux kernel. No userspace game loop. IPv6 packets circulate through a ring of network namespaces, and each XDP program invocation executes a burst of MBC (Monad Bytecode) instructions. The packet is the clock. The network is the bus. BPF maps are the memory. eBPF is the CPU.

How It Works

Doom C source → RISC-V cross-compile → MBC bytecode → BPF maps (ROM)

  ┌──────────────────────────────────────────────────────────────────┐
  │ Packet Injector (Go)  →  460K pkt/s  →  AF_PACKET raw socket   │
  └──────────────────────────────┬───────────────────────────────────┘
                                 │
                                 ▼
  monad0 ──▶ monad1 ──▶ monad2 ──▶ monad3 ──▶ monad4 ──▶ monad5
    ▲         XDP          XDP         XDP         XDP         │
    │     256 insns    256 insns   256 insns   256 insns       │
    └──────────────────────────────────────────────────────────┘
                    XDP_TX bounce ring (255 laps)

  Each packet: 256 insns × 255 bounces = 65,280 instructions
  doom-bridge (Go) reads SCREEN_MAP → WebSocket → Browser canvas

Architecture Mapping

Conventional CPU This Project
Clock crystal Packet injector (Go, AF_PACKET)
Clock signal IPv6 packet arrival event
ALU XDP BPF program (monad_cpu)
Instruction memory ROM_MAP — BPF Array, 1 MiB
Data memory RAM_MAP — BPF Array, 64 MiB
Register file CPU_MAP — 16 × 32-bit + flags
Memory-mapped I/O SCREEN_MAP, KBD_MAP
Front-side bus veth ring (6 namespaces, directed cycle)
Pipeline depth MAX_INSN_PER_TICK = 256

Compilation Pipeline

doom.c (id Software, 1993)
  + doomgeneric platform layer
  + libc_monad.c (minimal libc stubs)
  + crt0_monad.S (BSS clear, stack setup)
      │
      ▼  riscv64-unknown-elf-gcc -march=rv32i
      │
doom.elf (RV32I ELF, ~180KB .text)
      │
      ▼  rv32i_to_mbc (Rust translator)
      │
doom.mbc (76,128 MBC instruction words)
doom.rv2mbc (45,934 address translation entries)
      │
      ▼  doom-loader (Python, bpftool batch writes)
      │
BPF maps pinned at /sys/fs/bpf/unheaded/doom-ring/maps/

Memory Hierarchy

L0: BPF Registers        ~0 ns     16 × 32-bit MBC regs
L1: BPF Map (per-CPU)    ~50 ns    CPU_MAP, ROM_MAP
L2: BPF Map (shared)     ~100 ns   RAM_MAP, SCREEN_MAP, KBD_MAP
L3: Userspace Cache       ~1 µs    Loader pre-populated data
L4: Disk / WAD file       ~1 ms    doom1.wad, read once at load

Key Metrics (Phase 8)

Metric Value
Injection rate ~460K packets/sec
Instructions per packet 65,280 (256 × 255 bounces)
Mean instructions per frame 1,465,116
Effective throughput ~20-30M insns/sec
Frame rate ~20 fps (full 320×200)
BPF verifier states ~51,200 (under 1M limit)
MBC expansion ratio 1.65:1 (RV32I → MBC)

Repository Structure

doomgeneric/          ← upstream C source (id Software → ozkl → this fork)
doom.mbc              ← compiled MBC bytecode (333K)
doom.rv2mbc           ← RV32I → MBC address translation map (205K)
screenshots/          ← proof-of-concept screenshots

unheaded/             ← Go + eBPF integration layer
├── cmd/              ← CLI tools
│   ├── doom/         ← main orchestrator
│   ├── doom-bridge/  ← WebSocket frame server (Fenrir's Eye)
│   ├── doom-go-injector/  ← high-perf packet injector (Mjolnir)
│   ├── doom-cpu-dump/     ← BPF map state inspector
│   ├── doom-loader/       ← ROM/RAM loader
│   └── doom-injector-c/   ← C injector (reference)
├── ebpf/             ← eBPF/XDP programs (Rust + Aya)
│   ├── monad-cpu-ebpf/    ← the CPU — MBC instruction decoder
│   └── monad-common/      ← shared types (MbcCpuState, opcodes)
├── pkg/              ← Go libraries (BPF map access, types)
├── dashboard/        ← browser viewer (vanilla JS, WebSocket)
├── docker/           ← containerized ring setup
└── tests/            ← integration + security tests

docs/
├── doom/             ← implementation docs
│   ├── DOOM-BUILD-GUIDE.md        ← full build + run instructions
│   ├── DOOM-BRIDGE-ARCHITECTURE.md ← WebSocket bridge design
│   ├── PERFORMANCE.md             ← performance tuning (WS3)
│   ├── COMPUTATIONAL_GENERALITY.md ← beyond DOOM: Game Boy, SNES, Unix v4
│   ├── BPF-MAP-REFERENCE.md       ← map layouts + access patterns
│   └── phase8-results.md          ← D_DoomMain entry, RAM_MAP fix
├── protocol/         ← architecture specs
│   └── doom-over-ipv6-architecture.md  ← PhD-level system design
└── binder-book/      ← 4-level explainer (ELI5 → Staff/PhD)

Quick Start

Requires Linux 5.15+, Go 1.21+, Rust/Aya toolchain, doom1.wad.

# Build the eBPF CPU program
cd unheaded/ebpf/monad-cpu-ebpf && cargo xtask build-ebpf

# Set up the namespace ring
sudo ./scripts/doom-ring.sh

# Load ROM + RAM into BPF maps
sudo ./scripts/doom-loader.sh doom.mbc doom.rv2mbc doom1.wad

# Start the bridge (WebSocket frame server)
go build -o /tmp/doom-bridge ./unheaded/cmd/doom-bridge
sudo /tmp/doom-bridge --port 6660 --static ./unheaded/dashboard

# Inject packets (start the clock)
go build -o /tmp/doom-go-injector ./unheaded/cmd/doom-go-injector
sudo ip netns exec monad0 /tmp/doom-go-injector --count 500000 --mode fast

# Open http://localhost:6660 in browser

See docs/doom/DOOM-BUILD-GUIDE.md for the full walkthrough.

Upstream doomgeneric

The original doomgeneric library makes porting DOOM easy — implement 5 functions and you have a working port. This fork preserves full upstream compatibility.

Function Description
DG_Init Initialize platform (window, framebuffer)
DG_DrawFrame Frame ready in DG_ScreenBuffer — copy to screen
DG_SleepMs Sleep in milliseconds
DG_GetTicksMs Ticks since launch in milliseconds
DG_GetKey Provide keyboard events

Ported platforms: Windows, X11, SDL, emscripten, UPC/eBPF (this fork).

License

GPL-2.0 — see LICENSE

The doomgeneric/ directory and compiled MBC bytecode (doom.mbc, doom.rv2mbc) are GPL-2.0 per the original id Software release. The unheaded/ integration layer (Go, eBPF, tooling) uses separate licensing — see DOOM_IMPLEMENTATION.md for the GPL boundary.

Credits

  • Original DOOM source: id Software / John Carmack (1997)
  • doomgeneric portable engine: ozkl
  • UPC integration: unheaded

About

DOOM compiled to eBPF/MBC bytecode — computational completeness proof

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages