mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-24 14:17:16 -04:00
Support multiple outstanding load operations to the Dcache (#1348)
This modification introduces a pending load table that tracks outstanding load operations to the Dcache. The depth of this table is a parameter in the target configuration package.
This commit is contained in:
commit
d9ad16bbe1
17 changed files with 349 additions and 228 deletions
|
@ -3,4 +3,4 @@ cv64a6_imafdc_sv39:
|
|||
cv32a60x:
|
||||
gates: 160719
|
||||
cv32a6_embedded:
|
||||
gates: 127613
|
||||
gates: 127977
|
||||
|
|
|
@ -74,6 +74,7 @@ module cache_ctrl import ariane_pkg::*; import std_cache_pkg::*; #(
|
|||
typedef struct packed {
|
||||
logic [DCACHE_INDEX_WIDTH-1:0] index;
|
||||
logic [DCACHE_TAG_WIDTH-1:0] tag;
|
||||
logic [DCACHE_TID_WIDTH-1:0] id;
|
||||
logic [7:0] be;
|
||||
logic [1:0] size;
|
||||
logic we;
|
||||
|
@ -116,7 +117,7 @@ module cache_ctrl import ariane_pkg::*; import std_cache_pkg::*; #(
|
|||
req_port_o.data_gnt = 1'b0;
|
||||
req_port_o.data_rvalid = 1'b0;
|
||||
req_port_o.data_rdata = '0;
|
||||
req_port_o.data_rid = '0;
|
||||
req_port_o.data_rid = mem_req_q.id;
|
||||
miss_req_o = '0;
|
||||
mshr_addr_o = '0;
|
||||
// Memory array communication
|
||||
|
@ -138,6 +139,7 @@ module cache_ctrl import ariane_pkg::*; import std_cache_pkg::*; #(
|
|||
|
||||
// save index, be and we
|
||||
mem_req_d.index = req_port_i.address_index;
|
||||
mem_req_d.id = req_port_i.data_id;
|
||||
mem_req_d.be = req_port_i.data_be;
|
||||
mem_req_d.size = req_port_i.data_size;
|
||||
mem_req_d.we = req_port_i.data_we;
|
||||
|
@ -186,6 +188,7 @@ module cache_ctrl import ariane_pkg::*; import std_cache_pkg::*; #(
|
|||
if (req_port_i.data_req && !mem_req_q.we && !flush_i) begin
|
||||
state_d = WAIT_TAG; // switch back to WAIT_TAG
|
||||
mem_req_d.index = req_port_i.address_index;
|
||||
mem_req_d.id = req_port_i.data_id;
|
||||
mem_req_d.be = req_port_i.data_be;
|
||||
mem_req_d.size = req_port_i.data_size;
|
||||
mem_req_d.we = req_port_i.data_we;
|
||||
|
@ -391,6 +394,7 @@ module cache_ctrl import ariane_pkg::*; import std_cache_pkg::*; #(
|
|||
if (req_port_i.data_req) begin
|
||||
// save index, be and we
|
||||
mem_req_d.index = req_port_i.address_index;
|
||||
mem_req_d.id = req_port_i.data_id;
|
||||
mem_req_d.be = req_port_i.data_be;
|
||||
mem_req_d.size = req_port_i.data_size;
|
||||
mem_req_d.we = req_port_i.data_we;
|
||||
|
|
|
@ -59,6 +59,7 @@ module wt_dcache_ctrl import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
logic [DCACHE_TAG_WIDTH-1:0] address_tag_d, address_tag_q;
|
||||
logic [DCACHE_CL_IDX_WIDTH-1:0] address_idx_d, address_idx_q;
|
||||
logic [DCACHE_OFFSET_WIDTH-1:0] address_off_d, address_off_q;
|
||||
logic [DCACHE_TID_WIDTH-1:0] id_d, id_q;
|
||||
logic [DCACHE_SET_ASSOC-1:0] vld_data_d, vld_data_q;
|
||||
logic save_tag, rd_req_d, rd_req_q, rd_ack_d, rd_ack_q;
|
||||
logic [1:0] data_size_d, data_size_q;
|
||||
|
@ -72,6 +73,7 @@ module wt_dcache_ctrl import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
assign address_tag_d = (save_tag) ? req_port_i.address_tag : address_tag_q;
|
||||
assign address_idx_d = (req_port_o.data_gnt) ? req_port_i.address_index[DCACHE_INDEX_WIDTH-1:DCACHE_OFFSET_WIDTH] : address_idx_q;
|
||||
assign address_off_d = (req_port_o.data_gnt) ? req_port_i.address_index[DCACHE_OFFSET_WIDTH-1:0] : address_off_q;
|
||||
assign id_d = (req_port_o.data_gnt) ? req_port_i.data_id : id_q;
|
||||
assign data_size_d = (req_port_o.data_gnt) ? req_port_i.data_size : data_size_q;
|
||||
assign rd_tag_o = address_tag_d;
|
||||
assign rd_idx_o = address_idx_d;
|
||||
|
@ -79,7 +81,7 @@ module wt_dcache_ctrl import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
|
||||
assign req_port_o.data_rdata = rd_data_i;
|
||||
assign req_port_o.data_ruser = rd_user_i;
|
||||
assign req_port_o.data_rid = '0;
|
||||
assign req_port_o.data_rid = id_q;
|
||||
|
||||
// to miss unit
|
||||
assign miss_vld_bits_o = vld_data_q;
|
||||
|
@ -240,6 +242,7 @@ module wt_dcache_ctrl import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
address_tag_q <= '0;
|
||||
address_idx_q <= '0;
|
||||
address_off_q <= '0;
|
||||
id_q <= '0;
|
||||
vld_data_q <= '0;
|
||||
data_size_q <= '0;
|
||||
rd_req_q <= '0;
|
||||
|
@ -249,6 +252,7 @@ module wt_dcache_ctrl import ariane_pkg::*; import wt_cache_pkg::*; #(
|
|||
address_tag_q <= address_tag_d;
|
||||
address_idx_q <= address_idx_d;
|
||||
address_off_q <= address_off_d;
|
||||
id_q <= id_d;
|
||||
vld_data_q <= vld_data_d;
|
||||
data_size_q <= data_size_d;
|
||||
rd_req_q <= rd_req_d;
|
||||
|
|
|
@ -168,6 +168,7 @@ module cva6 import ariane_pkg::*; #(
|
|||
CVA6Cfg.AxiDataWidth,
|
||||
CVA6Cfg.AxiIdWidth,
|
||||
CVA6Cfg.AxiUserWidth,
|
||||
CVA6Cfg.NrLoadBufEntries,
|
||||
CVA6Cfg.FpuEn,
|
||||
CVA6Cfg.XF16,
|
||||
CVA6Cfg.XF16ALT,
|
||||
|
|
|
@ -21,6 +21,7 @@ package config_pkg;
|
|||
int unsigned AxiDataWidth;
|
||||
int unsigned AxiIdWidth;
|
||||
int unsigned AxiUserWidth;
|
||||
int unsigned NrLoadBufEntries;
|
||||
bit FpuEn;
|
||||
bit XF16;
|
||||
bit XF16ALT;
|
||||
|
@ -51,6 +52,7 @@ package config_pkg;
|
|||
unsigned'(64), // AxiDataWidth
|
||||
unsigned'(4), // AxiIdWidth
|
||||
unsigned'(32), // AxiUserWidth
|
||||
unsigned'(2), // NrLoadBufEntries
|
||||
bit'(0), // FpuEn
|
||||
bit'(0), // XF16
|
||||
bit'(0), // XF16ALT
|
||||
|
@ -81,6 +83,7 @@ package config_pkg;
|
|||
unsigned'(0), // AxiDataWidth
|
||||
unsigned'(0), // AxiIdWidth
|
||||
unsigned'(0), // AxiUserWidth
|
||||
unsigned'(0), // NrLoadBufEntries
|
||||
bit'(0), // FpuEn
|
||||
bit'(0), // XF16
|
||||
bit'(0), // XF16ALT
|
||||
|
|
|
@ -58,6 +58,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigNrLoadPipeRegs = 1;
|
||||
localparam CVA6ConfigNrStorePipeRegs = 0;
|
||||
localparam CVA6ConfigNrLoadBufEntries = 2;
|
||||
|
||||
localparam CVA6ConfigInstrTlbEntries = 2;
|
||||
localparam CVA6ConfigDataTlbEntries = 2;
|
||||
|
@ -77,20 +78,21 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigRvfiTrace = 1;
|
||||
|
||||
localparam config_pkg::cva6_cfg_t cva6_cfg = {
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
unsigned'(CVA6ConfigNrLoadBufEntries), // NrLoadBufEntries
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
// Extended
|
||||
bit'(0), // RVF
|
||||
bit'(0), // RVD
|
||||
|
|
|
@ -57,6 +57,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigNrLoadPipeRegs = 1;
|
||||
localparam CVA6ConfigNrStorePipeRegs = 0;
|
||||
localparam CVA6ConfigNrLoadBufEntries = 2;
|
||||
|
||||
localparam CVA6ConfigInstrTlbEntries = 2;
|
||||
localparam CVA6ConfigDataTlbEntries = 2;
|
||||
|
@ -76,20 +77,21 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigRvfiTrace = 1;
|
||||
|
||||
localparam config_pkg::cva6_cfg_t cva6_cfg = {
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
unsigned'(CVA6ConfigNrLoadBufEntries), // NrLoadBufEntries
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
// Extended
|
||||
bit'(0), // RVF
|
||||
bit'(0), // RVD
|
||||
|
|
|
@ -58,6 +58,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigNrLoadPipeRegs = 1;
|
||||
localparam CVA6ConfigNrStorePipeRegs = 0;
|
||||
localparam CVA6ConfigNrLoadBufEntries = 2;
|
||||
|
||||
localparam CVA6ConfigInstrTlbEntries = 2;
|
||||
localparam CVA6ConfigDataTlbEntries = 2;
|
||||
|
@ -77,20 +78,21 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigRvfiTrace = 1;
|
||||
|
||||
localparam config_pkg::cva6_cfg_t cva6_cfg = {
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
unsigned'(CVA6ConfigNrLoadBufEntries), // NrLoadBufEntries
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
// Extended
|
||||
bit'(0), // RVF
|
||||
bit'(0), // RVD
|
||||
|
|
|
@ -53,6 +53,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigNrCommitPorts = 2;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 8;
|
||||
localparam CVA6ConfigNrLoadBufEntries = 2;
|
||||
|
||||
localparam CVA6ConfigFPGAEn = 0;
|
||||
|
||||
|
@ -77,20 +78,21 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigRvfiTrace = 1;
|
||||
|
||||
localparam config_pkg::cva6_cfg_t cva6_cfg = {
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
unsigned'(CVA6ConfigNrLoadBufEntries), // NrLoadBufEntries
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
// Extended
|
||||
bit'(0), // RVF
|
||||
bit'(0), // RVD
|
||||
|
|
|
@ -58,6 +58,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigNrLoadPipeRegs = 1;
|
||||
localparam CVA6ConfigNrStorePipeRegs = 0;
|
||||
localparam CVA6ConfigNrLoadBufEntries = 2;
|
||||
|
||||
localparam CVA6ConfigInstrTlbEntries = 2;
|
||||
localparam CVA6ConfigDataTlbEntries = 2;
|
||||
|
@ -77,20 +78,21 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigRvfiTrace = 1;
|
||||
|
||||
localparam config_pkg::cva6_cfg_t cva6_cfg = {
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
unsigned'(CVA6ConfigNrLoadBufEntries), // NrLoadBufEntries
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
// Extended
|
||||
bit'(0), // RVF
|
||||
bit'(0), // RVD
|
||||
|
|
|
@ -58,6 +58,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigNrLoadPipeRegs = 1;
|
||||
localparam CVA6ConfigNrStorePipeRegs = 0;
|
||||
localparam CVA6ConfigNrLoadBufEntries = 2;
|
||||
|
||||
localparam CVA6ConfigInstrTlbEntries = 2;
|
||||
localparam CVA6ConfigDataTlbEntries = 2;
|
||||
|
@ -77,20 +78,21 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigRvfiTrace = 1;
|
||||
|
||||
localparam config_pkg::cva6_cfg_t cva6_cfg = {
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
unsigned'(CVA6ConfigNrLoadBufEntries), // NrLoadBufEntries
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
// Extended
|
||||
bit'(0), // RVF
|
||||
bit'(0), // RVD
|
||||
|
|
|
@ -58,6 +58,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigNrLoadPipeRegs = 1;
|
||||
localparam CVA6ConfigNrStorePipeRegs = 0;
|
||||
localparam CVA6ConfigNrLoadBufEntries = 2;
|
||||
|
||||
localparam CVA6ConfigInstrTlbEntries = 16;
|
||||
localparam CVA6ConfigDataTlbEntries = 16;
|
||||
|
@ -77,20 +78,21 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigRvfiTrace = 1;
|
||||
|
||||
localparam config_pkg::cva6_cfg_t cva6_cfg = {
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
unsigned'(CVA6ConfigNrLoadBufEntries), // NrLoadBufEntries
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
// Extended
|
||||
bit'(0), // RVF
|
||||
bit'(0), // RVD
|
||||
|
|
|
@ -58,6 +58,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigNrLoadPipeRegs = 1;
|
||||
localparam CVA6ConfigNrStorePipeRegs = 0;
|
||||
localparam CVA6ConfigNrLoadBufEntries = 2;
|
||||
|
||||
localparam CVA6ConfigInstrTlbEntries = 16;
|
||||
localparam CVA6ConfigDataTlbEntries = 16;
|
||||
|
@ -77,20 +78,21 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigRvfiTrace = 1;
|
||||
|
||||
localparam config_pkg::cva6_cfg_t cva6_cfg = {
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
unsigned'(CVA6ConfigNrLoadBufEntries), // NrLoadBufEntries
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
// Extended
|
||||
bit'(0), // RVF
|
||||
bit'(0), // RVD
|
||||
|
|
|
@ -58,6 +58,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigNrLoadPipeRegs = 1;
|
||||
localparam CVA6ConfigNrStorePipeRegs = 0;
|
||||
localparam CVA6ConfigNrLoadBufEntries = 2;
|
||||
|
||||
localparam CVA6ConfigInstrTlbEntries = 16;
|
||||
localparam CVA6ConfigDataTlbEntries = 16;
|
||||
|
@ -77,20 +78,21 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigRvfiTrace = 1;
|
||||
|
||||
localparam config_pkg::cva6_cfg_t cva6_cfg = {
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
unsigned'(CVA6ConfigNrLoadBufEntries), // NrLoadBufEntries
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
// Extended
|
||||
bit'(0), // RVF
|
||||
bit'(0), // RVD
|
||||
|
|
|
@ -58,6 +58,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigNrLoadPipeRegs = 1;
|
||||
localparam CVA6ConfigNrStorePipeRegs = 0;
|
||||
localparam CVA6ConfigNrLoadBufEntries = 2;
|
||||
|
||||
localparam CVA6ConfigInstrTlbEntries = 16;
|
||||
localparam CVA6ConfigDataTlbEntries = 16;
|
||||
|
@ -77,20 +78,21 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigRvfiTrace = 1;
|
||||
|
||||
localparam config_pkg::cva6_cfg_t cva6_cfg = {
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
unsigned'(CVA6ConfigNrCommitPorts), // NrCommitPorts
|
||||
unsigned'(CVA6ConfigAxiAddrWidth), // AxiAddrWidth
|
||||
unsigned'(CVA6ConfigAxiDataWidth), // AxiDataWidth
|
||||
unsigned'(CVA6ConfigAxiIdWidth), // AxiIdWidth
|
||||
unsigned'(CVA6ConfigDataUserWidth), // AxiUserWidth
|
||||
unsigned'(CVA6ConfigNrLoadBufEntries), // NrLoadBufEntries
|
||||
bit'(CVA6ConfigFpuEn), // FpuEn
|
||||
bit'(CVA6ConfigF16En), // XF16
|
||||
bit'(CVA6ConfigF16AltEn), // XF16ALT
|
||||
bit'(CVA6ConfigF8En), // XF8
|
||||
bit'(CVA6ConfigAExtEn), // RVA
|
||||
bit'(CVA6ConfigVExtEn), // RVV
|
||||
bit'(CVA6ConfigCExtEn), // RVC
|
||||
bit'(CVA6ConfigFVecEn), // XFVec
|
||||
bit'(CVA6ConfigCvxifEn), // CvxifEn
|
||||
// Extended
|
||||
bit'(0), // RVF
|
||||
bit'(0), // RVD
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
// Michael Schaffner <schaffner@iis.ee.ethz.ch>, ETH Zurich
|
||||
// Date: 15.08.2018
|
||||
// Description: Load Unit, takes care of all load requests
|
||||
//
|
||||
// Contributor: Cesar Fuguet <cesar.fuguettortolero@cea.fr>, CEA List
|
||||
// Date: August 29, 2023
|
||||
// Modification: add support for multiple outstanding load operations
|
||||
// to the data cache
|
||||
|
||||
module load_unit import ariane_pkg::*; #(
|
||||
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
|
||||
|
@ -50,13 +55,99 @@ module load_unit import ariane_pkg::*; #(
|
|||
ABORT_TRANSACTION, ABORT_TRANSACTION_NI, WAIT_TRANSLATION, WAIT_FLUSH,
|
||||
WAIT_WB_EMPTY
|
||||
} state_d, state_q;
|
||||
// in order to decouple the response interface from the request interface we need a
|
||||
// a queue which can hold all outstanding memory requests
|
||||
struct packed {
|
||||
logic [TRANS_ID_BITS-1:0] trans_id;
|
||||
logic [riscv::XLEN_ALIGN_BYTES-1:0] address_offset;
|
||||
fu_op operation;
|
||||
} load_data_d, load_data_q, in_data;
|
||||
|
||||
// in order to decouple the response interface from the request interface,
|
||||
// we need a a buffer which can hold all inflight memory load requests
|
||||
typedef struct packed {
|
||||
logic [TRANS_ID_BITS-1:0] trans_id; // scoreboard identifier
|
||||
logic [riscv::XLEN_ALIGN_BYTES-1:0] address_offset; // least significant bits of the address
|
||||
fu_op operation; // type of load
|
||||
} ldbuf_t;
|
||||
|
||||
|
||||
// to support a throughput of one load per cycle, if the number of entries
|
||||
// of the load buffer is 1, implement a fall-through mode. This however
|
||||
// adds a combinational path between the request and response interfaces
|
||||
// towards the cache.
|
||||
localparam logic LDBUF_FALLTHROUGH = (CVA6Cfg.NrLoadBufEntries == 1);
|
||||
localparam int unsigned REQ_ID_BITS = CVA6Cfg.NrLoadBufEntries > 1 ?
|
||||
$clog2(CVA6Cfg.NrLoadBufEntries) : 1;
|
||||
|
||||
typedef logic [REQ_ID_BITS-1:0] ldbuf_id_t;
|
||||
|
||||
logic [CVA6Cfg.NrLoadBufEntries-1:0] ldbuf_valid_q, ldbuf_valid_d;
|
||||
logic [CVA6Cfg.NrLoadBufEntries-1:0] ldbuf_flushed_q, ldbuf_flushed_d;
|
||||
ldbuf_t [CVA6Cfg.NrLoadBufEntries-1:0] ldbuf_q;
|
||||
logic ldbuf_empty, ldbuf_full;
|
||||
ldbuf_id_t ldbuf_free_index;
|
||||
logic ldbuf_w;
|
||||
ldbuf_t ldbuf_wdata;
|
||||
ldbuf_id_t ldbuf_windex;
|
||||
logic ldbuf_r;
|
||||
ldbuf_t ldbuf_rdata;
|
||||
ldbuf_id_t ldbuf_rindex;
|
||||
ldbuf_id_t ldbuf_last_id_q;
|
||||
|
||||
assign ldbuf_full = &ldbuf_valid_q;
|
||||
|
||||
//
|
||||
// buffer of outstanding loads
|
||||
|
||||
// write in the first available slot
|
||||
generate
|
||||
if (CVA6Cfg.NrLoadBufEntries > 1) begin : ldbuf_free_index_multi_gen
|
||||
lzc #(
|
||||
.WIDTH (CVA6Cfg.NrLoadBufEntries),
|
||||
.MODE (1'b0) // Count leading zeros
|
||||
) lzc_windex_i (
|
||||
.in_i (~ldbuf_valid_q),
|
||||
.cnt_o (ldbuf_free_index),
|
||||
.empty_o (ldbuf_empty)
|
||||
);
|
||||
end else begin : ldbuf_free_index_single_gen
|
||||
assign ldbuf_free_index = 1'b0;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign ldbuf_windex = (LDBUF_FALLTHROUGH && ldbuf_r) ? ldbuf_rindex : ldbuf_free_index;
|
||||
|
||||
always_comb
|
||||
begin : ldbuf_comb
|
||||
ldbuf_flushed_d = ldbuf_flushed_q;
|
||||
ldbuf_valid_d = ldbuf_valid_q;
|
||||
|
||||
// In case of flush, raise the flushed flag in all slots.
|
||||
if (flush_i) begin
|
||||
ldbuf_flushed_d = '1;
|
||||
end
|
||||
// Free read entry (in the case of fall-through mode, free the entry
|
||||
// only if there is no pending load)
|
||||
if (ldbuf_r && (!LDBUF_FALLTHROUGH || !ldbuf_w)) begin
|
||||
ldbuf_valid_d[ldbuf_rindex] = 1'b0;
|
||||
end
|
||||
// Track a new outstanding operation in the load buffer
|
||||
if (ldbuf_w) begin
|
||||
ldbuf_flushed_d[ldbuf_windex] = 1'b0;
|
||||
ldbuf_valid_d[ldbuf_windex] = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni)
|
||||
begin : ldbuf_ff
|
||||
if (!rst_ni) begin
|
||||
ldbuf_flushed_q <= '0;
|
||||
ldbuf_valid_q <= '0;
|
||||
ldbuf_last_id_q <= '0;
|
||||
ldbuf_q <= '0;
|
||||
end else begin
|
||||
ldbuf_flushed_q <= ldbuf_flushed_d;
|
||||
ldbuf_valid_q <= ldbuf_valid_d;
|
||||
if (ldbuf_w) begin
|
||||
ldbuf_last_id_q <= ldbuf_windex;
|
||||
ldbuf_q[ldbuf_windex] <= ldbuf_wdata;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// page offset is defined as the lower 12 bits, feed through for address checker
|
||||
assign page_offset_o = lsu_ctrl_i.vaddr[11:0];
|
||||
|
@ -65,8 +156,8 @@ module load_unit import ariane_pkg::*; #(
|
|||
// this is a read-only interface so set the write enable to 0
|
||||
assign req_port_o.data_we = 1'b0;
|
||||
assign req_port_o.data_wdata = '0;
|
||||
// compose the queue data, control is handled in the FSM
|
||||
assign in_data = {lsu_ctrl_i.trans_id, lsu_ctrl_i.vaddr[riscv::XLEN_ALIGN_BYTES-1:0], lsu_ctrl_i.operation};
|
||||
// compose the load buffer write data, control is handled in the FSM
|
||||
assign ldbuf_wdata = {lsu_ctrl_i.trans_id, lsu_ctrl_i.vaddr[riscv::XLEN_ALIGN_BYTES-1:0], lsu_ctrl_i.operation};
|
||||
// output address
|
||||
// we can now output the lower 12 bit as the index to the cache
|
||||
assign req_port_o.address_index = lsu_ctrl_i.vaddr[ariane_pkg::DCACHE_INDEX_WIDTH-1:0];
|
||||
|
@ -74,8 +165,8 @@ module load_unit import ariane_pkg::*; #(
|
|||
assign req_port_o.address_tag = paddr_i[ariane_pkg::DCACHE_TAG_WIDTH +
|
||||
ariane_pkg::DCACHE_INDEX_WIDTH-1 :
|
||||
ariane_pkg::DCACHE_INDEX_WIDTH];
|
||||
// we only issue one single request at a time
|
||||
assign req_port_o.data_id = '0;
|
||||
// request id = index of the load buffer's entry
|
||||
assign req_port_o.data_id = ldbuf_windex;
|
||||
// directly forward exception fields (valid bit is set below)
|
||||
assign ex_o.cause = ex_i.cause;
|
||||
assign ex_o.tval = ex_i.tval;
|
||||
|
@ -94,9 +185,10 @@ module load_unit import ariane_pkg::*; #(
|
|||
// Load Control
|
||||
// ---------------
|
||||
always_comb begin : load_control
|
||||
automatic logic accept_req;
|
||||
|
||||
// default assignments
|
||||
state_d = state_q;
|
||||
load_data_d = load_data_q;
|
||||
translation_req_o = 1'b0;
|
||||
req_port_o.data_req = 1'b0;
|
||||
// tag control
|
||||
|
@ -106,10 +198,14 @@ module load_unit import ariane_pkg::*; #(
|
|||
req_port_o.data_size = extract_transfer_size(lsu_ctrl_i.operation);
|
||||
pop_ld_o = 1'b0;
|
||||
|
||||
// In IDLE and SEND_TAG states, this unit can accept a new load request
|
||||
// when the load buffer is not full or if there is a response and the
|
||||
// load buffer is in fall-through mode
|
||||
accept_req = (valid_i && (!ldbuf_full || (LDBUF_FALLTHROUGH && ldbuf_r)));
|
||||
|
||||
case (state_q)
|
||||
IDLE: begin
|
||||
// we've got a new load request
|
||||
if (valid_i) begin
|
||||
if (accept_req) begin
|
||||
// start the translation process even though we do not know if the addresses match
|
||||
// this should ease timing
|
||||
translation_req_o = 1'b1;
|
||||
|
@ -168,6 +264,14 @@ module load_unit import ariane_pkg::*; #(
|
|||
// we've got a hit and we can continue with the request process
|
||||
if (dtlb_hit_i)
|
||||
state_d = WAIT_GNT;
|
||||
|
||||
// we got an exception
|
||||
if (ex_i.valid) begin
|
||||
// the next state will be the idle state
|
||||
state_d = IDLE;
|
||||
// pop load - but only if we are not getting an rvalid in here - otherwise we will over-write an incoming transaction
|
||||
pop_ld_o = ~req_port_i.data_rvalid;
|
||||
end
|
||||
end
|
||||
|
||||
WAIT_GNT: begin
|
||||
|
@ -195,8 +299,8 @@ module load_unit import ariane_pkg::*; #(
|
|||
SEND_TAG: begin
|
||||
req_port_o.tag_valid = 1'b1;
|
||||
state_d = IDLE;
|
||||
// we can make a new request here if we got one
|
||||
if (valid_i) begin
|
||||
|
||||
if (accept_req) begin
|
||||
// start the translation process even though we do not know if the addresses match
|
||||
// this should ease timing
|
||||
translation_req_o = 1'b1;
|
||||
|
@ -246,39 +350,33 @@ module load_unit import ariane_pkg::*; #(
|
|||
default: state_d = IDLE;
|
||||
endcase
|
||||
|
||||
// we got an exception
|
||||
if (ex_i.valid && valid_i) begin
|
||||
// the next state will be the idle state
|
||||
state_d = IDLE;
|
||||
// pop load - but only if we are not getting an rvalid in here - otherwise we will over-write an incoming transaction
|
||||
if (!req_port_i.data_rvalid)
|
||||
pop_ld_o = 1'b1;
|
||||
end
|
||||
|
||||
// save the load data for later usage -> we should not clutter the load_data register
|
||||
if (pop_ld_o && !ex_i.valid) begin
|
||||
load_data_d = in_data;
|
||||
end
|
||||
|
||||
// if we just flushed and the queue is not empty or we are getting an rvalid this cycle wait in a extra stage
|
||||
if (flush_i) begin
|
||||
state_d = WAIT_FLUSH;
|
||||
end
|
||||
end
|
||||
|
||||
// track the load data for later usage
|
||||
assign ldbuf_w = req_port_o.data_req & req_port_i.data_gnt;
|
||||
|
||||
// ---------------
|
||||
// Retire Load
|
||||
// ---------------
|
||||
assign ldbuf_rindex = (CVA6Cfg.NrLoadBufEntries > 1) ? ldbuf_id_t'(req_port_i.data_rid) : 1'b0,
|
||||
ldbuf_rdata = ldbuf_q[ldbuf_rindex];
|
||||
|
||||
// decoupled rvalid process
|
||||
always_comb begin : rvalid_output
|
||||
// read the pending load buffer
|
||||
ldbuf_r = req_port_i.data_rvalid;
|
||||
trans_id_o = ldbuf_q[ldbuf_rindex].trans_id;
|
||||
valid_o = 1'b0;
|
||||
ex_o.valid = 1'b0;
|
||||
// output the queue data directly, the valid signal is set corresponding to the process above
|
||||
trans_id_o = load_data_q.trans_id;
|
||||
// we got an rvalid and are currently not flushing and not aborting the request
|
||||
if (req_port_i.data_rvalid && state_q != WAIT_FLUSH) begin
|
||||
// we killed the request
|
||||
if(!req_port_o.kill_req)
|
||||
|
||||
// we got an rvalid and it's corresponding request was not flushed
|
||||
if (req_port_i.data_rvalid && !ldbuf_flushed_q[ldbuf_rindex]) begin
|
||||
// if the response corresponds to the last request, check that we are not killing it
|
||||
if((ldbuf_last_id_q != ldbuf_rindex) || !req_port_o.kill_req)
|
||||
valid_o = 1'b1;
|
||||
// the output is also valid if we got an exception. An exception arrives one cycle after
|
||||
// dtlb_hit_i is asserted, i.e. when we are in SEND_TAG. Otherwise, the exception
|
||||
|
@ -288,18 +386,15 @@ module load_unit import ariane_pkg::*; #(
|
|||
ex_o.valid = 1'b1;
|
||||
end
|
||||
end
|
||||
// an exception occurred during translation (we need to check for the valid flag because we could also get an
|
||||
// exception from the store unit)
|
||||
|
||||
// an exception occurred during translation
|
||||
// exceptions can retire out-of-order -> but we need to give priority to non-excepting load and stores
|
||||
// so we simply check if we got an rvalid if so we prioritize it by not retiring the exception - we simply go for another
|
||||
// round in the load FSM
|
||||
if (valid_i && ex_i.valid && !req_port_i.data_rvalid) begin
|
||||
valid_o = 1'b1;
|
||||
ex_o.valid = 1'b1;
|
||||
if ((state_q == WAIT_TRANSLATION) && !req_port_i.data_rvalid && ex_i.valid && valid_i) begin
|
||||
trans_id_o = lsu_ctrl_i.trans_id;
|
||||
// if we are waiting for the translation to finish do not give a valid signal yet
|
||||
end else if (state_q == WAIT_TRANSLATION) begin
|
||||
valid_o = 1'b0;
|
||||
valid_o = 1'b1;
|
||||
ex_o.valid = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -307,11 +402,9 @@ module load_unit import ariane_pkg::*; #(
|
|||
// latch physical address for the tag cycle (one cycle after applying the index)
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
state_q <= IDLE;
|
||||
load_data_q <= '0;
|
||||
state_q <= IDLE;
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
load_data_q <= load_data_d;
|
||||
state_q <= state_d;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -321,12 +414,12 @@ module load_unit import ariane_pkg::*; #(
|
|||
riscv::xlen_t shifted_data;
|
||||
|
||||
// realign as needed
|
||||
assign shifted_data = req_port_i.data_rdata >> {load_data_q.address_offset, 3'b000};
|
||||
assign shifted_data = req_port_i.data_rdata >> {ldbuf_rdata.address_offset, 3'b000};
|
||||
|
||||
/* // result mux (leaner code, but more logic stages.
|
||||
// can be used instead of the code below (in between //result mux fast) if timing is not so critical)
|
||||
always_comb begin
|
||||
unique case (load_data_q.operation)
|
||||
unique case (ldbuf_rdata.operation)
|
||||
LWU: result_o = shifted_data[31:0];
|
||||
LHU: result_o = shifted_data[15:0];
|
||||
LBU: result_o = shifted_data[7:0];
|
||||
|
@ -338,64 +431,57 @@ module load_unit import ariane_pkg::*; #(
|
|||
end */
|
||||
|
||||
// result mux fast
|
||||
logic [(riscv::XLEN/8)-1:0] sign_bits;
|
||||
logic [riscv::XLEN_ALIGN_BYTES-1:0] idx_d, idx_q;
|
||||
logic sign_bit, signed_d, signed_q, fp_sign_d, fp_sign_q;
|
||||
logic [(riscv::XLEN/8)-1:0] rdata_sign_bits;
|
||||
logic [riscv::XLEN_ALIGN_BYTES-1:0] rdata_offset;
|
||||
logic rdata_sign_bit, rdata_is_signed, rdata_is_fp_signed;
|
||||
|
||||
|
||||
// prepare these signals for faster selection in the next cycle
|
||||
assign signed_d = load_data_d.operation inside {ariane_pkg::LW, ariane_pkg::LH, ariane_pkg::LB};
|
||||
assign fp_sign_d = load_data_d.operation inside {ariane_pkg::FLW, ariane_pkg::FLH, ariane_pkg::FLB};
|
||||
|
||||
assign idx_d = ((load_data_d.operation inside {ariane_pkg::LW, ariane_pkg::FLW}) & riscv::IS_XLEN64) ? load_data_d.address_offset + 3 :
|
||||
(load_data_d.operation inside {ariane_pkg::LH, ariane_pkg::FLH}) ? load_data_d.address_offset + 1 :
|
||||
load_data_d.address_offset;
|
||||
|
||||
assign rdata_is_signed = ldbuf_rdata.operation inside {ariane_pkg::LW, ariane_pkg::LH, ariane_pkg::LB};
|
||||
assign rdata_is_fp_signed = ldbuf_rdata.operation inside {ariane_pkg::FLW, ariane_pkg::FLH, ariane_pkg::FLB};
|
||||
assign rdata_offset = ((ldbuf_rdata.operation inside {ariane_pkg::LW, ariane_pkg::FLW}) & riscv::IS_XLEN64) ? ldbuf_rdata.address_offset + 3 :
|
||||
( ldbuf_rdata.operation inside {ariane_pkg::LH, ariane_pkg::FLH}) ? ldbuf_rdata.address_offset + 1 :
|
||||
ldbuf_rdata.address_offset;
|
||||
|
||||
for (genvar i = 0; i < (riscv::XLEN/8); i++) begin : gen_sign_bits
|
||||
assign sign_bits[i] = req_port_i.data_rdata[(i+1)*8-1];
|
||||
assign rdata_sign_bits[i] = req_port_i.data_rdata[(i+1)*8-1];
|
||||
end
|
||||
|
||||
|
||||
// select correct sign bit in parallel to result shifter above
|
||||
// pull to 0 if unsigned
|
||||
assign sign_bit = signed_q & sign_bits[idx_q] | fp_sign_q;
|
||||
assign rdata_sign_bit = rdata_is_signed & rdata_sign_bits[rdata_offset] | rdata_is_fp_signed;
|
||||
|
||||
// result mux
|
||||
always_comb begin
|
||||
unique case (load_data_q.operation)
|
||||
ariane_pkg::LW, ariane_pkg::LWU, ariane_pkg::FLW: result_o = {{riscv::XLEN-32{sign_bit}}, shifted_data[31:0]};
|
||||
ariane_pkg::LH, ariane_pkg::LHU, ariane_pkg::FLH: result_o = {{riscv::XLEN-32+16{sign_bit}}, shifted_data[15:0]};
|
||||
ariane_pkg::LB, ariane_pkg::LBU, ariane_pkg::FLB: result_o = {{riscv::XLEN-32+24{sign_bit}}, shifted_data[7:0]};
|
||||
default: result_o = shifted_data[riscv::XLEN-1:0];
|
||||
unique case (ldbuf_rdata.operation)
|
||||
ariane_pkg::LW, ariane_pkg::LWU, ariane_pkg::FLW: result_o = {{riscv::XLEN-32{rdata_sign_bit}}, shifted_data[31:0]};
|
||||
ariane_pkg::LH, ariane_pkg::LHU, ariane_pkg::FLH: result_o = {{riscv::XLEN-32+16{rdata_sign_bit}}, shifted_data[15:0]};
|
||||
ariane_pkg::LB, ariane_pkg::LBU, ariane_pkg::FLB: result_o = {{riscv::XLEN-32+24{rdata_sign_bit}}, shifted_data[7:0]};
|
||||
default: result_o = shifted_data[riscv::XLEN-1:0];
|
||||
endcase
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
|
||||
if (~rst_ni) begin
|
||||
idx_q <= 0;
|
||||
signed_q <= 0;
|
||||
fp_sign_q <= 0;
|
||||
end else begin
|
||||
idx_q <= idx_d;
|
||||
signed_q <= signed_d;
|
||||
fp_sign_q <= fp_sign_d;
|
||||
end
|
||||
end
|
||||
// end result mux fast
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// assertions
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
//pragma translate_off
|
||||
// check invalid offsets
|
||||
//pragma translate_off
|
||||
`ifndef VERILATOR
|
||||
initial assert (ariane_pkg::DCACHE_TID_WIDTH >= REQ_ID_BITS) else
|
||||
$fatal(1, "CVA6ConfigDcacheIdWidth parameter is not wide enough to encode pending loads");
|
||||
// check invalid offsets, but only issue a warning as these conditions actually trigger a load address misaligned exception
|
||||
addr_offset0: assert property (@(posedge clk_i) disable iff (~rst_ni)
|
||||
valid_o |-> (load_data_q.operation inside {ariane_pkg::LW, ariane_pkg::LWU}) |-> load_data_q.address_offset < 5) else $fatal (1,"invalid address offset used with {LW, LWU}");
|
||||
ldbuf_w |-> (ldbuf_wdata.operation inside {ariane_pkg::LW, ariane_pkg::LWU}) |-> ldbuf_wdata.address_offset < 5) else
|
||||
$fatal(1, "invalid address offset used with {LW, LWU}");
|
||||
addr_offset1: assert property (@(posedge clk_i) disable iff (~rst_ni)
|
||||
valid_o |-> (load_data_q.operation inside {ariane_pkg::LH, ariane_pkg::LHU}) |-> load_data_q.address_offset < 7) else $fatal (1,"invalid address offset used with {LH, LHU}");
|
||||
ldbuf_w |-> (ldbuf_wdata.operation inside {ariane_pkg::LH, ariane_pkg::LHU}) |-> ldbuf_wdata.address_offset < 7) else
|
||||
$fatal(1, "invalid address offset used with {LH, LHU}");
|
||||
addr_offset2: assert property (@(posedge clk_i) disable iff (~rst_ni)
|
||||
valid_o |-> (load_data_q.operation inside {ariane_pkg::LB, ariane_pkg::LBU}) |-> load_data_q.address_offset < 8) else $fatal (1,"invalid address offset used with {LB, LBU}");
|
||||
//pragma translate_on
|
||||
ldbuf_w |-> (ldbuf_wdata.operation inside {ariane_pkg::LB, ariane_pkg::LBU}) |-> ldbuf_wdata.address_offset < 8) else
|
||||
$fatal(1, "invalid address offset used with {LB, LBU}");
|
||||
`endif
|
||||
//pragma translate_on
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -85,6 +85,8 @@ def setup_parser_config_generator():
|
|||
help="Load latency")
|
||||
parser.add_argument("--NrStorePipeRegs", type=int, default=None,
|
||||
help="Store latency")
|
||||
parser.add_argument("--NrLoadBufEntries", type=int, default=None,
|
||||
help="Number of entries in the load buffer")
|
||||
parser.add_argument("--InstrTlbEntries", type=int, default=None,
|
||||
help="Number of instruction TLB entries")
|
||||
parser.add_argument("--DataTlbEntries", type=int, default=None,
|
||||
|
@ -145,6 +147,7 @@ MapArgsToParameter={
|
|||
"FPGAEn" : "CVA6ConfigFPGAEn",
|
||||
"NrLoadPipeRegs" : "CVA6ConfigNrLoadPipeRegs",
|
||||
"NrStorePipeRegs" : "CVA6ConfigNrStorePipeRegs",
|
||||
"NrLoadBufEntries" : "CVA6ConfigNrLoadBufEntries",
|
||||
"InstrTlbEntries" : "CVA6ConfigInstrTlbEntries",
|
||||
"DataTlbEntries" : "CVA6ConfigDataTlbEntries",
|
||||
"RASDepth": "CVA6ConfigRASDepth",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue