目录
一. 实验内容
通过具体例程,学习vivado软件的下述功能: 1.例化:04节fifo核的使用 2.仿真:01节流水灯
二. 例化
2.1 概论
依我看,例化其实就是C语言的函数调用。这样做方便整体代码修改,以及模块化编写程序。咱们就带着函数调用的思想去学习例化的语法规则就好。
2.2 例化框架
例化的大体框架如下:
引用的外部模块名字 此模块的新名字 ( .外部参数1 (对应的内部参数1), .外部参数2 (对应的内部参数2), .外部参数3 (对应的内部参数3), .外部参数4 (对应的内部参数4), ...... ...... .外部参数n (对应的内部参数n) //注意:最后一个参数的括号后面没有逗号 );
这是fifo核的例化。
fifo_generator_0 u_fifo_generator_0 ( .clk (clk), .srst (~rst_n), .din (wr_data), .wr_en (wr_en), .rd_en (rd_en), .dout (rd_data), .full (full), .empty (empty) );
外部模块名为fifo_generator_0,
一般的,新名字都是 “u_模块名” ,即u_fifo_generator_0
再来看看参数。
外部参数名 | 内部参数名 |
---|---|
clk | clk |
srst | ~rst_n |
din | wr_data |
dout | rd_data |
没有列举完哈,这几个参数比较典型,拉出来说说。
fifo核自带的时钟名字为clk,我们定义的时钟名为clk
fifo核自带的复位名字为srst,我们定义的复位名为rst_n
(但因为srst为高电平有效,rst_n为低电平有效,所以取反)
fifo核自带的写数据名字为din,我们定义的写数据为wr_data
fifo核自带的读数据名字为dout,我们定义的读数据为rd_data
由此可见,外部参数和内部参数的名字不要求一致,只要他们代表的意义一样即可。
但内部参数对应的数据类型一般都是wire类型,这点还希望大家注意一下。
同理,ILA例化也是一样的框架。
ila_0 u_ila_0 ( .clk (clk), // input wire clk .probe0 (probe0) // input wire [26:0] probe0 );
值得一提的是,probe0参数有27位,但只是一个参数!
所以只占用一个外部参数名。
wire [26:0] probe0; assign probe0[0] = clk; assign probe0[1] = rst_n; assign probe0[2] = wr_rd_flag; assign probe0[3] = wr_en; assign probe0[4] = rd_en; assign probe0[12:5] = wr_data[7:0]; assign probe0[20:13] = rd_data[7:0]; assign probe0[21] = full; assign probe0[22] = empty; assign probe0[26:23] = cnt_dly[3:0];
三. 仿真
3.1 概论
选择仿真大致有两个情况:
- 不上电,先行验证代码的正确性
- 没有板子,只能通过仿真来进行观看结果
据我所知,一般在实验或者工程上电之前,都会进行仿真,一旦连仿真结果都是失败的错误的,那么也就不必去上电了。所以学会仿真是必要的。
3.2 建立仿真文件
我在01节仿真部分已经带着大家一起建立过仿真文件了,在此处就不耽误大家时间了,有需要的同学可以去01节看看喔。
3.3 编写仿真代码
仿真仿真,就是要模仿真的。真的具有什么,放出来的结果应该也具有什么特点。
所以,我们在仿真中需要实现
1.系统时钟的编写
2.复位信号的切换
3.结合具体情况的一些其他功能
当然,也要确保仿真模块的代码语法的正确性。下面我们就以01节仿真代码为例,来看看这一必要的仿真模块到底长什么样。
`timescale 1ns / 1ps module tb_led_stream(); reg sys_clk; reg sys_rst_n; wire [3:0] led; initial begin //初始化 sys_clk = 1'b0; sys_rst_n = 1'b0; #1 sys_rst_n = 1'b1; end always #10 sys_clk = ~sys_clk; //定义一个50M赫兹的时钟 led_stream u_led_stream( //例化 .clk (sys_clk), .rst_n (sys_rst_n), .led (led) ); endmodule
咱们一个部分一个部分的讲解:
- 单位时间:
`timescale 1ns / 1ps
这个代表了在仿真模块中的单位时间为1ns,精度为1ps。
举个例子,"#10"就代表经过10ns.
- 仿真变量:
reg sys_clk; reg sys_rst_n;
我要实现时钟和复位信号,就必然要先定义他们。
- 初始化:
initial begin //初始化 sys_clk = 1'b0; sys_rst_n = 1'b0; #1 sys_rst_n = 1'b1; end
代码翻译如下:
最开始,时钟信号为低电平,复位信号为低电平,1ns之后复位信号拉高。
这和真正的板子是一致的。板子真正的复位信号,是上电瞬间为低电平有效,之后就拉高为1。时钟也是相似的道理(详见下一模块)。
- 时钟模块
always #10 sys_clk = ~sys_clk; //定义一个50M赫兹的时钟
先来讲讲真正的系统时钟。
时钟信号就是不断地拉高拉低,通过记录时钟信号的上升沿即可得到时间。那么一个上升沿是多少时间呢。这就和系统的晶振有关系了。博宸电子的ZYNQ7020DEV开发板采用的是50M的晶振,即1s震动50M次。也就是时钟信号1s翻转50M次。
也就是说,时钟信号每隔10ns都是前一个瞬间的取反。
在仿真模块中,10ns后取反是
#10 sys_clk = ~sys_clk;
而时钟信号是一直每隔10ns就取反,所以必然有always语句。
always #10 sys_clk = ~sys_clk; //定义一个50M赫兹的时钟
- 例化模块
现在该把module模块例化到仿真模块中了,让仿真模块实现它的功能。
led_stream u_led_stream( //例化 .clk (sys_clk), .rst_n (sys_rst_n), .led (led) );
led_stream是module模块的模块名,直接从module中复制过来就行。剩下的例化知识就和上面讲例化是相同的。大家可以自行理解。
3.4 启动仿真
点击vivado左边的Run Simulation后就可以看到仿真图啦!