Generate clean, synthesizable Verilog HDL from your Ruby designs. Ready for FPGA synthesis and ASIC flows.
RHDL lowers your Ruby hardware descriptions through a multi-stage pipeline. First, the Ruby DSL is elaborated into an intermediate representation (IR) that captures the full circuit structure. Then, the IR is optimized and lowered to synthesizable Verilog HDL. Each stage preserves the design intent while producing industry-standard output.
Classes, ports, behavior blocks
Resolve params, flatten hierarchy
Nodes, nets, connections
Synthesizable .v files
Map IR to Verilog constructs
Dead code, constant folding
Exporting to Verilog is a single method call. You can export individual components or entire hierarchies.
require 'rhdl'
# Export a single component
counter = Counter.new(width: 8)
counter.to_verilog("output/counter.v")
# Export with all sub-components
cpu = CPU6502.new
cpu.to_verilog("output/", hierarchy: :flat)
# Creates: output/cpu6502.v (all modules in one file)
cpu.to_verilog("output/", hierarchy: :split)
# Creates: output/cpu6502.v, output/alu.v,
# output/control_unit.v, output/decoder.v, ...
RHDL generates clean, readable Verilog that passes lint checks and synthesizes efficiently. Signal names are preserved from your Ruby source, making debugging and waveform analysis straightforward.
Ruby source: a parameterized shift register with configurable depth and width.
class ShiftRegister < RHDL::Sim::SequentialComponent
def initialize(depth: 4, width: 8)
input :clk, :rst, :en
input :din, width: width
output :dout, width: width
depth.times do |i|
register :"stage_#{i}",
width: width
end
end
behavior clock: :clk,
reset: :rst do
if en
stage_0 <= din
(1...depth).each do |i|
send(:"stage_#{i}") <=
send(:"stage_#{i-1}")
end
dout <= send(:"stage_#{depth-1}")
end
end
end
Generated Verilog: clean, synthesizable output with preserved signal names and proper reset logic.
module shift_register (
input wire clk,
input wire rst,
input wire en,
input wire [7:0] din,
output reg [7:0] dout
);
reg [7:0] stage_0;
reg [7:0] stage_1;
reg [7:0] stage_2;
reg [7:0] stage_3;
always @(posedge clk or
posedge rst) begin
if (rst) begin
stage_0 <= 8'b0;
stage_1 <= 8'b0;
stage_2 <= 8'b0;
stage_3 <= 8'b0;
dout <= 8'b0;
end else if (en) begin
stage_0 <= din;
stage_1 <= stage_0;
stage_2 <= stage_1;
stage_3 <= stage_2;
dout <= stage_3;
end
end
endmodule
Generated Verilog targets the synthesizable subset of IEEE 1364-2005 (Verilog-2005). The output has been tested with major FPGA and ASIC synthesis tools to ensure broad compatibility.
| Tool | Vendor | Target | Status |
|---|---|---|---|
| Vivado | AMD/Xilinx | FPGA (7-series, UltraScale) | Fully supported |
| Quartus Prime | Intel/Altera | FPGA (Cyclone, Stratix) | Fully supported |
| Yosys | Open source | FPGA (iCE40, ECP5, Gowin) | Fully supported |
| Lattice Diamond | Lattice | FPGA (MachXO, ECP) | Fully supported |
| Design Compiler | Synopsys | ASIC | Compatible |
| Genus | Cadence | ASIC | Compatible |
| Icarus Verilog | Open source | Simulation | Fully supported |
| Verilator | Open source | Simulation / Lint | Fully supported |
The export pipeline avoids unsynthesizable constructs. All generated Verilog uses only blocking/non-blocking assignments, continuous assigns, and standard always blocks.
# Full synthesis workflow
design = MyProcessor.new
# Export with synthesis-friendly options
design.to_verilog("rtl/",
hierarchy: :split, # one file per module
reset_style: :async, # async reset (default)
clock_edge: :posedge, # rising edge triggered
naming: :snake_case, # signal naming convention
vendor_pragma: :xilinx, # include synthesis attributes
)
# Verify with Verilator lint
design.lint! # raises on warnings