组合逻辑和时序逻辑的综合

综合工具工作的步骤:

  1. 检测并消除冗余逻辑
  2. 查找组合反馈回路
  3. 利用无关紧要条件
  4. 检测出未使用的状态
  5. 查找并消除等价的状态;
  6. 进行状态分配;
  7. 在满足物理工艺的面积、速度限制的条件下,综合出最优的多级逻辑实现。既包括了最优化技术,又包括了工艺映射。

1. 综合简介

电路模型可以分成三个层次:**架构级(architectural level model)逻辑级(logic level model)物理级(physical level model)**。

架构级:必须由电路执行的、将一组输入转换成输出的操作,不与时钟相关联。架构的内部组成可以由不同结构的、互连的、同步的功能单元来实现(我认为是功能单元或模块的互联)。这里的设计关键是从架构描述中提取出一个实现所需功能的算法。

逻辑级:由电路实现的一组变量和一组布尔函数。它描述了寄存器资源和功能单元的架构、逻辑级的时序行为。这里的设计是将布尔逻辑转换成可满足功能的组合门电路和存储寄存器的最优化的网表。综合工具就是用来实现这一步的。综合工具先将Verilog代码翻译成布尔函数形式,然后进行优化、映射。

物理级:先不考虑。

从电路的高级别抽象模型到最终的物理实现。HDL可以对电路进行不同层次的描述来简化设计过程。

有三种描述层次:行为描述(behavioral)、结构描述(structral)、物理描述(physical)。

比如:一个架构模型的行为描述可以是定义一组数据变换的算法;同一个架构模型的结构描述是由实现这组算法的数据通路(寄存器、存储器、加法器等)和控制器组成(功能模块的组合)。一个逻辑级的行为描述包括状态转移图(STG)、算法状态机图(ASM)等;其结构描述是实现行为级所描述功能的门级网表。

其实这里不是很明白。直接从书上摘下来的。

2.1 逻辑综合

逻辑综合是将电路从逻辑级描述转换成结构描述,最终生成结构化的原语网表。

逻辑级描述是一组布尔方程。这些方程由连续赋值语句或等效的电平敏感的行为构成。

逻辑综合:

给定的原语网表 >> 优化的Verilog原语网表 >> 由目标工艺资源(asic单元)组成的等效电路。

综合工具的组成结构如下图:

综合要保证综合前后电路的等效性以及生成电路的可测性。

逻辑综合是进行逻辑优化,之后要进行性能优化,寻找在物理工艺上最优性能的电路。(比如功耗、面试、时序等)

2 组合逻辑的综合

可综合的组合逻辑有:

  1. 结构化的原语网表
  2. 一系列连续赋值语句
1
assign y = a & b;
  1. 电平敏感的周期性行为(无反馈、无锁存器
1
2
3
4
5
always@(a or b ) begin  //对于每个输入值都有对应的输出、
..... //逻辑中没有反馈回路、不生成锁存器
// case \if语句要写全
// 不能有时间控制语句 @ # 等
end

能够去除电路中的冗余逻辑。

2.1 优先级结构的综合

对于case和if语句,综合工具可能综合出有优先级的电路,也可能是没有优先级的电路,这要看HDL如何写的。

如果case语句中的*分支选项都是互斥***的,那么综合出 的电路没有优先级,会是个多路选择器结构。如果不是互斥的,那么case语句通常是对于首先匹配到的选项有高 的优先级,当然一般用的时候都是互斥结构。

如果if语句中的*分支选项是互斥***的,那么也不会出现优先级结构,而是多路选择器

1
2
3
4
5
6
7
8
9
10
11
12
/*
以下是一个会综合出优先级顺序的块。
因为sel_a与sel_b之间没有关系,if的分支选项不是互斥的。
比如,如果是没有优先级,当sel_a ==1 ,则y=a。此时sel_b也可能为1,那么y=b。没有优先级的话,
就不知道到底是匹配了哪一条分支。
所以要综合出优先级结构,且第一个条件分支的优先级最高。
*/
always@(sel_a or sel_b) begin
if(sel_a ==1 ) y = a;
else if (sel_b == 1) y = b;
else y = c;
end

2.2 ASIC资源共享

这跟编码风格有关。

1
2
3
4
// 一种 , 两个加法器
assign sum = sel ? (a+b) : (a+c);
// 另一中 , 一个加法器
assign sum = a + (sel ? b : c) ;

用括号来控制操作符分组来降低电路尺寸

比如下面的Verilog描述的加法器综合成ASIC库中的全加器,如下图中(a)所示,(b)图是为了提高速度而得到的另一种综合结果。(a)中的电路面积小于(b)。

1
2
3
module add_4(output [3:0] sum,output C,input [3:0]a,b,c);
assign {sum,C}=a+b+c;
endmodule

3 带锁存器的时序逻辑综合

无反馈的原语网表、连续赋值综合出无锁存器的组合逻辑。

带反馈的条件操作符综合出锁存器,如:

1
2
assign Out = (cs==0)?(we==0)?:In:Out:1'bz;
//如果cs==0,we==1,那么Out = Out,Out会被锁存。

3.1 无意综合出锁存器

综合出锁存器的情况:

  1. 电平敏感的always的敏感列表不全;
  2. if,case的分支条件不全;
  3. 带反馈的连续赋值语句。

4 三态总线接口的综合

三态输出端口

双向总线端口

5 带有触发器的时序逻辑综合

记着在阿里的实习面试的时候被问到,RTL中的reg变量都能综合处寄存器吗,在边沿触发的always中的reg变量都能被综合成寄存器吗?当时说reg只是Verilog语法,用来块语句中。至于沿触发的always中的reg变量可能会被综合工具优化掉。那个人说了句嗯,好像是表示同意。不过最后还是没有offer。

这一节的内容就能很好回答面试官的问题了

触发器仅由边沿敏感的always块综合而成,但并不是在边沿敏感的行为中的寄存器变量都被综合成触发器。

综合出触发器的情况——变量对存储有需求

  1. 该寄存器变量在行为描述范围以外被使用 (后面有例子)
  2. 该寄存器变量在未被赋值以前就在行为描述中用到 (后面有例子)
  3. 寄存器变量仅在行为的某些分支(if分支等)上被赋值。 (后面的例子好像不大实用)

在边沿敏感的行为语句中,如果if语句分支不完全,会综合出一个控制时钟使能的信号。这样即使在时钟变化时,寄存器变量也不会改变,除非满足分支条件,也就是时钟使能了。

1
2
3
4
5
always@(posedge clk)
begin
if(enable) data_out <= data_in;
// enable 信号控制时钟使能,enable有效,data_out改变,否则data_out被存储起来。
end
  • 寄存器变量在边沿触发的行为块之外被使用,那么综合工具会综合出触发器。如果没被使用,那么综合工具会忽略,不会综合出触发器
1
2
3
4
5
6
7
8
9
module test(    input clk,    input a,    output b    );
reg b_r;
reg e_r;
assign b = b_r;
always@(posedge clk) begin
b_r <= a;
e_r <= a;
end
endmodule

寄存器变量b_r在always块之外用到了,给到了输出端。e_r没有被用到,所以vivado综合忽略了e_r寄存器变量,只为b_r生成一个触发器。如下图:

  • 寄存器变量在未被赋值以前就在边沿触发的块中被用到,会生成触发器

    b_r寄存器变量在快语句之外没有被使用

1
2
3
4
5
6
7
8
9
module test(    input clk,    input a,    output b    );
reg b_r;
reg e_r;
assign b = b_r;
always@(posedge clk) begin
b_r <= e_r; //e_r在被赋值以前在always块中被用到
e_r <= a;
end
endmodule

如果e_r先被赋值,然后被使用,也会综合出触发器。网表与上面一样。

1
2
3
4
5
6
7
8
9
module test(    input clk,    input a,    output b    );
reg b_r;
reg e_r;
assign b = b_r;
always@(posedge clk) begin
e_r <= a;
b_r <= e_r; //e_r先赋值再使用
end
endmodule

但如果不给e_r赋值,则不会出现触发器

1
2
3
4
5
6
7
8
module test(    input clk,    input a,    output b    );
reg b_r;
reg e_r;
assign b = b_r;
always@(posedge clk) begin
b_r <= e_r; //不给e_r赋值
end
endmodule

所以应该改成寄存器变量被赋值,也被使用,那么就生成触发器,若只满足其一,不行。

  • 寄存器变量仅在行为描述的某些分支上出现,但在行为之外没有被使用,不能综合处触发器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module test(    input clk,    input a,    input sel,    output b    );
reg b_r;
reg e_r;
reg f_r;
assign b = b_r;
always@(posedge clk) begin
b_r <= a;
if(sel) begin e_r <= a;f_r <= a;end
else f_r <= ~a; //e_r只出现在if的一条分支上
end
endmodule
// 两个电路的综合结果一样
module test( input clk, input a, input sel, output b );
reg b_r;
reg e_r;
assign b = b_r;
always@(posedge clk) begin
b_r <= a;
if(sel) begin e_r <= a;end
//e_r只出现在if的一条分支上
end
endmodule

无论是e_r只出现在if的部分分支,还是f_r出现在if的所有分支,都不能综合出触发器。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!