這次介紹一些有關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選項的話也會生成鎖存器。