verilog float mult
module pipe_float_mul(input wire clk ,// 时钟信号input wire en ,// 使能信号input wire rst_n ,// 复位信号input wire round_cfg ,// 决定舍入的方法,0采用chopping,1采用就近舍入 input wire [31:0] flout_a ,// 输入的被乘数input wire [31:0] flout_b ,// 输入的乘数output reg [31:0] flout_c ,// 输出运算结果output wire valid_flout_c ,output reg [1:0] overflow // 输出溢出标志 ); reg s1, s2; // 输入数符号reg [7:0] exp1, exp2; // 输入阶码reg [23:0] man1, man2; // 输入尾数,多一位,把默认的'1'加上reg n; // 左归阶码reg [9:0] temp1, temp2, temp3; // 多两位,用于阶码的双符号表示,判断溢出reg [47:0] mul_out_p; // 第二级逻辑运算尾数部分//-------'s'为符号,'e'为阶码,'m'为尾数------------////第一级逻辑输出wire one_s_out;wire [9:0] one_e_out;reg [47:0] one_m_out;//第一级流水寄存reg one_s_reg; reg [9:0] one_e_reg; reg [47:0] one_m_reg;//第二级逻辑输出reg [1:0] two_f_out; //溢出reg [7:0] two_e_out; reg [22:0] two_m_out; //第二级流水寄存reg two_s_reg;reg [1:0] two_f_reg; //溢出reg [7:0] two_e_reg;reg [22:0] two_m_reg;reg [4:0] cnt_delay ;assign valid_flout_c = ( cnt_delay == 5'd3 )?1'b1:1'b0 ;
/*---------------提取flout_a 的符号,阶码,尾数---------------------*/
always @(posedge clk or negedge rst_n) beginif (!rst_n) begin //复位,初始化s1 <= 1'b0;exp1 <= 8'b0;man1 <= {1'b1, 23'b0};cnt_delay <= 5'd0 ;endelse beginif( cnt_delay == 5'd5 )begincnt_delay <= 5'd0 ;endelse if( en == 1'b1 )begincnt_delay <= 5'd1 ;endelse if( cnt_delay >= 5'd1 )begincnt_delay <= cnt_delay + 1'b1 ;endelse if( cnt_delay == 5'd0 )begincnt_delay <= 5'd0 ;endelsebegincnt_delay <= cnt_delay ;endif (en == 1'b1 ) begins1 <= flout_a[31];exp1 <= flout_a[30:23];man1 <= {1'b1, flout_a[22:0]};endendend/*---------------提取flout_b 的符号,阶码,尾数---------------------*/
always @(posedge clk or negedge rst_n) beginif (!rst_n) begin //复位,初始化s2 <= 1'b0;exp2 <= 8'b0;man2 <= {1'b1, 23'b0};endelse if (en) begins2 <= flout_b[31];exp2 <= flout_b[30:23];man2 <= {1'b1, flout_b[22:0]};end
end/*--------------------第一级逻辑运算---------------------------------*/
//符号位
assign one_s_out = s1 ^ s2; //输入符号异或//尾数相乘
always@(*) beginif (man1 == 24'b10000000000_0000000000000)one_m_out = 48'b0;else if (man2 == 24'b10000000000_0000000000000)one_m_out = 48'b0;elseone_m_out = man1 * man2; //48位
end//阶码相加,阶码是移码,移码是符号位取反的补码
always@(*) begin//把阶码的移码形式变为补码形式,并且转成双符号位格式,00为正,11为负if (exp1[7] == 1)temp1 = {2'b00, 1'b0, exp1[6:0]};else temp1 = {2'b11, 1'b1, exp1[6:0]};if (exp2[7] == 1)temp2 = {2'b00, 1'b0, exp2[6:0]};elsetemp2 = {2'b11, 1'b1, exp2[6:0]};
end//阶码以双符号补码的形式相加计算
assign one_e_out[9:0] = temp1[9:0] + temp2[9:0]; /*--------------------第一级流水寄存---------------------------------*/
always@(posedge clk or negedge rst_n) beginif (!rst_n) beginone_s_reg <= 1'b0;one_e_reg <= 10'b0;one_m_reg <= 48'b0;endelse beginone_s_reg <= one_s_out;one_e_reg <= one_e_out;one_m_reg <= one_m_out;end
end/*--------------------第二级逻辑运算---------------------------------*/
//尾数规范化及舍入处理,溢出判断
always@(*) beginif (one_m_reg == 48'b0) begin // 处理特殊值two_m_out = 23'b0;n = 1'b0;end else beginif (one_m_reg[47] == 1) beginn = 1'b1; // 左归码为1mul_out_p = one_m_reg >> 1; // 右移一位endelse beginn = 1'b0; // 左归码为0mul_out_p = one_m_reg; // 不需要右移endif (round_cfg == 1) begin // 0采用chopping,1采用就近舍入 if (mul_out_p[22] == 1)two_m_out[22:0] = mul_out_p[45:23] + 1'b1;elsetwo_m_out[22:0] = mul_out_p[45:23];endelse two_m_out[22:0] = mul_out_p[45:23];end// 双符号的定义,01为上溢,10为下溢,符号相同无溢出temp3 = one_e_reg[9:0] + n + 1'b1; // 加上左归阶码,因为补码与移码的转换是-128,而IEEE是-127,故加上1if (temp3[9:8] == 2'b01) two_f_out = 2'b01; //阶码上溢else if (temp3[9:8] == 2'b10) two_f_out = 2'b10; //阶码下溢else two_f_out = 2'b00; //无溢出//输出补码转回移码case(temp3[7]) 1'b1 : two_e_out = {1'b0,temp3[6:0]}; 1'b0 : two_e_out = {1'b1,temp3[6:0]}; endcase
end/*-------------------第二级流水寄存------------------------------------*/
always@(posedge clk or negedge rst_n) beginif (!rst_n) begintwo_s_reg <= 1'b0;two_e_reg <= 8'b0;two_m_reg <= 23'b0;two_f_reg <= 2'b0;endelse if ((two_m_out == 0) && (two_e_out == 0)) begin //特殊值处理two_s_reg <= 1'b0;two_e_reg <= 8'b0;two_m_reg <= 23'b0;two_f_reg <= 2'b0;endelse begintwo_s_reg <= one_s_reg;two_f_reg <= two_f_out;two_e_reg <= two_e_out;two_m_reg <= two_m_out;end
end//输出结果
always@(*) beginflout_c = ( valid_flout_c == 1'b1 )?{two_s_reg, two_e_reg[7:0], two_m_reg[22:0]}:32'd0;overflow = two_f_reg;
endendmodule
tb
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2025/04/19 15:16:46
// Design Name:
// Module Name: tb_pipe_float_mul
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module tb_pipe_float_mul();reg clk ;// 时钟信号reg en ;// 使能信号reg rst_n ;// 复位信号reg round_cfg ;// 决定舍入的方法,0采用chopping,1采用就近舍入 reg [31:0] flout_a ;// 输入的被乘数reg [31:0] flout_b ;// 输入的乘数wire [31:0] flout_c ;// 输出运算结果wire [1:0] overflow ;// 输出溢出标志wire valid_flout_c ;initialbeginclk = 1'b0 ;rst_n = 1'b0 ; en = 1'b0 ;round_cfg = 1'b0 ;#100flout_a = 32'b01000001001000000000000000000000 ;flout_b = 32'b01000001101000000000000000000000 ;en = 1'b1 ;rst_n = 1'b1 ; #10en = 1'b0 ;#20flout_a = 32'b01000001001000000000000000000000 ;flout_b = 32'b11000001101000000000000000000000 ;en = 1'b1 ;rst_n = 1'b1 ; #10en = 1'b0 ;#10$finish ;endalways #5beginclk = ~clk ;endpipe_float_mul pipe_float_mul_inst(.clk (clk),// 时钟信号.en (en),// 使能信号.rst_n (rst_n),// 复位信号.round_cfg (round_cfg),// 决定舍入的方法,0采用chopping,1采用就近舍入 .flout_a (flout_a),// 输入的被乘数.flout_b (flout_b),// 输入的乘数.flout_c (flout_c),// 输出运算结果.valid_flout_c (valid_flout_c),.overflow (overflow) // 输出溢出标志 ); endmodule