奇技淫巧我不會,但我這有一些我工作后才學(xué)到的一些Verilog寫法。
數(shù)字電路設(shè)計主要就是,選擇器、全加器、比較器,幾個常用邏輯門,再加個D觸發(fā)器,電路基本都能實現(xiàn)了。寫代碼其實是個體力活,電路和時序圖應(yīng)該在設(shè)計階段就已經(jīng)到了你的文檔里或在腦子里沒來得及寫出來。組合邏輯+時序邏輯
assign或always@(*)
always@(posedge clk or negedge rst_n)
有人說掌握Verilog 20%的語法就可以描述 90%以上的電路,說的對。
casez
always @(*)begin
casez(code)
8'b1???_???? : data[2:0] = 3'd7;
8'b01??_???? : data[2:0] = 3'd6;
8'b001?_???? : data[2:0] = 3'd5;
8'b0001_???? : data[2:0] = 3'd4;
8'b0000_1??? : data[2:0] = 3'd3;
8'b0000_01?? : data[2:0] = 3'd2;
8'b0000_001? : data[2:0] = 3'd1;
8'b0000_0001 : data[2:0] = 3'd0;
default : data[2:0] = 3'd0;
endcase
end
這樣的case有優(yōu)先級選擇,可綜合,實際項目可以使用,不過我個人習(xí)慣上還是,有優(yōu)先用if-else,沒有直接用case。synopsys的EDA工具有關(guān)于full case與parallel case可以查看下面博客鏈接。https://blog.csdn.net/li_hu/article/details/10336511 generate+for
合理使用generate+for循環(huán)可以提高編碼效率,同樣的賦值語句需要賦值多次。generate
genvar i;
for(i=0;i<16;i=i+1)
begin: neg_data
assign neg_data_out[i*DATA_WIDTH +:DATA_WIDTH] =
-data_in[i*DATA_WIDTH +:DATA_WIDTH]
end
endgenerate
?同一個模塊需要實例化多次
generate
genvar i;
0;i<16;i=i+1) =
begin: mult_12x12
DW02_mult #(
.A_WIDTH(12),
.B_WIDTH(12)
u_DW02_mult0(
+:12]),
+:12]),
.TC(1'b0),
+:24])
);
end
endgenerate
當(dāng)然這樣寫debug會有一些困擾,Verdi會顯示每一個generate塊,選中對應(yīng)的塊,加進去的波形就會是對應(yīng)的bit信號。
generate if/case
做一些通用IP的方法,隨便舉個例子比如要做一個選擇器通用IP,支持二選一,三選一,四選一。generate if(MUX_NUM == 0)begin : mux4_1
always@(*)begin
case(sel[1:0])
2'b00:data_out = data_in0;
2'b01:data_out = data_in1;
2'b10:data_out = data_in2;
default:data_out = data_in3;
endcase
end
end else if(MUX_NUM = 1) begin : mux3_1
always@(*)begin
case(sel[1:0])
2'b00:data_out = data_in0;
2'b01:data_out = data_in1;
default:data_out = data_in2;
endcase
end
end else begin : mux2_1
always@(*)begin
case(sel[1:0])
2'b00:data_out = data_in0;
default:data_out = data_in1;
endcase
end
end endgenerate
generate case可以寫更多的分支
generate
case(MUX_NUM)
0:begin:mux_2
end
1:begin: mux_3
end
2:begin: mux_4
end
default:begin
end
endcase
end endgenerate
調(diào)用的時候只需要
mux #(
.MUX_NUM(0)
)
u_mux(
...
);
參數(shù)化定義
模塊化設(shè)計,功能模塊的劃分盡可能細,差別不大的代碼通過參數(shù)化達到重復(fù)使用的目的。always @(*)begin
case(sel)
CASE0:data_out = data_in0;
CASE1:data_out = data_in1;
CASE2。。。
default:;
endcase
end
實例化
mux #(
.CASE0(8'd11),
.CASE1(8'd44)
...
)
u_mux(
...
);
移位操作
對于移位操作直接用位拼接assign data_shift[6:0] = data[4:0] << 2;
assign data_shift[7:0] = data[4:0] << shift[1:0];
寫成
assign data_shift[6:0] = {data[4:0], 2'b0};
always @(*)begin
case(shift[1:0])
2'b00: data_shift[7:0] = {3'b0, data[4:0]};
2'b01: data_shift[7:0] = {2'b0, data[4:0], 1'b0};
2'b10: data_shift[7:0] = {1'b0, data[4:0], 2'b0};
default:data_shift[7:0] = {data[4:0], 3'b0};
endcase
end
如果是有符號數(shù),高位要補符號位。也就是算術(shù)移位。
always @(*)begin
case(shift[1:0])
2'b00: data_shift[7:0] = {{3{data[4]}}, data[4:0]};
2'b01: data_shift[7:0] = {{2{data[4]}}, data[4:0], 1'b0};
2'b10: data_shift[7:0] = {data[4], data[4:0], 2'b0};
default:data_shift[7:0] = {data[4:0], 3'b0};
endcase
end
shift也可能是有符號數(shù),正數(shù)左移,負數(shù)右移。右移方法同理。
$clog2系統(tǒng)函數(shù)
Verilog-2005引入了$clog2系統(tǒng)函數(shù),為了方便計算數(shù)據(jù)位寬,避免位浪費。(這個是拿來湊字?jǐn)?shù)的)parameter DATA_WIDTH = 4,
parameter CNT_WIDTH = log2(DATA_WIDTH)
parameter CNT_WIDTH = clog2(DATA_WIDTH-1)
parameter CNT_WIDTH = $clog2(DATA_WIDTH)
reg [DATA_WIDTH-1:0] data_r0;
reg [CNT_WIDTH-1:0] cnt;
//-------------------------------------------------------
//以下兩個函數(shù)任用一個
//求2的對數(shù)函數(shù)
function integer log2;
input integer value;
begin
value = value-1;
for (log2=0; value>0; log2=log2+1)
value = value>>1;
end
endfunction
//求2的對數(shù)函數(shù)
function integer clogb2 (input integer bit_depth);
begin
for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
bit_depth = bit_depth>>1;
end
endfunction
對齊
tab鍵還是空格鍵?留言區(qū)說出你的故事。我把編輯器設(shè)置成tab自動替換成4個空格。 用空格對齊代碼,提高代碼觀賞性。assign signal_b = signal_a;
assign data_b = data_a;
assign cs_en = 1'b1;
assign signal_b = signal_a;
assign data_b = data_a;
assign cs_en = 1'b1;
第二種寫法更美觀,always塊里面的語句也應(yīng)該對齊。
命名
給模塊起名字,給信號起名字,真的很難,但是不管怎樣都不要用拼音,會遭人鄙視。是的,我見過!
階梯式assign
assign data_out[5:0] = data_vld0 ? data0[5:0] :
data_vld1 ? data1[5:0] :
data_vld2 ? data2[5:0] :
data_vld3 ? data3[5:0] : 6'b0;
由于if-else和case不能傳播不定態(tài),有的EDA工具有X態(tài)傳播選項,可以強行傳播,但是并不是所有的EDA工具都有這個功能,所以有些書上建議都用組合邏輯用assign。 這種寫法沒什么問題,但是有一點,覆蓋率不好收,如果一些情況沒跑到需要一個個分析。覆蓋率會把數(shù)據(jù)信號當(dāng)作一個情況列出來,比如數(shù)據(jù)信號data沒出現(xiàn)過0 的情況,實際上數(shù)據(jù)信號沒出現(xiàn)0的情況是正常的,這就要你一個一個的exclude掉。 所以不要寫很長的assign做選擇器,有優(yōu)先級用if-else,或根據(jù)具體情況用case。這樣哪一行哪一種情況沒跑到會一目了然。當(dāng)然if中的條件太多,覆蓋率也不好收,條件太多組合的情況多,分析起來繁瑣。如果上述信號的vld不同時出現(xiàn)也可以采用這種寫法,減少cell的使用數(shù)量。這樣也是有覆蓋率的問題,這只是一種特殊情況,很長的assign選擇器盡量不要寫。
assign data_out[5:0] = ({6{data_vld0}} & data0[5:0])
| ({6{data_vld1}} & data1[5:0])
| ({6{data_vld2}} & data2[5:0])
| ({6{data_vld0}} & data3[5:0]);
關(guān)于X態(tài)傳播,一定要注意,帶有reset的寄存器面積和時序會稍微差一些,控制通路的寄存器必須帶有復(fù)位,數(shù)據(jù)通路的寄存器可以不帶復(fù)位,但是要注意使用時如果使用數(shù)據(jù)通路的數(shù)據(jù)去做了控制條件,就必須要復(fù)位,否則如果X態(tài)沒有查出來,事情就大了。
布線太密的原因
寄存器位寬太大。reg [10000-1:0] data;
這樣寫在功能上沒什么問題,但是如果你之后有對這個數(shù)據(jù)做了很多邏輯,可能會造成后端布線太密,從后端的角度看到其實cell數(shù)量并不多,就是線比較密,比如說這個數(shù)據(jù)后面再放個選擇器,或者輸出給其他模塊,就相當(dāng)于一萬根線連到很多地方,布線很緊張,如果時序有問題需要繞線,或者需要ECO,做成的可能性很小。
盡量不要這樣做邏輯,除非對面積沒限制,要么最后只能改架構(gòu)。
第二個原因是負載太大。同一個信號在很多地方使用,布線也會變復(fù)雜,比如最常見的是參數(shù)信號,在很多模塊都會有用到的情況,用寄存器復(fù)制的方法。always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
data_para0 <= 4'b0;
data_para1 <= 4'b0;
data_para2 <= 4'b0;
end
else begin
data_para0 <= data_para;
data_para1 <= data_para;
data_para2 <= data_para;
end
end
畫倆圖大概意思一下。這樣每個寄存器的驅(qū)動變少。


有網(wǎng)友提到這樣子寫被綜合掉的概率也是很大。所以就只能在設(shè)計時盡量注意負載的問題。
加比選
面積:加法器 > 比較器 > 選擇器乘法器本質(zhì)上也是全加器。所以就有先選后比,先選后加,先選后乘。assign sum[4:0] = enable ? (data_a + data_b) : (data_c + data_d);
assign add_a[3:0] = enable ? data_a : data_c;
assign add_b[3:0] = enable ? data_b : data_d;
assign sum[4:0] = add_a + add_b;
畫個圖意思一下。


數(shù)據(jù)通路與控制通路
數(shù)據(jù)通路打拍可以不帶復(fù)位,帶著使能信號去打拍,減少信號翻轉(zhuǎn),減少功耗。保證數(shù)據(jù)用的時候不是X態(tài), 組合邏輯路徑是否需要插入pipeline,插入pipeline的位置需要注意。寄存器能少用就少用。 盡量不要用除法,首先除法器面積更大,除法也會有余數(shù),余數(shù)是否需要保留就很麻煩。除以常數(shù)可以做成乘以定點常數(shù)的方法。 乘以常數(shù)用移位加,也可直接用*號。例如a * 2‘d3,工具會幫你優(yōu)化成 a << 2’d1 + a。甚至可能優(yōu)化得更好。(杠:不要過度依賴工具)。關(guān)于用移位加還是*號的問題,博主做過綜合后的面積對比,相對來說,工具還是優(yōu)化那么一點點。直接用 * 號吧。 盡量不要用減法,減法要考慮到減翻的問題,盡量用加法。方案設(shè)計
方案最重要,一個好的方案往往事半功倍。 狀態(tài)機設(shè)計要狀態(tài)明確,一個狀態(tài)盡量只做一件事情。狀態(tài)機大法好。 做成IP化設(shè)計,功能分割盡量獨立并可復(fù)用性,相同的功能用同一塊IP,保證IP的沒問題,最后像搭積木一樣,搭建起數(shù)字系統(tǒng)。多積累些常用IP,常用的一些寫法的代碼。審核編輯 :李倩
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。
舉報投訴
-
寄存器
+關(guān)注
關(guān)注
31文章
5493瀏覽量
127705 -
比較器
+關(guān)注
關(guān)注
14文章
1869瀏覽量
110816 -
Verilog
+關(guān)注
關(guān)注
30文章
1368瀏覽量
113502
原文標(biāo)題:Verilog有什么奇技淫巧?
文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
熱點推薦
數(shù)字電路—22、時序邏輯電路
時序電路的邏輯功能可用邏輯表達式、狀態(tài)表、卡諾圖、狀態(tài)圖、時序圖和邏輯圖6種方式表示,這些表示方法在本質(zhì)上是相同的,可以互相轉(zhuǎn)換
發(fā)表于 03-26 15:03
CMOS邏輯IC是如何構(gòu)成的
電子設(shè)備正常運轉(zhuǎn)離不開“邏輯”的精密驅(qū)動。例如,當(dāng)我們在手機上滑動屏幕時,背后就有無數(shù)個CMOS邏輯電路在默默工作,它們通過復(fù)雜的邏輯運算,將我們的觸摸信號轉(zhuǎn)化為手機能夠理解的指令,從而實現(xiàn)各種功能。

解密邏輯單元與CoreScore得分的關(guān)系
FPGA 通過查找表 (LUT) 實現(xiàn)邏輯功能。這些 LUT 類似于真值表或卡諾圖 (Karnaugh map),F(xiàn)PGA 可以通過組合多個 LUT ,來實現(xiàn)幾乎任何你所需的邏輯功能。

Verilog 與 ASIC 設(shè)計的關(guān)系 Verilog 代碼優(yōu)化技巧
Circuit,專用集成電路)設(shè)計是一個復(fù)雜的過程,涉及到邏輯設(shè)計、綜合、布局布線、物理驗證等多個環(huán)節(jié)。在這個過程中,Verilog被用來描述數(shù)字電路的行為和結(jié)構(gòu),進而實現(xiàn)ASIC的設(shè)計。 具體來說
如何使用 Verilog 進行數(shù)字電路設(shè)計
首先,你需要清楚地了解你的數(shù)字電路需要實現(xiàn)什么功能。這可能包括輸入輸出的數(shù)量、數(shù)據(jù)寬度、時鐘頻率、時序要求等。明確的需求是設(shè)計成功的關(guān)鍵。 2. 設(shè)計邏輯電路 在明確了需求之后,你需要設(shè)計邏輯電路。這可以通過手繪
邏輯異或與異或門的工作原理
邏輯異或(Exclusive OR,簡稱XOR)與異或門的工作原理是數(shù)字邏輯電路中的核心概念。以下是對邏輯異或和異或門工作原理的介紹: 一、邏輯異或的定義
邏輯異或和邏輯或的比較分析
邏輯異或(Exclusive OR,簡稱XOR)和邏輯或(OR)是數(shù)字邏輯和編程中兩種基本的邏輯運算,它們各自具有獨特的功能和應(yīng)用場景。以下是對邏輯
邏輯異或的定義和應(yīng)用 邏輯異或與邏輯與的區(qū)別
邏輯異或(XOR,Exclusive OR)是一種二進制運算,其結(jié)果取決于兩個輸入值是否不同。如果兩個輸入值相同,結(jié)果為0(假);如果兩個輸入值不同,結(jié)果為1(真)。邏輯異或在計算機科學(xué)、數(shù)字邏輯
TTL邏輯門的種類及應(yīng)用
在數(shù)字電子領(lǐng)域,TTL(晶體管-晶體管邏輯)邏輯門是構(gòu)建復(fù)雜數(shù)字系統(tǒng)的基石。TTL技術(shù)以其可靠性、成本效益和廣泛的應(yīng)用而聞名。 TTL邏輯門的種類 TTL邏輯門可以分為基本的
簡單認識邏輯電路的用途
在數(shù)字電子的世界里,每一個決策、每一條指令、每一次數(shù)據(jù)處理,都離不開CMOS邏輯IC的掌控。CMOS邏輯IC大致包括兩種邏輯,即組合邏輯和
評論