CIRCT-LLHD仿真计数器电路

2021-12-09 13:58:23 浏览数 (1)

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代码:

代码语言:javascript复制
./moore -f mlir -e updowncounter_tb -o udcounter.mlir counter_ud_tb.v counter_ud.v

其中-f参数指定输出的格式,可选项有mlir|llhdllhd是使用rust编写的仿真器llhd-sim支持的格式,mlir是继承到CIRCT中的仿真器支持的格式;-e参数指定顶层模块名,上文中testbench中顶层模块名为updowncounter_tb-o参数指定输出文件名;其余参数被当作输入文件。

moore编译器会将verilog代码转换为SSA(静态单赋值)形式的LLHD IR表示;这里以mlir格式为例,截取综合出来的部分IR代码:

代码语言:javascript复制
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。然后执行仿真操作:

代码语言:javascript复制
./llhd-sim ../udcounter.llhd -N 100 -o udcounter.vcd

上述-N参数指定仿真执行多少步。此时,输出的vcd文件可以用gtkwave查看仿真波形:

代码语言:javascript复制
gtkwave ./udcounter.vcd

仿真波形如图,电路在reset信号清零后,按照逻辑描述随着时钟信号增加计数:

对于CIRCT中的llhd-sim,使用moore:

代码语言:javascript复制
./bin/llhd-sim ./udcounter.mlir -r updowncounter_tb -n 100 -o ./udcounter.sim

这里的-r参数指定仿真的root模块,-n参数指定仿真执行多少步。此时得到的仿真结果是llhd自己定义的格式,并不是标准的vcd格式,需要自己编写脚本进行一下格式转换。

0 人点赞