文章目录

  • 背景
  • 一、米联客verilog篇笔记
    • 1、为什么要推出vivado
    • 2、状态机,软核的理解
    • 3、always @的含义与 @()
    • 4、条件运算符
    • 5、阻塞逻辑和非阻塞逻辑混用
  • 二、xilinx官方DOC
  • 三、常用TestBench模板
    • 1、如何产生外部触发信号
    • 2、task的用法
    • 3、wait与@
  • 四、EDA先锋工作室笔记
    • 1、define
    • 2、逻辑值
    • 3、常量
    • 4、寄存器与存储器
    • 5、线网与寄存器
    • 6、verilog中的三种描述方式
    • 7、begin end与fork join
    • 8、if else 与case
  • 五、vivado的基本使用
    • 1、创建工程
    • 2、语法参考language templates与IP catalog
    • 3、RTL详细描述和分析
    • 4、综合及资源报告
    • 4、实现implement
    • 5、时序约束
    • 6、IO管脚分配
    • 7、仿真
      • 1、vivado simulator以及操作技巧
      • 2、基于modelsim的仿真(避免重复Xilinx编译库)
    • 8、烧写下载、固化程序
      • 1、生成bit文件
      • 2、固化程序
  • 福利链接

背景

一件事情,只有迈出了第一步,才会有第二步,永远迈不出第一步,那么就永远停留在原点,毕竟距离毕业还有一年时间,我觉得明年这个时候,我应该已经掌握了常用的XILINX IP使用,以及仿真等使用了,此外对verilog这种语言也会有更深一步的认识。
本篇文章是对verilog语言的全新认识,适用于有了基础后,想从语法联系到电路,这样才能对verilog有一个比较深刻的认识。

一、米联客verilog篇笔记

1、为什么要推出vivado

推出Vivado 是为了提高设计者的效率,硬件进入了28nm时代,软件的设计也要提升,它能够显著增加Xilinx的28nm工艺的可编程逻辑器件的设计、
综合与实现效率,所以,vivado目前只支持xilinx的28nm工艺的7系列FPGA,包括V7,K7,A7,ZYNQ。另外值得注意的是ISE 14.7是支持全系列的Xilinx family的。

2、状态机,软核的理解

我们可以把一些逻辑控制顺序复杂的事情用C代码来实现,让FPGA中运行CPU(由于逻辑控制顺序
复杂,不适合用状态机)而实时处理的部分仍然用Verilog来实现。并且那部分Verilog可以被C代码
控制。米联客的第三段,状态输出,写的是当前状态CS,而不是NS。

3、always @的含义与 @()

always @() 括号里面是敏感信号。这里的always @ (posedge clk),敏感信号是posedge clk含义是上升沿的时候有效,敏感信号还可以negedge clk含义是下降沿的时候有效,这种形式一般时序逻辑都会用到。

@代表的是在什么什么时刻,代表的是一种沿触发。

4、条件运算符

A=B?C:D 是一个条件运算符,含义是如果B为TRUE,则把C连线A,否则把D连线A,通常B是一个条件判断,用小括弧括起来:
assign c1_clk =(c1==25’d24999999)?1:0;

5、阻塞逻辑和非阻塞逻辑混用

always @ (posedge clk)
begin
A=1’b1; //阻塞逻辑
B<=1’b1; //非阻塞逻辑
end
看到上面这个程序是阻塞与非阻塞的混合使用,一般教材是极力反对这种写法的,但有时候这种用法还能帮上大忙,只不过,不理解的话乱用会导致时序违规。当时钟上升沿来临的时刻,首先A会被置1,然后B寄存器再置1.区别就是A和B不再同时置位1。A要比B提前零点几纳秒,这样就出现了先后顺序。这个过程还是在一个时钟内完成的,但是数据到达B寄存器相比非阻塞逻辑,晚了那么零点几纳秒。

二、xilinx官方DOC

三、常用TestBench模板

1、如何产生外部触发信号

很多时候我们需要外部触发信号来产生激励,我们可以采用forever语句来产生占空比非50%的脉冲。

  • 产生任意占空比的外部触发信号
initial                                                
begin                                                  
	#0 clk=0;
	#0 extriger=0;
	forever
	begin
		#10000 extriger=0;
		#60000 extriger=1;
	end
end    


上图中产生了10us的高电平,60us的低电平。
先产生60us的低电平,然后产生10us的高电平。

  • 产生脉冲个数固定的脉冲信号
    repeat函数。将程序执行n次
initial                                                
begin                                                  
	#0 clk=0;
	#0 extriger=0;
	repeat(10)
	begin
		#2000 extriger=0;	
	   #80000 extriger=1;
	end
end   

2、task的用法


task 就把它当做module模块来写即可,不过module是可以综合的,而task是不能综合的而已。

3、wait与@

四、EDA先锋工作室笔记

1、define

在一个文件中出现‘define可以被多个文件使用,也就是说‘defibe是一种全局性定义,这是‘define与parameter定义的最大区别。
‘define指令被编译以后,将在整个编译过程中有效,直到遇到‘undef指令为止,比如说:‘undef BUS_width

2、逻辑值

在Verilog语言中,为了对电路进行精确建模,又增加了两种逻辑状态,即“X”和“Z”。
当“X”用作信号状态时表示未知,当用作条件判断时(在casex或casez中)表示不关心;
“Z”表示高阻状态,也就是没有任何驱动,通常用来对三态总线进行建模。
但是在综合工具眼里,或者说在实际实现的电路中并没有什么X值,只存在0,1和Z 3种状态。但是在实际电路中还可能出现亚稳态,它既不是0,也不是1,而是一种不稳定状态。

3、常量

Verilog中的常量有三中类型:整数型、实数型、字符串型
这里就说一下字符串型吧。
字符串是指双引号中的字符序列,是8位ASCII码值的序列,例如“Hello World” ,该字符串包含11个ASCII符号(两个单词一共10个符号,单词之间的空格为一个符号,共11个ASCII符号),因此需要11个字节存储,方法如下:

reg [8*11:1] Message;
...
Message= “Hello World”;
这样就可以将字符串常量存入到Message变量。

4、寄存器与存储器

reg是最常用的寄存器类型数据,可以使一位、多位或者二维数组(存储器)
reg [3:0] ABC;//定义一个名字为ABC的4位存储器
在多位寄存器中可以进行位选择或者部分选择,例如:
ABC [3]=1; //将ABC的第三位赋值为1;
ABC [0]=0; //将ABC的第0位赋值为 0
ABC [2:1]=2’b01; //将ABC的第1、2位赋值为1和0

使用reg类型还可以定义二维寄存器数组,这种结构通常用于描述存储器(Memory结构)
reg [3:0] MEM [0:7]; //定义一个存储器,地址为0~7,每个存储单元都是4bit
与一维的reg变量不同的是,不能再对存储器中的存储单元进行位选择或部分选择,但是可以为每个单元单独赋值,比如:
MEM 【1】=4b‘0101; //为MEM中的第一个存储单元赋值4’b0101.
在verilog中,不存在一条语句对整个存储器赋值。必须对每个单元单独赋值。

5、线网与寄存器

线网是被驱动的,该值不被存储,在任意一个仿真步进上都需要重新计算。
寄存器是被赋值的,且该值将在仿真过程中被保存,直到再次对该变量进行赋值。

6、verilog中的三种描述方式

数据流描述:采用assign连续赋值语句
行为描述:使用always语句或initial语句块中的过程赋值语句
结构化描述:实例化已有的功能模块或原语

7、begin end与fork join

begin end在测试文件中是顺序执行出现在initial中
在fork join语句组中语句是并行执行的。代码改写为:

initial
fork
databin=0;
#6 databin=0;
#4 databin=1;
#2 databin=0;
join

由于所有语句是并行执行的,也就是说以上4条语句都是从0时刻开始执行的,因此产生的波形将和begin end的initial就不一样了。

8、if else 与case

if else语句是有优先顺序的,如果第一级是关键路径的话,就可以利用这样的优先级编码提高设计性能。
case语句中,所有被判断的分之条件都具有一样的优先级。
在always模块内,逻辑是按照指定的顺序执行的。always块中的语句称为顺序语句,因为他们是顺序执行的,请注意,两个或多个的always模块也是同事执行的,但是模块内部的语句是顺序执行的,看一下always内的语句,你就会明白它是如何实现功能的。if,,,else,,,if必须顺序执行,否则其功能就没有任何意义。如果else语句在if语句之前执行,功能就不符合要求。

五、vivado的基本使用

1、创建工程


选择RTL工程

选择器件

界面介绍

2、语法参考language templates与IP catalog


上面要介绍的这个Language Templates。包含了我们所有的语法,IP例化等等,真的是非常方便,而且,我们可以经常查阅这个模板,从而掌握更多的语法结构。

在上图中synthesis constructs包含了可综合的常见的语法结构

如上图所示,coding example包含了很多例子,包括乘法器,ram移位,状态机等等,简直可以称得上一本完美的教科书。

对于vivado FPGA工程师来说,这些代码永远值得参考学习,永远值得敬畏,永远值得温习,学习,从而改进自己的代码风格。
下图的IP catalog也是一个非常有用的工具,包含了所有的IP,我们可以根据这个目录去学习一些常用的IP核。


3、RTL详细描述和分析

详细描述(Elaboration)是指将RTL优化到FPGA技术。在基于RTL的设计中,详细描述是第一步,当设计者打开一个详细描述的RTL,设计者可以查看RTL结构、语法和逻辑定义。分析和报告能力包括:
RTL编译有效性和语法检查;
网表和原理图研究;
设计规则检查;
使用一个RTL端口列表的早期IO引脚规划;
在RTL视图中,选择一个对象,右击,出现浮动菜单。在浮动菜单内,选择go to source 选项,将自动跳转到定义该对象源代码的位置。

如下图所所示,可进行IO管脚分配。


从上图所示,选定了RTL的对象过后,右键点击go to source,可以跳转到代码位置。所以关于RTL的所有对象,我们也有必要学习,这样才能更深刻理解数字电路。关于RTL的所有对象,我以后会专门写一篇文章,这里暂时放一放。(无力吐糟感,处女座强迫症)

RTL Netlists里面,在该标签窗口中,查看RTL级网表。

上面箭头的Nets代表连线
leaf cells代表对象

4、综合及资源报告





添加verilog文件过后,我们可以看到



上面两张图是进行综合后的总结报告。
要比较X和A的FPGA,就要清楚两个大厂的FPGA的结构,但是,两家公司都可以统一到LUT(Look_UP_Table)查找表上。A家的片子,用的是LE这个术语。

而X家用的是CLB这个术语,作为基本单元

再来看看两家的基本单元有何不同:

A家就是一个4输入LUT+FF构成

而X家的CLB如下:

一个CLB由2个SLICE构成,一个SLICE含有4个6输入的LUT,所以LUT=8*CLB

这样的话,可以较比一下。EP4CE6基本就和XC6SLX9一个级别。。。。当然A家的片子是4输入LUT远比不上X家的6输入LUT。而X家的S-6片子,一个Slice内部有4个lut,8个FF。简而言之,一个Slice=四个LE。要注意的是A家C5以下的片子是4输入LUT而X家的是6输入LUT,差别也较大。如果不考虑FF,那么一个X家的slice=4个A家的LE。例如XC6SLX16含有2278个slices=EP4CE10(9000LE)的样子。当然,S-6的FF多一倍,达到了18224个。
在Virtex-5中(我们的设计大部分是Virtex,V5V6V7),一个Slice包含了4个LUT和4个FF。所以单纯从逻辑资源来看,S-6一个Slice比V-5的Slice强。当然V5的GTPGTX等等还有IO数量是S-6赶不上的。当然,A家的Cyclone V系列的片子,内部和前几代完全不同,采用了从高端的Stratix系列下放的技术,在新设计时,值得推荐~!
上述介绍参考:https://wwwblogs/lifan3a/articles/4682471.html
说了这么多,那么综合究竟是干嘛呢?综合就是将RTL级的设计描述转换成门级的描述,比如说触发器,我们知道触发器也是由门电路组成的。在综合过程中,将进行逻辑优化,并且映射到Xilinx器件原语。该综合工具支持xilinx设计约束XDC。
在综合的过程中,综合工具使用XDC约束来驱动综合优化,因此必须存在XDC文件。


当执行完综合后,可以展开synthesis design。在synthesis designed分组中听过了下列选项:
1、constraints wizard(约束向导)
2、Edit Tiing Constraints(编辑时序约束):该选项用于启动时序约束标签。
3、set up debug (设置调试):该选项用于启动标记网络视图界面,这些标记过的网络视图将用于调试目的。
4、report timing summary(报告时序总结):该选项生成一个默认的时序报告。
5、report clock networks(报告时钟网络):该选项生成该设计的时钟树。
6、report clock interaction(报告时钟相互作用):该选项用于在时钟域之间,验证路径上的约束收敛。
7、report DRC(报告DRC):该选项用于对整个设计执行设计规则检查。
8、report noise(报告噪声):该选项用于对设计中的输出和双向引脚执行一个SSO分析。
9、report utilization(报告利用率):该选项生成一个图形化的利用率报告
10、report power(报告功耗):该选项用于生成一个详细的功耗分析报告。
11、schematic(原理图):该选项用于打开原理图视图界面。

4、实现implement



可以看到经过实现后的资源有所变化,LUT减少
解决办法:
https://blog.csdn/xinxulsq/article/details/80926720

5、时序约束

参考视频:https://china.xilinx/video/hardware/using-vivado-timing-constraint-wizard.html
参考视频:中文配音:http://xilinx.eetrend/d6-xilinx/webinar/2016-08/10388.html
vivado中约束文件名字的后缀名是.xdc,用于取代ISE集成设计环境中的.ucf文件

6、IO管脚分配


在layout下,可以切换至IO规划器。
可以通过IO规划器来实现约束引脚位置。IO规划器允许设计者查看晶圆和封装视图,这样设计者就可以理解IO组合逻辑之间的关系。
在器件视图中,引脚之间的不同颜色区域标识了IO组,同时显示了差分对。从图中可以看到时钟使能引脚、VCC、GND,以及没有连接的引脚,这些引脚通过不同的形状来标识。


采用此工具还可以自动分配管脚。

7、仿真

1、vivado simulator以及操作技巧

通过点击add sources,可以增加仿真文件

如下图,添加tb文件添加成功。可以看到在我们添加了tb文件,然后编写tb文件代码后,原来的顶层模块也自动加入到sim中来了。


顶层代码:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2019/05/15 14:13:04
// Design Name: 
// Module Name: led_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

module led_top(
input clk,
input rst,
output led
    );

reg [28:0] time_cnt;
reg led_reg;

always @ (posedge clk or negedge rst)
	begin
		if(!rst)
		time_cnt<=0;
		else if (time_cnt=='d50000000)
		time_cnt<=0;
		else
		time_cnt<=time_cnt+1'b1;
	end

always @ (posedge clk or negedge rst)
	begin
		if(!rst)
		led_reg<=0;
		else if(time_cnt=='d50000000)
		led_reg<=~led_reg;
		else
		led_reg<=led_reg;
	end
assign led=led_reg;
endmodule


仿真文件

`timescale 1ns / 1ns
//
// Company: 
// Engineer: 
// 
// Create Date: 2019/05/15 14:06:03
// Design Name: 
// Module Name: led_top_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module led_top_tb(
reg clk,
reg rst,
wire led
    );
 parameter PERIOD = 20;
led_top led_top_inst(
        .clk(clk),
        .rst(rst),
        .led(led)
            );
initial 
begin
#0 clk=0;
#0 rst=0;
#100 rst=1;
   forever
      #(PERIOD/2) clk = ~clk;
end
endmodule

点击run simulation,第一个是行为仿真,后面还有4种仿真,一般来说,我们进行功能仿真,如果跑时序仿真,往往比较慢。


下图为运行综合function仿真后的结果

我们可以从左边的scope里面拖动要观察的信号到右边,然后run all即可

这里实现后,仿真就不介绍了,操作步骤都是一样的。
我们来看一下经过实现后的仿真,每个time_cnt累加已经变化了,也就是说,它不是一下就变化的,而是一位一位的变化的。

至此,我们的自带vivado simulator仿真实验就已经讲解完毕了。下面,我再针对仿真实验,做一些额外的补充。
补充参考视频资源:
https://www.bilibili/video/av44305906/?p=3基于Xsim的仿真

如上图所示,我们要将仿真工具设置为vivado simulator。
此外,仿真的语言,我们选择为verilog,如果我们选择vivado simulator就不需要再对仿真编译库进行额外的编译,但是如果选择第三方平台如modelsim等工具,我们是需要额外对仿真编译库进行编译的。
此外,如果我们针对多个模块进行仿真,写了多个模块的多个TB,那么我们需要制定要仿真顶层文件。

此外,我们还可以保存我们的波形文件,波形文件类型为wcfg

如上图所示,我们可以将选择option,从而设置默认的波形选项。
此外,我们还可以将波形信号进行分组,这样有个好处是将暂时不看的波形折叠到一起,挪出屏幕空间观察别的信号。

如何精准测量时间间隔

如上图所示,我们是怎么测量时钟之间的间隔的呢,首先,我们点击需要将光标落到某个要观察的信号,这样,这个信号就保持高亮状态了,然后点击如下图所示的两个transition按钮,这两个按钮的意思是数据变化的时间点。然后进行add maker。最后出现两条蓝色线后,点击


此外,如果我们需要观察的信号更多的话,还可以添加另一个波形窗口。

如何保存一个波形呢,然后下次直接打开保存的波形

首先是要进行保存波形文件,文件类型为wcfg文件。
下次打开这个波形文件的时候,要开启一个新的waveform configuration,然后再点击open waveform configuration。

2、基于modelsim的仿真(避免重复Xilinx编译库)

参考视频:https://www.bilibili/video/av44305906/?p=4 基于modelsim的仿真
值得注意的是,采用modelsim的仿真,是基于第三方平台,所以我们需要编译xilinx的库,如果我们使用vivado自带的就不需要

采用如上图所示的命令compile_smlib来编译


上图是编译库后的路径,那么现在问题来了,我们是不是需要每一次工程都让vivado编译整个xilinx的库呢?答案显示是不需要的,我只要指定编译好的文件为公共文件即可,这样就能实现每次共享了,除非是新版本的vivado的软件刚安装好,新的modelsim文件刚刚安装好。否则,我们只需要每次调用这个公共的xilinx的库即可。


上图是option里面modelsim的安装路径。
通过上面简单的介绍,下面我们就开始以真正的实际例子来说吧。
参考文章:
https://blog.csdn/gooyin/article/details/82769643

如上图所示,在tools–>compile simlation library -->设置编译选项并指定编译路径,如下图所示,我们将指定编译库的位置放在modelsim的安装路径,并且新建了一个文件夹叫做 vivado_simib

执行的命令为:

compile_simlib -language all -dir {D:/modism_10.4/vivado_simlib} -simulator_exec_path {D:/modism_10.4/win64} -library all -family  all

通过命令,我们应该可以看出来之前讲的理论了,这是编译了xilinx所有的器件库。
设置好后,点击compile即可,整个时间比较长,大概好几分钟的左右(i7 8核处理器)

此时我打开编译库的文件夹


编译的整个库文件大小为2.37GB
在编译的库文件里面有一个modelsim.ini文件

用notepad++打开并找到mvc_lib = $MODEL_TECH/…/mvc_lib
下面都是编译好的IP所处的路径,将这些全部复制,然后打开modelsim安装路径下的modelsim.ini文件并完成粘贴。


下面我们运行vivado run simulation就可以了,这样modelsim就可以运行了,并且我们可以看到modelsim中添加了大量的Xilinx库

如下图所示,成功调用了modelsim,并运行仿真。

其实在这里,我又在开始思考一个问题了,Alteral 是不是也可以这样避免每次重复编译库呢?这个问题,以后我亲自实践,研究研究后,会再写一篇文章。

8、烧写下载、固化程序

烧写程序有两种,一种是不保存的,一种是能够保存到flash中的。下面就开始分别介绍。

1、生成bit文件


上图是产生bitstream
然后给开发板通电,并且连接下载器,单击open target 然后单击auto connect

连接成功后vivado会自动识别到芯片


然后单击program device

下载过程

2、固化程序

对于纯粹的verilog工程的固化


然后选择一个flash类型,设置生成mcs文件名,选择生成的bit流文件

1、选择好flash存储器件
2、自动填充flash的存储大小,注意单位是MB,所以是原本flash大小再除以8
3、命名mcs文件
4、选择烧写接口
5、选择bit文件
6、全部勾选


最终我们可以看到生成了mcs文件和prm文件

最后我们来看如何将烧写后的程序固化到flash中。

接下来就是要连接到器件。这里由于我目前身边没有,我就直接粘贴一下外协给的步骤吧。


如上图,是识别到了三个FPGA,我们分别给每一个FPGA配置flash。



选中FLASH芯片,右键选择“Program Configuration Memory Device”。

添加待配置的.MCS和.prm文件,如下图所示,其它默认或按需求更改。注意不要选错文件。

然后静待固化完成,完成后会弹窗提示。最后断电、断开JTAG,再上电。

福利链接

认识FPGA已经有2年了,我可能以后不会从事FPGA开发了,但FPGA依然是相关的,所以FPGA我会慢慢学,而不是主打了,这里我总结了一些适合初学者以及想进阶的FPGA视频,
包含了USB 3.0 DDR2 sobel边缘检测、图像处理、千兆以太网的详细文档代码讲解,另外包含了xilinx 锆石的文档讲解,以及明德扬的信号处理文档(不含视频),此外还有Intel的官方视频。
都是良心推荐的。需要可以Q1183699227 10元



更多推荐

米联客资料笔记FPGA篇&EDA先锋工作室&官方DOC&常用TestBench模板&Vivado基本使用