【Verilator】 1 简明教程

这篇具有很好参考价值的文章主要介绍了【Verilator】 1 简明教程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

我是 雪天鱼,一名FPGA爱好者,研究方向是FPGA架构探索和数字IC设计。

欢迎来关注我的B站账号,我将定期更新IC设计教程。
B站账号:雪天鱼,https://space.bilibili.com/397002941?spm_id_from=333.1007.0.0

1 准备工作

先从GitHub下载实验代码

git clone https://github.com/n-kremeris/verilator_basics
git checkout verilator_pt1

2 我们的DUT

以一个用SystemVerilog编写的简单ALU来作为DUT(device under test)来学习Verilator是如何工作的。下面是ALU的源码:

/****** alu.sv ******/
typedef enum logic [1:0] {
     add     = 2'h1,
     sub     = 2'h2,
     nop     = 2'h0
} operation_t /*verilator public*/;

module alu #(
        parameter WIDTH = 6
) (
        input clk,
        input rst,

        input  operation_t  op_in,
        input  [WIDTH-1:0]  a_in,
        input  [WIDTH-1:0]  b_in,
        input               in_valid,

        output logic [WIDTH-1:0]  out,
        output logic              out_valid
);

        operation_t  op_in_r;
        logic  [WIDTH-1:0]  a_in_r;
        logic  [WIDTH-1:0]  b_in_r;
        logic               in_valid_r;
        logic  [WIDTH-1:0]  result;

        // Register all inputs
        always_ff @ (posedge clk, posedge rst) begin
                if (rst) begin
                        op_in_r     <= '0;
                        a_in_r      <= '0;
                        b_in_r      <= '0;
                        in_valid_r  <= '0;
                end else begin
                        op_in_r    <= op_in;
                        a_in_r     <= a_in;
                        b_in_r     <= b_in;
                        in_valid_r <= in_valid;
                end
        end

        // Compute the result
        always_comb begin
                result = '0;
                if (in_valid_r) begin
                        case (op_in_r)
                                add: result = a_in_r + b_in_r;
                                sub: result = a_in_r + (~b_in_r+1'b1);
                                default: result = '0;
                        endcase
                end
        end

        // Register outputs
        always_ff @ (posedge clk, posedge rst) begin
                if (rst) begin
                        out       <= '0;
                        out_valid <= '0;
                end else begin
                        out       <= result;
                        out_valid <= in_valid_r;
                end
        end

endmodule;

创建一个工作目录,并将上述代码保存为alu.sv.
这个ALU非常简单。只支持两种操作:加法和减法。操作经过两个周期计算出最终结果,下面是期望波形:

verilator教程,FPGA应用开发,fpga开发,Verilator,simulation

3 将 SystemVerilog 转换为 C++

由于Verilator要求C++ testbench 被编译成本地系统二进制。然而,我们不能将SystemVerilog编写的 ALU添加进C++ testbench:我们首先需要使用 Verilator 将 SystemVerilog 代码转换为C++,或者说 "Verilate",执行一行代码即可:

 verilator --cc alu.sv

verilator教程,FPGA应用开发,fpga开发,Verilator,simulation

通过执行该指令,会生成一个名为 obj_dir的子目录,里面是转换所生成的文件:

verilator教程,FPGA应用开发,fpga开发,Verilator,simulation

jccao@jccao-vm:~/jccao/files/code/verilator/part1$ ls  obj_dir/
Valu___024root__DepSet_h7172bd91__0.cpp        Valu_classes.mk
Valu___024root__DepSet_h7172bd91__0__Slow.cpp  Valu.cpp
Valu___024root__DepSet_ha59b247d__0.cpp        Valu.h
Valu___024root__DepSet_ha59b247d__0__Slow.cpp  Valu.mk
Valu___024root.h                               Valu__Syms.cpp
Valu___024root__Slow.cpp                       Valu__Syms.h
Valu___024unit__DepSet_h45503383__0__Slow.cpp  Valu__ver.d
Valu___024unit.h                               Valu__verFiles.dat
Valu___024unit__Slow.cpp

这里需要关注的文件有:

  1. Valu.cpp, Valu.h: alu转换后对应的C++实现源文件以及头文件,其中Valu.h 包含了转换后的 "ALU "类定义–也就是我们将在C++ testbench 中作为DUT "实例化 "的东西。
  2. Valu.mk: 用于编译可执行的仿真文件
  3. Valu___024unit.h: 这是 "ALU "类的内部头文件,包含了 operation_t 数据类型定义。

4 简单 testbench 设计

testbench 命名为 tb_alu.cpp,最简单的 testbench 代码如下所示:

#include <stdlib.h>
#include <iostream>
#include <verilated.h>
#include <verilated_vcd_c.h>
#include "Valu.h"
#include "Valu___024unit.h"

#define MAX_SIM_TIME 20  // 仿真总时钟边沿数
vluint64_t sim_time = 0; // 用于计数时钟边沿

int main(int argc, char** argv, char** env) {
    Valu *dut = new Valu; // 例化转换后的 ALU 模块
	  // 接下来的四行代码用于设置波形存储为VCD文件
    Verilated::traceEverOn(true);
    VerilatedVcdC *m_trace = new VerilatedVcdC;  
    dut->trace(m_trace, 5);               
    m_trace->open("waveform.vcd");
	  // 实际进行仿真的代码
    while (sim_time < MAX_SIM_TIME) {
        dut->clk ^= 1; 
        dut->eval();  
        m_trace->dump(sim_time);
        sim_time++; // 更新仿真时间
    }

    m_trace->close();
    delete dut;
    exit(EXIT_SUCCESS);
}
  1. testbench 需要包含 <verilated.h><verilated_vcd_c.h>,这两个头文件在安装好verilator就有了,前者里面包含了常用API,后者包含将波形写入VCD(value change dump)文件的API
  2. 刚说过"Valu.h"包含了 verilated 后 ALU模块的类定义,"Valu___024unit.h"包含 operation_t 数据类型定义,被ALU类所需要,所以需要在Testbench中包含这两个头文件
  3. dut->trace(m_trace, 5);的意思是将 m_trace 传递给 dut,5表示跟踪深度限制在DUT的5级以内,这个5级目前我理解为DUT的子模块层级。
while (sim_time < MAX_SIM_TIME) {
        dut->clk ^= 1;
        dut->eval();
        m_trace->dump(sim_time);
        sim_time++;
    }

该部分是实际启动仿真的代码。

  • dut->clk ^= 1 的意思是 clk 与 1 异或,翻转时钟
  • dut->eval() eval()函数更新电路的状态,可理解为仿真 ALU 模型中的所有信号
  • m_trace->dump(sim_time) 将所有被追踪的信号写入波形中

5 生成仿真执行文件

完成 testbench 编写后,我们需要 build 可执行文件来运行这个仿真。

这是因为 Verilator 不同于 Modelsim 这样的仿真软件,内置仿真器进行仿真,Verilator本身就是只进行转换和编译工作,即verilate, 仿真工作由C++可执行文件完成的,所以我们需要用make编译 testbench得到可执行文件。

testbench 和转换后的HDL编写的模块本质上是一个C++应用程序,它可以在你的计算机上建立和运行。运行编译后的可执行文件就是模拟你的设计,用GNU编译器集(GCC)构建Verilator可执行文件。

现在编译我们的测试文件并进行仿真,此时需要运行 Verilator 并重新生成包含测试用例的 .mk 文件:

$ verilator -Wall --trace -cc alu.sv --exe tb_alu.cpp
  • -Wall 表示开启 C++ 所有警告
  • –trace 表示开启波形跟踪
  • -cc 转换.sv为cpp
  • –exe 根据后面指定的testbench 生成用于仿真的可执行文件

随后我们进行编译:

make -C obj_dir -f Valu.mk Valu
  • -C obj_dir告诉make工作目录为 obj_dir
  • makefile 通过 -f指定
  • 最后的Valu则是 target,也就是编译生成的testbench可执行文件的name

编译成功的话,可以在obj_dir目录下找到 Valu 可执行文件

verilator教程,FPGA应用开发,fpga开发,Verilator,simulation

6 运行 testbench

./obj_dir/Valu 命令执行可执行文件进行仿真,此时会生成波形图 waveform.vcd,我们只需要执行 gtkwave waveform.vcd 即可查看波形图。

verilator教程,FPGA应用开发,fpga开发,Verilator,simulation

至此你已经完成了Verilator的一个基础仿真实验,也对Verilator有了一定的认知。

gtkwave安装:
sudo apt-get install gtkwave

7 问题思考

可以看到我们的仿真没有任何’x’,或未知值。这是因为Verilator是一个双状态的仿真工具,默认情况下,所有的信号都被初始化为0。这对于提高仿真速度来说是有效的,因为2个状态比4个状态要少,但是如果我们想检查我们的复位逻辑工作得如何,就不是很好。我们将在后面进一步探讨这个问题。文章来源地址https://www.toymoban.com/news/detail-786672.html

到了这里,关于【Verilator】 1 简明教程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • HuggingFace简明教程

    视频链接:HuggingFace简明教程,BERT中文模型实战示例.NLP预训练模型,Transformers类库,datasets类库快速入门._哔哩哔哩_bilibili 什么是huggingface?huggingface是一个开源社区,它提供了先进的NLP模型,数据集,以及其他便利的工具。 数据集:Hugging Face – The AI community building the future.  这

    2024年01月25日
    浏览(50)
  • mpack简明教程

    本文先简单介绍MessagePack的基本概念。 然后,介绍一个MessagePack C API - MPack的通常使用。 接着尝试对MPack截断数据的读取。 注:本文完整代码见仓库。 如果你使用过C/C++的json库,那么上手MessagePack是比较容易的。关于C/C++ Json库的使用可见:C++ JSON库的一般使用方法-CSDN博客。

    2024年02月20日
    浏览(53)
  • Husky使用简明教程

    Husky 是一个流行的 Git 钩子工具,用于在不同的 Git 操作(如提交和推送)前自动运行脚本。比如代码格式化、静态检查等。这有助于保持代码库的质量和一致性。本教程将详细介绍 Husky 的原理、使用方式、配置方法以及如何在开发中集成 Husky。 Husky 原理 安装 Husky 配置 Hus

    2024年04月10日
    浏览(50)
  • shell简明教程3函数

    在本章中,您将了解为什么以及何时需要使用函数。 你将学习如何创建函数以及如何使用函数。 我们将讨论变量及其作用域。 学习如何使用参数访问传递给函数的参数。 最后,您还将学习如何使用函数处理退出状态和返回代码。 计算机编程和应用程序开发中有一个概念叫

    2024年02月11日
    浏览(51)
  • Blender骨骼动画简明教程

    Blender 是首选的开源3D动画软件之一。 令人惊讶的是,开始创建简单的角色动画并不需要太多时间。 一旦获得最终的 3D 角色模型,你就可以使用该软件的众多动画功能和工具将其变为现实。 推荐:用 NSDT编辑器 快速搭建可编程3D场景 例如,Blender 的绑定工具将帮助你实现角色

    2024年02月07日
    浏览(52)
  • AI绘画工具简明教程

    官方地址 首先需要邮箱注册,等待邀请(可能需要等待一两天) 能成功登录后会进入这样一个界面 https://app.scenario.com/generators 创建模型 提供的图片集上传的时候得是jpg,还需要裁剪成正方形。批量修改图片在线网站:https://www.birme.net/ 根据图集生成图片 官方网址:https://

    2024年02月11日
    浏览(71)
  • WebGPU开发简明教程【2023】

    WebGPU 是一种全新的现代 API,用于在 Web 应用程序中访问 GPU 的功能。 在 WebGPU 之前,有 WebGL,它提供了 WebGPU 功能的子集。 它启用了新一类丰富的网络内容,开发人员用它构建了令人惊叹的东西。 然而,它基于 2007 年发布的 OpenGL ES 2.0 API,而该 API 又基于更旧的 OpenGL API。

    2024年02月16日
    浏览(48)
  • 电商3D产品渲染简明教程

    3D 渲染让动作电影看起来更酷,让建筑设计变得栩栩如生,现在还可以帮助营销人员推广他们的产品。 从最新的《阿凡达》电影到 Spotify 的上一次营销活动,3D 的应用让一切变得更加美好。 在营销领域,3D 产品渲染可帮助品牌创建产品的高分辨率图像和视频,这些图像和视

    2024年02月13日
    浏览(39)
  • stable diffusion使用简明教程

    controlNet模块使用 上面骨骼图是通过Openpose Editor调整姿势然后send to txt2img到这里的,使用Openpose Edito中姿势生成需要将Openpose Editor指定为none状态。 Preprocessor选项: Preprocessor部分选项使用教程 官方教程链接:Control human pose in Stable Diffusion Stable Diffusion Art (stable-diffusion-art.com) 1.

    2024年02月02日
    浏览(46)
  • 汇编语言简明教程习题答案

    (2)判断题 AX被称为累加器,在8086程序中使用很频繁。(✓) 指令指针IP寄存器属于通用寄存器。(✓) 8086具有8个32位通用寄存器。(×) 解析:8086的寄存器有8个16位通用寄存器、4个16位段寄存器、1个16位标志寄存器和1个16位指令指针寄存器 8086编程使用逻辑地址,将其中

    2023年04月08日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包