【计算机组成原理】乘法器verilog代码实现 补码乘法

平台:vivado

算法:booth

输入输出为补码形式

乘法器代码:

module multi (
    input signed [31:0] op1,
    input signed [31:0] op2,
    output reg signed [63:0] result,
    input clk,    //时钟 
    input start,  //开始标志 可以是拨动一个拨码开关 
    input ret_n,  //复位标志 低电平复位
    output reg done,
    output reg auxiliary //辅助位
);
    //增加开始标志和结束标志的乘法器 输入的数是补码 要按补码的乘法来做
    reg signed [32:0] acc;
    reg signed [32:0] op1_t;
    reg signed [31:0] op2_t;
    reg signed [32:0] op1_to; //被乘数的相反数的补码
    reg [5:0] k;

    initial begin
        acc = 33'b0;
        op1_t = 33'b0;
        op2_t = 32'b0;
        op1_to = 33'b0;
        k = 6'b0;
        done = 1'b0;
        auxiliary = 1'b0;
        result = 64'b0;
    end

    always @(posedge clk or negedge ret_n) begin
        if(!ret_n) begin  //如果为0 复位 非阻塞 同时赋值
            result <= 64'b0;
            done <= 1'b0;
            acc <= 33'b0;
            auxiliary <= 1'b0;
            op1_t <= 33'b0;
            op2_t <= 32'b0;
            op1_to <= 33'b0;
            k <= 6'b0;
        end else begin
            if (start && !done) begin
                if (k == 0) begin
                    op1_t <= {op1[31], op1};
                    op2_t <= op2;
                    op1_to <= ~{op1[31], op1} + 1'b1;
                    k <= k + 1;
                    #1 $display("op1t=%d",op1_t);
                end else if (k < 32) begin
                    #1 $display("au=%d op2t=%d,op2t[0]=%d -op1t=%d",auxiliary,op2_t,op2_t[0],-op1_t);
                    case ({auxiliary, op2_t[0]})
                        2'b10: acc <= acc + op1_t;
                        2'b01: acc <= acc - op1_t;
                        default: acc <= acc;
                    endcase
                    #1 //$display("accadd %d",acc);/// ?????为什么 加上这个输出就对了???
                    //重点不是输出 是#1 等待1单位时间
                    // 右移
                    auxiliary <= op2_t[0];
                    op2_t <= {acc[0], op2_t[31:1]};
                    acc <= {acc[32], acc[32:1]};
                    k <= k + 1;
                    #1 $display("rightmove: k=%d acc=%d ",k,acc);
                end else begin
                    case ({auxiliary, op2_t[0]})
                        2'b10: acc <= acc + op1_t;
                        2'b01: acc <= acc - op1_t;
                        default: acc <= acc;
                    endcase
                    #1 $display("result acc=%d op2t=%d op2t[31:1]=%d",acc,op2_t,op2_t[31:1]);
                    // result <= {acc[32],1'b0,acc[30:0], op2_t[31:1]};
                    result <= {acc, op2_t[31:1]}; //这里还是有一个问题 为什么可以识别两个符号位
                    done <= 1'b1;
                    k <= 6'b0;
                end
            end else begin
                // done <= 1'b0;
            end
        end
    end
endmodule

acc不能使用非阻塞赋值 acc加改为=也可

测试文件

`timescale 1ns / 1ps

module tb_multi;

    // 定义信号
    reg start_switch;
    reg ret_n_switch;
    wire done_led;
    reg [31:0] op1;
    reg [31:0] op2;
    wire [63:0] result;
    reg clk;

    // 实例化顶层模�?
    multi uut (
       .start(start_switch),
       .ret_n(ret_n_switch),
       .done(done_led),
       .op1(op1),
       .op2(op2),
       .result(result),
       .clk(clk)
    );

    // 时钟生成
    initial begin
        clk = 0;
        forever #5 clk = ~clk; // 10ns 时钟周期
    end

    // 测试序列
    initial begin
        // 初始化信�?
        start_switch = 0;
        ret_n_switch = 0;
        op1 = 32'd20;
        op1=~op1;
        op1=op1+1;
        op1[31]=1;
        // op1=~op1;
        // op1=op1+1;
        op2 = 32'd30;
        #20; // 等待�?段时间,确保复位完成

        // 释放复位信号
        ret_n_switch = 1;
        #20;

        // 启动乘法运算
        start_switch = 1;
        // #320;
        // start_switch = 0;

        // 等待运算完成
        wait (done_led);
        #20;

        // 显示结果
        $display("op1 = %d, op2 = %d, result = %d", op1, op2, result);

    end

endmodule

外围调用模块 (实验箱有lcd屏)

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/10/22 14:55:24
// Design Name: 
// Module Name: display_multiply
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
/*2025年3月23日15点45分 by 某人*/
//////////////////////////////////////////////////////////////////////////////////

module mul_display(
    input clk,
    input resetn,
    
    
    input input_sel,
    input sw_cin,
    output led_cout,
    
    // 实验箱拨码开关输入
    input wire start_switch,  // 对应 start 信号
    input wire ret_n_switch,  // 对应 ret_n 信号
    // 实验箱 LED 输出
    output wire done_led,     // 对应 done 信号

    
    
    //lcd 触摸屏相关接口,不需要更改
    output lcd_rst,
    output lcd_cs,
    output lcd_rs,
    output lcd_wr,
    output lcd_rd,
    inout[15:0] lcd_data_io,
    output lcd_bl_ctr,
    inout ct_int,
    inout ct_sda,
    output ct_scl,
    output ct_rstn
    );
    
    
    
//-----{调用乘法法模块}
    reg [31:0] mul_a;
    reg [31:0] mul_b;
    //wire adder_cin;
    wire [63:0] mul_result;
    //wire adder_cout;
    multi multiply_module(//需要改引脚名称
    .op1(mul_a),
    .op2(mul_b),
    .result(mul_result),
    .clk(clk),       // 假设 clk 是时钟信号,需要在顶层模块处理
    .start(start_switch),
    .ret_n(ret_n_switch),
    .done(done_led),
    .auxiliary()   
    );
    //assign adder_cin = sw_cin;
    //assign led_cout = adder_cout;
    
    
    
//---------------------{调用触摸屏模块}begin--------------------
//-----{实例化触摸屏}begin
//此小节不需要更改    
    reg display_valid;
    reg [39:0] display_name;
    reg [31:0] display_value;
    wire [5 :0] display_number;
    wire input_valid;
    wire [31:0] input_value;
    lcd_module lcd_module(
    .clk (clk),
    .resetn (resetn),
    
    
    //调用触摸屏的接口
    .display_valid (display_valid),
    .display_name (display_name),
    .display_value (display_value),
    .display_number (display_number),
    .input_valid (input_valid),
    .input_value (input_value),
    
    //lcd 触摸屏相关接口,不需要更改
    .lcd_rst (lcd_rst),
    .lcd_cs (lcd_cs),
    .lcd_rs (lcd_rs),
    .lcd_wr (lcd_wr),
    .lcd_rd (lcd_rd),
    .lcd_data_io (lcd_data_io),
    .lcd_bl_ctr (lcd_bl_ctr),
    .ct_int (ct_int),
    .ct_sda (ct_sda),
    .ct_scl (ct_scl),
    .ct_rstn (ct_rstn)
    );
//-----{实例化触摸屏}end


//-----{从触摸屏获取输入}begin
//根据实际需要输入的数修改此小节
//建议对每一个数的输入,编写单独一个 always 块



    //当 input_sel 为 0 时,表示输入数为加数 1,即 operand1
        always @(posedge clk)
        begin
        if (!resetn)
            begin
                mul_a<= 32'd0;
            end
        else if(input_valid && !input_sel)
            begin
                mul_a <= input_value;
            end
        end
        
        
        
    //当 input_sel 为 1 时,表示输入数为加数 2,即 operand2
        always @(posedge clk)
        begin
            if (!resetn)
            begin
                mul_b <= 32'd0;
            end
            else if(input_valid && input_sel)
            begin
                mul_b <= input_value;
            end
        end
//-----{从触摸屏获取输入}end       
        




//-----{输出到触摸屏显示}begin
//根据需要显示的数修改此小节,
//触摸屏上共有 44 块显示区域,可显示 44 组 32 位数据
//44 块显示区域从 1 开始编号,编号为 1~44,       
    always @(posedge clk)
    begin
        case(display_number)
            6'd1 :
            begin
                display_valid <= 1'b1;
                display_name <= "MUL_1";
                display_value <= mul_a;
            end
            6'd2 :
            begin
                display_valid <= 1'b1;
                display_name <= "MUL_2";
                display_value <= mul_b;
            end
            6'd3 :
            begin
                 display_valid <= 1'b1;
                 display_name <= "HIGH_";
                 display_value <= mul_result[63:32];
            end
            6'd4 :
                        begin
                            display_valid <= 1'b1;
                            display_name <= "LOW__";
                            display_value <= mul_result[31:0];
                        end
            default:
            begin
                display_valid <= 1'b0;
                display_name <= 40'd0;
                display_value <= 32'd0;
            end
        endcase
    end
//-----{输出到触摸屏显示}end


//----------------------{调用触摸屏模块}end---------------------//
endmodule

问题:最后result<={acc,op2_t[31:1]} acc有两位符号位 为什么结果也是对的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值