OBI protocol between Frontend to icache (#2205)

move cacheable region check from icache to frontend and manage it in OBI protocol
move address translation request from icache to Frontend
This commit is contained in:
Yannick Casamatta 2024-06-06 10:02:31 +00:00 committed by JeanRochCoulon
parent be3b8fc0d4
commit b59a0d1766
16 changed files with 1080 additions and 477 deletions

View file

@ -305,6 +305,7 @@ riscv-benchmarks := $(shell xargs printf '\n%s' < $(riscv-benchmarks-li
incdir := $(CVA6_REPO_DIR)/vendor/pulp-platform/common_cells/include/ $(CVA6_REPO_DIR)/vendor/pulp-platform/axi/include/ \
$(CVA6_REPO_DIR)/corev_apu/register_interface/include/ $(CVA6_REPO_DIR)/corev_apu/tb/common/ \
$(CVA6_REPO_DIR)/vendor/pulp-platform/axi/include/ \
$(CVA6_REPO_DIR)/vendor/pulp-platform/obi/include/ \
$(CVA6_REPO_DIR)/verif/core-v-verif/lib/uvm_agents/uvma_rvfi/ \
$(CVA6_REPO_DIR)/verif/core-v-verif/lib/uvm_components/uvmc_rvfi_reference_model/ \
$(CVA6_REPO_DIR)/verif/core-v-verif/lib/uvm_components/uvmc_rvfi_scoreboard/ \

View file

@ -33,6 +33,7 @@ ${CVA6_REPO_DIR}/vendor/pulp-platform/fpga-support/rtl/SyncThreePortRam.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpga-support/rtl/SyncDpRam_ind_r_w.sv
+incdir+${CVA6_REPO_DIR}/core/include/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/obi/include/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/include/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/axi/include/
@ -59,6 +60,8 @@ ${CVA6_REPO_DIR}/core/cvfpu/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/cvfpu/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/core/cvfpu/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/obi/src/obi_pkg.sv
${CVA6_REPO_DIR}/core/include/config_pkg.sv
${CVA6_REPO_DIR}/core/include/${TARGET_CFG}_config_pkg.sv
${CVA6_REPO_DIR}/core/include/riscv_pkg.sv
@ -83,7 +86,7 @@ ${CVA6_REPO_DIR}/core/cvxif_example/compressed_instr_decoder.sv
${CVA6_REPO_DIR}/core/cvxif_example/copro_alu.sv
// Common Cells
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/fifo_v3.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lfsr.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lfsr_8bit.sv
@ -102,6 +105,16 @@ ${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/exp_backoff.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/counter.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/delta_counter.sv
//OBI
${CVA6_REPO_DIR}/vendor/pulp-platform/obi/src/obi_atop_resolver.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/obi/src/obi_demux.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/obi/src/obi_err_sbr.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/obi/src/obi_intf.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/obi/src/obi_mux.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/obi/src/obi_sram_shim.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/obi/src/obi_xbar.sv
// Top-level source files (not necessarily instantiated at the top of the cva6).
${CVA6_REPO_DIR}/core/cva6.sv
${CVA6_REPO_DIR}/core/cva6_rvfi_probes.sv

View file

@ -17,10 +17,10 @@ module cva6_hpdcache_subsystem
// {{{
#(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
parameter type icache_areq_t = logic,
parameter type icache_arsp_t = logic,
parameter type icache_dreq_t = logic,
parameter type icache_drsp_t = logic,
parameter type fetch_req_t = logic,
parameter type fetch_rsp_t = logic,
parameter type obi_fetch_req_t = logic,
parameter type obi_fetch_rsp_t = logic,
parameter type icache_req_t = logic,
parameter type icache_rtrn_t = logic,
parameter type dcache_req_i_t = logic,
@ -65,14 +65,16 @@ module cva6_hpdcache_subsystem
input logic icache_flush_i,
// instructino cache miss - PERF_COUNTERS
output logic icache_miss_o,
// Input address translation request - EX_STAGE
input icache_areq_t icache_areq_i,
// Output address translation request - EX_STAGE
output icache_arsp_t icache_areq_o,
// Input data translation request - FRONTEND
input icache_dreq_t icache_dreq_i,
// Output data translation request - FRONTEND
output icache_drsp_t icache_dreq_o,
// Access request - FRONTEND
input fetch_req_t fetch_req_i,
// Output Access request - FRONTEND
output fetch_rsp_t fetch_rsp_o,
// OBI Fetch Request channel - FRONTEND
input obi_fetch_req_t obi_fetch_req_i,
// OBI Fetch Response channel - FRONTEND
output obi_fetch_rsp_t obi_fetch_rsp_o,
// }}}
// D$
@ -149,28 +151,28 @@ module cva6_hpdcache_subsystem
cva6_icache #(
.CVA6Cfg(CVA6Cfg),
.icache_areq_t(icache_areq_t),
.icache_arsp_t(icache_arsp_t),
.icache_dreq_t(icache_dreq_t),
.icache_drsp_t(icache_drsp_t),
.fetch_req_t(fetch_req_t),
.fetch_rsp_t(fetch_rsp_t),
.obi_fetch_req_t(obi_fetch_req_t),
.obi_fetch_rsp_t(obi_fetch_rsp_t),
.icache_req_t(icache_req_t),
.icache_rtrn_t(icache_rtrn_t),
.RdTxId(ICACHE_RDTXID)
) i_cva6_icache (
.clk_i (clk_i),
.rst_ni (rst_ni),
.flush_i (icache_flush_i),
.en_i (icache_en_i),
.miss_o (icache_miss_o),
.areq_i (icache_areq_i),
.areq_o (icache_areq_o),
.dreq_i (icache_dreq_i),
.dreq_o (icache_dreq_o),
.mem_rtrn_vld_i(icache_miss_resp_valid),
.mem_rtrn_i (icache_miss_resp),
.mem_data_req_o(icache_miss_valid),
.mem_data_ack_i(icache_miss_ready),
.mem_data_o (icache_miss)
.clk_i (clk_i),
.rst_ni (rst_ni),
.flush_i (icache_flush_i),
.en_i (icache_en_i),
.miss_o (icache_miss_o),
.fetch_req_i (fetch_req_i),
.fetch_rsp_o (fetch_rsp_o),
.obi_fetch_req_i(obi_fetch_req_i),
.obi_fetch_rsp_o(obi_fetch_rsp_o),
.mem_rtrn_vld_i (icache_miss_resp_valid),
.mem_rtrn_i (icache_miss_resp),
.mem_data_req_o (icache_miss_valid),
.mem_data_ack_i (icache_miss_ready),
.mem_data_o (icache_miss)
);
// }}}
@ -428,13 +430,10 @@ module cva6_hpdcache_subsystem
a_invalid_instruction_fetch :
assert property (
@(posedge clk_i) disable iff (!rst_ni) icache_dreq_o.valid |-> (|icache_dreq_o.data) !== 1'hX)
@(posedge clk_i) disable iff (~rst_ni) (obi_fetch_rsp_o.rvalid && obi_fetch_req_i.rready && !fetch_rsp_o.invalid_data) |-> (|obi_fetch_rsp_o.r.rdata) !== 1'hX)
else
$warning(
1,
"[l1 dcache] reading invalid instructions: vaddr=%08X, data=%08X",
icache_dreq_o.vaddr,
icache_dreq_o.data
1, "[l1 icache] FETCH reading invalid instructions: data=%08X", obi_fetch_rsp_o.r.rdata
);
a_invalid_write_data :

View file

@ -23,17 +23,19 @@
//
// 3) NC accesses to I/O space are expected to return 32bit from memory.
//
// Additional contributions by:
// 06.06.2024 - Yannick Casamatta, Thales
// OBI Protocol
module cva6_icache
import ariane_pkg::*;
import wt_cache_pkg::*;
#(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
parameter type icache_areq_t = logic,
parameter type icache_arsp_t = logic,
parameter type icache_dreq_t = logic,
parameter type icache_drsp_t = logic,
parameter type fetch_req_t = logic,
parameter type fetch_rsp_t = logic,
parameter type obi_fetch_req_t = logic,
parameter type obi_fetch_rsp_t = logic,
parameter type icache_req_t = logic,
parameter type icache_rtrn_t = logic,
/// ID to be used for read transactions
@ -43,17 +45,20 @@ module cva6_icache
input logic rst_ni,
/// flush the icache, flush and kill have to be asserted together
input logic flush_i,
input logic flush_i,
/// enable icache
input logic en_i,
input logic en_i,
/// to performance counter
output logic miss_o,
// address translation requests
input icache_areq_t areq_i,
output icache_arsp_t areq_o,
output logic miss_o,
// data requests
input icache_dreq_t dreq_i,
output icache_drsp_t dreq_o,
input fetch_req_t fetch_req_i,
output fetch_rsp_t fetch_rsp_o,
// OBI Fetch Request channel - FRONTEND
input obi_fetch_req_t obi_fetch_req_i,
// OBI Fetch Response channel - FRONTEND
output obi_fetch_rsp_t obi_fetch_rsp_o,
// refill port
input logic mem_rtrn_vld_i,
input icache_rtrn_t mem_rtrn_i,
@ -78,8 +83,9 @@ module cva6_icache
// signals
logic cache_en_d, cache_en_q; // cache is enabled
logic [CVA6Cfg.VLEN-1:0] vaddr_d, vaddr_q;
logic paddr_is_nc; // asserted if physical address is non-cacheable
logic [CVA6Cfg.ICACHE_SET_ASSOC-1:0] cl_hit; // hit from tag compare
logic paddr_is_nc_q, paddr_is_nc_d; // asserted if physical address is non-cacheable
logic [CVA6Cfg.ICACHE_SET_ASSOC-1:0] cl_hit, cl_hit2; // hit from tag compare
logic cache_rden; // triggers cache lookup
logic cache_wren; // triggers write to cacheline
logic
@ -123,31 +129,43 @@ module cva6_icache
FLUSH,
IDLE,
READ,
READ_BIS,
MISS,
KILL_ATRANS,
KILL_MISS
} state_e;
state_e state_d, state_q;
logic obi_valid, obi_grant;
logic [CVA6Cfg.FETCH_WIDTH-1:0] data_d, data_q, obi_rdata;
logic [CVA6Cfg.FETCH_USER_WIDTH-1:0] userdata_d, userdata_q, obi_ruser;
logic data_valid_obi, data_valid_obi_d, data_valid_obi_q;
//OBI
assign obi_fetch_rsp_o.gnt = obi_grant;
assign obi_fetch_rsp_o.gntpar = !obi_grant;
assign obi_fetch_rsp_o.rvalid = obi_valid;
assign obi_fetch_rsp_o.rvalidpar = !obi_valid;
assign obi_fetch_rsp_o.r.rid = '0;
assign obi_fetch_rsp_o.r.r_optional.exokay = '0;
assign obi_fetch_rsp_o.r.r_optional.rchk = '0;
assign obi_fetch_rsp_o.r.err = '0;
assign obi_fetch_rsp_o.r.rdata = obi_rdata;
assign obi_fetch_rsp_o.r.r_optional.ruser = obi_ruser;
///////////////////////////////////////////////////////
// address -> cl_index mapping, interface plumbing
///////////////////////////////////////////////////////
// extract tag from physical address, check if NC
assign cl_tag_d = (areq_i.fetch_valid) ? areq_i.fetch_paddr[CVA6Cfg.ICACHE_TAG_WIDTH+CVA6Cfg.ICACHE_INDEX_WIDTH-1:CVA6Cfg.ICACHE_INDEX_WIDTH] : cl_tag_q;
// noncacheable if request goes to I/O space, or if cache is disabled
assign paddr_is_nc = (~cache_en_q) | (~config_pkg::is_inside_cacheable_regions(
CVA6Cfg, {{64 - CVA6Cfg.PLEN{1'b0}}, cl_tag_d, {CVA6Cfg.ICACHE_INDEX_WIDTH{1'b0}}}
));
// pass exception through
assign dreq_o.ex = areq_i.fetch_exception;
assign cl_tag_d = (obi_fetch_req_i.req && obi_grant) ? obi_fetch_req_i.a.addr[CVA6Cfg.ICACHE_TAG_WIDTH+CVA6Cfg.ICACHE_INDEX_WIDTH-1:CVA6Cfg.ICACHE_INDEX_WIDTH] : cl_tag_q;
// memtype[1] = 1 is cacheable, memtype[1] = 0 is non cacheable
assign paddr_is_nc_d = !cache_en_q || ((obi_fetch_req_i.req && obi_grant) ? !obi_fetch_req_i.a.a_optional.memtype[1] : paddr_is_nc_q);
// latch this in case we have to stall later on
// make sure this is 32bit aligned
assign vaddr_d = (dreq_o.ready & dreq_i.req) ? dreq_i.vaddr : vaddr_q;
assign areq_o.fetch_vaddr = (vaddr_q >> CVA6Cfg.FETCH_ALIGN_BITS) << CVA6Cfg.FETCH_ALIGN_BITS;
assign vaddr_d = (fetch_rsp_o.ready & fetch_req_i.req) ? fetch_req_i.vaddr : vaddr_q;
// split virtual address into index and offset to address cache arrays
assign cl_index = vaddr_d[CVA6Cfg.ICACHE_INDEX_WIDTH-1:ICACHE_OFFSET_WIDTH];
@ -155,40 +173,120 @@ module cva6_icache
if (CVA6Cfg.NOCType == config_pkg::NOC_TYPE_AXI4_ATOP) begin : gen_axi_offset
// if we generate a noncacheable access, the word will be at offset 0 or 4 in the cl coming from memory
assign cl_offset_d = ( dreq_o.ready & dreq_i.req) ? (dreq_i.vaddr >> CVA6Cfg.FETCH_ALIGN_BITS) << CVA6Cfg.FETCH_ALIGN_BITS :
( paddr_is_nc & mem_data_req_o ) ? {{ICACHE_OFFSET_WIDTH-1{1'b0}}, cl_offset_q[2]}<<2 : // needed since we transfer 32bit over a 64bit AXI bus in this case
assign cl_offset_d = ( fetch_rsp_o.ready & fetch_req_i.req) ? (fetch_req_i.vaddr >> CVA6Cfg.FETCH_ALIGN_BITS) << CVA6Cfg.FETCH_ALIGN_BITS :
( paddr_is_nc_d & mem_data_req_o ) ? {{ICACHE_OFFSET_WIDTH-1{1'b0}}, cl_offset_q[2]}<<2 : // needed since we transfer 32bit over a 64bit AXI bus in this case
cl_offset_q;
// request word address instead of cl address in case of NC access
assign mem_data_o.paddr = (paddr_is_nc) ? {cl_tag_d, vaddr_q[CVA6Cfg.ICACHE_INDEX_WIDTH-1:3], 3'b0} : // align to 64bit
assign mem_data_o.paddr = (paddr_is_nc_d) ? {cl_tag_d, vaddr_q[CVA6Cfg.ICACHE_INDEX_WIDTH-1:3], 3'b0} : // align to 64bit
{cl_tag_d, vaddr_q[CVA6Cfg.ICACHE_INDEX_WIDTH-1:ICACHE_OFFSET_WIDTH], {ICACHE_OFFSET_WIDTH{1'b0}}}; // align to cl
end else begin : gen_piton_offset
// icache fills are either cachelines or 4byte fills, depending on whether they go to the Piton I/O space or not.
// since the piton cache system replicates the data, we can always index the full CL
assign cl_offset_d = (dreq_o.ready & dreq_i.req) ? {dreq_i.vaddr >> 2, 2'b0} : cl_offset_q;
assign cl_offset_d = (fetch_rsp_o.ready & fetch_req_i.req) ? {fetch_req_i.vaddr >> 2, 2'b0} : cl_offset_q;
// request word address instead of cl address in case of NC access
assign mem_data_o.paddr = (paddr_is_nc) ? {cl_tag_d, vaddr_q[CVA6Cfg.ICACHE_INDEX_WIDTH-1:2], 2'b0} : // align to 32bit
assign mem_data_o.paddr = (paddr_is_nc_d) ? {cl_tag_d, vaddr_q[CVA6Cfg.ICACHE_INDEX_WIDTH-1:2], 2'b0} : // align to 32bit
{cl_tag_d, vaddr_q[CVA6Cfg.ICACHE_INDEX_WIDTH-1:ICACHE_OFFSET_WIDTH], {ICACHE_OFFSET_WIDTH{1'b0}}}; // align to cl
end
assign mem_data_o.tid = RdTxId;
assign mem_data_o.nc = paddr_is_nc;
assign mem_data_o.nc = paddr_is_nc_d;
// way that is being replaced
assign mem_data_o.way = repl_way;
assign dreq_o.vaddr = vaddr_q;
// invalidations take two cycles
assign inv_d = inv_en;
typedef enum logic [1:0] {
OBI_R_IDLE,
OBI_R_WAIT,
OBI_R_VALID,
OBI_R_KILLED
} obi_r_state_e;
obi_r_state_e obi_r_state_d, obi_r_state_q;
// Common clocked process
always_ff @(posedge clk_i or negedge rst_ni) begin : p_obi
if (!rst_ni) begin
obi_r_state_q <= OBI_R_IDLE;
data_q <= '0;
userdata_q <= '0;
data_valid_obi_q <= '0;
end else begin
obi_r_state_q <= obi_r_state_d;
data_q <= data_d;
userdata_q <= userdata_d;
data_valid_obi_q <= data_valid_obi_d;
end
end
// OBI CHANNEL R protocol FSM (combi)
always_comb begin : p_fsm_obi_r
// default assignment
obi_valid = '0;
fetch_rsp_o.invalid_data = '0;
obi_rdata = data_q;
obi_ruser = userdata_q;
obi_r_state_d = obi_r_state_q;
unique case (obi_r_state_q)
OBI_R_IDLE: begin
if (obi_fetch_req_i.req && obi_grant) begin
if (!(fetch_req_i.kill_req || flush_d)) begin
obi_r_state_d = OBI_R_WAIT;
end else begin
obi_r_state_d = OBI_R_KILLED;
end
end
end
OBI_R_WAIT: begin
if (fetch_req_i.kill_req || flush_d) begin
obi_valid = '1;
fetch_rsp_o.invalid_data = '1;
obi_r_state_d = OBI_R_IDLE;
end else if (data_valid_obi || data_valid_obi_q) begin
obi_valid = '1;
if (data_valid_obi) begin
obi_rdata = data_d;
obi_ruser = userdata_d;
end
obi_ruser = userdata_d;
if (!(obi_fetch_req_i.req && obi_grant)) begin
obi_r_state_d = OBI_R_IDLE;
end
end
end
OBI_R_KILLED: begin
obi_valid = '1;
fetch_rsp_o.invalid_data = '1;
if (obi_fetch_req_i.req && obi_grant) begin
if (!(fetch_req_i.kill_req || flush_d)) begin
obi_r_state_d = OBI_R_WAIT;
end
end else begin
obi_r_state_d = OBI_R_IDLE;
end
end
default: begin
// we should never get here
obi_r_state_d = OBI_R_IDLE;
end
endcase
end
///////////////////////////////////////////////////////
// main control logic
///////////////////////////////////////////////////////
logic addr_ni;
assign addr_ni = config_pkg::is_inside_nonidempotent_regions(
CVA6Cfg, {{64 - CVA6Cfg.PLEN{1'b0}}, areq_i.fetch_paddr}
);
always_comb begin : p_fsm
// default assignment
state_d = state_q;
@ -199,14 +297,14 @@ module cva6_icache
cache_wren = 1'b0;
inv_en = 1'b0;
flush_d = flush_q | flush_i; // register incoming flush
// interfaces
dreq_o.ready = 1'b0;
areq_o.fetch_req = 1'b0;
dreq_o.valid = 1'b0;
fetch_rsp_o.ready = 1'b0;
mem_data_req_o = 1'b0;
// performance counter
miss_o = 1'b0;
obi_grant = 1'b0;
data_valid_obi = '0;
data_valid_obi_d = '0;
// handle invalidations unconditionally
// note: invald are mutually exclusive with
@ -242,16 +340,17 @@ module cva6_icache
end else begin
// mem requests are for sure invals here
if (!mem_rtrn_vld_i) begin
dreq_o.ready = 1'b1;
// we have a new request
if (dreq_i.req) begin
fetch_rsp_o.ready = 1'b1;
// we have a new request not killed
if (obi_fetch_req_i.req && !fetch_req_i.kill_req) begin
cache_rden = 1'b1;
state_d = READ;
state_d = READ_BIS;
obi_grant = 1'b1;
end else if (fetch_req_i.req && !fetch_req_i.kill_req) begin
cache_rden = 1'b1;
state_d = READ;
end
end
if (dreq_i.kill_s1) begin
state_d = IDLE;
end
end
end
//////////////////////////////////
@ -261,38 +360,37 @@ module cva6_icache
// reuse the miss mechanism to handle
// the request
READ: begin
areq_o.fetch_req = '1;
// only enable tag comparison if cache is enabled
cmp_en_d = cache_en_q;
cmp_en_d = cache_en_q;
// readout speculatively
cache_rden = cache_en_q;
cache_rden = cache_en_q;
if (obi_fetch_req_i.req) begin
state_d = READ_BIS;
obi_grant = 1'b1;
if (areq_i.fetch_valid && (!dreq_i.spec || ((CVA6Cfg.NonIdemPotenceEn && !addr_ni) || (!CVA6Cfg.NonIdemPotenceEn)))) begin
// check if we have to flush
if (flush_d) begin
state_d = IDLE;
// we have a hit or an exception output valid result
end else if (((|cl_hit && cache_en_q) || areq_i.fetch_exception.valid) && !inv_q) begin
dreq_o.valid = ~dreq_i.kill_s2; // just don't output in this case
state_d = IDLE;
// we can accept another request
// and stay here, but only if no inval is coming in
// note: we are not expecting ifill return packets here...
// we have an exception
end else if (fetch_req_i.kill_req) begin
state_d = IDLE;
if (!mem_rtrn_vld_i) begin
dreq_o.ready = 1'b1;
if (dreq_i.req) begin
fetch_rsp_o.ready = 1'b1;
if (fetch_req_i.req) begin
state_d = READ;
end
end
// if a request is being killed at this stage,
// we have to bail out and wait for the address translation to complete
if (dreq_i.kill_s1) begin
state_d = IDLE;
end
// we have a miss / NC transaction
end else if (dreq_i.kill_s2) begin
// we have a hit
end else if (|cl_hit && cache_en_q && !inv_q) begin
data_valid_obi_d = '1;
state_d = IDLE;
if (!mem_rtrn_vld_i) begin
fetch_rsp_o.ready = 1'b1;
if (fetch_req_i.req) begin
state_d = READ;
end
end
end else if (!inv_q) begin
cmp_en_d = 1'b0;
// only count this as a miss if the cache is enabled, and
@ -300,15 +398,80 @@ module cva6_icache
// send out ifill request
mem_data_req_o = 1'b1;
if (mem_data_ack_i) begin
miss_o = ~paddr_is_nc;
miss_o = ~paddr_is_nc_d;
state_d = MISS;
end
end
// bail out if this request is being killed (and we missed on the TLB)
end else if (dreq_i.kill_s2 || flush_d) begin
state_d = KILL_ATRANS;
end else if (flush_d) begin
state_d = IDLE;
end else if (fetch_req_i.kill_req) begin
state_d = IDLE;
// we can accept another request
// and stay here, but only if no inval is coming in
// note: we are not expecting ifill return packets here...
if (!mem_rtrn_vld_i) begin
fetch_rsp_o.ready = 1'b1;
if (fetch_req_i.req) begin
state_d = READ;
end
end
end else if (fetch_req_i.req) begin
//abort previous index and launch new one
state_d = IDLE;
if (!mem_rtrn_vld_i) begin
cache_rden = 1'b1;
fetch_rsp_o.ready = 1'b1;
state_d = READ;
end
end
end
READ_BIS: begin
// only enable tag comparison if cache is enabled
cmp_en_d = cache_en_q;
// readout speculatively
cache_rden = cache_en_q;
// check if we have to flush
if (flush_d) begin
state_d = IDLE;
end else if (fetch_req_i.kill_req) begin
state_d = IDLE;
if (!mem_rtrn_vld_i) begin
fetch_rsp_o.ready = 1'b1;
if (fetch_req_i.req) begin
state_d = READ;
end
end
// we have a hit
end else if ((|cl_hit2 && cache_en_q && !inv_q)) begin
state_d = IDLE;
data_valid_obi = 1'b1;
// we can accept another request
// and stay here, but only if no inval is coming in
// note: we are not expecting ifill return packets here...
if (!mem_rtrn_vld_i) begin
fetch_rsp_o.ready = 1'b1;
if (fetch_req_i.req) begin
state_d = READ;
end
end
end else if (!inv_q) begin
cmp_en_d = 1'b0;
// only count this as a miss if the cache is enabled, and
// the address is cacheable
// send out ifill request
mem_data_req_o = 1'b1;
if (mem_data_ack_i) begin
miss_o = ~paddr_is_nc_d;
state_d = MISS;
end
end
end
//////////////////////////////////
// wait until the memory transaction
// returns. do not write to memory
@ -319,27 +482,17 @@ module cva6_icache
if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_IFILL_ACK) begin
state_d = IDLE;
// only return data if request is not being killed
if (!(dreq_i.kill_s2 || flush_d)) begin
dreq_o.valid = 1'b1;
if (!(fetch_req_i.kill_req || flush_d)) begin
// only write to cache if this address is cacheable
cache_wren = ~paddr_is_nc;
cache_wren = ~paddr_is_nc_d;
data_valid_obi = '1;
end
// bail out if this request is being killed
end else if (dreq_i.kill_s2 || flush_d) begin
end else if (fetch_req_i.kill_req || flush_d) begin
state_d = KILL_MISS;
end
end
//////////////////////////////////
// killed address translation,
// wait until paddr is valid, and go
// back to idle
KILL_ATRANS: begin
areq_o.fetch_req = '1;
if (areq_i.fetch_valid) begin
state_d = IDLE;
end
end
//////////////////////////////////
// killed miss,
// wait until memory responds and
// go back to idle
@ -348,6 +501,7 @@ module cva6_icache
state_d = IDLE;
end
end
default: begin
// we should never get here
state_d = FLUSH;
@ -425,6 +579,7 @@ module cva6_icache
for (genvar i = 0; i < CVA6Cfg.ICACHE_SET_ASSOC; i++) begin : gen_tag_cmpsel
assign cl_hit[i] = (cl_tag_rdata[i] == cl_tag_d) & vld_rdata[i];
assign cl_hit2[i] = (cl_tag_rdata[i] == cl_tag_q) & vld_rdata[i];
assign cl_sel[i] = cl_rdata[i][{cl_offset_q, 3'b0}+:CVA6Cfg.FETCH_WIDTH];
assign cl_user[i] = cl_ruser[i][{cl_offset_q, 3'b0}+:CVA6Cfg.FETCH_USER_WIDTH];
end
@ -440,11 +595,11 @@ module cva6_icache
always_comb begin
if (cmp_en_q) begin
dreq_o.data = cl_sel[hit_idx];
dreq_o.user = cl_user[hit_idx];
data_d = cl_sel[hit_idx];
userdata_d = cl_user[hit_idx];
end else begin
dreq_o.data = mem_rtrn_i.data[{cl_offset_q, 3'b0}+:CVA6Cfg.FETCH_WIDTH];
dreq_o.user = mem_rtrn_i.user[{cl_offset_q, 3'b0}+:CVA6Cfg.FETCH_USER_WIDTH];
data_d = mem_rtrn_i.data[{cl_offset_q, 3'b0}+:CVA6Cfg.FETCH_WIDTH];
userdata_d = mem_rtrn_i.user[{cl_offset_q, 3'b0}+:CVA6Cfg.FETCH_USER_WIDTH];
end
end
@ -516,6 +671,7 @@ module cva6_icache
cl_offset_q <= '0;
repl_way_oh_q <= '0;
inv_q <= '0;
paddr_is_nc_q <= '0;
end else begin
cl_tag_q <= cl_tag_d;
flush_cnt_q <= flush_cnt_d;
@ -527,6 +683,7 @@ module cva6_icache
cl_offset_q <= cl_offset_d;
repl_way_oh_q <= repl_way_oh_d;
inv_q <= inv_d;
paddr_is_nc_q <= paddr_is_nc_d;
end
end
@ -548,7 +705,7 @@ module cva6_icache
invalid_state :
assert property (
@(posedge clk_i) disable iff (!rst_ni) (state_q inside {FLUSH, IDLE, READ, MISS, KILL_ATRANS, KILL_MISS}))
@(posedge clk_i) disable iff (!rst_ni) (state_q inside {FLUSH, IDLE, READ, READ_BIS, MISS, KILL_MISS}))
else $fatal(1, "[l1 icache] fsm reached an invalid state");
hot1 :

View file

@ -18,10 +18,10 @@ module cva6_icache_axi_wrapper
import wt_cache_pkg::*;
#(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
parameter type icache_areq_t = logic,
parameter type icache_arsp_t = logic,
parameter type icache_dreq_t = logic,
parameter type icache_drsp_t = logic,
parameter type fetch_dreq_t = logic,
parameter type fetch_drsp_t = logic,
parameter type obi_fetch_req_t = logic,
parameter type obi_fetch_rsp_t = logic,
parameter type icache_req_t = logic,
parameter type icache_rtrn_t = logic,
parameter type axi_req_t = logic,
@ -34,15 +34,19 @@ module cva6_icache_axi_wrapper
input logic flush_i, // flush the icache, flush and kill have to be asserted together
input logic en_i, // enable icache
output logic miss_o, // to performance counter
// address translation requests
input icache_areq_t areq_i,
output icache_arsp_t areq_o,
// data requests
input icache_dreq_t dreq_i,
output icache_drsp_t dreq_o,
input fetch_dreq_t dreq_i,
output fetch_drsp_t dreq_o,
// OBI Fetch Request channel - FRONTEND
input obi_fetch_req_t fetch_obi_req_i,
// OBI Fetch Response channel - FRONTEND
output obi_fetch_rsp_t fetch_obi_rsp_o,
// AXI refill port
output axi_req_t axi_req_o,
input axi_rsp_t axi_resp_i
input axi_rsp_t axi_resp_i
);
localparam AxiNumWords = (CVA6Cfg.ICACHE_LINE_WIDTH/CVA6Cfg.AxiDataWidth) * (CVA6Cfg.ICACHE_LINE_WIDTH > CVA6Cfg.DCACHE_LINE_WIDTH) +
@ -108,28 +112,28 @@ module cva6_icache_axi_wrapper
cva6_icache #(
// use ID 0 for icache reads
.CVA6Cfg(CVA6Cfg),
.icache_areq_t(icache_areq_t),
.icache_arsp_t(icache_arsp_t),
.icache_dreq_t(icache_dreq_t),
.icache_drsp_t(icache_drsp_t),
.fetch_dreq_t(fetch_dreq_t),
.fetch_drsp_t(fetch_drsp_t),
.obi_fetch_req_t(obi_fetch_req_t),
.obi_fetch_rsp_t(obi_fetch_rsp_t),
.icache_req_t(icache_req_t),
.icache_rtrn_t(icache_rtrn_t),
.RdTxId(0)
) i_cva6_icache (
.clk_i (clk_i),
.rst_ni (rst_ni),
.flush_i (flush_i),
.en_i (en_i),
.miss_o (miss_o),
.areq_i (areq_i),
.areq_o (areq_o),
.dreq_i (dreq_i),
.dreq_o (dreq_o),
.mem_rtrn_vld_i(icache_mem_rtrn_vld),
.mem_rtrn_i (icache_mem_rtrn),
.mem_data_req_o(icache_mem_data_req),
.mem_data_ack_i(icache_mem_data_ack),
.mem_data_o (icache_mem_data)
.clk_i (clk_i),
.rst_ni (rst_ni),
.flush_i (flush_i),
.en_i (en_i),
.miss_o (miss_o),
.dreq_i (dreq_i),
.dreq_o (dreq_o),
.fetch_obi_req_i(fetch_obi_req_i),
.fetch_obi_rsp_o(fetch_obi_rsp_o),
.mem_rtrn_vld_i (icache_mem_rtrn_vld),
.mem_rtrn_i (icache_mem_rtrn),
.mem_data_req_o (icache_mem_data_req),
.mem_data_ack_i (icache_mem_data_ack),
.mem_data_o (icache_mem_data)
);
// --------

View file

@ -20,10 +20,10 @@ module std_cache_subsystem
import std_cache_pkg::*;
#(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
parameter type icache_areq_t = logic,
parameter type icache_arsp_t = logic,
parameter type icache_dreq_t = logic,
parameter type icache_drsp_t = logic,
parameter type fetch_dreq_t = logic,
parameter type fetch_drsp_t = logic,
parameter type obi_fetch_req_t = logic,
parameter type obi_fetch_rsp_t = logic,
parameter type icache_req_t = logic,
parameter type icache_rtrn_t = logic,
parameter type dcache_req_i_t = logic,
@ -42,12 +42,15 @@ module std_cache_subsystem
input logic icache_en_i, // enable icache (or bypass e.g: in debug mode)
input logic icache_flush_i, // flush the icache, flush and kill have to be asserted together
output logic icache_miss_o, // to performance counter
// address translation requests
input icache_areq_t icache_areq_i, // to/from frontend
output icache_arsp_t icache_areq_o,
// data requests
input icache_dreq_t icache_dreq_i, // to/from frontend
output icache_drsp_t icache_dreq_o,
input fetch_dreq_t fetch_dreq_i, // to/from frontend
output fetch_drsp_t fetch_dreq_o,
// OBI Fetch Request channel - FRONTEND
input obi_fetch_req_t fetch_obi_req_i,
// OBI Fetch Response channel - FRONTEND
output obi_fetch_rsp_t fetch_obi_rsp_o,
// AMOs
input amo_req_t amo_req_i,
output amo_resp_t amo_resp_o,
@ -77,27 +80,27 @@ module std_cache_subsystem
cva6_icache_axi_wrapper #(
.CVA6Cfg(CVA6Cfg),
.icache_areq_t(icache_areq_t),
.icache_arsp_t(icache_arsp_t),
.icache_dreq_t(icache_dreq_t),
.icache_drsp_t(icache_drsp_t),
.fetch_dreq_t(fetch_dreq_t),
.fetch_drsp_t(fetch_drsp_t),
.obi_fetch_req_t(obi_fetch_req_t),
.obi_fetch_rsp_t(obi_fetch_rsp_t),
.icache_req_t(icache_req_t),
.icache_rtrn_t(icache_rtrn_t),
.axi_req_t(axi_req_t),
.axi_rsp_t(axi_rsp_t)
) i_cva6_icache_axi_wrapper (
.clk_i (clk_i),
.rst_ni (rst_ni),
.priv_lvl_i(priv_lvl_i),
.flush_i (icache_flush_i),
.en_i (icache_en_i),
.miss_o (icache_miss_o),
.areq_i (icache_areq_i),
.areq_o (icache_areq_o),
.dreq_i (icache_dreq_i),
.dreq_o (icache_dreq_o),
.axi_req_o (axi_req_icache),
.axi_resp_i(axi_resp_icache)
.clk_i (clk_i),
.rst_ni (rst_ni),
.priv_lvl_i (priv_lvl_i),
.flush_i (icache_flush_i),
.en_i (icache_en_i),
.miss_o (icache_miss_o),
.dreq_i (fetch_dreq_i),
.dreq_o (fetch_dreq_o),
.fetch_obi_req_i(fetch_obi_req_i),
.fetch_obi_rsp_o(fetch_obi_rsp_o),
.axi_req_o (axi_req_icache),
.axi_resp_i (axi_resp_icache)
);
// decreasing priority
@ -301,13 +304,13 @@ module std_cache_subsystem
a_invalid_instruction_fetch :
assert property (
@(posedge clk_i) disable iff (~rst_ni) icache_dreq_o.valid |-> (|icache_dreq_o.data) !== 1'hX)
@(posedge clk_i) disable iff (~rst_ni) (fetch_obi_rsp_o.rvalid && !fetch_dreq_o.invalid_data) |-> (|fetch_obi_rsp_o.r.rdata) !== 1'hX)
else
$warning(
1,
"[l1 dcache] reading invalid instructions: vaddr=%08X, data=%08X",
icache_dreq_o.vaddr,
icache_dreq_o.data
fetch_dreq_i.vaddr,
fetch_obi_rsp_o.r.rdata
);
a_invalid_write_data :

View file

@ -23,18 +23,18 @@ module wt_cache_subsystem
import ariane_pkg::*;
import wt_cache_pkg::*;
#(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
parameter type icache_areq_t = logic,
parameter type icache_arsp_t = logic,
parameter type icache_dreq_t = logic,
parameter type icache_drsp_t = logic,
parameter type dcache_req_i_t = logic,
parameter type dcache_req_o_t = logic,
parameter type icache_req_t = logic,
parameter type icache_rtrn_t = logic,
parameter int unsigned NumPorts = 4,
parameter type noc_req_t = logic,
parameter type noc_resp_t = logic
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
parameter type fetch_dreq_t = logic,
parameter type fetch_drsp_t = logic,
parameter type obi_fetch_req_t = logic,
parameter type obi_fetch_rsp_t = logic,
parameter type dcache_req_i_t = logic,
parameter type dcache_req_o_t = logic,
parameter type icache_req_t = logic,
parameter type icache_rtrn_t = logic,
parameter int unsigned NumPorts = 4,
parameter type noc_req_t = logic,
parameter type noc_resp_t = logic
) (
input logic clk_i,
input logic rst_ni,
@ -42,12 +42,15 @@ module wt_cache_subsystem
input logic icache_en_i, // enable icache (or bypass e.g: in debug mode)
input logic icache_flush_i, // flush the icache, flush and kill have to be asserted together
output logic icache_miss_o, // to performance counter
// address translation requests
input icache_areq_t icache_areq_i, // to/from frontend
output icache_arsp_t icache_areq_o,
// data requests
input icache_dreq_t icache_dreq_i, // to/from frontend
output icache_drsp_t icache_dreq_o,
input fetch_dreq_t fetch_dreq_i, // to/from frontend
output fetch_drsp_t fetch_dreq_o,
// OBI Fetch Request channel - FRONTEND
input obi_fetch_req_t fetch_obi_req_i,
// OBI Fetch Response channel - FRONTEND
output obi_fetch_rsp_t fetch_obi_rsp_o,
// D$
// Cache management
input logic dcache_enable_i, // from CSR
@ -115,28 +118,28 @@ module wt_cache_subsystem
cva6_icache #(
// use ID 0 for icache reads
.CVA6Cfg(CVA6Cfg),
.icache_areq_t(icache_areq_t),
.icache_arsp_t(icache_arsp_t),
.icache_dreq_t(icache_dreq_t),
.icache_drsp_t(icache_drsp_t),
.fetch_dreq_t(fetch_dreq_t),
.fetch_drsp_t(fetch_drsp_t),
.obi_fetch_req_t(obi_fetch_req_t),
.obi_fetch_rsp_t(obi_fetch_rsp_t),
.icache_req_t(icache_req_t),
.icache_rtrn_t(icache_rtrn_t),
.RdTxId(0)
) i_cva6_icache (
.clk_i (clk_i),
.rst_ni (rst_ni),
.flush_i (icache_flush_i),
.en_i (icache_en_i),
.miss_o (icache_miss_o),
.areq_i (icache_areq_i),
.areq_o (icache_areq_o),
.dreq_i (icache_dreq_i),
.dreq_o (icache_dreq_o),
.mem_rtrn_vld_i(adapter_icache_rtrn_vld),
.mem_rtrn_i (adapter_icache),
.mem_data_req_o(icache_adapter_data_req),
.mem_data_ack_i(adapter_icache_data_ack),
.mem_data_o (icache_adapter)
.clk_i (clk_i),
.rst_ni (rst_ni),
.flush_i (icache_flush_i),
.en_i (icache_en_i),
.miss_o (icache_miss_o),
.dreq_i (fetch_dreq_i),
.dreq_o (fetch_dreq_o),
.fetch_obi_req_i(fetch_obi_req_i),
.fetch_obi_rsp_o(fetch_obi_rsp_o),
.mem_rtrn_vld_i (adapter_icache_rtrn_vld),
.mem_rtrn_i (adapter_icache),
.mem_data_req_o (icache_adapter_data_req),
.mem_data_ack_i (adapter_icache_data_ack),
.mem_data_o (icache_adapter)
);
@ -242,13 +245,13 @@ module wt_cache_subsystem
`ifndef VERILATOR
a_invalid_instruction_fetch :
assert property (
@(posedge clk_i) disable iff (!rst_ni) icache_dreq_o.valid |-> (|icache_dreq_o.data) !== 1'hX)
@(posedge clk_i) disable iff (~rst_ni) (fetch_obi_rsp_o.rvalid && !fetch_dreq_o.invalid_data) |-> (|fetch_obi_rsp_o.r.rdata) !== 1'hX)
else
$warning(
1,
"[l1 dcache] reading invalid instructions: vaddr=%08X, data=%08X",
icache_dreq_o.vaddr,
icache_dreq_o.data
fetch_dreq_i.vaddr,
fetch_obi_rsp_o.r.rdata
);
for (genvar j = 0; j < CVA6Cfg.XLEN / 8; j++) begin : gen_invalid_write_assertion

View file

@ -12,6 +12,8 @@
// Date: 19.03.2017
// Description: CVA6 Top-level module
`include "obi/typedef.svh"
`include "obi/assign.svh"
`include "rvfi_types.svh"
`include "cvxif_types.svh"
@ -51,31 +53,25 @@ module cva6
// cache request ports
// I$ address translation requests
localparam type icache_areq_t = struct packed {
logic fetch_valid; // address translation valid
logic [CVA6Cfg.PLEN-1:0] fetch_paddr; // physical address in
exception_t fetch_exception; // exception occurred during fetch
},
localparam type icache_arsp_t = struct packed {
localparam type fetch_areq_t = struct packed {
logic fetch_req; // address translation request
logic [CVA6Cfg.VLEN-1:0] fetch_vaddr; // virtual address out
},
localparam type fetch_arsp_t = struct packed {
exception_t fetch_exception; // exception occurred during fetch
logic fetch_valid; // address translation valid
logic [CVA6Cfg.PLEN-1:0] fetch_paddr; // physical address in
},
// I$ data requests
localparam type icache_dreq_t = struct packed {
logic req; // we request a new word
logic kill_s1; // kill the current request
logic kill_s2; // kill the last request
logic spec; // request is speculative
logic [CVA6Cfg.VLEN-1:0] vaddr; // 1st cycle: 12 bit index is taken for lookup
localparam type fetch_req_t = struct packed {
logic req; // we request a new word
logic kill_req; // kill the last request
logic [CVA6Cfg.VLEN-1:0] vaddr; // 1st cycle: 12 bit index is taken for lookup
},
localparam type icache_drsp_t = struct packed {
logic ready; // icache is ready
logic valid; // signals a valid read
logic [CVA6Cfg.FETCH_WIDTH-1:0] data; // 2+ cycle out: tag
logic [CVA6Cfg.FETCH_USER_WIDTH-1:0] user; // User bits
logic [CVA6Cfg.VLEN-1:0] vaddr; // virtual address out
exception_t ex; // we've encountered an exception
localparam type fetch_rsp_t = struct packed {
logic ready; // fetch is ready
logic invalid_data; // obi data is invalid caused by aborted request kill_req, use for debug
},
// IF/ID Stage
@ -330,6 +326,11 @@ module cva6
input noc_resp_t noc_resp_i
);
//OBI FETCH
`OBI_TYPEDEF_ALL(obi_fetch, CVA6Cfg.ObiFetchbusCfg)
//OBI DATA
`OBI_TYPEDEF_ALL(obi_data, CVA6Cfg.ObiDatabusCfg)
localparam type interrupts_t = struct packed {
logic [CVA6Cfg.XLEN-1:0] S_SW;
logic [CVA6Cfg.XLEN-1:0] VS_SW;
@ -614,10 +615,14 @@ module cva6
logic flush_commit;
logic flush_acc;
icache_areq_t icache_areq_ex_cache;
icache_arsp_t icache_areq_cache_ex;
icache_dreq_t icache_dreq_if_cache;
icache_drsp_t icache_dreq_cache_if;
fetch_arsp_t fetch_arsp_ex_frontend;
fetch_areq_t fetch_areq_frontend_ex;
fetch_req_t fetch_req_if_cache;
fetch_rsp_t fetch_rsp_cache_if;
// OBI
obi_fetch_req_t obi_fetch_req_if_cache;
obi_fetch_rsp_t obi_fetch_rsp_cache_if;
amo_req_t amo_req;
amo_resp_t amo_resp;
@ -653,8 +658,12 @@ module cva6
.CVA6Cfg(CVA6Cfg),
.bp_resolve_t(bp_resolve_t),
.fetch_entry_t(fetch_entry_t),
.icache_dreq_t(icache_dreq_t),
.icache_drsp_t(icache_drsp_t)
.fetch_areq_t(fetch_areq_t),
.fetch_arsp_t(fetch_arsp_t),
.fetch_req_t(fetch_req_t),
.fetch_rsp_t(fetch_rsp_t),
.obi_fetch_req_t(obi_fetch_req_t),
.obi_fetch_rsp_t(obi_fetch_rsp_t)
) i_frontend (
.clk_i,
.rst_ni,
@ -671,8 +680,12 @@ module cva6
.trap_vector_base_i (trap_vector_base_commit_pcgen),
.set_debug_pc_i (set_debug_pc),
.debug_mode_i (debug_mode),
.icache_dreq_o (icache_dreq_if_cache),
.icache_dreq_i (icache_dreq_cache_if),
.areq_o (fetch_areq_frontend_ex),
.arsp_i (fetch_arsp_ex_frontend),
.fetch_req_o (fetch_req_if_cache),
.fetch_rsp_i (fetch_rsp_cache_if),
.obi_fetch_req_o (obi_fetch_req_if_cache), //OBI
.obi_fetch_rsp_i (obi_fetch_rsp_cache_if), //OBI
.fetch_entry_o (fetch_entry_if_id),
.fetch_entry_valid_o(fetch_valid_if_id),
.fetch_entry_ready_i(fetch_ready_id_if)
@ -916,10 +929,8 @@ module cva6
.dcache_req_o_t(dcache_req_o_t),
.exception_t(exception_t),
.fu_data_t(fu_data_t),
.icache_areq_t(icache_areq_t),
.icache_arsp_t(icache_arsp_t),
.icache_dreq_t(icache_dreq_t),
.icache_drsp_t(icache_drsp_t),
.fetch_areq_t(fetch_areq_t),
.fetch_arsp_t(fetch_arsp_t),
.lsu_ctrl_t(lsu_ctrl_t),
.x_result_t(x_result_t)
) ex_stage_i (
@ -1030,8 +1041,8 @@ module cva6
.vs_asid_i (vs_asid_csr_ex), // from CSR
.hgatp_ppn_i (hgatp_ppn_csr_ex), // from CSR
.vmid_i (vmid_csr_ex), // from CSR
.icache_areq_i (icache_areq_cache_ex),
.icache_areq_o (icache_areq_ex_cache),
.fetch_areq_i (fetch_areq_frontend_ex),
.fetch_arsp_o (fetch_arsp_ex_frontend),
// DCACHE interfaces
.dcache_req_ports_i (dcache_req_ports_cache_ex),
.dcache_req_ports_o (dcache_req_ports_ex_cache),
@ -1193,7 +1204,8 @@ module cva6
.bp_resolve_t(bp_resolve_t),
.exception_t(exception_t),
.scoreboard_entry_t(scoreboard_entry_t),
.icache_dreq_t(icache_dreq_t),
.fetch_req_t(fetch_req_t),
.obi_fetch_req_t(fetch_req_t),
.dcache_req_i_t(dcache_req_i_t),
.dcache_req_o_t(dcache_req_o_t),
.NumPorts(NumPorts)
@ -1220,9 +1232,11 @@ module cva6
.eret_i (eret),
.resolved_branch_i (resolved_branch),
.branch_exceptions_i(flu_exception_ex_id),
.l1_icache_access_i (icache_dreq_if_cache),
.l1_fetch_access_i (fetch_dreq_if_cache),
.l1_dcache_access_i (dcache_req_ports_ex_cache),
.miss_vld_bits_i (miss_vld_bits),
.fetch_req_i (fetch_req_if_cache),
.fetch_obi_req_i (obi_fetch_req_if_cache),
.i_tlb_flush_i (flush_tlb_ctrl_ex),
.stall_issue_i (stall_issue),
.mcountinhibit_i (mcountinhibit_csr_perf)
@ -1321,11 +1335,11 @@ module cva6
// this is a cache subsystem that is compatible with OpenPiton
wt_cache_subsystem #(
.CVA6Cfg (CVA6Cfg),
.icache_areq_t(icache_areq_t),
.icache_arsp_t(icache_arsp_t),
.icache_dreq_t(icache_dreq_t),
.icache_drsp_t(icache_drsp_t),
.fetch_dreq_t(fetch_dreq_t),
.fetch_drsp_t(fetch_drsp_t),
.icache_req_t(icache_req_t),
.obi_fetch_req_t(obi_fetch_req_t),
.obi_fetch_rsp_t(obi_fetch_rsp_t),
.icache_rtrn_t(icache_rtrn_t),
.dcache_req_i_t(dcache_req_i_t),
.dcache_req_o_t(dcache_req_o_t),
@ -1340,10 +1354,10 @@ module cva6
.icache_en_i (icache_en_csr),
.icache_flush_i (icache_flush_ctrl_cache),
.icache_miss_o (icache_miss_cache_perf),
.icache_areq_i (icache_areq_ex_cache),
.icache_areq_o (icache_areq_cache_ex),
.icache_dreq_i (icache_dreq_if_cache),
.icache_dreq_o (icache_dreq_cache_if),
.fetch_dreq_i (fetch_dreq_if_cache),
.fetch_dreq_o (fetch_dreq_cache_if),
.fetch_obi_req_i (obi_fetch_req_if_cache), //OBI
.fetch_obi_rsp_o (obi_fetch_rsp_cache_if), //OBI
// D$
.dcache_enable_i (dcache_en_csr_nbdcache),
.dcache_flush_i (dcache_flush_ctrl_cache),
@ -1373,14 +1387,14 @@ module cva6
begin : gen_cache_hpd
cva6_hpdcache_subsystem #(
.CVA6Cfg (CVA6Cfg),
.icache_areq_t(icache_areq_t),
.icache_arsp_t(icache_arsp_t),
.icache_dreq_t(icache_dreq_t),
.icache_drsp_t(icache_drsp_t),
.fetch_req_t(fetch_req_t),
.fetch_rsp_t(fetch_rsp_t),
.icache_req_t(icache_req_t),
.icache_rtrn_t(icache_rtrn_t),
.dcache_req_i_t(dcache_req_i_t),
.dcache_req_o_t(dcache_req_o_t),
.obi_fetch_req_t(obi_fetch_req_t),
.obi_fetch_rsp_t(obi_fetch_rsp_t),
.NumPorts (NumPorts),
.axi_ar_chan_t(axi_ar_chan_t),
.axi_aw_chan_t(axi_aw_chan_t),
@ -1398,10 +1412,10 @@ module cva6
.icache_en_i (icache_en_csr),
.icache_flush_i(icache_flush_ctrl_cache),
.icache_miss_o (icache_miss_cache_perf),
.icache_areq_i (icache_areq_ex_cache),
.icache_areq_o (icache_areq_cache_ex),
.icache_dreq_i (icache_dreq_if_cache),
.icache_dreq_o (icache_dreq_cache_if),
.fetch_req_i (fetch_req_if_cache),
.fetch_rsp_o (fetch_rsp_cache_if),
.obi_fetch_req_i (obi_fetch_req_if_cache), //OBI
.obi_fetch_rsp_o (obi_fetch_rsp_cache_if), //OBI
.dcache_enable_i (dcache_en_csr_nbdcache),
.dcache_flush_i (dcache_flush_ctrl_cache),
@ -1440,21 +1454,21 @@ module cva6
// note: this only works with one cacheable region
// not as important since this cache subsystem is about to be
// deprecated
.CVA6Cfg (CVA6Cfg),
.icache_areq_t (icache_areq_t),
.icache_arsp_t (icache_arsp_t),
.icache_dreq_t (icache_dreq_t),
.icache_drsp_t (icache_drsp_t),
.icache_req_t (icache_req_t),
.icache_rtrn_t (icache_rtrn_t),
.dcache_req_i_t(dcache_req_i_t),
.dcache_req_o_t(dcache_req_o_t),
.NumPorts (NumPorts),
.axi_ar_chan_t (axi_ar_chan_t),
.axi_aw_chan_t (axi_aw_chan_t),
.axi_w_chan_t (axi_w_chan_t),
.axi_req_t (noc_req_t),
.axi_rsp_t (noc_resp_t)
.CVA6Cfg (CVA6Cfg),
.fetch_dreq_t (fetch_dreq_t),
.fetch_drsp_t (fetch_drsp_t),
.icache_req_t (icache_req_t),
.icache_rtrn_t (icache_rtrn_t),
.obi_fetch_req_t(obi_fetch_req_t),
.obi_fetch_rsp_t(obi_fetch_rsp_t),
.dcache_req_i_t (dcache_req_i_t),
.dcache_req_o_t (dcache_req_o_t),
.NumPorts (NumPorts),
.axi_ar_chan_t (axi_ar_chan_t),
.axi_aw_chan_t (axi_aw_chan_t),
.axi_w_chan_t (axi_w_chan_t),
.axi_req_t (noc_req_t),
.axi_rsp_t (noc_resp_t)
) i_cache_subsystem (
// to D$
.clk_i (clk_i),
@ -1464,10 +1478,10 @@ module cva6
.icache_en_i (icache_en_csr),
.icache_flush_i (icache_flush_ctrl_cache),
.icache_miss_o (icache_miss_cache_perf),
.icache_areq_i (icache_areq_ex_cache),
.icache_areq_o (icache_areq_cache_ex),
.icache_dreq_i (icache_dreq_if_cache),
.icache_dreq_o (icache_dreq_cache_if),
.fetch_dreq_i (fetch_dreq_if_cache),
.fetch_dreq_o (fetch_dreq_cache_if),
.fetch_obi_req_i (obi_fetch_req_if_cache), //OBI
.fetch_obi_rsp_o (obi_fetch_rsp_cache_if), //OBI
// D$
.dcache_enable_i (dcache_en_csr_nbdcache),
.dcache_flush_i (dcache_flush_ctrl_cache),

View file

@ -26,10 +26,8 @@ module cva6_mmu
import ariane_pkg::*;
#(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
parameter type icache_areq_t = logic,
parameter type icache_arsp_t = logic,
parameter type icache_dreq_t = logic,
parameter type icache_drsp_t = logic,
parameter type fetch_areq_t = logic,
parameter type fetch_arsp_t = logic,
parameter type dcache_req_i_t = logic,
parameter type dcache_req_o_t = logic,
parameter type exception_t = logic,
@ -44,8 +42,8 @@ module cva6_mmu
input logic en_ld_st_translation_i, // enable virtual memory translation for load/stores
input logic en_ld_st_g_translation_i, // enable G-Stage translation for load/stores
// IF interface
input icache_arsp_t icache_areq_i,
output icache_areq_t icache_areq_o,
input fetch_areq_t fetch_areq_i,
output fetch_arsp_t fetch_arsp_o,
// LSU interface
// this is a more minimalistic interface because the actual addressing logic is handled
// in the LSU as we distinguish load and stores, what we do here is simple address translation
@ -169,7 +167,7 @@ module cva6_mmu
// Assignments
assign itlb_lu_access = icache_areq_i.fetch_req;
assign itlb_lu_access = fetch_areq_i.fetch_req;
assign dtlb_lu_access = lsu_req_i;
assign itlb_lu_asid = v_i ? vs_asid_i : asid_i;
assign dtlb_lu_asid = (ld_st_v_i || flush_tlb_vvma_i) ? vs_asid_i : asid_i;
@ -194,7 +192,7 @@ module cva6_mmu
.lu_access_i (itlb_lu_access),
.lu_asid_i (itlb_lu_asid),
.lu_vmid_i (vmid_i),
.lu_vaddr_i (icache_areq_i.fetch_vaddr),
.lu_vaddr_i (fetch_areq_i.fetch_vaddr),
.lu_gpaddr_o (itlb_gpaddr),
.lu_content_o (itlb_content),
.lu_g_content_o(itlb_g_content),
@ -264,7 +262,7 @@ module cva6_mmu
// did we miss?
.itlb_access_i(itlb_lu_access),
.itlb_hit_i (itlb_lu_hit),
.itlb_vaddr_i (icache_areq_i.fetch_vaddr),
.itlb_vaddr_i (fetch_areq_i.fetch_vaddr),
.dtlb_access_i(dtlb_lu_access),
.dtlb_hit_i (dtlb_lu_hit),
@ -360,54 +358,54 @@ module cva6_mmu
// The instruction interface is a simple request response interface
always_comb begin : instr_interface
// MMU disabled: just pass through
icache_areq_o.fetch_valid = icache_areq_i.fetch_req;
icache_areq_o.fetch_paddr = CVA6Cfg.PLEN'(icache_areq_i.fetch_vaddr[((CVA6Cfg.PLEN > CVA6Cfg.VLEN) ? CVA6Cfg.VLEN -1: CVA6Cfg.PLEN -1 ):0]);
fetch_arsp_o.fetch_valid = fetch_areq_i.fetch_req;
fetch_arsp_o.fetch_paddr = CVA6Cfg.PLEN'(fetch_areq_i.fetch_vaddr[((CVA6Cfg.PLEN > CVA6Cfg.VLEN) ? CVA6Cfg.VLEN -1: CVA6Cfg.PLEN -1 ):0]);
// two potential exception sources:
// 1. HPTW threw an exception -> signal with a page fault exception
// 2. We got an access error because of insufficient permissions -> throw an access exception
icache_areq_o.fetch_exception = '0;
fetch_arsp_o.fetch_exception = '0;
// Check whether we are allowed to access this memory region from a fetch perspective
iaccess_err = icache_areq_i.fetch_req && enable_translation_i && //
iaccess_err = fetch_areq_i.fetch_req && enable_translation_i && //
(((priv_lvl_i == riscv::PRIV_LVL_U) && ~itlb_content.u) //
|| ((priv_lvl_i == riscv::PRIV_LVL_S) && itlb_content.u));
if (CVA6Cfg.RVH)
i_g_st_access_err = icache_areq_i.fetch_req && enable_g_translation_i && !itlb_g_content.u;
i_g_st_access_err = fetch_areq_i.fetch_req && enable_g_translation_i && !itlb_g_content.u;
// MMU enabled: address from TLB, request delayed until hit. Error when TLB
// hit and no access right or TLB hit and translated address not valid (e.g.
// AXI decode error), or when PTW performs walk due to ITLB miss and raises
// an error.
if ((enable_translation_i || enable_g_translation_i)) begin
// we work with SV39 or SV32, so if VM is enabled, check that all bits [CVA6Cfg.VLEN-1:CVA6Cfg.SV-1] are equal
if (icache_areq_i.fetch_req && !((&icache_areq_i.fetch_vaddr[CVA6Cfg.VLEN-1:CVA6Cfg.SV-1]) == 1'b1 || (|icache_areq_i.fetch_vaddr[CVA6Cfg.VLEN-1:CVA6Cfg.SV-1]) == 1'b0)) begin
if (fetch_areq_i.fetch_req && !((&fetch_areq_i.fetch_vaddr[CVA6Cfg.VLEN-1:CVA6Cfg.SV-1]) == 1'b1 || (|fetch_areq_i.fetch_vaddr[CVA6Cfg.VLEN-1:CVA6Cfg.SV-1]) == 1'b0)) begin
icache_areq_o.fetch_exception.cause = riscv::INSTR_PAGE_FAULT;
icache_areq_o.fetch_exception.valid = 1'b1;
fetch_arsp_o.fetch_exception.cause = riscv::INSTR_ACCESS_FAULT;
fetch_arsp_o.fetch_exception.valid = 1'b1;
if (CVA6Cfg.TvalEn)
icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(icache_areq_i.fetch_vaddr);
fetch_arsp_o.fetch_exception.tval = CVA6Cfg.XLEN'(fetch_areq_i.fetch_vaddr);
if (CVA6Cfg.RVH) begin
icache_areq_o.fetch_exception.tval2 = '0;
icache_areq_o.fetch_exception.tinst = '0;
icache_areq_o.fetch_exception.gva = v_i;
fetch_arsp_o.fetch_exception.tval2 = '0;
fetch_arsp_o.fetch_exception.tinst = '0;
fetch_arsp_o.fetch_exception.gva = v_i;
end
end
icache_areq_o.fetch_valid = 1'b0;
fetch_arsp_o.fetch_valid = 1'b0;
icache_areq_o.fetch_paddr = {
fetch_arsp_o.fetch_paddr = {
(enable_g_translation_i && CVA6Cfg.RVH) ? itlb_g_content.ppn : itlb_content.ppn,
icache_areq_i.fetch_vaddr[11:0]
fetch_areq_i.fetch_vaddr[11:0]
};
if (CVA6Cfg.PtLevels == 3 && itlb_is_page[CVA6Cfg.PtLevels-2]) begin
icache_areq_o.fetch_paddr[PPNWMin-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels):9+CVA6Cfg.PtLevels] = icache_areq_i.fetch_vaddr[PPNWMin-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels):9+CVA6Cfg.PtLevels];
fetch_arsp_o.fetch_paddr[PPNWMin-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels):9+CVA6Cfg.PtLevels] = fetch_areq_i.fetch_vaddr[PPNWMin-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels):9+CVA6Cfg.PtLevels];
end
if (itlb_is_page[0]) begin
icache_areq_o.fetch_paddr[PPNWMin:12] = icache_areq_i.fetch_vaddr[PPNWMin:12];
fetch_arsp_o.fetch_paddr[PPNWMin:12] = fetch_areq_i.fetch_vaddr[PPNWMin:12];
end
// ---------//
@ -415,23 +413,23 @@ module cva6_mmu
// --------//
// if we hit the ITLB output the request signal immediately
if (itlb_lu_hit) begin
icache_areq_o.fetch_valid = icache_areq_i.fetch_req;
fetch_arsp_o.fetch_valid = fetch_areq_i.fetch_req;
if (CVA6Cfg.RVH && i_g_st_access_err) begin
icache_areq_o.fetch_exception.cause = riscv::INSTR_GUEST_PAGE_FAULT;
icache_areq_o.fetch_exception.valid = 1'b1;
fetch_arsp_o.fetch_exception.cause = riscv::INSTR_GUEST_PAGE_FAULT;
fetch_arsp_o.fetch_exception.valid = 1'b1;
if (CVA6Cfg.TvalEn)
icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(icache_areq_i.fetch_vaddr);
fetch_arsp_o.fetch_exception.tval = CVA6Cfg.XLEN'(fetch_areq_i.fetch_vaddr);
if (CVA6Cfg.RVH) begin
icache_areq_o.fetch_exception.tval2 = itlb_gpaddr[CVA6Cfg.GPLEN-1:0];
icache_areq_o.fetch_exception.tinst = '0;
icache_areq_o.fetch_exception.gva = v_i;
fetch_arsp_o.fetch_exception.tval2 = itlb_gpaddr[CVA6Cfg.GPLEN-1:0];
fetch_arsp_o.fetch_exception.tinst = '0;
fetch_arsp_o.fetch_exception.gva = v_i;
end
// we got an access error
end else if (iaccess_err) begin
// throw a page fault
icache_areq_o.fetch_exception.cause = riscv::INSTR_PAGE_FAULT;
icache_areq_o.fetch_exception.valid = 1'b1;
fetch_arsp_o.fetch_exception.cause = riscv::INSTR_PAGE_FAULT;
fetch_arsp_o.fetch_exception.valid = 1'b1;
if (CVA6Cfg.TvalEn)
icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(icache_areq_i.fetch_vaddr);
if (CVA6Cfg.RVH) begin
@ -445,36 +443,36 @@ module cva6_mmu
// ITLB Miss
// ---------//
// watch out for exceptions happening during walking the page table
icache_areq_o.fetch_valid = ptw_error | ptw_access_exception;
fetch_arsp_o.fetch_valid = ptw_error | ptw_access_exception;
if (ptw_error) begin
if (CVA6Cfg.RVH && ptw_error_at_g_st) begin
icache_areq_o.fetch_exception.cause = riscv::INSTR_GUEST_PAGE_FAULT;
icache_areq_o.fetch_exception.valid = 1'b1;
if (CVA6Cfg.TvalEn) icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(update_vaddr);
fetch_arsp_o.fetch_exception.cause = riscv::INSTR_GUEST_PAGE_FAULT;
fetch_arsp_o.fetch_exception.valid = 1'b1;
if (CVA6Cfg.TvalEn) fetch_arsp_o.fetch_exception.tval = CVA6Cfg.XLEN'(update_vaddr);
if (CVA6Cfg.RVH) begin
icache_areq_o.fetch_exception.tval2 = ptw_bad_gpaddr[CVA6Cfg.GPLEN-1:0];
icache_areq_o.fetch_exception.tinst=(ptw_err_at_g_int_st ? (CVA6Cfg.IS_XLEN64 ? riscv::READ_64_PSEUDOINSTRUCTION : riscv::READ_32_PSEUDOINSTRUCTION) : '0);
icache_areq_o.fetch_exception.gva = v_i;
fetch_arsp_o.fetch_exception.tval2 = ptw_bad_gpaddr[CVA6Cfg.GPLEN-1:0];
fetch_arsp_o.fetch_exception.tinst=(ptw_err_at_g_int_st ? (CVA6Cfg.IS_XLEN64 ? riscv::READ_64_PSEUDOINSTRUCTION : riscv::READ_32_PSEUDOINSTRUCTION) : '0);
fetch_arsp_o.fetch_exception.gva = v_i;
end
end else begin
icache_areq_o.fetch_exception.cause = riscv::INSTR_PAGE_FAULT;
icache_areq_o.fetch_exception.valid = 1'b1;
if (CVA6Cfg.TvalEn) icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(update_vaddr);
fetch_arsp_o.fetch_exception.cause = riscv::INSTR_PAGE_FAULT;
fetch_arsp_o.fetch_exception.valid = 1'b1;
if (CVA6Cfg.TvalEn) fetch_arsp_o.fetch_exception.tval = CVA6Cfg.XLEN'(update_vaddr);
if (CVA6Cfg.RVH) begin
icache_areq_o.fetch_exception.tval2 = '0;
icache_areq_o.fetch_exception.tinst = '0;
icache_areq_o.fetch_exception.gva = v_i;
fetch_arsp_o.fetch_exception.tval2 = '0;
fetch_arsp_o.fetch_exception.tinst = '0;
fetch_arsp_o.fetch_exception.gva = v_i;
end
end
end else begin
icache_areq_o.fetch_exception.cause = riscv::INSTR_ACCESS_FAULT;
icache_areq_o.fetch_exception.valid = 1'b1;
if (CVA6Cfg.TvalEn) //To confirm this is the right TVAL
icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(update_vaddr);
fetch_arsp_o.fetch_exception.cause = riscv::INSTR_ACCESS_FAULT;
fetch_arsp_o.fetch_exception.valid = 1'b1;
if (CVA6Cfg.TvalEn) //To confirm this is the right TVAL
fetch_arsp_o.fetch_exception.tval = CVA6Cfg.XLEN'(update_vaddr);
if (CVA6Cfg.RVH) begin
icache_areq_o.fetch_exception.tval2 = '0;
icache_areq_o.fetch_exception.tinst = '0;
icache_areq_o.fetch_exception.gva = v_i;
fetch_arsp_o.fetch_exception.tval2 = '0;
fetch_arsp_o.fetch_exception.tinst = '0;
fetch_arsp_o.fetch_exception.gva = v_i;
end
end
end

View file

@ -24,10 +24,8 @@ module ex_stage
parameter type dcache_req_o_t = logic,
parameter type exception_t = logic,
parameter type fu_data_t = logic,
parameter type icache_areq_t = logic,
parameter type icache_arsp_t = logic,
parameter type icache_dreq_t = logic,
parameter type icache_drsp_t = logic,
parameter type fetch_areq_t = logic,
parameter type fetch_arsp_t = logic,
parameter type lsu_ctrl_t = logic,
parameter type x_result_t = logic
) (
@ -203,10 +201,10 @@ module ex_stage
input logic [CVA6Cfg.PPNW-1:0] hgatp_ppn_i,
// TO_BE_COMPLETED - CSR_REGFILE
input logic [CVA6Cfg.VMID_WIDTH-1:0] vmid_i,
// icache translation response - CACHE
input icache_arsp_t icache_areq_i,
// icache translation request - CACHE
output icache_areq_t icache_areq_o,
// fetch translation request - FETCH
input fetch_areq_t fetch_areq_i,
// fetch translation response - FETCH
output fetch_arsp_t fetch_arsp_o,
// Data cache request ouput - CACHE
input dcache_req_o_t [2:0] dcache_req_ports_i,
// Data cache request input - CACHE
@ -525,10 +523,8 @@ module ex_stage
.dcache_req_o_t(dcache_req_o_t),
.exception_t(exception_t),
.fu_data_t (fu_data_t),
.icache_areq_t(icache_areq_t),
.icache_arsp_t(icache_arsp_t),
.icache_dreq_t(icache_dreq_t),
.icache_drsp_t(icache_drsp_t),
.fetch_areq_t(fetch_areq_t),
.fetch_arsp_t(fetch_arsp_t),
.lsu_ctrl_t(lsu_ctrl_t)
) lsu_i (
.clk_i,
@ -554,8 +550,8 @@ module ex_stage
.enable_g_translation_i,
.en_ld_st_translation_i,
.en_ld_st_g_translation_i,
.icache_areq_i,
.icache_areq_o,
.fetch_areq_i,
.fetch_arsp_o,
.priv_lvl_i,
.v_i,
.ld_st_priv_lvl_i,

View file

@ -15,14 +15,22 @@
// This module interfaces with the instruction cache, handles control
// change request from the back-end and does branch prediction.
// Additional contributions by:
// 06.06.2024 - Yannick Casamatta, Thales
// OBI Protocol
module frontend
import ariane_pkg::*;
#(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
parameter type bp_resolve_t = logic,
parameter type fetch_entry_t = logic,
parameter type icache_dreq_t = logic,
parameter type icache_drsp_t = logic
parameter type fetch_req_t = logic,
parameter type fetch_rsp_t = logic,
parameter type fetch_areq_t = logic,
parameter type fetch_arsp_t = logic,
parameter type obi_fetch_req_t = logic,
parameter type obi_fetch_rsp_t = logic
) (
// Subsystem Clock - SUBSYSTEM
input logic clk_i,
@ -54,10 +62,18 @@ module frontend
input logic set_debug_pc_i,
// Debug mode state - CSR
input logic debug_mode_i,
// address translation request chanel - EXECUTE
input fetch_arsp_t arsp_i,
// address translation response chanel - EXECUTE
output fetch_areq_t areq_o,
// Handshake between CACHE and FRONTEND (fetch) - CACHES
output icache_dreq_t icache_dreq_o,
output fetch_req_t fetch_req_o,
// Handshake between CACHE and FRONTEND (fetch) - CACHES
input icache_drsp_t icache_dreq_i,
input fetch_rsp_t fetch_rsp_i,
// OBI Fetch Request channel - CACHES
output obi_fetch_req_t obi_fetch_req_o,
// OBI Fetch Response channel - CACHES
input obi_fetch_rsp_t obi_fetch_rsp_i,
// Handshake's data between fetch and decode - ID_STAGE
output fetch_entry_t [CVA6Cfg.NrIssuePorts-1:0] fetch_entry_o,
// Handshake's valid between fetch and decode - ID_STAGE
@ -89,13 +105,13 @@ module frontend
};
// Instruction Cache Registers, from I$
logic [ CVA6Cfg.FETCH_WIDTH-1:0] icache_data_q;
logic icache_valid_q;
ariane_pkg::frontend_exception_t icache_ex_valid_q;
logic [ CVA6Cfg.VLEN-1:0] icache_vaddr_q;
logic [ CVA6Cfg.GPLEN-1:0] icache_gpaddr_q;
logic [ 31:0] icache_tinst_q;
logic icache_gva_q;
logic [ CVA6Cfg.FETCH_WIDTH-1:0] fetch_data_q;
logic fetch_valid_q;
ariane_pkg::frontend_exception_t fetch_ex_valid_q;
logic [ CVA6Cfg.VLEN-1:0] fetch_vaddr_q;
logic [ CVA6Cfg.GPLEN-1:0] fetch_gpaddr_q;
logic [ 31:0] fetch_tinst_q;
logic fetch_gva_q;
logic instr_queue_ready;
logic [CVA6Cfg.INSTR_PER_FETCH-1:0] instr_queue_consumed;
// upper-most branch-prediction from last cycle
@ -106,16 +122,20 @@ module frontend
logic [CVA6Cfg.VLEN-1:0] npc_d, npc_q; // next PC
// indicates whether we come out of reset (then we need to load boot_addr_i)
logic npc_rst_load_q;
logic npc_rst_load_q;
logic replay;
logic [ CVA6Cfg.VLEN-1:0] replay_addr;
logic replay;
logic [CVA6Cfg.VLEN-1:0] replay_addr;
logic [CVA6Cfg.VLEN-1:0]
npc_fetch_address, vaddr_d, obi_vaddr_q, obi_vaddr_d, vaddr_q, fetch_vaddr_d;
logic [CVA6Cfg.PLEN-1:0] paddr_d, paddr_q;
// shift amount
logic [$clog2(CVA6Cfg.INSTR_PER_FETCH)-1:0] shamt;
// address will always be 16 bit aligned, make this explicit here
if (CVA6Cfg.RVC) begin : gen_shamt
assign shamt = icache_dreq_i.vaddr[$clog2(CVA6Cfg.INSTR_PER_FETCH):1];
assign shamt = fetch_vaddr_d[$clog2(CVA6Cfg.INSTR_PER_FETCH):1];
end else begin
assign shamt = 1'b0;
end
@ -153,18 +173,20 @@ module frontend
logic [CVA6Cfg.INSTR_PER_FETCH-1:0] taken_rvi_cf;
logic [CVA6Cfg.INSTR_PER_FETCH-1:0] taken_rvc_cf;
logic serving_unaligned;
logic kill_s1, kill_s2;
logic serving_unaligned;
// Re-align instructions
instr_realign #(
.CVA6Cfg(CVA6Cfg)
) i_instr_realign (
.clk_i (clk_i),
.rst_ni (rst_ni),
.flush_i (icache_dreq_o.kill_s2),
.valid_i (icache_valid_q),
.flush_i (kill_s2),
.valid_i (fetch_valid_q),
.serving_unaligned_o(serving_unaligned),
.address_i (icache_vaddr_q),
.data_i (icache_data_q),
.address_i (fetch_vaddr_q),
.data_i (fetch_data_q),
.valid_o (instruction_valid),
.addr_o (addr),
.instr_o (instr)
@ -303,26 +325,413 @@ module frontend
end
assign is_mispredict = resolved_branch_i.valid & resolved_branch_i.is_mispredict;
// Cache interface
assign icache_dreq_o.req = instr_queue_ready;
assign if_ready = icache_dreq_i.ready & instr_queue_ready;
logic spec_req_non_idempot;
// MMU interface
assign areq_o.fetch_vaddr = (vaddr_q >> CVA6Cfg.FETCH_ALIGN_BITS) << CVA6Cfg.FETCH_ALIGN_BITS;
// CHECK PMA regions
logic paddr_is_cacheable, paddr_is_cacheable_q; // asserted if physical address is non-cacheable
assign paddr_is_cacheable = config_pkg::is_inside_cacheable_regions(
CVA6Cfg, {{64 - CVA6Cfg.PLEN{1'b0}}, obi_fetch_req_o.a.addr} //TO DO CHECK GRANULARITY
);
logic paddr_nonidempotent;
assign paddr_nonidempotent = config_pkg::is_inside_nonidempotent_regions(
CVA6Cfg, {{64 - CVA6Cfg.PLEN{1'b0}}, obi_fetch_req_o.a.addr} //TO DO CHECK GRANULARITY
);
// Caches optimisation signals
typedef enum logic [1:0] {
WAIT_NEW_REQ,
WAIT_ATRANS,
WAIT_OBI,
WAIT_FLUSH
} custom_state_e;
custom_state_e custom_state_d, custom_state_q;
// Address translation signals
logic atrans_req;
logic atrans_kill;
logic atrans_ready;
logic atrans_valid;
logic atrans_ex;
typedef enum logic [1:0] {
IDLE,
READ,
KILL_ATRANS
} atrans_state_e;
atrans_state_e atrans_state_d, atrans_state_q;
// OBI signals
logic obi_a_req;
logic obi_a_ready;
typedef enum logic [1:0] {
TRANSPARENT,
REGISTRED
} obi_a_state_e;
obi_a_state_e obi_a_state_d, obi_a_state_q;
// OBI signals
logic obi_r_req;
logic data_valid_obi;
logic data_valid_under_ex;
typedef enum logic [1:0] {
OBI_R_IDLE,
OBI_R_PENDING,
OBI_R_KILLED
} obi_r_state_e;
obi_r_state_e obi_r_state_d, obi_r_state_q;
// We need to flush the cache pipeline if:
// 1. We mispredicted
// 2. Want to flush the whole processor front-end
// 3. Need to replay an instruction because the fetch-fifo was full
assign icache_dreq_o.kill_s1 = is_mispredict | flush_i | replay;
assign kill_s1 = is_mispredict | flush_i | replay;
// if we have a valid branch-prediction we need to only kill the last cache request
// also if we killed the first stage we also need to kill the second stage (inclusive flush)
assign icache_dreq_o.kill_s2 = icache_dreq_o.kill_s1 | bp_valid;
assign kill_s2 = kill_s1 | bp_valid;
assign fetch_req_o.vaddr = vaddr_d;
assign fetch_req_o.kill_req = kill_s1 | kill_s2 | atrans_ex;
// Common clocked process
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
if (!rst_ni) begin
custom_state_q <= WAIT_NEW_REQ;
atrans_state_q <= IDLE;
obi_a_state_q <= TRANSPARENT;
obi_r_state_q <= OBI_R_IDLE;
vaddr_q <= '0;
paddr_q <= '0;
obi_vaddr_q <= '0;
paddr_is_cacheable_q <= '0;
end else begin
custom_state_q <= custom_state_d;
atrans_state_q <= atrans_state_d;
obi_a_state_q <= obi_a_state_d;
obi_r_state_q <= obi_r_state_d;
vaddr_q <= vaddr_d;
paddr_q <= paddr_d;
obi_vaddr_q <= obi_vaddr_d;
paddr_is_cacheable_q <= paddr_is_cacheable;
end
end
// custom protocol FSM (combi)
always_comb begin : p_fsm_common
// default assignment
custom_state_d = custom_state_q;
atrans_req = '0;
atrans_kill = '0;
obi_a_req = '0;
obi_vaddr_d = obi_vaddr_q;
fetch_req_o.req = '0;
data_valid_under_ex = '0;
if_ready = '0;
vaddr_d = vaddr_q;
unique case (custom_state_q)
WAIT_NEW_REQ: begin
vaddr_d = npc_fetch_address;
if ((obi_a_state_q == TRANSPARENT || obi_r_req == '1) && instr_queue_ready && atrans_ready && !kill_s2) begin
fetch_req_o.req = '1;
if (fetch_rsp_i.ready) begin
if_ready = '1;
atrans_req = '1;
custom_state_d = WAIT_ATRANS;
end
end
end
WAIT_ATRANS: begin
if (atrans_valid) begin
if (kill_s2) begin
vaddr_d = npc_fetch_address;
if (instr_queue_ready && atrans_ready && !kill_s1) begin
fetch_req_o.req = '1;
if (fetch_rsp_i.ready) begin
if_ready = '1;
atrans_req = '1;
end else begin
custom_state_d = WAIT_NEW_REQ;
end
end else begin
custom_state_d = WAIT_NEW_REQ;
end
end else if (atrans_ex) begin
obi_vaddr_d = vaddr_d;
data_valid_under_ex = '1;
custom_state_d = WAIT_FLUSH;
end else if (obi_a_ready && !spec_req_non_idempot) begin
obi_a_req = '1;
obi_vaddr_d = vaddr_d;
vaddr_d = npc_fetch_address;
if (obi_r_req && instr_queue_ready && atrans_ready && !kill_s1) begin
fetch_req_o.req = '1;
if (fetch_rsp_i.ready) begin
if_ready = '1;
atrans_req = '1;
end else begin
custom_state_d = WAIT_NEW_REQ;
end
end else begin
custom_state_d = WAIT_NEW_REQ;
end
end else begin
custom_state_d = WAIT_OBI;
end
end
if (kill_s2) begin
atrans_kill = '1;
vaddr_d = npc_fetch_address;
if (instr_queue_ready && atrans_ready && !kill_s1) begin
fetch_req_o.req = '1;
if (fetch_rsp_i.ready) begin
if_ready = '1;
atrans_req = '1;
end else begin
custom_state_d = WAIT_NEW_REQ;
end
end else begin
custom_state_d = WAIT_NEW_REQ;
end
end
end
WAIT_OBI: begin
if (kill_s2) begin
vaddr_d = npc_fetch_address;
if ((obi_a_state_q == TRANSPARENT || obi_r_req == '1) && instr_queue_ready && atrans_ready && !kill_s1) begin
fetch_req_o.req = '1;
if (fetch_rsp_i.ready) begin
if_ready = '1;
atrans_req = '1;
custom_state_d = WAIT_ATRANS;
end else begin
custom_state_d = WAIT_NEW_REQ;
end
end else begin
custom_state_d = WAIT_NEW_REQ;
end
end else if (obi_a_ready && !spec_req_non_idempot) begin
obi_a_req = '1;
obi_vaddr_d = vaddr_d;
vaddr_d = npc_fetch_address;
if (obi_r_req && instr_queue_ready && atrans_ready && !kill_s1) begin
fetch_req_o.req = '1;
if (fetch_rsp_i.ready) begin
if_ready = '1;
atrans_req = '1;
custom_state_d = WAIT_ATRANS;
end else begin
custom_state_d = WAIT_NEW_REQ;
end
end else begin
custom_state_d = WAIT_NEW_REQ;
end
end
end
WAIT_FLUSH: begin
if (kill_s1) begin
custom_state_d = WAIT_NEW_REQ;
end
end
default: begin
custom_state_d = WAIT_NEW_REQ;
end
endcase
end
// Address translation protocol FSM (combi)
always_comb begin : p_fsm_atrans
// default assignment
atrans_state_d = atrans_state_q;
areq_o.fetch_req = 1'b0;
atrans_ready = 1'b0;
atrans_valid = 1'b0;
paddr_d = paddr_q;
atrans_ex = 1'b0;
unique case (atrans_state_q)
IDLE: begin
atrans_ready = 1'b1;
if (atrans_req) begin
atrans_state_d = READ;
end
end
READ: begin
areq_o.fetch_req = '1;
if (arsp_i.fetch_valid) begin
atrans_ready = 1'b1;
if (!atrans_kill) begin
atrans_valid = 1'b1;
paddr_d = arsp_i.fetch_paddr;
atrans_ex = arsp_i.fetch_exception.valid;
end
if (!atrans_req) begin
atrans_state_d = IDLE;
end
end else if (atrans_kill) begin
atrans_state_d = KILL_ATRANS;
end
end
KILL_ATRANS: begin
areq_o.fetch_req = '1;
if (arsp_i.fetch_valid) begin
atrans_ready = 1'b1;
if (atrans_req) begin
atrans_state_d = READ;
end else begin
atrans_state_d = IDLE;
end
end
end
default: begin
atrans_state_d = IDLE;
end
endcase
end
// OBI CHANNEL A protocol FSM (combi)
always_comb begin : p_fsm_obi_a
// default assignment
obi_a_state_d = obi_a_state_q;
obi_a_ready = 1'b0;
obi_r_req = '0;
//default obi state registred
obi_fetch_req_o.req = 1'b1;
obi_fetch_req_o.reqpar = 1'b0;
obi_fetch_req_o.a.addr = paddr_q;
obi_fetch_req_o.a.we = '0;
obi_fetch_req_o.a.be = '1;
obi_fetch_req_o.a.wdata= '0;
obi_fetch_req_o.a.aid = '0;
obi_fetch_req_o.a.a_optional.auser= '0;
obi_fetch_req_o.a.a_optional.wuser= '0;
obi_fetch_req_o.a.a_optional.atop= '0;
obi_fetch_req_o.a.a_optional.memtype[0]='0;
obi_fetch_req_o.a.a_optional.memtype[1]=paddr_is_cacheable_q;
obi_fetch_req_o.a.a_optional.mid= '0;
obi_fetch_req_o.a.a_optional.prot= '0;
obi_fetch_req_o.a.a_optional.dbg= '0;
obi_fetch_req_o.a.a_optional.achk= '0;
unique case (obi_a_state_q)
TRANSPARENT: begin
obi_a_ready = '1;
if (obi_a_req) begin
if (obi_fetch_rsp_i.gnt) begin
obi_r_req = '1; //push pending request
end else begin
obi_a_state_d = REGISTRED;
end
end
obi_fetch_req_o.req = obi_a_req;
obi_fetch_req_o.reqpar = !obi_a_req;
obi_fetch_req_o.a.addr = paddr_d;
obi_fetch_req_o.a.we = '0;
obi_fetch_req_o.a.be = '1;
obi_fetch_req_o.a.wdata= '0;
obi_fetch_req_o.a.aid = '0;
obi_fetch_req_o.a.a_optional.auser= '0;
obi_fetch_req_o.a.a_optional.wuser= '0;
obi_fetch_req_o.a.a_optional.atop= '0;
obi_fetch_req_o.a.a_optional.memtype[0]='0;
obi_fetch_req_o.a.a_optional.memtype[1]=paddr_is_cacheable;
obi_fetch_req_o.a.a_optional.mid= '0;
obi_fetch_req_o.a.a_optional.prot= '0;
obi_fetch_req_o.a.a_optional.dbg= '0;
obi_fetch_req_o.a.a_optional.achk= '0;
end
REGISTRED: begin
if (obi_fetch_rsp_i.gnt) begin
obi_r_req = '1; //push pending request
obi_a_state_d = TRANSPARENT;
end
end
default: begin
obi_a_state_d = TRANSPARENT;
end
endcase
end
// OBI CHANNEL R protocol FSM (combi)
always_comb begin : p_fsm_obi_r
// default assignment
obi_r_state_d = obi_r_state_q;
data_valid_obi = '0;
unique case (obi_r_state_q)
OBI_R_IDLE: begin
if (obi_r_req) begin
if (kill_s2) begin
obi_r_state_d = OBI_R_KILLED;
end else begin
obi_r_state_d = OBI_R_PENDING;
end
end
end
OBI_R_PENDING: begin
if (obi_fetch_req_o.rready && obi_fetch_rsp_i.rvalid) begin
data_valid_obi = !kill_s2;
if (!obi_r_req) begin
obi_r_state_d = OBI_R_IDLE;
end
end else if (kill_s2) begin
obi_r_state_d = OBI_R_KILLED;
end
end
OBI_R_KILLED: begin
if (obi_fetch_req_o.rready && obi_fetch_rsp_i.rvalid) begin
if (obi_r_req) begin
if (!kill_s2) begin
obi_r_state_d = OBI_R_PENDING;
end
end else begin
obi_r_state_d = OBI_R_IDLE;
end
end
end
default: begin
obi_r_state_d = OBI_R_IDLE;
end
endcase
end
//always ready to get data
assign obi_fetch_req_o.rready = '1;
assign obi_fetch_req_o.rreadypar = !obi_fetch_req_o.rready;
// Update Control Flow Predictions
bht_update_t bht_update;
btb_update_t btb_update;
// assert on branch, deassert when resolved
logic speculative_q, speculative_d;
assign speculative_d = (speculative_q && !resolved_branch_i.valid || |is_branch || |is_return || |is_jalr) && !flush_i;
assign icache_dreq_o.spec = speculative_d;
assign spec_req_non_idempot = CVA6Cfg.NonIdemPotenceEn ? speculative_d && paddr_nonidempotent : 1'b0;
assign bht_update.valid = resolved_branch_i.valid
& (resolved_branch_i.cf_type == ariane_pkg::Branch);
@ -406,54 +815,59 @@ module frontend
// enter debug on a hard-coded base-address
if (CVA6Cfg.DebugEn && set_debug_pc_i)
npc_d = CVA6Cfg.DmBaseAddress[CVA6Cfg.VLEN-1:0] + CVA6Cfg.HaltAddress[CVA6Cfg.VLEN-1:0];
icache_dreq_o.vaddr = fetch_address;
npc_fetch_address = fetch_address;
end
logic [CVA6Cfg.FETCH_WIDTH-1:0] icache_data;
logic [CVA6Cfg.FETCH_WIDTH-1:0] fetch_data;
logic fetch_valid_d;
// re-align the cache line
assign icache_data = icache_dreq_i.data >> {shamt, 4'b0};
assign fetch_data = data_valid_under_ex ? '0 : obi_fetch_rsp_i.r.rdata >> {shamt, 4'b0};
assign fetch_valid_d = data_valid_under_ex || data_valid_obi;
assign fetch_vaddr_d = data_valid_under_ex ? vaddr_q : obi_vaddr_q;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
npc_rst_load_q <= 1'b1;
npc_q <= '0;
speculative_q <= '0;
icache_data_q <= '0;
icache_valid_q <= 1'b0;
icache_vaddr_q <= 'b0;
icache_gpaddr_q <= 'b0;
icache_tinst_q <= 'b0;
icache_gva_q <= 1'b0;
icache_ex_valid_q <= ariane_pkg::FE_NONE;
btb_q <= '0;
bht_q <= '0;
npc_rst_load_q <= 1'b1;
npc_q <= '0;
speculative_q <= '0;
fetch_data_q <= '0;
fetch_valid_q <= 1'b0;
fetch_vaddr_q <= 'b0;
fetch_gpaddr_q <= 'b0;
fetch_tinst_q <= 'b0;
fetch_gva_q <= 1'b0;
fetch_ex_valid_q <= ariane_pkg::FE_NONE;
btb_q <= '0;
bht_q <= '0;
end else begin
npc_rst_load_q <= 1'b0;
npc_q <= npc_d;
speculative_q <= speculative_d;
icache_valid_q <= icache_dreq_i.valid;
if (icache_dreq_i.valid) begin
icache_data_q <= icache_data;
icache_vaddr_q <= icache_dreq_i.vaddr;
npc_q <= npc_d;
speculative_q <= speculative_d;
fetch_valid_q <= fetch_valid_d;
if (fetch_valid_d) begin
fetch_data_q <= fetch_data;
fetch_vaddr_q <= fetch_vaddr_d;
if (CVA6Cfg.RVH) begin
icache_gpaddr_q <= icache_dreq_i.ex.tval2[CVA6Cfg.GPLEN-1:0];
icache_tinst_q <= icache_dreq_i.ex.tinst;
icache_gva_q <= icache_dreq_i.ex.gva;
fetch_gpaddr_q <= arsp_i.fetch_exception.tval2[CVA6Cfg.GPLEN-1:0];
fetch_tinst_q <= arsp_i.fetch_exception.tinst;
fetch_gva_q <= arsp_i.fetch_exception.gva;
end else begin
icache_gpaddr_q <= 'b0;
icache_tinst_q <= 'b0;
icache_gva_q <= 1'b0;
fetch_gpaddr_q <= 'b0;
fetch_tinst_q <= 'b0;
fetch_gva_q <= 1'b0;
end
// Map the only three exceptions which can occur in the frontend to a two bit enum
if (CVA6Cfg.MmuPresent && icache_dreq_i.ex.cause == riscv::INSTR_GUEST_PAGE_FAULT) begin
icache_ex_valid_q <= ariane_pkg::FE_INSTR_GUEST_PAGE_FAULT;
end else if (CVA6Cfg.MmuPresent && icache_dreq_i.ex.cause == riscv::INSTR_PAGE_FAULT) begin
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;
if (CVA6Cfg.MmuPresent && arsp_i.fetch_exception.cause == riscv::INSTR_GUEST_PAGE_FAULT) begin
fetch_ex_valid_q <= ariane_pkg::FE_INSTR_GUEST_PAGE_FAULT;
end else if (CVA6Cfg.MmuPresent && arsp_i.fetch_exception.cause == riscv::INSTR_PAGE_FAULT) begin
fetch_ex_valid_q <= ariane_pkg::FE_INSTR_PAGE_FAULT;
end else if (arsp_i.fetch_exception.cause == riscv::INSTR_ACCESS_FAULT) begin
fetch_ex_valid_q <= ariane_pkg::FE_INSTR_ACCESS_FAULT;
end else begin
icache_ex_valid_q <= ariane_pkg::FE_NONE;
fetch_ex_valid_q <= ariane_pkg::FE_NONE;
end
// save the uppermost prediction
btb_q <= btb_prediction[CVA6Cfg.INSTR_PER_FETCH-1];
@ -484,8 +898,8 @@ module frontend
//while for ASIC, BTB is implemented in D flip-flop
//and can be read at the same cycle.
//Same for BHT
assign vpc_btb = (CVA6Cfg.FpgaEn) ? icache_dreq_i.vaddr : icache_vaddr_q;
assign vpc_bht = (CVA6Cfg.FpgaEn && CVA6Cfg.FpgaAlteraEn && icache_dreq_i.valid) ? icache_dreq_i.vaddr : icache_vaddr_q;
assign vpc_btb = (CVA6Cfg.FpgaEn) ? vaddr_q : fetch_vaddr_q;
assign vpc_bht = (CVA6Cfg.FpgaEn && CVA6Cfg.FpgaAlteraEn && data_valid_obi) ? vaddr_q : fetch_vaddr_q;
if (CVA6Cfg.BTBEntries == 0) begin
assign btb_prediction = '0;
@ -556,11 +970,11 @@ module frontend
.flush_i (flush_i),
.instr_i (instr), // from re-aligner
.addr_i (addr), // from re-aligner
.exception_i (icache_ex_valid_q), // from I$
.exception_addr_i (icache_vaddr_q),
.exception_gpaddr_i (icache_gpaddr_q),
.exception_tinst_i (icache_tinst_q),
.exception_gva_i (icache_gva_q),
.exception_i (fetch_ex_valid_q), // from I$
.exception_addr_i (fetch_vaddr_q),
.exception_gpaddr_i (fetch_gpaddr_q),
.exception_tinst_i (fetch_tinst_q),
.exception_gva_i (fetch_gva_q),
.predict_address_i (predict_address),
.cf_type_i (cf_type),
.valid_i (instruction_valid), // from re-aligner

View file

@ -159,7 +159,8 @@ package build_config_pkg;
cfg.AXI_USER_EN = CVA6Cfg.DataUserEn | CVA6Cfg.FetchUserEn;
cfg.FETCH_WIDTH = unsigned'(CVA6Cfg.SuperscalarEn ? 64 : 32);
cfg.FETCH_ALIGN_BITS = $clog2(cfg.FETCH_WIDTH / 8);
cfg.FETCH_BE_WIDTH = cfg.FETCH_WIDTH / 8;
cfg.FETCH_ALIGN_BITS = $clog2(cfg.FETCH_BE_WIDTH);
cfg.INSTR_PER_FETCH = cfg.FETCH_WIDTH / (CVA6Cfg.RVC ? 16 : 32);
cfg.LOG2_INSTR_PER_FETCH = cfg.INSTR_PER_FETCH > 1 ? $clog2(cfg.INSTR_PER_FETCH) : 1;

View file

@ -364,6 +364,7 @@ package config_pkg;
bit AXI_USER_EN;
int unsigned FETCH_WIDTH;
int unsigned FETCH_BE_WIDTH;
int unsigned FETCH_ALIGN_BITS;
int unsigned INSTR_PER_FETCH;
int unsigned LOG2_INSTR_PER_FETCH;

View file

@ -21,8 +21,8 @@ module load_store_unit
parameter type dcache_req_o_t = logic,
parameter type exception_t = logic,
parameter type fu_data_t = logic,
parameter type icache_areq_t = logic,
parameter type icache_arsp_t = logic,
parameter type fetch_areq_t = logic,
parameter type fetch_arsp_t = logic,
parameter type icache_dreq_t = logic,
parameter type icache_drsp_t = logic,
parameter type lsu_ctrl_t = logic
@ -82,10 +82,10 @@ module load_store_unit
// Enable G-Stage memory translation for load/stores - TO_BE_COMPLETED
input logic en_ld_st_g_translation_i,
// Instruction cache input request - CACHES
input icache_arsp_t icache_areq_i,
// Instruction cache output request - CACHES
output icache_areq_t icache_areq_o,
// Instruction cache input request - FETCH
input fetch_areq_t fetch_areq_i,
// Instruction cache output response - FETCH
output fetch_arsp_t fetch_arsp_o,
// Current privilege mode - CSR_REGFILE
input riscv::priv_lvl_t priv_lvl_i,
@ -205,33 +205,33 @@ module load_store_unit
logic translation_req;
logic translation_valid;
logic [CVA6Cfg.VLEN-1:0] mmu_vaddr;
logic [CVA6Cfg.PLEN-1:0] mmu_paddr, lsu_paddr;
logic [ 31:0] mmu_tinst;
logic mmu_hs_ld_st_inst;
logic mmu_hlvx_inst;
exception_t mmu_exception;
exception_t pmp_exception;
icache_areq_t pmp_icache_areq_i;
logic pmp_translation_valid;
logic dtlb_hit;
logic [ CVA6Cfg.PPNW-1:0] dtlb_ppn;
logic [CVA6Cfg.PLEN-1:0] mmu_paddr, fetch_vaddr_plen, lsu_paddr;
logic [ 31:0] mmu_tinst;
logic mmu_hs_ld_st_inst;
logic mmu_hlvx_inst;
exception_t mmu_exception;
exception_t pmp_exception;
fetch_arsp_t pmp_fetch_arsp;
logic pmp_translation_valid;
logic dtlb_hit;
logic [ CVA6Cfg.PPNW-1:0] dtlb_ppn;
logic ld_valid;
logic [CVA6Cfg.TRANS_ID_BITS-1:0] ld_trans_id;
logic [ CVA6Cfg.XLEN-1:0] ld_result;
logic st_valid;
logic [CVA6Cfg.TRANS_ID_BITS-1:0] st_trans_id;
logic [ CVA6Cfg.XLEN-1:0] st_result;
logic ld_valid;
logic [CVA6Cfg.TRANS_ID_BITS-1:0] ld_trans_id;
logic [ CVA6Cfg.XLEN-1:0] ld_result;
logic st_valid;
logic [CVA6Cfg.TRANS_ID_BITS-1:0] st_trans_id;
logic [ CVA6Cfg.XLEN-1:0] st_result;
logic [ 11:0] page_offset;
logic page_offset_matches;
logic [ 11:0] page_offset;
logic page_offset_matches;
exception_t misaligned_exception;
exception_t ld_ex;
exception_t st_ex;
exception_t misaligned_exception;
exception_t ld_ex;
exception_t st_ex;
logic hs_ld_st_inst;
logic hlvx_inst;
logic hs_ld_st_inst;
logic hlvx_inst;
logic [1:0] sum, mxr;
logic [CVA6Cfg.PPNW-1:0] satp_ppn[2:0];
@ -247,10 +247,8 @@ module load_store_unit
cva6_mmu #(
.CVA6Cfg (CVA6Cfg),
.exception_t (exception_t),
.icache_areq_t (icache_areq_t),
.icache_arsp_t (icache_arsp_t),
.icache_dreq_t (icache_dreq_t),
.icache_drsp_t (icache_drsp_t),
.fetch_areq_t (fetch_areq_t),
.fetch_arsp_t (fetch_arsp_t),
.dcache_req_i_t(dcache_req_i_t),
.dcache_req_o_t(dcache_req_o_t),
.HYP_EXT (HYP_EXT)
@ -262,8 +260,8 @@ module load_store_unit
.enable_g_translation_i(enable_g_translation_i),
.en_ld_st_translation_i(en_ld_st_translation_i),
.en_ld_st_g_translation_i(en_ld_st_g_translation_i),
.icache_areq_i(icache_areq_i),
.icache_areq_o(pmp_icache_areq_i),
.fetch_areq_i(fetch_areq_i),
.fetch_arsp_o(pmp_fetch_arsp),
// misaligned bypass
.misaligned_ex_i(misaligned_exception),
.lsu_req_i(translation_req),
@ -313,14 +311,14 @@ module load_store_unit
.pmpaddr_i
);
end else begin : gen_no_mmu
// icache request without MMU, virtual and physical address are identical
assign pmp_icache_areq_i.fetch_valid = icache_areq_i.fetch_req;
// fetch request without MMU, virtual and physical address are identical
assign pmp_fetch_arsp.fetch_valid = fetch_areq_i.fetch_req;
if (CVA6Cfg.VLEN >= CVA6Cfg.PLEN) begin : gen_virtual_physical_address_instruction_vlen_greater
assign pmp_icache_areq_i.fetch_paddr = icache_areq_i.fetch_vaddr[CVA6Cfg.PLEN-1:0];
assign pmp_fetch_arsp.fetch_paddr = fetch_areq_i.fetch_vaddr[CVA6Cfg.PLEN-1:0];
end else begin : gen_virtual_physical_address_instruction_plen_greater
assign pmp_icache_areq_i.fetch_paddr = CVA6Cfg.PLEN'(icache_areq_i.fetch_vaddr);
assign pmp_fetch_arsp.fetch_paddr = CVA6Cfg.PLEN'(fetch_areq_i.fetch_vaddr);
end
assign pmp_icache_areq_i.fetch_exception = 'h0;
assign pmp_fetch_arsp.fetch_exception = 'h0;
// dcache request without mmu for load or store,
// Delay of 1 cycle to match MMU latency giving the address tag
always_ff @(posedge clk_i or negedge rst_ni) begin
@ -363,14 +361,14 @@ module load_store_unit
pmp_data_if #(
.CVA6Cfg (CVA6Cfg),
.icache_areq_t(icache_areq_t),
.icache_areq_t(fetch_arsp_t),
.exception_t (exception_t)
) i_pmp_data_if (
.clk_i (clk_i),
.rst_ni (rst_ni),
.icache_areq_i (pmp_icache_areq_i),
.icache_areq_o (icache_areq_o),
.icache_fetch_vaddr_i(icache_areq_i.fetch_vaddr),
.icache_areq_i (pmp_fetch_arsp),
.icache_areq_o (fetch_arsp_o),
.icache_fetch_vaddr_i(fetch_areq_i.fetch_vaddr),
.lsu_valid_i (pmp_translation_valid),
.lsu_paddr_i (lsu_paddr),
.lsu_vaddr_i (mmu_vaddr),

View file

@ -21,7 +21,7 @@ module perf_counters
parameter type dcache_req_i_t = logic,
parameter type dcache_req_o_t = logic,
parameter type exception_t = logic,
parameter type icache_dreq_t = logic,
parameter type fetch_dreq_t = logic,
parameter type scoreboard_entry_t = logic,
parameter int unsigned NumPorts = 3 // number of miss ports
) (
@ -52,7 +52,7 @@ module perf_counters
input bp_resolve_t resolved_branch_i,
// for newly added events
input exception_t branch_exceptions_i, //Branch exceptions->execute unit-> branch_exception_o
input icache_dreq_t l1_icache_access_i,
input fetch_dreq_t l1_fetch_access_i,
input dcache_req_i_t [2:0] l1_dcache_access_i,
input logic [NumPorts-1:0][CVA6Cfg.DCACHE_SET_ASSOC-1:0]miss_vld_bits_i, //For Cache eviction (3ports-LOAD,STORE,PTW)
input logic i_tlb_flush_i,
@ -123,7 +123,7 @@ module perf_counters
5'b01101: events[i] = |return_event; //Return
5'b01110: events[i] = sb_full_i; //MSB Full
5'b01111: events[i] = if_empty_i; //Instruction fetch Empty
5'b10000: events[i] = l1_icache_access_i.req; //L1 I-Cache accesses
5'b10000: events[i] = l1_fetch_access_i.req; //L1 I-Cache accesses
5'b10001:
events[i] = l1_dcache_access_i[0].data_req || l1_dcache_access_i[1].data_req || l1_dcache_access_i[2].data_req;//L1 D-Cache accesses
5'b10010:

View file

@ -44,6 +44,7 @@ set_property include_dirs { \
"src/axi_sd_bridge/include" \
"../../vendor/pulp-platform/common_cells/include" \
"../../vendor/pulp-platform/axi/include" \
"../../vendor/pulp-platform/obi/include" \
"../../core/cache_subsystem/hpdcache/rtl/include" \
"../register_interface/include" \
"../../core/include" \