FPGA學習筆記(五)—— 組合邏輯電路設計


 設計方法:    分析真值表規律
 
      兩種描述方式:
    • 方式1:用assign描述,用阻塞賦值=
    • 方式2:用always@(*)描述,用非阻塞賦值<=
 
    選擇功能的三種描述方式:
    • 方式1:三目運算符 ? :  ; 
    • 方式2:if...else if.....else(有優先級)
    • 方式3:case....default...(並行)           
  例1.mux2二選一數據選擇器

      

 

//方式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高阻態(輸入)

 

   三態門和二選一多路器類似,不再進行仿真測試;

   例3.加法器
        1、半加器halfadder

 

 

module half_adder(
    input  a,
    input  b,
    output out,     //結果輸出
    output cout     //進位輸出
    );
    //功能描述
    assign out  = a ^ b;
    assign cout = a & b;
    
endmodule

 

  testbench測試代碼:
`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):

  

  分析出的電路(和上一篇數字電路設計的一模一樣,由一個異或門和與門構成):

  

    2、全加器adder
           設計方式1:層次化設計,由兩個半加器和一個或門組成
           設計方式2:根據真值表采用verilog直接描述(如下圖)

 

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;  (注意一定要加上分號)

         ③窮舉出所有可能的情況


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM