RHDL’s gate-level backend converts high-level HDL components into netlists composed of seven primitive gate types plus D flip-flops. This intermediate representation (IR) is the foundation for gate-level simulation, synthesis statistics, and verification.

Architecture

HDL Component (Ruby DSL)
        │
        ▼
┌───────────────────┐
│   Netlist Lower   │  lib/rhdl/codegen/structure/lower.rb
└───────────────────┘
        │
        ▼
┌───────────────────┐
│  Structure IR     │  Gate-level intermediate representation
└───────────────────┘
        │
        ├──────────────┬──────────────┬──────────────┐
        ▼              ▼              ▼              ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│  JSON Export│ │ CPU Sim     │ │ SIMD Sim    │ │ Verilog Gen │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘

Primitive Gates

The IR uses seven combinational primitives plus a sequential element:

GateInputsFunction
AND2+Bitwise AND (N-ary reduced to binary tree)
OR2+Bitwise OR (N-ary reduced to binary tree)
XOR2Exclusive OR
NOT1Inverter
MUX32-to-1 multiplexer (select, when_true, when_false)
BUF1Buffer/identity (used for fan-out)
CONST0Constant 0 or 1
ElementInputsFunction
DFFd, clk, rst, enD flip-flop with optional reset and enable

IR Data Structures

The Structure IR (RHDL::Codegen::Structure::IR) represents a complete gate-level design:

ir = RHDL::Codegen::Structure::IR.new(
  name: "component_name",
  net_count: 42,
  gates: [...],
  dffs: [...],
  inputs: { "a" => [0, 1, 2, 3, 4, 5, 6, 7] },
  outputs: { "y" => [32, 33, 34, 35, 36, 37, 38, 39] }
)

Gate Struct

Gate = Struct.new(:type, :inputs, :output, :value)
# type:   :AND, :OR, :XOR, :NOT, :MUX, :BUF, :CONST
# inputs: Array of net indices feeding this gate
# output: Net index for gate output
# value:  Constant value (for CONST gates only)

DFF Struct

DFF = Struct.new(:d, :q, :rst, :en, :async_reset, :reset_value)
# d:           D input net index
# q:           Q output net index
# rst:         Reset signal net index (optional)
# en:          Enable signal net index (optional)
# async_reset: Boolean for asynchronous reset behavior
# reset_value: Value on reset (0 or 1)

Net Mapping

Every signal in the design is bit-blasted — multi-bit buses become arrays of individual net indices. Input and output ports map to arrays of net IDs:

{
  "inputs": {
    "a": [0, 1, 2, 3, 4, 5, 6, 7],
    "b": [8, 9, 10, 11, 12, 13, 14, 15]
  },
  "outputs": {
    "result": [100, 101, 102, 103, 104, 105, 106, 107]
  }
}

Gate Count Examples

Typical gate counts for common components:

ComponentWidthGatesDFFsNets
AndGate1103
RippleCarryAdder848067
Register80824
Counter8~608~80
ALU8~4000~500
Multiplier8~8000~1000
SynthDatapath (CPU)~50524~600

Supported Components

The backend supports 53 HDL components across all categories:

CategoryCountExamples
Gates13AND, OR, XOR, NOT, NAND, NOR, Bitwise ops
Sequential12DFF, Register, ShiftRegister, Counter, PC
Arithmetic10Adders, Subtractor, ALU, Multiplier, Divider
Combinational16Mux2–MuxN, Decoders, Encoders, BarrelShifter
CPU2InstructionDecoder, SynthDatapath

File Locations

lib/rhdl/codegen/structure/
├── ir.rb           # Gate-level IR data structures
├── lower.rb        # HDL to gate-level lowering
├── primitives.rb   # Gate primitive definitions
├── toposort.rb     # Topological sorting
├── sim_cpu.rb      # CPU-based interpreter
└── sim_gpu.rb      # SIMD-style simulator

Next Steps