Skip to content

Commit

Permalink
Fully support the Write-Back mode of the HPDcache in the CVA6 (#2691)
Browse files Browse the repository at this point in the history
This PR modifies some components in the CVA6 to fully support the WB mode of the HPDcache.

When on WB mode, there may be coherency issues between the Instruction Cache and the Data Cache. This may happen when the software writes on instruction segments (e.g. to relocate a code in memory).

This PR contains the following modifications:

The CVA6 controller module rises the flush signal to the caches when executing a fence or fence.i instruction.
The HPDcache cache subsystem translates this fence signal to a FLUSH request to the cache (when the HPDcache is in WB mode).
Add new parameters in the CVA6 configuration packages:
DcacheFlushOnInvalidate: It changes the behavior of the CVA6 controller. When this parameter is set, the controller rises the Flush signal on fence instructions.
DcacheInvalidateOnFlush: It changes the behavior of the HPDcache request adapter. When issuing a flush, it also asks the HPDcache to invalidate the cachelines.
Add additional values to the DcacheType enum: HPDCACHE_WT, HPDCACHE_WB, HPDCACHE_WT_WB
In addition, it also fixes some issues with the rvfi_mem_paddr signal from the store_buffer.
  • Loading branch information
cfuguet authored Jan 10, 2025
1 parent 71f96d4 commit db568f3
Show file tree
Hide file tree
Showing 20 changed files with 441 additions and 102 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,15 @@ jobs:
strategy:
matrix:
testcase: [ cv64a6_imafdc_tests ]
config: [ cv64a6_imafdc_sv39_hpdcache, cv64a6_imafdc_sv39_wb, cv64a6_imafdc_sv39 ]
config: [ cv64a6_imafdc_sv39_hpdcache, cv64a6_imafdc_sv39_hpdcache_wb, cv64a6_imafdc_sv39_wb, cv64a6_imafdc_sv39 ]
simulator: [ veri-testharness ]
include:
- testcase: dv-riscv-arch-test
config: cv64a6_imafdc_sv39_hpdcache
simulator: veri-testharness
- testcase: dv-riscv-arch-test
config: cv64a6_imafdc_sv39_hpdcache_wb
simulator: veri-testharness
needs:
build-riscv-tests
steps:
Expand Down
198 changes: 159 additions & 39 deletions core/cache_subsystem/cva6_hpdcache_if_adapter.sv
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ module cva6_hpdcache_if_adapter
parameter type hpdcache_rsp_t = logic,
parameter type dcache_req_i_t = logic,
parameter type dcache_req_o_t = logic,
parameter bit is_load_port = 1'b1
parameter bit InvalidateOnFlush = 1'b0,
parameter bit IsLoadPort = 1'b1
)
// }}}

Expand All @@ -42,6 +43,10 @@ module cva6_hpdcache_if_adapter
input ariane_pkg::amo_req_t cva6_amo_req_i,
output ariane_pkg::amo_resp_t cva6_amo_resp_o,

// Dcache flush signal
input logic cva6_dcache_flush_i,
output logic cva6_dcache_flush_ack_o,

// Request port to the L1 Dcache
output logic hpdcache_req_valid_o,
input logic hpdcache_req_ready_i,
Expand All @@ -58,16 +63,21 @@ module cva6_hpdcache_if_adapter

// Internal nets and registers
// {{{
logic forward_store, forward_amo;
typedef enum {
FLUSH_IDLE,
FLUSH_PEND
} flush_fsm_t;

logic hpdcache_req_is_uncacheable;
hpdcache_req_t hpdcache_req;
// }}}

// Request forwarding
// {{{
generate
// LOAD request
// {{{
if (is_load_port == 1'b1) begin : load_port_gen
if (IsLoadPort == 1'b1) begin : load_port_gen
assign hpdcache_req_is_uncacheable = !config_pkg::is_inside_cacheable_regions(
CVA6Cfg,
{
Expand All @@ -79,19 +89,19 @@ module cva6_hpdcache_if_adapter

// Request forwarding
assign hpdcache_req_valid_o = cva6_req_i.data_req;
assign hpdcache_req_o.addr_offset = cva6_req_i.address_index;
assign hpdcache_req_o.wdata = '0;
assign hpdcache_req_o.op = hpdcache_pkg::HPDCACHE_REQ_LOAD;
assign hpdcache_req_o.be = cva6_req_i.data_be;
assign hpdcache_req_o.size = cva6_req_i.data_size;
assign hpdcache_req_o.sid = hpdcache_req_sid_i;
assign hpdcache_req_o.tid = cva6_req_i.data_id;
assign hpdcache_req_o.need_rsp = 1'b1;
assign hpdcache_req_o.phys_indexed = 1'b0;
assign hpdcache_req_o.addr_tag = '0; // unused on virtually indexed request
assign hpdcache_req_o.pma.uncacheable = 1'b0;
assign hpdcache_req_o.pma.io = 1'b0;
assign hpdcache_req_o.pma.wr_policy_hint = hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO;
assign hpdcache_req.addr_offset = cva6_req_i.address_index;
assign hpdcache_req.wdata = '0;
assign hpdcache_req.op = hpdcache_pkg::HPDCACHE_REQ_LOAD;
assign hpdcache_req.be = cva6_req_i.data_be;
assign hpdcache_req.size = cva6_req_i.data_size;
assign hpdcache_req.sid = hpdcache_req_sid_i;
assign hpdcache_req.tid = cva6_req_i.data_id;
assign hpdcache_req.need_rsp = 1'b1;
assign hpdcache_req.phys_indexed = 1'b0;
assign hpdcache_req.addr_tag = '0; // unused on virtually indexed request
assign hpdcache_req.pma.uncacheable = 1'b0;
assign hpdcache_req.pma.io = 1'b0;
assign hpdcache_req.pma.wr_policy_hint = hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO;

assign hpdcache_req_abort_o = cva6_req_i.kill_req;
assign hpdcache_req_tag_o = cva6_req_i.address_tag;
Expand All @@ -104,6 +114,15 @@ module cva6_hpdcache_if_adapter
assign cva6_req_o.data_rdata = hpdcache_rsp_i.rdata;
assign cva6_req_o.data_rid = hpdcache_rsp_i.tid;
assign cva6_req_o.data_gnt = hpdcache_req_ready_i;

// Assertions
// {{{
// pragma translate_off
flush_on_load_port_assert :
assert property (@(posedge clk_i) disable iff (rst_ni !== 1'b1) (cva6_dcache_flush_i == 1'b0))
else $error("Flush unsupported on load adapters");
// pragma translate_on
// }}}
end // }}}

// {{{
Expand All @@ -119,6 +138,53 @@ module cva6_hpdcache_if_adapter
logic [31:0] amo_resp_word;
logic amo_pending_q;

hpdcache_req_t hpdcache_req_amo;
hpdcache_req_t hpdcache_req_store;
hpdcache_req_t hpdcache_req_flush;

flush_fsm_t flush_fsm_q, flush_fsm_d;

logic forward_store, forward_amo, forward_flush;

// DCACHE flush request
// {{{
always_ff @(posedge clk_i or negedge rst_ni) begin : flush_ff
if (!rst_ni) begin
flush_fsm_q <= FLUSH_IDLE;
end else begin
flush_fsm_q <= flush_fsm_d;
end
end

always_comb begin : flush_comb
forward_flush = 1'b0;
cva6_dcache_flush_ack_o = 1'b0;

flush_fsm_d = flush_fsm_q;

case (flush_fsm_q)
FLUSH_IDLE: begin
if (cva6_dcache_flush_i) begin
forward_flush = 1'b1;
if (hpdcache_req_ready_i) begin
flush_fsm_d = FLUSH_PEND;
end
end
end
FLUSH_PEND: begin
if (hpdcache_rsp_valid_i) begin
if (hpdcache_rsp_i.tid == '0) begin
cva6_dcache_flush_ack_o = 1'b1;
flush_fsm_d = FLUSH_IDLE;
end
end
end
default: begin
end
endcase
end
// }}}

// AMO logic
// {{{
always_comb begin : amo_op_comb
Expand Down Expand Up @@ -148,7 +214,7 @@ module cva6_hpdcache_if_adapter
CVA6Cfg,
{
{64 - CVA6Cfg.DCACHE_TAG_WIDTH{1'b0}}
, hpdcache_req_o.addr_tag,
, hpdcache_req.addr_tag,
{CVA6Cfg.DCACHE_INDEX_WIDTH{1'b0}}
}
);
Expand All @@ -163,23 +229,73 @@ module cva6_hpdcache_if_adapter
assign amo_data_be = 8'h0f;
end

assign hpdcache_req_amo = '{
addr_offset: amo_addr_offset,
wdata: amo_data,
op: amo_op,
be: amo_data_be,
size: cva6_amo_req_i.size,
sid: hpdcache_req_sid_i,
tid: '1,
need_rsp: 1'b1,
phys_indexed: 1'b1,
addr_tag: amo_tag,
pma: '{
uncacheable: hpdcache_req_is_uncacheable,
io: 1'b0,
wr_policy_hint: hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO
}
};

assign hpdcache_req_store = '{
addr_offset: cva6_req_i.address_index,
wdata: cva6_req_i.data_wdata,
op: hpdcache_pkg::HPDCACHE_REQ_STORE,
be: cva6_req_i.data_be,
size: cva6_req_i.data_size,
sid: hpdcache_req_sid_i,
tid: '0,
need_rsp: 1'b0,
phys_indexed: 1'b1,
addr_tag: cva6_req_i.address_tag,
pma: '{
uncacheable: hpdcache_req_is_uncacheable,
io: 1'b0,
wr_policy_hint: hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO
}
};

assign hpdcache_req_flush = '{
addr_offset: '0,
addr_tag: '0,
wdata: '0,
op:
InvalidateOnFlush
?
hpdcache_pkg::HPDCACHE_REQ_CMO_FLUSH_INVAL_ALL
:
hpdcache_pkg::HPDCACHE_REQ_CMO_FLUSH_ALL,
be: '0,
size: '0,
sid: hpdcache_req_sid_i,
tid: '0,
need_rsp: 1'b1,
phys_indexed: 1'b0,
pma: '{
uncacheable: 1'b0,
io: 1'b0,
wr_policy_hint: hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO
}
};

assign forward_store = cva6_req_i.data_req;
assign forward_amo = cva6_amo_req_i.req;

assign hpdcache_req_valid_o = forward_store | (forward_amo & ~amo_pending_q);
assign hpdcache_req_o.addr_offset = forward_amo ? amo_addr_offset : cva6_req_i.address_index;
assign hpdcache_req_o.wdata = forward_amo ? amo_data : cva6_req_i.data_wdata;
assign hpdcache_req_o.op = forward_amo ? amo_op : hpdcache_pkg::HPDCACHE_REQ_STORE;
assign hpdcache_req_o.be = forward_amo ? amo_data_be : cva6_req_i.data_be;
assign hpdcache_req_o.size = forward_amo ? cva6_amo_req_i.size : cva6_req_i.data_size;
assign hpdcache_req_o.sid = hpdcache_req_sid_i;
assign hpdcache_req_o.tid = forward_amo ? '1 : '0;
assign hpdcache_req_o.need_rsp = forward_amo;
assign hpdcache_req_o.phys_indexed = 1'b1;
assign hpdcache_req_o.addr_tag = forward_amo ? amo_tag : cva6_req_i.address_tag;
assign hpdcache_req_o.pma.uncacheable = hpdcache_req_is_uncacheable;
assign hpdcache_req_o.pma.io = 1'b0;
assign hpdcache_req_o.pma.wr_policy_hint = hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO;
assign hpdcache_req_valid_o = (forward_amo & ~amo_pending_q) | forward_store | forward_flush;

assign hpdcache_req = forward_amo ? hpdcache_req_amo :
forward_store ? hpdcache_req_store : hpdcache_req_flush;

assign hpdcache_req_abort_o = 1'b0; // unused on physically indexed requests
assign hpdcache_req_tag_o = '0; // unused on physically indexed requests
assign hpdcache_req_pma_o.uncacheable = 1'b0;
Expand Down Expand Up @@ -216,17 +332,21 @@ module cva6_hpdcache_if_adapter
(~cva6_amo_resp_o.ack & amo_pending_q);
end
end

// Assertions
// {{{
// pragma translate_off
forward_one_request_assert :
assert property (@(posedge clk_i) disable iff (rst_ni !== 1'b1) ($onehot0(
{forward_store, forward_amo, forward_flush}
)))
else $error("Only one request shall be forwarded");
// pragma translate_on
// }}}
end
// }}}
endgenerate
// }}}

// Assertions
// {{{
// pragma translate_off
forward_one_request_assert :
assert property (@(posedge clk_i) ($onehot0({forward_store, forward_amo})))
else $error("Only one request shall be forwarded");
// pragma translate_on
assign hpdcache_req_o = hpdcache_req;
// }}}
endmodule
83 changes: 46 additions & 37 deletions core/cache_subsystem/cva6_hpdcache_subsystem.sv
Original file line number Diff line number Diff line change
Expand Up @@ -189,43 +189,52 @@ module cva6_hpdcache_subsystem
// NumPorts + 1: Hardware Memory Prefetcher (hwpf)
localparam int HPDCACHE_NREQUESTERS = NumPorts + 2;

localparam hpdcache_pkg::hpdcache_user_cfg_t HPDcacheUserCfg = '{
nRequesters: HPDCACHE_NREQUESTERS,
paWidth: CVA6Cfg.PLEN,
wordWidth: CVA6Cfg.XLEN,
sets: CVA6Cfg.DCACHE_NUM_WORDS,
ways: CVA6Cfg.DCACHE_SET_ASSOC,
clWords: CVA6Cfg.DCACHE_LINE_WIDTH / CVA6Cfg.XLEN,
reqWords: 1,
reqTransIdWidth: CVA6Cfg.DcacheIdWidth,
reqSrcIdWidth: 3, // Up to 8 requesters
victimSel: hpdcache_pkg::HPDCACHE_VICTIM_RANDOM,
dataWaysPerRamWord: __minu(CVA6Cfg.DCACHE_SET_ASSOC, 128 / CVA6Cfg.XLEN),
dataSetsPerRam: CVA6Cfg.DCACHE_NUM_WORDS,
dataRamByteEnable: 1'b1,
accessWords: __maxu(CVA6Cfg.DCACHE_LINE_WIDTH / (2 * CVA6Cfg.XLEN), 1),
mshrSets: CVA6Cfg.NrLoadBufEntries < 16 ? 1 : CVA6Cfg.NrLoadBufEntries / 2,
mshrWays: CVA6Cfg.NrLoadBufEntries < 16 ? CVA6Cfg.NrLoadBufEntries : 2,
mshrWaysPerRamWord: CVA6Cfg.NrLoadBufEntries < 16 ? CVA6Cfg.NrLoadBufEntries : 2,
mshrSetsPerRam: CVA6Cfg.NrLoadBufEntries < 16 ? 1 : CVA6Cfg.NrLoadBufEntries / 2,
mshrRamByteEnable: 1'b1,
mshrUseRegbank: (CVA6Cfg.NrLoadBufEntries < 16),
refillCoreRspFeedthrough: 1'b1,
refillFifoDepth: 2,
wbufDirEntries: CVA6Cfg.WtDcacheWbufDepth,
wbufDataEntries: CVA6Cfg.WtDcacheWbufDepth,
wbufWords: 1,
wbufTimecntWidth: 3,
rtabEntries: 4,
flushEntries: 0,
flushFifoDepth: 0,
memAddrWidth: CVA6Cfg.AxiAddrWidth,
memIdWidth: CVA6Cfg.MEM_TID_WIDTH,
memDataWidth: CVA6Cfg.AxiDataWidth,
wtEn: 1'b1,
wbEn: 1'b0
};
function automatic hpdcache_pkg::hpdcache_user_cfg_t hpdcacheSetConfig();
hpdcache_pkg::hpdcache_user_cfg_t userCfg;
userCfg.nRequesters = HPDCACHE_NREQUESTERS;
userCfg.paWidth = CVA6Cfg.PLEN;
userCfg.wordWidth = CVA6Cfg.XLEN;
userCfg.sets = CVA6Cfg.DCACHE_NUM_WORDS;
userCfg.ways = CVA6Cfg.DCACHE_SET_ASSOC;
userCfg.clWords = CVA6Cfg.DCACHE_LINE_WIDTH / CVA6Cfg.XLEN;
userCfg.reqWords = 1;
userCfg.reqTransIdWidth = CVA6Cfg.DcacheIdWidth;
userCfg.reqSrcIdWidth = 3; // Up to 8 requesters
userCfg.victimSel = hpdcache_pkg::HPDCACHE_VICTIM_RANDOM;
userCfg.dataWaysPerRamWord = __minu(CVA6Cfg.DCACHE_SET_ASSOC, 128 / CVA6Cfg.XLEN);
userCfg.dataSetsPerRam = CVA6Cfg.DCACHE_NUM_WORDS;
userCfg.dataRamByteEnable = 1'b1;
userCfg.accessWords = __maxu(CVA6Cfg.AxiDataWidth / CVA6Cfg.XLEN, 1 /*reqWords*/);
userCfg.mshrSets = CVA6Cfg.NrLoadBufEntries < 16 ? 1 : CVA6Cfg.NrLoadBufEntries / 2;
userCfg.mshrWays = CVA6Cfg.NrLoadBufEntries < 16 ? CVA6Cfg.NrLoadBufEntries : 2;
userCfg.mshrWaysPerRamWord = CVA6Cfg.NrLoadBufEntries < 16 ? CVA6Cfg.NrLoadBufEntries : 2;
userCfg.mshrSetsPerRam = CVA6Cfg.NrLoadBufEntries < 16 ? 1 : CVA6Cfg.NrLoadBufEntries / 2;
userCfg.mshrRamByteEnable = 1'b1;
userCfg.mshrUseRegbank = (CVA6Cfg.NrLoadBufEntries < 16);
userCfg.refillCoreRspFeedthrough = 1'b1;
userCfg.refillFifoDepth = 2;
userCfg.wbufDirEntries = CVA6Cfg.WtDcacheWbufDepth;
userCfg.wbufDataEntries = CVA6Cfg.WtDcacheWbufDepth;
userCfg.wbufWords = 1;
userCfg.wbufTimecntWidth = 3;
userCfg.rtabEntries = 4;
/*FIXME we should add additional CVA6 config parameters (flushEntries)*/
userCfg.flushEntries = CVA6Cfg.WtDcacheWbufDepth;
/*FIXME we should add additional CVA6 config parameters (flushFifoDepth)*/
userCfg.flushFifoDepth = CVA6Cfg.WtDcacheWbufDepth;
userCfg.memAddrWidth = CVA6Cfg.AxiAddrWidth;
userCfg.memIdWidth = CVA6Cfg.MEM_TID_WIDTH;
userCfg.memDataWidth = CVA6Cfg.AxiDataWidth;
userCfg.wtEn =
(CVA6Cfg.DCacheType == config_pkg::HPDCACHE_WT) ||
(CVA6Cfg.DCacheType == config_pkg::HPDCACHE_WT_WB);
userCfg.wbEn =
(CVA6Cfg.DCacheType == config_pkg::HPDCACHE_WB) ||
(CVA6Cfg.DCacheType == config_pkg::HPDCACHE_WT_WB);
return userCfg;
endfunction

localparam hpdcache_pkg::hpdcache_user_cfg_t HPDcacheUserCfg = hpdcacheSetConfig();
localparam hpdcache_pkg::hpdcache_cfg_t HPDcacheCfg = hpdcache_pkg::hpdcacheBuildConfig(
HPDcacheUserCfg
);
Expand Down Expand Up @@ -407,7 +416,7 @@ module cva6_hpdcache_subsystem
// {{{
// pragma translate_off
initial begin : initial_assertions
assert (HPDcacheCfg.u.reqSrcIdWidth >= $clog2(HPDCACHE_NREQUESTERS))
assert (HPDcacheCfg.u.reqSrcIdWidth >= $clog2(HPDcacheCfg.u.nRequesters))
else $fatal(1, "HPDCACHE_REQ_SRC_ID_WIDTH is not wide enough");
assert (CVA6Cfg.MEM_TID_WIDTH <= CVA6Cfg.AxiIdWidth)
else $fatal(1, "MEM_TID_WIDTH shall be less or equal to the AxiIdWidth");
Expand Down
Loading

0 comments on commit db568f3

Please sign in to comment.