[TOC]
## 前言
` `在linux下做FPGA开发验证模块功能时我们需要仿真,但是我们使用IDE工具会拉低效率,因为无论是quartus还是xilinx的开发工具,其设计本来就比较全面,运行的时候有很多东西都在运行,如果我们只需要仿真一个简单的模块,有可能整套走下来需要几分钟,源文件更改后再次仿真又要耗时几分钟,因此会影响我们的效率。
` `这个时候我们可以使用iverilog这块轻量级的综合工具来做好这个工作,搭建好环境后反复调试将会很节约时间。
## 准备工作
` `首先我们需要安装必要的工具。我的环境是deepin15.11。
* 安装iverilog
```
sudo apt-get install iverilog
```
* 安装查看波形的工具GTKwave
```
sudo apt-get install gtkwave
```
` `linux下的verilog编辑器推荐使用**VS Code**,VS Code是一款非常好用的编辑器,基本各种语言使用中都可以得到很好的体验。一款编辑器,搞定linux下大部分开发。注意要支持verilog语法,请到VSCode的插件中搜索verilog然后选择一款进行安装。
![](https://img.kancloud.cn/a3/f3/a3f35242e2a051b8ee61a327e56c8c60_902x528.png)
![](https://img.kancloud.cn/22/34/223400bdb79160dc5a47e9f629744773_499x428.png)
## 基本参数说明
Icarus Verilog编译器主要包含3个工具:
* iverilog:用于编译verilog和vhdl文件,进行语法检查,生成可执行文件
* vvp:根据可执行文件,生成仿真波形文件
* gtkwave:用于打开仿真波形文件,图形化显示波形
在终端输入`iverilog`回车,可以看到常用参数使用方法的简单介绍:
![](https://img.kancloud.cn/91/f3/91f32daaf4d930f04f0981211aec6ddc_721x360.png)
### 参数 -o
` `这是比较常用的一个参数了,和GCC中-o的使用几乎一样,用于指定生成文件的名称。如果不指定,默认生成文件名为a.out。如:`iverilog -o test test.v`。
### 参数 -y
` `用于指定包含文件夹,如果top.v中调用了其他的的.v模块,top.v直接编译会提示
~~~
led_demo_tb.v:38: error: Unknown module type: led_demo
2 error(s) during elaboration.
*** These modules were missing:
led_demo referenced 1 times.
***
~~~
` `找不到调用的模块,那么就需要指定调用模块所在文件夹的路径,支持相对路径和绝对路径。
` `如:`iverilog -y D:/test/demo led_demo_tb.v`
` `如果是同一目录下:`iverilog -y ./ led_demo_tb.v`,另外,iverilog还支持Xilinx、Altera、Lattice等FPGA厂商的仿真库,需要在编译时通过-y参数指定库文件的路径,详细的使用方法可以查看官方用户指南:
[https://iverilog.fandom.com/wiki/User\_Guide](https://iverilog.fandom.com/wiki/User_Guide)
### 参数-I
` `如果程序使用`include语句包含了头文件路径,可以通过-i参数指定文件路径,使用方法和-y参数一样。
` `如:`iverilog -I D:/test/demo led_demo_tb.v`
### 参数-tvhdl
` `verilog还支持把verilog文件转换为VHDL文件,如`iverilog -tvhdl -o out_file.vhd in_file.v`
## 仿真流程
### 综合
` `通过`iverilog -o tb tp_counter.v counter.v`命令,对源文件和仿真文件,进行语法规则检查和编译。由于本示例比较简单,只有1个文件,如果调用了多个.v的模块,可以通过前面介绍的-y参数指定源文件的路径,否则编译报错。如果源文件都在同同一个目录,可以直接通过`./`绝对路径的方式来指定。
` `如果编译成功,会在当前目录下生成名称为tb的文件。
![](https://img.kancloud.cn/c6/4b/c64bc664714caf763f84dc08551b1d29_773x482.png)
### 生成波形文件
` `使用`vvp -n tb -lxt2`命令生成lxt波形文件,运行之后,会在当前目录下生成.lxt文件。
![](https://img.kancloud.cn/5a/fa/5afa5ad43f464194793cb8fb3d95d7db_813x84.png)
` `如果没有生成,需要检查testbench文件中是否添加了如下几行:
```
initial begin
$dumpfile("tb.lxt");
$dumpvars(0, counter);
end
```
### 使用GTKwav查看波形
` `使用命令`gtkwave tb.lxt`,可以在图形化界面中查看仿真的波形图
![](https://wcc-blog.oss-cn-beijing.aliyuncs.com/img/iverilog/gtkwave.gif)
![](https://img.kancloud.cn/de/5c/de5cc1956e77bfc68c7ecceb87f60251_1022x635.png)
![](https://img.kancloud.cn/8a/69/8a690087655457a9e7fe2f0df9e35580_1184x497.png)
verilog转换为VHDL
` `虽然VHDL和Verilog都诞生于20世纪80年代,而且都属于硬件描述语言(HDL),但是二者的语法特性却不一样。Icarus Verilog 还有一个小功能就是支持把使用Verilog语言编写的.v文件转换为VHDL语言的.vhd文件。
` `如把led_demo.v文件转换为VHDL文件led_demo.vhd,使用命令`iverilog -tvhdl -o led_demo.vhd led_demo.v`。
### VHDL文件编译和仿真
` `如果你还和编译Verilog一样,使用`iverilog led_dmeo.v`来编译VHDL文件的话,那么会提示有语法错误,这是正常的,因为Verilog和VHDL是不同的语法规则,不能使用Verilog的标准来检查VHDL文件的语法。需要添加`-g2012`参数来对VHDL文件进行编译,如`iverilog -g2012 led_demo.vhd`,和Verilog一样,同样也支持Testbech文件的编译和仿真,当然需要编写对应的VHDL Testbench文件。
## 搭建工程
` `开始搭建工程,首先新建一个文件夹,并在VS Code中打开该文件夹。
* step1:建立verilog模块文件“counter.v”
```
`timescale 1ns/1ps
module counter(
input clk,
input rst_n,
output reg [4:0] ocnt
);
always@(posedge clk or negedge rst_n)
if (!rst_n) begin
ocnt <= 5'd0;
end
else ocnt <= ocnt + 5'd1;
endmodule
```
* step2:建立testbech文件"top_counter.v"
```
//`include "counter.v"
`timescale 1ns/1ps
module tp_counter;
reg clk;
reg rst_n;
wire [4:0]od;
counter counter
(
.rst_n (rst_n),
.clk (clk),
.ocnt(od)
);
localparam CLK_PERIOD = 2;
always #(CLK_PERIOD/2) clk=~clk;
initial begin
$dumpfile("tb.lxt"); //生成lxt的文件名称
$dumpvars(0, counter); //tb中实例化的仿真目标实例名称
end
initial begin
#1 rst_n<=1'bx;clk<=1'bx;
#(CLK_PERIOD*3) rst_n<=1;
#(CLK_PERIOD*3) rst_n<=0;clk<=0;
repeat(5) @(posedge clk);
rst_n<=1;
repeat(64) @(posedge clk);
$dumpflush;
$stop;
end
endmodule
```
` `注意testbench文件中有几行iverilog编译器专用的语句,如果不加的话后面不能生成lxt文件。
```
initial begin
$dumpfile("tb.lxt"); //生成lxt的文件名称
$dumpvars(0, counter); //tb中实例化的仿真目标实例名称
end
```
* step3:编写makefile文件
` `采用makefile的方式,可以在我么第一次搭建好工程之后,之后进行综合的时候方便一些。我们可以使用`make`命令就能进行综合仿真,一步到位。
` `该工程的makefile文件如下:
```
tb: tp_counter.v counter.v
iverilog -o tb tp_counter.v counter.v
vvp -n tb -lxt2
clean:
rm -rf tb tb.lxt2
```
* step4:编写运行脚本“run.sh”,方便直接查看波形
```
#!/bin/bash
make
gtkwave tb.lxt
```
` `为脚本添加运行权限
```
chmod +x tb.lxt
```
* step5:开始仿真
` `上述文件都准备好后,我们可以使用`make`命令来综合工程并生成波形文件,若出现错误,在终端将会有相应的提示。
` `没有错误后,在终端输入`./run.sh`将会再次进行综合一次,并在gtkwave中打开波形文件。然后就可以使用上面查看波形的方法查看信号。
## $dumpfile() $ dumpvars()的用法
` `$dumpfile和$dumpvar是verilog语言中的两个系统任务,可以调用这两个系统任务来创建和将指定信息导入VCD文件. (什么是VCD文件? 答:VCD文件是在对设计进行的仿真过程中,记录各种信号取值变化情况的信息记录文件。EDA工具通过读取VCD格式的文件,显示图形化的仿真波形,所以,可以把VCD文件简单地视为波形记录文件.)下面分别描述它们的用法并举例说明之。
` `$dumpfile系统任务:为所要创建的VCD文件指定文件名。
` `举例("//"符号后的内容为注释文字):
```
initial
$dumpfile ("myfile.dump"); //指定VCD文件的名字为myfile.dump,仿真信息将记录到此文件
```
` `$dumpvar系统任务:指定需要记录到VCD文件中的信号,可以指定某一模块层次上的所有信号,也可以单独指定某一个信号。
` `典型语法为$dumpvar(level, module\_name); 参数level为一个整数,用于指定层次数,参数module则指定要记录的模块。整句的意思就是,对于指定的模块,包括其下各个层次(层次数由level指定)的信号,都需要记录到VCD文件中去。
```verilog
举例:
initial
$dumpvar (0, top); //指定层次数为0,则top模块及其下面各层次的所有信号将被记录
initial
$dumpvar (1, top); //记录模块实例top以下一层的信号
//层次数为1,即记录top模块这一层次的信号
//对于top模块中调用的更深层次的模块实例,则不记录其信号变化
initial
$dumpvar (2, top); //记录模块实例top以下两层的信号
//即top模块及其下一层的信号将被记录
```
` `假设模块top中包含有子模块module1,而我们希望记录top.module1模块以下两层的信号,则语法举例如下:
```
initial
$dumpvar (2, top.module1); //模块实例top.module1及其下一层的信号将被记录
```
` `假设模块top包含信号signal1和signal2(注意是变量而不是子模块), 如我们希望只记录这两个信号,则语法举例如下:
```
initial
$dumpvar (0, top.signal1, top.signal2); //虽然指定了层次数,但层次数是不影响单独指定的信号的
//即指定层次数和单独指定的信号无关
```
` `我们甚至可以在同一个$dumpvar的调用中,同时指定某些层次上的所有信号和某个单独的信号,假设模块top包含信号signal1,同时包含有子模块module1,如果我们不但希望记录signal1这个独立的信号,而且还希望记录子模块module1以下三层的所有信号,则语法举例如下:
```
initial
$dumpvar (3, top.signal1, top.module1); //指定层次数和单独指定的信号无关
//所以层次数3只作用于模块top.module1, 而与信号
top.signal1无关
```
` `上面这个例子和下面的语句是等效的:
```
initial
begin
$dumpvar (0, top.signal1);
$dumpvar (3, top.module1);
end
$dumpvar的特别用法(不带任何参数):
initial
$dumpvar; //无参数,表示设计中的所有信号都将被记录
```
> 最后,我们将$dumpfile和$dumpvar这两个系统任务的使用方法在下面的例子中综合说明,假设我们有一个设计实例,名为i\_design,此设计中包含模块module1,模块module1下面还有很多层次,我们希望对这个设计进行仿真,并将仿真过程中模块module1及其以下所有层次中所有信号的变化情况,记录存储到名为mydesign.dump的VCD文件中去,则例示如下:
initial
begin
` `$dumpfile ("mydesign.dump"); //指定VCD文件名为mydesign.dump
` `$dumpvar (0, i_design.module1); //记录i_design.module1模块及其下面层次中所有模块的所有信号
end
最后提供一个iverilog搭建好的模板:https://gitee.com/yuan_hp/iverilog_template.git
- 序
- 第1章 Linux下开发FPGA
- 1.1 Linux下安装diamond
- 1.2 使用轻量级linux仿真工具iverilog
- 1.3 使用linux shell来读写串口
- 1.4 嵌入式上的linux
- 设备数教程
- linux C 标准库文档
- linux 网络编程
- 开机启动流程
- 1.5 linux上实现与树莓派,FPGA等通信的串口脚本
- 第2章 Intel FPGA的使用
- 2.1 特别注意
- 2.2 高级应用开发流程
- 2.2.1 生成二进制bit流rbf
- 2.2.2 制作Preloader Image
- 2.2.2.1 生成BSP文件
- 2.2.2.2 编译preloader和uboot
- 2.2.2.3 更新SD的preloader和uboot
- 2.3 HPS使用
- 2.3.1 通过JTAG下载代码
- 2.3.2 HPS软件部分开发
- 2.3 quartus中IP核的使用
- 2.3.1 Intel中RS232串口IP的使用
- 2.4 一些问题的解决方法
- 2.4.1 关于引脚的复用的综合出错
- 第3章 关于C/C++的一些语法
- 3.1 C中数组作为形参不传长度
- 3.2 汇编中JUMP和CALL的区别
- 3.3 c++中map的使用
- 3.4 链表的一些应用
- 3.5 vector的使用
- 3.6 使用C实现一个简单的FIFO
- 3.6.1 循环队列
- 3.7 C语言不定长参数
- 3.8 AD采样计算同频信号的相位差
- 3.9 使用C实现栈
- 3.10 增量式PID
- 第4章 Xilinx的FPGA使用
- 4.1 Alinx使用中的一些问题及解决方法
- 4.1.1 在Genarate Bitstream时提示没有name.tcl
- 4.1.2 利用verilog求位宽
- 4.1.3 vivado中AXI写DDR说明
- 4.1.4 zynq中AXI GPIO中断问题
- 4.1.5 关于时序约束
- 4.1.6 zynq的PS端利用串口接收电脑的数据
- 4.1.7 SDK启动出错的解决方法
- 4.1.8 让工具综合是不优化某一模块的方法
- 4.1.9 固化程序(双核)
- 4.1.10 分配引脚时的问题
- 4.1.11 vivado仿真时相对文件路径的问题
- 4.2 GCC使用Attribute分配空间给变量
- 4.3 关于Zynq的DDR写入byte和word的方法
- 4.4 常用模块
- 4.4.1 I2S接收串转并
- 4.5 时钟约束
- 4.5.1 时钟约束
- 4.6 VIVADO使用
- 4.6.1 使用vivado进行仿真
- 4.7 关于PicoBlaze软核的使用
- 4.8 vivado一些IP的使用
- 4.8.1 float-point浮点单元的使用
- 4.10 zynq的双核中断
- 第5章 FPGA的那些好用的工具
- 5.1 iverilog
- 5.2 Arduino串口绘图器工具
- 5.3 LabVIEW
- 5.4 FPGA开发实用小工具
- 5.5 Linux下绘制时序图软件
- 5.6 verilog和VHDL相互转换工具
- 5.7 linux下搭建轻量易用的verilog仿真环境
- 5.8 VCS仿真verilog并查看波形
- 5.9 Verilog开源的综合工具-Yosys
- 5.10 sublim text3编辑器配置verilog编辑环境
- 5.11 在线工具
- 真值表 -> 逻辑表达式
- 5.12 Modelsim使用命令仿真
- 5.13 使用TCL实现的个人仿真脚本
- 5.14 在cygwin下使用命令行下载arduino代码到开发板
- 5.15 STM32开发
- 5.15.1 安装Atollic TrueSTUDIO for STM32
- 5.15.2 LED闪烁吧
- 5.15.3 模拟U盘
- 第6章 底层实现
- 6.1 硬件实现加法的流程
- 6.2 硬件实现乘法器
- 6.3 UART实现
- 6.3.1 通用串口发送模块
- 6.4 二进制数转BCD码
- 6.5 基本开源资源
- 6.5.1 深度资源
- 6.5.2 FreeCore资源集合
- 第7章 常用模块
- 7.1 温湿度传感器DHT11的verilog驱动
- 7.2 DAC7631驱动(verilog)
- 7.3 按键消抖
- 7.4 小脚丫数码管显示
- 7.5 verilog实现任意人数表决器
- 7.6 基本模块head.v
- 7.7 四相八拍步进电机驱动
- 7.8 单片机部分
- 7.8.1 I2C OLED驱动
- 第8章 verilog 扫盲区
- 8.1 时序电路中数据的读写
- 8.2 从RTL角度来看verilog中=和<=的区别
- 8.3 case和casez的区别
- 8.4 关于参数的传递与读取(paramter)
- 8.5 关于符号优先级
- 第9章 verilog中的一些语法使用
- 9.1 可综合的repeat
- 第10章 system verilog
- 10.1 简介
- 10.2 推荐demo学习网址
- 10.3 VCS在linux上环境的搭建
- 10.4 deepin15.11(linux)下搭建system verilog的vcs仿真环境
- 10.5 linux上使用vcs写的脚本仿真管理
- 10.6 system verilog基本语法
- 10.6.1 数据类型
- 10.6.2 枚举与字符串
- 第11章 tcl/tk的使用
- 11.1 使用Tcl/Tk
- 11.2 tcl基本语法教程
- 11.3 Tk的基本语法
- 11.3.1 建立按钮
- 11.3.2 复选框
- 11.3.3 单选框
- 11.3.4 标签
- 11.3.5 建立信息
- 11.3.6 建立输入框
- 11.3.7 旋转框
- 11.3.8 框架
- 11.3.9 标签框架
- 11.3.10 将窗口小部件分配到框架/标签框架
- 11.3.11 建立新的上层窗口
- 11.3.12 建立菜单
- 11.3.13 上层窗口建立菜单
- 11.3.14 建立滚动条
- 11.4 窗口管理器
- 11.5 一些学习的脚本
- 11.6 一些常用的操作语法实现
- 11.6.1 删除同一后缀的文件
- 11.7 在Lattice的Diamond中使用tcl
- 第12章 FPGA的重要知识
- 12.1 面积与速度的平衡与互换
- 12.2 硬件原则
- 12.3 系统原则
- 12.4 同步设计原则
- 12.5 乒乓操作
- 12.6 串并转换设计技巧
- 12.7 流水线操作设计思想
- 12.8 数据接口的同步方法
- 第13章 小项目
- 13.1 数字滤波器
- 13.2 FIFO
- 13.3 一个精简的CPU( mini-mcu )
- 13.3.1 基本功能实现
- 13.3.2 中断添加
- 13.3.3 使用中断实现流水灯(实际硬件验证)
- 13.3.4 综合一点的应用示例
- 13.4.5 使用flex开发汇编编译器
- 13.4.5 linux--Flex and Bison
- 13.4 有符号数转单精度浮点数
- 13.5 串口调试FPGA模板