Add option to improve load perf in case OBIVersion==0 or no MMU

This commit is contained in:
Casamatta Yannick 2025-02-20 14:02:42 +01:00 committed by JeanRochCoulon
parent ff2dfa4335
commit 15f0be1934
23 changed files with 351 additions and 331 deletions

View file

@ -108,91 +108,132 @@ module cva6_hpdcache_if_adapter
logic [1:0] load_data_size;
if (CVA6Cfg.XLEN == 64) begin
assign load_data_size = ariane_pkg::size_gen(load_req_i.be);
assign load_data_size = ariane_pkg::size_gen(hpdcache_req.be);
end else begin
assign load_data_size = ariane_pkg::size_gen_32(load_req_i.be);
assign load_data_size = ariane_pkg::size_gen_32(hpdcache_req.be);
end
// Request forwarding
assign hpdcache_req_valid_o = load_req_i.req;
assign hpdcache_req.addr_offset = load_req_i.address_index;
// Request forwarding OBI channel A
assign hpdcache_req.wdata = '0;
assign hpdcache_req.op = hpdcache_pkg::HPDCACHE_REQ_LOAD;
assign hpdcache_req.be = load_req_i.be;
assign hpdcache_req.size = load_data_size;
assign hpdcache_req.sid = hpdcache_req_sid_i;
assign hpdcache_req.tid = load_req_i.aid;
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 = load_req_i.kill_req;
assign hpdcache_req_tag_o = obi_load_req_i.a.addr[CVA6Cfg.DCACHE_TAG_WIDTH +
if (CVA6Cfg.MmuPresent) begin
// When MMu is present request is done in 2 phases, s0: index, s1:tag
assign hpdcache_req.phys_indexed = 1'b0;
assign hpdcache_req_valid_o = load_req_i.req;
assign hpdcache_req.addr_offset = load_req_i.address_index;
assign hpdcache_req.addr_tag = '0; // unused on virtually indexed request
assign hpdcache_req.be = load_req_i.be;
assign hpdcache_req.tid = load_req_i.aid;
assign hpdcache_req.pma.uncacheable = 1'b0; // unused on virtually indexed request
assign hpdcache_req.pma.io = 1'b0; // unused on virtually indexed request
assign hpdcache_req.pma.wr_policy_hint = hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO; // unused on virtually indexed request
assign hpdcache_req_pma_o.uncacheable = !obi_load_req_i.a.a_optional.memtype[1];
assign hpdcache_req_pma_o.io = 1'b0;
assign hpdcache_req_pma_o.wr_policy_hint = hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO;
assign hpdcache_req_tag_o = obi_load_req_i.a.addr[CVA6Cfg.DCACHE_TAG_WIDTH +
CVA6Cfg.DCACHE_INDEX_WIDTH-1 :
CVA6Cfg.DCACHE_INDEX_WIDTH];
assign hpdcache_req_pma_o.uncacheable = !obi_load_req_i.a.a_optional.memtype[1];
assign hpdcache_req_pma_o.io = 1'b0;
assign hpdcache_req_pma_o.wr_policy_hint = hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO;
assign load_rsp_o.gnt = hpdcache_req_ready_i;
assign obi_load_rsp_o.gnt = 1'b1; //if hpdcache is always ready to accept tag in s1
assign load_rsp_o.gnt = hpdcache_req_ready_i;
end else begin
// When MMu is not present request is done in 1 phases, s0: index+tag
assign hpdcache_req.phys_indexed = 1'b1;
assign hpdcache_req_valid_o = obi_load_req_i.req;
assign hpdcache_req.addr_offset = obi_load_req_i.a.addr[CVA6Cfg.DCACHE_INDEX_WIDTH-1:0];
assign hpdcache_req.addr_tag = obi_load_req_i.a.addr[CVA6Cfg.DCACHE_TAG_WIDTH +
CVA6Cfg.DCACHE_INDEX_WIDTH-1 :
CVA6Cfg.DCACHE_INDEX_WIDTH];
assign hpdcache_req.be = obi_load_req_i.a.be;
assign hpdcache_req.tid = obi_load_req_i.a.aid;
assign hpdcache_req.pma.uncacheable = !obi_load_req_i.a.a_optional.memtype[1];
assign hpdcache_req.pma.io = 1'b0;
assign hpdcache_req.pma.wr_policy_hint = hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO;
obi_load_rsp_t obi_load_rsp_q, obi_load_rsp_d;
logic resp_while_request;
logic buffered_valid;
logic killed_in_s1;
assign hpdcache_req_pma_o.uncacheable = '0; // unused on physically indexed request
assign hpdcache_req_pma_o.io = '0; // unused on physically indexed request
assign hpdcache_req_pma_o.wr_policy_hint = hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO;
; // unused on physically indexed request
assign hpdcache_req_tag_o = '0; // unused on physically indexed request
assign obi_load_rsp_o.gnt = 1'b1; //if hpdcache is always ready to accept tag
assign obi_load_rsp_o.gntpar = 1'b0;
assign obi_load_rsp_o.rvalid = hpdcache_rsp_valid_i;
assign obi_load_rsp_o.rvalidpar = !hpdcache_rsp_valid_i;
assign obi_load_rsp_o.r.rid = hpdcache_rsp_i.tid;
assign obi_load_rsp_o.r.r_optional.exokay = '0;
assign obi_load_rsp_o.r.r_optional.rchk = '0;
assign obi_load_rsp_o.r.err = '0;
assign obi_load_rsp_o.r.rdata = hpdcache_rsp_i.rdata;
assign obi_load_rsp_o.r.r_optional.ruser = '0;
assign obi_load_rsp_d.gnt = '0; //unused
assign obi_load_rsp_d.gntpar = '0; //unused
assign obi_load_rsp_d.rvalid = hpdcache_rsp_valid_i;
assign obi_load_rsp_d.rvalidpar = !hpdcache_rsp_valid_i;
assign obi_load_rsp_d.r.rid = hpdcache_rsp_i.tid;
assign obi_load_rsp_d.r.r_optional.exokay = '0;
assign obi_load_rsp_d.r.r_optional.rchk = '0;
assign obi_load_rsp_d.r.err = '0;
assign obi_load_rsp_d.r.rdata = hpdcache_rsp_i.rdata;
assign obi_load_rsp_d.r.r_optional.ruser = '0;
assign resp_while_request = (CVA6Cfg.ObiVersion != 0 && (obi_load_req_i.a.aid == hpdcache_rsp_i.tid) && (obi_load_req_i.req && obi_load_rsp_o.gnt)) ? hpdcache_rsp_valid_i : 1'b0;
assign killed_in_s1 = (CVA6Cfg.ObiVersion != 0 && (obi_load_req_i.a.aid == hpdcache_rsp_i.tid) && (load_req_i.kill_req)) ? 1'b1 : 1'b0;
always @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
buffered_valid <= 1'b0;
obi_load_rsp_q <= 1'b0;
end else begin
if (resp_while_request) begin
obi_load_rsp_q <= obi_load_rsp_d;
buffered_valid <= 1'b1;
end
if (buffered_valid) begin
buffered_valid <= 1'b0;
end
end
assign obi_load_rsp_o.gnt = obi_load_req_i.req && hpdcache_req_ready_i;
assign load_rsp_o.gnt = 1'b0;
end
// Response forwarding
assign obi_load_rsp_o.rvalid = resp_while_request ? '0 : (buffered_valid ? 1'b1 : (killed_in_s1 ? 1'b0 : hpdcache_rsp_valid_i));
assign obi_load_rsp_o.rvalidpar = !obi_load_rsp_o.rvalid;
assign obi_load_rsp_o.r.rid = resp_while_request ? '0 : (buffered_valid ? obi_load_rsp_q.r.rid : obi_load_rsp_d.r.rid);
assign obi_load_rsp_o.r.r_optional.exokay = resp_while_request ? '0 : (buffered_valid ? obi_load_rsp_q.r.r_optional.exokay : obi_load_rsp_d.r.r_optional.exokay);
assign obi_load_rsp_o.r.r_optional.rchk = resp_while_request ? '0 : (buffered_valid ? obi_load_rsp_q.r.r_optional.rchk : obi_load_rsp_d.r.r_optional.rchk);
assign obi_load_rsp_o.r.err = resp_while_request ? '0 : (buffered_valid ? obi_load_rsp_q.r.err : obi_load_rsp_d.r.err);
assign obi_load_rsp_o.r.rdata = resp_while_request ? '0 : (buffered_valid ? obi_load_rsp_q.r.rdata : obi_load_rsp_d.r.rdata);
assign obi_load_rsp_o.r.r_optional.ruser = resp_while_request ? '0 : (buffered_valid ? obi_load_rsp_q.r.r_optional.ruser : obi_load_rsp_d.r.r_optional.ruser);
assign obi_load_rsp_o.gntpar = !obi_load_rsp_o.gnt;
// Response forwarding OBI channel R
if (!CVA6Cfg.MmuPresent || (CVA6Cfg.ObiVersion == config_pkg::OBI_NOT_COMPLIANT)) begin
assign obi_load_rsp_o.rvalid = hpdcache_rsp_valid_i;
assign obi_load_rsp_o.rvalidpar = !hpdcache_rsp_valid_i;
assign obi_load_rsp_o.r.rid = hpdcache_rsp_i.tid;
assign obi_load_rsp_o.r.r_optional.exokay = '0;
assign obi_load_rsp_o.r.r_optional.rchk = '0;
assign obi_load_rsp_o.r.err = '0;
assign obi_load_rsp_o.r.rdata = hpdcache_rsp_i.rdata;
assign obi_load_rsp_o.r.r_optional.ruser = '0;
end else begin
// In case we have a MMU and we want a compliance to OBI protocol, we need to delay response in case of HIT.
obi_load_rsp_t obi_load_rsp_q, obi_load_rsp_d;
logic resp_while_request;
logic buffered_valid;
logic killed_in_s1;
assign obi_load_rsp_d.gnt = '0; //unused
assign obi_load_rsp_d.gntpar = '0; //unused
assign obi_load_rsp_d.rvalid = hpdcache_rsp_valid_i;
assign obi_load_rsp_d.rvalidpar = !hpdcache_rsp_valid_i;
assign obi_load_rsp_d.r.rid = hpdcache_rsp_i.tid;
assign obi_load_rsp_d.r.r_optional.exokay = '0;
assign obi_load_rsp_d.r.r_optional.rchk = '0;
assign obi_load_rsp_d.r.err = '0;
assign obi_load_rsp_d.r.rdata = hpdcache_rsp_i.rdata;
assign obi_load_rsp_d.r.r_optional.ruser = '0;
assign resp_while_request = (obi_load_req_i.a.aid == hpdcache_rsp_i.tid) && obi_load_req_i.req && obi_load_rsp_o.gnt ? hpdcache_rsp_valid_i : 1'b0;
assign killed_in_s1 = (obi_load_req_i.a.aid == hpdcache_rsp_i.tid) ? load_req_i.kill_req : 1'b0; //maybe can be managed by need_resp = 0
always @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
buffered_valid <= 1'b0;
obi_load_rsp_q <= 1'b0;
end else begin
if (resp_while_request) begin
obi_load_rsp_q <= obi_load_rsp_d;
buffered_valid <= 1'b1;
end
if (buffered_valid) begin
buffered_valid <= 1'b0;
end
end
end
assign obi_load_rsp_o.rvalid = resp_while_request ? '0 : (buffered_valid ? 1'b1 : (killed_in_s1 ? 1'b0 : hpdcache_rsp_valid_i));
assign obi_load_rsp_o.rvalidpar = !obi_load_rsp_o.rvalid;
assign obi_load_rsp_o.r.rid = resp_while_request ? '0 : (buffered_valid ? obi_load_rsp_q.r.rid : obi_load_rsp_d.r.rid);
assign obi_load_rsp_o.r.r_optional.exokay = resp_while_request ? '0 : (buffered_valid ? obi_load_rsp_q.r.r_optional.exokay : obi_load_rsp_d.r.r_optional.exokay);
assign obi_load_rsp_o.r.r_optional.rchk = resp_while_request ? '0 : (buffered_valid ? obi_load_rsp_q.r.r_optional.rchk : obi_load_rsp_d.r.r_optional.rchk);
assign obi_load_rsp_o.r.err = resp_while_request ? '0 : (buffered_valid ? obi_load_rsp_q.r.err : obi_load_rsp_d.r.err);
assign obi_load_rsp_o.r.rdata = resp_while_request ? '0 : (buffered_valid ? obi_load_rsp_q.r.rdata : obi_load_rsp_d.r.rdata);
assign obi_load_rsp_o.r.r_optional.ruser = resp_while_request ? '0 : (buffered_valid ? obi_load_rsp_q.r.r_optional.ruser : obi_load_rsp_d.r.r_optional.ruser);
end
// Assertions
// {{{
@ -517,8 +558,8 @@ else if (IsZcmtPort == 1'b1) begin : zcmt_port_gen
assign obi_amo_valid = hpdcache_rsp_valid_i && (hpdcache_rsp_i.tid == '1);
//OBI
assign obi_store_rsp_o.gnt = hpdcache_req_ready_i & forward_store;
assign obi_store_rsp_o.gntpar = !(hpdcache_req_ready_i & forward_store);
assign obi_store_rsp_o.gnt = hpdcache_req_ready_i & obi_store_req_i.req;
assign obi_store_rsp_o.gntpar = !obi_store_rsp_o.gnt;
assign obi_store_rsp_o.rvalid = obi_store_valid;
assign obi_store_rsp_o.rvalidpar = !obi_store_valid;
assign obi_store_rsp_o.r.rid = '0;
@ -529,7 +570,7 @@ else if (IsZcmtPort == 1'b1) begin : zcmt_port_gen
assign obi_store_rsp_o.r.r_optional.ruser = '0;
assign obi_amo_rsp_o.gnt = hpdcache_req_ready_i & forward_amo;
assign obi_amo_rsp_o.gntpar = !(hpdcache_req_ready_i & forward_amo);
assign obi_amo_rsp_o.gntpar = !obi_amo_rsp_o.gnt;
assign obi_amo_rsp_o.rvalid = obi_amo_valid;
assign obi_amo_rsp_o.rvalidpar = !obi_amo_valid;
assign obi_amo_rsp_o.r.rid = '0;

View file

@ -30,7 +30,7 @@ package build_config_pkg;
int unsigned PtLevels = (CVA6Cfg.XLEN == 64) ? 3 : 2;
config_pkg::cva6_cfg_t cfg;
cfg.ObiVersion = 1; //FIXME CVA6Cfg.ObiVersion; //0 not compliant
cfg.ObiVersion = CVA6Cfg.ObiVersion;
cfg.XLEN = CVA6Cfg.XLEN;
cfg.VLEN = CVA6Cfg.VLEN;
cfg.PLEN = (CVA6Cfg.XLEN == 32) ? 34 : 56;
@ -57,7 +57,7 @@ package build_config_pkg;
cfg.AxiIdWidth = CVA6Cfg.AxiIdWidth;
cfg.AxiUserWidth = CVA6Cfg.AxiUserWidth;
cfg.MEM_TID_WIDTH = CVA6Cfg.AxiIdWidth; //CVA6Cfg.MemTidWidth; FIXME HPDCACHE related
cfg.NrLoadBufEntries = cfg.ObiVersion == 0 ? CVA6Cfg.NrLoadBufEntries : 1;
cfg.NrLoadBufEntries = cfg.ObiVersion == config_pkg::OBI_NOT_COMPLIANT ? CVA6Cfg.NrLoadBufEntries : 1; //FIXME: To fix in order response
cfg.RVF = CVA6Cfg.RVF;
cfg.RVD = CVA6Cfg.RVD;
cfg.XF16 = CVA6Cfg.XF16;

View file

@ -15,6 +15,13 @@ package config_pkg;
localparam int unsigned ILEN = 32;
localparam int unsigned NRET = 1;
// ---------------
// OBI
// ---------------
localparam int unsigned OBI_NOT_COMPLIANT = 0;
localparam int unsigned OBI_V1_6 = 1600;
/// The NoC type is a top-level parameter, hence we need a bit more
/// information on what protocol those type parameters are supporting.
/// Currently two values are supported"

View file

@ -104,7 +104,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(0),
NrStorePipeRegs: int'(0),
DcacheIdWidth: int'(1),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(1) //FIXME
};

View file

@ -104,7 +104,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(0),
NrStorePipeRegs: int'(0),
DcacheIdWidth: int'(1),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(1) //FIXME
};

View file

@ -156,7 +156,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};

View file

@ -156,7 +156,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};
endpackage

View file

@ -155,7 +155,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};

View file

@ -156,7 +156,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};

View file

@ -159,7 +159,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};

View file

@ -159,7 +159,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};

View file

@ -166,7 +166,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};

View file

@ -165,7 +165,9 @@ package cva6_config_pkg;
SharedTlbDepth: int'(64),
NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth)
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};
endpackage

View file

@ -159,7 +159,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};

View file

@ -159,7 +159,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};

View file

@ -159,7 +159,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};

View file

@ -159,7 +159,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};

View file

@ -159,7 +159,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(CVA6ConfigNrLoadPipeRegs),
NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs),
DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};
endpackage

View file

@ -111,7 +111,7 @@ package cva6_config_pkg;
NrLoadPipeRegs: int'(0),
NrStorePipeRegs: int'(0),
DcacheIdWidth: int'(1),
ObiVersion: int'(1),
ObiVersion: int'(config_pkg::OBI_V1_6),
PipelineOnly: bit'(0)
};

View file

@ -337,39 +337,19 @@ module load_store_unit
assign pmp_fetch_arsp.fetch_paddr = CVA6Cfg.PLEN'(fetch_areq_i.fetch_vaddr);
end
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
if (~rst_ni) begin
lsu_paddr <= '0;
pmp_exception <= '0;
pmp_translation_valid <= 1'b0;
end else begin
if (CVA6Cfg.VLEN >= CVA6Cfg.PLEN) begin : gen_virtual_physical_address_lsu
lsu_paddr <= mmu_vaddr[CVA6Cfg.PLEN-1:0];
end else begin
lsu_paddr <= CVA6Cfg.PLEN'(mmu_vaddr);
end
pmp_exception <= misaligned_exception;
pmp_translation_valid <= translation_req;
end
assign pmp_exception = misaligned_exception;
assign pmp_translation_valid = translation_req;
if (CVA6Cfg.VLEN > CVA6Cfg.PLEN) begin
assign lsu_paddr = mmu_vaddr[CVA6Cfg.PLEN-1:0];
end else begin
assign lsu_paddr = CVA6Cfg.PLEN'(mmu_vaddr);
end
// dcache interface of PTW not used
assign dcache_req_ports_o[0].address_index = '0;
assign dcache_req_ports_o[0].address_tag = '0;
assign dcache_req_ports_o[0].data_wdata = '0;
assign dcache_req_ports_o[0].data_req = 1'b0;
assign dcache_req_ports_o[0].data_be = '1;
assign dcache_req_ports_o[0].data_size = 2'b11;
assign dcache_req_ports_o[0].data_we = 1'b0;
assign dcache_req_ports_o[0].kill_req = '0;
assign dcache_req_ports_o[0].tag_valid = 1'b0;
assign itlb_miss_o = 1'b0;
assign dtlb_miss_o = 1'b0;
assign dtlb_ppn = lsu_paddr[CVA6Cfg.PLEN-1:12];
assign dtlb_hit = 1'b1;
assign itlb_miss_o = 1'b0;
assign dtlb_miss_o = 1'b0;
assign dtlb_ppn = lsu_paddr[CVA6Cfg.PLEN-1:12];
assign dtlb_hit = 1'b1;
end

View file

@ -116,7 +116,6 @@ module load_unit
logic ldbuf_empty, ldbuf_full;
ldbuf_id_t ldbuf_free_index;
logic ldbuf_w, ldbuf_w_q;
ldbuf_t ldbuf_wdata;
ldbuf_id_t ldbuf_windex, ldbuf_windex_q;
logic ldbuf_r;
ldbuf_t ldbuf_rdata;
@ -124,9 +123,13 @@ module load_unit
ldbuf_id_t ldbuf_last_id_q;
logic kill_req_d, kill_req_q;
logic [CVA6Cfg.PLEN-1:0] paddr_q;
logic [(CVA6Cfg.XLEN/8)-1:0] be_q;
assign ldbuf_full = &ldbuf_valid_q;
assign ldbuf_full = &ldbuf_valid_q && !(LDBUF_FALLTHROUGH && ldbuf_r);
//
// buffer of outstanding loads
@ -163,7 +166,7 @@ module load_unit
ldbuf_valid_d[ldbuf_rindex] = 1'b0;
end
// Free on exception
if ((ldbuf_w_q && ex_i.valid)) begin
if (CVA6Cfg.MmuPresent && (ldbuf_w_q && ex_i.valid)) begin
ldbuf_valid_d[ldbuf_windex_q] = 1'b0;
end
// Track a new outstanding operation in the load buffer
@ -214,6 +217,10 @@ module load_unit
assign ex_o.tinst = CVA6Cfg.RVH ? ex_i.tinst : '0;
assign ex_o.gva = CVA6Cfg.RVH ? ex_i.gva : 1'b0;
logic [CVA6Cfg.PLEN-1:0] paddr;
assign paddr = CVA6Cfg.MmuPresent ? paddr_i : lsu_ctrl_i.vaddr; //paddr_i is delayed in s1, but no s1 in mode no MMU
// CHECK PMA regions
logic paddr_is_cacheable, paddr_is_cacheable_q; // asserted if physical address is non-cacheable
@ -232,7 +239,6 @@ module load_unit
logic stall_ni;
assign not_commit_time = commit_tran_id_i != lsu_ctrl_i.trans_id;
assign inflight_stores = (!dcache_wbuffer_not_ni_i || !store_buffer_empty_i);
assign stall_ni = (inflight_stores || not_commit_time) && (paddr_nonidempotent && CVA6Cfg.NonIdemPotenceEn);
typedef enum logic [1:0] {
TRANSPARENT,
@ -243,84 +249,86 @@ module load_unit
// ---------------
// Load Control
// ---------------
logic ex_s0, ex_s1, kill_s1;
assign load_req_o.kill_req = kill_req_q || (ldbuf_w_q && ex_i.valid) || flush_i;
logic stall_obi, stall_translation;
logic data_req, data_rvalid;
// custom protocol FSM (combi)
assign load_req_o.kill_req = kill_req_q || kill_s1;
assign stall_ni = (inflight_stores || not_commit_time) && (paddr_nonidempotent && CVA6Cfg.NonIdemPotenceEn);
assign stall_obi = (obi_a_state_q == REGISTRED); //&& !obi_load_rsp_i.gnt;
assign stall_translation = CVA6Cfg.MmuPresent ? translation_req_o && !dtlb_hit_i : 1'b0;
assign ex_s0 = CVA6Cfg.MmuPresent && stall_translation && ex_i.valid;
assign ex_s1 = ((CVA6Cfg.MmuPresent ? ldbuf_w_q : valid_i) && ex_i.valid);
assign kill_s1 = CVA6Cfg.MmuPresent ? ex_s1 : 1'b0;
assign data_rvalid = obi_load_rsp_i.rvalid && !ldbuf_flushed_q[ldbuf_rindex];
assign data_req = (CVA6Cfg.MmuPresent ? ldbuf_w_q && !ex_s1 : ldbuf_w);
always_comb begin : p_fsm_common
// default assignment
load_req_o.req = '0;
kill_req_d = 1'b0;
ldbuf_w = 1'b0;
pop_ld_o = 1'b0;
translation_req_o = 1'b0;
//response
trans_id_o = 1'b0;
trans_id_o = lsu_ctrl_i.trans_id;
valid_o = 1'b0;
ex_o.valid = 1'b0;
pop_ld_o = 1'b0; // release lsu_bypass fifo
if (!flush_i) begin
//EXCEPTION PENDING in s1
if (ldbuf_w_q && ex_i.valid) begin
// exceptions can retire out-of-order -> but we need to give priority to non-excepting load and stores
// we got an rvalid and it's corresponding request was not flushed
if ((obi_load_rsp_i.rvalid && !ldbuf_flushed_q[ldbuf_rindex]) && (ldbuf_rindex != ldbuf_windex_q)) begin
trans_id_o = ldbuf_q[ldbuf_rindex].trans_id;
valid_o = 1'b1;
ex_o.valid = 1'b0;
// retire load that cause exception (misalign)
end else begin
trans_id_o = ldbuf_q[ldbuf_windex_q].trans_id;
valid_o = 1'b1;
ex_o.valid = 1'b1;
end
//NO EXCEPTION PENDING in s0 (page fault)
end else if (valid_i && ex_i.valid) begin
trans_id_o = lsu_ctrl_i.trans_id;
valid_o = 1'b1;
ex_o.valid = 1'b1;
pop_ld_o = 1'b1; // release lsu_bypass fifo
end else begin
// REQUEST
if (valid_i && (!ldbuf_full)) begin
translation_req_o = 1'b1;
if (!page_offset_matches_i) begin
load_req_o.req = 1'b1;
if (load_rsp_i.gnt) begin
if ((CVA6Cfg.MmuPresent && !dtlb_hit_i) || stall_ni || (obi_a_state_q == REGISTRED)) begin
kill_req_d = 1'b1; // next cycle kill s1
end else begin
ldbuf_w = 1'b1; // record request into outstanding load fifo
pop_ld_o = 1'b1; // release lsu_bypass fifo
end
end
// REQUEST
if (valid_i) begin
translation_req_o = 1'b1;
if (!page_offset_matches_i) begin
load_req_o.req = 1'b1;
if (!CVA6Cfg.MmuPresent || load_rsp_i.gnt) begin
if (stall_translation || stall_ni || stall_obi || ldbuf_full || flush_i) begin
kill_req_d = 1'b1; // MmuPresent only: next cycle is s2 but we need to kill because not ready to send tag
end else begin
ldbuf_w = CVA6Cfg.MmuPresent ? 1'b1 : !ex_s1; // record request into outstanding load fifo and trigger OBI request
pop_ld_o = !ex_s1; // release lsu_bypass fifo
end
end
// RETIRE LOAD
// we got an rvalid and it's corresponding request was not flushed
if (obi_load_rsp_i.rvalid && !ldbuf_flushed_q[ldbuf_rindex]) begin
trans_id_o = ldbuf_q[ldbuf_rindex].trans_id;
valid_o = 1'b1;
ex_o.valid = 1'b0;
end
end
end
// RETIRE LOAD
// we got an rvalid and it's corresponding request was not flushed
if (data_rvalid) begin
trans_id_o = ldbuf_q[ldbuf_rindex].trans_id;
valid_o = 1'b1;
ex_o.valid = 1'b0;
// RETIRE EXCEPTION (low priority)
end else if (ex_s1) begin
trans_id_o = CVA6Cfg.MmuPresent ? ldbuf_q[ldbuf_windex_q].trans_id : lsu_ctrl_i.trans_id;
valid_o = 1'b1;
ex_o.valid = 1'b1;
pop_ld_o = 1'b1; // release lsu_bypass fifo
// RETIRE EXCEPTION (low priority)
end else if (CVA6Cfg.MmuPresent && ex_s0) begin
trans_id_o = lsu_ctrl_i.trans_id;
valid_o = 1'b1;
ex_o.valid = 1'b1;
pop_ld_o = 1'b1; // release lsu_bypass fifo
end
end
//default obi state registred
//default obi state registred
assign obi_load_req_o.reqpar = !obi_load_req_o.req;
assign obi_load_req_o.a.addr = obi_a_state_q == TRANSPARENT ? paddr_i : paddr_q;
assign obi_load_req_o.a.addr = obi_a_state_q == TRANSPARENT ? paddr : paddr_q;
assign obi_load_req_o.a.we = '0;
assign obi_load_req_o.a.be = be_q;
assign obi_load_req_o.a.be = (!CVA6Cfg.MmuPresent && (obi_a_state_q == TRANSPARENT)) ? lsu_ctrl_i.be : be_q;
assign obi_load_req_o.a.wdata = '0;
assign obi_load_req_o.a.aid = ldbuf_windex_q;
assign obi_load_req_o.a.aid = (!CVA6Cfg.MmuPresent && (obi_a_state_q == TRANSPARENT)) ? ldbuf_windex : ldbuf_windex_q;
assign obi_load_req_o.a.a_optional.auser = '0;
assign obi_load_req_o.a.a_optional.wuser = '0;
assign obi_load_req_o.a.a_optional.atop = '0;
assign obi_load_req_o.a.a_optional.memtype[0] = '0;
assign obi_load_req_o.a.a_optional.memtype[1] = paddr_is_cacheable_q;
assign obi_load_req_o.a.a_optional.memtype[1]= (!CVA6Cfg.MmuPresent && (obi_a_state_q == TRANSPARENT)) ? paddr_is_cacheable : paddr_is_cacheable_q;
assign obi_load_req_o.a.a_optional.mid = '0;
assign obi_load_req_o.a.a_optional.prot = '0;
assign obi_load_req_o.a.a_optional.dbg = '0;
@ -336,7 +344,7 @@ module load_unit
unique case (obi_a_state_q)
TRANSPARENT: begin
if (ldbuf_w_q && !(ldbuf_w_q && ex_i.valid)) begin
if (data_req) begin
obi_load_req_o.req = 1'b1;
if (!obi_load_rsp_i.gnt) begin
obi_a_state_d = REGISTRED;
@ -369,13 +377,17 @@ module load_unit
ldbuf_windex_q <= '0;
ldbuf_w_q <= '0;
end else begin
if (obi_a_state_q == TRANSPARENT) begin
paddr_q <= paddr;
be_q <= lsu_ctrl_i.be;
paddr_is_cacheable_q <= paddr_is_cacheable;
end
obi_a_state_q <= obi_a_state_d;
paddr_q <= paddr_i;
be_q <= lsu_ctrl_i.be;
paddr_is_cacheable_q <= paddr_is_cacheable;
kill_req_q <= kill_req_d;
//if (!ex_s1) begin
ldbuf_windex_q <= ldbuf_windex;
ldbuf_w_q <= ldbuf_w;
//end
end
end

View file

@ -78,7 +78,7 @@ module store_buffer
logic [$clog2(DEPTH_COMMIT)-1:0] commit_read_pointer_n, commit_read_pointer_q;
logic [$clog2(DEPTH_COMMIT)-1:0] commit_write_pointer_n, commit_write_pointer_q;
assign store_buffer_empty_o = (speculative_status_cnt_q == 0) & no_st_pending_o;
assign store_buffer_empty_o = (speculative_status_cnt_q == 0) & !valid_i & no_st_pending_o;
// ----------------------------------------
// Speculative Queue - Core Interface
// ----------------------------------------
@ -127,23 +127,24 @@ module store_buffer
end
// we are ready if the speculative and the commit queue have a space left
ready_o = (speculative_status_cnt_n < (DEPTH_SPEC)) || commit_i;
ready_o = CVA6Cfg.MmuPresent ? (speculative_status_cnt_n < (DEPTH_SPEC)) || commit_i : speculative_status_cnt_q < (DEPTH_SPEC);
end
// ----------------------------------------
// Commit Queue - Memory Interface
// ----------------------------------------
logic direct_req_from_speculative;
// we will never kill a request in the store buffer since we already know that the translation is valid
// e.g.: a kill request will only be necessary if we are not sure if the requested memory address will result in a TLB fault
assign rvfi_mem_paddr_o = speculative_queue_q[speculative_read_pointer_q].address;
assign rvfi_mem_paddr_o = direct_req_from_speculative ? speculative_queue_q[speculative_read_pointer_q].address : commit_queue_n[commit_read_pointer_n].address;
assign obi_store_req_o.reqpar = !obi_store_req_o.req;
assign obi_store_req_o.a.addr = commit_queue_q[commit_read_pointer_q].address;
assign obi_store_req_o.a.addr = direct_req_from_speculative ? speculative_queue_q[speculative_read_pointer_q].address : commit_queue_q[commit_read_pointer_q].address;
assign obi_store_req_o.a.we = 1'b1;
assign obi_store_req_o.a.be = commit_queue_q[commit_read_pointer_q].be;
assign obi_store_req_o.a.wdata = commit_queue_q[commit_read_pointer_q].data;
assign obi_store_req_o.a.be = direct_req_from_speculative ? speculative_queue_q[speculative_read_pointer_q].be : commit_queue_q[commit_read_pointer_q].be;
assign obi_store_req_o.a.wdata = direct_req_from_speculative ? speculative_queue_q[speculative_read_pointer_q].data : commit_queue_q[commit_read_pointer_q].data;
assign obi_store_req_o.a.aid = '0;
assign obi_store_req_o.a.a_optional.auser = '0;
assign obi_store_req_o.a.a_optional.wuser = '0;
@ -152,7 +153,8 @@ module store_buffer
assign obi_store_req_o.a.a_optional.memtype[1] = config_pkg::is_inside_cacheable_regions(
CVA6Cfg,
{
{64 - CVA6Cfg.PLEN{1'b0}}, commit_queue_q[commit_read_pointer_q].address
{64 - CVA6Cfg.PLEN{1'b0}},
direct_req_from_speculative ? speculative_queue_q[speculative_read_pointer_q].address : commit_queue_q[commit_read_pointer_q].address
} //TO DO CHECK GRANULARITY
);
assign obi_store_req_o.a.a_optional.mid = '0;
@ -165,19 +167,20 @@ module store_buffer
always_comb begin : store_if
automatic logic [$clog2(DEPTH_COMMIT):0] commit_status_cnt;
commit_status_cnt = commit_status_cnt_q;
commit_status_cnt = commit_status_cnt_q;
commit_ready_o = (commit_status_cnt_q < DEPTH_COMMIT);
commit_ready_o = (commit_status_cnt_q < DEPTH_COMMIT);
// no store is pending if we don't have any element in the commit queue e.g.: it is empty
no_st_pending_o = (commit_status_cnt_q == 0);
no_st_pending_o = (commit_status_cnt_q == 0);
// default assignments
commit_read_pointer_n = commit_read_pointer_q;
commit_write_pointer_n = commit_write_pointer_q;
commit_read_pointer_n = commit_read_pointer_q;
commit_write_pointer_n = commit_write_pointer_q;
commit_queue_n = commit_queue_q;
commit_queue_n = commit_queue_q;
obi_store_req_o.req = 1'b0;
obi_store_req_o.rready = 1'b1;
obi_store_req_o.req = 1'b0;
obi_store_req_o.rready = 1'b1;
direct_req_from_speculative = 1'b0;
// there should be no commit when we are flushing
// if the entry in the commit queue is valid and not speculative anymore we can issue this instruction
@ -190,12 +193,15 @@ module store_buffer
commit_read_pointer_n = commit_read_pointer_q + 1'b1;
commit_status_cnt--;
end
end else if (commit_i && speculative_queue_q[speculative_read_pointer_q].valid && (commit_write_pointer_q == speculative_read_pointer_q) && !stall_st_pending_i) begin
obi_store_req_o.req = 1'b1;
direct_req_from_speculative = 1'b1;
end
// we ignore the rvalid signal for now as we assume that the store
// happened if we got a grant
// shift the store request from the speculative buffer to the non-speculative
if (commit_i) begin
if (commit_i && !(obi_store_rsp_i.gnt && direct_req_from_speculative)) begin
commit_queue_n[commit_write_pointer_q] = speculative_queue_q[speculative_read_pointer_q];
commit_write_pointer_n = commit_write_pointer_n + 1'b1;
commit_status_cnt++;

View file

@ -116,134 +116,103 @@ module store_unit
endfunction
// it doesn't matter what we are writing back as stores don't return anything
assign result_o = lsu_ctrl_i.data;
assign result_o = lsu_ctrl_i.data;
enum logic [1:0] {
IDLE,
VALID_STORE,
WAIT_TRANSLATION,
WAIT_STORE_READY
}
state_d, state_q;
// directly forward exception fields (valid bit is set below)
assign ex_o.cause = ex_i.cause;
assign ex_o.tval = ex_i.tval;
assign ex_o.tval2 = CVA6Cfg.RVH ? ex_i.tval2 : '0;
assign ex_o.tinst = CVA6Cfg.RVH ? ex_i.tinst : '0;
assign ex_o.gva = CVA6Cfg.RVH ? ex_i.gva : 1'b0;
// store buffer control signals
logic st_ready;
logic st_valid;
logic st_valid_without_flush;
logic instr_is_amo;
assign instr_is_amo = is_amo(lsu_ctrl_i.operation);
// keep the data and the byte enable for the second cycle (after address translation)
logic [CVA6Cfg.XLEN-1:0] st_data_n, st_data_q;
logic [(CVA6Cfg.XLEN/8)-1:0] st_be_n, st_be_q;
logic [1:0] st_data_size_n, st_data_size_q;
amo_t amo_op_d, amo_op_q;
logic [CVA6Cfg.XLEN-1:0] st_data, st_data_n, st_data_q;
logic [(CVA6Cfg.XLEN/8)-1:0] st_be, st_be_n, st_be_q;
logic [1:0] st_data_size, st_data_size_n, st_data_size_q;
amo_t amo_op, amo_op_d, amo_op_q;
logic store_buffer_valid, store_buffer_valid_d, store_buffer_valid_q;
logic store_buffer_valid_no_flush, store_buffer_valid_no_flush_d, store_buffer_valid_no_flush_q;
logic amo_buffer_valid, amo_buffer_valid_d, amo_buffer_valid_q;
logic store_buffer_ready, amo_buffer_ready;
logic [CVA6Cfg.TRANS_ID_BITS-1:0] trans_id_n, trans_id_q;
logic ex_s0, ex_s1;
logic stall_translation;
// output assignments
assign vaddr_o = lsu_ctrl_i.vaddr; // virtual address
assign vaddr_o = lsu_ctrl_i.vaddr; // virtual address
assign hs_ld_st_inst_o = CVA6Cfg.RVH ? lsu_ctrl_i.hs_ld_st_inst : 1'b0;
assign hlvx_inst_o = CVA6Cfg.RVH ? lsu_ctrl_i.hlvx_inst : 1'b0;
assign tinst_o = CVA6Cfg.RVH ? lsu_ctrl_i.tinst : '0; // transformed instruction
assign trans_id_o = trans_id_q; // transaction id from previous cycle
assign hlvx_inst_o = CVA6Cfg.RVH ? lsu_ctrl_i.hlvx_inst : 1'b0;
assign tinst_o = CVA6Cfg.RVH ? lsu_ctrl_i.tinst : '0; // transformed instruction
assign stall_translation = CVA6Cfg.MmuPresent ? translation_req_o && !dtlb_hit_i : 1'b0;
assign ex_s0 = CVA6Cfg.MmuPresent && stall_translation && ex_i.valid;
assign ex_s1 = CVA6Cfg.MmuPresent ? (store_buffer_valid_q || (CVA6Cfg.RVA && amo_buffer_valid_q)) && ex_i.valid : valid_i && ex_i.valid;
always_comb begin : store_control
translation_req_o = 1'b0;
valid_o = 1'b0;
st_valid = 1'b0;
st_valid_without_flush = 1'b0;
pop_st_o = 1'b0;
ex_o = ex_i;
trans_id_n = lsu_ctrl_i.trans_id;
state_d = state_q;
// default assignment
translation_req_o = 1'b0;
valid_o = 1'b0;
amo_buffer_valid_d = 1'b0;
store_buffer_valid_d = 1'b0;
store_buffer_valid_no_flush_d = 1'b0;
pop_st_o = 1'b0;
ex_o.valid = 1'b0;
trans_id_n = lsu_ctrl_i.trans_id;
trans_id_o = lsu_ctrl_i.trans_id;
case (state_q)
// we got a valid store
IDLE: begin
if (valid_i) begin
state_d = VALID_STORE;
translation_req_o = 1'b1;
pop_st_o = 1'b1;
// check if translation was valid and we have space in the store buffer
// otherwise simply stall
if (CVA6Cfg.MmuPresent && !dtlb_hit_i) begin
state_d = WAIT_TRANSLATION;
pop_st_o = 1'b0;
// REQUEST
if (valid_i) begin
translation_req_o = 1'b1;
if (!CVA6Cfg.MmuPresent || !stall_translation) begin
if (CVA6Cfg.RVA && instr_is_amo) begin
if (amo_buffer_ready) begin
pop_st_o = 1'b1;
amo_buffer_valid_d = !flush_i;
// RETIRE STORE NO MMU
if (!CVA6Cfg.MmuPresent) begin
trans_id_o = lsu_ctrl_i.trans_id;
valid_o = 1'b1;
ex_o.valid = ex_s1;
end
end
if (!st_ready) begin
state_d = WAIT_STORE_READY;
pop_st_o = 1'b0;
end
end
end
VALID_STORE: begin
valid_o = 1'b1;
// post this store to the store buffer if we are not flushing
if (!flush_i) st_valid = 1'b1;
st_valid_without_flush = 1'b1;
// we have another request and its not an AMO (the AMO buffer only has depth 1)
if ((valid_i && CVA6Cfg.RVA && !instr_is_amo) || (valid_i && !CVA6Cfg.RVA)) begin
translation_req_o = 1'b1;
state_d = VALID_STORE;
pop_st_o = 1'b1;
if (CVA6Cfg.MmuPresent && !dtlb_hit_i) begin
state_d = WAIT_TRANSLATION;
pop_st_o = 1'b0;
end
if (!st_ready) begin
state_d = WAIT_STORE_READY;
pop_st_o = 1'b0;
end
// if we do not have another request go back to idle
end else begin
state_d = IDLE;
end
end
// the store queue is currently full
WAIT_STORE_READY: begin
// keep the translation request high
translation_req_o = 1'b1;
if (st_ready && dtlb_hit_i) begin
state_d = IDLE;
end
end
default: begin
// we didn't receive a valid translation, wait for one
// but we know that the store queue is not full as we could only have landed here if
// it wasn't full
if (state_q == WAIT_TRANSLATION && CVA6Cfg.MmuPresent) begin
translation_req_o = 1'b1;
if (dtlb_hit_i) begin
state_d = IDLE;
if (store_buffer_ready) begin
pop_st_o = 1'b1;
store_buffer_valid_d = !flush_i;
store_buffer_valid_no_flush_d = 1'b1;
// RETIRE STORE NO MMU
if (!CVA6Cfg.MmuPresent) begin
trans_id_o = lsu_ctrl_i.trans_id;
valid_o = 1'b1;
ex_o.valid = ex_s1;
end
end
end
end
endcase
// -----------------
// Access Exception
// -----------------
// we got an address translation exception (access rights, misaligned or page fault)
if (ex_i.valid && (state_q != IDLE)) begin
// the only difference is that we do not want to store this request
pop_st_o = 1'b1;
st_valid = 1'b0;
state_d = IDLE;
valid_o = 1'b1;
end
if (flush_i) state_d = IDLE;
// RETIRE STORE WITH MMU
if (CVA6Cfg.MmuPresent) begin
if (store_buffer_valid_q || (CVA6Cfg.RVA && amo_buffer_valid_q)) begin
trans_id_o = trans_id_q;
valid_o = 1'b1;
ex_o.valid = ex_s1;
end
if (ex_s0) begin
trans_id_o = lsu_ctrl_i.trans_id;
valid_o = 1'b1;
ex_o.valid = 1'b1;
pop_st_o = 1'b1;
end
end
end
// -----------
@ -277,14 +246,13 @@ module store_unit
end
end
logic store_buffer_valid, amo_buffer_valid;
logic store_buffer_ready, amo_buffer_ready;
// multiplex between store unit and amo buffer
assign store_buffer_valid = st_valid & (!CVA6Cfg.RVA || (amo_op_q == AMO_NONE));
assign amo_buffer_valid = st_valid & (CVA6Cfg.RVA && (amo_op_q != AMO_NONE));
assign st_ready = store_buffer_ready & amo_buffer_ready;
assign st_be = CVA6Cfg.MmuPresent ? st_be_q : st_be_n;
assign st_data = CVA6Cfg.MmuPresent ? st_data_q : st_data_n;
assign st_data_size = CVA6Cfg.MmuPresent ? st_data_size_q : st_data_size_n;
assign amo_op = CVA6Cfg.MmuPresent ? amo_op_q : amo_op_d;
assign store_buffer_valid = CVA6Cfg.MmuPresent ? store_buffer_valid_q && !ex_s1 : store_buffer_valid_d;
assign store_buffer_valid_no_flush = CVA6Cfg.MmuPresent ? store_buffer_valid_no_flush_q && !ex_s1 : store_buffer_valid_no_flush_d;
assign amo_buffer_valid = CVA6Cfg.MmuPresent ? amo_buffer_valid_q && !ex_s1 : amo_buffer_valid_d;
// ---------------
// Store Queue
@ -311,12 +279,12 @@ module store_unit
// functionaly it doesn't make a difference whether we use
// the correct valid signal or not as we are flushing
// the whole pipeline anyway
.valid_without_flush_i(st_valid_without_flush),
.paddr_i,
.valid_without_flush_i(store_buffer_valid_no_flush),
.paddr_i (paddr_i),
.rvfi_mem_paddr_o (rvfi_mem_paddr_o),
.data_i (st_data_q),
.be_i (st_be_q),
.data_size_i (st_data_size_q),
.data_i (st_data),
.be_i (st_be),
.data_size_i (st_data_size),
.obi_store_req_o (obi_store_req_o),
.obi_store_rsp_i (obi_store_rsp_i)
);
@ -333,9 +301,9 @@ module store_unit
.valid_i (amo_buffer_valid),
.ready_o (amo_buffer_ready),
.paddr_i (paddr_i),
.amo_op_i (amo_op_q),
.data_i (st_data_q),
.data_size_i (st_data_size_q),
.amo_op_i (amo_op),
.data_i (st_data),
.data_size_i (st_data_size),
.obi_amo_req_o (obi_amo_req_o),
.obi_amo_rsp_i (obi_amo_rsp_i),
.amo_valid_commit_i(amo_valid_commit_i),
@ -351,19 +319,23 @@ module store_unit
// ---------------
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
state_q <= IDLE;
st_be_q <= '0;
st_data_q <= '0;
st_data_size_q <= '0;
trans_id_q <= '0;
amo_op_q <= AMO_NONE;
st_be_q <= '0;
st_data_q <= '0;
st_data_size_q <= '0;
trans_id_q <= '0;
amo_op_q <= AMO_NONE;
amo_buffer_valid_q <= '0;
store_buffer_valid_q <= '0;
store_buffer_valid_no_flush_q <= '0;
end else begin
state_q <= state_d;
st_be_q <= st_be_n;
st_data_q <= st_data_n;
trans_id_q <= trans_id_n;
st_data_size_q <= st_data_size_n;
amo_op_q <= amo_op_d;
st_be_q <= st_be_n;
st_data_q <= st_data_n;
trans_id_q <= trans_id_n;
st_data_size_q <= st_data_size_n;
amo_op_q <= amo_op_d;
amo_buffer_valid_q <= amo_buffer_valid_d;
store_buffer_valid_q <= store_buffer_valid_d;
store_buffer_valid_no_flush_q <= store_buffer_valid_no_flush_d;
end
end