这次介绍一些有关RTL综合的知识
组合逻辑综合
可综合的逻辑可由以下方式描述:
- 结构化的基本门网表
- 一系列连续赋值语句
- 一个电平敏感的周期性行为
门级网表综合
module test(
input a, b, c, d, e,
output y1_out, y2_out
);
wire y1, y2, y3, y4, y5, y6, y7, y8;
and (y1, a, c);
and (y2, a, d);
and (y3, a, e);
or (y4, y1, y2);
or (y1_out, y3, y4);
and (y5, b, c);
and (y6, b, d);
and (y7, b, e);
or (y8, y5, y6);
or (y2_out, y7, y8);
endmodule
综合后电路:
由图可看到编译器还自动把y4去除,使用了三输入或门
连续赋值语句
module or_nand(
input en, x1, x2, x3, x4,
output y
);
assign y = ~(en & (x1 | x2) & (x3 | x4));
endmodule
综合后的电路:
电平敏感周期行为
module comparator(
input [SIZE:0] a, b,
output reg a_gt_b, a_lt_b, a_eq_b
);
parameter SIZE = 2'd2;
//--------------------------------------------
integer k;
always@(a or b)
begin:compare_loop
for(k = 0; k < SIZE; k = k + 1)
begin
if(a[k] != b[k])
begin
a_gt_b <= a[k];
a_lt_b <= ~a[k];
a_eq_b <= 1'b0;
disable compare_loop;
end
end
a_gt_b <= 1'b0;
a_lt_b <= 1'b0;
a_eq_b <= 1'b1;
end
//--------------------------------------------
endmodule
综合后电路:
if和case语句的综合
if和case基本可以看做一致。一般,综合工具会判定case语句中的分支是否互不相同,如果这些选项是互不相同的,那么综合工具将认为它们具有相同的优先级别,并综合成一个MUX而不是优先级结构。甚至,当分支列表不是互不相同的时候,综合工具也允许用户决定是否以无优先权形式来处理。当if语句中的分支是用互不相同的条件指定时,该if语句会综合成MUX结构,但是分支并不是互不相同的情况下,综合工具会综合成一个优先级结构。
module test(
input a, b, c, d,
input [1:0] sel,
output reg y
);
//--------------------------------------------
always@(*)
begin
case(sel)
2'b00: y <= a;
2'b01: y <= b;
2'b10: y <= c;
2'b11: y <= d;
endcase
end
//--------------------------------------------
endmodule
case语句综合成了MUX结构,消耗了两个LE
module test(
input a, b, c, d,
input [1:0] sel,
output reg y
);
//--------------------------------------------
always@(*)
begin
if(sel == 2'b00) y <= a;
else if(sel == 2'b01) y <= b;
else if(sel == 2'b10) y <= c;
else y <= d;
end
//--------------------------------------------
endmodule
由上可见,RTL视图只是按照语言流程综合的,未经过任何优化,将其代码优化后生成的Technology Map视图可看作针对器件优化后的视图,if和case优化后的视图一致,可见两者在综合后的实现一样。
case casez casex的使用
case
case | 0 | 1 | x | z |
---|---|---|---|---|
0 | 1 | 0 | 0 | 0 |
1 | 0 | 1 | 0 | 0 |
x | 0 | 0 | 1 | 0 |
z | 0 | 0 | 0 | 1 |
casez
casez | 0 | 1 | x | z |
---|---|---|---|---|
0 | 1 | 0 | 0 | 1 |
1 | 0 | 1 | 0 | 1 |
x | 0 | 0 | 1 | 1 |
z | 1 | 1 | 1 | 1 |
casex
casex | 0 | 1 | x | z |
---|---|---|---|---|
0 | 1 | 0 | 1 | 1 |
1 | 0 | 1 | 1 | 1 |
x | 1 | 1 | 1 | 1 |
z | 1 | 1 | 1 | 1 |
1. 大多数情况下,一般使用casez语句,case语句用的也较少,强烈不推荐使用casex语句。不过需要说明的是,这三个case语句都是可综合的,都能生成RTL电路。
2. 在casez语句中,如果敏感信号表达式和分支表达式某些位的值(考虑对应二进制的情况下)为高阻态(即z或Z),那么对这些位的比较就会忽略,不予考虑,而只关注其他位的比较结果。
3. 在casex语句中,如果敏感信号表达式和分支表达式某些位的值(考虑对应二进制的情况下)为高阻态或不定态(即z或x),则在进行敏感信号表达式和分支值比较时,这些位不参与比较(也就是忽略该位),而只关注其他位的比较结果。
full_case语句
在case语句(含casez和casex)中,通常使用default选项来对分支选项中没有列举到的敏感信号表达式的值做统一的处理,从功能上看,如果不需要处理的分支值一般来说是我们不需要的功能,可以不写,但对于综合器来说,如果分支选项不全的话,对FPGA/CPLD硬件的资源的使用甚至是性能的使用是有影响的。
module test(
input [1:0] sel,
input [2:0] a,
output reg y
);
//--------------------------------------------
always@(*)
begin
casez(sel)
2'b00: y <= a[0];
2'b01: y <= a[1];
2'b10: y <= a[2];
endcase
end
//--------------------------------------------
endmodule
综合后的视图
然后加上default分支
- 从语法角度上看,这个case语句实现的是一个多路选择功能,这两个RTL图中也都体现出来了,唯独不同的是,在前一个RTL视图中,还多了一个y$latch!这是一个锁存器。也就是说,当case语句分支选项不全时,综合器会自动生成一个锁存器,一旦敏感表达式不和分支选项值都不同时,电路不会产生新的输出,而是保持上次电路的运行结果。
- 有时候,这种锁存器的功能我们不需要,但是它的产生占用了fpga资源。如果说不想使用default语句,也不想生成锁存器的话,可以采用综合属性full_case来避免锁存器的生成。
module test(
input [1:0] sel,
input [3:0] a,
output reg y
);
//--------------------------------------------
always@(*)
begin
casez(sel) //synthesis full_case
2'b00: y <= a[0];
2'b01: y <= a[1];
2'b10: y <= a[2];
endcase
end
//--------------------------------------------
endmodule
综合后
- 和带有default语句的几乎一样。但是需要说明的是,当sel为2’b11时,y输出不是0,而是随机值。在使用这个语句过程中,不要把sel端的外接输入的值设为2’b11。
- 所以,当分支选项不全时,case条件语句会生成锁存器。合理的使用综合属性可以避免锁存器,或者使用default分支项。同理,对于if条件语句来说,如果没有else选项的话也会生成锁存器。