文章目錄
- 1 多路選取器Multiplexer
- 1.2 帶優先順序的多路選取器
- 輔助閱讀
- 參考
對讀者的假設
已經掌握:
- 可程式化邏輯基礎
- Verilog HDL基礎
- 使用Verilog設計的Quartus II入門指南
- 使用Verilog設計的ModelSIm入門指南
內容1 多路選取器Multiplexer
此處所說的多路選取器,為組合邏輯電路中的多路多路選取器:多路輸入,一路輸出。
1.1 不帶優先順序的多路選取器1.1.1 使用case語句描述
此處以4選1多路選取器為例:
代碼1.1 4選1多路選取器(可綜合)
`timescale 1ns/1nsmodule multiplexer( input iA, input iB, input iC, input iD, input [1:0] iSel, output reg oQ );always @ (*) case (iSel) 2'b00 : oQ = iA; 2'b01 : oQ = iB; 2'b10 : oQ = iC; 2'b11 : oQ = iD; endcaseendmodule
第10~16行,使用case語句來實現4選1多路選取器。因為是2^n個case選項,所以此處沒有使用default語句。下面我會使用一個3選1的多路選取器來說明default的作用。
always @ (*) case (iSel) 2'b00 : oQ = iA; 2'b01 : oQ = iB; 2'b10 : oQ = iC; 2'b11 : oQ = iD; endcase
圖1.1 4選1多路選取器的RTL視圖
由圖1.1所示,在2^n個case選項時,沒有加上default語句,其綜合的結果為並行的MUX。
代碼1.2 4選1多路選取器testbench(不可綜合,僅用於模擬)
`timescale 1ns/1nsmodule multiplexer_tb;reg i_a, i_b, i_c, i_d;reg [1:0] i_sel;wire o_q; initial begin i_a = 1; i_b = 0; i_c = 0; i_d = 0; #20 i_a = 1; i_b = 0; i_c = 1; i_d = 1; #20 i_a = 0; i_b = 0; i_c = 1; i_d = 0; #20 i_a = 1; i_b = 1; i_c = 1; i_d = 0;end initial begin i_sel = 2'b00; #20 i_sel = 2'b01; #20 i_sel = 2'b10; #20 i_sel = 2'b11; #20 $stop;end multiplexer multiplexer_inst( .iA (i_a), .iB (i_b), .iC (i_c), .iD (i_d), .iSel (i_sel), .oQ (o_q) ); endmodule
第3~5行聲明了一些變數,使用的標準為:映射為所需測試模組的輸入訊號,即需要使用initial或always來給出激勵,因此多聲明為reg類型;而映射為所需測試模組的輸出訊號,不需要激勵,聲明為wire類型即可。
reg i_a, i_b, i_c, i_d;reg [1:0] i_sel;wire o_q;
第21行,$stop表示模擬在此時刻終止。更多$打頭的函數,請參考Verilog文法書。
#20 $stop;
圖1.2 4選1多路選取器的功能模擬波形
圖1.3 4選1多路選取器的門級模擬波形
由圖1.2和圖1.3所示,在2^n個case選項時,沒有加上default語句,其功能模擬和門級模擬保持一致。
1.1.2 怎麼多出個鎖存器?
此處以3選1多路選取器為例。
代碼1.3 3選1多路選取器1(可綜合)
module multiplexer( input iA, input iB, input iC, input [1:0] iSel, output reg oQ );always @ (*) case (iSel) 2'b00 : oQ = iA; 2'b01 : oQ = iB; 2'b10 : oQ = iC; endcaseendmodule
圖1.4 3選1多路選取器1的RTL視圖
1.4所示,綜合出來了鎖存器。下面我們討論如何消除這個鎖存器。
方法1 加(* full_case *)修飾
代碼1.4 3選1多路選取器2(可綜合)
module multiplexer( input iA, input iB, input iC, input [1:0] iSel, output reg oQ );always @ (*) (* full_case *) case (iSel) 2'b00 : oQ = iA; 2'b01 : oQ = iB; 2'b10 : oQ = iC; endcaseendmodule
第10行,加(* full_case *)修飾,強制綜合成full case。
(* full_case *) case (iSel)
圖1.5 3選1多路選取器2的RTL視圖
方法2 使用default語句
代碼1.5 3選1多路選取器3(可綜合)
module multiplexer( input iA, input iB, input iC, input [1:0] iSel, output reg oQ );always @ (*) case (iSel) 2'b00 : oQ = iA; 2'b01 : oQ = iB; 2'b10 : oQ = iC; default: oQ = 1'b0; endcaseendmodule
第14行,加上default語句,來描述預設動作。
default: oQ = 1'b0;
圖1.6 3選1多路選取器3的RTL視圖
方法3 在敏感列表後,賦初值
代碼1.6 3選1多路選取器4(可綜合)
module multiplexer( input iA, input iB, input iC, input [1:0] iSel, output reg oQ );always @ (*)begin oQ = 1'b0; case (iSel) 2'b00 : oQ = iA; 2'b01 : oQ = iB; 2'b10 : oQ = iC; endcaseendendmodule
注意第9~17,在代碼1.3的基礎上,于敏感列表之後,加入oQ的初值。
always @ (*)begin oQ = 1'b0; case (iSel) 2'b00 : oQ = iA; 2'b01 : oQ = iB; 2'b10 : oQ = iC; endcaseend
圖1.7 3選1多路選取器4的RTL視圖
方法123的比較
代碼1.7 3選1多路選取器的testbench(不可綜合,僅用於模擬)
`timescale 1ns/1nsmodule multiplexer_tb;reg i_a, i_b, i_c;reg [1:0] i_sel;wire o_q;initial begin i_a = 0; i_b = 0; i_c = 0; #20 i_a = 1; i_b = 0; i_c = 0; #20 i_a = 1; i_b = 0; i_c = 1; #20 i_a = 0; i_b = 0; i_c = 1; #20 i_a = 1'bx; i_b = 1'bx; i_c = 1'bx;endinitial begin i_sel = 2'bxx; #20 i_sel = 2'b00; #20 i_sel = 2'b01; #20 i_sel = 2'b10; #20 i_sel = 2'b11; #20 $stop;endmultiplexer multiplexer_inst( .iA (i_a), .iB (i_b), .iC (i_c), .iSel (i_sel), .oQ (o_q) );endmodule
圖1.8 方法1的功能模擬波形
圖1.9 方法1的門級模擬波形
由圖1.8和圖1.9所示,雖然方法1加了(* full_case *)修飾後,3選1多路選取器的綜合結果沒有產生鎖存器,但是其功能模擬波形卻當作鎖存器來處理,而其門級模擬波形則是當作無關項來處理。即方法1,其前後模擬結果是不一致的。至於其他的特點,本文暫不討論。想要瞭解更多full case的資訊,請閱讀參考2。
圖1.10 方法2的功能模擬波形
圖1.11 方法2的門級模擬波形
1.10和1.11所示,方法2使用了default語句,其前後模擬和綜合的RTL視圖一致。蕭鴻森大哥提醒我們:正確的做法是,default指定輸出0或者某個選項。
圖1.12 方法3的功能模擬波形
圖1.13 方法3的門級模擬波形
1.12和1.13所示,方法3在敏感列表後,賦初值也可以很好解決鎖存器的問題。
1.1.3 結論
雖然方法123都可以解決鎖存器的問題,但是:方法1的前後模擬結果不同;方法3的其他特點暫時沒有研究。因此此處只推薦大家使用方法2,即要實現並行的mux,當case選項不是2^n個的時候,加上default指定輸出0或某個選項是最安全的(雖然Verilog文法沒有強制加入default)。
1.2 帶優先順序的多路選取器1.2.1 使用if-else-if描述
此處以3選1多路選取器為例。
代碼1.8 使用if-else-if描述的3選1多路選取器(可綜合)
module multiplexer( input iA, input iB, input iC, input [1:0] iSel, output reg oQ );always @ (*) if (iSel == 2'b0) oQ = iA; else if (iSel == 2'b01) oQ = iB; else oQ = iC;endmodule
第9~15行,使用if-else-if描述帶優先順序的多路選取器。有人看到My Code會有一點小疑問?為什麼always塊沒有加begin-end的。其實呢這個begin-end就相當於C語言裡面的{},與C語言類似,當後面的語句條數為1時,可以省略begin-end。而if-else-if恰好為一個完整的語句。
always @ (*) if (iSel == 2'b0) oQ = iA; else if (iSel == 2'b01) oQ = iB; else oQ = iC;
圖1.14 使用if-else-if描述的3選1多路選取器的RTL視圖
1.2.2 使用“: ?”描述
既然使用if-else-if可以描述帶優先順序的多路選取器,那麼使用“: ?”當然也是可行的。
代碼1.9 使用“: ?”描述的3選1多路選取器(可綜合)
module multiplexer( input iA, input iB, input iC, input [1:0] iSel, output oQ );assign oQ = (iSel == 2'b00) ? iA : (iSel == 2'b01) ? iB : iC; endmodule
第9~10行,使用“: ?”描述帶優先順序的多路選取器。
assign oQ = (iSel == 2'b00) ? iA : (iSel == 2'b01) ? iB : iC;
實際上等同於,為什麼使用上面這種寫法呢?因為“: ?”的運算優先順序比較低,所以不必加括弧。
assign oQ = (iSel == 2'b00) ? iA : ((iSel == 2'b01) ? iB : iC);
注意:第6行的聲明,由於是使用assign語句賦值,因此無需聲明成reg類型。
output oQ
圖1.15 使用“: ?”描述的3選1多路選取器的RTL視圖
1.15所示,使用“: ?”描述多路選取器與if-else-if描述完全一致,因此兩種描述方式可以互換。
2 多路分解器De-Multiplexer
多路分解器,也叫資料選取器,顧名思義即多路輸入,一路輸出。有了前面的基礎,那麼描述一個多路分解器,便是輕而易舉事情了。
代碼2.1 使用case描述多路分解器
module de_multiplexer( input iA, input [1:0] iSel, output reg oQ_0, output reg oQ_1, output reg oQ_2);always @ (*)begin oQ_0 = 1'b0; oQ_1 = 1'b0; oQ_2 = 1'b0; case (iSel) 2'b00 : oQ_0 = iA; 2'b01 : oQ_1 = iA; 2'b10 : oQ_2 = iA; default : ; endcaseendendmodule
第9~20行,在敏感列表後,追加初始值,可以有效地避免產生鎖存器。
always @ (*)begin oQ_0 = 1'b0; oQ_1 = 1'b0; oQ_2 = 1'b0; case (iSel) 2'b00 : oQ_0 = iA; 2'b01 : oQ_1 = iA; 2'b10 : oQ_2 = iA; default : ; endcaseend
圖2.1 代碼2.1綜合後的RTL視圖
代碼2.2 代碼2.1的testbench
`timescale 1ns/1nsmodule de_multiplexer_tb;reg i_a;reg [1:0] i_sel;wire o_q_0, o_q_1, o_q_2;initial begin i_a = 0; forever #10 i_a = ~i_a;end initial begin i_sel = 2'b00; #20 i_sel = 2'b01; #20 i_sel = 2'b10; #20 i_sel = 2'b11; #20 $stop;end de_multiplexer de_multiplexer_inst( .iA(i_a), .iSel(i_sel), .oQ_0(o_q_0), .oQ_1(o_q_1), .oQ_2(o_q_2));endmodule
圖2.1 代碼2.1的功能模擬波形
圖2.2 代碼2.1的門級模擬波形
圖2.1和圖2.2的所示波形與代碼2.1一致。
輔助閱讀
1. Wikipedia.Multiplexer
參考
1. 劉福奇, 劉波.Verilog HDL應用程式設計執行個體精講.電子工業出版社
2. Cliff Cummings' Award-Winning Verilog & SystemVerilog Papers. "full_case parallel_case", the Evil Twins of Verilog Synthesis
3. 蕭鴻森.(原創) 多工器MUX coding style整理 (SOC) (Verilog) (Quartus II)
4. Altera.Recommended HDL Coding Styles.General Coding Guidelines
另見
[與艾米一起學FPGA/SOPC].[邏輯實驗文檔連載計劃]