文章目录
经常看到是否可 Synthesis 的题目,网上对于Verilog 结构是否可 Synthesis 有很多分类标准,但是没有说明具体引用来源,所以学起来总感觉没有底气。
现在以Vivado IDE Synthesis 支持的Verilog 结构来具体学习 Verilog 的可综合性。具体文档是UG901。
1 Verilog 设计
复杂电路的设计通常采用自顶向下的方法。
- 设计过程的每个阶段都需要不同的规范级别(specification level)。例如,在体系结构级别,规范可以对应于框图或算法状态机(ASM)图。
- 一个块 或 ASM阶段 对应于一个寄存器传输块,其中的连接是n位导线,例如:
- 寄存器(Register)
- 加法器(Adder)
- 计数器(Counter)
- 乘法器(Multiplexer)
- 内部连接逻辑(Interconnect logic)
- 有限状态机(Finite State Machine (FSM))
- Verilog允许用计算机语言表达诸如ASM图和电路图之类的符号。
2 Verilog 功能
Verilog提供行为(behavioral)和结构(structural)语言结构。这些结构允许在高抽象级别和低抽象级别上表达设计对象。
- 使用Verilog设计硬件允许使用软件概念,例如:
- 并行处理
- 面向对象的程序设计
- Verilog的语法类似于C和Pascal
- Vivado synthesis 支持 IEEE 1364 Verilog
- 在Vivado synthesis 中支持Verilog,允许以最有效的方式描述全局电路和每个块。
- 对每个block采用最佳 synthesis 流程进行 synthesis
- 本文中的synthesis是将高级行为和结构Verilog HDL语句编译成一个平坦的门级网表( gate-level netlist)。然后,可以使用网表对可编程逻辑设备(如Virtex设备)进行自定义编程。
- 不同的synthesis方法用于:
- 算数运算块
- 内部连接逻辑
- 有限状态机组件
2.1 对 Verilog-2001 的支持
Vivado synthesis 支持 Verilog-2001 的如下功能:
- 生成(Generate)语句
- 组合端口/数据类型声明
- ANSI-style端口列表
- 模块操作符端口列表
- ANSI C风格的任务/函数声明
- 逗号分隔敏感列表
- 组合逻辑的敏感信号
- 使用连续赋值的默认线网类型
- 禁用默认的net声明
- Indexed vector的部分选择
- 多维数组
- net和real数据类型的数组
- 数组 位和部分选择
- Signed reg、net和 port 声明
- Signed-based 整数
- Signed 算术表达式
- 算术移位操作符
- 自动宽度扩展超过32位
- 幂操作符
- 待定位宽参数(N-sized parameter)
- 固定的局部参数
- 增强的条件编译
- 文件和行编译器指令
- 变量的部分选择
reg [3:0] data; reg [3:0] select; // a value from 0 to 7 wire [7:0] byte = data[select +: 8];
- 递归任务和函数
- 常量函数
2.2 结构性Verilog
结构化的Verilog描述集合了几个代码块,并允许在设计中引入层次结构。硬件结构的相关概念及其说明如下表所示。
概念 | 说明 |
---|---|
Component | 构建或基本块 |
Port | 组件的 I/O 连接器 |
Signal | 对应于组件之间的连线 |
内建逻辑门包括 与(AND)、或(OR)、异或(XOR)、与非(NAND)、或非(NOR)、非(NOT)
Verilog的结构特性允许通过实例化预定义的原语,Xilinx提供的源于如BUFG、CLKDLL等
2.3 Verilog 参数
Verilog参数的作用:
- 创建易于重用和扩展的参数化代码。
- 使代码更具可读性、更紧凑、更易于维护。
- 描述这样的功能:
- 总线位宽
- 在模型设计单元中某些重复元素的数量
- 常数。对于参数化模块的每个实例化,可以重写默认操作符值。
- 相当于VHDL泛型。不支持空字符串参数。
2.4 Verilog 参数与属性冲突的情况
Verilog参数和属性冲突可能会出现以下情况:
- 参数和属性可以应用于Verilog代码中的实例和模块。
- 同时属性也可以在约束文件中指定
2.5 Verilog使用限制
Verilog在Vivado synthesis中的使用限制包括:
- 大小写敏感
- Verilog大小写敏感,但是当模块名称只是大小写不同时,Vivado synthesis会出错。
- 阻塞和非阻塞赋值
- 不要混合使用阻塞和非阻塞赋值。虽然 Vivado synthesis 不会报错(注意只是不会报错)但是仿真会出错。
- 错误示范
always @(in1) begin if (in2) out1 = in1; end else out1 <= in2;
- 整数处理
- 在case表达式中,未设置大小的整数可能导致不可预测的结果。
- 连接操作符中的整数处理,vivado会新建32bit临时变量在进行位拼接。
2.6 Verilog元注释
- Translate Off and Translate On
// synthesis translate_on // synthesis translate_off
- Parallel Case
// synthesis parallel_case full_case // synthesis parallel_case // synthesis full_case
3 Verilog 结构
下表列出了Vivado synthesis 支持的 Verilog结构:
3.1 常量
常量 | 是否支持 |
---|---|
Integer | 支持 |
Real | 支持 |
String | 不支持 |
3.2 数据类型
数据类型 | 是否支持 |
---|---|
tri0,tri1,trireg三种线网类型 | 不支持 |
所有的驱动强度(Drive strength) | 忽略 |
real和realtime寄存器 | 不支持 |
所有命名过的event | 不支持 |
delay | 忽略 |
3.3 过程性语句
类型 | 是否支持 |
---|---|
过程性assign | 不支持 |
过程性deassign | 不支持 |
force | 不支持 |
release | 不支持 |
forever语句 | 不支持 |
repeat语句 | 支持,但重复值必须是常量 |
for语句 | 支持,但边界必须是静态的 |
delay (#) | 忽略 |
event (@) | 不支持 |
wait | 不支持 |
named events | 不支持 |
parallel blocks(fork…join) | 不支持 |
specify blocks | 忽略 |
disable | 支持,除了For和Repeat循环语句 |
3.3 设计层次结构
结构 | 是否支持 |
---|---|
module定义 | 支持 |
macromodule定义 | 不支持 |
hierarchical 名字 | 支持 |
defparam | 支持 |
数组的实例 | 支持 |
3.4 编译指令
指令 | 是否支持 |
---|---|
`celldefine `endcelldefine | 忽略 |
`default_nettype | 支持 |
`define | 支持 |
`ifdef `else `endif | 支持 |
undef, \ ifndef, `elsif | 支持 |
`include | 支持 |
`resetall | 忽略 |
`timescale | 忽略 |
`unconnected_drive `nounconnected_drive | 忽略 |
`uselib | 不支持 |
`file, `line | 支持 |
4 Verilog 系统task与function
Vivado synthesis支持的系统任务或功能如下表所示。Vivado synthesis忽略不支持的系统任务。
系统任务或函数 | 状态 | 说明 |
---|---|---|
$display | 不支持 | |
$fclose | 支持 | |
$fdisplay | 忽略 | |
$fgets | 支持 | |
$finish | 忽略 | |
$fopen | 支持 | |
$fscanf | 支持 | 转义序列仅限于%b和%d |
$fwrite | 忽略 | |
$monitor | 忽略 | |
$random | 忽略 | |
$readmemb | 支持 | |
$readmemh | 支持 | |
$signed | 支持 | |
$stop | 忽略 | |
$strobe | 忽略 | |
$time | 忽略 | |
$unsigned | 支持 | |
$write | 不支持 | |
$clog2 | 支持 | 这仅在SystemVerilog中受支持 |
$floor | 限制支持 | 仅限参数 |
$ceil | 限制支持 | 仅限参数 |
$rtoi | 不支持 | |
$itor | 不支持 | |
all others | 忽略 |
5 转换函数的使用
使用以下语法在任何表达式上调用
s
i
g
n
e
d
和
signed和
signed和unsigned系统任务。
$signed(expr) or $unsigned(expr)
- 这些调用的返回值与输入值大小相同。
- 无论前面有任何符号,返回值的符号都是强制的。
另外,可以使用使用 r e a d m e m b 和 readmemb和 readmemb和readmemh系统任务来初始化块内存。
6 Verilog 基本单元(原语)的支持
Vivado综合支持Verilog门级(gate-level)原语,除了下表:
基本单元 | 状态 |
---|---|
pulldown 和 pullup | 不支持 |
驱动强度与延时 | 忽略 |
数组的基本单元 | 不支持 |
Vivado synthesis 不支持Verilog开关级( switch-level )原语,例如:cmos, nmos, pmos, rcmos, rnmos, rpmos rtran, rtranif0, rtranif1, tran, tranif0, tranif1
7 Verilog 保留的关键词
做题目的时候遇到偏僻关键词直接搜索
always | and | assign | automatic |
begin | buf | bufif0 | bufif1 |
case | casex | casez | cell* |
cmos | config* | deassign | default |
defparam | design* | disable | edge |
else | end | endcase | endconfig* |
endfunction | endgenerate | endmodule | endprimitive |
endspecify | endtable | endtask | event |
for | force | forever | fork |
function | generate | genvar | highz0 |
highz1 | if | ifnone | incdir* |
include* | initial | inout | input |
instance* | integer | join | larger |
liblist* | library* | localparam | macromodule |
medium | module | nand | negedge |
nmos | nor | noshow-cancelled* | not |
notif0 | notif1 | or | output |
parameter | pmos | posedge | primitive |
pull0 | pull1 | pullup* | pulldown* |
pulsestyle_ondetect* | pulsestyle_onevent* | rcmos | real |
realtime | reg | release | repeat |
rnmos | rpmos | rtran | rtranif0 |
rtranif1 | scalared | show-cancelled* | signed |
small | specify | specpa | strong0 |
strong1 | supply0 | supply1 | table |
task | time | tran | tranif0 |
tranif1 | tri | tri0 | tri1 |
triand | trior | trireg | use* |
vectored | wait | wand | weak0 |
weak1 | while | wire | wor |
xnor | xor |
8 行为级Verilog语言结构
Vivado synthesis 支持行为Verilog硬件描述语言(HDL),除非另有说明
8.1 变量
- 行为级Verilog中的变量声明为整数。
- 这些声明只在测试代码中使用。Verilog为实际的硬件描述提供了reg和wire等数据类型。
- reg和wire之间的区别取决于变量的值是在过程块(reg)中给出的,还是在连续赋值(wire)中给出的。
- reg和wire都有一个位(标量)的默认宽度。
- 要为声明的reg或wire指定n位宽度(向量),左位和右位位置在用冒号分隔的方括号中定义。
- 在Verilog-2001中,reg和连接数据类型可以为有符号或无符号。
8.2 初始值
在Verilog-2001中声明寄存器时初始化它们。
- 初始值:
- 常数
- 不能依赖于较早的初始值。
- 不能是函数或任务调用。
- 可以是传播到寄存器的 parameter 值。
- 指定向量的所有位。
- 当在声明中将一个寄存器赋值为初始值时,Vivado synthesis将在全局复位或上电时在寄存器的输出上设置此值。
reg arb_onebit = 1'b0;
reg [3:0] arb_priority = 4'b1011;
- 当以这种方式赋值时:
- 该值作为寄存器上的INIT属性携带在Verilog文件中。
- 该值与任何本地reset无关。
给寄存器赋一个set/reset(初始)值:
- 当寄存器重置行变为适当值时,将该值赋给寄存器。示例。
always @(posedge clk) begin if (rst) arb_onebit <= 1'b0; end
- 当你给一个变量赋初始值时:
- 该值以一个触发器的形式实现,其输出由本地reset控制。
- 该值作为FDP或FDC触发器在Verilog文件中携带。
8.3 reg 或 wire 数组
支持
reg [3:0] mem_array [31:0];
8.4 多维数组
Vivado synthesis 支持至多二维的多维数组类型
wire [7:0] array2 [0:255][0:15];
reg [63:0] regarray2 [255:0][7:0];
- 多维数组可以是:
- 任意net
- 任意变量数据类型
- 使用数组进行赋值和算术运算。
- 一次不能选择数组中的多个元素。
- 不能将多维数组传递给:
- 系统任务或函数
- 常规任务或函数
8.5 数据类型
bit 数据类型的Verilog表示包含以下值:
- 0:逻辑0
- 1:逻辑1
- x:未知逻辑值
- z:高阻态
支持的数据类型
- net
- wire
- register
- reg
- integer
- 常数
- 参数
- 多维数组(内存)
8.6 合法的语句
Vivado综合支持行为Verilog合法语句
- 以下语句(变量赋值和信号赋值)是合法的:
- variable = expression
- if (condition)语句
- else 语句
- case (expression)
- for (variable = expression; condition; variable = variable + expression) 语句
- while (condition) 语句
- forever 语句
- 函数与任务
- 所有变量都声明为integer或reg。
- 不能将变量声明为wire。
8.7 块Block
Vivado综合支持一些块语句,如下所示:
- 语句块
- 将语句组织在一起。
- begin和end关键字指定
- 按照块中列出的顺序执行语句。
- Vivado合成只支持顺序块。
- Vivado合成不支持并行块。
- 所有过程语句都发生在模块内部定义的块中。
- 两种过程块是:
- initial block
- always block
- Verilog在每个块中使用begin和end关键字来封装语句。因为在综合过程中忽略initial块,所以只描述always块。
9 过程性赋值(Procedural Assignment)
- 行为Verilog过程性赋值:
- 为声明为reg的变量赋值。
- 由always块、任务和函数引入。
- 模型寄存器和有限状态机组件
- Vivado综合支持:
- 组合逻辑函数
- 组合逻辑与时序逻辑任务
- 组合逻辑与时序逻辑always块
组合逻辑always块
组合逻辑由Verilog时间控制语句高效建模:
- 延时控制语句[#]
- 仅作用于仿真
- 综合过程会忽略
- 事件控制时间控制语句[@]
- always组合块的敏感性列表出现在always@后面的括号中
- 如果一个事件(值改变或边沿信号)出现在一个敏感列表信号上,一个always块将被激活。
- 敏感列表可以包含:
- 在条件中出现的任何信号,如if或case。
- 任何出现在赋值函数右边的信号。
- 通过将@(at)替换为不带圆括号的信号列表,always块将为描述的任何always块信号中的事件激活。
9.1 if-else 语句
支持
9.2 case 语句
支持
9.3 for和repeat语句
Vivado综合支持for和repeat语句。当使用always块时,重复或bit slice结构也可以使用for语句或repeat语句来描述。
repeat语句只支持常量值
9.4 while 语句
当使用always块时,使用while循环来执行重复的过程。
- 一个while循环:
- 如果测试表达式最初为假,则不执行。
- 执行其他语句,直到其测试表达式变为false
- 测试表达式是任何有效的Verilog表达式。
- 要防止无限循环,使用-loop_iteration_limit选项。
- while循环可以有disable语句。disable语句在标记块中使用,如下代码片段所示:
disable <blockname>