Line 16... |
Line 16... |
// You should have received a copy of the GNU General Public
|
// You should have received a copy of the GNU General Public
|
// License along with this work; if not, write to the Free Software
|
// License along with this work; if not, write to the Free Software
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
//
|
//
|
// ========== Copyright Header End ============================================
|
// ========== Copyright Header End ============================================
|
|
`ifdef SIMPLY_RISC_TWEAKS
|
|
`define SIMPLY_RISC_SCANIN .si(0)
|
|
`else
|
|
`define SIMPLY_RISC_SCANIN .si()
|
|
`endif
|
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
/*
|
/*
|
// Module Name: sparc_exu_ecl_mdqctl
|
// Module Name: sparc_exu_ecl_mdqctl
|
// Description: This block is the control logic for the multiply/divide
|
// Description: This block is the control logic for the multiply/divide
|
// input buffer. It generates the select lines for both the output
|
// input buffer. It generates the select lines for both the output
|
Line 32... |
Line 37... |
// of the mdq, but may cause a lost cycle as the kill won't affect the logic
|
// of the mdq, but may cause a lost cycle as the kill won't affect the logic
|
// which chooses the output until the next cycle. The block also
|
// which chooses the output until the next cycle. The block also
|
// stores the thr, rd, setcc and other control bits for each entry.
|
// stores the thr, rd, setcc and other control bits for each entry.
|
*/
|
*/
|
|
|
|
`define MULS 10
|
|
`define IS64 9
|
|
`define SIGNED 8
|
|
`define SET_CC 7
|
|
|
module sparc_exu_ecl_mdqctl (/*AUTOARG*/
|
module sparc_exu_ecl_mdqctl (/*AUTOARG*/
|
// Outputs
|
// Outputs
|
mdqctl_divcntl_input_vld, mdqctl_divcntl_reset_div,
|
mdqctl_divcntl_input_vld, mdqctl_divcntl_reset_div,
|
mdqctl_divcntl_muldone, ecl_div_div64, ecl_div_signed_div,
|
mdqctl_divcntl_muldone, ecl_div_div64, ecl_div_signed_div,
|
Line 170... |
Line 175... |
.in0({curr_div_vld, div_data[10:0]}),
|
.in0({curr_div_vld, div_data[10:0]}),
|
.in1(div_input_data_d[11:0]),
|
.in1(div_input_data_d[11:0]),
|
.sel0(~new_div_vld),
|
.sel0(~new_div_vld),
|
.sel1(new_div_vld));
|
.sel1(new_div_vld));
|
|
|
dffr #(12) div_data_dff(.din(div_data_next[11:0]), .clk(clk), .q(div_data[11:0]),
|
dffr_s #(12) div_data_dff(.din(div_data_next[11:0]), .clk(clk), .q(div_data[11:0]),
|
.se(se), .si(), .so(), .rst(reset));
|
.se(se), `SIMPLY_RISC_SCANIN, .so(), .rst(reset));
|
|
|
//div kill logic (kills on div by zero exception or if there isn't an outstanding div)
|
//div kill logic (kills on div by zero exception or if there isn't an outstanding div)
|
assign div_zero_e = isdiv_e & div_ecl_detect_zero_high & div_ecl_detect_zero_low & ~div_data[10];
|
assign div_zero_e = isdiv_e & div_ecl_detect_zero_high & div_ecl_detect_zero_low & ~div_data[`MULS];
|
assign invalid_div_w = isdiv_w & (~ifu_exu_inst_vld_w | ifu_tlu_flush_w | early_flush_w);
|
assign invalid_div_w = isdiv_w & (~ifu_exu_inst_vld_w | ifu_tlu_flush_w | early_flush_w);
|
assign kill_thr_div = ~(div_data[1] ^ tid_w1[1]) & ~(div_data[0] ^ tid_w1[0]);
|
assign kill_thr_div = ~(div_data[1] ^ tid_w1[1]) & ~(div_data[0] ^ tid_w1[0]);
|
assign div_kill = (flush_w1 & kill_thr_div) | invalid_div_w | new_div_vld;
|
assign div_kill = (flush_w1 & kill_thr_div) | invalid_div_w | new_div_vld;
|
assign curr_div_vld = div_data[11] & ~div_zero_m & ~div_kill & ~div_used;
|
assign curr_div_vld = div_data[11] & ~div_zero_m & ~div_kill & ~div_used;
|
|
|
wire div_zero_unqual_m;
|
wire div_zero_unqual_m;
|
assign div_zero_m = div_zero_unqual_m & isdiv_m;
|
assign div_zero_m = div_zero_unqual_m & isdiv_m;
|
dff div_zero_e2m(.din(div_zero_e), .clk(clk), .q(div_zero_unqual_m), .se(se), .si(), .so());
|
dff_s div_zero_e2m(.din(div_zero_e), .clk(clk), .q(div_zero_unqual_m), .se(se), `SIMPLY_RISC_SCANIN, .so());
|
|
|
// pipeling for divide valid signal (for inst_vld checking)
|
// pipeling for divide valid signal (for inst_vld checking)
|
dff isdiv_d2e(.din(new_div_vld), .clk(clk), .q(isdiv_e),
|
dff_s isdiv_d2e(.din(new_div_vld), .clk(clk), .q(isdiv_e),
|
.se(se), .si(), .so());
|
.se(se), `SIMPLY_RISC_SCANIN, .so());
|
dff isdiv_e2m(.din(isdiv_e_valid), .clk(clk), .q(isdiv_m),
|
dff_s isdiv_e2m(.din(isdiv_e_valid), .clk(clk), .q(isdiv_m),
|
.se(se), .si(), .so());
|
.se(se), `SIMPLY_RISC_SCANIN, .so());
|
dff isdiv_m2w(.din(isdiv_m_valid), .clk(clk), .q(isdiv_w),
|
dff_s isdiv_m2w(.din(isdiv_m_valid), .clk(clk), .q(isdiv_w),
|
.se(se), .si(), .so());
|
.se(se), `SIMPLY_RISC_SCANIN, .so());
|
assign isdiv_e_valid = isdiv_e & ~div_kill;
|
assign isdiv_e_valid = isdiv_e & ~div_kill;
|
assign isdiv_m_valid = isdiv_m & ~div_kill;
|
assign isdiv_m_valid = isdiv_m & ~div_kill;
|
|
|
// control for div state machine
|
// control for div state machine
|
assign mdqctl_divcntl_reset_div = (~div_data[11] | div_kill);
|
assign mdqctl_divcntl_reset_div = (~div_data[11] | div_kill);
|
assign mdqctl_divcntl_input_vld = isdiv_e;
|
assign mdqctl_divcntl_input_vld = isdiv_e;
|
|
|
// control signals for div
|
// control signals for div
|
assign ecl_div_div64 = div_data[9];
|
assign ecl_div_div64 = div_data[`IS64];
|
assign ecl_div_signed_div = div_data[8];
|
assign ecl_div_signed_div = div_data[`SIGNED];
|
assign ecl_div_muls = div_data[10];
|
assign ecl_div_muls = div_data[`MULS];
|
|
|
// control for writeback on completion
|
// control for writeback on completion
|
assign mdqctl_wb_divrd_g[4:0] = div_data[6:2];
|
assign mdqctl_wb_divrd_g[4:0] = div_data[6:2];
|
assign mdqctl_wb_divthr_g[1:0] = div_data[1:0];
|
assign mdqctl_wb_divthr_g[1:0] = div_data[1:0];
|
assign mdqctl_wb_divsetcc_g = div_data[7] | div_data[10];
|
assign mdqctl_wb_divsetcc_g = div_data[`SET_CC] | div_data[`MULS];
|
assign mdqctl_wb_yreg_shift_g = div_used & div_data[10];
|
assign mdqctl_wb_yreg_shift_g = div_used & div_data[`MULS];
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
// Multiply control
|
// Multiply control
|
//----------------------
|
//----------------------
|
// The multiply will drop the current operation if a new request is issued.
|
// The multiply will drop the current operation if a new request is issued.
|
// This requires addition checking to make sure that the kills are for the
|
// This requires addition checking to make sure that the kills are for the
|
// proper operation.
|
// proper operation.
|
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
dff ismul_d2e(.din(ifu_exu_muldivop_d[4]), .clk(clk), .q(ismul_e),
|
dff_s ismul_d2e(.din(ifu_exu_muldivop_d[4]), .clk(clk), .q(ismul_e),
|
.se(se), .si(), .so());
|
.se(se), `SIMPLY_RISC_SCANIN, .so());
|
dff ismul_e2m(.din(ismul_e_valid), .clk(clk), .q(ismul_m),
|
dff_s ismul_e2m(.din(ismul_e_valid), .clk(clk), .q(ismul_m),
|
.se(se), .si(), .so());
|
.se(se), `SIMPLY_RISC_SCANIN, .so());
|
dff ismul_m2w(.din(ismul_m_valid), .clk(clk), .q(ismul_w),
|
dff_s ismul_m2w(.din(ismul_m_valid), .clk(clk), .q(ismul_w),
|
.se(se), .si(), .so());
|
.se(se), `SIMPLY_RISC_SCANIN, .so());
|
assign ismul_e_valid = ismul_e & ~mul_kill;
|
assign ismul_e_valid = ismul_e & ~mul_kill;
|
assign ismul_m_valid = ismul_m & ~mul_kill & ~ismul_e;
|
assign ismul_m_valid = ismul_m & ~mul_kill & ~ismul_e;
|
|
|
// store control signals
|
// store control signals
|
// assign mul_used = divcntl_wb_req_g & wb_divcntl_ack_g & ~ecl_div_sel_div;
|
// assign mul_used = divcntl_wb_req_g & wb_divcntl_ack_g & ~ecl_div_sel_div;
|
Line 237... |
Line 242... |
ifu_exu_muldivop_d[0], // setcc
|
ifu_exu_muldivop_d[0], // setcc
|
ifu_exu_rd_d[4:0],
|
ifu_exu_rd_d[4:0],
|
tid_d[1:0]};
|
tid_d[1:0]};
|
assign mul_data_next[9:0] = (new_mul_d)? mul_input_data_d[9:0]: mul_data[9:0];
|
assign mul_data_next[9:0] = (new_mul_d)? mul_input_data_d[9:0]: mul_data[9:0];
|
|
|
dff #(10) mul_data_dff(.din(mul_data_next[9:0]), .clk(clk), .q(mul_data[9:0]),
|
dff_s #(10) mul_data_dff(.din(mul_data_next[9:0]), .clk(clk), .q(mul_data[9:0]),
|
.se(se), .si(), .so());
|
.se(se), `SIMPLY_RISC_SCANIN, .so());
|
|
|
// mul kill logic
|
// mul kill logic
|
assign kill_thr_mul = ~(mul_data[1] ^ tid_w1[1]) & ~(mul_data[0] ^ tid_w1[0]);
|
assign kill_thr_mul = ~(mul_data[1] ^ tid_w1[1]) & ~(mul_data[0] ^ tid_w1[0]);
|
assign mul_kill = (flush_w1 & kill_thr_mul) | reset;
|
assign mul_kill = (flush_w1 & kill_thr_mul) | reset;
|
assign invalid_mul_w = ismul_w & ~ifu_exu_inst_vld_w;
|
assign invalid_mul_w = ismul_w & ~ifu_exu_inst_vld_w;
|
|
|
// control signals for mul data in div unit
|
// control signals for mul data in div unit
|
assign ecl_div_mul_keep_data = ~ismul_e;
|
assign ecl_div_mul_keep_data = ~ismul_e;
|
assign ecl_div_mul_get_new_data = ismul_e & mul_data[9];
|
assign ecl_div_mul_get_new_data = ismul_e & mul_data[`IS64];
|
assign ecl_div_mul_get_32bit_data = ismul_e & ~mul_data[9];
|
assign ecl_div_mul_get_32bit_data = ismul_e & ~mul_data[`IS64];
|
assign ecl_div_mul_sext_rs1_e = byp_alu_rs1_data_31_e & mul_data[8];
|
assign ecl_div_mul_sext_rs1_e = byp_alu_rs1_data_31_e & mul_data[`SIGNED];
|
assign ecl_div_mul_sext_rs2_e = byp_alu_rs2_data_31_e & mul_data[8];
|
assign ecl_div_mul_sext_rs2_e = byp_alu_rs2_data_31_e & mul_data[`SIGNED];
|
|
|
// control for writeback on completion
|
// control for writeback on completion
|
assign mdqctl_wb_yreg_wen_g = ~mul_data[9] & ecl_div_mul_wen;
|
assign mdqctl_wb_yreg_wen_g = ~mul_data[`IS64] & ecl_div_mul_wen;
|
assign mdqctl_wb_multhr_g[1:0] = mul_data[1:0];
|
assign mdqctl_wb_multhr_g[1:0] = mul_data[1:0];
|
assign mdqctl_wb_mulsetcc_g = mul_data[7];
|
assign mdqctl_wb_mulsetcc_g = mul_data[`SET_CC];
|
assign mdqctl_wb_mulrd_g[4:0] = mul_data[6:2];
|
assign mdqctl_wb_mulrd_g[4:0] = mul_data[6:2];
|
|
|
// interface with mul and state of pending mul
|
// interface with mul and state of pending mul
|
assign mul_ready_next = ismul_e_valid | (mul_ready & ~mul_exu_ack & ~mul_kill & ~ismul_e & ~invalid_mul_w);
|
assign mul_ready_next = ismul_e_valid | (mul_ready & ~mul_exu_ack & ~mul_kill & ~ismul_e & ~invalid_mul_w);
|
dff mul_ready_dff(.din(mul_ready_next), .clk(clk), .q(mul_ready), .se(se), .si(), .so());
|
dff_s mul_ready_dff(.din(mul_ready_next), .clk(clk), .q(mul_ready), .se(se), `SIMPLY_RISC_SCANIN, .so());
|
|
|
assign exu_mul_input_vld = mul_ready;
|
assign exu_mul_input_vld = mul_ready;
|
|
|
// If there was a valid request and an ack then start passing down pipe
|
// If there was a valid request and an ack then start passing down pipe
|
assign mul_done_ack = mul_ready & ~mul_kill & ~ismul_e & mul_exu_ack & ~invalid_mul_w;
|
assign mul_done_ack = mul_ready & ~mul_kill & ~ismul_e & mul_exu_ack & ~invalid_mul_w;
|
dff dff_done_ack2c0(.din(mul_done_ack), .clk(clk), .q(mul_done_c0),
|
dff_s dff_done_ack2c0(.din(mul_done_ack), .clk(clk), .q(mul_done_c0),
|
.se(se), .si(), .so());
|
.se(se), `SIMPLY_RISC_SCANIN, .so());
|
// need to check here cause this could be w
|
// need to check here cause this could be w
|
assign mul_done_valid_c0 = mul_done_c0 & ~mul_kill & ~invalid_mul_w & ~ismul_e;
|
assign mul_done_valid_c0 = mul_done_c0 & ~mul_kill & ~invalid_mul_w & ~ismul_e;
|
dff dff_done_c02c1(.din(mul_done_valid_c0), .clk(clk), .q(mul_done_c1),
|
dff_s dff_done_c02c1(.din(mul_done_valid_c0), .clk(clk), .q(mul_done_c1),
|
.se(se), .si(), .so());
|
.se(se), `SIMPLY_RISC_SCANIN, .so());
|
// need to check here cause this could be w1
|
// need to check here cause this could be w1
|
assign mul_done_valid_c1 = mul_done_c1 & ~mul_kill & ~ismul_e;
|
assign mul_done_valid_c1 = mul_done_c1 & ~mul_kill & ~ismul_e;
|
dff dff_done_c1c2(.din(mul_done_valid_c1), .clk(clk), .q(mul_done_c2),
|
dff_s dff_done_c1c2(.din(mul_done_valid_c1), .clk(clk), .q(mul_done_c2),
|
.se(se), .si(), .so());
|
.se(se), `SIMPLY_RISC_SCANIN, .so());
|
dff dff_done_c22c3(.din(mul_done_c2), .clk(clk), .q(mul_done_c3),
|
dff_s dff_done_c22c3(.din(mul_done_c2), .clk(clk), .q(mul_done_c3),
|
.se(se), .si(), .so());
|
.se(se), `SIMPLY_RISC_SCANIN, .so());
|
dff dff_done_c32c4(.din(mul_done_c3), .clk(clk), .q(ecl_div_mul_wen),
|
dff_s dff_done_c32c4(.din(mul_done_c3), .clk(clk), .q(ecl_div_mul_wen),
|
.se(se), .si(), .so());
|
.se(se), `SIMPLY_RISC_SCANIN, .so());
|
|
|
// Mul result state machine
|
// Mul result state machine
|
assign go_mul_done = ~mul_done & ecl_div_mul_wen;
|
assign go_mul_done = ~mul_done & ecl_div_mul_wen;
|
assign stay_mul_done = mul_done & (~wb_divcntl_ack_g | ecl_div_sel_div);
|
assign stay_mul_done = mul_done & (~wb_divcntl_ack_g | ecl_div_sel_div);
|
assign next_mul_done = ~reset & (go_mul_done | stay_mul_done);
|
assign next_mul_done = ~reset & (go_mul_done | stay_mul_done);
|
|
|
assign mdqctl_divcntl_muldone = mul_done;
|
assign mdqctl_divcntl_muldone = mul_done;
|
|
|
// mul state flop
|
// mul state flop
|
dff mulstate_dff(.din(next_mul_done), .clk(clk), .q(mul_done), .se(se), .si(),
|
dff_s mulstate_dff(.din(next_mul_done), .clk(clk), .q(mul_done), .se(se), `SIMPLY_RISC_SCANIN,
|
.so());
|
.so());
|
|
|
/////////////////////////////////////////
|
/////////////////////////////////////////
|
// Pipeline registers for control signals
|
// Pipeline registers for control signals
|
/////////////////////////////////////////
|
/////////////////////////////////////////
|