通過(guò)spyglass等工具修正rtl lint問(wèn)題過(guò)程中,位寬不匹配問(wèn)題是一大類(lèi)很讓人頭疼的error和warning。很多時(shí)候可以根據(jù)經(jīng)驗(yàn)和項(xiàng)目組的要求進(jìn)行review和waive,但這些操作還是要基于比較清晰和正確的綜合工具對(duì)這些問(wèn)題處理方式的了解。于是借此機(jī)會(huì),對(duì)補(bǔ)位和截位的規(guī)則通過(guò)實(shí)驗(yàn)再明確一番。
case0:寬 = 窄自動(dòng)補(bǔ)位的場(chǎng)景,比如如下這段代碼:
module test #(parameter INP0 = 4, INP1 = 4, OUTP = 32)
(
input clk,
input rst_n,
input [INP0 -1:0]i_data0,
input [INP1 -1:0]i_data1,
output reg [OUTP -1:0]o_data
);
wire[OUTP -1:0]o_data_d = i_data1 * ((i_data0 + 1'b1) * 2'd3);
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
o_data {OUTP{1'b0}};
end
else begin
o_data o_data_d;
end
end
endmodule
輸入信號(hào)是是兩個(gè)4bit信號(hào),輸出為32bit,一定會(huì)報(bào)lint error的邏輯是這句:wire[OUTP -1:0]o_data_d = i_data1 * ((i_data0 + 1'b1) * 2'd3);
位寬是32bit = 4bit * ((4bit + 1bit) * 2bit) = 4bit * 7bit,還是通過(guò)DC+TSMC90 fast庫(kù)進(jìn)行一下綜合://///////////////////////////////////////////////////////////
// Created by: Synopsys DC Expert(TM) in wire load mode
// Version : O-2018.06-SP1
// Date : Wed Jul 24 15:00:53 2024
/////////////////////////////////////////////////////////////
而后我想看一下綜合后的門(mén)電路是如何處理,當(dāng)然謹(jǐn)慎的講綜合結(jié)果只供參考,畢竟這和工具以及庫(kù)應(yīng)該是有一定的關(guān)系的,對(duì)于后端我涉及不夠深入所以只擺一下結(jié)果。綜合結(jié)果中通過(guò)門(mén)電路綜合了一個(gè)乘法器,輸入分別為7bit和4bit,輸出為10bit:
module test_DW02_mult_0 ( A, B, PRODUCT );
input [6:0] A;
input [3:0] B;
output [10:0] PRODUCT;
...
XOR2X8 U63 ( .A(n29), .B(n28), .Y(PRODUCT[9]) );
endmodule
分析代碼可以看到,輸出的10個(gè)bit都是有驅(qū)動(dòng)的。后面在重映射的門(mén)級(jí)test模塊中,調(diào)用的情況如下:module test ( clk, rst_n, i_data0, i_data1, o_data );
input [3:0] i_data0;
input [3:0] i_data1;
output [31:0] o_data;
input clk, rst_n;
wire N8, N7, N5, N10, n43, n44, n45, n46, n47, n48, n49, n50, n51, n52,
n53, n54, n55, n56, n57, n58, n59, n60, n61, n62, n63, n64, n65, n66,
n67, n68, n69;
wire [10:0] o_data_d;
test_DW02_mult_0 mult_9_2 ( .A({1'b0, N10, n69, N8, N7, n46, N5}), .B({
i_data1[3], n50, n49, i_data1[0]}), .PRODUCT(o_data_d) );
DFFRQX2 o_data_reg_0_ ( .D(o_data_d[0]), .CK(clk), .RN(rst_n), .Q(o_data[0])
);
...
DFFRHQX4 o_data_reg_9_ ( .D(o_data_d[9]), .CK(clk), .RN(rst_n), .Q(o_data[9]) );
INVX2 U24 ( .A(1'b1), .Y(o_data[11]) );
...
INVX2 U64 ( .A(1'b1), .Y(o_data[31]) );
...
XOR2X8 U96 ( .A(n65), .B(n66), .Y(n69) );
endmodule
test_DW02_mult_0的A端口對(duì)應(yīng)的是((i_data0 + 1'b1) * 2'd3),i_data0在邏輯電路中被映射為{1'b0, N10, n69, N8, N7, n46, N5},比如簡(jiǎn)單看一個(gè)邏輯鏈:
BUFX12 U89 ( .A(i_data0[3]), .Y(n54) );
CLKINVX6 U73 ( .A(n54), .Y(n64) );
CLKAND2X12 U85 ( .A(n45), .B(n54), .Y(N10) );
而B(niǎo)端口對(duì)應(yīng)的就是i_data1:
.B({i_data1[3], n50, n49, i_data1[0]})
BUFX8 U88 ( .A(i_data1[1]), .Y(n49) );
BUFX12 U90 ( .A(i_data1[2]), .Y(n50) );
而輸出則是連接到中間信號(hào)o_data_d,在原始代碼里定義o_data_d的位寬為32bit,但在綜合后的信號(hào)只有11bit。
wire [10:0] o_data_d;
這是非常合理當(dāng)然也是符合我們的預(yù)期的,而后11bit的o_data_d驅(qū)動(dòng)了32bit的o_data低11bit:
DFFRQX2 o_data_reg_0_ ( .D(o_data_d[0]), .CK(clk), .RN(rst_n), .Q(o_data[0])
);
DFFRQX1 o_data_reg_5_ ( .D(o_data_d[5]), .CK(clk), .RN(rst_n), .Q(o_data[5])
);
DFFRQX1 o_data_reg_4_ ( .D(o_data_d[4]), .CK(clk), .RN(rst_n), .Q(o_data[4])
);
...
而o_data高21比特則被驅(qū)動(dòng)為常0:
INVX2 U24 ( .A(1'b1), .Y(o_data[11]) );
INVX2 U26 ( .A(1'b1), .Y(o_data[12]) );
INVX2 U28 ( .A(1'b1), .Y(o_data[13]) );
case1:窄 = 寬自動(dòng)截位的場(chǎng)景,使用的代碼如下:
module test #(parameter INP0 = 7, INP1 = 16, OUTP = 16)
(
input clk,
input rst_n,
input [INP0 -1:0]i_data0,
input [INP1 -1:0]i_data1,
output reg [OUTP -1:0]o_data
);
wire[OUTP -1:0]o_data_d = i_data1 * i_data0;
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
o_data {OUTP{1'b0}};
end
else begin
o_data o_data_d;
end
end
endmodule
16bit = 16bit * 7bit,綜合后有一個(gè)乘法器test_DW02_mult_0,其實(shí)里面還調(diào)用了綜合出的一個(gè)加法器test_DW01_add_1,不過(guò)其內(nèi)部代碼不影響分析就不放在這了。
module test_DW02_mult_0 ( A, B, PRODUCT );
input [6:0] A;
input [15:0] B;
output [22:0] PRODUCT;
test_DW01_add_1 FS_1 ( .A({1'b0, A1_19_, A1_18_, A1_17_, A1_16_, A1_15_,
A1_14_, A1_13_, A1_12_, A1_11_, A1_10_, A1_9_, A1_8_, A1_7_, A1_6_,
A1_5_, SUMB_6__0_, A1_3_, A1_2_, A1_1_, A1_0_}), .B({n11, n16, n15,
n14, n13, n12, A2_14_, n10, n39, n43, n40, n42, A2_8_, n41, n38, 1'b0,
1'b0, 1'b0, 1'b0, 1'b0, 1'b0}), .SUM({SYNOPSYS_UNCONNECTED_1,
SYNOPSYS_UNCONNECTED_2, SYNOPSYS_UNCONNECTED_3, SYNOPSYS_UNCONNECTED_4,
SYNOPSYS_UNCONNECTED_5, SYNOPSYS_UNCONNECTED_6, SYNOPSYS_UNCONNECTED_7,
PRODUCT[15:2]}) );
...
XOR2XL U165 ( .A(ab_1__0_), .B(ab_0__1_), .Y(PRODUCT[1]) );
NOR2BXL U216 ( .AN(B[0]), .B(n8), .Y(PRODUCT[0]) );
endmodule
PRODUCT的位寬定義雖然是23bit,但是只有PRODUCT[15:0]被賦值因?yàn)樽詈蟮妮敵鍪?6bit,所以這里進(jìn)行了截?cái)唷拇a里也能看到是計(jì)算結(jié)果時(shí)進(jìn)行截?cái)嗟,并沒(méi)有提前截?cái)嘈盘?hào)i_data1:
NOR2BXL U82 ( .AN(B[15]), .B(n49), .Y(ab_0__15_) );
case2:窄 = 寬 * 窄module test #(parameter INP0 = 7, INP1 = 8, OUTP = 12)
(
input clk,
input rst_n,
input [INP0 -1:0]i_data0,
input [INP1 -1:0]i_data1,
output reg [OUTP -1:0]o_data
);
wire[2*INP0 -1:0]i_data0_db = i_data0 * i_data0;
wire[OUTP -1:0]o_data_d = i_data1 * i_data0_db;
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
o_data {OUTP{1'b0}};
end
else begin
o_data o_data_d;
end
end
endmodule
o_data_d = i_data1 * i_data0_db這句的位寬是12bit = 8bit * 14bit,綜合是還是以門(mén)級(jí)電路綜合出了模塊test_DW02_mult_1:
module test_DW02_mult_1 ( B, PRODUCT );
input [6:0] B;
output [13:0] PRODUCT;
...
XOR3X4 U48 ( .A(A1_9_), .B(n57), .C(n84), .Y(PRODUCT[11]) );
...
endmodule
觀察代碼還是會(huì)發(fā)現(xiàn),乘法模塊輸出最高賦值到bit[11],顯然這是對(duì)齊到后面的第二步乘法操作輸出值位寬的。也就是說(shuō)跟之前的經(jīng)驗(yàn)一樣,不管在這里定義了多大的位寬都會(huì)根據(jù)最后需要進(jìn)行中間截位的。
綜合出的第二個(gè)乘法器已經(jīng)把輸入位寬限定在了12bit,但是仍然給了一個(gè)位寬充分的輸出:
module test_DW02_mult_0 ( A, B, PRODUCT );
input [11:0] A;
input [7:0] B;
output [19:0] PRODUCT;
...
XOR3X4 S4_0 ( .A(ab_11__0_), .B(CARRYB_10__0_), .C(SUMB_10__1_), .Y(
PRODUCT[11]) );
...
endmodule
跟前面一樣,乘法器雖然定義了輸出位寬為20bit,但是只驅(qū)動(dòng)了12bit。最后整體的綜合后test簡(jiǎn)單看下就好了,和之前沒(méi)有太大區(qū)別: test_DW02_mult_1 mult_9 ( .B({n15, n14, n13, n12, n11, n10, n9}), .PRODUCT({
SYNOPSYS_UNCONNECTED_1, SYNOPSYS_UNCONNECTED_2, i_data0_db_11_,
i_data0_db_10_, i_data0_db_9_, i_data0_db_8_, i_data0_db_7_,
i_data0_db_6_, i_data0_db_5_, i_data0_db_4_, i_data0_db_3_,
i_data0_db_2_, SYNOPSYS_UNCONNECTED_3, i_data0_db_0_}) );
test_DW02_mult_0 mult_10 ( .A({i_data0_db_11_, i_data0_db_10_, i_data0_db_9_,
i_data0_db_8_, i_data0_db_7_, n1, n2, n3, i_data0_db_3_, i_data0_db_2_,
1'b0, i_data0_db_0_}), .B({i_data1[7], n8, n7, n6, n5, n4,
i_data1[1:0]}), .PRODUCT({SYNOPSYS_UNCONNECTED_4,
SYNOPSYS_UNCONNECTED_5, SYNOPSYS_UNCONNECTED_6, SYNOPSYS_UNCONNECTED_7,
SYNOPSYS_UNCONNECTED_8, SYNOPSYS_UNCONNECTED_9,
SYNOPSYS_UNCONNECTED_10, SYNOPSYS_UNCONNECTED_11, o_data_d}) );
然后我又順便測(cè)試了一下把兩步計(jì)算合成一步是否會(huì)有區(qū)別(因?yàn)樾辧int時(shí)總會(huì)有類(lèi)似的操作,為了避免位寬error會(huì)拆分計(jì)算式進(jìn)行位寬對(duì)齊):
wire[OUTP -1:0]o_data_d = (i_data0 * i_data0) * i_data1;
然后綜合看了下,和拆分寫(xiě)果然是沒(méi)有區(qū)別的。第一個(gè)乘法器i_data0自己乘自己的這個(gè),只驅(qū)動(dòng)12bit:
module test_DW02_mult_1 ( B, PRODUCT );
input [6:0] B;
output [13:0] PRODUCT;
...
XOR3X4 U48 ( .A(A1_9_), .B(n58), .C(n85), .Y(PRODUCT[11]) );
...
endmodule
第二個(gè)乘法器也只驅(qū)動(dòng)12bit,和預(yù)期一致:
module test_DW02_mult_0 ( A, B, PRODUCT );
input [11:0] A;
input [7:0] B;
output [19:0] PRODUCT;
...
XOR3X4 S4_0 ( .A(ab_11__0_), .B(CARRYB_10__0_), .C(SUMB_10__1_), .Y(
PRODUCT[11]) );
...
endmodule
可見(jiàn)這種拆分或者合并的邏輯表達(dá)式,除了規(guī)避lint之外對(duì)電路的最終實(shí)現(xiàn)應(yīng)當(dāng)是沒(méi)有區(qū)別的。
case3:寬 + 窄不同位寬的信號(hào)進(jìn)行操作根據(jù)剛剛的實(shí)驗(yàn)其實(shí)已經(jīng)比較明確了:會(huì)綜合出一個(gè)滿(mǎn)位寬的加法器/乘法器/...,但是根據(jù)最終的結(jié)果位寬進(jìn)行截?cái)。不過(guò)這個(gè)補(bǔ)充實(shí)驗(yàn)我想進(jìn)一步明確下,當(dāng)寬窄信號(hào)進(jìn)行操作時(shí)的確不會(huì)出現(xiàn)很多人擔(dān)心的寬信號(hào)被截?cái)嗟秸粚挼那闆r。
module test #(parameter INP0 = 7, INP1 = 10, OUTP = 9)
(
input clk,
input rst_n,
input [INP0 -1:0]i_data0,
input [INP1 -1:0]i_data1,
output reg [OUTP -1:0]o_data
);
wire[OUTP -1:0]o_data_d = i_data0 + i_data1;
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
o_data {OUTP{1'b0}};
end
else begin
o_data o_data_d;
end
end
endmodule
9bit = 7bit+10bit,綜合之后是一個(gè)9bit的加法器:
module test_DW01_add_1 ( A, B, SUM );
input [8:0] A;
input [8:0] B;
output [8:0] SUM;
...
endmodule
而后在頂層調(diào)用時(shí)可以明確:
test_DW01_add_1 add_9 ( .A({1'b0, 1'b0, i_data0[6:1], n3}), .B({i_data1[8:1],
n2}), .SUM(o_data_d) );
位寬7bit的輸入信號(hào)i_data0補(bǔ)了2bit的0作為9bit傳遞給test_DW01_add_1,而位寬10bit的輸入信號(hào)i_data1則是截?cái)酁閕_data1[8:0]的9bit信號(hào)傳遞給test_DW01_add_1。因此可以確定的是,信號(hào)的截?cái)啵ㄒ约把a(bǔ)0)確實(shí)是根據(jù)最終的輸出位寬來(lái)決定的,而不會(huì)根據(jù)參與運(yùn)算的窄信號(hào)截?cái)唷?br />
case4:有符號(hào)數(shù)最后這一部分是對(duì)之前文章的一個(gè)確認(rèn)驗(yàn)證。看下同樣的代碼,對(duì)于有符號(hào)數(shù)綜合時(shí)是如何處理的。對(duì)剛剛的代碼做一點(diǎn)修改,輸入輸出都設(shè)置為signed:
module test #(parameter INP0 = 7, INP1 = 10, OUTP = 9)
(
input clk,
input rst_n,
input signed[INP0 -1:0]i_data0,
input signed[INP1 -1:0]i_data1,
output reg signed[OUTP -1:0]o_data
);
wire[OUTP -1:0]o_data_d = i_data0 + i_data1;
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
o_data 而后在綜合后調(diào)用test_DW01_add_1時(shí)就能看到符號(hào)位拓展了:
test_DW01_add_1 add_9 ( .A({n5, n5, n5, i_data0[5:2], n2, n4}), .B({
i_data1[8:1], n3}), .SUM(o_data_d) );
BUFX2 U6 ( .A(i_data0[6]), .Y(n5) );而且還能看到的是,綜合工具以及實(shí)際電路里哪有什么signed和unsigned:
module test ( clk, rst_n, i_data0, i_data1, o_data );
input [6:0] i_data0;
input [9:0] i_data1;
output [8:0] o_data;
input clk, rst_n;
wire n2, n3, n4, n5;
wire [8:0] o_data_d;
...
endmodule
系列文章入口——
【芯片設(shè)計(jì)】SoC 101(一):緒論 | 【芯片設(shè)計(jì)】FIFO漫談(零)從無(wú)處不在的FIFO開(kāi)始說(shuō)起 | 【芯片設(shè)計(jì)】計(jì)算機(jī)體系結(jié)構(gòu)(一)虛擬內(nèi)存 | 【芯片設(shè)計(jì)】深入理解AMBA總線(零)緒論
| 【芯片設(shè)計(jì)】握手協(xié)議的介紹與時(shí)序說(shuō)明 | 【芯片設(shè)計(jì)】復(fù)位那些小事 —— 復(fù)位消抖 | 【芯片設(shè)計(jì)】快速入門(mén)數(shù)字芯片設(shè)計(jì)(一)Introduction | 【芯片驗(yàn)證】UVM源碼計(jì)劃(零)下定決心讀源碼前的自測(cè)環(huán)節(jié)
| 【芯片設(shè)計(jì)】異步電路碎碎念(一) 到底什么是異步電路
| 【芯片設(shè)計(jì)】從RTL到GDS(一):Introduction
| 其他文章鏈接——
【芯片驗(yàn)證】sva_assertion: 15道助力飛升的斷言練習(xí) | 【芯片驗(yàn)證】可能是RTL定向驗(yàn)證的巔峰之作 | 【芯片驗(yàn)證】RTL仿真中X態(tài)行為的傳播 —— 從xprop說(shuō)起 | 【芯片驗(yàn)證】年輕人的第一個(gè)systemVerilog驗(yàn)證環(huán)境全工程與解析 |
【芯片設(shè)計(jì)】verilog中有符號(hào)數(shù)和無(wú)符號(hào)數(shù)的本質(zhì)探究
| 【芯片設(shè)計(jì)】論RTL中always語(yǔ)法的消失術(shù) | 【芯片設(shè)計(jì)】代碼即注釋?zhuān)⑨尲创a | 【芯片設(shè)計(jì)】700行代碼的risc處理器你確實(shí)不能要求太多了 |
入職芯片開(kāi)發(fā)部門(mén)后,每天摸魚(yú)之外的時(shí)間我們要做些什么呢 | 如何計(jì)算系統(tǒng)的outstanding 和 burst length? | 芯片搬磚日!け扑缽(qiáng)迫癥的關(guān)鍵詞不對(duì)齊事件 | 熟人社會(huì)里,一群沒(méi)有社會(huì)價(jià)值的局外人 |
|