关于 Verilog HDL 的认知
常见认知(错误)
正确认知
HDL:hardware Description
- HDL 语言仅是对已知硬件电路的文本表现形式编写前,对所需实现的硬件电路“ 胸有成竹 ”
- Verilog HDL 的基本功能之一是描述可综合的硬件电路。
- 相比 C 语言,最显著的区别在于 HDL 语言具备以下硬件设计的基本概念:
Verilog HDL 用于可综合描述的语句
- always
- if-else
- case
- assign
这里课件上的 for 不可用于综合,这点不敢苟同
if-else 相关语句的硬件结果映射及优化
if-else 硬件结构
- 映射的硬件结构: Multiplexing Hardware -> 多路选择器, 输出结果由输入的选择条件决定
- 重构 if-else 映射的硬件结构:减少了一个加法器,减少了硬件面积:
trade-off :但是在这种情况下,电路的传播延迟 -> 数据通路的延迟没改变,但是控制通路的传播也变成了一个选择器和加法器之和,如果 aflag 到来延迟晚,则后一种电路没前者好的性能没这么好:
单 if 语句-无优先级的判断结构
如以下代码:
always@(a or b or c or d or sel)begin
z=0;
if(sel[3])
z=d;
else if(sel[2])
z=c;
else if(sel[1])
z=b;
else if(sel[0])
z=a;
end
硬件结构为:
多 if 语句-具有优先级的判断结构
如以下代码:
always@(a or b or c or d or sel)begin
z=0;
if(sel[0])z=a;
if(sel[1])z=b;
if(sel[2])z=c;
if(sel[3])z=d;
end
硬件结构为:
最后一级选择信号具有最高的优先级,具有优先级的多选结构会消耗组合逻辑
- 若某些设计中,有些信号要求先到达(如关键使能信号,选择信号等),而有些信号需要后到达(如慢速信号,有效时间较长的信号等),此时则需要采用此结构
- 设计方法:最高优先级给最迟到达的关键信号
此处结合阻塞赋值与非阻塞赋值去想都是成立的
case-无优先级的判断结构
如以下代码:
always@(a or b or c or d or sel)begin
case(sel)
2'b00: z=d;
2'b01: z=c;
2'b10: z=b;
2'b11: z=a;
default: z=1'b0;
endcase
end
- 与单 if 语句的区别: 条件多为互斥
- 多用于指令译码电路
慎用 Latch
综合器很难解释 latch,因此,除非特殊用途,一般避免引入 latch.
一般只在异步电路与门控时钟中用到
- latch 由电平触发,非同步控制.在使能信号有效时,latch 相当于通路,在使能信号无效时 latch 保持输出状态。DFF 由时钟沿触发,同步控制。
- latch 容易产生毛刺(glitch),DFF 则不易产生毛刺。
- latch 将静态时序分析变得极为复杂。
- 一般的设计规则时:在绝大多数设计中避免产生 latch。latch 最大的危害在于 不能过滤毛刺 。这对于下一级电路时极其危险的。所以,只要能用 D 触发器的地方,就不用 latch。
- 易引入 latch 的途径:使用不完备的条件判断语句
所以防止产生非目的性 latch 的措施:
- 使用完备的 if-else 语句
- 为每个输入条件设计输出操作,为 case 语句设置 default 操作
- 仔细检查综合器生成的报告,latch 会以 warning 的形式报告
利用综合器指令指定电路结构
full-case
对如红绿灯等只有红绿黄三种情况下,采用 2bit 的状态编码则会产生分支赋值不完备的情况:
always@(a or b or c or sel)begin
case(sel)
2'b00: y=a;
2'b01: y=b;
2'b10: y=c;
endcase
end
此时现实的状态已经完备了,但是从数字电路角度出发会有一个 2'b11 下的 latch
此时使用 full-case:
- full-case: 告诉综合器,当前 case 结构所列条件已完备
always@(a or b or c or sel)begin
case(sel) // synopsys full_case
2'b00: y=a;
2'b01: y=b;
2'b10: y=c;
endcase
end
此时综合器结果:
则不会推断出 latch
parallel_case
当 case 语句中的分支条件不互斥,则 case 语句存在优先级,如:
always@(irq)begin
int = 3'b0;
casez(irq)
3'b1??: int[2]=1'b1;
3'b?1?: int[1]=1'b1;
3'b??1: int[0]=1'b1;
endcase
end
综合器报告:
使用 parallel-case 原语:告诉 DC,所有条件互斥,并行且无优先级
always@(irq)begin
int = 3'b0;
casez(irq) // synopsys parallel_case
3'b1??: int[2]=1'b1;
3'b?1?: int[1]=1'b1;
3'b??1: int[0]=1'b1;
endcase
end
合理使用 parallel case 约束,可以条件译码逻辑
逻辑复制-均衡负载
通过逻辑赋值,降低关键信号的扇出,进而降低该信号的传播延迟,提高电路性能:
trade-off: 资源消耗
资源共享-减少面积
若电路中存在较多公共单元,可以通过资源共享来减少面积:
但一般共享会导致性能下降
资源顺序重排-降低传播延时
对到达延迟大的信号,可以重排其电路顺序以降低传播延时,提高性能:
如图,假设 A 来得比较晚,就可以将其尽可能放在后面,隐藏他的延迟
":?"仅用于连线,always 用于逻辑运算
尽可能使用 always 来描述电路,assign 仅仅用来实现连线,如:
assign a = (b==1)?((c&&d)? 1'b1:1'b0):1'b0;
与 always 块描述的:
always@(*) begin
if(b==1'b1)
if(c&&d == 1'b1)
a=1'b1;
else
a=1'b0;
else
a=1'b0;
end
关于 assign 和三目运算符:
- 仅用于信号连线
- 难以阅读,且多层嵌套后很难被综合器解释
可综合风格对代码的要求
完整的 always 敏感信号列表
- 所有的组合逻辑或所存的 always 结构必须由敏感信号列表.其中必须包括所有的输入信号
- 原因: 综合过程将产生要给取决于除命案列表中所有其它值的结构,它将可能在行为仿真和门级仿真间产生潜在的失配.
每个 always 敏感信号列表对应一个时钟
- 在综合过程中,每个 Verilog always 敏感信号列表只能对应一个时钟。
- 原因:这是将每一个过程限制在单一寄存器类型的要求,有利于逻辑综合和时序分析
不允许 Wait 声明和# delay 声明
- Wait 声明语句,无论时清楚还是含糊,都不能用于可综合设计。
- 原因:从 RTL 级转换到 gate 级的综合工具一般都不支持 Wait 声明和# delay 声明,为了有效的综合,这些语句应该避免。
- 例外:在不需要进行综合的行为模块中,如测试模块,表示行为的虚拟期间模块中可以使用。
在时序电路中必须使用非阻塞赋值(<=)
在组合逻辑中必须使用阻塞赋值(=)
模块划分
分开异步逻辑与同步逻辑
- 建议分开异步逻辑与同步逻辑
- 原因:简化综合时的问题,简化约束和编码难度
- 例外:不可应用于非综合模块中(例如:总线模块,总线监视器或是模拟模块)除非他们被设计来综合仿真。
分开控制逻辑和存储器
- 建议分开控制逻辑与存储器逻辑为独立模块
- 原因:存储器一般由 memory compiler 生成,便于高层的存储器模块的使用和便于重新描述为不同的存储器类型。混用不利于综合,不利于方便更换工艺库和平台。
-
寄存器
+关注
关注
31文章
5322浏览量
120022 -
触发器
+关注
关注
14文章
1996浏览量
61053 -
HDL语言
+关注
关注
0文章
46浏览量
8912 -
dff
+关注
关注
0文章
26浏览量
3400 -
多路选择器
+关注
关注
1文章
22浏览量
6517
发布评论请先 登录
相关推荐
评论