小生才疏学浅,孤陋寡闻,下文若有不当之处,还请赐教
1 代码编写
1. 编写规范
- 排版
input,output,inout,reg,wire,parameter不缩进,且每次声明各占一行;
always,task,function不缩进;
输入输出信号的宽度定义与关键字之间,信号名与宽度间用空格分开;相同类型的定义对齐;
always中一般要用begin end区分,if else中仅有一个语句时,不使用begin end - 命名风格
端口,信号,变量名所用字母小写,若含义较复杂,可分段描述(三段),如tx_data_val;
函数名,宏定义,参数定义用大写;
低电平有效信号,后加”_n”
无条件寄存的寄存信号在原信号上加ff1,ff2…如data_in_ff1;
不能用reg作为后缀名,因为综合工具会给寄存器自动加_reg,此时会扰乱网表可读性 - 表达式书写
在长式子中适当添加括号;
赋值时需给常数注明比特宽度 - 条件判断语句
if else必须配合使用,case中也要添加default - FSM
状态机的时序逻辑部分和组合逻辑部分要分开写
推荐使用三段式写法,即两个组合逻辑电路和一个时序逻辑电路 - 注释
最好每个always前都要加注释
2.Verilog硬件描述编写
(一)数据类型
Verilog里面出来parameter,整形等类型外,硬件电路类型只有reg和wire两种。输出尽量设置成reg类型,采用寄存器输出方式。原因是组合逻辑输出存在毛刺,寄存器输出非常干净,毛刺较少
由于verilog中没有定义大小(size)整数缺省为32位,因此定义数字最好用完整形式 如8’d50
- wire
线网型,可作任意表达式的输入
通常做组合逻辑的赋值,即如果某信号出现在assign等号的左边,则该信号必为wire型
四值系统,取指为0,1,x(未知态),z(高阻态/浮空量)
出现X的情况通常是信号没有赋值,或者一个变量的赋值有多个来源;
出现Z的情况通常是wire类型悬空; - reg
表示“线”或“寄存器”,可做任意表达式的输入
通常作为时序逻辑的赋值,即如果某信号在always或initial模块中被赋值,则该信号必为reg型
取指为0,1,x - integer
表示循环变量,即循环次数
结合for循环使用
初值为x - parameter
定义符号常量
用标识符代替常量,提高代码可读性
- 定义数组(reg型的扩展)
也被称为memory 型数据。在Verilog中通过对reg数据建立数组来对存储器进行建模,verilog中没有多维数组存在,memory型数据是通过扩展reg型数据的地址范围实现的。存储器的地址索引必须是常数表达式(n-1,m-1等必须是常量,符号常量也可以)。如:reg [n-1:0] array [0:m-1]; //包含了m个n位数据的数组array。
在这里[n-1:0]定义了存储器中每一个存储单元的大小,即n位寄存器。array名后面的[0:m-1],表示定义的存储器中有多少个这样的寄存器。
(二)语句
- 条件说明语句(if-else/case)
条件说明语句必须放在always和Initial过程块内部;同时语句必须完整if-else/case-default,否则可能会综合出锁存器。
if else和case的选择:
if else的综合是由与或非门构成的,也可能一组多路选择器;case结构的综合是由一条多路选择器组成。
对于要写出平行结构的条件,优先写成case结构,例如地址译码等;而条件之间由重复和嵌套的情况则写成if else结构
- always过程语句块
描述逻辑功能(组合/时序逻辑)
- 一个always块的执行需要触发条件
- 一个always块可以多次执行
- 多个always块并发执行
- 单个过程块内是顺序执行的
- 多个过程块(包括initial过程块)在仿真一开始便并行执行,他们之间的同步是通过信号的变化(event触发)、对特定事件的等待(时钟周期)或时间(固定延时)来完成。
- 分为电平敏感和边沿敏感
电平敏感:一般描述组合逻辑,敏感列表必须包含所有出现在等式右边和条件中的信号,always块中赋值对象不能出现在等号右边。例如:always @(a or b)、always @(*)等
边沿敏感:一般描述时序逻辑,等号左边的变量可以出现在等号的右边
- assign——持续赋值语句
用来描述组合逻辑
- 一个assign语句等式右边的变量变化即执行
- 一个assign可以多次执行,始终处于活跃状态
- 多个assign并发执行
- assign和always不可互相嵌套
- assign语句中的赋值对象必须是wire型
- 有限状态机
同步时序逻辑电路的一种描述方式,表示电路状态的一种改变
- 过程赋值语句:阻塞赋值(=)和非阻塞赋值(<=)
如果后面的赋值语句要等前面的赋值语句完成才执行,称为阻塞,即一个begin/end中的阻塞赋值语句是顺序执行的;
如多条语句同时执行,则称为非阻塞,即一个begin/end中的非组设赋值是并发执行的
(1) always块中时序电路建模时,用非阻塞赋值。时序电路中,对于阻塞赋值,硬件没有对应的电路,因而综合结果未知
(2) always块中建立时序和组合逻辑电路时,用非阻塞赋值。
(3) always块建立组合逻辑模型时,用阻塞赋值。
(4) 在同一个always块中不要既用非阻塞赋值又用阻塞赋值。
(5) 不要在一个以上的always块中为同一个reg变量赋值。
(三)符号
- 某些特殊符号
- { }
表示拼接,{第一位,第二位…};
{{ }}表示拼接运算,例如:{4{a}}等同于{a,a,a,a}; - $
表示系统任务和函数,用于仿真、调试和验证
在系统任务名称前加$使之与用户定义的任务和函数相区分,比如常用的$display(显示信号值),$monitor(监视信号值),$time(返回当前仿真时间),$stop(暂停仿真),$finish(结束仿真)等 - #
(1) #(a,b,c…….)表示改变参数型常量(parameter)的值。
(2) #10 表示延时10个时间单位。 - <<和>>
Verilog中存在移位运算 - ^
异或,位操作 - ~和!
~表示位操作,与&、|同类
!表示逻辑操作,与&&、||同类 - === / !==
判断全等或不等,可包含x,z判断 - `
宏定义标志 - 数组: ram[i*8 +: 8]
从“:”左边索引开始,一共有“:”右边数字的位数,其中 +号是递增,-号是递减,ram[2*8+:8]表示为: ram[23 : 16]
如addr[20+3:3]表示为:addr[25:3] - 缩减运算符:| & 等
参考链接:https://blog.csdn.net/weixin_46022434/article/details/106311870
(四)预编译处理
- 功能
- 对预编译处理命令进行预处理
- 通常当宏定义过多时,`include和`define可配合使用,将所有宏定义均放在include的文件中。
- 预编译处理命令
- `include
将一个源文件包含到另一个源文件中,支持重复使用,资源共享格式:`include “文件名” 或`include “路径/文件名”
- `define
使用有意义的名字替代没有意义的数字、符号、表达式——提高可读性,可移植性。即用标识符代表字符串,无论数字还是算术运算符,都被视为“字符串”,在预编译阶段处理时将宏名替换为字符串。
功能类似parameter,但`define可在模块外使用,而parameter只能在模块内使用
3.testbench编写
参见链接:https://blog.csdn.net/qq_39815222/article/details/108045488
2. verilog代码优化
1 电路结构优化
- 通过插入寄存器实现电路的流水化,从而提升电路的主频
- 同步时序逻辑电路和异步电路
能用同步时序逻辑电路就尽量使用同步时序逻辑电路。
在SoC设计中,各个IP和CPU等运行速率不一致,可能会使用多种时钟,从而采用异步时序逻辑电路。
2 代码优化
- 尽量使用移位操作或加法器替代乘法器,尽量用选择器替代加法器
- 注意硬件电路算术逻辑计算的特征
参考链接:https://blog.csdn.net/qq_39815222/article/details/111187460
3 编码errors/warnings
- 编码错误
- 信号指定不明
例如:
output [31:0] count; #定义信号
reg count;该写法错误,count会被综合成1 bit。
1. wire和reg型被综合的情况
区分在组合逻辑电路和时序逻辑电路综合情况,组合逻辑主要是由门级网表构成的,时序逻辑主要由门级网表和D触发器构成。
2. 冒险和竞争
一个逻辑门的两个输入端的信号同时向相反方向变化,而变化的时间有差异的现象称为竞争,推荐使用非阻塞赋值或特定的信号延迟来解决同步的问题。
由竞争而可能产生输出干扰脉冲的现象称为冒险。
3.语句执行顺序
verilog是描述硬件的语言,因此对于代码的执行需要根据电路来理解。always之间均是并行执行;begin-end内是顺序执行,但如果里面是非阻塞赋值(<=),该赋值部分则是并行执行
4. 不可综合的verilog
描述事件的语句,无法用门来实现,如:
=== !== / % delay Initial Repeat forever wait fork join event
5.全局时钟资源语句
大型设计一般推荐使用同步时序电路。同步时序电路基于时钟触发沿设计,对时钟的周期、占空比、延时和抖动提出了更高的要求。为了满足同步时序设计的要求,一般在FPGA设计中采用全局时钟资源驱动设计的主时钟,以达到最低的时钟抖动和延迟。与全局时钟资源相关的原语常用的与全局时钟资源相关的Xilinx器件原语包括:IBUFG、IBUFGDS、BUFG、BUFGP、BUFGCE、BUFGMUX、BUFGDLL和DCM
IBUFG:输入全局缓冲,是与专用全局时钟输入管脚相连接的首级全局缓冲。所有从全局时钟管脚输入的信号必须经过IBUF元,否则在布局布线时会报错。 IBUFG支持AGP、CTT、GTL、GTLP、HSTL、LVCMOS、LVDCI、LVDS、LVPECL、LVTTL、PCI、PCIX和 SSTL等多种格式的IO标准。
IBUFGDS:IBUFG的差分形式,当信号从一对差分全局时钟管脚输入时,必须使用IBUFGDS作为全局时钟输入缓冲。
BUFG:全局缓冲,它的输入是IBUFG的输出,BUFG的输出到达FPGA内部的IOB、CLB、选择性块RAM的时钟延迟和抖动最小。
BUFGCE:带有时钟使能端的全局缓冲。它有一个输入I、一个使能端CE和一个输出端O。只有当BUFGCE的使能端CE有效(高电平)时,BUFGCE才有输出。
BUFGMUX:全局时钟选择缓冲,它有I0和I1两个输入,一个控制端S,一个输出端O。当S为低电平时输出时钟为I0,反之为I1。需要指出的是BUFGMUX的应用十分灵活,I0和I1两个输入时钟甚至可以为异步关系
BUFGP:相当于IBUG加上BUFG。
BUFGDLL:全局缓冲延迟锁相环,相当于BUFG与DLL的结合。BUFGDLL在早期设计中经常使用,用以完成全局时钟的同步和驱动等功能。随着数字时钟管理单元(DCM)的日益完善,目前BUFGDLL的应用已经逐渐被DCM所取代。
DCM:数字时钟管理单元,主要完成时钟的同步、移相、分频、倍频和去抖动等。DCM与全局时钟有着密不可分的联系,为了达到最小的延迟和抖动,几乎所有的DCM应用都要使用全局缓冲资源。DCM可以用Xilinx ISE软件中的Architecture Wizard直接生成。
4 Verilog综合及仿真
- EDA工具的数字系统设计流程
无论是针对FPGA还是ASIC编写verilog代码,使用EDA工具的流程一般分为一下几步:
- 设计输入
- 仿真测试
- 综合实现
- 编程下载
- 系统测试
- verilog仿真器
仿真器不同,结果可能不同
- Verilog-XL:
cadence开发的解释仿真器,“解释”即有一个运行时间的解释工具执行每一条Verilog指令并且与时间队列进行交流。该仿真器在cadence系统里是一个默认的verilog仿真器,但一直未被cadence更新,不具备verilog的新特点。 - NC-Verilog:
cadence的编译仿真器,把Verilog转换成该程序的定制仿真器,即先转换成C程序,再编译成仿真器。与Verilog-2001大部分兼容。 - VCS:
synopsys开发的编译仿真器,可以与该公司的其他工具集成在一起。兼容Verilog-2001
- Verilog综合成电路的方法
- behavioral(行为级RTL):
用高层次的Verilog描述所希望的系统行为,随后用综合工具综合成硬件电路。 - structural(结构级):
Verilog完全由一个标准单元库基本门的实例构成。该Verilog可以完全是文本的,或是采用标准库中逻辑门符号的层次化原理图。
- 编译综合过程
- 编译阶段
工具通过阅读目标代码,进行语法和语义分析,将每个模块分别编入库中 - 建模阶段
工具将各模块按照设计集成关系最终组成顶层模块,主要包括模块例化,接口例化,程序例化,层次集成,计算参数,解决层次信号引用,建立模块连接等。类似软件编译的link阶段。 - 仿真阶段
通过读取建模后的对象文件,建立硬件RTL模型和验证环境,以周期驱动或事件驱动进行仿真。
5. FPGA补充
FPGA中的寄存器是SRAM型
- FPGA的组成
当今FPGA内部有多中部件,如DSP、BLOCK RAM,BLOCK ROM等,但最基本单元式CLB逻辑块,CLB的组成有查找表LUT,寄存器Flip-flop,多路选择器Mux。
- LUT
用于实现组合逻辑电路,具体作用是存储组合逻辑电路计算的所有结果(因此EDA工具生成的烧进FPGA的是bitstream文件) - Mux
多路选择,配合LUT实现根据输入选择结果
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/82536.html