CIRCT项目尝试基于LLVM和MLIR构建一套模块化、语义清晰一致、可重用的硬件设计基础设施。LLHD是其中一种用于硬件电路的中间表示(IR)。本文记录尝试用LLHD进行硬件电路仿真的过程。
数字计数器verilog源码
这里以一个非常简单的不带进位的十六进制加减计数器为例,verilog设计代码如下:
代码语言:javascript复制module up_down_counter(
input clk, reset,up_down,
output[3:0] counter
);
reg [3:0] counter_up_down;
// down counter
always @(posedge clk or posedge reset)
begin
if(reset)
counter_up_down <= 4'h0;
else if(~up_down)
counter_up_down <= counter_up_down 4'd1;
else
counter_up_down <= counter_up_down - 4'd1;
end
assign counter = counter_up_down;
endmodule
然后还需要一个testbench来给模块添加测试激励:
代码语言:javascript复制`timescale 10ns/1ns // 时间单位/时间精度
// 测试顶层模块
module updowncounter_tb();
reg clk, reset,up_down;
wire [3:0] counter;
// 例化一个待测试模块
up_down_counter dut(clk, reset,up_down, counter);
// 指定时钟行为
initial begin
clk=0;
forever #5ns clk=~clk;
end
// 其它控制信号行为
initial begin
reset=1;
up_down=0;
#20ns;
reset=0;
#200ns;
up_down=1;
end
endmodule
LLHD编译器Moore使用
llhd使用rust编写了一个支持systemverilog的编译器,也能实现对verilog的兼容,可以将verilog源码转换为LLHD IR的表示形式。Moore编译器在github上开源:https://github.com/fabianschuiki/moore,下文就使用moore来编译上文中的计数器:
首先,按照moore
项目中的readme文件编译moore
应用(需要先安装好rust环境):
然后使用moore
编译verilog代码:
./moore -f mlir -e updowncounter_tb -o udcounter.mlir counter_ud_tb.v counter_ud.v
其中-f
参数指定输出的格式,可选项有mlir|llhd
,llhd
是使用rust编写的仿真器llhd-sim
支持的格式,mlir
是继承到CIRCT中的仿真器支持的格式;-e
参数指定顶层模块名,上文中testbench中顶层模块名为updowncounter_tb
;-o
参数指定输出文件名;其余参数被当作输入文件。
moore
编译器会将verilog代码转换为SSA(静态单赋值)形式的LLHD IR表示;这里以mlir
格式为例,截取综合出来的部分IR代码:
llhd.entity @updowncounter_tb() -> () {
%0 = hw.constant 0 : i1
%clk = llhd.sig "clk" %0 : i1
%reset = llhd.sig "reset" %0 : i1
%up_down = llhd.sig "up_down" %0 : i1
%1 = hw.constant 0 : i4
%counter = llhd.sig "counter" %1 : i4
// 待验证电路示例
llhd.inst "inst" @up_down_counter.param1(%clk, %reset, %up_down) -> (%counter) : (!llhd.sig<i1>, !llhd.sig<i1>, !llhd.sig<i1>) -> (!llhd.sig<i4>)
// 时钟clk信号驱动逻辑块
llhd.inst "inst1" @updowncounter_tb.initial.63.0() -> (%clk) : () -> (!llhd.sig<i1>)
// 其他控制信号驱动逻辑块
llhd.inst "inst2" @updowncounter_tb.initial.112.0() -> (%reset, %up_down) : () -> (!llhd.sig<i1>, !llhd.sig<i1>)
}
LLHD仿真器llhd-sim
使用
llhd-sim
实现基于LLHD IR的电路仿真,最开始是采用rust编写的应用:https://github.com/fabianschuiki/llhd;目前合入到了CIRCT项目中,但是CIRCT中的llhd-sim
输出格式为自定义格式,需要自己写脚本转换为VCD格式后才能用GTKWave查看。
对于Rust编写的llhd-sim
,在使用moore
编译verilog代码时需要将输出格式指定为llhd。然后执行仿真操作:
./llhd-sim ../udcounter.llhd -N 100 -o udcounter.vcd
上述-N
参数指定仿真执行多少步。此时,输出的vcd文件可以用gtkwave查看仿真波形:
gtkwave ./udcounter.vcd
仿真波形如图,电路在reset信号清零后,按照逻辑描述随着时钟信号增加计数:
对于CIRCT中的llhd-sim
,使用moore
:
./bin/llhd-sim ./udcounter.mlir -r updowncounter_tb -n 100 -o ./udcounter.sim
这里的-r
参数指定仿真的root模块,-n参数指定仿真执行多少步。此时得到的仿真结果是llhd自己定义的格式,并不是标准的vcd格式,需要自己编写脚本进行一下格式转换。