mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-24 06:07:19 -04:00
Add option to improve load perf in case OBIVersion==0 or no MMU
This commit is contained in:
parent
ff2dfa4335
commit
15f0be1934
23 changed files with 351 additions and 331 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue