记录一下学习仿真文件的vlog
仿真是FPGA开发的重要环节,帮助我们正式下载数据流之前发现问题。仿真文件的编写尤为重要,这篇博客就聊聊关于仿真文件的基本写法。
同样,先瞟一眼我上篇博客中点亮led.v的仿真文件(想看上篇博客的欢迎拖到文章底部的超链接~~~)
cpp
`timescale 1ns / 1ns //仿真单位/仿真精度
module tb_led();
reg key;
wire led;
//信号初始化
initial begin
key <= 1'b1; //按键上电默认高电平
//key信号变化
#200 //延迟200ns
key <= 1'b1; //按键没有被按下
#1000
key <= 1'b0; //按键被按下
#600
key <= 1'b1;
#1000
key <= 1'b0;
end
//例化led模块
led u_led(
.key (key),
.led (led)
);
endmodule
注释倒是写的挺详细的 看了跟没看一样 啥也看不懂!!!
看不懂没关系~ 且听我细细道来!
看着挺多,不过仿真文件只有两部分组成:
- 时间尺度指令(Time Scale Directive)
- 仿真模块(Testbench)
你没发现整个程序除了`timescale 1ns / 1ns(时间尺度指令)就一个module tb_led()模块吗?
再次体现Verilog的模块化编程模式:连仿真文件都得写成模块的形式。
确实,不过......tb_led里面都是坨啥??
别急,先说说时间尺度指令。
时间尺度指令
其语法结构如下:
cpp
`timescale <时间单位> / <时间精度>
尤其需要注意的是最前面的标点符号,不是单引号'
这玩意在哪找捏?按键如下:
这个
尤其注意!!
时间单位是之后写的仿真延时的单位,比如这个:
cpp
`timescale 1ns/1ns
......
key <= 1'b1;
#100
key <= 1'b0
就代表key <= 1'b1 和key <= 1'b0 之间间隔100ns(仿真时候的,跟真实硬件没关系)
如果写成这个样子:
cpp
`timescale 10ns/1ns
......
key <= 1'b1;
#100 //就代表1000ns了
key <= 1'b0
key <= 1'b1 和key <= 1'b0之间就间隔1000ns了。
"/"后面的是时间精度,比如这样写:
cpp
`timescale 1ns/1ps //时间精度改成ps
......
key <= 1'b1;
#1.001
key <= 1'b0
但这样就不行了:
cpp
`timescale 1ns/1ns //时间精度改回ns
......
key <= 1'b1;
#1.001 //错误,因为时间精度最小就是ns,无法再精确了!
key <= 1'b0
仿真模块的编写
最重要的仿真模块来啦!
仿真模块里的主要三部分:
- 信号类型定义
- 信号初始化
- 模块例化
要讲Verilog的信号类型,就不得不说说Verilog的数据类型了。
类比C++的int、long、char、string.etc(中英夹杂~),Verilog中数据类型主要以下三种:
Verilog的数据类型 | 作用 |
---|---|
reg | 寄存器类型 |
wire | 线网类型 |
parameter | 参数类型 |
说白了reg对应FPGA里的D触发器和寄存器(触发器级联),wire用来连接查找表和触发器(或者别的什么)。
区别在于:reg可以存储数据,而wire不能
但wire可以承载数据
注意"承载"和"存储"不是一个意思 (你品,你仔细品~)
那参数是干啥的?答:存个常量。
个人理解,作用类似与嵌入式开发的宏定义。(就是给数字起个字母的名字)
举个栗子:
cpp
parameter COUNT_MAX = 25_000_000; //但这是常量不能运算
相信聪明的你一眼就明白了。
通常,我们会把输入信号(比如点亮led中的key)定义为寄存器类型reg,输出信号(比如led)定义为线网类型wire。
信号初始化
这里介绍一个新语句initial。
再介绍两个关键字begin和end。
后面这俩完全等于C++的花括号"{}"。至于为啥Verilog不用花括号啊,咱也不知道,咱也不敢问......
如果后面只有一行,则不用写begin和end。
cpp
initial
key = 1'b0; //虽然对于intial啥用没有
多了就得写:
cpp
initial begin
key = 1'b0;
#100
key = 1'b1;
#100
key = 1'b0;
end
begin不一定要和initial写在一行,不过业界都这么写,咱也随波逐流吧哈哈~
中间的#100是延时语句,语法就是一个#再加一个数字。
注意initial语句只用在仿真文件,不用于RTL代码!!一定注意!!
模块例化
有个博主方法很好(是谁就不说了),打开RTL代码(就点亮led的代码),把下面这个模块:
cpp
module led(
input key,
output led
);
从led开始,到;结束,复制然后粘贴到仿真文件,删掉端口类型,最后长成这个德行:
cpp
led(
key,
led
);
给例化模块起个名字(我习惯加"u_"跟原子哥学的哈哈 ),每个端口前加点".",后面加括号:
cpp
led u_led(
.key(),
.led()
);
里面写要连接的线(名称可以重复,我一般喜欢重复):
cpp
led u_led(
.key(key),
.led(key)
);
就搞定啦!
我个人喜欢用Modelsim这个仿真软件,仿真波形如下:
期待我和大家早日一同学会Verilog和FPGA!!
如果有不明白或错误之处,也希望大家在评论区给出,帮助大家的同时也能再次提升自己对于FPGA和Verilog的理解,感谢大家!!
系列链接: