Verilog實現加減乘除計算器


主要內容:

  1. 按鍵按下后,進行加減乘除操作

  2. Verilog往TXT文本文件中寫入數據

  3. 完成計算模塊

  4. 最終實現加減乘除計算器

 

1. 實現按鍵按下后,選擇option,進行加減乘除操作,除法計算結果為商&余數

module jsq( 
                clk, 
                rst_n,
                key, 
                option,
                x, 
                y, 
                result,
                quotient,
                remainder
                );
    parameter N = 16; // 輸入數的位數
    
    input clk;   // 輸入時鍾
    input rst_n; // 低電平有效的復位(清零)
    input key;
    input [1:0]option;
    input [N-1:0] x;
    input [N-1:0] y;
  
    output [2*N-1:0] result;
    output [N-1:0] quotient;    //輸出計算的商
    output [N-1:0] remainder;   //輸出計算的余數

    reg [2*N-1:0] result_r;
    reg [N-1:0] quotient_r,remainder_r;

    always @ (posedge clk or negedge rst_n)
        begin
            if (!rst_n)
                begin
                    result_r <= 1'b0;
                    quotient_r <= 1'b0;
                    remainder_r <= 1'b0;

                end
            else
                begin
                    if (key == 1'b0)
                        begin //按鍵按下
                            case(option)
                                2'b00: result_r = x + y;
                                2'b01: result_r <= x + (~y + 1'b1);
                                2'b10: result_r = x * y;
                                2'b11: //result_r = x / y;
                                    begin
                                        quotient_r = x / y;
                                        remainder_r = x % y;
                                    end
                                
                            endcase
                            
                        end
                    else
                        begin // 按鍵釋放
                            result_r <= 1'b0;
                            quotient_r <= 1'b0;
                            remainder_r <= 1'b0;
                        end
                end
        end
    assign result = result_r ;
    assign quotient= quotient_r;
    assign remainder = remainder_r;

endmodule
View Code
`timescale 1ns/1ps
`define clock_period 20

module jsq_tb;
    
    reg clk;
    reg rst_n;
    reg key;
    reg [1:0]option;

    reg [15:0] x,y;

    wire [31:0] result;
    wire [15:0] quotient;
    wire [15:0] remainder;
    
    initial begin
        clk = 1'b1;
        rst_n = 1'b0;
        key = 1'b1; // 復位時,按鍵釋放
        # 20 //復位20ns
        rst_n = 1'b1;
        # 20
        
        key = 1'b0;
        option = 2'b10;
        # 100
        key = 1'b1;
        # 20
        
        key = 1'b0;
        option = 2'b11;
        # 100
    //    key = 1'b1;
    //    # 20
        $stop;
    end
    
    always #(`clock_period/2) clk = ~clk; //50M
    
    jsq #(.N(16)) jsq_0(
            .clk(clk),
            .rst_n(rst_n),
            .key(key),
            .option(option),
            .x(x),
            .y(y),
            .result(result),
            .quotient(quotient),
            .remainder(remainder)
            );
        

  initial begin
     x = 0;
     repeat(20)
        #(`clock_period) x = {$random}%100; //通過位拼接操作{}產生0—59范圍的隨機數

  end

  initial begin
     y = 0;
     repeat(20)
        #(`clock_period) y = {$random}%50;

  end


    /*integer i;
    initial begin
        x = 0;
        y = 0;
        for(i = 0; i < 20; i = i + 1)
            begin
                //利用$random系統函數產生隨機數。因為是16位,因此產生的數據最大不能超過65535.所以要對65535取模。
                x = {$random}%100;
                y = {$random}%50;
            end
    end*/

endmodule
View Code

 

2.Verilog往TXT文本文件中寫入數據

integer handle;//定義后面要用到的變量
//...
//...
 
handle = $fopen("data.txt");//打開文件
//...
//...
always #10 clk = ~clk;//定義時鍾
always #20
begin
    $fdisplay(handle,"%d",rand_num);//寫數據
    while(!rst_n) $fclose(handle);//關文件
end
View Code

 

3.實現計算模塊(減法運算支持結果顯示為負數)

module calc(a, b, clk, rst_n, opcode, result);
    parameter N = 16;
    input [N-1:0] a,b;
    input clk;
    input rst_n;
    input [3:0] opcode;
    
    output [2*N-1:0] result;
//    output reg neg_flag;

    reg [2*N-1:0] result_r;
    always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
        begin
            result_r <= 0;
//            neg_flag <= 0;
        end
        else
        begin
            case(opcode)
                10: begin result_r[2*N-1:0] <= a + b; end  
                11: begin 
                        /*if(a>=b)
                            result_r[2*N-1:0] <= a - b; 
                        else begin
                            result_r[2*N-1:0] <= b - a;
                            //result_r[2*N-1] <= 1;
                            end*/
                        result_r <= a + (~b + 1'b1);    
                        end  
                12: begin result_r[2*N-1:0] <= a * b; end  
                13: begin result_r[2*N-1:0] <= a / b; end 
                default: result_r[2*N-1:0] <= 0;
            endcase
        end
    end
    assign result = result_r;
endmodule
View Code
`timescale 1ns/1ps
`define clock_period 20

module calc_tb;

    reg [15:0] a,b;
    reg clk;
    reg rst_n;
    reg [3:0] opcode;
    
    wire[31:0] result;
    
    initial begin
        clk = 1'b1;
        rst_n = 1'b0;
          a = 0;
          b = 0;
        # 20 //復位20ns
        rst_n = 1'b1;
        # 20
        
        opcode = 4'd10;
          a = 50;
          b = 44;
        # 20
          a = 550;
          b = 440;
        # 20
        opcode = 4'd11;
          a = 11;
          b = 9;
        # 20
          a = 11;
          b = 21;
        # 20              
        opcode = 4'd12;
          a = 56;
          b = 10;
        # 20
          a = 555;
          b = 10;
        # 20        
        opcode = 4'd13;
          a = 70;
          b = 7;
        # 20
          a = 7;
          b = 70;
        # 20
          a = 770;
          b = 11;
        # 20          
        $stop;
    end
    always #(`clock_period/2) clk = ~clk; //50M
    
    calc #(.N(16)) calc_0(
            .clk(clk),
            .rst_n(rst_n),
            .opcode(opcode),
            .a(a),
            .b(b),
            .result(result)
            );
        

/*  initial begin
     a = 0;
     repeat(20)
        #(`clock_period) a = {$random}%100; //通過位拼接操作{}產生0—59范圍的隨機數

  end

  initial begin
     b = 0;
     repeat(20)
        #(`clock_period) b = {$random}%50;

  end*/
endmodule
View Code

 

4. 實現加減乘除計算器(由輸入控制模塊和計算模塊組成)

具體功能為:實現非負整數的加減乘除運算。計算器頂層模塊的輸入端口有:輸入時鍾;10個單bit輸入端口,分別代表十進制數0到9;5個單bit輸入端口,分別代表符號“+”、“-”、“×”、“÷”、“=”;1個單bit輸入端口,代表計算器顯示清零符號。代表計算器按鍵的單bit輸入端口,如果出現1個時鍾周期的高電平脈沖信號,表示這個按鍵按下。計算器可處理位寬至少為16位二進制數(即十進制數0到65535)的輸入數據,並得到正確的運算結果,運算結果的位寬不限於16位二進制數。其中,減法運算支持運算結果為負數,激勵中計算器的輸入數據和運算結果存入文本文件中

module top(
        clk,
        rst_n,
        input0,
        input1,
        input2,
        input3,
        input4,
        input5,
        input6,
        input7,
        input8,
        input9,
        add,
        sub,
        mul,
        div,
        enter,
        
        num,
        a,
        b,
        opcode,
        result
        );
    input clk,rst_n;
    input input0,input1,input2,input3,input4,input5,input6,input7,input8,input9;

    input add,sub,mul,div,enter;
    

    output [15:0] a;
    output [15:0] b;
    output [3:0] opcode;    
    output [31:0]result;
    output [15:0] num;
    
    key key_0(
            .clk(clk),
            .rst_n(rst_n),
            .input0(input0),
            .input1(input1),
            .input2(input2),
            .input3(input3),
            .input4(input4),
            .input5(input5),
            .input6(input6),
            .input7(input7),
            .input8(input8),
            .input9(input9),
            .add(add),
            .sub(sub),
            .mul(mul),
            .div(div),
            .enter(enter),
            
            .num(num),
            .opcode(opcode),
            .a(a),
            .b(b)    
    );
    
   calc #(.N(16)) calc_0(
            .clk(clk),
            .rst_n(rst_n),
            .opcode(opcode),
            .a(a),
            .b(b),
                .enter(enter),
                
            .result(result)
            );    
endmodule
                
top
`timescale 1ns/1ps
`define clock_period 20

module top_tb;

    reg clk;
    reg rst_n;
    reg input0,input1,input2,input3,input4,input5,input6,input7,input8,input9;
    reg add,sub,mul,div,enter;
    
    wire [15:0] num;  //順序影響波形信號的順序
    wire [15:0] a, b; 
    wire [3:0] opcode;
    wire [31:0]result;
    
    integer file;
    
    
    initial begin
      clk = 1'b1;
      rst_n = 1'b0;
        input0 = 1'b0;
        input1 = 1'b0;
        input2 = 1'b0;
        input3 = 1'b0;
        input4 = 1'b0;
        input5 = 1'b0;
        input6 = 1'b0;
        input7 = 1'b0;
        input8 = 1'b0;
        input9 = 1'b0;
          
        add = 1'b0;
        sub = 1'b0;
        mul = 1'b0;
        div = 1'b0;
        enter = 1'b0;
      # 20 //復位20ns
      rst_n = 1'b1;
      # 20       

        
        input1 <= 1'b1;
      # 20
        input1 <= 1'b0;
      # 20
        input2 <= 1'b1;
      # 20
        input2 <= 1'b0;
      # 20
        
        mul <= 1'b1;
      # 20
        mul <= 1'b0;
      # 20
        

        input4 <= 1'b1;
      # 20
        input4 <= 1'b0;
      # 20
        input2 <= 1'b1;
      # 20
        input2 <= 1'b0;
      # 20
        enter <= 1'b1;
      # 20
        enter <= 1'b0;
      # 20
        
        
        rst_n = 1'b0;
        #20
        rst_n = 1'b1;
      # 20 
        input4 <= 1'b1;
      # 20
        input4 <= 1'b0;
      # 20
        input3 <= 1'b1;
      # 20
        input3 <= 1'b0;
      # 20
        sub <= 1'b1;
      # 20
        sub <= 1'b0;
      # 20
        input6 <= 1'b1;
      # 20
        input6 <= 1'b0;
      # 20
        input5 <= 1'b1;
      # 20
        input5 <= 1'b0;
        # 20
        input5 <= 1'b1;
      # 20
        input5 <= 1'b0;
        # 20
        input3 <= 1'b1;
      # 20
        input3 <= 1'b0;
        # 20
        
        
        enter <= 1'b1;
      # 20
        enter <= 1'b0;
      # 20
        
        
        file = $fopen("calc.txt");         // 打開文件
        begin
            $fdisplay(file,"%d",a);  // 寫數據
            $fdisplay(file,"%d",b);
            $fdisplay(file,"%d",result);
            while(!rst_n) $fclose(file);  // 關閉文件
        end
        
      $stop;
    end
    always #(`clock_period/2) clk = ~clk; //50M
    
    top top_0(
            .clk(clk),
            .rst_n(rst_n),
                .input0(input0),
                .input1(input1),
                .input2(input2),
                .input3(input3),
                .input4(input4),
                .input5(input5),
                .input6(input6),
                .input7(input7),
                .input8(input8),
                .input9(input9),
                
                .add(add),
                .sub(sub),
                .mul(mul),
                .div(div),
                .enter(enter),
                
                .num(num),
                .a(a),
                .b(b),    
                .opcode(opcode),            
                .result(result)
            );    
    
endmodule
top_tb
module calc(clk, rst_n, a, b, opcode, enter,             result);
    parameter N = 16;
    input [N-1:0] a,b;
    input clk,rst_n;
    input enter;
    input [3:0] opcode;
    
    output [2*N-1:0] result;
//    output reg neg_flag;

    reg [2*N-1:0] result_r;
    always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
        begin
            result_r <= 0;
//            neg_flag <= 0;
        end
        else
        begin
            if(enter == 1) begin
                case(opcode)
                    4'b0001: begin result_r[2*N-1:0] <= a + b; end  
                    4'b0010: begin 
                            /*if(a>=b) begin
                                result_r[2*N-1:0] <= a - b; 
                                end
                            else begin
                                result_r[2*N-1:0] <= b - a;
                                end*/
                            result_r <= a + (~b + 1'b1);    //減法結果支持負數顯示
                            end  
                    4'b0100: begin result_r[2*N-1:0] <= a * b; end  
                    4'b1000: begin result_r[2*N-1:0] <= a / b; end 
                    default: result_r[2*N-1:0] <= 0;
                endcase
            end
        end
    end
    assign result = result_r;
endmodule
calc
module key(
        clk,
        rst_n,
        input0,
        input1,
        input2,
        input3,
        input4,
        input5,
        input6,
        input7,
        input8,
        input9,
        add,
        sub,
        mul,
        div,
        enter,

        num,
        a,
        b,
        opcode
        );
    input clk,rst_n;
    input input0,input1,input2,input3,input4,input5,input6,input7,input8,input9;
    input add,sub,mul,div,enter;
    
    output [15:0] a,b;
    output [3:0] opcode;
    
    reg [15:0] a_r,b_r,a_temp;
    reg [3:0] opcode_r;
    
    reg [9:0] input_all;
    
    //鍵值翻譯
    output reg [15:0] num;
    always @ (posedge clk or negedge rst_n)
        begin
            input_all = {input9,input8,input7,input6,input5,input4,input3,input2,input1,input0};
            case (input_all)
                10'b0000000001: num = 0;
                10'b0000000010: num = 1;
                10'b0000000100: num = 2;
                10'b0000001000: num = 3;
                10'b0000010000: num = 4;
                10'b0000100000: num = 5;
                10'b0001000000: num = 6;
                10'b0010000000: num = 7;
                10'b0100000000: num = 8;
                10'b1000000000: num = 9;
                default:;
            endcase
        end    
                    
    always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
        begin
            a_r <= 0;
            a_temp <= 0;
            b_r <= 0;
            opcode_r <= 4'b0000;        
        end
        else
        begin
            if(add)
                begin
                    opcode_r <= 4'b0001;
                end
            if(sub)
                begin
                    opcode_r <= 4'b0010;
                end
            if(mul)
                begin
                    opcode_r <= 4'b0100;
                end
            if(div)
                begin
                    opcode_r <= 4'b1000;
                end
            if(opcode_r == 4'b0000 && input_all != (10'b0000000000))  // 按下運算符前,存第一個數
                a_r <= a_r*10 + num;
            if(opcode_r != 4'b0000 && input_all != (10'b0000000000))  // 按下運算符后,存第二個數
                b_r <= b_r*10 + num;        
        end 
    end
    
    assign a = a_r;
    assign b = b_r;
    assign opcode = opcode_r;
    
endmodule
                
key
`timescale 1ns/1ps
`define clock_period 20

module calc_tb;

    reg [15:0] a,b;
    reg clk,rst_n;
    reg enter;
    reg [3:0] opcode;
    
    wire[31:0] result;
    
    initial begin
        clk = 1'b1;
        rst_n = 1'b0;
          enter = 1'b0;
          a = 0;
          b = 0;
        # 20 //復位20ns
        rst_n = 1'b1;
        # 20
        
        opcode = 4'd10;
          a = 50;
          b = 44;
          enter = 1'b1;
        # 20

          a = 550;
          b = 440;

        # 20

        opcode = 4'd11;
          a = 11;
          b = 9;

        # 20

          a = 11;
          b = 21;

        # 20    
      
        opcode = 4'd12;
          a = 56;
          b = 10;

        # 20

          a = 555;
          b = 10;

        # 20        
        opcode = 4'd13;

          a = 70;
          b = 7;

        # 20

          a = 7;
          b = 70;

        # 20

          a = 770;
          b = 11;

        # 20    

        $stop;
    end
    always #(`clock_period/2) clk = ~clk; //50M
    
    calc #(.N(16)) calc_0(
            .clk(clk),
            .rst_n(rst_n),
            .opcode(opcode),
                .enter(enter),
            .a(a),
            .b(b),
                
                
            .result(result)
            );
        

/*  initial begin
     a = 0;
     repeat(20)
        #(`clock_period) a = {$random}%100; //通過位拼接操作{}產生0—59范圍的隨機數

  end

  initial begin
     b = 0;
     repeat(20)
        #(`clock_period) b = {$random}%50;

  end*/
endmodule
calc_tb

 

小BUG:當減法結果為負數時,輸出到txt不能正常顯示該負數。

 解決:輸出端口result設為signed類型即可


免責聲明!

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



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