RHDL exports synthesizable Verilog from your Ruby hardware descriptions. This page covers the export workflow, supported DSL features, module naming, and generated output.
Quick Start
CLI
# Export all components
rhdl export --all
# Export only library components
rhdl export --all --scope lib
# Export only examples
rhdl export --all --scope examples
# Export a single component
rhdl export --lang verilog --out ./output RHDL::HDL::Counter
# Export with custom top module name
rhdl export --lang verilog --out ./output --top my_counter RHDL::HDL::Counter
# Clean generated files
rhdl export --cleanProgrammatic
# Single module
verilog = MyComponent.to_verilog
# With custom module name
verilog = MyComponent.to_verilog(top_name: 'custom_name')
# Complete hierarchy (all sub-modules)
verilog = MyComponent.to_verilog_hierarchySupported DSL Features
| DSL Feature | Verilog Output |
|---|---|
input/output with widths | Port declarations |
wire | Wire declarations |
behavior block | assign statements |
sequential block | always @(posedge clk) |
mux(sel, a, b) | Ternary sel ? a : b |
case_select | case statement |
| Arithmetic operators | Verilog operators |
| Bitwise operators | Verilog bitwise ops |
| Shift operators | Verilog shift ops |
| Comparison operators | Verilog comparisons |
instance + port | Module instantiation |
memory + sync_write | reg arrays with always blocks |
async_read | assign from memory |
Bit selection a[7..0] | Verilog bit select |
concat | Verilog concatenation {a, b} |
Anything outside this subset raises an error during lowering.
Module Naming
Ruby class names are automatically converted to snake_case Verilog module names:
RHDL::HDL::ALU # => "alu"
RHDL::HDL::DualPortRAM # => "dual_port_ram"
MOS6502::InstructionDecoder # => "mos6502_instruction_decoder"Signal Sanitization
- Invalid characters replaced with
_ - Verilog keywords suffixed with
_rhdl
Generated Output Example
For this RHDL component:
class Counter < RHDL::Sim::SequentialComponent
parameter :width, default: 8
input :clk, :rst, :en
output :q, width: :width
sequential clock: :clk, reset: :rst, reset_values: { q: 0 } do
q <= mux(en, q + lit(1, width: 8), q)
end
endRHDL generates:
module counter #(
parameter WIDTH = 8
)(
input clk,
input rst,
input en,
output [7:0] q
);
reg [7:0] q_reg;
always @(posedge clk) begin
if (rst)
q_reg <= 8'h00;
else
q_reg <= en ? (q_reg + 8'h01) : q_reg;
end
assign q = q_reg;
endmoduleHierarchical Export
For designs with sub-components, to_verilog_hierarchy generates all modules:
verilog = CPU.to_verilog_hierarchyThis produces a single file containing all referenced modules, or individual files per module when using the CLI.
Output Directory Structure
export/verilog/
├── gates/
│ ├── and_gate.v
│ ├── or_gate.v
│ └── ...
├── sequential/
│ ├── counter.v
│ ├── register.v
│ └── ...
├── arithmetic/
│ ├── alu.v
│ └── ...
└── mos6502/
├── mos6502_alu.v
└── ...
FIRRTL Export
RHDL can also export to FIRRTL format for interoperability with the CIRCT ecosystem:
firrtl = MyComponent.to_firrtl
firrtl = MyComponent.to_firrtl_hierarchyIntermediate Representation
Access the IR directly for custom processing:
ir = MyComponent.to_ir
ir.ports # Port definitions
ir.nets # Wire declarations
ir.regs # Register declarations
ir.assigns # Continuous assignments
ir.instances # Sub-component instances
ir.processes # Sequential processes
ir.memories # Memory definitionsNext Steps
- Gate Synthesis — gate-level netlist generation
- FPGA Workflows — verification with external tools
- Compilation Pipeline — end-to-end flow