diff --git a/core/Flist.cv32a60x b/core/Flist.cv32a60x index 7c2269f71..2524c94a0 100644 --- a/core/Flist.cv32a60x +++ b/core/Flist.cv32a60x @@ -105,6 +105,7 @@ ${CVA6_REPO_DIR}/core/issue_read_operands.sv ${CVA6_REPO_DIR}/core/issue_stage.sv ${CVA6_REPO_DIR}/core/load_unit.sv ${CVA6_REPO_DIR}/core/load_store_unit.sv +${CVA6_REPO_DIR}/core/lsu_bypass.sv ${CVA6_REPO_DIR}/core/mult.sv ${CVA6_REPO_DIR}/core/multiplier.sv ${CVA6_REPO_DIR}/core/serdiv.sv diff --git a/core/Flist.cv32a6_imac_sv0 b/core/Flist.cv32a6_imac_sv0 index c05630c63..310cc070d 100644 --- a/core/Flist.cv32a6_imac_sv0 +++ b/core/Flist.cv32a6_imac_sv0 @@ -105,6 +105,7 @@ ${CVA6_REPO_DIR}/core/issue_read_operands.sv ${CVA6_REPO_DIR}/core/issue_stage.sv ${CVA6_REPO_DIR}/core/load_unit.sv ${CVA6_REPO_DIR}/core/load_store_unit.sv +${CVA6_REPO_DIR}/core/lsu_bypass.sv ${CVA6_REPO_DIR}/core/mult.sv ${CVA6_REPO_DIR}/core/multiplier.sv ${CVA6_REPO_DIR}/core/serdiv.sv diff --git a/core/Flist.cv32a6_imac_sv32 b/core/Flist.cv32a6_imac_sv32 index c05630c63..310cc070d 100644 --- a/core/Flist.cv32a6_imac_sv32 +++ b/core/Flist.cv32a6_imac_sv32 @@ -105,6 +105,7 @@ ${CVA6_REPO_DIR}/core/issue_read_operands.sv ${CVA6_REPO_DIR}/core/issue_stage.sv ${CVA6_REPO_DIR}/core/load_unit.sv ${CVA6_REPO_DIR}/core/load_store_unit.sv +${CVA6_REPO_DIR}/core/lsu_bypass.sv ${CVA6_REPO_DIR}/core/mult.sv ${CVA6_REPO_DIR}/core/multiplier.sv ${CVA6_REPO_DIR}/core/serdiv.sv diff --git a/core/Flist.cv32a6_imafc_sv32 b/core/Flist.cv32a6_imafc_sv32 index c05630c63..310cc070d 100644 --- a/core/Flist.cv32a6_imafc_sv32 +++ b/core/Flist.cv32a6_imafc_sv32 @@ -105,6 +105,7 @@ ${CVA6_REPO_DIR}/core/issue_read_operands.sv ${CVA6_REPO_DIR}/core/issue_stage.sv ${CVA6_REPO_DIR}/core/load_unit.sv ${CVA6_REPO_DIR}/core/load_store_unit.sv +${CVA6_REPO_DIR}/core/lsu_bypass.sv ${CVA6_REPO_DIR}/core/mult.sv ${CVA6_REPO_DIR}/core/multiplier.sv ${CVA6_REPO_DIR}/core/serdiv.sv diff --git a/core/Flist.cv64a6_imafdc_sv39 b/core/Flist.cv64a6_imafdc_sv39 index 71b327a51..72a038bc1 100644 --- a/core/Flist.cv64a6_imafdc_sv39 +++ b/core/Flist.cv64a6_imafdc_sv39 @@ -112,6 +112,7 @@ ${CVA6_REPO_DIR}/core/issue_read_operands.sv ${CVA6_REPO_DIR}/core/issue_stage.sv ${CVA6_REPO_DIR}/core/load_unit.sv ${CVA6_REPO_DIR}/core/load_store_unit.sv +${CVA6_REPO_DIR}/core/lsu_bypass.sv ${CVA6_REPO_DIR}/core/mult.sv ${CVA6_REPO_DIR}/core/multiplier.sv ${CVA6_REPO_DIR}/core/serdiv.sv diff --git a/core/csr_regfile.sv b/core/csr_regfile.sv index 188ab58d2..5e4c0c03b 100644 --- a/core/csr_regfile.sv +++ b/core/csr_regfile.sv @@ -1180,10 +1180,11 @@ module csr_regfile import ariane_pkg::*; #( for(int i = 0; i < 16; i++) begin if(i < NrPMPEntries) begin // We only support >=8-byte granularity, NA4 is disabled - if(pmpcfg_d[i].addr_mode != riscv::NA4 && !(pmpcfg_d[i].access_type.r == '0 && pmpcfg_d[i].access_type.w == '1)) + if(pmpcfg_d[i].addr_mode != riscv::NA4 && !(pmpcfg_d[i].access_type.r == '0 && pmpcfg_d[i].access_type.w == '1)) begin pmpcfg_q[i] <= pmpcfg_d[i]; - else + end else begin pmpcfg_q[i] <= pmpcfg_q[i]; + end pmpaddr_q[i] <= pmpaddr_d[i]; end else begin pmpcfg_q[i] <= '0; diff --git a/core/cva6.sv b/core/cva6.sv index 588f3c24a..e04ebc9e3 100644 --- a/core/cva6.sv +++ b/core/cva6.sv @@ -927,7 +927,7 @@ module cva6 import ariane_pkg::*; #( //pragma translate_on `ifdef RVFI_TRACE - always_comb + always_comb begin for (int i = 0; i < NR_COMMIT_PORTS; i++) begin logic exception, mem_exception; exception = commit_instr_id_commit[i].valid && ex_commit.valid; @@ -958,6 +958,7 @@ module cva6 import ariane_pkg::*; #( rvfi_o[i].rd_wdata = ariane_pkg::is_rd_fpr(commit_instr_id_commit[i].op) == 0 ? wdata_commit_id[i] : commit_instr_id_commit[i].result; rvfi_o[i].pc_rdata = commit_instr_id_commit[i].pc; end + end `endif endmodule // ariane diff --git a/core/frontend/frontend.sv b/core/frontend/frontend.sv index 6c965960f..19e5333d4 100644 --- a/core/frontend/frontend.sv +++ b/core/frontend/frontend.sv @@ -129,7 +129,7 @@ module frontend import ariane_pkg::*; #( // the prediction we saved from the previous fetch assign bht_prediction_shifted[0] = (serving_unaligned) ? bht_q : bht_prediction[addr[0][1]]; assign btb_prediction_shifted[0] = (serving_unaligned) ? btb_q : btb_prediction[addr[0][1]]; - + if (ariane_pkg::RVC) begin : gen_btb_prediction_shifted // for all other predictions we can use the generated address to index // into the branch prediction data structures @@ -138,7 +138,7 @@ module frontend import ariane_pkg::*; #( assign btb_prediction_shifted[i] = btb_prediction[addr[i][$clog2(INSTR_PER_FETCH):1]]; end end; - + // for the return address stack it doens't matter as we have the // address of the call/return already logic bp_valid; @@ -361,7 +361,9 @@ module frontend import ariane_pkg::*; #( icache_ex_valid_q <= ariane_pkg::FE_INSTR_PAGE_FAULT; end else if (icache_dreq_i.ex.cause == riscv::INSTR_ACCESS_FAULT) begin icache_ex_valid_q <= ariane_pkg::FE_INSTR_ACCESS_FAULT; - end else icache_ex_valid_q <= ariane_pkg::FE_NONE; + end else begin + icache_ex_valid_q <= ariane_pkg::FE_NONE; + end // save the uppermost prediction btb_q <= btb_prediction[INSTR_PER_FETCH-1]; bht_q <= bht_prediction[INSTR_PER_FETCH-1]; diff --git a/core/id_stage.sv b/core/id_stage.sv index cb80b295d..d91256c0b 100644 --- a/core/id_stage.sv +++ b/core/id_stage.sv @@ -40,11 +40,12 @@ module id_stage ( input logic tsr_i ); // ID/ISSUE register stage - struct packed { + typedef struct packed { logic valid; ariane_pkg::scoreboard_entry_t sbe; logic is_ctrl_flow; - } issue_n, issue_q; + } issue_struct_t; + issue_struct_t issue_n, issue_q; logic is_control_flow_instr; ariane_pkg::scoreboard_entry_t decoded_instruction; diff --git a/core/issue_read_operands.sv b/core/issue_read_operands.sv index 2edfc6b75..d50eeee0a 100644 --- a/core/issue_read_operands.sv +++ b/core/issue_read_operands.sv @@ -212,11 +212,12 @@ module issue_read_operands import ariane_pkg::*; #( operand_b_n = operand_b_regfile; // immediates are the third operands in the store case // for FP operations, the imm field can also be the third operand from the regfile - if (NR_RGPR_PORTS == 3) + if (NR_RGPR_PORTS == 3) begin imm_n = is_imm_fpr(issue_instr_i.op) ? {{riscv::XLEN-FLEN{1'b0}}, operand_c_regfile} : issue_instr_i.op == OFFLOAD ? operand_c_regfile : issue_instr_i.result; - else + end else begin imm_n = is_imm_fpr(issue_instr_i.op) ? {{riscv::XLEN-FLEN{1'b0}}, operand_c_regfile} : issue_instr_i.result; + end trans_id_n = issue_instr_i.trans_id; fu_n = issue_instr_i.fu; operator_n = issue_instr_i.op; @@ -276,12 +277,15 @@ module issue_read_operands import ariane_pkg::*; #( // we do not want to issue this instruction if (!issue_instr_i.ex.valid && issue_instr_valid_i && issue_ack_o) begin case (issue_instr_i.fu) - ALU: + ALU: begin alu_valid_q <= 1'b1; - CTRL_FLOW: + end + CTRL_FLOW: begin branch_valid_q <= 1'b1; - MULT: + end + MULT: begin mult_valid_q <= 1'b1; + end FPU : begin fpu_valid_q <= 1'b1; fpu_fmt_q <= orig_instr.rftype.fmt; // fmt bits from instruction @@ -292,10 +296,12 @@ module issue_read_operands import ariane_pkg::*; #( fpu_fmt_q <= orig_instr.rvftype.vfmt; // vfmt bits from instruction fpu_rm_q <= {2'b0, orig_instr.rvftype.repl}; // repl bit from instruction end - LOAD, STORE: + LOAD, STORE: begin lsu_valid_q <= 1'b1; - CSR: + end + CSR: begin csr_valid_q <= 1'b1; + end default:; endcase end @@ -443,7 +449,7 @@ module issue_read_operands import ariane_pkg::*; #( .raddr_i ( fp_raddr_pack ), .rdata_o ( fprdata ), .waddr_i ( waddr_pack ), - .wdata_i ( wdata_pack ), + .wdata_i ( fp_wdata_pack ), .we_i ( we_fpr_i ), .* ); diff --git a/core/load_store_unit.sv b/core/load_store_unit.sv index 609a09d6b..acda1f44a 100644 --- a/core/load_store_unit.sv +++ b/core/load_store_unit.sv @@ -462,107 +462,3 @@ module load_store_unit import ariane_pkg::*; #( endmodule -// ------------------ -// LSU Control -// ------------------ -// The LSU consists of two independent block which share a common address translation block. -// The one block is the load unit, the other one is the store unit. They will signal their readiness -// with separate signals. If they are not ready the LSU control should keep the last applied signals stable. -// Furthermore it can be the case that another request for one of the two store units arrives in which case -// the LSU control should sample it and store it for later application to the units. It does so, by storing it in a -// two element FIFO. This is necessary as we only know very late in the cycle whether the load/store will succeed (address check, -// TLB hit mainly). So we better unconditionally allow another request to arrive and store this request in case we need to. -module lsu_bypass import ariane_pkg::*; ( - input logic clk_i, - input logic rst_ni, - input logic flush_i, - - input lsu_ctrl_t lsu_req_i, - input logic lsu_req_valid_i, - input logic pop_ld_i, - input logic pop_st_i, - - output lsu_ctrl_t lsu_ctrl_o, - output logic ready_o - ); - - lsu_ctrl_t [1:0] mem_n, mem_q; - logic read_pointer_n, read_pointer_q; - logic write_pointer_n, write_pointer_q; - logic [1:0] status_cnt_n, status_cnt_q; - - logic empty; - assign empty = (status_cnt_q == 0); - assign ready_o = empty; - - always_comb begin - automatic logic [1:0] status_cnt; - automatic logic write_pointer; - automatic logic read_pointer; - - status_cnt = status_cnt_q; - write_pointer = write_pointer_q; - read_pointer = read_pointer_q; - - mem_n = mem_q; - // we've got a valid LSU request - if (lsu_req_valid_i) begin - mem_n[write_pointer_q] = lsu_req_i; - write_pointer++; - status_cnt++; - end - - if (pop_ld_i) begin - // invalidate the result - mem_n[read_pointer_q].valid = 1'b0; - read_pointer++; - status_cnt--; - end - - if (pop_st_i) begin - // invalidate the result - mem_n[read_pointer_q].valid = 1'b0; - read_pointer++; - status_cnt--; - end - - if (pop_st_i && pop_ld_i) - mem_n = '0; - - if (flush_i) begin - status_cnt = '0; - write_pointer = '0; - read_pointer = '0; - mem_n = '0; - end - // default assignments - read_pointer_n = read_pointer; - write_pointer_n = write_pointer; - status_cnt_n = status_cnt; - end - - // output assignment - always_comb begin : output_assignments - if (empty) begin - lsu_ctrl_o = lsu_req_i; - end else begin - lsu_ctrl_o = mem_q[read_pointer_q]; - end - end - - // registers - always_ff @(posedge clk_i or negedge rst_ni) begin - if (~rst_ni) begin - mem_q <= '0; - status_cnt_q <= '0; - write_pointer_q <= '0; - read_pointer_q <= '0; - end else begin - mem_q <= mem_n; - status_cnt_q <= status_cnt_n; - write_pointer_q <= write_pointer_n; - read_pointer_q <= read_pointer_n; - end - end -endmodule - diff --git a/core/lsu_bypass.sv b/core/lsu_bypass.sv new file mode 100644 index 000000000..fd60e4485 --- /dev/null +++ b/core/lsu_bypass.sv @@ -0,0 +1,119 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. +// +// Author: Florian Zaruba, ETH Zurich +// Date: 19.04.2017 +// Description: Load Store Unit, handles address calculation and memory interface signals + + +// ------------------ +// LSU Control +// ------------------ +// The LSU consists of two independent block which share a common address translation block. +// The one block is the load unit, the other one is the store unit. They will signal their readiness +// with separate signals. If they are not ready the LSU control should keep the last applied signals stable. +// Furthermore it can be the case that another request for one of the two store units arrives in which case +// the LSU control should sample it and store it for later application to the units. It does so, by storing it in a +// two element FIFO. This is necessary as we only know very late in the cycle whether the load/store will succeed (address check, +// TLB hit mainly). So we better unconditionally allow another request to arrive and store this request in case we need to. +module lsu_bypass import ariane_pkg::*; ( + input logic clk_i, + input logic rst_ni, + input logic flush_i, + + input lsu_ctrl_t lsu_req_i, + input logic lsu_req_valid_i, + input logic pop_ld_i, + input logic pop_st_i, + + output lsu_ctrl_t lsu_ctrl_o, + output logic ready_o + ); + + lsu_ctrl_t [1:0] mem_n, mem_q; + logic read_pointer_n, read_pointer_q; + logic write_pointer_n, write_pointer_q; + logic [1:0] status_cnt_n, status_cnt_q; + + logic empty; + assign empty = (status_cnt_q == 0); + assign ready_o = empty; + + always_comb begin + automatic logic [1:0] status_cnt; + automatic logic write_pointer; + automatic logic read_pointer; + + status_cnt = status_cnt_q; + write_pointer = write_pointer_q; + read_pointer = read_pointer_q; + + mem_n = mem_q; + // we've got a valid LSU request + if (lsu_req_valid_i) begin + mem_n[write_pointer_q] = lsu_req_i; + write_pointer++; + status_cnt++; + end + + if (pop_ld_i) begin + // invalidate the result + mem_n[read_pointer_q].valid = 1'b0; + read_pointer++; + status_cnt--; + end + + if (pop_st_i) begin + // invalidate the result + mem_n[read_pointer_q].valid = 1'b0; + read_pointer++; + status_cnt--; + end + + if (pop_st_i && pop_ld_i) + mem_n = '0; + + if (flush_i) begin + status_cnt = '0; + write_pointer = '0; + read_pointer = '0; + mem_n = '0; + end + // default assignments + read_pointer_n = read_pointer; + write_pointer_n = write_pointer; + status_cnt_n = status_cnt; + end + + // output assignment + always_comb begin : output_assignments + if (empty) begin + lsu_ctrl_o = lsu_req_i; + end else begin + lsu_ctrl_o = mem_q[read_pointer_q]; + end + end + + // registers + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + mem_q <= '0; + status_cnt_q <= '0; + write_pointer_q <= '0; + read_pointer_q <= '0; + end else begin + mem_q <= mem_n; + status_cnt_q <= status_cnt_n; + write_pointer_q <= write_pointer_n; + read_pointer_q <= read_pointer_n; + end + end +endmodule + diff --git a/core/re_name.sv b/core/re_name.sv index bfcf64453..9e776603a 100644 --- a/core/re_name.sv +++ b/core/re_name.sv @@ -69,9 +69,9 @@ module re_name import ariane_pkg::*; ( issue_instr_o.rs2 = { ENABLE_RENAME & name_bit_rs2, issue_instr_i.rs2[4:0] }; // re-name the third operand in imm if it's actually an operand - if (is_imm_fpr(issue_instr_i.op)) + if (is_imm_fpr(issue_instr_i.op)) begin issue_instr_o.result = { ENABLE_RENAME & name_bit_rs3, issue_instr_i.result[4:0]}; - + end // re-name the destination register issue_instr_o.rd = { ENABLE_RENAME & name_bit_rd, issue_instr_i.rd[4:0] };