From 54943101d94883528dc1ea03150897fbcac99c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Sun, 1 Nov 2026 09:52:47 +0100 Subject: [PATCH 1/4] asap7/cva6: the D-cache RAMs as upstream has them, made macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit asap7/cva6 had rewritten hpdcache_sram_wbyteenable to instantiate a fakeram7_128x64 macro and dropped its byte enables: the RAM holds both ways of a set in one 64-bit word, so every refill and store hit wrote the whole word and overwrote the other way's data. hpdcache_sram.sv and hpdcache_sram_wbyteenable.sv are upstream cva6's again (3a389af, cv-hpdcache 04de808), unmodified, with upstream's behavioural hpdcache_sram_1rw and hpdcache_sram_wbyteenable_1rw. AUTO_MEMORIES makes each a macro, cva6.memories naming its pins and byte enables: the data RAM (128 x 64, 8 byte enables) and the directory (64 x 28). Fixes #4769 Co-Authored-By: Claude Opus 5.5 Signed-off-by: Øyvind Harboe --- flow/designs/asap7/cva6/config.mk | 16 +-- flow/designs/asap7/cva6/cva6.memories | 119 ++++++++++++++++++ .../hpdcache/rtl/src/common/hpdcache_sram.sv | 32 ++--- .../src/common/hpdcache_sram_wbyteenable.sv | 35 +++--- .../common/macros/behav/hpdcache_sram_1rw.sv | 60 +++++++++ .../behav/hpdcache_sram_wbyteenable_1rw.sv | 63 ++++++++++ 6 files changed, 277 insertions(+), 48 deletions(-) create mode 100644 flow/designs/asap7/cva6/cva6.memories create mode 100644 flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_1rw.sv create mode 100644 flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_wbyteenable_1rw.sv diff --git a/flow/designs/asap7/cva6/config.mk b/flow/designs/asap7/cva6/config.mk index 363f55e6ad..a61e0435ab 100644 --- a/flow/designs/asap7/cva6/config.mk +++ b/flow/designs/asap7/cva6/config.mk @@ -52,7 +52,8 @@ export VERILOG_FILES = $(sort $(wildcard $(SRC_HOME)/common/local/util/ $(SRC_HOME)/core/cache_subsystem/hpdcache/rtl/src/hwpf_stride/hwpf_stride_wrapper.sv \ $(sort $(wildcard $(SRC_HOME)/core/cache_subsystem/*.sv)) \ $(sort $(wildcard $(SRC_HOME)/core/cache_subsystem/hpdcache/rtl/src/common/*.sv)) \ - $(sort $(wildcard $(SRC_HOME)/core/cache_subsystem/hpdcache/rtl/src/common/macros/blackbox/*.sv)) \ + $(SRC_HOME)/core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_1rw.sv \ + $(SRC_HOME)/core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_wbyteenable_1rw.sv \ $(sort $(wildcard $(SRC_HOME)/core/cache_subsystem/hpdcache/rtl/src/utils/*.sv)) \ $(sort $(wildcard $(SRC_HOME)/core/cva6_mmu/*.sv)) \ $(SRC_HOME)/core/cvfpu/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv \ @@ -66,8 +67,6 @@ export VERILOG_FILES = $(sort $(wildcard $(SRC_HOME)/common/local/util/ $(sort $(wildcard $(SRC_HOME)/core/frontend/*.sv)) \ $(SRC_HOME)/vendor/pulp-platform/tech_cells_generic/src/rtl/tc_sram.sv \ $(PLATFORM_DIR)/verilog/fakeram7_64x256.sv \ - $(PLATFORM_DIR)/verilog/fakeram7_128x64.sv \ - $(PLATFORM_DIR)/verilog/fakeram7_64x28.sv \ $(PLATFORM_DIR)/verilog/fakeram7_64x25.sv export VERILOG_INCLUDE_DIRS = $(DESIGN_HOME)/src/$(DESIGN_NICKNAME)/core/include \ @@ -77,15 +76,18 @@ export VERILOG_INCLUDE_DIRS = $(DESIGN_HOME)/src/$(DESIGN_NICKNAME)/core/include export VERILOG_DEFINES += -D HPDCACHE_ASSERT_OFF export ADDITIONAL_LEFS = $(PLATFORM_DIR)/lef/fakeram7_64x256.lef \ - $(PLATFORM_DIR)/lef/fakeram7_128x64.lef \ - $(PLATFORM_DIR)/lef/fakeram7_64x28.lef \ $(PLATFORM_DIR)/lef/fakeram7_64x25.lef export ADDITIONAL_LIBS = $(PLATFORM_DIR)/lib/NLDM/fakeram7_64x256.lib \ - $(PLATFORM_DIR)/lib/NLDM/fakeram7_128x64.lib \ - $(PLATFORM_DIR)/lib/NLDM/fakeram7_64x28.lib \ $(PLATFORM_DIR)/lib/NLDM/fakeram7_64x25.lib +# The D-cache RAMs are upstream's, the RTL unmodified, and AUTO_MEMORIES +# makes each a macro, cva6.memories naming its pins and byte enables: +# the data RAM (hpdcache_sram_wbyteenable_1rw) and the directory +# (hpdcache_sram_1rw). +export AUTO_MEMORIES = 1 +export ADDITIONAL_MEMORIES = $(DESIGN_HOME)/$(PLATFORM)/cva6/cva6.memories + export SDC_FILE = $(DESIGN_HOME)/$(PLATFORM)/$(DESIGN_NAME)/constraint.sdc export CORE_UTILIZATION = 70 diff --git a/flow/designs/asap7/cva6/cva6.memories b/flow/designs/asap7/cva6/cva6.memories new file mode 100644 index 0000000000..884a077d58 --- /dev/null +++ b/flow/designs/asap7/cva6/cva6.memories @@ -0,0 +1,119 @@ +{ + "version": 1, + "memories": [ + { + "name": "hpdcache_sram_1rw", + "rows": 64, + "bits": 28, + "addr_w": 6, + "rw_ports": 1, + "idiomatic": true, + "reason": "the D-cache directory RAM: one read-write port", + "pins": [ + { + "name": "clk", + "direction": "input", + "width": 1, + "port_id": "RW0", + "function": "clk" + }, + { + "name": "cs", + "direction": "input", + "width": 1, + "port_id": "RW0", + "function": "en" + }, + { + "name": "we", + "direction": "input", + "width": 1, + "port_id": "RW0", + "function": "wmode" + }, + { + "name": "addr", + "direction": "input", + "width": 6, + "port_id": "RW0", + "function": "addr" + }, + { + "name": "wdata", + "direction": "input", + "width": 28, + "port_id": "RW0", + "function": "data_in" + }, + { + "name": "rdata", + "direction": "output", + "width": 28, + "port_id": "RW0", + "function": "data_out" + } + ] + }, + { + "name": "hpdcache_sram_wbyteenable_1rw", + "rows": 128, + "bits": 64, + "addr_w": 7, + "rw_ports": 1, + "mask_lanes": 8, + "idiomatic": true, + "reason": "the D-cache data RAM, both ways of a set in a word: one read-write port, byte mask", + "pins": [ + { + "name": "clk", + "direction": "input", + "width": 1, + "port_id": "RW0", + "function": "clk" + }, + { + "name": "cs", + "direction": "input", + "width": 1, + "port_id": "RW0", + "function": "en" + }, + { + "name": "we", + "direction": "input", + "width": 1, + "port_id": "RW0", + "function": "wmode" + }, + { + "name": "addr", + "direction": "input", + "width": 7, + "port_id": "RW0", + "function": "addr" + }, + { + "name": "wdata", + "direction": "input", + "width": 64, + "port_id": "RW0", + "function": "data_in" + }, + { + "name": "wbyteenable", + "direction": "input", + "width": 8, + "port_id": "RW0", + "function": "mask" + }, + { + "name": "rdata", + "direction": "output", + "width": 64, + "port_id": "RW0", + "function": "data_out" + } + ] + } + ] +} diff --git a/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_sram.sv b/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_sram.sv index d078555ac4..d4cab7de79 100644 --- a/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_sram.sv +++ b/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_sram.sv @@ -39,26 +39,18 @@ module hpdcache_sram output logic [DATA_SIZE-1:0] rdata ); - fakeram7_64x28 ram_i ( - .clk(clk), - .ce_in(cs), - .we_in(we), - .addr_in(addr), - .wd_in(wdata), - .rd_out(rdata) + hpdcache_sram_1rw #( + .ADDR_SIZE(ADDR_SIZE), + .DATA_SIZE(DATA_SIZE), + .DEPTH(DEPTH) + ) ram_i ( + .clk, + .rst_n, + .cs, + .we, + .addr, + .wdata, + .rdata ); - // hpdcache_sram_1rw #( - // .ADDR_SIZE(ADDR_SIZE), - // .DATA_SIZE(DATA_SIZE), - // .DEPTH(DEPTH) - // ) ram_i ( - // .clk, - // .rst_n, - // .cs, - // .we, - // .addr, - // .wdata, - // .rdata - // ); endmodule : hpdcache_sram diff --git a/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_sram_wbyteenable.sv b/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_sram_wbyteenable.sv index d0cf76a389..43bdb4506f 100644 --- a/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_sram_wbyteenable.sv +++ b/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_sram_wbyteenable.sv @@ -39,27 +39,20 @@ module hpdcache_sram_wbyteenable input logic [DATA_SIZE/8-1:0] wbyteenable, output logic [DATA_SIZE-1:0] rdata ); - fakeram7_128x64 ram_i ( - .clk (clk), - .ce_in(cs), - .we_in(we), - .addr_in(addr), - .wd_in(wdata), - .rd_out(rdata) + + hpdcache_sram_wbyteenable_1rw #( + .ADDR_SIZE(ADDR_SIZE), + .DATA_SIZE(DATA_SIZE), + .DEPTH(DEPTH) + ) ram_i ( + .clk, + .rst_n, + .cs, + .we, + .addr, + .wdata, + .wbyteenable, + .rdata ); - // hpdcache_sram_wbyteenable_1rw #( - // .ADDR_SIZE(ADDR_SIZE), - // .DATA_SIZE(DATA_SIZE), - // .DEPTH(DEPTH) - // ) ram_i ( - // .clk, - // .rst_n, - // .cs, - // .we, - // .addr, - // .wdata, - // .wbyteenable, - // .rdata - // ); endmodule : hpdcache_sram_wbyteenable diff --git a/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_1rw.sv b/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_1rw.sv new file mode 100644 index 0000000000..7288c731fd --- /dev/null +++ b/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_1rw.sv @@ -0,0 +1,60 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : March, 2020 + * Description : SRAM behavioral model + * History : + */ +module hpdcache_sram_1rw +#( + parameter int unsigned ADDR_SIZE = 0, + parameter int unsigned DATA_SIZE = 0, + parameter int unsigned DEPTH = 2**ADDR_SIZE +) +( + input logic clk, + input logic rst_n, + input logic cs, + input logic we, + input logic [ADDR_SIZE-1:0] addr, + input logic [DATA_SIZE-1:0] wdata, + output logic [DATA_SIZE-1:0] rdata +); + + /* + * Internal memory array declaration + */ + typedef logic [DATA_SIZE-1:0] mem_t [DEPTH]; + mem_t mem; + + /* + * Process to update or read the memory array + */ + always_ff @(posedge clk) + begin : mem_update_ff + if (cs == 1'b1) begin + if (we == 1'b1) begin + mem[addr] <= wdata; + end + rdata <= mem[addr]; + end + end : mem_update_ff +endmodule : hpdcache_sram_1rw diff --git a/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_wbyteenable_1rw.sv b/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_wbyteenable_1rw.sv new file mode 100644 index 0000000000..0e5e2256cc --- /dev/null +++ b/flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_wbyteenable_1rw.sv @@ -0,0 +1,63 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : March, 2020 + * Description : Behavioral model of a 1RW SRAM with write byte enable + * History : + */ +module hpdcache_sram_wbyteenable_1rw +#( + parameter int unsigned ADDR_SIZE = 0, + parameter int unsigned DATA_SIZE = 0, + parameter int unsigned DEPTH = 2**ADDR_SIZE +) +( + input logic clk, + input logic rst_n, + input logic cs, + input logic we, + input logic [ADDR_SIZE-1:0] addr, + input logic [DATA_SIZE-1:0] wdata, + input logic [DATA_SIZE/8-1:0] wbyteenable, + output logic [DATA_SIZE-1:0] rdata +); + + /* + * Internal memory array declaration + */ + typedef logic [DATA_SIZE-1:0] mem_t [DEPTH]; + mem_t mem; + + /* + * Process to update or read the memory array + */ + always_ff @(posedge clk) + begin : mem_update_ff + if (cs == 1'b1) begin + if (we == 1'b1) begin + for (int i = 0; i < DATA_SIZE/8; i++) begin + if (wbyteenable[i]) mem[addr][i*8 +: 8] <= wdata[i*8 +: 8]; + end + end + rdata <= mem[addr]; + end + end : mem_update_ff +endmodule : hpdcache_sram_wbyteenable_1rw From 948c46b565a0cd6af9e095d8da701b475dc25945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Sun, 1 Nov 2026 09:53:01 +0100 Subject: [PATCH 2/4] asap7/cva6: the I-cache RAMs behind the techno cut, made macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit asap7/cva6 had rewritten sram_cache to instantiate fakeram7_64x256 and fakeram7_64x25 in place of its techno cut, dropping the I-cache RAMs' byte enables and replacing tc_sram's read behaviour with a fakeram's. sram_cache.sv is upstream cva6's again, unmodified. Upstream fills its techno cut, tc_sram_wrapper_cache_techno, with pulp's generic tc_sram; SYNTH_VERILOG_SURGERY (surgery.py) puts a single-port SRAM with byte enables there in its place, for AUTO_MEMORIES to make a macro of: the I-cache data (64 x 256, 32 byte enables) and tag (64 x 25, 4 byte enables, the last of them 1 bit, which needs mask_lane_width). The fakeram views leave the config. The Verilog is in surgery/, next to the script: the module as upstream has it (the one in VERILOG_FILES must match it token for token, or the build stops), its replacement, and the two SRAMs. The script reads and writes UTF-8 whatever the locale. tc_sram's read data follows the last read address through idle cycles and writes; an SRAM holds while idle. cva6_icache uses read data only in a cycle after a read, or after idle cycles with no write since that read, so the two return the same data whenever it is used. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018PFLaCzFtFbnWE4nPTDwpC Signed-off-by: Øyvind Harboe --- flow/designs/asap7/cva6/config.mk | 20 +-- flow/designs/asap7/cva6/cva6.memories | 123 ++++++++++++++++++ flow/designs/asap7/cva6/surgery.py | 106 +++++++++++++++ .../cva6/surgery/cva6_icache_data_sram.sv | 24 ++++ .../cva6/surgery/cva6_icache_tag_sram.sv | 26 ++++ .../surgery/tc_sram_wrapper_cache_techno.sv | 40 ++++++ .../tc_sram_wrapper_cache_techno.upstream.sv | 52 ++++++++ .../src/cva6/common/local/util/sram_cache.sv | 94 ++++++------- 8 files changed, 416 insertions(+), 69 deletions(-) create mode 100644 flow/designs/asap7/cva6/surgery.py create mode 100644 flow/designs/asap7/cva6/surgery/cva6_icache_data_sram.sv create mode 100644 flow/designs/asap7/cva6/surgery/cva6_icache_tag_sram.sv create mode 100644 flow/designs/asap7/cva6/surgery/tc_sram_wrapper_cache_techno.sv create mode 100644 flow/designs/asap7/cva6/surgery/tc_sram_wrapper_cache_techno.upstream.sv diff --git a/flow/designs/asap7/cva6/config.mk b/flow/designs/asap7/cva6/config.mk index a61e0435ab..01f6cfe6b6 100644 --- a/flow/designs/asap7/cva6/config.mk +++ b/flow/designs/asap7/cva6/config.mk @@ -65,9 +65,7 @@ export VERILOG_FILES = $(sort $(wildcard $(SRC_HOME)/common/local/util/ $(SRC_HOME)/core/cvfpu/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv \ $(SRC_HOME)/core/cvxif_example/include/cvxif_instr_pkg.sv \ $(sort $(wildcard $(SRC_HOME)/core/frontend/*.sv)) \ - $(SRC_HOME)/vendor/pulp-platform/tech_cells_generic/src/rtl/tc_sram.sv \ - $(PLATFORM_DIR)/verilog/fakeram7_64x256.sv \ - $(PLATFORM_DIR)/verilog/fakeram7_64x25.sv + $(SRC_HOME)/vendor/pulp-platform/tech_cells_generic/src/rtl/tc_sram.sv export VERILOG_INCLUDE_DIRS = $(DESIGN_HOME)/src/$(DESIGN_NICKNAME)/core/include \ $(DESIGN_HOME)/src/$(DESIGN_NICKNAME)/core/cvfpu/src/common_cells/include \ @@ -75,16 +73,12 @@ export VERILOG_INCLUDE_DIRS = $(DESIGN_HOME)/src/$(DESIGN_NICKNAME)/core/include export VERILOG_DEFINES += -D HPDCACHE_ASSERT_OFF -export ADDITIONAL_LEFS = $(PLATFORM_DIR)/lef/fakeram7_64x256.lef \ - $(PLATFORM_DIR)/lef/fakeram7_64x25.lef - -export ADDITIONAL_LIBS = $(PLATFORM_DIR)/lib/NLDM/fakeram7_64x256.lib \ - $(PLATFORM_DIR)/lib/NLDM/fakeram7_64x25.lib - -# The D-cache RAMs are upstream's, the RTL unmodified, and AUTO_MEMORIES -# makes each a macro, cva6.memories naming its pins and byte enables: -# the data RAM (hpdcache_sram_wbyteenable_1rw) and the directory -# (hpdcache_sram_1rw). +# The RAMs are upstream's, the RTL unmodified, and AUTO_MEMORIES makes +# each a macro, cva6.memories naming its pins and byte enables: the +# D-cache data (hpdcache_sram_wbyteenable_1rw) and directory +# (hpdcache_sram_1rw), and the I-cache data and tag, which surgery.py +# puts behind sram_cache's techno cut in place of pulp's tc_sram. +export SYNTH_VERILOG_SURGERY = $(DESIGN_HOME)/$(PLATFORM)/cva6/surgery.py export AUTO_MEMORIES = 1 export ADDITIONAL_MEMORIES = $(DESIGN_HOME)/$(PLATFORM)/cva6/cva6.memories diff --git a/flow/designs/asap7/cva6/cva6.memories b/flow/designs/asap7/cva6/cva6.memories index 884a077d58..cc0fc0cfab 100644 --- a/flow/designs/asap7/cva6/cva6.memories +++ b/flow/designs/asap7/cva6/cva6.memories @@ -1,6 +1,129 @@ { "version": 1, "memories": [ + { + "name": "cva6_icache_data_sram", + "rows": 64, + "bits": 256, + "addr_w": 6, + "rw_ports": 1, + "mask_lanes": 32, + "idiomatic": true, + "reason": "the I-cache data RAM behind the techno cut (surgery.py): one read-write port, byte enables", + "pins": [ + { + "name": "clk", + "direction": "input", + "width": 1, + "port_id": "RW0", + "function": "clk" + }, + { + "name": "cs", + "direction": "input", + "width": 1, + "port_id": "RW0", + "function": "en" + }, + { + "name": "we", + "direction": "input", + "width": 1, + "port_id": "RW0", + "function": "wmode" + }, + { + "name": "addr", + "direction": "input", + "width": 6, + "port_id": "RW0", + "function": "addr" + }, + { + "name": "wdata", + "direction": "input", + "width": 256, + "port_id": "RW0", + "function": "data_in" + }, + { + "name": "be", + "direction": "input", + "width": 32, + "port_id": "RW0", + "function": "mask" + }, + { + "name": "rdata", + "direction": "output", + "width": 256, + "port_id": "RW0", + "function": "data_out" + } + ] + }, + { + "name": "cva6_icache_tag_sram", + "rows": 64, + "bits": 25, + "addr_w": 6, + "rw_ports": 1, + "mask_lanes": 4, + "mask_lane_width": 8, + "idiomatic": true, + "reason": "the I-cache tag RAM behind the techno cut (surgery.py): one read-write port, byte enables, the last 1 bit", + "pins": [ + { + "name": "clk", + "direction": "input", + "width": 1, + "port_id": "RW0", + "function": "clk" + }, + { + "name": "cs", + "direction": "input", + "width": 1, + "port_id": "RW0", + "function": "en" + }, + { + "name": "we", + "direction": "input", + "width": 1, + "port_id": "RW0", + "function": "wmode" + }, + { + "name": "addr", + "direction": "input", + "width": 6, + "port_id": "RW0", + "function": "addr" + }, + { + "name": "wdata", + "direction": "input", + "width": 25, + "port_id": "RW0", + "function": "data_in" + }, + { + "name": "be", + "direction": "input", + "width": 4, + "port_id": "RW0", + "function": "mask" + }, + { + "name": "rdata", + "direction": "output", + "width": 25, + "port_id": "RW0", + "function": "data_out" + } + ] + }, { "name": "hpdcache_sram_1rw", "rows": 64, diff --git a/flow/designs/asap7/cva6/surgery.py b/flow/designs/asap7/cva6/surgery.py new file mode 100644 index 0000000000..08ced7a935 --- /dev/null +++ b/flow/designs/asap7/cva6/surgery.py @@ -0,0 +1,106 @@ +"""SYNTH_VERILOG_SURGERY for cva6: the I-cache RAMs behind the techno cut. + +cva6's sram_cache puts its RAMs behind tc_sram_wrapper_cache_techno, the +techno cut a technology's SRAM goes behind, and upstream fills it with +pulp's generic tc_sram, a model with port arrays and a read latency that +no SRAM macro has. This keeps the wrapper's parameters and ports and puts +a single-port SRAM with byte enables behind it, one module per shape +cv32a65x uses, for AUTO_MEMORIES to make a macro of: the I-cache data, +64 x 256 (32 byte enables), and the tag, 64 x 25 (4 byte enables, the +last of them 1 bit, as tc_sram's). An elaboration-time $error stops any +other shape. + +An SRAM is not tc_sram: tc_sram's read data follows the last read +address, through idle cycles and writes, and a single-port SRAM reads +the address it is given and holds while idle. cva6_icache uses read +data only in a cycle after a read, or after idle cycles with no write +since the read, so the two return the same data whenever it is used. + +The Verilog is in surgery/, next to this script: + +- tc_sram_wrapper_cache_techno.upstream.sv: the module as upstream has it. + The module found in VERILOG_FILES must match it token for token, + comments and whitespace aside, or the build stops. +- tc_sram_wrapper_cache_techno.sv: what replaces it. +- cva6_icache_data_sram.sv, cva6_icache_tag_sram.sv: the two SRAMs, + appended after the replacement. + +Every other file is copied unchanged. +""" + +import argparse +import os +import re +import sys + +RESOURCES = os.path.join(os.path.dirname(os.path.abspath(__file__)), "surgery") +MODULE = "tc_sram_wrapper_cache_techno" + + +def resource(name): + with open(os.path.join(RESOURCES, name), encoding="utf-8") as f: + return f.read() + + +def tokens(text): + """The Verilog text without comments, whitespace collapsed.""" + text = re.sub(r"//[^\n]*", "", text) + text = re.sub(r"/\*.*?\*/", "", text, flags=re.S) + return " ".join(text.split()) + + +def fail(message): + sys.exit("cva6 surgery: " + message) + + +def replace_module(path, text, upstream, replacement): + """Return `text` with MODULE replaced, and whether it was found.""" + found = list( + re.finditer(r"^module\s+%s\b.*?^endmodule\b" % MODULE, text, re.M | re.S) + ) + if len(found) > 1: + fail("%s defines %s %d times" % (path, MODULE, len(found))) + if not found: + return text, False + module = found[0] + if tokens(module.group(0)) != tokens(upstream): + fail( + "%s in %s is not the one in surgery/%s.upstream.sv;" + " upstream changed it, update the surgery" % (MODULE, path, MODULE) + ) + return text[: module.start()] + replacement + text[module.end() :], True + + +def main(): + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("--out-dir", required=True) + parser.add_argument("files", nargs="+") + args = parser.parse_args() + + upstream = resource(MODULE + ".upstream.sv") + replacement = "\n\n".join( + resource(name).rstrip("\n") + for name in ( + MODULE + ".sv", + "cva6_icache_data_sram.sv", + "cva6_icache_tag_sram.sv", + ) + ) + + replaced_in = [] + for path in args.files: + with open(path, encoding="utf-8") as f: + text = f.read() + text, replaced = replace_module(path, text, upstream, replacement) + if replaced: + replaced_in.append(path) + out = os.path.join(args.out_dir, os.path.basename(path)) + with open(out, "w", encoding="utf-8") as f: + f.write(text) + + if len(replaced_in) != 1: + fail("%s found in %d files, not one" % (MODULE, len(replaced_in))) + + +if __name__ == "__main__": + main() diff --git a/flow/designs/asap7/cva6/surgery/cva6_icache_data_sram.sv b/flow/designs/asap7/cva6/surgery/cva6_icache_data_sram.sv new file mode 100644 index 0000000000..4fe26c13a2 --- /dev/null +++ b/flow/designs/asap7/cva6/surgery/cva6_icache_data_sram.sv @@ -0,0 +1,24 @@ +// The I-cache data RAM, behavioural; AUTO_MEMORIES makes it a macro. +// WORDS is 64 where the techno cut instances it; a check may shrink it. +module cva6_icache_data_sram #( + parameter WORDS = 64, + parameter AW = $clog2(WORDS) +) ( + input clk, + input cs, + input we, + input [AW-1:0] addr, + input [255:0] wdata, + input [31:0] be, + output reg [255:0] rdata +); + reg [255:0] mem [0:WORDS-1]; + integer j; + always @(posedge clk) + if (cs) begin + if (we) + for (j = 0; j < 32; j = j + 1) + if (be[j]) mem[addr][j*8 +: 8] <= wdata[j*8 +: 8]; + rdata <= mem[addr]; + end +endmodule diff --git a/flow/designs/asap7/cva6/surgery/cva6_icache_tag_sram.sv b/flow/designs/asap7/cva6/surgery/cva6_icache_tag_sram.sv new file mode 100644 index 0000000000..eab10f5985 --- /dev/null +++ b/flow/designs/asap7/cva6/surgery/cva6_icache_tag_sram.sv @@ -0,0 +1,26 @@ +// The I-cache tag RAM, behavioural; AUTO_MEMORIES makes it a macro. Its +// last byte enable covers the one bit left over, as tc_sram's does. +module cva6_icache_tag_sram #( + parameter WORDS = 64, + parameter AW = $clog2(WORDS) +) ( + input clk, + input cs, + input we, + input [AW-1:0] addr, + input [24:0] wdata, + input [3:0] be, + output reg [24:0] rdata +); + reg [24:0] mem [0:WORDS-1]; + always @(posedge clk) + if (cs) begin + if (we) begin + if (be[0]) mem[addr][7:0] <= wdata[7:0]; + if (be[1]) mem[addr][15:8] <= wdata[15:8]; + if (be[2]) mem[addr][23:16] <= wdata[23:16]; + if (be[3]) mem[addr][24] <= wdata[24]; + end + rdata <= mem[addr]; + end +endmodule diff --git a/flow/designs/asap7/cva6/surgery/tc_sram_wrapper_cache_techno.sv b/flow/designs/asap7/cva6/surgery/tc_sram_wrapper_cache_techno.sv new file mode 100644 index 0000000000..99bcb0405c --- /dev/null +++ b/flow/designs/asap7/cva6/surgery/tc_sram_wrapper_cache_techno.sv @@ -0,0 +1,40 @@ +module tc_sram_wrapper_cache_techno #( + parameter int unsigned NumWords = 32'd1024, // Number of Words in data array + parameter int unsigned DataWidth = 32'd128, // Data signal width + parameter int unsigned ByteWidth = 32'd8, // Width of a data byte + parameter int unsigned NumPorts = 32'd2, // Number of read and write ports + parameter int unsigned Latency = 32'd1, // Latency when the read data is available + parameter SimInit = "none", // Simulation initialization + parameter BYTE_ACCESS = 1, + parameter bit PrintSimCfg = 1'b0, // Print configuration + parameter int unsigned AddrWidth = (NumWords > 32'd1) ? $clog2(NumWords) : 32'd1, + parameter int unsigned BeWidth = (DataWidth + ByteWidth - 32'd1) / ByteWidth, // ceil_div + parameter type addr_t = logic [AddrWidth-1:0], + parameter type data_t = logic [DataWidth-1:0], + parameter type be_t = logic [BeWidth-1:0] +) ( + input logic clk_i, + input logic rst_ni, + input logic [NumPorts-1:0] req_i, + input logic [NumPorts-1:0] we_i, + input addr_t [NumPorts-1:0] addr_i, + input data_t [NumPorts-1:0] wdata_i, + input be_t [NumPorts-1:0] be_i, + output data_t [NumPorts-1:0] rdata_o +); + // SYNTH_VERILOG_SURGERY (asap7/cva6/surgery.py): a single-port SRAM with + // byte enables behind the techno cut, for the shapes cv32a65x uses. + if (NumPorts != 1 || Latency != 1 || ByteWidth != 8 || NumWords != 64 + || !(DataWidth == 256 || DataWidth == 25)) begin : gen_surgery_shape + $error("cva6 surgery: tc_sram_wrapper_cache_techno rewritten for 1 port, latency 1, 64 words of 256 or 25 bits"); + end + if (DataWidth == 256) begin : gen_data + cva6_icache_data_sram i_sram ( + .clk(clk_i), .cs(req_i[0]), .we(we_i[0]), .addr(addr_i[0]), + .wdata(wdata_i[0]), .be(be_i[0]), .rdata(rdata_o[0])); + end else begin : gen_tag + cva6_icache_tag_sram i_sram ( + .clk(clk_i), .cs(req_i[0]), .we(we_i[0]), .addr(addr_i[0]), + .wdata(wdata_i[0]), .be(be_i[0]), .rdata(rdata_o[0])); + end +endmodule diff --git a/flow/designs/asap7/cva6/surgery/tc_sram_wrapper_cache_techno.upstream.sv b/flow/designs/asap7/cva6/surgery/tc_sram_wrapper_cache_techno.upstream.sv new file mode 100644 index 0000000000..ff40353fb6 --- /dev/null +++ b/flow/designs/asap7/cva6/surgery/tc_sram_wrapper_cache_techno.upstream.sv @@ -0,0 +1,52 @@ +module tc_sram_wrapper_cache_techno #( + parameter int unsigned NumWords = 32'd1024, // Number of Words in data array + parameter int unsigned DataWidth = 32'd128, // Data signal width + parameter int unsigned ByteWidth = 32'd8, // Width of a data byte + parameter int unsigned NumPorts = 32'd2, // Number of read and write ports + parameter int unsigned Latency = 32'd1, // Latency when the read data is available + parameter SimInit = "none", // Simulation initialization + parameter BYTE_ACCESS = 1, + parameter bit PrintSimCfg = 1'b0, // Print configuration + // DEPENDENT PARAMETERS, DO NOT OVERWRITE! + parameter int unsigned AddrWidth = (NumWords > 32'd1) ? $clog2(NumWords) : 32'd1, + parameter int unsigned BeWidth = (DataWidth + ByteWidth - 32'd1) / ByteWidth, // ceil_div + parameter type addr_t = logic [AddrWidth-1:0], + parameter type data_t = logic [DataWidth-1:0], + parameter type be_t = logic [BeWidth-1:0] +) ( + input logic clk_i, // Clock + input logic rst_ni, // Asynchronous reset active low + // input ports + input logic [NumPorts-1:0] req_i, // request + input logic [NumPorts-1:0] we_i, // write enable + input addr_t [NumPorts-1:0] addr_i, // request address + input data_t [NumPorts-1:0] wdata_i, // write data + input be_t [NumPorts-1:0] be_i, // write byte enable + // output ports + output data_t [NumPorts-1:0] rdata_o // read data +); + +// synthesis translate_off + + tc_sram #( + .NumWords(NumWords), + .DataWidth(DataWidth), + .ByteWidth(ByteWidth), + .NumPorts(NumPorts), + .Latency(Latency), + .SimInit(SimInit), + .PrintSimCfg(PrintSimCfg) + ) i_tc_sram ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .req_i ( req_i ), + .we_i ( we_i ), + .be_i ( be_i ), + .wdata_i ( wdata_i ), + .addr_i ( addr_i ), + .rdata_o ( rdata_o ) + ); + +// synthesis translate_on + +endmodule diff --git a/flow/designs/src/cva6/common/local/util/sram_cache.sv b/flow/designs/src/cva6/common/local/util/sram_cache.sv index 799c63afcd..7ca7559b7c 100644 --- a/flow/designs/src/cva6/common/local/util/sram_cache.sv +++ b/flow/designs/src/cva6/common/local/util/sram_cache.sv @@ -52,34 +52,25 @@ module sram_cache #( rdata_o = rdata_user[DATA_AND_USER_WIDTH-1:DATA_WIDTH]; ruser_o = rdata_user[USER_WIDTH-1:0]; end - fakeram7_64x256 i_tc_sram_wrapper( - .clk ( clk_i ), - .ce_in ( req_i ), - .we_in ( we_i ), - .wd_in ( wdata_user ), - .addr_in ( addr_i ), - .rd_out ( rdata_user ) - ); - - // tc_sram_wrapper_cache_techno #( - // .NumWords(NUM_WORDS), // Number of Words in data array - // .DataWidth(DATA_AND_USER_WIDTH),// Data signal width - // .ByteWidth(32'd8), // Width of a data byte - // .NumPorts(32'd1), // Number of read and write ports - // .Latency(32'd1), // Latency when the read data is available - // .SimInit(SIM_INIT), // Simulation initialization - // .BYTE_ACCESS(BYTE_ACCESS), // ACCESS byte or full word - // .PrintSimCfg(1'b0) // Print configuration - // ) i_tc_sram_wrapper ( - // .clk_i ( clk_i ), - // .rst_ni ( rst_ni ), - // .req_i ( req_i ), - // .we_i ( we_i ), - // .be_i ( be ), - // .wdata_i ( wdata_user ), - // .addr_i ( addr_i ), - // .rdata_o ( rdata_user ) - // ); + tc_sram_wrapper_cache_techno #( + .NumWords(NUM_WORDS), // Number of Words in data array + .DataWidth(DATA_AND_USER_WIDTH),// Data signal width + .ByteWidth(32'd8), // Width of a data byte + .NumPorts(32'd1), // Number of read and write ports + .Latency(32'd1), // Latency when the read data is available + .SimInit(SIM_INIT), // Simulation initialization + .BYTE_ACCESS(BYTE_ACCESS), // ACCESS byte or full word + .PrintSimCfg(1'b0) // Print configuration + ) i_tc_sram_wrapper ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .req_i ( req_i ), + .we_i ( we_i ), + .be_i ( be ), + .wdata_i ( wdata_user ), + .addr_i ( addr_i ), + .rdata_o ( rdata_user ) + ); end else begin logic [DATA_WIDTH-1:0] wdata_user; logic [DATA_WIDTH-1:0] rdata_user; @@ -91,34 +82,25 @@ module sram_cache #( rdata_o = rdata_user; ruser_o = '0; end - fakeram7_64x25 i_tc_sram_wrapper( - .clk ( clk_i ), - .ce_in ( req_i ), - .we_in ( we_i ), - .wd_in ( wdata_user ), - .addr_in ( addr_i ), - .rd_out ( rdata_user ) - ); - - // tc_sram_wrapper_cache_techno #( - // .NumWords(NUM_WORDS), // Number of Words in data array - // .DataWidth(DATA_AND_USER_WIDTH),// Data signal width - // .ByteWidth(32'd8), // Width of a data byte - // .NumPorts(32'd1), // Number of read and write ports - // .Latency(32'd1), // Latency when the read data is available - // .SimInit(SIM_INIT), // Simulation initialization - // .BYTE_ACCESS(BYTE_ACCESS), // ACCESS byte or full word - // .PrintSimCfg(1'b0) // Print configuration - // ) i_tc_sram_wrapper ( - // .clk_i ( clk_i ), - // .rst_ni ( rst_ni ), - // .req_i ( req_i ), - // .we_i ( we_i ), - // .be_i ( be ), - // .wdata_i ( wdata_user ), - // .addr_i ( addr_i ), - // .rdata_o ( rdata_user ) - // ); + tc_sram_wrapper_cache_techno #( + .NumWords(NUM_WORDS), // Number of Words in data array + .DataWidth(DATA_AND_USER_WIDTH),// Data signal width + .ByteWidth(32'd8), // Width of a data byte + .NumPorts(32'd1), // Number of read and write ports + .Latency(32'd1), // Latency when the read data is available + .SimInit(SIM_INIT), // Simulation initialization + .BYTE_ACCESS(BYTE_ACCESS), // ACCESS byte or full word + .PrintSimCfg(1'b0) // Print configuration + ) i_tc_sram_wrapper ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .req_i ( req_i ), + .we_i ( we_i ), + .be_i ( be ), + .wdata_i ( wdata_user ), + .addr_i ( addr_i ), + .rdata_o ( rdata_user ) + ); end end else begin sram #( From 5b73a13ec32c165baf1b5b6d993c7dd9408acbff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Sun, 1 Nov 2026 09:53:01 +0100 Subject: [PATCH 3/4] cva6: say what differs from upstream MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The README said "with some changes for the RAMs". The RAMs are now upstream's; what still differs are tie-offs for outputs or struct fields cv32a65x leaves undriven, listed by file. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Øyvind Harboe --- flow/designs/src/cva6/README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/flow/designs/src/cva6/README.md b/flow/designs/src/cva6/README.md index cd27453e1c..57b66e5a53 100644 --- a/flow/designs/src/cva6/README.md +++ b/flow/designs/src/cva6/README.md @@ -1,3 +1,15 @@ Extracted from https://github.com/openhwgroup/cva6 -Based on commit 3a389af with some changes for the RAMs +Based on commit 3a389af (cv-hpdcache 04de808, cvfpu 3116391). + +The RAMs are upstream's, unmodified: `asap7/cva6` makes them macros with +AUTO_MEMORIES, and puts the I-cache's behind `sram_cache`'s techno cut +with SYNTH_VERILOG_SURGERY (`asap7/cva6/surgery.py`). + +Changed from upstream, tie-offs for outputs or struct fields cv32a65x +leaves undriven: `core/cache_subsystem/cva6_hpdcache_if_adapter.sv`, +`core/cache_subsystem/cva6_hpdcache_wrapper.sv`, +`core/cache_subsystem/hpdcache/rtl/src/hwpf_stride/hwpf_stride.sv`, +`core/csr_regfile.sv` (`debug_mode_o` gated by `DebugEn`), +`core/cva6_mmu/cva6_mmu.sv`, `core/cvxif_fu.sv`, `core/id_stage.sv`, +`core/load_store_unit.sv` and `core/load_unit.sv`. From afac85c8ced39dcdbe5bcf83b91a1c16b2265d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Fri, 6 Nov 2026 11:40:21 +0100 Subject: [PATCH 4/4] asap7/cva6: Kepler LEC check off for now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI's CTS stage stops in the Kepler LEC check: kepler-formal cannot load the netlist, "cva6_icache_data_sram cannot be found in SNL", the macro AUTO_MEMORIES makes of the I-cache data RAM. A new kepler-formal is in the works; LEC_CHECK is 0 for cva6 until the Kepler team rewires it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018PFLaCzFtFbnWE4nPTDwpC Signed-off-by: Øyvind Harboe --- flow/designs/asap7/cva6/config.mk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/flow/designs/asap7/cva6/config.mk b/flow/designs/asap7/cva6/config.mk index 01f6cfe6b6..3e393c28a8 100644 --- a/flow/designs/asap7/cva6/config.mk +++ b/flow/designs/asap7/cva6/config.mk @@ -82,6 +82,11 @@ export SYNTH_VERILOG_SURGERY = $(DESIGN_HOME)/$(PLATFORM)/cva6/surgery.py export AUTO_MEMORIES = 1 export ADDITIONAL_MEMORIES = $(DESIGN_HOME)/$(PLATFORM)/cva6/cva6.memories +# Kepler LEC off for now: kepler-formal stops on the macros AUTO_MEMORIES +# makes ("cva6_icache_data_sram cannot be found"). A new kepler-formal is +# in the works; the Kepler team rewires LEC for cva6 with it. +export LEC_CHECK = 0 + export SDC_FILE = $(DESIGN_HOME)/$(PLATFORM)/$(DESIGN_NAME)/constraint.sdc export CORE_UTILIZATION = 70