一生一芯学习记录(一):简单介绍 + 建立Verilator仿真环境

一开始先来简单讲述下我的个人情况,研一在读,目前C阶段结束,然后想简单记录一下做一生一芯中遇到的困难和想法,以便后人学习。我学习的版本是2306的版本,所以2407我就不做了,2407据说是给大一或者更小年纪的人平滑的学习一生一芯所用的版本,简单看了看,感觉对于时间紧张的研究生来说有点没必要。我并不会Markdown,所以可能博客写的会很丑,后面慢慢学应该会好看点,前面先别喷我😭。本人的github主页:https://github.com/yuweijie-20030124/ysyx-workbench

所用的系统:Windows10上使用WSL2的Ubuntu22.04,并且用vscode进行远程连接。

预学习阶段其实当时还是过了很久的,可能也得将近一年吧,然后完成C也用了两个月,所以之前东西可能忘了,多多包涵。

  • 如何科学的提问:这个其实就是告诉你如何高效的寻求他人帮助,很简单,这里不再赘述。

  • Linux系统安装和使用:对于linux初学者和并不想那么折腾的人来说,我的建议是使用Ubuntu,下载东西直接用sudo apt install下载即可,只要找到合适的源。所以现在选择要么就是虚拟机,要么就是wsl,我的选择是wsl,可以根据你电脑的内存大小来进行选择。我电脑只有512G,之前使用过Linux,所以选择了wsl,wsl的优点就是运行速度快,缺点就是没有图形化界面。虚拟机优点就是有图形化界面,缺点就是内存占比会比较大,运行速度会慢一点,但是对于现代电脑来说也不会慢到哪里去了,看你电脑内存吧。

  • C语言:纯看教程,这个我觉得还挺重要的,因为后面nemu和C阶段都会涉及大量的C语言知识,你看不懂nemu如何运行你就写不了NPC了,所以其实还是非常重要。2407有两个章节要求学C,我的建议是没啥必要,没必要吧太多时间花费在C语言上,你可以先去看nemu是如何跑起来,如何执行一条指令的去一边学C一边用C,不会了再去前面看教程,效率会高一点,这里针对的是时间比较短的同学来说,如果你0基础或者大一那我建议你可以老老实实按照他的要求来,你们的时间还好多呢😭。

  • 搭建verilator仿真环境:前期就是简单写一个让你仿真与门的一个建议testbench,等到C阶段,你自己写出你的RTL代码后要把这个RTL代码放到你类似NEMU的仿真环境下去跑,此时verilator就很重要了,会大量使用DPI-C功能,等你C就知道了,这里不赘述,总之预学习会先告诉你需要学什么,后面慢慢学精通就可以完成任务了。

来简单讲述下Verilator,首先我们来看官方手册的定义:
官方手册连接:https://verilator.org/guide/latest/overview.html

The Verilator package converts Verilog 1 and SystemVerilog 2 hardware description language (HDL) designs into a C++ or SystemC model that, after compiling, can be executed. Verilator is not a traditional simulator but a compiler.

翻译过来就是会将硬件描述语言转换为C++或者SystemC语言,编译之后会生成可执行文件,以此来达到仿真的行为,由此可见他是一个编译器,而非模拟器。

运行示例:照抄这里的C++ Example即可
image

仿真代码:

点击查看代码
#include "Vour.h"
#include "verilated.h"
int main(int argc, char** argv) {
    VerilatedContext* contextp = new VerilatedContext;
    contextp->commandArgs(argc, argv);
    Vour* top = new Vour{contextp};
    while (!contextp->gotFinish()) { top->eval(); }
    delete top;
    delete contextp;
    return 0;
}

.V文件代码:

点击查看代码
  module our;
     initial begin $display("Hello World"); $finish; end
  endmodule

别忘了更新环境变量

之后输入
verilator --cc --exe --build -j 0 -Wall sim_main.cpp our.v

上述操作没错的话就会生成一个build文件,其中会有一个可执行文件,运行它就会打印hello world出来。

示例: 双控开关

仿真文件

点击查看代码
#include <assert.h> //下面要用到assert
#include <stdio.h>  
#include <stdlib.h>
#include "Vtop.h"   //包含top模块的顶层类
#include <verilated.h> 
#include <verilated_vcd_c.h> //向VCD文件中写入文件

int main(int argc, char** argv) {

    VerilatedContext* contextp = new VerilatedContext;
    contextp->commandArgs(argc, argv);
    contextp->traceEverOn(true);//打开追踪功能
    Vtop* top = new Vtop{contextp};
    VerilatedVcdC *wave = new VerilatedVcdC;
    top->trace(wave,0);
    wave->open("waveform.vcd");
    while (!contextp->gotFinish()) {
        int a = rand() & 1;
        int b = rand() & 1;
        top->a = a;
        top->b = b;
        top->eval();
        printf("a = %d, b = %d, f = %d\n", a, b, top->f);
        assert(top->f == (a ^ b));//验证一下电路正确性,不对的话直接退出
        wave->dump(contextp->time());
        contextp->timeInc(1);//推动仿真时间
      }
    wave->close();
    delete top;
    delete contextp;
    delete wave;
    return 0;
}    

RTL代码

点击查看代码
module top(
  input a,
  input b,
  output f
);

  assign f = a ^ b;//按位异或

endmodule

之后再obj_dir中就会生成一个名为Vtop的可执行文件,可以用./Vtop来执行他,随后会出现这样子的永不结束的仿真输出
image

tips:此时可以用ctrl + c 强行中断程序以达到退出的效果。

此时可以用GTKWAVE命令行输入
gtkwave waveform.vcd
以查看波形文件。
image

重点是

点击查看代码
    while (!contextp->gotFinish()) {
        int a = rand() & 1;
        int b = rand() & 1;
        top->a = a;
        top->b = b;
        top->eval();
        printf("a = %d, b = %d, f = %d\n", a, b, top->f);
        assert(top->f == (a ^ b));//验证一下电路正确性,不对的话直接退出
        wave->dump(contextp->time());
        contextp->timeInc(1);//推动仿真时间
      }
这一串代码,时刻更新电路信息并且打印出来,意思就是给a一个随机数,给b一个随机数,然后把值传递给结构体(verilator所要求),这个`top->eval();`是更新一下电路的状态,然后就打印出去,并且添加波形时间记录波形以方便我们后边看波形。

编写Makefile

点击查看代码
clean:
	rm -r obj_dir

sim:		
	verilator -Wall  --cc --trace --exe --build sim_main.cpp top.v

all:
	verilator -Wall  --cc --trace --exe --build sim_main.cpp top.v
	gtkwave obj_dir/waveform.vcd

非常简单。

接入NVBoard
直接复制粘贴他的example过来,然后修改一下仿真环境和管脚约束和.v文件即可算是接入NVBoard了。具体步骤如下:
修改仿真环境

点击查看代码
#include <nvboard.h>
#include <Vtop.h>
 
static TOP_NAME dut;
 
void nvboard_bind_all_pins(TOP_NAME* top);
 
int main() {
  nvboard_bind_all_pins(&dut);
  nvboard_init();
 
  while(1) {
    nvboard_update();
    dut.eval(); 
  }
}

修改RTL

点击查看代码
module top(
  input clk,
  input rst,
  input [1:0] sw,
  output reg  led
);

always @(*) begin
        led = sw[0] ^ sw[1]; // 按位异或
    end

endmodule

修改管脚约束

点击查看代码
top=top

led (LD0)
sw (SW1, SW0)

然后make run就可以开启NVBoard,拨动最后两个拨码开关看实验结果了。
image

实例:流水灯
和前面一样直接复制nvboard的example文件然后改三个地方:①RTL ②仿真 ③管脚约束
①RTL

点击查看代码
module top(
  input clk,
  input rst,
  output reg [15:0] led
);
  reg [31:0] count;
  always @(posedge clk) begin
    if (rst) begin led <= 1; count <= 0; end
    else begin
      if (count == 0) led <= {led[14:0], led[15]};
      count <= (count >= 5000000 ? 32'b0 : count + 1);
    end
  end
endmodule

②仿真

点击查看代码
#include <nvboard.h>
#include <Vtop.h>

static TOP_NAME dut;

void nvboard_bind_all_pins(TOP_NAME* top);

static void single_cycle() {
  dut.clk = 0; dut.eval();
  dut.clk = 1; dut.eval();
}

static void reset(int n) {
  dut.rst = 1;
  while (n -- > 0) single_cycle();
  dut.rst = 0;
}

int main() {
  nvboard_bind_all_pins(&dut);
  nvboard_init();

  reset(10);

  while(1) {
    nvboard_update();
    single_cycle();
  }
}

③管脚约束

点击查看代码
top=top

led (LD15, LD14, LD13, LD12, LD11, LD10, LD9, LD8, LD7, LD6, LD5, LD4, LD3, LD2, LD1, LD0)

rst BTNL

此时命令行输入make run即可查看流水灯现象。

更多Verilator学习可以使用这个网站https://www.itsembedded.com/,上面很多例程。

一些思考题和个人感想

1. 思考题

不知道NVBoard如何工作

阅读verilator编译出的C++代码, 然后结合verilog代码, 尝试理解仿真器进行仿真的时候都发生了什么.

理解RTL仿真的行为

试试从make命令开始, 看看一切是如何发生的. 通过前面的学习, 你已经掌握了足够的知识背景去理解NVBoard如何工作了: 包括Makefile的使用, C语言和C++中类的基本用法. 现在就试试阅读代码(Makefile也是代码), 看看示例中的verilog顶层端口, 约束文件, 以及NVBoard是如何建立联系的.

要求我们看NVboard和Verilator如何工作的,后面各出一片关于NVBoard的和Verilator的教程,写完了把链接放在这里。

verilator进阶学习
链接(还没写)

2. 个人思考
Verilator在C阶段中起到很重要的作用,预学习阶段的后续阶段中我们通过PA了解到了NEMU是如何运行的,此时我们可以在npc文件夹中写一个类似nemu的仿真环境,然后用Verilator将自己写的RTL代码编译成C++,将nemu取指,译码,执行,访存,回写的操作仿真我们自己的处理器中,其余操作仿真仿真环境中,那我们就可以在仿真环境中存储指令,通过Verilator中DPI-C的特性将指令进行取指,译码,执行,访存,回写等操作,从而在NPC上”跑起来“。
而NVBoard,虽然我还没到B阶段,但是我从周围已经完成B阶段的人看到他们后续要将NPC接入SoC中要用到NVBoard。
因此了解verilator和nvboard是如何运行的也十分重要。

posted on 2025-09-02 17:04  yuweijie0124  阅读(202)  评论(0)    收藏  举报