奇技淫巧我不會,但我這有一些我工作后才學到的一些Verilog寫法。
數字電路設計主要就是,選擇器、全加器、比較器,幾個常用邏輯門,再加個D觸發器,電路基本都能實現了。寫代碼其實是個體力活,電路和時序圖應該在設計階段就已經到了你的文檔里或在腦子里沒來得及寫出來。組合邏輯+時序邏輯
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; endcaseend這樣的case有優先級選擇,可綜合,實際項目可以使用,不過我個人習慣上還是,有優先用if-else,沒有直接用case。synopsys的EDA工具有關于full case與parallel case可以查看下面博客鏈接。https://blog.csdn.net/li_hu/article/details/10336511 generate+for
合理使用generate+for循環可以提高編碼效率,同樣的賦值語句需要賦值多次。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] endendgenerate?同一個模塊需要實例化多次
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]) ); endendgenerate當然這樣寫debug會有一些困擾,Verdi會顯示每一個generate塊,選中對應的塊,加進去的波形就會是對應的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 endend 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 endend else begin : mux2_1 always@(*)begin case(sel[1:0]) 2'b00:data_out = data_in0; default:data_out = data_in1; endcase endend endgenerategenerate case可以寫更多的分支
generate case(MUX_NUM) 0:begin:mux_2 end 1:begin: mux_3 end 2:begin: mux_4 end default:begin end endcaseend endgenerate調用的時候只需要
mux #( .MUX_NUM(0))u_mux( ...);參數化定義
模塊化設計,功能模塊的劃分盡可能細,差別不大的代碼通過參數化達到重復使用的目的。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}; endcaseend如果是有符號數,高位要補符號位。也就是算術移位。
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}; endcaseendshift也可能是有符號數,正數左移,負數右移。右移方法同理。
$clog2系統函數
Verilog-2005引入了$clog2系統函數,為了方便計算數據位寬,避免位浪費。(這個是拿來湊字數的)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; //-------------------------------------------------------//以下兩個函數任用一個//求2的對數函數function integer log2; input integer value; begin value = value-1; for (log2=0; value>0; log2=log2+1) value = value>>1; endendfunction //求2的對數函數function integer clogb2 (input integer bit_depth);begin for(clogb2=0; bit_depth>0; clogb2=clogb2+1) bit_depth = bit_depth>>1;endendfunction對齊
tab鍵還是空格鍵?留言區說出你的故事。我把編輯器設置成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塊里面的語句也應該對齊。
命名
給模塊起名字,給信號起名字,真的很難,但是不管怎樣都不要用拼音,會遭人鄙視。是的,我見過!
階梯式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不能傳播不定態,有的EDA工具有X態傳播選項,可以強行傳播,但是并不是所有的EDA工具都有這個功能,所以有些書上建議都用組合邏輯用assign。 這種寫法沒什么問題,但是有一點,覆蓋率不好收,如果一些情況沒跑到需要一個個分析。覆蓋率會把數據信號當作一個情況列出來,比如數據信號data沒出現過0 的情況,實際上數據信號沒出現0的情況是正常的,這就要你一個一個的exclude掉。 所以不要寫很長的assign做選擇器,有優先級用if-else,或根據具體情況用case。這樣哪一行哪一種情況沒跑到會一目了然。當然if中的條件太多,覆蓋率也不好收,條件太多組合的情況多,分析起來繁瑣。如果上述信號的vld不同時出現也可以采用這種寫法,減少cell的使用數量。這樣也是有覆蓋率的問題,這只是一種特殊情況,很長的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]);關于X態傳播,一定要注意,帶有reset的寄存器面積和時序會稍微差一些,控制通路的寄存器必須帶有復位,數據通路的寄存器可以不帶復位,但是要注意使用時如果使用數據通路的數據去做了控制條件,就必須要復位,否則如果X態沒有查出來,事情就大了。
布線太密的原因
寄存器位寬太大。reg [10000-1:0] data;
這樣寫在功能上沒什么問題,但是如果你之后有對這個數據做了很多邏輯,可能會造成后端布線太密,從后端的角度看到其實cell數量并不多,就是線比較密,比如說這個數據后面再放個選擇器,或者輸出給其他模塊,就相當于一萬根線連到很多地方,布線很緊張,如果時序有問題需要繞線,或者需要ECO,做成的可能性很小。
盡量不要這樣做邏輯,除非對面積沒限制,要么最后只能改架構。
第二個原因是負載太大。同一個信號在很多地方使用,布線也會變復雜,比如最常見的是參數信號,在很多模塊都會有用到的情況,用寄存器復制的方法。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; endend畫倆圖大概意思一下。這樣每個寄存器的驅動變少。


有網友提到這樣子寫被綜合掉的概率也是很大。所以就只能在設計時盡量注意負載的問題。
加比選
面積:加法器 > 比較器 > 選擇器乘法器本質上也是全加器。所以就有先選后比,先選后加,先選后乘。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;畫個圖意思一下。


數據通路與控制通路
數據通路打拍可以不帶復位,帶著使能信號去打拍,減少信號翻轉,減少功耗。保證數據用的時候不是X態, 組合邏輯路徑是否需要插入pipeline,插入pipeline的位置需要注意。寄存器能少用就少用。 盡量不要用除法,首先除法器面積更大,除法也會有余數,余數是否需要保留就很麻煩。除以常數可以做成乘以定點常數的方法。 乘以常數用移位加,也可直接用*號。例如a * 2‘d3,工具會幫你優化成 a << 2’d1 + a。甚至可能優化得更好。(杠:不要過度依賴工具)。關于用移位加還是*號的問題,博主做過綜合后的面積對比,相對來說,工具還是優化那么一點點。直接用 * 號吧。 盡量不要用減法,減法要考慮到減翻的問題,盡量用加法。方案設計
方案最重要,一個好的方案往往事半功倍。 狀態機設計要狀態明確,一個狀態盡量只做一件事情。狀態機大法好。 做成IP化設計,功能分割盡量獨立并可復用性,相同的功能用同一塊IP,保證IP的沒問題,最后像搭積木一樣,搭建起數字系統。多積累些常用IP,常用的一些寫法的代碼。審核編輯 :李倩
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
寄存器
+關注
關注
31文章
5608瀏覽量
130010 -
比較器
+關注
關注
14文章
1929瀏覽量
111933 -
Verilog
+關注
關注
30文章
1374瀏覽量
114534
原文標題:Verilog有什么奇技淫巧?
文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
熱點推薦
FPGA 入門必看:Verilog 與 VHDL 編程基礎解析!
很多開發者第一次接觸FPGA,都會有同樣的疑問:FPGA是硬件,不是軟件,怎么寫程序?答案就是用硬件描述語言(HDL),最常用的就是Verilog和VHDL。今天,我們就帶你入門,搞清楚FPGA編程
【「龍芯之光 自主可控處理器設計解析」閱讀體驗】--LoongArch邏輯綜合、芯片設計
TransferLevel,RTL)描述轉換為滿足功能、時序和面積要求的門級網表的過程。
按照流程,邏輯綜合通常可分為面向應用的專用集成電路(Application-Specific
發表于 01-18 14:15
有源邏輯探頭的具體應用
及典型場景的詳細拆解: 一、數字電路研發與調試 此為有源邏輯探頭的核心應用場景,核心解決復雜數字系統中“信號觀測無干擾、多通道信號同步分析”的關鍵需求,為電路設計驗證提供精準的信號數據支撐。 時序邏輯驗證: 針對
電能質量在線監測裝置的自診斷功能對通信故障的檢測邏輯是怎樣的?
” 的組合,明確故障觸發條件,確保檢測精準、無遺漏,具體邏輯如下: 一、物理接口層:硬件直接檢測,判斷 “接口是否可用” 這是最基礎的檢測環節,通過硬件電路直接采集接口物理狀態,快速識別硬件級故障,不依賴復雜軟件: 檢測邏輯核心
vivado時序分析相關經驗
存在不滿足時序要求的邏輯級數。邏輯級數過多一般可以通過插入寄存器打拍子,分割冗長的組合邏輯。
線延時較長時,一般是因為扇出較大。
”repo
發表于 10-30 06:58
MDD 邏輯IC的邏輯電平不兼容問題與解決方案
在現代電子系統中,MDD辰達半導體邏輯IC(集成電路)扮演著至關重要的角色,廣泛應用于數據處理、時序控制、信號轉換等各類電路中。隨著技術的進步,不同邏輯系列的IC(如TTL、CMOS、BiCMOS等
時序約束問題的解決辦法
在使用vivado對 Verilog 代碼進行綜合后,點擊“SYNTHESIS”下的“Report Timing Summary”,可以查看綜合后的時序報告,查看 Setup Time 和 Hold
發表于 10-24 09:55
咨詢符合國標GB/T 4728.12-2022的邏輯門電路設計軟件
不正確呀。
咨詢
1、開源免費的軟件,能夠繪制符合國家標準GB/T 4728.12-2022的邏輯門電路,繪制和驗證簡單的邏輯電路,最好提供74LS系列等常用的芯片,以及基本門電路芯片連接、組合等功能
發表于 09-09 09:46
實用電子電路設計(全6本)——數字邏輯電路的ASIC設計
門電路、邏輯壓縮、組合電路、Johnson計數器、定序器設計及應用等,并介紹了實現最佳設計的各種工程設計方法。
純分享貼,有需要可以直接下載附件獲取完整資料!
(如果內容有幫助可以關注、點贊、評論支持一下哦~)
發表于 05-15 15:22
長虹電視;屏幕豎線;邏輯板問題么
電視機型號:長虹3D46C2000i.
請大神幫忙看下我得測試過程及結果,是邏輯板故障么?
1,狀態圖片為開機顯示畫面;
2,圖片2為分別拆卸邏輯板輸出測試;
3,圖片3為拆卸右側(從背面看)邏輯板
發表于 04-26 22:04
CMOS邏輯IC是如何構成的
電子設備正常運轉離不開“邏輯”的精密驅動。例如,當我們在手機上滑動屏幕時,背后就有無數個CMOS邏輯電路在默默工作,它們通過復雜的邏輯運算,將我們的觸摸信號轉化為手機能夠理解的指令,從而實現各種功能。
Verilog寫法:組合邏輯+時序邏輯
評論