From b63ee1383beec38b2564ac0e3e5eb9079e5da933 Mon Sep 17 00:00:00 2001 From: Luca Colagrande Date: Fri, 6 Oct 2023 15:59:08 +0200 Subject: [PATCH] cva6_icache: Allow one outstanding killed miss --- .../core/cache_subsystem/cva6_icache.sv | 54 +++---- ...he-Allow-one-outstanding-killed-miss.patch | 134 ++++++++++++++++++ 2 files changed, 164 insertions(+), 24 deletions(-) create mode 100644 hw/vendor/patches/openhwgroup_cva6/0011-cva6_icache-Allow-one-outstanding-killed-miss.patch diff --git a/hw/vendor/openhwgroup_cva6/core/cache_subsystem/cva6_icache.sv b/hw/vendor/openhwgroup_cva6/core/cache_subsystem/cva6_icache.sv index 6dd677d85..9c0814269 100644 --- a/hw/vendor/openhwgroup_cva6/core/cache_subsystem/cva6_icache.sv +++ b/hw/vendor/openhwgroup_cva6/core/cache_subsystem/cva6_icache.sv @@ -66,6 +66,7 @@ module cva6_icache import ariane_pkg::*; import wt_cache_pkg::*; #( logic cache_wren; // triggers write to cacheline logic cmp_en_d, cmp_en_q; // enable tag comparison in next cycle. used to cut long path due to NC signal. logic flush_d, flush_q; // used to register and signal pending flushes + logic outst_miss_d, outst_miss_q; // tracks whether there are any outstanding misses // replacement strategy logic update_lfsr; // shift the LFSR @@ -171,6 +172,7 @@ end else begin : gen_piton_offset cache_wren = 1'b0; inv_en = 1'b0; flush_d = flush_q | flush_i; // register incoming flush + outst_miss_d = outst_miss_q; // interfaces dreq_o.ready = 1'b0; @@ -189,6 +191,11 @@ end else begin : gen_piton_offset inv_en = 1'b1; end + // kill an outstanding miss + if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_IFILL_ACK && outst_miss_q) begin + outst_miss_d = 1'b0; + end + unique case (state_q) ////////////////////////////////// // this clears all valid bits @@ -213,7 +220,7 @@ end else begin : gen_piton_offset // wait for incoming requests end else if (!stall_i) begin - // mem requests are for sure invals here + // mem requests are for sure invals or killed misses here if (!mem_rtrn_vld_i) begin dreq_o.ready = 1'b1; // we have a new request @@ -251,8 +258,8 @@ end else begin : gen_piton_offset // we can accept another request // and stay here, but only if no inval is coming in - // note: we are not expecting ifill return packets here... - if (!mem_rtrn_vld_i) begin + // note: ifill return packets may arrive here only if killed... + if (!mem_rtrn_vld_i || (mem_rtrn_i.rtype == ICACHE_IFILL_ACK)) begin dreq_o.ready = 1'b1; if (dreq_i.req) begin state_d = READ; @@ -287,19 +294,25 @@ end else begin : gen_piton_offset // returns. do not write to memory // if the nc bit is set. MISS: begin - // note: this is mutually exclusive with ICACHE_INV_REQ, - // so we do not have to check for invals here - if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_IFILL_ACK) begin - state_d = IDLE; - // only return data if request is not being killed - if (!(dreq_i.kill_s2 || flush_d)) begin - dreq_o.valid = 1'b1; - // only write to cache if this address is cacheable - cache_wren = ~paddr_is_nc; + // if there is an outstanding miss we must wait that it is discarded + if (!outst_miss_q) begin + // note: this is mutually exclusive with ICACHE_INV_REQ, + // so we do not have to check for invals here + if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_IFILL_ACK) begin + state_d = IDLE; + // only return data if request is not being killed + if (!(dreq_i.kill_s2 || flush_d)) begin + dreq_o.valid = 1'b1; + // only write to cache if this address is cacheable + cache_wren = ~paddr_is_nc; + end + // bail out if this request is being killed + end else if (dreq_i.kill_s2 || flush_d) begin + state_d = IDLE; + // track if there is an outstanding miss, + // the next response from memory must be discarded + outst_miss_d = 1'b1; end - // bail out if this request is being killed - end else if (dreq_i.kill_s2 || flush_d) begin - state_d = KILL_MISS; end end ////////////////////////////////// @@ -312,15 +325,6 @@ end else begin : gen_piton_offset state_d = IDLE; end end - ////////////////////////////////// - // killed miss, - // wait until memory responds and - // go back to idle - KILL_MISS: begin - if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_IFILL_ACK) begin - state_d = IDLE; - end - end default: begin // we should never get here state_d = FLUSH; @@ -492,6 +496,7 @@ end else begin : gen_piton_offset cl_offset_q <= '0; repl_way_oh_q <= '0; inv_q <= '0; + outst_miss_q <= '0; end else begin cl_tag_q <= cl_tag_d; flush_cnt_q <= flush_cnt_d; @@ -503,6 +508,7 @@ end else begin : gen_piton_offset cl_offset_q <= cl_offset_d; repl_way_oh_q <= repl_way_oh_d; inv_q <= inv_d; + outst_miss_q <= outst_miss_d; end end diff --git a/hw/vendor/patches/openhwgroup_cva6/0011-cva6_icache-Allow-one-outstanding-killed-miss.patch b/hw/vendor/patches/openhwgroup_cva6/0011-cva6_icache-Allow-one-outstanding-killed-miss.patch new file mode 100644 index 000000000..55580197e --- /dev/null +++ b/hw/vendor/patches/openhwgroup_cva6/0011-cva6_icache-Allow-one-outstanding-killed-miss.patch @@ -0,0 +1,134 @@ +From d9902d6cfb889da4e302f531b9dd31c2987bcb0c Mon Sep 17 00:00:00 2001 +From: Luca Colagrande +Date: Fri, 6 Oct 2023 15:59:08 +0200 +Subject: [PATCH] cva6_icache: Allow one outstanding killed miss + +--- + core/cache_subsystem/cva6_icache.sv | 54 ++++++++++++++++------------- + 1 file changed, 30 insertions(+), 24 deletions(-) + +diff --git a/core/cache_subsystem/cva6_icache.sv b/core/cache_subsystem/cva6_icache.sv +index 6dd677d8..9c081426 100644 +--- a/core/cache_subsystem/cva6_icache.sv ++++ b/core/cache_subsystem/cva6_icache.sv +@@ -66,6 +66,7 @@ module cva6_icache import ariane_pkg::*; import wt_cache_pkg::*; #( + logic cache_wren; // triggers write to cacheline + logic cmp_en_d, cmp_en_q; // enable tag comparison in next cycle. used to cut long path due to NC signal. + logic flush_d, flush_q; // used to register and signal pending flushes ++ logic outst_miss_d, outst_miss_q; // tracks whether there are any outstanding misses + + // replacement strategy + logic update_lfsr; // shift the LFSR +@@ -171,6 +172,7 @@ end else begin : gen_piton_offset + cache_wren = 1'b0; + inv_en = 1'b0; + flush_d = flush_q | flush_i; // register incoming flush ++ outst_miss_d = outst_miss_q; + + // interfaces + dreq_o.ready = 1'b0; +@@ -189,6 +191,11 @@ end else begin : gen_piton_offset + inv_en = 1'b1; + end + ++ // kill an outstanding miss ++ if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_IFILL_ACK && outst_miss_q) begin ++ outst_miss_d = 1'b0; ++ end ++ + unique case (state_q) + ////////////////////////////////// + // this clears all valid bits +@@ -213,7 +220,7 @@ end else begin : gen_piton_offset + // wait for incoming requests + end + else if (!stall_i) begin +- // mem requests are for sure invals here ++ // mem requests are for sure invals or killed misses here + if (!mem_rtrn_vld_i) begin + dreq_o.ready = 1'b1; + // we have a new request +@@ -251,8 +258,8 @@ end else begin : gen_piton_offset + + // we can accept another request + // and stay here, but only if no inval is coming in +- // note: we are not expecting ifill return packets here... +- if (!mem_rtrn_vld_i) begin ++ // note: ifill return packets may arrive here only if killed... ++ if (!mem_rtrn_vld_i || (mem_rtrn_i.rtype == ICACHE_IFILL_ACK)) begin + dreq_o.ready = 1'b1; + if (dreq_i.req) begin + state_d = READ; +@@ -287,19 +294,25 @@ end else begin : gen_piton_offset + // returns. do not write to memory + // if the nc bit is set. + MISS: begin +- // note: this is mutually exclusive with ICACHE_INV_REQ, +- // so we do not have to check for invals here +- if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_IFILL_ACK) begin +- state_d = IDLE; +- // only return data if request is not being killed +- if (!(dreq_i.kill_s2 || flush_d)) begin +- dreq_o.valid = 1'b1; +- // only write to cache if this address is cacheable +- cache_wren = ~paddr_is_nc; ++ // if there is an outstanding miss we must wait that it is discarded ++ if (!outst_miss_q) begin ++ // note: this is mutually exclusive with ICACHE_INV_REQ, ++ // so we do not have to check for invals here ++ if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_IFILL_ACK) begin ++ state_d = IDLE; ++ // only return data if request is not being killed ++ if (!(dreq_i.kill_s2 || flush_d)) begin ++ dreq_o.valid = 1'b1; ++ // only write to cache if this address is cacheable ++ cache_wren = ~paddr_is_nc; ++ end ++ // bail out if this request is being killed ++ end else if (dreq_i.kill_s2 || flush_d) begin ++ state_d = IDLE; ++ // track if there is an outstanding miss, ++ // the next response from memory must be discarded ++ outst_miss_d = 1'b1; + end +- // bail out if this request is being killed +- end else if (dreq_i.kill_s2 || flush_d) begin +- state_d = KILL_MISS; + end + end + ////////////////////////////////// +@@ -312,15 +325,6 @@ end else begin : gen_piton_offset + state_d = IDLE; + end + end +- ////////////////////////////////// +- // killed miss, +- // wait until memory responds and +- // go back to idle +- KILL_MISS: begin +- if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_IFILL_ACK) begin +- state_d = IDLE; +- end +- end + default: begin + // we should never get here + state_d = FLUSH; +@@ -492,6 +496,7 @@ end else begin : gen_piton_offset + cl_offset_q <= '0; + repl_way_oh_q <= '0; + inv_q <= '0; ++ outst_miss_q <= '0; + end else begin + cl_tag_q <= cl_tag_d; + flush_cnt_q <= flush_cnt_d; +@@ -503,6 +508,7 @@ end else begin : gen_piton_offset + cl_offset_q <= cl_offset_d; + repl_way_oh_q <= repl_way_oh_d; + inv_q <= inv_d; ++ outst_miss_q <= outst_miss_d; + end + end + +-- +2.28.0 +