// ========== Copyright Header Begin ========================================== // // OpenSPARC T1 Processor File: fpu_mul_frac_dp.v // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. // // The above named program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public // License version 2 as published by the Free Software Foundation. // // The above named program is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public // License along with this work; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. // // ========== Copyright Header End ============================================ /////////////////////////////////////////////////////////////////////////////// // // Multiply pipeline fraction datapath. // /////////////////////////////////////////////////////////////////////////////// module fpu_mul_frac_dp ( inq_in1, inq_in2, m6stg_step, m2stg_frac1_dbl_norm, m2stg_frac1_dbl_dnrm, m2stg_frac1_sng_norm, m2stg_frac1_sng_dnrm, m2stg_frac1_inf, m1stg_snan_dbl_in1, m1stg_snan_sng_in1, m2stg_frac2_dbl_norm, m2stg_frac2_dbl_dnrm, m2stg_frac2_sng_norm, m2stg_frac2_sng_dnrm, m2stg_frac2_inf, m1stg_snan_dbl_in2, m1stg_snan_sng_in2, m1stg_inf_zero_in, m1stg_inf_zero_in_dbl, m1stg_dblop, m1stg_dblop_inv, m4stg_frac, m4stg_sh_cnt_in, m3bstg_ld0_inv, m4stg_left_shift_step, m4stg_right_shift_step, m5stg_fmuls, m5stg_fmulda, mul_frac_out_fracadd, mul_frac_out_frac, m5stg_in_of, m5stg_to_0, fmul_clken_l, rclk, m2stg_frac1_array_in, m2stg_frac2_array_in, m1stg_ld0_1, m1stg_ld0_2, m4stg_frac_105, m3stg_ld0_inv, m4stg_shl_54, m4stg_shl_55, m5stg_frac_32_0, m5stg_frac_dbl_nx, m5stg_frac_sng_nx, m5stg_frac_neq_0, m5stg_fracadd_cout, mul_frac_out, se, si, so ); input [54:0] inq_in1; // request operand 1 to op pipes input [54:0] inq_in2; // request operand 2 to op pipes input m6stg_step; // advance the multiply pipe input m2stg_frac1_dbl_norm; // select line to m2stg_frac1 input m2stg_frac1_dbl_dnrm; // select line to m2stg_frac1 input m2stg_frac1_sng_norm; // select line to m2stg_frac1 input m2stg_frac1_sng_dnrm; // select line to m2stg_frac1 input m2stg_frac1_inf; // select line to m2stg_frac1 input m1stg_snan_dbl_in1; // operand 1 is double signalling NaN input m1stg_snan_sng_in1; // operand 1 is single signalling NaN input m2stg_frac2_dbl_norm; // select line to m2stg_frac2 input m2stg_frac2_dbl_dnrm; // select line to m2stg_frac2 input m2stg_frac2_sng_norm; // select line to m2stg_frac2 input m2stg_frac2_sng_dnrm; // select line to m2stg_frac2 input m2stg_frac2_inf; // select line to m2stg_frac2 input m1stg_snan_dbl_in2; // operand 2 is double signalling NaN input m1stg_snan_sng_in2; // operand 2 is single signalling NaN input m1stg_inf_zero_in; // 1 operand is infinity; other is 0 input m1stg_inf_zero_in_dbl; // 1 opnd is infinity; other is 0- dbl input m1stg_dblop; // double precision operation- mul 1 stg input m1stg_dblop_inv; // single or int operation- mul 1 stg input [105:0] m4stg_frac; // multiply array output input [5:0] m4stg_sh_cnt_in; // multiply normalization shift count input [6:0] m3bstg_ld0_inv; // leading 0's in multiply operands input m4stg_left_shift_step; // select line to m5stg_frac input m4stg_right_shift_step; // select line to m5stg_frac input m5stg_fmuls; // fmuls- multiply 5 stage input m5stg_fmulda; // fmuld- multiply 5 stage input mul_frac_out_fracadd; // select line to mul_frac_out input mul_frac_out_frac; // select line to mul_frac_out input m5stg_in_of; // multiply overflow- select exp out input m5stg_to_0; // result to max finite on overflow input fmul_clken_l; // multiply pipe clk enable - asserted low input rclk; // global clock output [52:0] m2stg_frac1_array_in; // multiply array input 1 output [52:0] m2stg_frac2_array_in; // multiply array input 2 output [5:0] m1stg_ld0_1; // denorm operand 1 leading 0's output [5:0] m1stg_ld0_2; // denorm operand 2 leading 0's output m4stg_frac_105; // multiply stage 4a fraction input[105] output [6:0] m3stg_ld0_inv; // leading 0's in multiply operands output m4stg_shl_54; // multiply shift left output bit[54] output m4stg_shl_55; // multiply shift left output bit[55] output [32:0] m5stg_frac_32_0; // multiply stage 5 fraction input output m5stg_frac_dbl_nx; // double precision inexact result output m5stg_frac_sng_nx; // single precision inexact result output m5stg_frac_neq_0; // fraction input to mul 5 stage != 0 output m5stg_fracadd_cout; // fraction rounding adder carry out output [51:0] mul_frac_out; // multiply fraction output input se; // scan_enable input si; // scan in output so; // scan out wire [54:0] mul_frac_in1; wire [54:0] mul_frac_in2; wire [52:0] m2stg_frac1_in; wire [52:0] m2stg_frac1_array_in; wire [52:0] m2stg_frac2_in; wire [52:0] m2stg_frac2_array_in; wire [52:0] m1stg_ld0_1_din; wire [5:0] m1stg_ld0_1; wire [52:0] m1stg_ld0_2_din; wire [5:0] m1stg_ld0_2; wire m4stg_frac_105; wire [5:0] m4stg_sh_cnt_5; wire [5:0] m4stg_sh_cnt_4; wire [5:0] m4stg_sh_cnt; wire [6:0] m3stg_ld0_inv; wire [168:63] m4stg_shl_tmp; wire [55:0] m4stg_shl; wire m4stg_shl_54; wire m4stg_shl_55; // 2/18/03: Changed to 225:0 (for easier LEC matching plus closer to implementation) // wire [219:0] m4stg_shr_tmp; wire [168:0] m4stg_shr_tmp; wire [55:0] m4stg_shr; wire [54:0] m5stg_frac_pre1_in; wire [54:0] m5stg_frac_pre1; wire [54:0] m5stg_frac_pre2_in; wire [54:0] m5stg_frac_pre2; wire [54:0] m5stg_frac_pre3_in; wire [54:0] m5stg_frac_pre3; wire [54:0] m5stg_frac_pre4_in; wire [54:0] m5stg_frac_pre4; wire [54:33] m5stg_frac_54_33; wire [32:0] m5stg_frac_32_0; wire [54:3] m5stg_fraca; wire [54:0] m5stg_fracb; wire m5stg_frac_dbl_nx; wire m5stg_frac_sng_nx; wire m5stg_frac_neq_0; wire [52:0] m5stg_fracadd_tmp; wire m5stg_fracadd_cout; wire [51:0] m5stg_fracadd; wire [51:0] mul_frac_out_in; wire [51:0] mul_frac_out; wire [30:0] mstg_xtra_regs; wire se_l; assign se_l = ~se; clken_buf ckbuf_mul_frac_dp ( .clk(clk), .rclk(rclk), .enb_l(fmul_clken_l), .tmb_l(se_l) ); /////////////////////////////////////////////////////////////////////////////// // // Multiply fraction inputs. // // Multiply input stage. // /////////////////////////////////////////////////////////////////////////////// dffe_s #(55) i_mul_frac_in1 ( .din (inq_in1[54:0]), .en (m6stg_step), .clk (clk), .q (mul_frac_in1[54:0]), .se (se), .si (), .so () ); dffe_s #(55) i_mul_frac_in2 ( .din (inq_in2[54:0]), .en (m6stg_step), .clk (clk), .q (mul_frac_in2[54:0]), .se (se), .si (), .so () ); /////////////////////////////////////////////////////////////////////////////// // // Multiply normalization and special input injection. // // Multiply stage 1. // /////////////////////////////////////////////////////////////////////////////// assign m2stg_frac1_in[52:0]= ({53{m2stg_frac1_dbl_norm}} & {1'b1, (mul_frac_in1[51] || m1stg_snan_dbl_in1), mul_frac_in1[50:0]}) | ({53{m2stg_frac1_dbl_dnrm}} & {mul_frac_in1[51:0], 1'b0}) | ({53{m2stg_frac1_sng_norm}} & {1'b1, (mul_frac_in1[54] || m1stg_snan_sng_in1), mul_frac_in1[53:32], 29'b0}) | ({53{m2stg_frac1_sng_dnrm}} & {mul_frac_in1[54:32], 30'b0}) | ({53{m2stg_frac1_inf}} & 53'h10000000000000); assign m2stg_frac1_array_in[52:0]= (~m2stg_frac1_in[52:0]); assign m2stg_frac2_in[52:0]= ({53{m2stg_frac2_dbl_norm}} & {1'b1, (mul_frac_in2[51] || m1stg_snan_dbl_in2), mul_frac_in2[50:0]}) | ({53{m2stg_frac2_dbl_dnrm}} & {mul_frac_in2[51:0], 1'b0}) | ({53{m2stg_frac2_sng_norm}} & {1'b1, (mul_frac_in2[54] || m1stg_snan_sng_in2), mul_frac_in2[53:32], 29'b0}) | ({53{m2stg_frac2_sng_dnrm}} & {mul_frac_in2[54:32], 30'b0}) | ({53{m2stg_frac2_inf}} & {1'b1, {23{m1stg_inf_zero_in}}, {29{m1stg_inf_zero_in_dbl}}}); assign m2stg_frac2_array_in[52:0]= m2stg_frac2_in[52:0]; /////////////////////////////////////////////////////////////////////////////// // // Multiply leading 0 counts. // // Multiply stage 1. // /////////////////////////////////////////////////////////////////////////////// assign m1stg_ld0_1_din[52:0]= ({53{m1stg_dblop_inv}} & {mul_frac_in1[54:32], 30'b0}) | ({53{m1stg_dblop}} & {mul_frac_in1[51:0], 1'b0}); fpu_cnt_lead0_53b i_m1stg_ld0_1 ( .din (m1stg_ld0_1_din[52:0]), .lead0 (m1stg_ld0_1[5:0]) ); assign m1stg_ld0_2_din[52:0]= ({53{m1stg_dblop_inv}} & {mul_frac_in2[54:32], 30'b0}) | ({53{m1stg_dblop}} & {mul_frac_in2[51:0], 1'b0}); fpu_cnt_lead0_53b i_m1stg_ld0_2 ( .din (m1stg_ld0_2_din[52:0]), .lead0 (m1stg_ld0_2[5:0]) ); /////////////////////////////////////////////////////////////////////////////// // // Multiply shifts for post-normalization/denormalization. // // Multiply stage 4a. // /////////////////////////////////////////////////////////////////////////////// assign m4stg_frac_105= m4stg_frac[105]; dffe_s #(56) i_mstg_xtra_regs ( .din ({{6{m4stg_sh_cnt_in[5]}}, {6{m4stg_sh_cnt_in[4]}}, m4stg_sh_cnt_in[5:0], m3bstg_ld0_inv[6:0], 31'h0000_0000}), .en (m6stg_step), .clk (clk), .q ({m4stg_sh_cnt_5[5:0], m4stg_sh_cnt_4[5:0], m4stg_sh_cnt[5:0], m3stg_ld0_inv[6:0], mstg_xtra_regs[30:0]}), .se (se), .si (), .so () ); //assign m4stg_shl_tmp[168:0]= {m4stg_frac[105:0], 63'b0} // << {m4stg_sh_cnt_5[0], m4stg_sh_cnt[4:0]}; assign m4stg_shl_tmp[168:63]= m4stg_frac[105:0] << {m4stg_sh_cnt_5[0], m4stg_sh_cnt[4:0]}; assign m4stg_shl[55:0]= {m4stg_shl_tmp[168:114], (|m4stg_shl_tmp[113:63])}; assign m4stg_shl_54= m4stg_shl[54]; assign m4stg_shl_55= m4stg_shl[55]; // 2/18/03: changed below to match implementation plus easier LEC // assign m4stg_shr_tmp[219:0]= {57'b0, m4stg_frac[105:0], 57'b0} // >> m4stg_sh_cnt[5:0]; // assign m4stg_shr[55:0]= {m4stg_shr_tmp[162:108], (|m4stg_shr_tmp[107:0])}; //assign m4stg_shr_tmp[225:0]= {57'b0, m4stg_frac[105:0], 63'b0} >> m4stg_sh_cnt[5:0]; assign m4stg_shr_tmp[168:0]= { m4stg_frac[105:0], 63'b0} >> m4stg_sh_cnt[5:0]; assign m4stg_shr[55:0]= {m4stg_shr_tmp[168:114], (|m4stg_shr_tmp[113:0])}; /////////////////////////////////////////////////////////////////////////////// // // Select post-normalization or denormalization result. // // Multiply stage 4. // /////////////////////////////////////////////////////////////////////////////// // 2/18/03: Inverted the logic (nand instead of and) to reflect implementation and easier LEC // assign m5stg_frac_pre1_in[54:0]= ({55{(m4stg_left_shift_step && m4stg_shl[55])}} // & m4stg_shl[54:0]) // | ({55{(!m6stg_step)}} // & m5stg_fracb[54:0]); assign m5stg_frac_pre1_in[54:0]= ~(({55{(m4stg_left_shift_step && m4stg_shl[55])}} & m4stg_shl[54:0]) | ({55{(!m6stg_step)}} & m5stg_fracb[54:0])); dff_s #(55) i_m5stg_frac_pre1 ( .din (m5stg_frac_pre1_in[54:0]), .clk (clk), .q (m5stg_frac_pre1[54:0]), .se (se), .si (), .so () ); // 2/18/03: Inverted the logic (nand instead of and) to reflect implementation and easier LEC // assign m5stg_frac_pre2_in[54:0]= ({55{(m4stg_left_shift_step // && (!m4stg_shl[55]))}} // & {m4stg_shl[53:0], 1'b0}); assign m5stg_frac_pre2_in[54:0]= ~({55{(m4stg_left_shift_step && (!m4stg_shl[55]))}} & {m4stg_shl[53:0], 1'b0}); dff_s #(55) i_m5stg_frac_pre2 ( .din (m5stg_frac_pre2_in[54:0]), .clk (clk), .q (m5stg_frac_pre2[54:0]), .se (se), .si (), .so () ); // 2/18/03: Inverted the logic (nand instead of and) to reflect implementation and easier LEC // assign m5stg_frac_pre3_in[54:0]= ({55{(m4stg_right_shift_step // && m4stg_shr[55])}} // & m4stg_shr[54:0]); assign m5stg_frac_pre3_in[54:0]= ~({55{(m4stg_right_shift_step && m4stg_shr[55])}} & m4stg_shr[54:0]); dff_s #(55) i_m5stg_frac_pre3 ( .din (m5stg_frac_pre3_in[54:0]), .clk (clk), .q (m5stg_frac_pre3[54:0]), .se (se), .si (), .so () ); // 2/18/03: Inverted the logic (nand instead of and) to reflect implementation and easier LEC // assign m5stg_frac_pre4_in[54:0]= ({55{(m4stg_right_shift_step // && (!m4stg_shr[55]))}} // & {m4stg_shr[53:0], 1'b0}); assign m5stg_frac_pre4_in[54:0]= ~({55{(m4stg_right_shift_step && (!m4stg_shr[55]))}} & {m4stg_shr[53:0], 1'b0}); dff_s #(55) i_m5stg_frac_pre4 ( .din (m5stg_frac_pre4_in[54:0]), .clk (clk), .q (m5stg_frac_pre4[54:0]), .se (se), .si (), .so () ); // 2/18/03: Inverted the logic (nand instead of or) to reflect implementation and easier LEC // assign m5stg_frac[54:0]= (m5stg_frac_pre1[54:0] // | m5stg_frac_pre2[54:0] // | m5stg_frac_pre3[54:0] // | m5stg_frac_pre4[54:0]); assign {m5stg_frac_54_33[54:33], m5stg_frac_32_0[32:0]} = ~(m5stg_frac_pre1[54:0] & m5stg_frac_pre2[54:0] & m5stg_frac_pre3[54:0] & m5stg_frac_pre4[54:0]); assign m5stg_fraca[54:3]= {m5stg_frac_54_33[54:33], m5stg_frac_32_0[32:3]}; assign m5stg_fracb[54:0]= {m5stg_frac_54_33[54:33], m5stg_frac_32_0[32:0]}; /////////////////////////////////////////////////////////////////////////////// // // Multiply rounding. // // Multiply stage 5. // /////////////////////////////////////////////////////////////////////////////// assign m5stg_frac_dbl_nx= (|m5stg_fracb[2:0]); assign m5stg_frac_sng_nx= m5stg_frac_dbl_nx || (|m5stg_fracb[31:3]); assign m5stg_frac_neq_0= m5stg_frac_sng_nx || (|m5stg_fracb[54:32]); assign m5stg_fracadd_tmp[52:0]= {1'b0, m5stg_fraca[54:3]} + {23'b0, m5stg_fmuls, 28'b0, m5stg_fmulda}; assign m5stg_fracadd_cout= m5stg_fracadd_tmp[52]; assign m5stg_fracadd[51:0]= m5stg_fracadd_tmp[51:0]; assign mul_frac_out_in[51:0]= ({52{mul_frac_out_fracadd}} & m5stg_fracadd[51:0]) | ({52{mul_frac_out_frac}} & m5stg_fracb[54:3]) | ({52{m5stg_in_of}} & {52{m5stg_to_0}}); dffe_s #(52) i_mul_frac_out ( .din (mul_frac_out_in[51:0]), .en (m6stg_step), .clk (clk), .q (mul_frac_out[51:0]), .se (se), .si (), .so () ); endmodule