-
- 方式1:用assign描述,用阻塞賦值=
-
- 方式2:用always@(*)描述,用非阻塞賦值<=
-
- 方式1:三目運算符 ? : ;
-
- 方式2:if...else if.....else(有優先級)
-
- 方式3:case....default...(並行)
//方式1(先列出端口,后定義端口屬性) module mux2( a, b, sel, out ); //端口屬性定義(輸入/輸出,位寬) input a; input b; input sel; //sel = 0,out輸出a output out; //位寬1位 //功能描述 //阻塞賦值語句 assign out = (sel == 0)?a:b; //assign out = (!sel)?a:b; //assign out = sel?b:a; endmodule
//方式2(在聲明端口的同時定義屬性) module mux2( //端口屬性定義 input a, input b, input sel, output out //此處沒有分號 ); //功能描述 //阻塞賦值語句 assign out = (sel == 0)?a:b; endmodule
testbench測試文件(組合邏輯電路一般都采用窮舉法):
`timescale 1ns / 1ps module mux2_tb(); reg a; reg b; reg sel; wire c; //例化測試模塊 mux2 mu2_test( .a(a), .b(b), .sel(sel), .c(c) ); initial begin a = 0; b = 0; sel = 0; #100; //延時100ns(時間步進前面第一行代碼已經設置為1ns) a = 0; b = 0; sel = 1; #100; a = 0; b = 1; sel = 0; #100; a = 0; b = 1; sel = 1; #100; a = 1; b = 0; sel = 0; #100; a = 1; b = 0; sel = 1; #100; a = 1; b = 1; sel = 0; #100; a = 1; b = 1; sel = 1; #100; $stop; end endmodule
測試結果(modelsim):
分析出的電路:
例2.三態門控制
//三態門控制 assign oe = sel; assign io = oe?out[0]:1'bz; //z高阻態(輸入)
三態門和二選一多路器類似,不再進行仿真測試;
module half_adder( input a, input b, output out, //結果輸出 output cout //進位輸出 ); //功能描述 assign out = a ^ b; assign cout = a & b; endmodule
`timescale 1ns / 1ps module half_adder_tb(); reg a; reg b; wire out; wire cout; //例化測試模塊 half_adder half_adder_test( .a(a), .b(b), .out(out), //結果輸出 .cout(cout) //進位輸出 ); //開始測試 initial begin a = 0; b = 0; #100; a = 0; b = 1; #100; a = 1; b = 0; #100; a = 1; b = 1; #100; $stop; end endmodule
測試結果(modelsim):
分析出的電路(和上一篇數字電路設計的一模一樣,由一個異或門和與門構成):
module adder( input a, input b, input cin, //進位輸入 output out, //結果輸出 output cout //進位輸出 ); //功能描述 assign out = a ^ b ^ cin; assign cout = a&b | a&cin | b&cin; endmodule
testbench測試文件
`timescale 1ns / 1ps module adder_tb(); reg a; reg b; reg cin; wire out; wire cout; //例化測試模塊 adder adder_test( .a(a), .b(b), .cin(cin), //進位輸入 .out(out), //結果輸出 .cout(cout) //進位輸出 ); //開始測試 initial begin a = 0; b = 0; cin = 0; #100; a = 0; b = 1; cin = 0; #100; a = 1; b = 0; cin = 0; #100; a = 1; b = 1; cin = 0; #100; a = 0; b = 0; cin = 1; #100; a = 0; b = 1; cin = 1; #100; a = 1; b = 0; cin = 1; #100; a = 1; b = 1; cin = 1; #100; $stop; end endmodule
測試結果(modelsim):
分析出的電路:
例4.數碼管顯示譯碼器
通常我們用的數碼管有共陽極和共陰極之分,共陽極段碼給0,位選給1全部點亮;共陰極段碼給1,位選給0全部點亮;數碼管都是7段數碼管顯示+一位小數點,Basys3開發板數碼管原理圖和數碼管顯示原理如下圖:
這樣每個數字都會有對應的7段編碼,但我們熟悉的是二進制碼或者BCD碼,所以需要設計一個顯示譯碼器,將輸入的4bitBCD碼轉換為數碼管對應的8bit段碼;由Basys3原理圖可知,要讓數碼管顯示,還需要選中位選,所以還需要設計一個2-4譯碼器,用兩個開關控制哪一位顯示,設計圖如下:
Verilog描述組合邏輯電路中的譯碼器通常采用case語句,完整的代碼如下:
///////////////////////////////////////////////////////////////////////////////////////////////// // Module Name: seg_display // Description: 數碼管顯示模塊,由一個顯示譯碼器模塊decoder_display和一個2-4譯碼器decoder2_4構成; ////////////////////////////////////////////////////////////////////////////////////////////////// module seg_display( input [3:0]data_display, //數碼管待顯示數據 input [1:0]wei, //選擇哪一位顯示 output [6:0]segments, //數碼管段碼 output [3:0]wei_sel //數碼管位碼 ); //功能描述 //例化顯示譯碼模塊 decoder_display decoder_display_0( .data_in(data_display), .segments(segments) ); //例化位選模塊 decoder2_4 decoder2_4_0( .data_in(wei), .wei_sel(wei_sel) ); endmodule //數碼管顯示譯碼模塊 //note:只包含7位段碼,不包括小數點控制 module decoder_display( input [3:0]data_in, output reg [6:0]segments ); //顯示譯碼功能描述 always@(*) case(data_in) //對應段 abc_defg 4'h0: segments = 7'b000_0001; 4'h1: segments = 7'b100_1111; 4'h2: segments = 7'b001_0010; 4'h3: segments = 7'b000_0110; 4'h4: segments = 7'b100_1100; 4'h5: segments = 7'b010_0100; 4'h6: segments = 7'b010_0000; 4'h7: segments = 7'b000_1111; 4'h8: segments = 7'b000_0000; 4'h9: segments = 7'b000_1100; 4'hA: segments = 7'b000_1000; 4'hB: segments = 7'b110_0000; 4'hC: segments = 7'b011_0001; 4'hD: segments = 7'b100_0010; 4'hE: segments = 7'b011_0000; 4'hF: segments = 7'b011_1000; default: segments = 7'b111_1111; endcase endmodule module decoder2_4( input [1:0]data_in, output reg [3:0]wei_sel //4位數碼管選中位 ); //位選2-4譯碼器功能描述 always@(*) case(data_in) //對應位 4'h0: wei_sel = 4'b1110; 4'h1: wei_sel = 4'b1101; 4'h2: wei_sel = 4'b1011; 4'h3: wei_sel = 4'b0111; default: wei_sel = 4'b1111; endcase endmodule
testbench測試代碼如下:
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Module Name: seg_display_tb // Description: 數碼管顯示模塊seg_display測試模塊 ////////////////////////////////////////////////////////////////////////////////// module seg_display_tb(); reg [3:0]data_display; //數碼管待顯示數據 reg [1:0]wei; //選擇哪一位顯示 wire [6:0]segments; //數碼管段碼 wire [3:0]wei_sel; //數碼管位碼 //例化測試模塊 seg_display seg_display_test( .data_display(data_display), //數碼管待顯示數據 .wei(wei), //選擇哪一位顯示 .segments(segments), //數碼管段碼 .wei_sel(wei_sel) //數碼管位碼 ); //開始測試 initial begin wei = 2'h0; //選中第一位顯示0-F data_display = 4'h0; //顯示"0" #10; data_display = 4'h1; //顯示"1" #10; data_display = 4'h2; //顯示"2" #10; data_display = 4'h3; //顯示"3" #10; data_display = 4'h4; //顯示"4" #10; data_display = 4'h5; //顯示"5" #10; data_display = 4'h6; //顯示"6" #10; data_display = 4'h7; //顯示"7" #10; data_display = 4'h8; //顯示"8" #10; data_display = 4'h9; //顯示"9" #10; data_display = 4'ha; //顯示"A" #10; data_display = 4'hb; //顯示"b" #10; data_display = 4'hc; //顯示"C" #10; data_display = 4'hd; //顯示"d" #10; data_display = 4'he; //顯示"E" #10; data_display = 4'hf; //顯示"F" #10; wei = 2'h1; //選中第二位顯示"F" #10; wei = 2'h2; //選中第三位顯示"F" #10; wei = 2'h3; //選中第四位顯示"F" #100; $stop; //測試停止 end endmodule
仿真結果如下圖:
綜合分析出的電路如圖:
小結 —— 組合邏輯電路的設計方法
1、verilog描述方法
對於組合邏輯電路,有兩個步驟,一是描述端口,二是描述功能(最重要的是得出真值表,然后根據真值表得出邏輯表達式,描述功能);
2、testbench編寫方法
對於組合邏輯電路的testbench測試文件的編寫:
1)定義時間步進/時間精度:`timescale 1ns/1ps
2)定義一些測試模塊輸入所用到的寄存器,用於產生對測試模塊輸入信號(即將測試模塊input類型信號改為reg類型信號);
定義用於觀察的輸出信號接到測試模塊的輸出(即將測試模塊output類型信號改為wire類型信號);
3)例化測試模塊(注意要定義例化模塊名稱)
4) 開始測試
①基本結構 initial begin ....... end......$stop;
②延時100ns的表示方法 #100; (注意一定要加上分號)
③窮舉出所有可能的情況