》日志日期:2020-8-20
。Verilog HDL是一种硬件描述语言,它是以文本形式来描述数字系统硬件的结构和行为的语言。 (Verilog HDL是一种描述语言,它和常见的编程语言C有根本的不同。C语言,让计算机的CPU从上往下按顺序执行每一条指令,执行完程序就结束了。
而Verilog HDL主要是描述了一个数字模块的结构,或者行为。有点像商业合同,合同里面也会描述产品的结构,产品的功能等等。合同的每一个条款,并不需要严格的先后顺序,只要把项目的方方面面都考虑完整,写下来就OK了。我们用Verilog HDL描述数字模块的功能,剩下的交给编译器;编译器会根据我们的要求设计重构FPGA内部硬件。)
@Vivado软件的使用学习
要想学会如何使用FPGA的内部资源,就要先学会如何使用对应的EDA软件,通过软件编写代码来实现FPGA的内部功能。这里用的时xilinx公司的Vivado2019.2,从网上查找且主要根据正点原子的FPGA教学资料进行学习,新建工程就不介绍了。
创建完一个新工程后,首先添加一个源文件,过程如下。
添加好源文件,编写完代码并保存后,进行分析综合,步骤如下。
现在介绍下Project summary界面的一些信息。
分析综合结束后就要进行约束输入。约束输入有 时钟约束 和 管脚约束 。这里介绍下如何看自己编写的代码的硬件原理图,但主要是找到IO Planning进行管脚约束,过程如下。
当设计实现时,生成比特流下载到板子上运行。生成比特流时比较慢需要等几分钟。
。当设计好后,还需要进行调试验证,这时就需要用到xlinx的硬件调试解决方案。
。xlinx硬件调试解决方案:
>Vivado集成了逻辑分析仪
>添加ILA核和VIO核实现硬件调试
>通过JTAG接口与PC相连
(
ILA:监控逻辑内部信号和端口信号。
VIO:实时监控和驱动逻辑内部信号和端口信号。
)
#如何使用ILA核
要如何使用ILA核首先要添加ILA核,添加过程如下。
设置完成,后面还有一步,默认就行,点击OK生成IP核文件,然后过程如下。
当源文件中的信号参数改变后(例如位宽,名称等),vivado软件不会自动改变ILA核的配置信息,也就是说修改完源文件,ILA核的配置信息还是对应修改前的源文件,这会导致调试仿真时并不是真正的仿真波形。当我们修改源文件的信号参数时,也要修改配置ILA核的对应信号探针的参数。
》日志日期:2020-8-21
。硬件调试简介:
1.功能仿真:
主要用来验证电路的功能是否符合设计要求,不考虑门电路的延迟和线延迟。
2.时序仿真:
是指电路已经映射到特定的环境后,综合考虑门电路的延迟和线延迟的影响,验证电路能否在一定时序条件下满足设计构想的过程,较好的反映芯片的实际工作情况。
#如何创建Sim仿真文件进行软件仿真
#代码固化
。固化原理:
就是将运行代码加到外设存储设备,然后重新上电运行外部存储设备中的程序。
。固化方式:
1.Bin文件烧录进Flash进行固化。
2.Mcs文件烧录进Flash进行固化。
。代码固化过程如下。
然后重新生成比特流文件,Bin文件会跟着比特流文件一起生成。然后下载到硬件就行,前提是配置了与外部存储芯片相同的硬件信息。
@VerilogHDL的学习
#Verilog基础
。四种逻辑状态:
。标识符:
。VerilogHDL的数据类型:
在 Verilog 语法中,主要有三大类数据类型,即寄存器类型、线网类型和参数类型。从名称中,我们可以看出,真正在数字电路中起作用的数据类型应该是寄存器类型和线网类型。
。寄存器类型:
寄存器类型表示一个抽象的数据存储单元,它只能在 always 语句和 initial 语句中被赋值,并且它的值从一个赋值到另一个赋值过程中被保存下来。如果该过程语句描述的是时序逻辑,即 always 语句带有时钟信号,则该寄存器变量对应为寄存器;如果该过程语句描述的是组合逻辑,即 always 语句不带有时钟信号,则该寄存器变量对应为硬件连线;寄存器类型的缺省值是 x(未知状态)。
寄存器数据类型有很多种,如 reg、integer、real 等,其中最常用的就是 reg 类型。例子如下。
。线网类型:
线网表示 Verilog 结构化元件间的物理连线。它的值由驱动元件的值决定,例如连续赋值或门的输出。如果没有驱动元件连接到线网,线网的缺省值为 z(高阻态)。线网类型同寄存器类型一样也是有很多种,如 tri 和 wire 等,其中最常用的就是 wire 类型。例子如下。
。参数类型:
参数其实就是一个常量,常被用于定义状态机的状态、数据位宽和延迟大小等,由于它可以在编译时修改参数的值,因此它又常被用于一些参数可调的模块中,使用户在实例化模块时,可以根据需要配置参数。在定义参数时,我们可以一次定义多个参数,参数与参数之间需要用逗号隔开。这里我们需要注意的是参数的定义是局部的,只在当前模块中有效。例子如下。
。阻塞赋值与非阻塞赋值:
>阻塞赋值:
阻塞赋值,顾名思义即在一个 always 块中,后面的语句会受到前语句的影响,具体来说就是在同一个always 中,一条阻塞赋值语句如果没有执行结束,那么该语句后面的语句就不能被执行,即被“阻塞”。也就是说 always 块内的语句是一种顺序关系,这里和 C 语言很类似。符号“=”用于阻塞的赋值(如:b = a;),阻塞赋值“=”在 begin 和 end 之间的语句是顺序执行,属于串行语句。阻塞赋值的执行可以认为是只有一个步骤的操作,即计算右值的值并更新左值,此时不允许任何其他语句的干扰,所谓的阻塞的概念就是值在同一个 always 块中,其后面的赋值语句从概念上来讲是在前面一条语句赋值完成后才执行的。
>非阻塞赋值:
符号“<=”用于非阻塞赋值(如:b <= a;),非阻塞赋值是由时钟节拍决定,在时钟上升到来时,执行赋值语句右边,然后将 begin-end 之间的所有赋值语句同时赋值到赋值语句的左边,注意:是 begin—end 之间的所有语句,一起执行,且一个时钟只执行一次,属于并行执行语句。
所谓的非阻塞的概念是指,在计算非阻塞赋值的 RHS 以及 LHS 期间,允许其它的非阻塞赋值语句同时计算 RHS 和更新 LHS。
(RHS:赋值等号右边的表达式或变量可以写作 RHS 表达式或 RHS 变量;
LHS:赋值等号左边的表达式或变量可以写作 LHS 表达式或 LHS 变量;)
。什么时候使用阻塞赋值核非阻塞赋值?
在描述组合逻辑电路的时候,使用阻塞赋值,比如 assign 赋值语句和不带时钟的 always 赋值语句,这种电路结构只与输入电平的变化有关系。
在描述时序逻辑的时候,使用非阻塞赋值,综合成时序逻辑的电路结构,比如带时钟的 always 语句;这种电路结构往往与触发沿有关系,只有在触发沿时才可能发生赋值的变化。
。assign和always的区别:
assign 语句使用时不能带时钟。
always 语句可以带时钟,也可以不带时钟。
(在 always 不带时钟时,逻辑功能和 assign 完全一致,都是只产生组合逻辑。比较简单的组合逻辑推荐使用 assign 语句,比较复杂的组合逻辑推荐使用 always 语句。)
。always带时钟与不带时钟的区别:
1.不带时钟:
always 语句可以带时钟,也可以不带时钟。在 always 不带时钟时,逻辑功能和 assign 完全一致,虽然产生的信号定义还是 reg 类型,但是该语句产生的还是组合逻辑。
2.带时钟:
在 always 带时钟信号时,这个逻辑语句才能产生真正的寄存器。
。什么是latch?
latch 是指锁存器,是一种对脉冲电平敏感的存储单元电路。锁存器和寄存器都是基本存储单元,锁存器是电平触发的存储器,寄存器是边沿触发的存储器。两者的基本功能是一样的,都可以存储数据。锁存器是组合逻辑产生的,而寄存器是在时序电路中使用,由时钟触发产生的。
(latch 的主要危害是会产生毛刺(glitch),这种毛刺对下一级电路是很危险的。并且其隐蔽性很强,不易查出。因此,在设计中,应尽量避免 latch 的使用。)
。代码里出现latch的两个原因:
在组合逻辑中,if 或者 case 语句不完整的描述,比如 if 缺少 else 分支,case 缺少 default 分支,导致代码在综合过程中出现了 latch。解决办法就是 if 必须带 else 分支,case 必须带default 分支。(只有不带时钟的 always 语句 if 或者 case 语句不完整才会产生 latch,带时钟的语句 if或者 case 语句不完整描述不会产生 latch。)
#状态机
。为什么要用状态机?
Verilog 是硬件描述语言,硬件电路是并行执行的,当需要按照流程或者步骤来完成某个功能时,代码中通常会使用很多个 if 嵌套语句来实现,这样就增加了代码的复杂度,以及降低了代码的可读性,这个时候就可以使用状态机来编写代码。状态机相当于一个控制器,它将一项功能的完成分解为若干步,每一步对应于二进制的一个状态,通过预先设计的顺序在各状态之间进行转换,状态转换的过程就是实现逻辑功能的过程。
。什么是状态机?
状态机是一种在有限个状态之间按一定规律转换的时序电路,可以认为是组合逻辑和时序逻辑的一种组合。状态机通过控制各个状态的跳转来控制流程,使得整个代码看上去更加清晰易懂,在控制复杂流程的时候,状态机优势明显,因此基本上都会用到状态机,如 SDRAM 控制器等。
。两类状态机:
1.Mealy状态机:组合逻辑的输出不仅取决于当前状态,还取决于输入状态。
2.Moore状态机:组合逻辑的输出只取决于当前状态。
。三段式状态机:
根据状态机的实际写法,状态机还可以分为一段式、二段式和三段式状态机。
*一段式:整个状态机写到一个 always 模块里面,在该模块中既描述状态转移,又描述状态的输入和输出。不推荐采用这种状态机,因为从代码风格方面来讲,一般都会要求把组合逻辑和时序逻辑分开;从代码维护和升级来说,组合逻辑和时序逻辑混合在一起不利于代码维护和修改,也不利于约束。
*二段式:用两个 always 模块来描述状态机,其中一个 always 模块采用同步时序描述状态转移;另一个模块采用组合逻辑判断状态转移条件,描述状态转移规律以及输出。不同于一段式状态机的是,它需要定义两个状态,现态和次态,然后通过现态和次态的转换来实现时序逻辑。
*三段式:在两个 always 模块描述方法基础上,使用三个 always 模块,一个 always 模块采用同步时序描述状态转移,一个 always 采用组合逻辑判断状态转移条件,描述状态转移规律,另一个 always 模块描述状态输出(可以用组合电路输出,也可以时序电路输出)。
实际应用中三段式状态机使用最多,因为三段式状态机将组合逻辑和时序分开,有利于综合器分析优化以及程序的维护;并且三段式状态机将状态转移与状态输出分开,使代码看上去更加清晰易懂,提高了代码的可读性。
三段式状态机的基本格式是:
*第一个 always 语句实现同步状态跳转;
*第二个 always 语句采用组合逻辑判断状态转移条件;
*第三个 always 语句描述状态输出(可以用组合电路输出,也可以时序电路输出)。
这里就写完了,刚入门的菜鸟一只,有很多不懂得地方,文章有不完善的地方还请大佬们指点指点,学习一下😊😊😊😊😊