• 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类型即可

  • 相关阅读:
    读取xml文件(可执行文件根目录debug)
    c# winform textbox与combox让用户不能输入
    枚举类型
    值类型与引用类型
    error: failed to push some refs to 'https://git.oschina.net/bluede/TuShuGuanLi.g it'
    left join on 和where中条件的放置位置
    left join、right join、inner join、full join
    Union、Union All、Intersect、Minus
    分层设计的好处
    Hibernate查询方式
  • 原文地址:https://www.cnblogs.com/HuangYJ/p/13060790.html
Copyright © 2020-2023  润新知