From 1c9d4d899a99a9533bdb292aee66e68687ec822b Mon Sep 17 00:00:00 2001 From: socet137 Date: Sat, 20 Jan 2024 21:19:45 -0500 Subject: [PATCH] create new folder for uop arch --- .../stage4/include/stage3_fetch_execute_if.vh | 60 ++++ .../include/stage3_forwarding_unit_if.vh | 32 ++ .../stage4/include/stage3_hazard_unit_if.vh | 126 +++++++ .../stage4/include/stage3_mem_pipe_if.vh | 34 ++ .../pipelines/stage4/include/uop_if.vh | 38 ++ .../pipelines/stage4/source/decode_queue.sv | 141 ++++++++ .../stage4/source/decode_resolution.sv | 65 ++++ .../pipelines/stage4/source/scalar_decode.sv | 132 +++++++ .../stage4/source/stage3_execute_stage.sv | 329 ++++++++++++++++++ .../stage4/source/stage3_fetch_stage.sv | 159 +++++++++ .../stage4/source/stage3_forwarding_unit.sv | 14 + .../stage4/source/stage3_hazard_unit.sv | 218 ++++++++++++ .../stage4/source/stage3_mem_stage.sv | 273 +++++++++++++++ .../stage4/source/stage3_types_pkg.sv | 130 +++++++ source_code/pipelines/stage4/source/stage4.sv | 76 ++++ .../pipelines/stage4/source/uop_queue.sv | 80 +++++ source_code/pipelines/stage4/stage4.core | 40 +++ 17 files changed, 1947 insertions(+) create mode 100644 source_code/pipelines/stage4/include/stage3_fetch_execute_if.vh create mode 100644 source_code/pipelines/stage4/include/stage3_forwarding_unit_if.vh create mode 100644 source_code/pipelines/stage4/include/stage3_hazard_unit_if.vh create mode 100644 source_code/pipelines/stage4/include/stage3_mem_pipe_if.vh create mode 100644 source_code/pipelines/stage4/include/uop_if.vh create mode 100644 source_code/pipelines/stage4/source/decode_queue.sv create mode 100644 source_code/pipelines/stage4/source/decode_resolution.sv create mode 100644 source_code/pipelines/stage4/source/scalar_decode.sv create mode 100644 source_code/pipelines/stage4/source/stage3_execute_stage.sv create mode 100644 source_code/pipelines/stage4/source/stage3_fetch_stage.sv create mode 100644 source_code/pipelines/stage4/source/stage3_forwarding_unit.sv create mode 100644 source_code/pipelines/stage4/source/stage3_hazard_unit.sv create mode 100644 source_code/pipelines/stage4/source/stage3_mem_stage.sv create mode 100644 source_code/pipelines/stage4/source/stage3_types_pkg.sv create mode 100644 source_code/pipelines/stage4/source/stage4.sv create mode 100644 source_code/pipelines/stage4/source/uop_queue.sv create mode 100644 source_code/pipelines/stage4/stage4.core diff --git a/source_code/pipelines/stage4/include/stage3_fetch_execute_if.vh b/source_code/pipelines/stage4/include/stage3_fetch_execute_if.vh new file mode 100644 index 000000000..3c2b013d8 --- /dev/null +++ b/source_code/pipelines/stage4/include/stage3_fetch_execute_if.vh @@ -0,0 +1,60 @@ +/* +* Copyright 2016 Purdue University +* +* 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. +* +* +* Filename: stage3_fetch_execute_if.vh +* +* Created by: Jacob R. Stevens +* Email: steven69@purdue.edu +* Date Created: 06/01/2016 +* Description: Interface between the fetch and execute pipeline stages +*/ + +`ifndef STAGE3_FETCH_EXECUTE_IF_VH +`define STAGE3_FETCH_EXECUTE_IF_VH + +interface stage3_fetch_execute_if; + import rv32i_types_pkg::*; + import stage3_types_pkg::*; + + fetch_ex_t fetch_ex_reg; + word_t brj_addr; + + uop_t[0:0] s_ctrls; + logic[3:0] s_num_uops; + + uop_t uop; + + modport fetch( + output fetch_ex_reg + ); + + modport execute( + input uop + //input fetch_ex_reg + ); + + modport s_decode( + input fetch_ex_reg, + output s_ctrls, s_num_uops + ); + + modport queue( + input s_ctrls, s_num_uops, + output uop + ); + +endinterface +`endif diff --git a/source_code/pipelines/stage4/include/stage3_forwarding_unit_if.vh b/source_code/pipelines/stage4/include/stage3_forwarding_unit_if.vh new file mode 100644 index 000000000..6dbc7085a --- /dev/null +++ b/source_code/pipelines/stage4/include/stage3_forwarding_unit_if.vh @@ -0,0 +1,32 @@ +`ifndef __STAGE3_FORWARD_UNIT_VH__ +`define __STAGE3_FORWARD_UNIT_VH__ + +interface stage3_forwarding_unit_if(); + + rv32i_types_pkg::regsel_t rd_m; + rv32i_types_pkg::regsel_t rs1_e; + rv32i_types_pkg::regsel_t rs2_e; + logic reg_write; + logic load; + logic fwd_rs1; + logic fwd_rs2; + rv32i_types_pkg::word_t rd_mem_data; + + modport execute( + input fwd_rs1, fwd_rs2, rd_mem_data, + output rs1_e, rs2_e + ); + + modport mem( + output rd_m, rd_mem_data, reg_write, load + ); + + modport fw_unit( + input rs1_e, rs2_e, rd_m, reg_write, load, + output fwd_rs1, fwd_rs2 + ); + +endinterface + + +`endif \ No newline at end of file diff --git a/source_code/pipelines/stage4/include/stage3_hazard_unit_if.vh b/source_code/pipelines/stage4/include/stage3_hazard_unit_if.vh new file mode 100644 index 000000000..6ee76d766 --- /dev/null +++ b/source_code/pipelines/stage4/include/stage3_hazard_unit_if.vh @@ -0,0 +1,126 @@ +/* +* Copyright 2016 Purdue University +* +* 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. +* +* +* Filename: stage3_hazard_unit_if.vh +* +* Created by: Jacob R. Stevens +* Email: steven69@purdue.edu +* Date Created: 06/15/2016 +* Description: Interface for the hazard unit of the two stage pipeline +*/ + +`ifndef STAGE3_HAZARD_UNIT_IF_VH +`define STAGE3_HAZARD_UNIT_IF_VH + +interface stage3_hazard_unit_if(); + + import rv32i_types_pkg::word_t; + import rv32i_types_pkg::regsel_t; + + // Pipeline status signals (inputs) + regsel_t rs1_e, rs2_e; + regsel_t rd_m; + logic reg_write, csr_read; + logic i_mem_busy, d_mem_busy, dren, dwen, ret, suppress_data; + logic jump, branch, fence_stall; + logic mispredict, halt; + word_t pc_f, pc_e, pc_m; + logic valid_e, valid_m; // f always valid since it's the PC + logic ifence; + logic ex_busy; + logic lsc_queue_full; + + // Control (outputs) + logic pc_en, npc_sel; + logic if_ex_flush, ex_mem_flush; + logic if_ex_stall, ex_mem_stall; + logic iren, suppress_iren; + logic rollback; // signal for rolling back fetched instructions after instruction in mem stage, for certain CSR and ifence instructions + + // xTVEC Insertion + word_t priv_pc; + logic insert_priv_pc; + + //Pipeline Exceptions (inputs) + logic fault_insn, mal_insn, illegal_insn, fault_l, mal_l, fault_s, mal_s, + breakpoint, env, wfi; + word_t badaddr; + + // Pipeline Tokens + logic token_ex; + logic token_mem; + + // RV32C + logic rv32c_ready; + + + // uop stage + logic stall_queue, flush_queue, is_queue_full; + logic valid_decode; + word_t + pc_decode; + + + modport hazard_unit ( + input rs1_e, rs2_e, rd_m, + reg_write, csr_read, + i_mem_busy, d_mem_busy, dren, dwen, ret, + jump, branch, fence_stall, mispredict, halt, pc_f, pc_e, pc_m, + fault_insn, mal_insn, illegal_insn, fault_l, mal_l, fault_s, mal_s, breakpoint, env, wfi, + badaddr, ifence, + token_ex, token_mem, rv32c_ready, + valid_e, valid_m, ex_busy, + + is_queue_full, pc_decode, valid_decode, + + + output pc_en, npc_sel, + if_ex_flush, ex_mem_flush, + if_ex_stall, ex_mem_stall, + priv_pc, insert_priv_pc, iren, suppress_iren, suppress_data, rollback, + + stall_queue, flush_queue + + ); + + modport fetch ( + input pc_en, npc_sel, if_ex_stall, if_ex_flush, priv_pc, insert_priv_pc, iren, suppress_iren, rollback, + output i_mem_busy, rv32c_ready, pc_f + ); + + modport queue ( + input stall_queue, flush_queue, + output is_queue_full, pc_decode, valid_decode + ); + + modport execute ( + input ex_mem_stall, ex_mem_flush, npc_sel, + output rs1_e, rs2_e, token_ex, pc_e, valid_e, ex_busy + ); + + modport mem ( + input ex_mem_stall, ex_mem_flush, suppress_data, + output rd_m, reg_write, csr_read, + d_mem_busy, dren, dwen, ret, + jump, branch, fence_stall, mispredict, halt, pc_m, valid_m, + fault_insn, mal_insn, illegal_insn, fault_l, mal_l, fault_s, mal_s, breakpoint, env, + badaddr, ifence, wfi, + token_mem + ); + + endinterface + +`endif \ No newline at end of file diff --git a/source_code/pipelines/stage4/include/stage3_mem_pipe_if.vh b/source_code/pipelines/stage4/include/stage3_mem_pipe_if.vh new file mode 100644 index 000000000..cb4916950 --- /dev/null +++ b/source_code/pipelines/stage4/include/stage3_mem_pipe_if.vh @@ -0,0 +1,34 @@ +`ifndef __STAGE3_MEM_PIPE_IF__ +`define __STAGE3_MEM_PIPE_IF__ + +interface stage3_mem_pipe_if(); + + import rv32i_types_pkg::*; + import stage3_types_pkg::*; + + logic reg_write; + regsel_t rd_m; + ex_mem_t ex_mem_reg; + word_t brj_addr; + word_t reg_wdata; + word_t pc4; // For flush in case of fence_i, CSR, etc. + + modport fetch( + input brj_addr, pc4 + ); + + + modport execute( + input reg_wdata, reg_write, rd_m, + output ex_mem_reg + ); + + modport mem( + input ex_mem_reg, + output brj_addr, reg_wdata, reg_write, rd_m, pc4 + ); + +endinterface + + +`endif \ No newline at end of file diff --git a/source_code/pipelines/stage4/include/uop_if.vh b/source_code/pipelines/stage4/include/uop_if.vh new file mode 100644 index 000000000..f7ac9225d --- /dev/null +++ b/source_code/pipelines/stage4/include/uop_if.vh @@ -0,0 +1,38 @@ +`ifndef STAGE3_UOP_IF_VH +`define STAGE3_UOP_IF_VH + +interface uop_if; + import rv32i_types_pkg::*; + import stage3_types_pkg::*; + + fetch_ex_t fetch_ex_reg; + word_t brj_addr; + + modport ctrls_in( + output fetch_ex_reg + ); + + modport ctrls_out( + output fetch_ex_reg + ); + + modport rf_out( + output fetch_ex_reg + ); + + modport fetch_in( + + ); + + modport fetch_out( + + ); + + + modport execute( + input fetch_ex_reg + ); + +endinterface + +`endif \ No newline at end of file diff --git a/source_code/pipelines/stage4/source/decode_queue.sv b/source_code/pipelines/stage4/source/decode_queue.sv new file mode 100644 index 000000000..1eaf7f886 --- /dev/null +++ b/source_code/pipelines/stage4/source/decode_queue.sv @@ -0,0 +1,141 @@ +/* +* Copyright 2023 Purdue University +* +* 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. +* +* +* Filename: decode_queue.sv +* +* Created by: Fahad Aloufi +* Email: faloufi@purdue.edu +* Date Created: 11/19/2023 +* Description: Decode queue for uops +*/ + +//`include "stage3_types_pkg.sv" + +import stage3_types_pkg::*; +// import alu_types_pkg::*; +// import rv32i_types_pkg::*; +// import machine_mode_types_1_12_pkg::*; +// import rv32m_pkg::*; + +module decode_queue +#( + parameter type D_TYPE = uop_t, + parameter QUEUE_LEN = 8, + parameter DISPATCH_SIZE = 1 +) +( + input logic CLK, nRST, + input D_TYPE [DISPATCH_SIZE-1:0] ctrls, + input logic stall_queue, flush_queue, store, + input logic[$clog2(DISPATCH_SIZE):0] num_uops, + + output logic[$clog2(QUEUE_LEN)+1:0] num_free_slots, + output D_TYPE uop0 +); + +logic[$clog2(QUEUE_LEN)+1:0] tail_idx, nxt_tail_idx; + +D_TYPE[QUEUE_LEN:1] queue_data, nxt_queue_data; // start counting from 1 instead of 0 so I don't have to deal with negative numbers (if tail_idx == 0, then tail_idx - 1= -1) + + +assign uop0 = queue_data[1]; // assign up0 to the head to of the queue + +always_ff @(posedge CLK, negedge nRST) begin:TAIL_IDX_REG + if(~nRST) + tail_idx = 0; + else + tail_idx = nxt_tail_idx; +end + +always_ff @(posedge CLK, negedge nRST) begin:QUEUE_DATA_REG + if(~nRST) begin + for(int i = 1; i <= QUEUE_LEN; i+=1) + queue_data[i] <= '0; + end + else begin + for(int i = 1; i <= QUEUE_LEN; i+=1) + queue_data[i] <= nxt_queue_data[i]; + end +end + +always_comb begin: NXT_QUEUE_DATA_LOGIC + for(int i = 1; i <= QUEUE_LEN; i+=1) // default case, elements retain their values + nxt_queue_data[i] = queue_data[i]; + + if(flush_queue) begin + for(int i = 1; i <= QUEUE_LEN; i+=1) + nxt_queue_data[i] = '0; + end + else if(~store && ~stall_queue) begin // behaves like a shift register + for(int i = 1; i <= QUEUE_LEN-1; i+=1 ) begin + nxt_queue_data[i] = queue_data[i+1]; + end + nxt_queue_data[QUEUE_LEN] = '0; // shift in a NOP + end + else if(store) begin + if(stall_queue) begin + for(int i = 1; i <= tail_idx; i+=1) + nxt_queue_data[i] = queue_data[i]; // retain elements already in the queue + + for(int i = tail_idx + 1; i <= tail_idx + num_uops; i+=1) + nxt_queue_data[i] = ctrls[i - 1 - tail_idx]; // add the uops to the queue + + end + else begin + if(tail_idx == 0) begin + for(int i = 1; i <= num_uops; i+=1) begin + nxt_queue_data[i] = ctrls[i-1]; // add all uops + end + end + else begin + for(int i = 1; i <= tail_idx - 1; i+=1) // shift in uops already inside queue + nxt_queue_data[i] = queue_data[i+1]; + + for(int i = tail_idx; i <= tail_idx + num_uops - 1 ; i+=1) // store additional uops + nxt_queue_data[i] = ctrls[i - tail_idx]; + end + end + + end + + +end +always_comb begin:NXT_TAIL_IDX_LOGIC + if(flush_queue) + nxt_tail_idx = 0; + else if(~store) begin + if(stall_queue) + nxt_tail_idx = tail_idx; + else + nxt_tail_idx = tail_idx == 0 ? 0 : tail_idx - 1; + end + else begin + if(stall_queue) + nxt_tail_idx = tail_idx + num_uops; + else + nxt_tail_idx = tail_idx == 0 ? num_uops : tail_idx + num_uops - 1; + end +end + +always_comb begin:NUM_FREE_SLOTS + if(stall_queue) + num_free_slots = QUEUE_LEN - tail_idx; + else + num_free_slots = tail_idx == 0 ? QUEUE_LEN : ((QUEUE_LEN + 1) - tail_idx); +end + + +endmodule \ No newline at end of file diff --git a/source_code/pipelines/stage4/source/decode_resolution.sv b/source_code/pipelines/stage4/source/decode_resolution.sv new file mode 100644 index 000000000..f27324695 --- /dev/null +++ b/source_code/pipelines/stage4/source/decode_resolution.sv @@ -0,0 +1,65 @@ +/* +* Copyright 2023 Purdue University +* +* 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. +* +* +* Filename: decode_resolution.sv +* +* Created by: Fahad Aloufi +* Email: faloufi@purdue.edu +* Date Created: 11/19/2023 +* Description: Arbitrate between scalar and vector decode and feed uops into the queue +*/ + +//`include "stage3_types_pkg.sv" +import stage3_types_pkg::*; +import rv32i_types_pkg::*; + + +module decode_resolution +#( + parameter type D_TYPE = uop_t, + parameter QUEUE_LEN = 8, + parameter DISPATCH_SIZE = 1 +) +( + input D_TYPE[DISPATCH_SIZE-1:0] s_ctrls, + input logic[$clog2(QUEUE_LEN)+1:0] num_free_slots, + input logic[$clog2(DISPATCH_SIZE):0] s_num_uops, + + + output D_TYPE[DISPATCH_SIZE-1:0] ctrls, + output logic[$clog2(DISPATCH_SIZE):0] num_uops, + output logic store, + output word_t pc_decode, + output logic valid_decode +); + +assign ctrls = s_ctrls; + +assign num_uops = s_ctrls[0].if_out.valid ? DISPATCH_SIZE : 0; + + +// EPC signals for interrupts +assign valid_decode = s_ctrls[0].if_out.valid; +assign pc_decode = s_ctrls[0].if_out.pc; + +always_comb begin + if((num_uops > 0) && (num_free_slots >= num_uops)) + store = 1; + else + store = 0; +end + +endmodule diff --git a/source_code/pipelines/stage4/source/scalar_decode.sv b/source_code/pipelines/stage4/source/scalar_decode.sv new file mode 100644 index 000000000..799a228e2 --- /dev/null +++ b/source_code/pipelines/stage4/source/scalar_decode.sv @@ -0,0 +1,132 @@ +/* +* Copyright 2023 Purdue University +* +* 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. +* +* +* Filename: scalar_decode.sv +* +* Created by: Fahad Aloufi +* Email: faloufi@purdue.edu +* Date Created: 11/19/2023 +* Description: scalar decode block for non-vector instructions +*/ +//'include "stage3_types_pkg.sv" + +`include "stage3_fetch_execute_if.vh" +`include "stage3_hazard_unit_if.vh" +`include "stage3_forwarding_unit_if.vh" +`include "control_unit_if.vh" +`include "component_selection_defines.vh" +`include "rv32i_reg_file_if.vh" +`include "alu_if.vh" +//`include "prv_pipeline_if.vh" +//`include "risc_mgmt_if.vh" +`include "rv32c_if.vh" + +import stage3_types_pkg::*; +import rv32i_types_pkg::*; + +module scalar_decode +( + stage3_fetch_execute_if.s_decode fetch_ex_if, + input stall_queue, + rv32c_if.execute rv32cif +); + +assign fetch_ex_if.s_ctrls[0].if_out = fetch_ex_if.fetch_ex_reg; +assign fetch_ex_if.s_num_uops = fetch_ex_if.s_ctrls[0].if_out.valid ? 1 : 0; + + + +control_unit_if cu_if (); +rv32i_reg_file_if rf_if (); + + +// RV32C inputs +assign rv32cif.inst16 = fetch_ex_if.fetch_ex_reg.instr[15:0]; +assign rv32cif.halt = 1'b0; // TODO: Is this signal necessary? Can't get it right on decode of a halt instruction +assign rv32cif.ex_busy = stall_queue; //cu_if.dren | cu_if.dwen | rm_if.risc_mgmt_start; +assign cu_if.instr = rv32cif.c_ena ? rv32cif.inst32 : fetch_ex_if.fetch_ex_reg.instr; //if_stage_in.instr; +//assign rm_if.insn = rv32cif.c_ena ? rv32cif.inst32 : fetch_ex_if.fetch_ex_reg.instr; + +// Control unit, inputs are post-decompression +control_unit cu ( + .cu_if(cu_if), + .rf_if(rf_if), + .rmgmt_rsel_s_0('0), + .rmgmt_rsel_s_1('0), + .rmgmt_rsel_d('0), + .rmgmt_req_reg_r('0), + .rmgmt_req_reg_w('0) + //.rmgmt_rsel_s_0(rm_if.rsel_s_0), + //.rmgmt_rsel_s_1(rm_if.rsel_s_1), + //.rmgmt_rsel_d(rm_if.rsel_d), + //.rmgmt_req_reg_r(rm_if.req_reg_r), + //.rmgmt_req_reg_w(rm_if.req_reg_w) +); + +// connect the ports between the interfaces and the struct type +assign fetch_ex_if.s_ctrls[0].ctrl_out.dwen = cu_if.dwen; +assign fetch_ex_if.s_ctrls[0].ctrl_out.dren = cu_if.dren; +assign fetch_ex_if.s_ctrls[0].ctrl_out.j_sel = cu_if.j_sel; +assign fetch_ex_if.s_ctrls[0].ctrl_out.branch = cu_if.branch; +assign fetch_ex_if.s_ctrls[0].ctrl_out.jump = cu_if.jump; +assign fetch_ex_if.s_ctrls[0].ctrl_out.ex_pc_sel = cu_if.ex_pc_sel; +assign fetch_ex_if.s_ctrls[0].ctrl_out.imm_shamt_sel = cu_if.imm_shamt_sel; +assign fetch_ex_if.s_ctrls[0].ctrl_out.halt = cu_if.halt; +assign fetch_ex_if.s_ctrls[0].ctrl_out.wen = cu_if.wen; +assign fetch_ex_if.s_ctrls[0].ctrl_out.ifence = cu_if.ifence; +assign fetch_ex_if.s_ctrls[0].ctrl_out.wfi = cu_if.wfi; + +assign fetch_ex_if.s_ctrls[0].ctrl_out.alu_op = cu_if.alu_op; +assign fetch_ex_if.s_ctrls[0].ctrl_out.alu_a_sel = cu_if.alu_a_sel; +assign fetch_ex_if.s_ctrls[0].ctrl_out.alu_b_sel = cu_if.alu_b_sel; +assign fetch_ex_if.s_ctrls[0].ctrl_out.w_sel = cu_if.w_sel; +assign fetch_ex_if.s_ctrls[0].ctrl_out.shamt = cu_if.shamt; +assign fetch_ex_if.s_ctrls[0].ctrl_out.rd = cu_if.rd; +assign fetch_ex_if.s_ctrls[0].ctrl_out.imm_I = cu_if.imm_I; +assign fetch_ex_if.s_ctrls[0].ctrl_out.imm_S = cu_if.imm_S; +assign fetch_ex_if.s_ctrls[0].ctrl_out.imm_UJ = cu_if.imm_UJ; +assign fetch_ex_if.s_ctrls[0].ctrl_out.imm_SB = cu_if.imm_SB; +// word_t instr; +assign fetch_ex_if.s_ctrls[0].ctrl_out.imm_U = cu_if.imm_U; +assign fetch_ex_if.s_ctrls[0].ctrl_out.load_type = cu_if.load_type; +assign fetch_ex_if.s_ctrls[0].ctrl_out.branch_type = cu_if.branch_type; +assign fetch_ex_if.s_ctrls[0].ctrl_out.opcode = cu_if.opcode; + +// Privilege ctrl signals +assign fetch_ex_if.s_ctrls[0].ctrl_out.fault_insn = cu_if.fault_insn; +assign fetch_ex_if.s_ctrls[0].ctrl_out.illegal_insn = cu_if.illegal_insn; +assign fetch_ex_if.s_ctrls[0].ctrl_out.ret_insn = cu_if.ret_insn; +assign fetch_ex_if.s_ctrls[0].ctrl_out.breakpoint = cu_if.breakpoint; +assign fetch_ex_if.s_ctrls[0].ctrl_out.ecall_insn = cu_if.ecall_insn; +assign fetch_ex_if.s_ctrls[0].ctrl_out.csr_swap = cu_if.csr_swap; +assign fetch_ex_if.s_ctrls[0].ctrl_out.csr_set = cu_if.csr_set; +assign fetch_ex_if.s_ctrls[0].ctrl_out.csr_clr = cu_if.csr_clr; +assign fetch_ex_if.s_ctrls[0].ctrl_out.csr_imm = cu_if.csr_imm; +assign fetch_ex_if.s_ctrls[0].ctrl_out.csr_rw_valid = cu_if.csr_rw_valid; +assign fetch_ex_if.s_ctrls[0].ctrl_out.csr_addr = cu_if.csr_addr; +assign fetch_ex_if.s_ctrls[0].ctrl_out.zimm = cu_if.zimm; + +// Extension ctrl signals +assign fetch_ex_if.s_ctrls[0].ctrl_out.rv32m_control = cu_if.rv32m_control; + + +// RF interface signasl +assign fetch_ex_if.s_ctrls[0].ctrl_out.rs1 = rf_if.rs1; +assign fetch_ex_if.s_ctrls[0].ctrl_out.rs2 = rf_if.rs2; + + + +endmodule diff --git a/source_code/pipelines/stage4/source/stage3_execute_stage.sv b/source_code/pipelines/stage4/source/stage3_execute_stage.sv new file mode 100644 index 000000000..e38b9a0d2 --- /dev/null +++ b/source_code/pipelines/stage4/source/stage3_execute_stage.sv @@ -0,0 +1,329 @@ +/* +* Copyright 2016 Purdue University +* +* 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. +* +* +* Filename: stage3_execute_stage.sv +* +* Created by: Jacob R. Stevens +* Email: steven69@purdue.edu +* Date Created: 06/16/2016 +* Description: Execute Stage for the Two Stage Pipeline +*/ + +`include "stage3_fetch_execute_if.vh" +`include "stage3_hazard_unit_if.vh" +`include "stage3_forwarding_unit_if.vh" +`include "control_unit_if.vh" +`include "component_selection_defines.vh" +`include "rv32i_reg_file_if.vh" +`include "alu_if.vh" +//`include "prv_pipeline_if.vh" +//`include "risc_mgmt_if.vh" +`include "rv32c_if.vh" +import stage3_types_pkg::*; +import rv32i_types_pkg::*; + +module stage3_execute_stage ( + input CLK, + input nRST, + + stage3_fetch_execute_if.execute fetch_ex_if, + //input uop_t uop_out, + stage3_mem_pipe_if.execute ex_mem_if, + stage3_hazard_unit_if.execute hazard_if, + stage3_forwarding_unit_if.execute fw_if, + //risc_mgmt_if.ts_execute rm_if, + sparce_pipeline_if.pipe_execute sparce_if, + rv32c_if.execute rv32cif +); + + import rv32i_types_pkg::*; + import pma_types_1_12_pkg::*; + import stage3_types_pkg::*; + + // Interface declarations + control_unit_if cu_if (); + rv32i_reg_file_if rf_if (); + alu_if alu_if (); + jump_calc_if jump_if (); + branch_res_if branch_if (); + + assign rf_if.rs1 = fetch_ex_if.uop.ctrl_out.rs1; + assign rf_if.rs2 = fetch_ex_if.uop.ctrl_out.rs2; + + + /********************** + * Decode/Register Read + ***********************/ + + // // RV32C inputs + // assign rv32cif.inst16 = fetch_ex_if.fetch_ex_reg.instr[15:0]; + // assign rv32cif.halt = 1'b0; // TODO: Is this signal necessary? Can't get it right on decode of a halt instruction + // assign rv32cif.ex_busy = hazard_if.ex_mem_stall; //cu_if.dren | cu_if.dwen | rm_if.risc_mgmt_start; + // assign cu_if.instr = rv32cif.c_ena ? rv32cif.inst32 : fetch_ex_if.fetch_ex_reg.instr; + // //assign rm_if.insn = rv32cif.c_ena ? rv32cif.inst32 : fetch_ex_if.fetch_ex_reg.instr; + + // // Control unit, inputs are post-decompression + // control_unit cu ( + // .cu_if(cu_if), + // .rf_if(rf_if), + // .rmgmt_rsel_s_0('0), + // .rmgmt_rsel_s_1('0), + // .rmgmt_rsel_d('0), + // .rmgmt_req_reg_r('0), + // .rmgmt_req_reg_w('0) + // //.rmgmt_rsel_s_0(rm_if.rsel_s_0), + // //.rmgmt_rsel_s_1(rm_if.rsel_s_1), + // //.rmgmt_rsel_d(rm_if.rsel_d), + // //.rmgmt_req_reg_r(rm_if.req_reg_r), + // //.rmgmt_req_reg_w(rm_if.req_reg_w) + // ); + + assign wfi = fetch_ex_if.uop.ctrl_out.wfi; //Added by rkannank + + generate + if (BASE_ISA == "RV32E") begin : g_rfile_select + rv32e_reg_file rf ( + .CLK, + .nRST, + .rf_if + ); + end else begin : g_rfile_select + rv32i_reg_file rf ( + .CLK, + .nRST, + .rf_if + ); + end + endgenerate + + + /****************** + * Functional Units + *******************/ + logic rv32m_busy; + word_t rv32m_out; + word_t ex_out; + word_t rs1_post_fwd, rs2_post_fwd; + + alu alu (.*); + jump_calc jump_calc (.*); + branch_res branch_res (.br_if(branch_if)); + + rv32m_wrapper RV32M_FU ( + .CLK, + .nRST, + .rv32m_start(fetch_ex_if.uop.ctrl_out.rv32m_control.select), + .operation(fetch_ex_if.uop.ctrl_out.rv32m_control.op), // TODO: Better way? + .rv32m_a(rs1_post_fwd), // All RV32M are reg-reg, so just feed post-fwd regs + .rv32m_b(rs2_post_fwd), + .rv32m_busy, + .rv32m_out + ); + + // Forwarding + // These rs*_post_fwd values should be used in place of rs1/rs2 anywhere they are used + assign rs1_post_fwd = fw_if.fwd_rs1 ? fw_if.rd_mem_data : rf_if.rs1_data; + assign rs2_post_fwd = fw_if.fwd_rs2 ? fw_if.rd_mem_data : rf_if.rs2_data; + + + /****************** + * Sign Extensions + ******************/ + word_t imm_I_ext, imm_S_ext, imm_UJ_ext; + assign imm_I_ext = {{20{fetch_ex_if.uop.ctrl_out.imm_I[11]}}, fetch_ex_if.uop.ctrl_out.imm_I}; + assign imm_UJ_ext = {{11{fetch_ex_if.uop.ctrl_out.imm_UJ[20]}}, fetch_ex_if.uop.ctrl_out.imm_UJ}; + assign imm_S_ext = {{20{fetch_ex_if.uop.ctrl_out.imm_S[11]}}, fetch_ex_if.uop.ctrl_out.imm_S}; + + /********************************************** + * Jump Target Calculator and Associated Logic + **********************************************/ + word_t jump_addr /* verilator isolate_assignments */; + always_comb begin + if (fetch_ex_if.uop.ctrl_out.j_sel) begin + jump_if.base = fetch_ex_if.uop.if_out.pc; + jump_if.offset = imm_UJ_ext; + jump_addr = jump_if.jal_addr; + end else begin + jump_if.base = rs1_post_fwd; + jump_if.offset = imm_I_ext; + jump_addr = jump_if.jalr_addr; + end + end + + /***** + * ALU + *****/ + word_t imm_or_shamt; + assign imm_or_shamt = (fetch_ex_if.uop.ctrl_out.imm_shamt_sel == 1'b1) ? fetch_ex_if.uop.ctrl_out.shamt : imm_I_ext; + assign alu_if.aluop = fetch_ex_if.uop.ctrl_out.alu_op; + logic mal_addr; + + always_comb begin + case (fetch_ex_if.uop.ctrl_out.alu_a_sel) + 2'd0: alu_if.port_a = rs1_post_fwd; + 2'd1: alu_if.port_a = imm_S_ext; + 2'd2: alu_if.port_a = fetch_ex_if.uop.if_out.pc; + 2'd3: alu_if.port_a = '0; //Not Used + endcase + end + + always_comb begin + case (fetch_ex_if.uop.ctrl_out.alu_b_sel) + 2'd0: alu_if.port_b = rs1_post_fwd; + 2'd1: alu_if.port_b = rs2_post_fwd; + 2'd2: alu_if.port_b = imm_or_shamt; + 2'd3: alu_if.port_b = fetch_ex_if.uop.ctrl_out.imm_U; + endcase + end + + + // FU output mux -- feeds into pipeline register + // Add to this when more FUs are added + // TODO: Make this nicer, with enum for FU selection + assign ex_out = (fetch_ex_if.uop.ctrl_out.rv32m_control.select) ? rv32m_out : alu_if.port_out; + + /************************* + * Register File Writeback + *************************/ + assign rf_if.w_data = ex_mem_if.reg_wdata; + assign rf_if.rd = ex_mem_if.rd_m; + assign rf_if.wen = ex_mem_if.reg_write && !hazard_if.ex_mem_stall; // TODO: The second signal only matters for some miniscule power reduction by not writing each cycle. This is correct with only the wen signal due to no loop from reg read to reg write + + /*********************************************** + * Branch Target Resolution and Associated Logic + ***********************************************/ + word_t resolved_addr; + logic branch_taken; + word_t branch_addr; + word_t brj_addr; + + assign branch_if.rs1_data = rs1_post_fwd;//rf_if.rs1_data; + assign branch_if.rs2_data = rs2_post_fwd; //rf_if.rs2_data; + assign branch_if.pc = fetch_ex_if.uop.if_out.pc; + assign branch_if.imm_sb = fetch_ex_if.uop.ctrl_out.imm_SB; + assign branch_if.branch_type = fetch_ex_if.uop.ctrl_out.branch_type; + + // Mux resource based on if RISC-MGMT is trying to access it + assign branch_taken = branch_if.branch_taken;//rm_if.req_br_j ? rm_if.branch_jump : branch_if.branch_taken; + assign branch_addr = branch_if.branch_addr;//rm_if.req_br_j ? rm_if.br_j_addr : branch_if.branch_addr; + //assign rm_if.pc = fetch_ex_if.fetch_ex_reg.pc; + + assign resolved_addr = branch_if.branch_taken ? branch_addr : fetch_ex_if.uop.if_out.pc4; + assign brj_addr = fetch_ex_if.uop.ctrl_out.ex_pc_sel ? jump_addr : resolved_addr; + //assign brj_addr = ((fetch_ex_if.uop.ctrl_out.ex_pc_sel == 1'b1) && ~rm_if.req_br_j) ? + // jump_addr : resolved_addr; + + //assign hazard_if.mispredict = fetch_ex_if.fetch_ex_reg.prediction ^ branch_taken; + + /******************************** + * Hazard/Forwarding Unit Signals + *********************************/ + assign hazard_if.rs1_e = rf_if.rs1; + assign hazard_if.rs2_e = rf_if.rs2; + + assign fw_if.rs1_e = rf_if.rs1; + assign fw_if.rs2_e = rf_if.rs2; + + assign hazard_if.pc_e = fetch_ex_if.uop.if_out.pc; + assign hazard_if.ex_busy = (rv32m_busy && fetch_ex_if.uop.ctrl_out.rv32m_control.select); // Add & conditions here for other FUs that can stall + assign hazard_if.valid_e = fetch_ex_if.uop.if_out.valid; + + + // TODO: NEW + always_ff @(posedge CLK, negedge nRST) begin + if(!nRST) begin + /*verilator lint_off ENUMVALUE*/ + ex_mem_if.ex_mem_reg <= '{default: '0}; + /*verilator lint_on ENUMVALUE*/ + end else begin + // TODO: This register is ~180b. Not awful, but can it be smaller? + // PS: Does it even matter? Synth. tools may be able to merge regs. + if(!hazard_if.ex_mem_flush && !hazard_if.ex_mem_stall) begin + // TODO: Handle case of exceptions earlier in the pipe being passed on to handle in the last stage + // Single bit control signals -- squash these if we have an exception + // Only need to check illegal since it's the only "new" exception we have + ex_mem_if.ex_mem_reg.valid <= fetch_ex_if.uop.if_out.valid; + if(!fetch_ex_if.uop.ctrl_out.illegal_insn) begin + ex_mem_if.ex_mem_reg.branch <= fetch_ex_if.uop.ctrl_out.branch; + ex_mem_if.ex_mem_reg.prediction <= fetch_ex_if.uop.if_out.prediction; + ex_mem_if.ex_mem_reg.branch_taken <= branch_if.branch_taken; + ex_mem_if.ex_mem_reg.dren <= fetch_ex_if.uop.ctrl_out.dren; + ex_mem_if.ex_mem_reg.dwen <= fetch_ex_if.uop.ctrl_out.dwen; + ex_mem_if.ex_mem_reg.reg_write <= fetch_ex_if.uop.ctrl_out.wen; + ex_mem_if.ex_mem_reg.ifence <= fetch_ex_if.uop.ctrl_out.ifence; + ex_mem_if.ex_mem_reg.jump <= fetch_ex_if.uop.ctrl_out.jump; + ex_mem_if.ex_mem_reg.halt <= fetch_ex_if.uop.ctrl_out.halt; + ex_mem_if.ex_mem_reg.csr_swap <= fetch_ex_if.uop.ctrl_out.csr_swap; + ex_mem_if.ex_mem_reg.csr_clr <= fetch_ex_if.uop.ctrl_out.csr_clr; + ex_mem_if.ex_mem_reg.csr_set <= fetch_ex_if.uop.ctrl_out.csr_set; + ex_mem_if.ex_mem_reg.csr_imm <= fetch_ex_if.uop.ctrl_out.csr_imm; + ex_mem_if.ex_mem_reg.csr_read_only <= (rf_if.rs1 == '0) || (fetch_ex_if.uop.ctrl_out.zimm == '0); + ex_mem_if.ex_mem_reg.breakpoint <= fetch_ex_if.uop.ctrl_out.breakpoint; + ex_mem_if.ex_mem_reg.ecall_insn <= fetch_ex_if.uop.ctrl_out.ecall_insn; + ex_mem_if.ex_mem_reg.ret_insn <= fetch_ex_if.uop.ctrl_out.ret_insn; + ex_mem_if.ex_mem_reg.wfi_insn <= fetch_ex_if.uop.ctrl_out.wfi; + ex_mem_if.ex_mem_reg.was_compressed <= 1'b0; // TODO: RV32C support + end + ex_mem_if.ex_mem_reg.illegal_insn <= fetch_ex_if.uop.ctrl_out.illegal_insn; + ex_mem_if.ex_mem_reg.badaddr <= fetch_ex_if.uop.if_out.badaddr; + ex_mem_if.ex_mem_reg.mal_insn <= fetch_ex_if.uop.if_out.mal_insn; + ex_mem_if.ex_mem_reg.fault_insn <= fetch_ex_if.uop.if_out.fault_insn; + + // Bit vectors + ex_mem_if.ex_mem_reg.w_sel <= fetch_ex_if.uop.ctrl_out.w_sel; + ex_mem_if.ex_mem_reg.zimm <= fetch_ex_if.uop.ctrl_out.zimm; + ex_mem_if.ex_mem_reg.rd_m <= fetch_ex_if.uop.ctrl_out.rd; + ex_mem_if.ex_mem_reg.load_type <= fetch_ex_if.uop.ctrl_out.load_type; + ex_mem_if.ex_mem_reg.csr_addr <= fetch_ex_if.uop.ctrl_out.csr_addr; + + // Word sized members + ex_mem_if.ex_mem_reg.brj_addr <= brj_addr; + ex_mem_if.ex_mem_reg.port_out <= ex_out; + ex_mem_if.ex_mem_reg.rs1_data <= rs1_post_fwd; + ex_mem_if.ex_mem_reg.rs2_data <= rs2_post_fwd; + ex_mem_if.ex_mem_reg.instr <= fetch_ex_if.uop.if_out.instr; + ex_mem_if.ex_mem_reg.pc <= fetch_ex_if.uop.if_out.pc; + ex_mem_if.ex_mem_reg.pc4 <= fetch_ex_if.uop.if_out.pc4; + ex_mem_if.ex_mem_reg.imm_U <= fetch_ex_if.uop.ctrl_out.imm_U; + + // CPU Tracker + ex_mem_if.ex_mem_reg.tracker_signals.opcode <= fetch_ex_if.uop.ctrl_out.opcode; + ex_mem_if.ex_mem_reg.tracker_signals.imm_SB <= fetch_ex_if.uop.ctrl_out.imm_SB; + ex_mem_if.ex_mem_reg.tracker_signals.imm_S <= fetch_ex_if.uop.ctrl_out.imm_S; + ex_mem_if.ex_mem_reg.tracker_signals.imm_I <= fetch_ex_if.uop.ctrl_out.imm_I; + ex_mem_if.ex_mem_reg.tracker_signals.imm_UJ <= fetch_ex_if.uop.ctrl_out.imm_UJ; + ex_mem_if.ex_mem_reg.tracker_signals.imm_U <= fetch_ex_if.uop.ctrl_out.imm_U; + + end else if(hazard_if.ex_mem_flush && !hazard_if.ex_mem_stall) begin + /*verilator lint_off ENUMVALUE*/ + ex_mem_if.ex_mem_reg <= '{default: '0}; + /*verilator lint_on ENUMVALUE*/ + end + // else: retain state + end + end + + /********************************************************* + *** SparCE Module Logic + *********************************************************/ + /*assign sparce_if.wb_data = rf_if.w_data; + assign sparce_if.wb_en = rf_if.wen; + assign sparce_if.sasa_data = rf_if.rs2_data; + assign sparce_if.sasa_addr = alu_if.port_out; + assign sparce_if.sasa_wen = uop_out.ctrl_out.dwen; + assign sparce_if.rd = rf_if.rd;*/ + +endmodule diff --git a/source_code/pipelines/stage4/source/stage3_fetch_stage.sv b/source_code/pipelines/stage4/source/stage3_fetch_stage.sv new file mode 100644 index 000000000..34fed7aa2 --- /dev/null +++ b/source_code/pipelines/stage4/source/stage3_fetch_stage.sv @@ -0,0 +1,159 @@ +/* +* Copyright 2016 Purdue University +* +* 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. +* +* +* Filename: stage3_fetch_stage.sv +* +* Created by: John Skubic +* Email: jskubic@purdue.edu +* Date Created: 06/19/2016 +* Description: Fetch stage for the two stage pipeline +*/ + +`include "stage3_fetch_execute_if.vh" +`include "stage3_hazard_unit_if.vh" +`include "predictor_pipeline_if.vh" +`include "generic_bus_if.vh" +`include "component_selection_defines.vh" +`include "cache_control_if.vh" +`include "rv32c_if.vh" +`include "prv_pipeline_if.vh" + +module stage3_fetch_stage ( + input logic CLK, + nRST, + stage3_fetch_execute_if.fetch fetch_ex_if, + stage3_mem_pipe_if.fetch mem_fetch_if, + stage3_hazard_unit_if.fetch hazard_if, + predictor_pipeline_if.access predict_if, + generic_bus_if.cpu igen_bus_if, + sparce_pipeline_if.pipe_fetch sparce_if, + rv32c_if.fetch rv32cif, + prv_pipeline_if.fetch prv_pipe_if +); + import rv32i_types_pkg::*; + import pma_types_1_12_pkg::*; + + parameter logic [31:0] RESET_PC = 32'h80000000; + + word_t pc, pc4or2, npc, instr; + + //Send exceptions through pipeline + logic mal_addr; + logic fault_insn; + logic mal_insn; + word_t badaddr; + + //PC logic + + always_ff @(posedge CLK, negedge nRST) begin + if (~nRST) begin + pc <= RESET_PC; + end else if (hazard_if.pc_en /*| rv32cif.done_earlier*/) begin + pc <= npc; + end + end + + //RV32C + assign rv32cif.inst = igen_bus_if.rdata; + assign rv32cif.inst_arrived = hazard_if.if_ex_flush == 0 & hazard_if.if_ex_stall == 0; + assign rv32cif.reset_en = hazard_if.insert_priv_pc | hazard_if.rollback | sparce_if.skipping + | hazard_if.npc_sel | predict_if.predict_taken; + assign rv32cif.pc_update = hazard_if.pc_en; + assign rv32cif.reset_pc = hazard_if.insert_priv_pc ? hazard_if.priv_pc + : (hazard_if.rollback ? mem_fetch_if.pc4 + : (sparce_if.skipping ? sparce_if.sparce_target + : (hazard_if.npc_sel ? mem_fetch_if.brj_addr + : (predict_if.predict_taken ? predict_if.target_addr + : pc4or2)))); + assign rv32cif.reset_pc_val = RESET_PC; + + assign pc4or2 = (rv32cif.rv32c_ena & (rv32cif.result[1:0] != 2'b11)) ? (pc + 2) : (pc + 4); + assign predict_if.current_pc = pc; + assign npc = hazard_if.insert_priv_pc ? hazard_if.priv_pc + : (hazard_if.rollback ? mem_fetch_if.pc4 + : (sparce_if.skipping ? sparce_if.sparce_target + : (hazard_if.npc_sel ? mem_fetch_if.brj_addr + : (predict_if.predict_taken ? predict_if.target_addr + : rv32cif.rv32c_ena ? rv32cif.nextpc + : pc4or2)))); + + //Instruction Access logic + assign hazard_if.i_mem_busy = igen_bus_if.busy && !fault_insn; + assign igen_bus_if.addr = rv32cif.rv32c_ena ? rv32cif.imem_pc : pc; + assign igen_bus_if.ren = hazard_if.iren && !rv32cif.done_earlier && !hazard_if.suppress_iren; + assign igen_bus_if.wen = 1'b0; + assign igen_bus_if.byte_en = 4'b1111; + assign igen_bus_if.wdata = '0; + + + assign mal_addr = (igen_bus_if.addr[1:0] != 2'b00); + assign fault_insn = prv_pipe_if.prot_fault_i || (igen_bus_if.ren && igen_bus_if.error); // TODO: Set this up to fault on bus error + assign mal_insn = mal_addr; + assign badaddr = igen_bus_if.addr; + assign hazard_if.pc_f = pc; + assign hazard_if.rv32c_ready = rv32cif.done_earlier && rv32cif.rv32c_ena; // TODO: Is rv32cif.done needed? Seems like it coincides with busy = 0 + + + //Fetch Execute Pipeline Signals + word_t instr_to_ex; + assign instr_to_ex = rv32cif.rv32c_ena ? rv32cif.result : igen_bus_if.rdata; + always_ff @(posedge CLK, negedge nRST) begin + if (!nRST) fetch_ex_if.fetch_ex_reg <= '0; + else if (hazard_if.if_ex_flush && !hazard_if.if_ex_stall) fetch_ex_if.fetch_ex_reg <= '0; + else if (!hazard_if.if_ex_stall) begin + if(mal_insn || fault_insn) begin + // Squash to NOP if exception + // Still valid for exception handling + fetch_ex_if.fetch_ex_reg.instr <= '0; + end else begin + fetch_ex_if.fetch_ex_reg.instr <= instr_to_ex; + end + fetch_ex_if.fetch_ex_reg.valid <= 1'b1; + fetch_ex_if.fetch_ex_reg.token <= 1'b1; + fetch_ex_if.fetch_ex_reg.mal_insn <= mal_insn; + fetch_ex_if.fetch_ex_reg.fault_insn <= fault_insn; + fetch_ex_if.fetch_ex_reg.badaddr <= badaddr; + fetch_ex_if.fetch_ex_reg.pc <= pc; + fetch_ex_if.fetch_ex_reg.pc4 <= pc4or2; + fetch_ex_if.fetch_ex_reg.prediction <= predict_if.predict_taken; // TODO: This is just wrong... + end + end + + + // Send memory protection signals + assign prv_pipe_if.iren = hazard_if.iren; + assign prv_pipe_if.iaddr = igen_bus_if.addr; + assign prv_pipe_if.i_acc_width = WordAcc; + + // Choose the endianness of the data coming into the processor + generate + if (BUS_ENDIANNESS == "big") assign instr = igen_bus_if.rdata; + else if (BUS_ENDIANNESS == "little") + endian_swapper ltb_endian ( + .word_in(igen_bus_if.rdata), + .word_out(instr) + ); + endgenerate + + /********************************************************* + *** SparCE Module Logic + *********************************************************/ + + assign sparce_if.pc = pc; + assign sparce_if.rdata = igen_bus_if.rdata; +endmodule + + diff --git a/source_code/pipelines/stage4/source/stage3_forwarding_unit.sv b/source_code/pipelines/stage4/source/stage3_forwarding_unit.sv new file mode 100644 index 000000000..0f5bf141f --- /dev/null +++ b/source_code/pipelines/stage4/source/stage3_forwarding_unit.sv @@ -0,0 +1,14 @@ + +module stage3_forwarding_unit( + stage3_forwarding_unit_if.fw_unit fw_if +); + + logic rs1_match, rs2_match; + + assign rs1_match = (fw_if.rd_m != 0) && (fw_if.rs1_e == fw_if.rd_m); + assign rs2_match = (fw_if.rd_m != 0) && (fw_if.rs2_e == fw_if.rd_m); + + assign fw_if.fwd_rs1 = rs1_match && fw_if.reg_write && !fw_if.load; + assign fw_if.fwd_rs2 = rs2_match && fw_if.reg_write && !fw_if.load; + +endmodule diff --git a/source_code/pipelines/stage4/source/stage3_hazard_unit.sv b/source_code/pipelines/stage4/source/stage3_hazard_unit.sv new file mode 100644 index 000000000..d75da6e54 --- /dev/null +++ b/source_code/pipelines/stage4/source/stage3_hazard_unit.sv @@ -0,0 +1,218 @@ +/* +* Copyright 2016 Purdue University +* +* 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. +* +* +* Filename: stage3_hazard_unit.sv +* +* Created by: Jacob R. Stevens +* Email: steven69@purdue.edu +* Date Created: 06/14/2016 +* Description: Hazard unit that controls the flushing and stalling of +* the stages of the Two Stage Pipeline +*/ + +`include "stage3_hazard_unit_if.vh" +`include "prv_pipeline_if.vh" +//`include "risc_mgmt_if.vh" + +import alu_types_pkg::*; +import rv32i_types_pkg::*; +import stage3_types_pkg::*; + +module stage3_hazard_unit ( + stage3_hazard_unit_if.hazard_unit hazard_if, + prv_pipeline_if.hazard prv_pipe_if + //risc_mgmt_if.ts_hazard rm_if, + //sparce_pipeline_if.hazard sparce_if + + //input logic is_queue_full, valid_decode, + //input word_t pc_decode, + //output logic stall_queue, flush_queue + + +); + + + // Pipeline hazard signals + logic dmem_access; + logic branch_jump; + logic wait_for_imem; + logic wait_for_dmem; + logic rs1_match; + logic rs2_match; + logic mem_use_stall; + logic cannot_forward; + logic fetch_busy; + logic execute_busy; + logic mem_busy; + + // IRQ/Exception hazard signals + logic ex_flush_hazard; + logic exception; + logic intr; + word_t epc; + + // TODO: RISC-MGMT + //logic rmgmt_stall; + + //assign rm_if.if_ex_enable = ~hazard_if.if_ex_stall; + //assign rmgmt_stall = rm_if.memory_stall | rm_if.execute_stall; + + // Hazard detection + + assign rs1_match = ((hazard_if.rs1_e.regidx == hazard_if.rd_m.regidx) && (hazard_if.rd_m.regidx != 0)); + assign rs2_match = ((hazard_if.rs2_e.regidx == hazard_if.rd_m.regidx) && (hazard_if.rd_m.regidx != 0)); + // assign rs1_match = (hazard_if.rs1_e == hazard_if.rd_m) && (hazard_if.rd_m != 0); + // assign rs2_match = (hazard_if.rs2_e == hazard_if.rd_m) && (hazard_if.rd_m != 0); + assign cannot_forward = (hazard_if.dren || hazard_if.csr_read); // cannot forward outputs generated in mem stage + + assign dmem_access = (hazard_if.dren || hazard_if.dwen); + assign branch_jump = hazard_if.jump || (hazard_if.branch && hazard_if.mispredict); + assign wait_for_imem = hazard_if.iren && hazard_if.i_mem_busy && !hazard_if.suppress_iren && !hazard_if.rv32c_ready; // don't wait for imem when rv32c is done early + assign wait_for_dmem = dmem_access && hazard_if.d_mem_busy && !hazard_if.suppress_data; + assign mem_use_stall = hazard_if.reg_write && cannot_forward && (rs1_match || rs2_match); + + assign hazard_if.npc_sel = branch_jump; + + + + /* Hazards due to Interrupts/Exceptions */ + assign prv_pipe_if.ret = hazard_if.ret; + assign exception = hazard_if.fault_insn | hazard_if.mal_insn // | prv_pipe_if.prot_fault_i + | hazard_if.illegal_insn | hazard_if.fault_l | hazard_if.mal_l + | hazard_if.fault_s | hazard_if.mal_s | hazard_if.breakpoint + | hazard_if.env | prv_pipe_if.prot_fault_l | prv_pipe_if.prot_fault_s; + + assign intr = ~exception & prv_pipe_if.intr; + + assign prv_pipe_if.pipe_clear = 1'b1; // TODO: What is this for?//exception; //| ~(hazard_if.token_ex | rm_if.active_insn); + assign ex_flush_hazard = ((intr || exception) && !wait_for_dmem) || exception || prv_pipe_if.ret || (hazard_if.ifence && !hazard_if.fence_stall); // I-fence must flush to force re-fetch of in-flight instructions. Flush will happen after stallling for cache response. + + assign hazard_if.insert_priv_pc = prv_pipe_if.insert_pc; + assign hazard_if.priv_pc = prv_pipe_if.priv_pc; + + assign hazard_if.iren = 1'b1; + // TODO: Removed intr as cause of suppression -- is this OK? + //assign hazard_if.suppress_iren = branch_jump || exception || prv_pipe_if.ret || prv_pipe_if.insert_pc; // prevents a false instruction request from being sent when pipeline flush imminent + assign hazard_if.suppress_iren = branch_jump || ex_flush_hazard || prv_pipe_if.ret || prv_pipe_if.insert_pc; // prevents a false instruction request from being sent when pipeline flush imminent + assign hazard_if.suppress_data = exception; // suppress data transfer on interrupt/exception. Exception case: prevent read/write of faulting location. Interrupt: make symmetric with exceptions for ease + + assign hazard_if.rollback = (hazard_if.ifence && !hazard_if.fence_stall); // TODO: more cases for CSRs that affect I-fetch (PMA/PMP registers) + + // EPC priority logic + assign epc = hazard_if.valid_m && !intr ? hazard_if.pc_m : + (hazard_if.valid_e ? hazard_if.pc_e : ( hazard_if.valid_decode ? hazard_if.pc_decode : hazard_if.pc_f)); + + /* Send Exception notifications to Prv Block */ + // TODO: Correct execution of exceptions + assign prv_pipe_if.wb_enable = !hazard_if.if_ex_stall | + hazard_if.jump | + hazard_if.branch; //Because 2 stages + + assign prv_pipe_if.fault_insn = hazard_if.fault_insn;// | prv_pipe_if.prot_fault_i; + assign prv_pipe_if.mal_insn = hazard_if.mal_insn; + assign prv_pipe_if.illegal_insn = hazard_if.illegal_insn; + assign prv_pipe_if.fault_l = hazard_if.fault_l | prv_pipe_if.prot_fault_l; + assign prv_pipe_if.mal_l = hazard_if.mal_l; + assign prv_pipe_if.fault_s = hazard_if.fault_s | prv_pipe_if.prot_fault_s; + assign prv_pipe_if.mal_s = hazard_if.mal_s; + assign prv_pipe_if.breakpoint = hazard_if.breakpoint; + assign prv_pipe_if.env = hazard_if.env; + assign prv_pipe_if.wfi = hazard_if.wfi; + assign prv_pipe_if.ex_rmgmt = 1'b0;//rm_if.exception; + + assign prv_pipe_if.ex_rmgmt_cause = '0;//rm_if.ex_cause; + assign prv_pipe_if.epc = epc; + assign prv_pipe_if.badaddr = hazard_if.badaddr; + + + /* + * Pipeline control signals + * + * Control hazard (Exception, Jump, Mispredict): F/E -> Flush, E/M -> Flush + * - Special case: interrupt. Async, don't know where the oldest insn is. Interrupts must assume the memory op will go through, so flush only I/F + * Data hazard (unforwardable, load/CSR read): F/E -> Stall, E/M -> Flush + * Waiting (i.e. slow dmem access, fence, etc.): + * - If fetch stage slow, flush if_ex so in-flight instructions may finish (insert bubbles) + * - If ex stage slow, flush ex_mem so in-flight instruction may finish (insert bubbles). Stall if_ex + * - If mem stage slow, stall everyone + * - Halt - stall everyone + * Note: Stall of later stage implies stall of earlier stage. + * PC should not update if: + * - fetch_if is stalling (can't pass instruction on) + * PC should update if: + * - fetch is not stalling + * - there is a forced redirect + */ + + /*assign hazard_if.pc_en = (~wait_for_dmem & ~wait_for_imem & ~hazard_if.halt & ~ex_flush_hazard + & ~rmgmt_stall & ~hazard_if.fence_stall) + | branch_jump | prv_pipe_if.insert_pc | prv_pipe_if.ret | hazard_if.rollback;*/ + // Unforunately, pc_en is negative logic of stalling + assign hazard_if.pc_en = (!hazard_if.if_ex_stall && !wait_for_imem) // Normal case: next stage free, not waiting for instruction + || branch_jump + //|| ex_flush_hazard + || prv_pipe_if.insert_pc + || prv_pipe_if.ret;//) //&& !wait_for_imem; + + assign hazard_if.if_ex_flush = //ex_flush_hazard // control hazard + //branch_jump || // control hazard + branch_jump || ex_flush_hazard || (wait_for_imem); //&& !hazard_if.ex_mem_stall); // Flush if fetch stage lagging, but ex/mem are moving + assign hazard_if.flush_queue = ex_flush_hazard // control hazard + || branch_jump; // control hazard + //|| (wait_for_imem && !hazard_if.ex_mem_stall); // Flush if fetch stage lagging, but ex/mem are moving + + assign hazard_if.ex_mem_flush = ex_flush_hazard // Control hazard + || branch_jump // Control hazard + //|| (mem_use_stall && !hazard_if.d_mem_busy) // Data hazard -- flush once data memory is no longer busy (request complete) + || (hazard_if.stall_queue && !hazard_if.ex_mem_stall); // if_ex_stall covers mem_use stall condition + + + // assign hazard_if.if_ex_stall = hazard_if.ex_mem_stall // Stall this stage if next stage is stalled + // // || (wait_for_imem && !dmem_access) // ??? + // //& (~ex_flush_hazard | e_ex_stage) // ??? + // //|| rm_if.execute_stall // + // || (hazard_if.ex_busy && !ex_flush_hazard && !branch_jump) // Ugly case -- need to flush for control hazards when X busy, but other cases require stalling to take priority to prevent data loss (e.g. slow instruction fetch, valid insn in X, load in M --> giving flush priority would destroy insn in X) + // || mem_use_stall + // || hazard_if.fence_stall // Data hazard -- stall until dependency clears (from E/M flush after writeback) + // || is_queue_full; + assign hazard_if.if_ex_stall = hazard_if.is_queue_full || hazard_if.fence_stall; // || hazard_if.fence_stall; + + assign hazard_if.stall_queue = hazard_if.ex_mem_stall // Stall this stage if next stage is stalled + // || (wait_for_imem && !dmem_access) // ??? + //& (~ex_flush_hazard | e_ex_stage) // ??? + //|| rm_if.execute_stall // + //|| branch_jump + //|| (hazard_if.if_ex_stall && !hazard_if.ex_mem_stall) + //|| ex_flush_hazard + || (hazard_if.ex_busy && !ex_flush_hazard && !branch_jump) // Ugly case -- need to flush for control hazards when X busy, but other cases require stalling to take priority to prevent data loss (e.g. slow instruction fetch, valid insn in X, load in M --> giving flush priority would destroy insn in X) + || mem_use_stall + || hazard_if.fence_stall; // Data hazard -- stall until dependency clears (from E/M flush after writeback) + + + // TODO: Exceptions + assign hazard_if.ex_mem_stall = wait_for_dmem // Second clause ensures we finish memory op on interrupt condition + || hazard_if.fence_stall + || hazard_if.halt; + //|| branch_jump && wait_for_imem; // This can be removed once there is I$. Solves problem where + // stale I-request returns after PC is redirected + // TODO: Enforce mutual exclusivity of these signals with assertion + + /********************************************************* + *** SparCE Module Logic + *********************************************************/ + //assign sparce_if.if_ex_enable = rm_if.if_ex_enable; + +endmodule diff --git a/source_code/pipelines/stage4/source/stage3_mem_stage.sv b/source_code/pipelines/stage4/source/stage3_mem_stage.sv new file mode 100644 index 000000000..e937e1d1c --- /dev/null +++ b/source_code/pipelines/stage4/source/stage3_mem_stage.sv @@ -0,0 +1,273 @@ + +`include "stage3_hazard_unit_if.vh" +`include "stage3_mem_pipe_if.vh" +`include "generic_bus_if.vh" +`include "predictor_pipeline_if.vh" +`include "cache_control_if.vh" +`include "prv_pipeline_if.vh" + +module stage3_mem_stage( + input CLK, + input nRST, + stage3_mem_pipe_if.mem ex_mem_if, + stage3_hazard_unit_if.mem hazard_if, + stage3_forwarding_unit_if.mem fw_if, + generic_bus_if.cpu dgen_bus_if, + prv_pipeline_if.pipe prv_pipe_if, + cache_control_if.pipeline cc_if, + predictor_pipeline_if.update predict_if, + output logic halt, + output logic wfi +); + + import rv32i_types_pkg::*; + import pma_types_1_12_pkg::*; + + /*************** + * Branch Update + ****************/ + assign predict_if.update_predictor = ex_mem_if.ex_mem_reg.branch; + assign predict_if.prediction = ex_mem_if.ex_mem_reg.prediction; + assign predict_if.branch_result = ex_mem_if.ex_mem_reg.branch_taken; + assign predict_if.update_addr = ex_mem_if.ex_mem_reg.brj_addr; + + + + + /************* + * Data Access + **************/ + word_t store_swapped; + word_t dload_ext; + logic mal_addr; + logic [1:0] byte_offset; + logic [3:0] byte_en, byte_en_temp, byte_en_standard; + + + + // TODO: RISC-MGMT + assign dgen_bus_if.ren = ex_mem_if.ex_mem_reg.dren && !hazard_if.suppress_data; + assign dgen_bus_if.wen = ex_mem_if.ex_mem_reg.dwen && !hazard_if.suppress_data; + assign dgen_bus_if.byte_en = byte_en; + assign dgen_bus_if.addr = ex_mem_if.ex_mem_reg.port_out; + assign byte_offset = ex_mem_if.ex_mem_reg.port_out[1:0]; + + // TODO: RISC-MGMT + assign byte_en_temp = byte_en_standard; + + // Address alignment + always_comb begin + if (byte_en == 4'hf) mal_addr = (dgen_bus_if.addr[1:0] != 2'b00); + else if (byte_en == 4'h3 || byte_en == 4'hc) begin + mal_addr = (dgen_bus_if.addr[1:0] == 2'b01 || dgen_bus_if.addr[1:0] == 2'b11); + end else mal_addr = 1'b0; + end + + endian_swapper store_swap( + .word_in(ex_mem_if.ex_mem_reg.rs2_data), + .word_out(store_swapped) + ); + + dmem_extender dmem_ext( + .dmem_in(dgen_bus_if.rdata), + .load_type(ex_mem_if.ex_mem_reg.load_type), + .byte_en(byte_en), + .ext_out(dload_ext) + ); + + always_comb begin : LOAD_TYPE + case (ex_mem_if.ex_mem_reg.load_type) + LB, LBU: begin + case (byte_offset) + 2'b00: byte_en_standard = 4'b0001; + 2'b01: byte_en_standard = 4'b0010; + 2'b10: byte_en_standard = 4'b0100; + 2'b11: byte_en_standard = 4'b1000; + default: byte_en_standard = 4'b0000; + endcase + end + + LH, LHU: begin + case (byte_offset) + 2'b00: byte_en_standard = 4'b0011; + 2'b10: byte_en_standard = 4'b1100; + default: byte_en_standard = 4'b0000; + endcase + end + + LW: begin + byte_en_standard = 4'b1111; + end + + default: byte_en_standard = 4'b0000; + endcase + end : LOAD_TYPE + + // TODO: RISC-MGMT + always_comb begin : STORE_TYPE + case(ex_mem_if.ex_mem_reg.load_type) + LB: dgen_bus_if.wdata = {4{ex_mem_if.ex_mem_reg.rs2_data[7:0]}}; + LH: dgen_bus_if.wdata = {2{ex_mem_if.ex_mem_reg.rs2_data[15:0]}}; + LW: dgen_bus_if.wdata = ex_mem_if.ex_mem_reg.rs2_data; + default: dgen_bus_if.wdata = '0; + endcase + end : STORE_TYPE + + // Endianness + generate + if(BUS_ENDIANNESS == "big") begin : g_data_bus_be + assign byte_en = byte_en_temp; + end else if(BUS_ENDIANNESS == "little") begin : g_data_bus_le + assign byte_en = ex_mem_if.ex_mem_reg.dren ? byte_en_temp + : {byte_en_temp[0], byte_en_temp[1], + byte_en_temp[2], byte_en_temp[3]}; + end + endgenerate + + + /****************** + * Cache management + *******************/ + logic ifence_reg; + logic ifence_pulse; + logic iflushed, iflushed_next; + logic dflushed, dflushed_next; + logic iflush_done_reg, dflush_done_reg; + + always_ff @(posedge CLK, negedge nRST) begin + if(!nRST) begin + ifence_reg <= 1'b0; + iflushed <= 1'b1; + dflushed <= 1'b1; + end else begin + ifence_reg <= ex_mem_if.ex_mem_reg.ifence; + iflushed <= iflushed_next; + dflushed <= dflushed_next; + end + end + + assign ifence_pulse = ex_mem_if.ex_mem_reg.ifence & ~ifence_reg; + assign cc_if.icache_flush = ifence_pulse; + assign cc_if.dcache_flush = ifence_pulse; + // holds iflushed/dflushed high when done, resets to 0 on a pulse + always_comb begin + iflushed_next = iflushed; + dflushed_next = dflushed; + if (ifence_pulse) begin + iflushed_next = 0; + dflushed_next = 0; + end + if (cc_if.iflush_done) + iflushed_next = 1; + if (cc_if.dflush_done) + dflushed_next = 1; + end + + /************************ + * Hazard/Forwarding Unit + *************************/ + // Note: Some hazard unit signals are assigned below in the CSR section + assign hazard_if.d_mem_busy = dgen_bus_if.busy; + assign hazard_if.ifence = ex_mem_if.ex_mem_reg.ifence; + assign hazard_if.fence_stall = ifence_reg && !(iflushed && dflushed); + assign hazard_if.dren = ex_mem_if.ex_mem_reg.dren; + assign hazard_if.dwen = ex_mem_if.ex_mem_reg.dwen; + assign hazard_if.jump = ex_mem_if.ex_mem_reg.jump; + assign hazard_if.branch = ex_mem_if.ex_mem_reg.branch; + assign hazard_if.halt = ex_mem_if.ex_mem_reg.halt; + assign hazard_if.rd_m = ex_mem_if.ex_mem_reg.rd_m; + assign hazard_if.reg_write = ex_mem_if.ex_mem_reg.reg_write; + assign hazard_if.csr_read = prv_pipe_if.valid_write; + assign hazard_if.token_mem = 0; // TODO: RISC-MGMT + assign hazard_if.mispredict = ex_mem_if.ex_mem_reg.prediction ^ ex_mem_if.ex_mem_reg.branch_taken; + //assign hazard_if.pc = ex_mem_if.ex_mem_reg.pc; + + assign halt = ex_mem_if.ex_mem_reg.halt; + assign fw_if.rd_m = ex_mem_if.ex_mem_reg.rd_m; + assign fw_if.reg_write = ex_mem_if.reg_write; + assign fw_if.load = (ex_mem_if.ex_mem_reg.dren || ex_mem_if.ex_mem_reg.dwen); + + + /****** + * CSRs + *******/ + assign prv_pipe_if.swap = ex_mem_if.ex_mem_reg.csr_swap; + assign prv_pipe_if.clr = ex_mem_if.ex_mem_reg.csr_clr; + assign prv_pipe_if.set = ex_mem_if.ex_mem_reg.csr_set; + assign prv_pipe_if.read_only = ex_mem_if.ex_mem_reg.csr_read_only; + assign prv_pipe_if.wdata = ex_mem_if.ex_mem_reg.csr_imm ? {27'h0, ex_mem_if.ex_mem_reg.zimm} : ex_mem_if.ex_mem_reg.rs1_data; + assign prv_pipe_if.csr_addr = ex_mem_if.ex_mem_reg.csr_addr; + assign prv_pipe_if.valid_write = (prv_pipe_if.swap | prv_pipe_if.clr + | prv_pipe_if.set) & ~hazard_if.ex_mem_stall; + assign prv_pipe_if.instr = (ex_mem_if.ex_mem_reg.instr != '0); + + assign hazard_if.fault_insn = ex_mem_if.ex_mem_reg.fault_insn; + assign hazard_if.mal_insn = ex_mem_if.ex_mem_reg.mal_insn; + assign hazard_if.illegal_insn = ex_mem_if.ex_mem_reg.illegal_insn || prv_pipe_if.invalid_priv_isn; + assign hazard_if.fault_l = ex_mem_if.ex_mem_reg.dren && dgen_bus_if.error; + assign hazard_if.mal_l = ex_mem_if.ex_mem_reg.dren & mal_addr; + assign hazard_if.fault_s = ex_mem_if.ex_mem_reg.dwen && dgen_bus_if.error; + assign hazard_if.mal_s = ex_mem_if.ex_mem_reg.dwen & mal_addr; + assign hazard_if.breakpoint = ex_mem_if.ex_mem_reg.breakpoint; + assign hazard_if.env = ex_mem_if.ex_mem_reg.ecall_insn; + assign hazard_if.ret = ex_mem_if.ex_mem_reg.ret_insn; + assign hazard_if.wfi = ex_mem_if.ex_mem_reg.wfi_insn; + assign hazard_if.badaddr = (hazard_if.fault_insn || hazard_if.mal_insn) ? ex_mem_if.ex_mem_reg.badaddr : dgen_bus_if.addr; + + // NEW + assign hazard_if.pc_m = ex_mem_if.ex_mem_reg.pc; + assign hazard_if.valid_m = ex_mem_if.ex_mem_reg.valid; + assign ex_mem_if.pc4 = ex_mem_if.ex_mem_reg.pc4; + + // Memory protection (doesn't consider RISC-MGMT) + assign prv_pipe_if.dren = ex_mem_if.ex_mem_reg.dren; + assign prv_pipe_if.dwen = ex_mem_if.ex_mem_reg.dwen; + assign prv_pipe_if.daddr = ex_mem_if.ex_mem_reg.port_out; + assign prv_pipe_if.d_acc_width = WordAcc; + + // TODO: Currently omitting SparCE + + /*********** + * Writeback + ************/ + assign ex_mem_if.brj_addr = ex_mem_if.ex_mem_reg.brj_addr; + assign ex_mem_if.reg_write = ex_mem_if.ex_mem_reg.reg_write; + assign ex_mem_if.rd_m = ex_mem_if.ex_mem_reg.rd_m; + + always_comb begin + // TODO: RISC-MGMT + case (ex_mem_if.ex_mem_reg.w_sel) + 3'd0: ex_mem_if.reg_wdata = dload_ext; + 3'd1: ex_mem_if.reg_wdata = ex_mem_if.ex_mem_reg.pc4; + 3'd2: ex_mem_if.reg_wdata = ex_mem_if.ex_mem_reg.imm_U; + 3'd3: ex_mem_if.reg_wdata = ex_mem_if.ex_mem_reg.port_out; + 3'd4: ex_mem_if.reg_wdata = prv_pipe_if.rdata; + default: ex_mem_if.reg_wdata = '0; + endcase + + // Forwarding unit + case (ex_mem_if.ex_mem_reg.w_sel) + 3'd1: fw_if.rd_mem_data = ex_mem_if.ex_mem_reg.pc4; + 3'd2: fw_if.rd_mem_data = ex_mem_if.ex_mem_reg.imm_U; + 3'd3: fw_if.rd_mem_data = ex_mem_if.ex_mem_reg.port_out; + 3'd4: fw_if.rd_mem_data = prv_pipe_if.rdata; + default: fw_if.rd_mem_data = '0; + endcase + end + + /************** + * CPU Tracking + ***************/ + logic wb_stall; + logic [2:0] funct3; + logic [11:0] funct12; + logic instr_30; + + // TODO: Fix up hazard unit + assign funct3 = ex_mem_if.ex_mem_reg.instr[14:12]; + assign funct12 = ex_mem_if.ex_mem_reg.instr[31:20]; + assign instr_30 = ex_mem_if.ex_mem_reg.instr[30]; + assign wb_stall = hazard_if.ex_mem_stall & ~hazard_if.jump & ~hazard_if.branch; // TODO: Is this right? + + +endmodule diff --git a/source_code/pipelines/stage4/source/stage3_types_pkg.sv b/source_code/pipelines/stage4/source/stage3_types_pkg.sv new file mode 100644 index 000000000..f22d4c46e --- /dev/null +++ b/source_code/pipelines/stage4/source/stage3_types_pkg.sv @@ -0,0 +1,130 @@ + +package stage3_types_pkg; + + import alu_types_pkg::*; + import rv32i_types_pkg::*; + import machine_mode_types_1_12_pkg::*; + import rv32m_pkg::*; + + typedef struct packed { + logic valid; + logic token; + logic mal_insn; + logic fault_insn; + word_t pc; + word_t pc4; + word_t instr; + word_t prediction; + word_t badaddr; + } fetch_ex_t; + + typedef struct packed { + opcode_t opcode; + logic [12:0] imm_SB; + logic [11:0] imm_S; + logic [11:0] imm_I; + logic [20:0] imm_UJ; + logic [31:0] imm_U; + } tracker_ex_mem_t; + + // TODO: Instructions? + typedef struct packed { + logic valid; + logic branch; + logic prediction; + logic branch_taken; + logic dren; + logic dwen; + logic reg_write; + logic ifence; + logic jump; + logic halt; + logic csr_swap; + logic csr_clr; + logic csr_set; + logic csr_imm; + logic csr_read_only; + logic breakpoint; + logic ecall_insn; + logic ret_insn; + logic wfi_insn; + logic was_compressed; // Determine if PC should advance by 4 or 2, avoid passing PC and PC + (2/4) through pipeline + logic [2:0] w_sel; + logic [3:0] byte_en; // TODO: Where should this be generated? + logic [4:0] zimm; + regsel_t rd_m; + logic mal_insn; + logic fault_insn; + logic illegal_insn; + load_t load_type; + csr_addr_t csr_addr; + word_t brj_addr; + word_t port_out; + word_t rs1_data; + word_t rs2_data; + word_t instr; + word_t pc; + word_t pc4; + word_t imm_U; + word_t badaddr; + tracker_ex_mem_t tracker_signals; + // TODO: imm_U? Maybe needed + } ex_mem_t; + + typedef struct packed { + logic dwen; + logic dren; + logic j_sel; + logic branch; + logic jump; + logic ex_pc_sel; + logic imm_shamt_sel; + logic halt; + logic wen; + logic ifence; + logic wfi; + + aluop_t alu_op; + logic [1:0] alu_a_sel; + logic[1:0] alu_b_sel; + logic [2:0] w_sel; + logic [4:0] shamt; + regsel_t rd; + logic [11:0] imm_I; + logic[11:0] imm_S; + logic [20:0] imm_UJ; + logic [12:0] imm_SB; + // word_t instr; + word_t imm_U; + load_t load_type; + branch_t branch_type; + opcode_t opcode; + + // Privilege control signals + logic fault_insn; + logic illegal_insn; + logic ret_insn; + logic breakpoint; + logic ecall_insn; + logic csr_swap; + logic csr_set; + logic csr_clr; + logic csr_imm; + logic csr_rw_valid; + csr_addr_t csr_addr; + logic [4:0] zimm; + + // Extension control signals + rv32m_decode_t rv32m_control; + + // RF interface signals + regsel_t rs1; + regsel_t rs2; + } control_t; + + + typedef struct packed { + fetch_ex_t if_out; + control_t ctrl_out; + } uop_t; +endpackage \ No newline at end of file diff --git a/source_code/pipelines/stage4/source/stage4.sv b/source_code/pipelines/stage4/source/stage4.sv new file mode 100644 index 000000000..1bbecaa51 --- /dev/null +++ b/source_code/pipelines/stage4/source/stage4.sv @@ -0,0 +1,76 @@ +/* +* Copyright 2016 Purdue University +* +* 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. +* +* +* Filename: stage4.sv +* +* Created by: John Skubic +* Email: jskubic@purdue.edu +* Date Created: 06/01/2016 +* Description: Two Stage In-Order Pipeline +*/ + +`include "stage3_fetch_execute_if.vh" +`include "stage3_hazard_unit_if.vh" +`include "predictor_pipeline_if.vh" +`include "generic_bus_if.vh" +`include "prv_pipeline_if.vh" +//`include "risc_mgmt_if.vh" +`include "cache_control_if.vh" +`include "sparce_pipeline_if.vh" +`include "rv32c_if.vh" + +//`include "stage3_types_pkg.sv" + +import stage3_types_pkg::*; + +module stage4 #( + RESET_PC = 32'h80000000 +)( + input CLK, + input nRST, + output logic halt, + output logic wfi, + generic_bus_if.cpu igen_bus_if, + generic_bus_if.cpu dgen_bus_if, + prv_pipeline_if prv_pipe_if, + predictor_pipeline_if predict_if, + //risc_mgmt_if rm_if, + cache_control_if cc_if, + sparce_pipeline_if sparce_if, + rv32c_if rv32cif +); + + + //interface instantiations + stage3_fetch_execute_if fetch_ex_if(); + + stage3_mem_pipe_if mem_pipe_if(); + stage3_hazard_unit_if hazard_if(); + stage3_forwarding_unit_if fw_if(); + + + + //module instantiations + stage3_fetch_stage #(.RESET_PC(RESET_PC)) fetch_stage_i(.mem_fetch_if(mem_pipe_if), .*); + scalar_decode S_DECODE(.*, .stall_queue(hazard_if.stall_queue)); + uop_queue #(.QUEUE_LEN(8), .DISPATCH_SIZE(1)) uop_stage(.*); + stage3_execute_stage execute_stage_i(.ex_mem_if(mem_pipe_if), .*); + stage3_mem_stage mem_stage_i(.ex_mem_if(mem_pipe_if), .*); + stage3_hazard_unit hazard_unit_i(.*); + stage3_forwarding_unit forward_unit_i(.*); + + +endmodule diff --git a/source_code/pipelines/stage4/source/uop_queue.sv b/source_code/pipelines/stage4/source/uop_queue.sv new file mode 100644 index 000000000..18e5cc0ee --- /dev/null +++ b/source_code/pipelines/stage4/source/uop_queue.sv @@ -0,0 +1,80 @@ +/* +* Copyright 2023 Purdue University +* +* 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. +* +* +* Filename: uop_queue.sv +* +* Created by: Fahad Aloufi +* Email: faloufi@purdue.edu +* Date Created: 11/19/2023 +* Description: uop stage in pipeline that recieves input from the IF stage and generates output to the EX stage. +*/ +//'include "stage3_types_pkg.sv" +`include "stage3_fetch_execute_if.vh" + +import stage3_types_pkg::*; +import rv32i_types_pkg::*; + +module uop_queue +#( + parameter type D_TYPE = uop_t, + parameter QUEUE_LEN = 8, + parameter DISPATCH_SIZE = 1 +) +( + input logic CLK, + input logic nRST, + + stage3_fetch_execute_if.queue fetch_ex_if, + stage3_hazard_unit_if.queue hazard_if + +); + + + +D_TYPE[DISPATCH_SIZE-1:0] ctrls; +logic[$clog2(QUEUE_LEN)+1:0] num_free_slots; + +logic[$clog2(DISPATCH_SIZE):0] num_uops; +logic store; + +decode_resolution #(.D_TYPE(D_TYPE), .QUEUE_LEN(QUEUE_LEN), .DISPATCH_SIZE(DISPATCH_SIZE)) + DEC_RES(.num_free_slots(num_free_slots), + .num_uops(num_uops), + .ctrls(ctrls), + .store(store), + .valid_decode(hazard_if.valid_decode), + .pc_decode(hazard_if.pc_decode), + .s_ctrls(fetch_ex_if.s_ctrls), + .s_num_uops(fetch_ex_if.s_num_uops) + ); + + +decode_queue #(.D_TYPE(D_TYPE), .QUEUE_LEN(QUEUE_LEN), .DISPATCH_SIZE(DISPATCH_SIZE)) + DEC_QUEUE(.CLK(CLK), + .nRST(nRST), + .ctrls(ctrls), + .num_uops(num_uops), + .stall_queue(hazard_if.stall_queue), + .flush_queue(hazard_if.flush_queue), + .num_free_slots(num_free_slots), + .uop0(fetch_ex_if.uop), + .store(store)); + + +assign hazard_if.is_queue_full = (num_free_slots < num_uops) & ~hazard_if.flush_queue; + + +endmodule diff --git a/source_code/pipelines/stage4/stage4.core b/source_code/pipelines/stage4/stage4.core new file mode 100644 index 000000000..44262169d --- /dev/null +++ b/source_code/pipelines/stage4/stage4.core @@ -0,0 +1,40 @@ +CAPI=2: +name: socet:riscv:stage4:0.1.0 +description: Two-stage pipeline + +filesets: + rtl: + files: + - source/stage3_types_pkg.sv + - include/stage3_fetch_execute_if.vh : {is_include_file: true} + - include/stage3_mem_pipe_if.vh : {is_include_file: true} + - include/stage3_hazard_unit_if.vh : {is_include_file: true} + - include/stage3_forwarding_unit_if.vh : {is_include_file: true} + - source/stage3_fetch_stage.sv + - source/stage3_execute_stage.sv + - source/stage3_mem_stage.sv + - source/stage3_hazard_unit.sv + - source/stage3_forwarding_unit.sv + - source/stage4.sv + - source/scalar_decode.sv + - source/uop_queue.sv + - source/decode_resolution.sv + - source/decode_queue.sv + file_type: systemVerilogSource + + +targets: + default: &default + filesets: + - rtl + toplevel: stage4 + + lint: + <<: *default + description: Linting + default_tool: veriblelint + toplevel: stage4 + tools: + veriblelint: + verible_lint_args: ['--autofix=inplace-interactive', '--rules_config_search', '--waiver_files=stage4.waiver'] +