// SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or it's affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. module el2_exu import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Top level clock input logic rst_l, // Reset input logic scan_mode, // Scan control input logic [1:0] dec_data_en, // Clock enable {x,r}, one cycle pulse input logic [1:0] dec_ctl_en, // Clock enable {x,r}, two cycle pulse input logic [31:0] dbg_cmd_wrdata, // Debug data to primary I0 RS1 input el2_alu_pkt_t i0_ap, // DEC alu {valid,predecodes} input logic dec_debug_wdata_rs1_d, // Debug select to primary I0 RS1 input el2_predict_pkt_t dec_i0_predict_p_d, // DEC branch predict packet input logic [pt.BHT_GHR_SIZE-1:0] i0_predict_fghr_d, // DEC predict fghr input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] i0_predict_index_d, // DEC predict index input logic [pt.BTB_BTAG_SIZE-1:0] i0_predict_btag_d, // DEC predict branch tag input logic dec_i0_rs1_en_d, // Qualify GPR RS1 data input logic dec_i0_rs2_en_d, // Qualify GPR RS2 data input logic [31:0] gpr_i0_rs1_d, // DEC data gpr input logic [31:0] gpr_i0_rs2_d, // DEC data gpr input logic [31:0] dec_i0_immed_d, // DEC data immediate input logic [31:0] dec_i0_rs1_bypass_data_d, // DEC bypass data input logic [31:0] dec_i0_rs2_bypass_data_d, // DEC bypass data input logic [12:1] dec_i0_br_immed_d, // Branch immediate input logic dec_i0_alu_decode_d, // Valid to X-stage ALU input logic dec_i0_select_pc_d, // PC select to RS1 input logic [31:1] dec_i0_pc_d, // Instruction PC input logic [1:0] dec_i0_rs1_bypass_en_d, // DEC bypass select 1 - X-stage, 0 - dec bypass data input logic [1:0] dec_i0_rs2_bypass_en_d, // DEC bypass select 1 - X-stage, 0 - dec bypass data input logic dec_csr_ren_d, // Clear I0 RS1 primary input el2_mul_pkt_t mul_p, // DEC {valid, operand signs, low, operand bypass} input el2_div_pkt_t div_p, // DEC {valid, unsigned, rem} input logic dec_div_cancel, // Cancel the divide operation input logic [31:1] pred_correct_npc_x, // DEC NPC for correctly predicted branch input logic dec_tlu_flush_lower_r, // Flush divide and secondary ALUs input logic [31:1] dec_tlu_flush_path_r, // Redirect target input logic dec_extint_stall, // External stall mux select input logic [31:2] dec_tlu_meihap, // External stall mux data output logic [31:0] exu_lsu_rs1_d, // LSU operand output logic [31:0] exu_lsu_rs2_d, // LSU operand output logic exu_flush_final, // Pipe is being flushed this cycle output logic [31:1] exu_flush_path_final, // Target for the oldest flush source output logic [31:0] exu_i0_result_x, // Primary ALU result to DEC output logic [31:1] exu_i0_pc_x, // Primary PC result to DEC output logic [31:0] exu_csr_rs1_x, // RS1 source for a CSR instruction output logic [31:1] exu_npc_r, // Divide NPC output logic [1:0] exu_i0_br_hist_r, // to DEC I0 branch history output logic exu_i0_br_error_r, // to DEC I0 branch error output logic exu_i0_br_start_error_r, // to DEC I0 branch start error output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_i0_br_index_r, // to DEC I0 branch index output logic exu_i0_br_valid_r, // to DEC I0 branch valid output logic exu_i0_br_mp_r, // to DEC I0 branch mispredict output logic exu_i0_br_middle_r, // to DEC I0 branch middle output logic [pt.BHT_GHR_SIZE-1:0] exu_i0_br_fghr_r, // to DEC I0 branch fghr output logic exu_i0_br_way_r, // to DEC I0 branch way output el2_predict_pkt_t exu_mp_pkt, // Mispredict branch packet output logic [pt.BHT_GHR_SIZE-1:0] exu_mp_eghr, // Mispredict global history output logic [pt.BHT_GHR_SIZE-1:0] exu_mp_fghr, // Mispredict fghr output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_mp_index, // Mispredict index output logic [pt.BTB_BTAG_SIZE-1:0] exu_mp_btag, // Mispredict btag output logic exu_pmu_i0_br_misp, // to PMU - I0 E4 branch mispredict output logic exu_pmu_i0_br_ataken, // to PMU - I0 E4 taken output logic exu_pmu_i0_pc4, // to PMU - I0 E4 PC output logic [31:0] exu_div_result, // Divide result output logic exu_div_wren // Divide write enable to GPR ); logic data_gate_en; logic [31:0] i0_rs1_bypass_data_d; logic [31:0] i0_rs2_bypass_data_d; logic i0_rs1_bypass_en_d; logic i0_rs2_bypass_en_d; logic [31:0] i0_rs1_d, i0_rs2_d; logic [31:0] muldiv_rs1_d, muldiv_rs2_d; logic [31:1] pred_correct_npc_r; logic i0_pred_correct_upper_r; logic [31:0] csr_rs1_in_d; logic [31:1] i0_flush_path_upper_r; logic x_data_en, r_data_en; logic x_ctl_en, r_ctl_en; logic [pt.BHT_GHR_SIZE-1:0] ghr_d_ns, ghr_d; logic [pt.BHT_GHR_SIZE-1:0] ghr_x_ns, ghr_x; logic i0_taken_d; logic i0_taken_x; logic i0_valid_d; logic i0_valid_x; logic [pt.BHT_GHR_SIZE-1:0] after_flush_eghr; el2_predict_pkt_t final_predict_mp; el2_predict_pkt_t i0_predict_newp_d; logic flush_lower_ff; logic flush_in_d; logic [31:0] alu_result_x; logic mul_valid_x; logic [31:0] mul_result_x; el2_predict_pkt_t i0_pp_r; logic i0_flush_upper_d; logic [31:1] i0_flush_path_d; el2_predict_pkt_t i0_predict_p_d; logic i0_pred_correct_upper_d; logic i0_flush_upper_x; logic [31:1] i0_flush_path_x; el2_predict_pkt_t i0_predict_p_x; logic i0_pred_correct_upper_x; localparam PREDPIPESIZE = pt.BTB_ADDR_HI-pt.BTB_ADDR_LO+1+pt.BHT_GHR_SIZE+pt.BTB_BTAG_SIZE; logic [PREDPIPESIZE-1:0] predpipe_d, predpipe_x, predpipe_r, final_predpipe_mp; rvdffe #(31) i_flush_path_x_ff (.*, .en ( x_data_en ), .din( i0_flush_path_d[31:1] ), .dout( i0_flush_path_x[31:1] ) ); rvdffe #(32) i_csr_rs1_x_ff (.*, .en ( x_data_en ), .din( csr_rs1_in_d[31:0] ), .dout( exu_csr_rs1_x[31:0] ) ); rvdffe #($bits(el2_predict_pkt_t)) i_predictpacket_x_ff (.*, .en ( x_data_en ), .din( i0_predict_p_d ), .dout( i0_predict_p_x ) ); rvdffe #(PREDPIPESIZE) i_predpipe_x_ff (.*, .en ( x_data_en ), .din( predpipe_d ), .dout( predpipe_x ) ); rvdffe #(PREDPIPESIZE) i_predpipe_r_ff (.*, .en ( r_data_en ), .din( predpipe_x ), .dout( predpipe_r ) ); rvdffe #(4+pt.BHT_GHR_SIZE) i_x_ff (.*, .en ( x_ctl_en ), .din ({i0_valid_d,i0_taken_d,i0_flush_upper_d,i0_pred_correct_upper_d,ghr_x_ns[pt.BHT_GHR_SIZE-1:0]} ), .dout({i0_valid_x,i0_taken_x,i0_flush_upper_x,i0_pred_correct_upper_x,ghr_x[pt.BHT_GHR_SIZE-1:0]} ) ); rvdffe #($bits(el2_predict_pkt_t)+7) i_r_ff0 (.*, .en ( r_ctl_en ), .din ({i0_predict_p_x ,pred_correct_npc_x[6:1],i0_pred_correct_upper_x}), .dout({i0_pp_r ,pred_correct_npc_r[6:1],i0_pred_correct_upper_r}) ); rvdffe #(56) i_r_ff1 (.*, .en ( r_data_en ), .din ({i0_flush_path_x[31:1] ,pred_correct_npc_x[31:7]}), .dout({i0_flush_path_upper_r[31:1],pred_correct_npc_r[31:7]}) ); if (pt.BHT_SIZE==32 || pt.BHT_SIZE==64) begin rvdffs #(pt.BHT_GHR_SIZE+2) i_data_gate_ff (.*, .en( data_gate_en ), .din ({ghr_d_ns[pt.BHT_GHR_SIZE-1:0],mul_p.valid,dec_tlu_flush_lower_r}), .dout({ghr_d[pt.BHT_GHR_SIZE-1:0] ,mul_valid_x,flush_lower_ff} ) ); end else begin rvdffe #(pt.BHT_GHR_SIZE+2) i_data_gate_ff (.*, .en( data_gate_en ), .din ({ghr_d_ns[pt.BHT_GHR_SIZE-1:0],mul_p.valid,dec_tlu_flush_lower_r}), .dout({ghr_d[pt.BHT_GHR_SIZE-1:0] ,mul_valid_x,flush_lower_ff} ) ); end assign data_gate_en = ( ghr_d_ns[pt.BHT_GHR_SIZE-1:0] != ghr_d[pt.BHT_GHR_SIZE-1:0]) | ( mul_p.valid != mul_valid_x ) | ( dec_tlu_flush_lower_r != flush_lower_ff ); assign predpipe_d[PREDPIPESIZE-1:0] = {i0_predict_fghr_d, i0_predict_index_d, i0_predict_btag_d}; assign i0_rs1_bypass_en_d = dec_i0_rs1_bypass_en_d[0] | dec_i0_rs1_bypass_en_d[1]; assign i0_rs2_bypass_en_d = dec_i0_rs2_bypass_en_d[0] | dec_i0_rs2_bypass_en_d[1]; assign i0_rs1_bypass_data_d[31:0]=({32{dec_i0_rs1_bypass_en_d[0]}} & dec_i0_rs1_bypass_data_d[31:0]) | ({32{dec_i0_rs1_bypass_en_d[1]}} & exu_i0_result_x[31:0] ); assign i0_rs2_bypass_data_d[31:0]=({32{dec_i0_rs2_bypass_en_d[0]}} & dec_i0_rs2_bypass_data_d[31:0]) | ({32{dec_i0_rs2_bypass_en_d[1]}} & exu_i0_result_x[31:0] ); assign i0_rs1_d[31:0] = ({32{ i0_rs1_bypass_en_d }} & i0_rs1_bypass_data_d[31:0]) | ({32{~i0_rs1_bypass_en_d & dec_i0_select_pc_d }} & {dec_i0_pc_d[31:1],1'b0} ) | // for jal's ({32{~i0_rs1_bypass_en_d & dec_debug_wdata_rs1_d }} & dbg_cmd_wrdata[31:0] ) | ({32{~i0_rs1_bypass_en_d & ~dec_debug_wdata_rs1_d & dec_i0_rs1_en_d}} & gpr_i0_rs1_d[31:0] ); assign i0_rs2_d[31:0] = ({32{~i0_rs2_bypass_en_d & dec_i0_rs2_en_d}} & gpr_i0_rs2_d[31:0] ) | ({32{~i0_rs2_bypass_en_d }} & dec_i0_immed_d[31:0] ) | ({32{ i0_rs2_bypass_en_d }} & i0_rs2_bypass_data_d[31:0]); assign exu_lsu_rs1_d[31:0] = ({32{~i0_rs1_bypass_en_d & ~dec_extint_stall & dec_i0_rs1_en_d}} & gpr_i0_rs1_d[31:0] ) | ({32{ i0_rs1_bypass_en_d & ~dec_extint_stall }} & i0_rs1_bypass_data_d[31:0]) | ({32{ dec_extint_stall }} & {dec_tlu_meihap[31:2],2'b0}); assign exu_lsu_rs2_d[31:0] = ({32{~i0_rs2_bypass_en_d & ~dec_extint_stall & dec_i0_rs2_en_d}} & gpr_i0_rs2_d[31:0] ) | ({32{ i0_rs2_bypass_en_d & ~dec_extint_stall }} & i0_rs2_bypass_data_d[31:0]); assign muldiv_rs1_d[31:0] = ({32{~i0_rs1_bypass_en_d & dec_i0_rs1_en_d}} & gpr_i0_rs1_d[31:0] ) | ({32{ i0_rs1_bypass_en_d }} & i0_rs1_bypass_data_d[31:0]); assign muldiv_rs2_d[31:0] = ({32{~i0_rs2_bypass_en_d & dec_i0_rs2_en_d}} & gpr_i0_rs2_d[31:0] ) | ({32{~i0_rs2_bypass_en_d }} & dec_i0_immed_d[31:0] ) | ({32{ i0_rs2_bypass_en_d }} & i0_rs2_bypass_data_d[31:0]); assign csr_rs1_in_d[31:0] = ( dec_csr_ren_d ) ? i0_rs1_d[31:0] : exu_csr_rs1_x[31:0]; assign x_data_en = dec_data_en[1]; assign r_data_en = dec_data_en[0]; assign x_ctl_en = dec_ctl_en[1]; assign r_ctl_en = dec_ctl_en[0]; el2_exu_alu_ctl #(.pt(pt)) i_alu (.*, .enable ( x_ctl_en ), // I .pp_in ( i0_predict_newp_d ), // I .valid_in ( dec_i0_alu_decode_d ), // I .flush_upper_x ( i0_flush_upper_x ), // I .flush_lower_r ( dec_tlu_flush_lower_r ), // I .a_in ( i0_rs1_d[31:0] ), // I .b_in ( i0_rs2_d[31:0] ), // I .pc_in ( dec_i0_pc_d[31:1] ), // I .brimm_in ( dec_i0_br_immed_d[12:1] ), // I .ap ( i0_ap ), // I .csr_ren_in ( dec_csr_ren_d ), // I .result_ff ( alu_result_x[31:0] ), // O .flush_upper_out ( i0_flush_upper_d ), // O .flush_final_out ( exu_flush_final ), // O .flush_path_out ( i0_flush_path_d[31:1] ), // O .predict_p_out ( i0_predict_p_d ), // O .pred_correct_out ( i0_pred_correct_upper_d ), // O .pc_ff ( exu_i0_pc_x[31:1] )); // O el2_exu_mul_ctl #(.pt(pt)) i_mul (.*, .mul_p ( mul_p ), // I .rs1_in ( muldiv_rs1_d[31:0] ), // I .rs2_in ( muldiv_rs2_d[31:0] ), // I .result_x ( mul_result_x[31:0] )); // O el2_exu_div_ctl #(.pt(pt)) i_div (.*, .cancel ( dec_div_cancel ), // I .dp ( div_p ), // I .dividend ( muldiv_rs1_d[31:0] ), // I .divisor ( muldiv_rs2_d[31:0] ), // I .finish_dly ( exu_div_wren ), // O .out ( exu_div_result[31:0] )); // O assign exu_i0_result_x[31:0] = (mul_valid_x) ? mul_result_x[31:0] : alu_result_x[31:0]; always_comb begin i0_predict_newp_d = dec_i0_predict_p_d; i0_predict_newp_d.boffset = dec_i0_pc_d[1]; // from the start of inst end assign exu_pmu_i0_br_misp = i0_pp_r.misp; assign exu_pmu_i0_br_ataken = i0_pp_r.ataken; assign exu_pmu_i0_pc4 = i0_pp_r.pc4; assign i0_valid_d = i0_predict_p_d.valid & dec_i0_alu_decode_d & ~dec_tlu_flush_lower_r; assign i0_taken_d = (i0_predict_p_d.ataken & dec_i0_alu_decode_d); // maintain GHR at D assign ghr_d_ns[pt.BHT_GHR_SIZE-1:0] = ({pt.BHT_GHR_SIZE{~dec_tlu_flush_lower_r & i0_valid_d}} & {ghr_d[pt.BHT_GHR_SIZE-2:0], i0_taken_d}) | ({pt.BHT_GHR_SIZE{~dec_tlu_flush_lower_r & ~i0_valid_d}} & ghr_d[pt.BHT_GHR_SIZE-1:0] ) | ({pt.BHT_GHR_SIZE{ dec_tlu_flush_lower_r }} & ghr_x[pt.BHT_GHR_SIZE-1:0] ); // maintain GHR at X assign ghr_x_ns[pt.BHT_GHR_SIZE-1:0] = ({pt.BHT_GHR_SIZE{ i0_valid_x}} & {ghr_x[pt.BHT_GHR_SIZE-2:0], i0_taken_x}) | ({pt.BHT_GHR_SIZE{~i0_valid_x}} & ghr_x[pt.BHT_GHR_SIZE-1:0] ) ; assign exu_i0_br_valid_r = i0_pp_r.valid; assign exu_i0_br_mp_r = i0_pp_r.misp; assign exu_i0_br_way_r = i0_pp_r.way; assign exu_i0_br_hist_r[1:0] = i0_pp_r.hist[1:0]; assign exu_i0_br_error_r = i0_pp_r.br_error; assign exu_i0_br_middle_r = i0_pp_r.pc4 ^ i0_pp_r.boffset; assign exu_i0_br_start_error_r = i0_pp_r.br_start_error; assign {exu_i0_br_fghr_r[pt.BHT_GHR_SIZE-1:0], exu_i0_br_index_r[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]}= predpipe_r[PREDPIPESIZE-1:pt.BTB_BTAG_SIZE]; assign final_predict_mp = (i0_flush_upper_x) ? i0_predict_p_x : '0; assign final_predpipe_mp[PREDPIPESIZE-1:0] = (i0_flush_upper_x) ? predpipe_x : '0; assign after_flush_eghr[pt.BHT_GHR_SIZE-1:0] = (i0_flush_upper_x & ~dec_tlu_flush_lower_r) ? ghr_d[pt.BHT_GHR_SIZE-1:0] : ghr_x[pt.BHT_GHR_SIZE-1:0]; assign exu_mp_pkt.way = final_predict_mp.way; assign exu_mp_pkt.misp = final_predict_mp.misp; assign exu_mp_pkt.pcall = final_predict_mp.pcall; assign exu_mp_pkt.pja = final_predict_mp.pja; assign exu_mp_pkt.pret = final_predict_mp.pret; assign exu_mp_pkt.ataken = final_predict_mp.ataken; assign exu_mp_pkt.boffset = final_predict_mp.boffset; assign exu_mp_pkt.pc4 = final_predict_mp.pc4; assign exu_mp_pkt.hist[1:0] = final_predict_mp.hist[1:0]; assign exu_mp_pkt.toffset[11:0] = final_predict_mp.toffset[11:0]; assign exu_mp_fghr[pt.BHT_GHR_SIZE-1:0] = after_flush_eghr[pt.BHT_GHR_SIZE-1:0]; assign {exu_mp_index[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO], exu_mp_btag[pt.BTB_BTAG_SIZE-1:0]} = final_predpipe_mp[PREDPIPESIZE-pt.BHT_GHR_SIZE-1:0]; assign exu_mp_eghr[pt.BHT_GHR_SIZE-1:0] = final_predpipe_mp[PREDPIPESIZE-1:pt.BTB_ADDR_HI-pt.BTB_ADDR_LO+pt.BTB_BTAG_SIZE+1]; // mp ghr for bht write assign exu_flush_path_final[31:1] = (dec_tlu_flush_lower_r) ? dec_tlu_flush_path_r[31:1] : i0_flush_path_d[31:1]; assign exu_npc_r[31:1] = (i0_pred_correct_upper_r) ? pred_correct_npc_r[31:1] : i0_flush_path_upper_r[31:1]; endmodule // el2_exu