赞
踩
逻辑综合是ASIC半定制设计流程的一个阶段,用于将基于HDL的行为描述(RTL级层次)转化和优化为纯粹的结构描述(门级网表)
全定制设计:设计在电路级(晶体管级)进行,版图中每个器件和连线都是人工设计的,以期获得最小的芯片尺寸和最佳性能(速度、功耗)
- 是一种以人工设计为主的方法,EDA自动化程度低,设计时间耗时、麻烦;一般只用版图编辑工具,进行版图编辑、DRC/ERC检查和模拟验证
- 与IC工艺相关,可移植性、可重用性差
- 全定制设计需要经验丰富的专业工程师,这样的全定制的设计效果才可能好于半定制,设计成本高。
- 只有当现有的单元库满足不了要求,不计上市时间/成本压力时才考虑
半定制设计:是一种约束性设计方式,能简化设计/缩短设计周期,降低设计成本,提高设计正确率,按照逻辑实现方式的不同,可以分为门阵列法、标准单元法和可编程逻辑电路法
- 设计调用预先已设计好的大小不一的标准单元完成,这些标准单元统称为标准单元库,一般是厂家预先为指定工艺生成逻辑门一级的设计实体
- 单元库是人工全定制优化设计,已通过功能/性能的模拟和验证
- 单元库通常与某一工艺对应,包含了电路单元在各种描述层次属性的一组数据
- 设计人员不必关心低层次电路结构,可以在更高抽象层次设计电路的功能(行为级),由EDA工具自动综合生成网表和版图数据
- 设计与工艺不相关,提高了设计可移植、可重用性,设计效率高
- 与全定制相比,一般面积、功耗会稍大
- EDA自动化程度高,大幅缩短了复杂数字IC的设计时间,降低了成本
综合的过程是:在Foundry厂家给出的标准单元库和设计人员给出的设计约束的前提下,将一个高级HDL设计描述转化为优化过的门级网表,并把优化的门级网表映射成由标准库单元组成的等效电路结构,输出门级网表文件
VerilogHDL的基本功能之一就是描述可综合的硬件电路,但并不是所有的关键字都可以综合,有四个关键字可以综合为硬件电路 ,分别为always
、if-else
、case
和assign
,其他很多关键字都是不可综合的,比如说fork-join
和while
,这些不可综合的关键字一般用于书写testbench
if-else映射的硬件结构为多路选择器
always @* begin
if (Aflag == 1'b1) begin
outData = A + B;
end
else begin
outData = C + D;
end
end
上述代码等价于下面的硬件电路
对上述代码进行如下的改写,可以减小电路的面积
reg [3:0] op1, op2; always @* begin if (Aflag == 1'b1) begin op1 = A; op2 = B; end else begin op1 = C; op2 = D; end end always @* begin outData = op1 + op2; end
其硬件电路为
该结构减少了一个加法器,增加了一个MUX,通常来说加法器的面积更大,因此改写后的代码可以生成更小面积的电路;但是改写电路的控制通道的传播延迟更大(一个MUX和一个加法器),如果控制信号到来的延迟比较晚,那么改写电路的性能会更差。因此需要根据输入约束,来选择“先加后选”还是“先选后加”。
多条if语句可以“级联”,以执行多布尔条件并建立优先级,如下所示
always @(sel or A or B or C or D) begin Z = 4'b0; if (sel[0] == 1'b1) begin // 最高优先级 Z = A; end else if (sel[1] == 1'b1) begin Z = B; end else if (sel[2] == 1'b1) begin Z = C; end else if (sel[3] == 1'b1) begin // 最低优先级 Z = D; end end
该代码对应的硬件结构如下所示
下面的代码也可以建立优先级。
always @(sel or A or B or C or D) begin Z = 4'b0; // 最低优先级 if (sel[0] == 1'b1) begin Z = A; end if (sel[1] == 1'b1) begin Z = B; end if (sel[2] == 1'b1) begin Z = C; end // 最高优先级 if (sel[3] == 1'b1) begin Z = D; end end
其对应的硬件结构如下所示
在某些设计中,有些信号要求先到达(如关键使能信号、选择信号等),而有些信号需要后到达(如慢速信号、有效时间较长的信号等),此时可以使用具有优先级的if结构,一般是最高优先级给最迟到达的关键信号
相对于if语句只有两个分支而言,case语句是一种多分支语句,故case语句可用于描述多条件分支电路,如译码器、数据选择器、状态机及微处理器指令译码等。
always @(sel or A or B or C or D) begin
case (sel)
4'b0001: Z = A;
4'b0010: Z = B;
4'b0100: Z = C;
4'b1000: Z = D;
default: Z = 0;
endcase
end
上面代码对应的硬件结构如下所示
case语句在经过综合器优化后,不一定会生成多路选择器
除了常规的case语句,还有两种变体casez和casex。
在casez语句中,认为表达式中的z值和?是无关值(即对应为无需匹配)
在casex语句中,认为表达式中的z,x值和?为无关值。
由于z和x可能出现在仿真中,我们更倾向于采用?
下面给出了casez的一个使用案例
always @* casez (r) 4'b1???: y = 3'b100; 4'b01??: y = 3'b011; 4'b001?: y = 3'b010; 4'b0001: y = 3'b001; 4'b0000: y = 3'b000; // 这里可以使用default endcase
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
综合命令 full_case 与 parallel_case 有时会被用来优化逻辑,比如可以减少资源消耗和减少逻辑级数。但是,这两个命令的使用也是很危险的,极易造成综合结果与仿真结果的不匹配,引入bug。详情参考这篇文章当心 full_case 和 parallel_case - 知乎 (zhihu.com)
锁存器由电平触发,当使能信号有效时latch相当于通路,使能信号无效时latch保持输出状态。慎用latch的原因主要有以下几点:
一般的设计规则是:在绝大多数设计中避免产生latch,latch最大的危害在于不能过滤毛刺,这对于下一级电路是极其危险的,所以可以使用D触发器的地方就不用latch
容易产生latch的途径:case和if中使用不完备的条件判断语句,或者信号的输出赋值不完整,如下面的代码所示
always @* begin
if (a > b)
gt = 1'b1;
else if (a == b)
eq = 1'b1;
end
上面的if语句会生成类似如下的硬件结构,可以看到存在latch
解决上述引入latch的方法有以下2种:
修改后的代码如下所示
// 方法1 always @* begin if (a > b) begin gt = 1'b1; eq = 1'b0; end else if (a == b) begin gt = 1'b1; eq = 1'b1; end else begin gt = 1'b0; eq = 1'b0; end end // 方法2 // 如果gt和eq之后未赋值,则认为是0 always @* begin gt = 1'b0; // gt的默认赋值 eq = 1'b0; // eq的默认赋值 if (a > b) begin gt = 1'b1; end else if (a == b) begin eq = 1'b1; end end
方法1对应的硬件电路如下所示
方法2对应的硬件电路如下所示
当always块用于描述组合逻辑电路时,一定要确保always块的敏感信号列表完整,即必须包含该块所有的输入信号,其基本的语法格式有以下三种
always @(a or b or c)
always @(a, b, c)
alway @*
当always块用于描述组合逻辑电路时,如果存在不完整分支和不完整输出赋值,则可能引入latch
在设计电路的时候可以对资源进行重排,降低延迟。如下图所示,A信号到来比较晚,可以将它尽可能放在后面,从而尽可能隐藏其延迟。
assign a = (b=1)? ((c && d) ? 1'b1:1'b0) : 1'b0;
上面的代码难以阅读,且多层嵌套后很难被综合器解释,尽量将逻辑运算放在always块中,assign更多用于信号连接
建议分开异步逻辑与同步逻辑,避免综合时的问题,简化约束和编码难度
建议控制逻辑和存储器逻辑分成独立的模块,便于高层的存储器模块的使用和便于重新描述为不同的存储器类型
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。