Skip to content

skryl/rhdl

Repository files navigation

Build and Test

    ____  __  ______  __
   / __ \/ / / / __ \/ /
  / /_/ / /_/ / / / / /
 / _, _/ __  / /_/ / /___
/_/ |_/_/ /_/_____/_____/

  Ruby Hardware Description Language

RHDL

RHDL is a Domain Specific Language (DSL) for designing hardware using Ruby's flexible syntax and exporting to synthesizable Verilog. It provides Ruby developers with a comfortable environment to create hardware designs leveraging Ruby's metaprogramming capabilities.

Demo: Web Simulator

Web Simulator

Features

  • Component DSLs: Ruby-based DSLs for combinational, sequential, memory, and state machine components
  • Verilog Export: Generate synthesizable Verilog from Ruby definitions
  • HDL Simulation: RTL-level and Gate-level simulation using a fast Rust backend
  • Component Library: Gates, flip-flops, registers, ALU, memory, CPU examples, and more
  • Gate-Level Synthesis: Lower components to primitive gate netlists (AND, OR, XOR, NOT, MUX, DFF)
  • Diagram Generation: Multi-level circuit diagrams with SVG, PNG, and DOT output
  • Web Simulator: WASM based simulator for running your designs in the browser

Documentation

Document Description
Overview Introduction to the HDL framework
CLI Reference Command line interface reference
DSL Guide DSL reference for synthesizable components
Components Complete reference for all HDL components
Simulation Core simulation engine infrastructure
Export Verilog and gate-level export
Gate-Level Backend Gate-level synthesis and simulation
Diagrams Multi-level circuit diagrams
Debugging Signal probing, breakpoints, and TUI
8-bit CPU Sample 8-bit CPU reference
MOS 6502 MOS 6502 CPU implementation
Apple II Apple II emulation
Game Boy Game Boy (DMG/GBC/SGB) emulation
RISC-V + Linux/xv6 RISC-V RV32I CPU implementation with Linux and xv6 build/boot workflows
Web Simulator Browser simulator (WASM + VCD + Apple II runner)

Web Simulator

RHDL includes a browser-based simulator with WASM backends, live VCD tracing, Apple II runner tooling, memory dump workflows, and component/source exploration.

Quick Start

Installation

gem install bundler -v '~> 2.5'
bundle install

Defining Components with the DSL

RHDL provides several DSL constructs for synthesizable hardware:

Combinational Logic

class SimpleALU < RHDL::Sim::Component
  input :a, width: 8
  input :b, width: 8
  input :op, width: 2
  output :result, width: 8

  behavior do
    result <= case_select(op, {
      0 => a + b,
      1 => a - b,
      2 => a & b,
      3 => a | b
    }, default: 0)
  end
end

Sequential Logic

class Counter < RHDL::Sim::SequentialComponent
  input :clk
  input :rst
  input :en
  output :count, width: 8

  sequential clock: :clk, reset: :rst, reset_values: { count: 0 } do
    count <= mux(en, count + 1, count)
  end
end

Memory Components

class RAM256x8 < RHDL::Sim::Component
  include RHDL::DSL::Memory

  input :clk
  input :we
  input :addr, width: 8
  input :din, width: 8
  output :dout, width: 8

  memory :mem, depth: 256, width: 8
  sync_write :mem, clock: :clk, enable: :we, addr: :addr, data: :din
  async_read :dout, from: :mem, addr: :addr
end

State Machines

class TrafficLight < RHDL::Sim::SequentialComponent
  include RHDL::DSL::StateMachine

  input :clk
  input :rst
  input :sensor
  output :red
  output :yellow
  output :green

  state_machine clock: :clk, reset: :rst do
    state :RED, value: 0 do
      output red: 1, yellow: 0, green: 0
      transition to: :GREEN, when_cond: :sensor
    end

    state :YELLOW, value: 1 do
      output red: 0, yellow: 1, green: 0
      transition to: :RED, after: 3
    end

    state :GREEN, value: 2 do
      output red: 0, yellow: 0, green: 1
      transition to: :YELLOW, when_cond: proc { in_val(:sensor) == 0 }
    end

    initial_state :RED
  end
end

Hierarchical Components

Build complex components from sub-components using instance, wire, and port:

class MyDatapath < RHDL::Sim::Component
  input :clk
  input :rst
  input :a, width: 8
  input :b, width: 8
  output :result, width: 8

  # Internal wire
  wire :alu_out, width: 8

  # Sub-component instances
  instance :alu, ALU, width: 8
  instance :reg, Register, width: 8

  # Port connections
  port :a => [:alu, :a]
  port :b => [:alu, :b]
  port [:alu, :result] => :alu_out
  port :alu_out => [:reg, :d]
  port :clk => [:reg, :clk]
  port :rst => [:reg, :rst]
  port [:reg, :q] => :result
end

Exporting to Verilog

require 'rhdl'

# Export a component to Verilog
component = MyComponent.new
verilog_code = RHDL::Export.verilog(component)

# Or use the class method
verilog_code = MyComponent.to_verilog

# Batch export with CLI
# rhdl export --all
# rhdl export --all --scope lib

Generated Verilog example:

module simple_alu(
  input [7:0] a,
  input [7:0] b,
  input [1:0] op,
  output [7:0] result
);
  assign result = (op == 2'd0) ? (a + b) :
                  (op == 2'd1) ? (a - b) :
                  (op == 2'd2) ? (a & b) :
                  (a | b);
endmodule

Simulation

require 'rhdl'

# Create an ALU
alu = RHDL::HDL::ALU.new("my_alu", width: 8)
alu.set_input(:a, 10)
alu.set_input(:b, 5)
alu.set_input(:op, RHDL::HDL::ALU::OP_ADD)
alu.propagate

puts alu.get_output(:result)  # => 15

Examples

RHDL includes four comprehensive example implementations demonstrating the framework's capabilities for building complex hardware systems.

Example Type CPU Description
MOS 6502 Processor 8-bit Classic 1970s microprocessor
Apple II Computer 6502 Complete 1977 personal computer
Game Boy Console SM83 Nintendo handheld (DMG/GBC/SGB)
RISC-V Processor 32-bit RV32I cores with xv6 readiness and UART/virtio validation

MOS 6502 CPU

Complete behavior simulation of the MOS 6502 with all 56 instructions, 13 addressing modes, and BCD arithmetic.

+----------------------------------------------------------+
|                      MOS6502::CPU                        |
+----------------------------------------------------------+
|  +----------------------------------------------------+  |
|  |                     Datapath                       |  |
|  |  +-------+  +-------+  +-------+  +-------------+  |  |
|  |  | A(8b) |  | X(8b) |  | Y(8b) |  | Status(8b)  |  |  |
|  |  +-------+  +-------+  +-------+  | N V B D I Z C  |  |
|  |  +--------+  +-------+           +-------------+   |  |
|  |  | PC(16b)|  | SP(8b)|                             |  |
|  |  +--------+  +-------+                             |  |
|  |  +-------------------------------------------------+  |
|  |  |              ALU (14 operations)                |  |
|  |  +-------------------------------------------------+  |
|  +----------------------------------------------------+  |
|  +----------------------------------------------------+  |
|  |         Control Unit (26-state FSM)                |  |
|  +----------------------------------------------------+  |
|  +----------------------------------------------------+  |
|  |      Instruction Decoder (151 opcodes)             |  |
|  +----------------------------------------------------+  |
+----------------------------------------------------------+

CLI Options:

rhdl examples mos6502 --demo           # Run demo program
rhdl examples mos6502 --karateka       # Play Karateka game

Quick Example:

require_relative 'examples/mos6502/cpu'

cpu = MOS6502::CPU.new
cpu.assemble_and_load(<<~ASM, 0x8000)
  LDA #$42      ; Load 0x42 into accumulator
  STA $00       ; Store to zero page
  BRK           ; Break
ASM
cpu.reset
cpu.run
puts cpu.status_string  # A:42 X:00 Y:00 SP:FD PC:8006

Apple II

Complete Apple II emulation with video modes, keyboard, speaker, and Disk II controller.

+-----------------------------------------------------------------------+
|                           Apple II System                             |
+-----------------------------------------------------------------------+
|  +-----------+     +----------+     +--------------------------+      |
|  |  MOS 6502 |     |  Timing  |     |     Video Generator      |      |
|  |    CPU    |<--->|Generator |---->|  - Text (40x24)          |      |
|  |   1 MHz   |     |  14 MHz  |     |  - Lo-res (40x48)        |      |
|  +-----------+     +----------+     |  - Hi-res (280x192)      |      |
|        |                            +--------------------------+      |
|  +-----+--------------------------------------------------+           |
|  |                   Address/Data Bus                     |           |
|  +--+--------+--------+--------+--------+---------+-------+           |
|     |        |        |        |        |         |                   |
|  +--+--+  +--+--+  +--+--+  +--+--+  +--+---+  +--+--+                |
|  | 48KB|  | 12KB|  | I/O |  |Disk |  |Key-  |  |Speak|                |
|  | RAM |  | ROM |  | Page|  | II  |  |board |  | er  |                |
|  +-----+  +-----+  +-----+  +-----+  +------+  +-----+                |
+-----------------------------------------------------------------------+

CLI Options:

rhdl examples apple2 --appleiigo              # Run with AppleIIGo ROM
rhdl examples apple2 --karateka --hires       # Play Karateka in hi-res
rhdl examples apple2 --appleiigo --disk g.dsk # Load disk image
rhdl examples apple2 --demo                   # Run demo program

Game Boy

Nintendo Game Boy emulation based on MiSTer reference, supporting DMG, GBC, and SGB modes.

+-----------------------------------------------------------------------+
|                          Game Boy System                              |
+-----------------------------------------------------------------------+
|  +---------+    +-------+    +---------------------------+            |
|  |  SM83   |    | Timer |    |      PPU (Video)          |            |
|  |  CPU    |<-->|Counter|--->|  - Background layer       |            |
|  | 4.19MHz |    +-------+    |  - Window layer           |            |
|  +----+----+                 |  - 40 sprites (8x8/8x16)  |            |
|       |                      |  - 160x144 LCD            |            |
|  +----+--------------------------------------------------+            |
|  |                  Address/Data Bus                     |            |
|  +--+------+------+------+------+------+------+----------+            |
|     |      |      |      |      |      |      |                       |
|  +--+-+  +-+-+  +-+-+  +-+-+  +-+-+  +-+-+  +-+----+                  |
|  |ROM |  |VRAM| |WRAM| |OAM | |HRAM| |I/O|  | APU  |                  |
|  |0-8M|  |8KB | |8KB | |160B| |127B| |   |  | 4ch  |                  |
|  +----+  +---+  +----+ +----+ +----+ +---+  +------+                  |
+-----------------------------------------------------------------------+

CLI Options:

rhdl examples gameboy cpu_instrs.gb            # Run test ROM
rhdl examples gameboy --demo                   # Run demo display
rhdl examples gameboy --pop                    # Load Prince of Persia ROM
rhdl examples gameboy game.gb --audio          # Enable audio

RISC-V RV32I

Modern 32-bit RISC-V processor with single-cycle and 5-stage pipelined implementations.

Single-Cycle Datapath:

+-----------------------------------------------------------------------+
|                    RV32I Single-Cycle Datapath                        |
+-----------------------------------------------------------------------+
|  +------+    +------+    +-------+    +-------+                       |
|  |  PC  |--->| Inst |--->|Decoder|--->|Control|                       |
|  | Reg  |    | Mem  |    |       |    |Signals|                       |
|  +--+---+    +------+    +-------+    +---+---+                       |
|     |                                     |                           |
|  +--+-------------------------------------+--+                        |
|  |              Datapath Muxes               |                        |
|  +--+--------+-------------------+-----------+                        |
|     |        |                   |                                    |
|  +--+--+  +--+--+            +---+--+    +------+                     |
|  | PC  |  | Reg |  rs1/rs2   | ALU  |--->| Data |                     |
|  |+4/Br|  |File |----------->|      |    | Mem  |                     |
|  +-----+  |32x32|            +------+    +------+                     |
|           +--+--+                |           |                        |
|              ^                   v           v                        |
|              +--------[ Write Back ]<--------+                        |
+-----------------------------------------------------------------------+

5-Stage Pipeline:

+------+    +------+    +------+    +------+    +------+
|  IF  |--->|  ID  |--->|  EX  |--->| MEM  |--->|  WB  |
+------+    +------+    +------+    +------+    +------+
 Fetch      Decode      Execute     Memory     Write
 Inst       Regs/Imm    ALU/Br      Access     Back

Usage:

require_relative 'examples/riscv/hdl/ir_harness'

harness = RHDL::Examples::RISCV::IRHarness.new(backend: :jit, allow_fallback: false)
harness.load_program([
  0x00500093,  # addi x1, x0, 5
  0x00A00113,  # addi x2, x0, 10
  0x002081B3,  # add x3, x1, x2
])
harness.reset!
harness.run_cycles(10)
puts "x3 = #{harness.read_reg(3)}"  # => 15

CLI Options:

# Run a RISC-V binary in the terminal runner
# Defaults: --mode ir --sim compile
rhdl examples riscv path/to/program.bin

# Choose mode/backend and display mode
rhdl examples riscv --mode ir --sim compile --io mmap path/to/program.bin

# Core selection (default is single)
rhdl examples riscv --core pipeline path/to/program.bin
rhdl examples riscv --core single path/to/program.bin

# Show live debug panel (ESC toggles command mode)
rhdl examples riscv -d --io uart path/to/program.bin

# Launch xv6 (forces UART mode automatically)
./examples/riscv/software/build_xv6.sh
rhdl examples riscv --xv6 -d
rhdl examples riscv --xv6 --mode verilog
rhdl examples riscv --xv6 --mode circt

# Build Linux kernel artifacts (Phase 0 source workflow)
git submodule update --init --recursive examples/riscv/software/linux
./examples/riscv/software/build_linux.sh
# Buildroot for prebuilt toolchain defaults to linux/amd64 Buildroot host images.

# Run Linux via the top-level CLI (forces UART mode automatically)
rhdl examples riscv --linux
rhdl examples riscv --linux --mode verilog
rhdl examples riscv --linux --mode circt

# Optional Linux artifact overrides (initramfs + custom DTB)
rhdl examples riscv --linux \
  --initramfs path/to/initramfs.cpio \
  --dtb path/to/riscv.dtb

# Headless run for CI/smoke tests
rhdl examples riscv --headless --cycles 200000 path/to/program.bin

Linux milestones are covered in spec/examples/riscv/linux_boot_milestones_spec.rb. Additional Linux compatibility specs live under spec/examples/riscv/linux_*_spec.rb. xv6 shell I/O coverage across IR/Verilator/Arcilator lives in spec/examples/riscv/xv6_shell_io_spec.rb.

See each example's documentation for complete details on architecture, instruction sets, and CLI options.

Project Structure

rhdl/
├── lib/rhdl/           # Core library
│   ├── dsl.rb          # HDL DSL for component definitions
│   ├── export/         # Verilog export backends
│   ├── simulation/     # Simulation engine
│   ├── hdl/            # HDL component library
│   │   ├── gates.rb, sequential.rb, arithmetic.rb, ...
│   │   └── cpu/        # HDL CPU implementation
│   ├── debug/          # Signal probing & debugging
│   ├── tui/            # Terminal GUI
│   └── diagram/        # Diagram rendering
├── examples/           # Example implementations
│   ├── mos6502/        # MOS 6502 CPU (8-bit, 189+ tests)
│   ├── apple2/         # Apple II computer emulation
│   ├── gameboy/        # Game Boy (DMG/GBC/SGB)
│   └── riscv/          # RISC-V RV32I CPU (single + pipelined)
├── export/             # Generated output files
│   ├── verilog/        # Generated Verilog
│   └── gates/          # Gate-level JSON netlists
└── docs/               # Documentation

Command Line Interface

RHDL provides a comprehensive CLI for common operations. See CLI Reference for complete documentation.

# Interactive TUI debugger
rhdl tui sequential/counter              # Debug a counter component
rhdl tui RHDL::HDL::ALU --signals inputs # Debug ALU, show only inputs
rhdl tui --list                          # List available components

# Diagram generation
rhdl diagram --all                       # Generate all diagrams
rhdl diagram RHDL::HDL::ALU --format svg # Single component diagram

# Verilog export
rhdl export --all                        # Export all components
rhdl export --lang verilog --out ./out RHDL::HDL::Counter

# Gate-level synthesis
rhdl gates --export                      # Export to JSON netlists
rhdl gates --stats                       # Show synthesis statistics

# Example emulators
rhdl examples apple2 --demo              # Run Apple II demo mode
rhdl examples gameboy --demo             # Run Game Boy demo mode
rhdl examples riscv --xv6 -d             # Run RISC-V xv6 with debug panel

Execution Backends

RHDL provides multiple simulation backends with different performance/flexibility tradeoffs:

Behavioral Simulation (Ruby)

Pure Ruby execution at the behavior block level. Best for development and debugging.

sim = RHDL::Sim::Simulator.new
sim.add_component(alu)
sim.add_clock(clk)
sim.run(100)  # 100 clock cycles

Gate-Level (Netlist) Simulation

Simulates primitive gate netlists (AND, OR, XOR, NOT, MUX, DFF). Four backend options:

Backend Speed Startup Use Case
Ruby SimCPU 22K iter/s Immediate Development, small circuits
Rust Interpreter 427K iter/s (20x) Immediate Functional verification
Rust JIT (Cranelift) 50-100M gates/s 0.1-0.5s Fast interactive simulation
Rust Compiler (SIMD) 100M+ gates/s 1-2s Maximum throughput, batch testing

The compiler supports AVX2/AVX512 for 256-512 parallel test vectors.

ir = RHDL::Codegen::Netlist::Lower.from_components([alu])
sim = RHDL::Codegen::Netlist::NetlistSimulator.new(ir, backend: :interpreter, lanes: 64)
sim.poke('a', 0xFF)
sim.evaluate
result = sim.peek('y')

IR-Level Simulation (Word-Level)

Word-level bytecode simulation for complex designs like CPUs:

Backend Speed Startup Use Case
Interpreter 60K cycles/s Immediate Interactive CPU debugging
JIT (Cranelift) 600K cycles/s (10x) 0.1-0.5s Moderate simulations
AOT Compiler 2.3M cycles/s (38x) 0.5-2s Long simulations, games
sim = RHDL::Codegen::IR::IrSimulator.new(ir_json, backend: :jit)
sim.compile
sim.run_ticks(1_000_000)

Verilog Export & External Simulation

Export components to Verilog for synthesis or simulation with industry-standard tools:

# Export component to Verilog
verilog_code = RHDL::Codegen.verilog(component)
File.write('alu.v', verilog_code)

External simulators:

Tool Speed Use Case
iverilog ~100K cycles/s Functional verification, golden reference
Verilator ~5.7M cycles/s High-performance RTL simulation, benchmarking
CIRCT/MLIR (Arcilator) Workload-dependent Native RTL simulation from FIRRTL/MLIR flows
# Compile and run with iverilog
iverilog -o sim alu.v testbench.v && vvp sim

# Compile with Verilator for maximum performance
verilator --cc alu.v --exe testbench.cpp

# Compile FIRRTL/MLIR with CIRCT + Arcilator
firtool design.fir --ir-hw -o design.mlir
arcilator design.mlir --state-file=state.json -o design.ll

When iverilog is installed, RHDL automatically runs gate-level verification tests comparing synthesized Verilog against behavioral simulation.

Building Native Extensions

rake native:build    # Build all Rust extensions
rake native:check    # Check availability

All backends include automatic fallback to Ruby when native extensions aren't available.

See Simulation and Gate-Level Backend for complete details.

Performance Benchmarks

RHDL includes benchmarking tasks to measure simulation performance across backends:

rake bench:native[gates]             # Benchmark gate-level simulation
rake bench:native[cpu8bit,cycles]    # Benchmark 8-bit CPU FastHarness (compiler vs arcilator_gpu)
rake bench:native[mos6502,cycles]    # Benchmark MOS 6502 CPU
rake bench:native[apple2,cycles]     # Benchmark Apple II full system
rake bench:native[gameboy,frames]    # Benchmark GameBoy with Prince of Persia
rake bench:web[apple2,cycles] # Benchmark Apple II web WASM backends
rake bench:web[riscv,cycles]  # Benchmark RISC-V web WASM backends

Sample Results (1M cycles):

System JIT Compiler Verilator Compiler Speedup
MOS 6502 0.23M/s 1.58M/s ~5.6M/s 6.8x vs JIT
Apple II 0.06M/s 0.28M/s ~5.6M/s 4.8x vs JIT
GameBoy - 1.27 MHz ~5.8 MHz 30% real-time

Backend Selection Guide:

  • < 100K cycles: Use JIT (fast startup)
  • 100K - 1M cycles: Use JIT or Compiler
  • > 1M cycles: Use Compiler, Verilator, or CIRCT/MLIR (Arcilator)
  • Maximum RTL speed: Use Verilator or CIRCT/MLIR (requires external tools)

See Performance Guide for detailed benchmarks and optimization tips.

Rake Tasks

# Testing
bundle exec rake spec                  # Run all tests
bundle exec rake spec[riscv]           # Run RISC-V specs
bundle exec rake pspec                 # Run tests in parallel
bundle exec rake pspec[riscv]          # Run RISC-V specs in parallel

# Test and simulation benchmarks
bundle exec rake spec:bench[riscv,20]  # Benchmark 20 RISC-V spec files
bundle exec rake bench:native[ir,5000000]     # Benchmark IR runners
bundle exec rake bench:native[gates]          # Benchmark gate-level simulation
bundle exec rake bench:native[cpu8bit,5000000] # Benchmark 8-bit CPU compiler vs arcilator_gpu
bundle exec rake bench:web[apple2]     # Benchmark Apple II web compiler vs arcilator vs verilator
bundle exec rake bench:web[riscv]      # Benchmark RISC-V web compiler vs arcilator vs verilator

# Dependency checks
bundle exec rake deps:check             # General dependency status
bundle exec rake deps:check_gpu         # Fail-fast ArcToGPU toolchain check
RHDL_ENABLE_ARCILATOR_GPU=1 bundle exec rspec spec/examples/8bit/hdl/cpu/arcilator_gpu_parity_spec.rb # Enable ArcToGPU parity test

# Native backends
bundle exec rake native:build          # Build native extensions
bundle exec rake native:check          # Check extension availability

# Web simulator
bundle exec rake web:build             # Generate web simulator WASM artifacts
bundle exec rake web:generate          # Generate web fixtures/artifacts
bundle exec rake web:bundle            # Bundle web app + runtime assets with Bun (web/dist/)
bundle exec rake web:start             # Start local web server with COOP/COEP headers

# Desktop app (Electrobun)
bundle exec rake desktop:install        # Install desktop dependencies (bun install in web/desktop)
bundle exec rake desktop:dev           # Build and launch desktop app in dev mode
bundle exec rake desktop:build         # Build desktop app package (development target)
bundle exec rake desktop:release       # Build desktop app package (stable target)
bundle exec rake desktop:clean         # Remove desktop build artifacts

Component Library

Category Components
Gates AND, OR, XOR, NOT, NAND, NOR, XNOR, Buffer, Tristate
Flip-flops DFlipFlop, TFlipFlop, JKFlipFlop, SRFlipFlop, SRLatch
Registers Register, ShiftRegister, Counter, ProgramCounter, StackPointer
Arithmetic HalfAdder, FullAdder, RippleCarryAdder, Subtractor, Multiplier, Divider, ALU
Combinational Mux2/4/8/N, Demux, Decoder, Encoder, BarrelShifter, ZeroDetect
Memory RAM, DualPortRAM, ROM, RegisterFile, Stack, FIFO

License

MIT License

About

Ruby Hardware Description Language and Simulator

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors