From 31948853c6889a8e246c9f9370fb3c1212face3b Mon Sep 17 00:00:00 2001 From: JeanRochCoulon Date: Tue, 21 Mar 2023 14:18:18 +0100 Subject: [PATCH] Replace WT_DCACHE define by CVA6ConfigCacheType localparam (#1127) --- .github/workflows/ci.yml | 2 +- .gitlab-ci/cva6.yml | 127 +---- Bender.yml | 4 +- Makefile | 4 +- README.md | 2 +- core/Flist.cva6 | 14 +- core/cache_subsystem/axi_adapter.sv | 454 ++++++++++++++++++ core/cache_subsystem/wt_cache_subsystem.sv | 2 +- core/controller.sv | 20 +- core/cva6.sv | 6 +- core/include/ariane_pkg.sv | 13 +- core/include/cv32a60x_config_pkg.sv | 7 + .../cv32a6_ima_sv32_fpga_config_pkg.sv | 7 + core/include/cv32a6_imac_sv0_config_pkg.sv | 7 + core/include/cv32a6_imac_sv32_config_pkg.sv | 7 + core/include/cv32a6_imafc_sv32_config_pkg.sv | 7 + core/include/cv64a6_imafdc_sv39_config_pkg.sv | 7 + ...cv64a6_imafdc_sv39_openpiton_config_pkg.sv | 7 + corev_apu/fpga/src/genesysii.svh | 6 - corev_apu/fpga/src/kc705.svh | 6 - corev_apu/fpga/src/vc707.svh | 6 - pd/synth/Makefile | 2 +- 22 files changed, 552 insertions(+), 165 deletions(-) create mode 100644 core/cache_subsystem/axi_adapter.sv diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7496e6368f..994355767b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: testcase: [asm-tests, mul, amo, fp, benchmarks] - cache: [WB_DCACHE, WT_DCACHE] + target: [cv64a6_imafdc_sv39, cv32a60x, cv32a6_imafc_sv32] env: RISCV: /riscv steps: diff --git a/.gitlab-ci/cva6.yml b/.gitlab-ci/cva6.yml index 1321e528c9..dbe021d095 100644 --- a/.gitlab-ci/cva6.yml +++ b/.gitlab-ci/cva6.yml @@ -53,14 +53,14 @@ build: asm-quest: stage: write-back script: - - make -j${NUM_JOBS} run-asm-tests batch-mode=1 defines=WB_DCACHE + - make -j${NUM_JOBS} run-asm-tests batch-mode=1 dependencies: - build amo-quest: stage: write-back script: - - make -j${NUM_JOBS} run-amo-tests batch-mode=1 defines=WB_DCACHE + - make -j${NUM_JOBS} run-amo-tests batch-mode=1 dependencies: - build @@ -68,14 +68,14 @@ amo-quest: fp-quest: stage: write-back script: - - make -j${NUM_JOBS} run-fp-tests batch-mode=1 defines=WB_DCACHE + - make -j${NUM_JOBS} run-fp-tests batch-mode=1 dependencies: - build bench-quest: stage: write-back script: - - make -j${NUM_JOBS} run-benchmarks batch-mode=1 defines=WB_DCACHE + - make -j${NUM_JOBS} run-benchmarks batch-mode=1 dependencies: - build @@ -83,7 +83,7 @@ bench-quest: asm1-ver: stage: write-back script: - - make -j${NUM_JOBS} run-asm-tests1-verilator defines=WB_DCACHE + - make -j${NUM_JOBS} run-asm-tests1-verilator dependencies: - build @@ -91,7 +91,7 @@ asm1-ver: asm2-ver: stage: write-back script: - - make -j${NUM_JOBS} run-asm-tests2-verilator defines=WB_DCACHE + - make -j${NUM_JOBS} run-asm-tests2-verilator dependencies: - build @@ -99,7 +99,7 @@ asm2-ver: mul-ver: stage: write-back script: - - make -j${NUM_JOBS} run-mul-verilator defines=WB_DCACHE + - make -j${NUM_JOBS} run-mul-verilator dependencies: - build @@ -107,7 +107,7 @@ mul-ver: amo-ver: stage: write-back script: - - make -j${NUM_JOBS} run-amo-verilator defines=WB_DCACHE + - make -j${NUM_JOBS} run-amo-verilator dependencies: - build @@ -115,21 +115,21 @@ amo-ver: fp-ver: stage: write-back script: - - make -j${NUM_JOBS} run-fp-verilator defines=WB_DCACHE + - make -j${NUM_JOBS} run-fp-verilator dependencies: - build bench-ver: stage: write-back script: - - make -j${NUM_JOBS} run-benchmarks-verilator defines=WB_DCACHE + - make -j${NUM_JOBS} run-benchmarks-verilator dependencies: - build bench-ver: stage: write-back script: - - make -j${NUM_JOBS} run-benchmarks-verilator defines=WB_DCACHE + - make -j${NUM_JOBS} run-benchmarks-verilator dependencies: - build @@ -150,108 +150,3 @@ serdiv-quest: dependencies: - build -################################### -# tests with write-through cache system - -s-asm-quest: - stage: write-through - script: - - make -j${NUM_JOBS} run-asm-tests defines=WT_DCACHE batch-mode=1 - dependencies: - - build - -# atomics -s-amo-quest: - stage: write-through - script: - - make -j${NUM_JOBS} run-amo-tests defines=WT_DCACHE batch-mode=1 - dependencies: - - build - -# floating point -s-fp-quest: - stage: write-through - script: - - make -j${NUM_JOBS} run-fp-tests defines=WT_DCACHE batch-mode=1 - dependencies: - - build - -s-bench-quest: - stage: write-through - script: - - make -j${NUM_JOBS} run-benchmarks defines=WT_DCACHE batch-mode=1 - dependencies: - - build - -# rv64ui-p-* tests -s-asm1-ver: - stage: write-through - script: - - make -j${NUM_JOBS} run-asm-tests1-verilator defines=WT_DCACHE - dependencies: - - build - -# rv64ui-v-* tests -s-asm2-ver: - stage: write-through - script: - - make -j${NUM_JOBS} run-asm-tests2-verilator defines=WT_DCACHE - dependencies: - - build - -# rv64um-*-* tests -mul-ver: - stage: write-through - script: - - make -j${NUM_JOBS} run-mul-verilator defines=WT_DCACHE - dependencies: - - build - -# atomics -amo-ver: - stage: write-through - script: - - make -j${NUM_JOBS} run-amo-verilator defines=WT_DCACHE - dependencies: - - build - -# floating point -s-fp-ver: - stage: write-through - script: - - make -j${NUM_JOBS} run-fp-verilator defines=WT_DCACHE - dependencies: - - build - -s-bench-ver: - stage: write-through - script: - - make -j${NUM_JOBS} run-benchmarks-verilator defines=WT_DCACHE - dependencies: - - build - -s-icache-quest: - stage: write-through - script: - - cd tb/tb_icache/ - - make simc - - "grep 'CI: PASSED' summary.rep" - -s-dcache-quest: - stage: write-through - script: - - cd tb/tb_wt_dcache/ - - make simc - - "grep 'CI: PASSED' RD0_summary.rep" - - "grep 'CI: PASSED' RD1_summary.rep" - - "grep 'CI: PASSED' TB_MEM_summary.rep" - dependencies: - - build - -# s-torture: -# stage: write-through -# script: -# - make torture-rtest defines=WT_DCACHE batch-mode=1 -# - make torture-rtest-verilator defines=WT_DCACHE -# dependencies: -# - build diff --git a/Bender.yml b/Bender.yml index 4c38020d7f..5874a7b0a4 100644 --- a/Bender.yml +++ b/Bender.yml @@ -20,9 +20,7 @@ dependencies: frozen: true sources: - - defines: - WT_DCACHE: 1 - files: + - files: - target: cv64a6_imafdc_sv39 files: - core/include/cv64a6_imafdc_sv39_config_pkg.sv diff --git a/Makefile b/Makefile index 9b0193e105..77565a7434 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ verilator ?= verilator # traget option target-options ?= # additional definess -defines ?= WT_DCACHE+RVFI_TRACE +defines ?= RVFI_TRACE # test name for torture runs (binary name) test-location ?= output/test # set to either nothing or -log @@ -282,7 +282,7 @@ endif vcs_build: $(dpi-library)/ariane_dpi.so mkdir -p $(vcs-library) cd $(vcs-library) &&\ - vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog +define+$(defines) -f ../core/Flist.cva6 &&\ + vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog +define+$(defines) -assert svaext -f ../core/Flist.cva6 &&\ vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog +define+$(defines) $(filter %.sv,$(ariane_pkg)) +incdir+core/include/+$(VCS_HOME)/etc/uvm-1.2/dpi &&\ vhdlan $(if $(VERDI), -kdb,) -full64 -nc $(filter %.vhd,$(uart_src)) &&\ vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog -assert svaext +define+$(defines) $(filter %.sv,$(src)) +incdir+../vendor/pulp-platform/common_cells/include/+../vendor/pulp-platform/axi/include/+../corev_apu/register_interface/include/ &&\ diff --git a/README.md b/README.md index c8e74b4f34..de3222dc20 100644 --- a/README.md +++ b/README.md @@ -328,7 +328,7 @@ CVA6 has preliminary support for the OpenPiton distributed cache system from Pri The corresponding integration patches will be released on [OpenPiton GitHub repository](https://github.com/PrincetonUniversity/openpiton). Check the `README` in that repository to see how to use CVA6 in the OpenPiton setting. -To activate the different cache system, compile your code with the macro `WT_DCACHE` (set by default). +To activate the different cache system, compile your code with the macro `DCACHE_TYPE`. ## Planned Improvements diff --git a/core/Flist.cva6 b/core/Flist.cva6 index 1be54b7924..3b25761499 100644 --- a/core/Flist.cva6 +++ b/core/Flist.cva6 @@ -25,8 +25,6 @@ // /////////////////////////////////////////////////////////////////////////////// -+define+WT_DCACHE - //FPGA memories ${CVA6_REPO_DIR}/vendor/pulp-platform/fpga-support/rtl/SyncDpRam.sv ${CVA6_REPO_DIR}/vendor/pulp-platform/fpga-support/rtl/AsyncDpRam.sv @@ -62,6 +60,11 @@ ${CVA6_REPO_DIR}/core/cvxif_example/instr_decoder.sv ${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/cf_math_pkg.sv ${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/fifo_v3.sv ${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lfsr.sv +${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lfsr_8bit.sv +${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/stream_arbiter.sv +${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/stream_arbiter_flushable.sv +${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/stream_mux.sv +${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/stream_demux.sv ${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lzc.sv ${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/rr_arb_tree.sv ${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/shift_reg.sv @@ -146,6 +149,13 @@ ${CVA6_REPO_DIR}/core/cache_subsystem/wt_dcache.sv ${CVA6_REPO_DIR}/core/cache_subsystem/cva6_icache.sv ${CVA6_REPO_DIR}/core/cache_subsystem/wt_cache_subsystem.sv ${CVA6_REPO_DIR}/core/cache_subsystem/wt_axi_adapter.sv +${CVA6_REPO_DIR}/core/cache_subsystem/tag_cmp.sv +${CVA6_REPO_DIR}/core/cache_subsystem/axi_adapter.sv +${CVA6_REPO_DIR}/core/cache_subsystem/miss_handler.sv +${CVA6_REPO_DIR}/core/cache_subsystem/cache_ctrl.sv +${CVA6_REPO_DIR}/core/cache_subsystem/cva6_icache_axi_wrapper.sv +${CVA6_REPO_DIR}/core/cache_subsystem/std_cache_subsystem.sv +${CVA6_REPO_DIR}/core/cache_subsystem/std_nbdcache.sv // Physical Memory Protection // NOTE: pmp.sv modified for DSIM (unchanged for other simulators) diff --git a/core/cache_subsystem/axi_adapter.sv b/core/cache_subsystem/axi_adapter.sv new file mode 100644 index 0000000000..c08eddd738 --- /dev/null +++ b/core/cache_subsystem/axi_adapter.sv @@ -0,0 +1,454 @@ +/* Copyright 2018 ETH Zurich and University of Bologna. + * Copyright and related rights are licensed under the Solderpad Hardware + * License, Version 0.51 (the “License”); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law + * or agreed to in writing, software, hardware and materials distributed under + * this 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. + * + * File: axi_adapter.sv + * Author: Florian Zaruba + * Date: 1.8.2018 + * + * Description: Manages communication with the AXI Bus + */ +//import std_cache_pkg::*; + +module axi_adapter #( + parameter int unsigned DATA_WIDTH = 256, + parameter logic CRITICAL_WORD_FIRST = 0, // the AXI subsystem needs to support wrapping reads for this feature + parameter int unsigned CACHELINE_BYTE_OFFSET = 8, + parameter int unsigned AXI_ADDR_WIDTH = 0, + parameter int unsigned AXI_DATA_WIDTH = 0, + parameter int unsigned AXI_ID_WIDTH = 0, + parameter type axi_req_t = ariane_axi::req_t, + parameter type axi_rsp_t = ariane_axi::resp_t +)( + input logic clk_i, // Clock + input logic rst_ni, // Asynchronous reset active low + + input logic req_i, + input ariane_axi::ad_req_t type_i, + input ariane_pkg::amo_t amo_i, + output logic gnt_o, + input logic [riscv::XLEN-1:0] addr_i, + input logic we_i, + input logic [(DATA_WIDTH/AXI_DATA_WIDTH)-1:0][AXI_DATA_WIDTH-1:0] wdata_i, + input logic [(DATA_WIDTH/AXI_DATA_WIDTH)-1:0][(AXI_DATA_WIDTH/8)-1:0] be_i, + input logic [1:0] size_i, + input logic [AXI_ID_WIDTH-1:0] id_i, + // read port + output logic valid_o, + output logic [(DATA_WIDTH/AXI_DATA_WIDTH)-1:0][AXI_DATA_WIDTH-1:0] rdata_o, + output logic [AXI_ID_WIDTH-1:0] id_o, + // critical word - read port + output logic [AXI_DATA_WIDTH-1:0] critical_word_o, + output logic critical_word_valid_o, + // AXI port + output axi_req_t axi_req_o, + input axi_rsp_t axi_resp_i +); + localparam BURST_SIZE = (DATA_WIDTH/AXI_DATA_WIDTH)-1; + localparam ADDR_INDEX = ($clog2(DATA_WIDTH/AXI_DATA_WIDTH) > 0) ? $clog2(DATA_WIDTH/AXI_DATA_WIDTH) : 1; + + enum logic [3:0] { + IDLE, WAIT_B_VALID, WAIT_AW_READY, WAIT_LAST_W_READY, WAIT_LAST_W_READY_AW_READY, WAIT_AW_READY_BURST, + WAIT_R_VALID, WAIT_R_VALID_MULTIPLE, COMPLETE_READ, WAIT_AMO_R_VALID + } state_q, state_d; + + // counter for AXI transfers + logic [ADDR_INDEX-1:0] cnt_d, cnt_q; + logic [(DATA_WIDTH/AXI_DATA_WIDTH)-1:0][AXI_DATA_WIDTH-1:0] cache_line_d, cache_line_q; + // save the address for a read, as we allow for non-cacheline aligned accesses + logic [(DATA_WIDTH/AXI_DATA_WIDTH)-1:0] addr_offset_d, addr_offset_q; + logic [AXI_ID_WIDTH-1:0] id_d, id_q; + logic [ADDR_INDEX-1:0] index; + // save the atomic operation and size + ariane_pkg::amo_t amo_d, amo_q; + logic [1:0] size_d, size_q; + + always_comb begin : axi_fsm + // Default assignments + axi_req_o.aw_valid = 1'b0; + // Cast to AXI address width + axi_req_o.aw.addr = addr_i; + axi_req_o.aw.prot = 3'b0; + axi_req_o.aw.region = 4'b0; + axi_req_o.aw.len = 8'b0; + axi_req_o.aw.size = {1'b0, size_i}; // 1, 2, 4 or 8 bytes + axi_req_o.aw.burst = axi_pkg::BURST_INCR; // Use BURST_INCR for AXI regular transaction + axi_req_o.aw.lock = 1'b0; + axi_req_o.aw.cache = axi_pkg::CACHE_MODIFIABLE; + axi_req_o.aw.qos = 4'b0; + axi_req_o.aw.id = id_i; + axi_req_o.aw.atop = atop_from_amo(amo_i); + axi_req_o.aw.user = '0; + + axi_req_o.ar_valid = 1'b0; + // Cast to AXI address width + axi_req_o.ar.addr = addr_i; + // in case of a single request or wrapping transfer we can simply begin at the address, if we want to request a cache-line + // with an incremental transfer we need to output the corresponding base address of the cache line + if (!CRITICAL_WORD_FIRST && type_i != ariane_axi::SINGLE_REQ) begin + axi_req_o.ar.addr[CACHELINE_BYTE_OFFSET-1:0] = '0; + end + axi_req_o.ar.prot = 3'b0; + axi_req_o.ar.region = 4'b0; + axi_req_o.ar.len = 8'b0; + axi_req_o.ar.size = {1'b0, size_i}; // 1, 2, 4 or 8 bytes + axi_req_o.ar.burst = (CRITICAL_WORD_FIRST ? axi_pkg::BURST_WRAP : axi_pkg::BURST_INCR); // wrapping transfer in case of a critical word first strategy + axi_req_o.ar.lock = 1'b0; + axi_req_o.ar.cache = axi_pkg::CACHE_MODIFIABLE; + axi_req_o.ar.qos = 4'b0; + axi_req_o.ar.id = id_i; + axi_req_o.ar.user = '0; + + axi_req_o.w_valid = 1'b0; + axi_req_o.w.data = wdata_i[0]; + axi_req_o.w.strb = be_i[0]; + axi_req_o.w.last = 1'b0; + axi_req_o.w.user = '0; + + axi_req_o.b_ready = 1'b0; + axi_req_o.r_ready = 1'b0; + + gnt_o = 1'b0; + valid_o = 1'b0; + id_o = axi_resp_i.r.id; + + critical_word_o = axi_resp_i.r.data; + critical_word_valid_o = 1'b0; + rdata_o = cache_line_q; + + state_d = state_q; + cnt_d = cnt_q; + cache_line_d = cache_line_q; + addr_offset_d = addr_offset_q; + id_d = id_q; + amo_d = amo_q; + size_d = size_q; + index = '0; + + case (state_q) + + IDLE: begin + cnt_d = '0; + // we have an incoming request + if (req_i) begin + // is this a read or write? + // write + if (we_i) begin + // the data is valid + axi_req_o.aw_valid = 1'b1; + axi_req_o.w_valid = 1'b1; + // store-conditional requires exclusive access + axi_req_o.aw.lock = amo_i == ariane_pkg::AMO_SC; + // its a single write + if (type_i == ariane_axi::SINGLE_REQ) begin + // only a single write so the data is already the last one + axi_req_o.w.last = 1'b1; + // single req can be granted here + gnt_o = axi_resp_i.aw_ready & axi_resp_i.w_ready; + case ({axi_resp_i.aw_ready, axi_resp_i.w_ready}) + 2'b11: state_d = WAIT_B_VALID; + 2'b01: state_d = WAIT_AW_READY; + 2'b10: state_d = WAIT_LAST_W_READY; + default: state_d = IDLE; + endcase + + if (axi_resp_i.aw_ready) begin + amo_d = amo_i; + size_d = size_i; + end + + // its a request for the whole cache line + end else begin + // bursts of AMOs unsupported + assert (amo_i == ariane_pkg::AMO_NONE) + else $fatal("Bursts of atomic operations are not supported"); + + axi_req_o.aw.len = BURST_SIZE; // number of bursts to do + axi_req_o.w.data = wdata_i[0]; + axi_req_o.w.strb = be_i[0]; + + if (axi_resp_i.w_ready) + cnt_d = BURST_SIZE - 1; + else + cnt_d = BURST_SIZE; + + case ({axi_resp_i.aw_ready, axi_resp_i.w_ready}) + 2'b11: state_d = WAIT_LAST_W_READY; + 2'b01: state_d = WAIT_LAST_W_READY_AW_READY; + 2'b10: state_d = WAIT_LAST_W_READY; + default:; + endcase + end + // read + end else begin + + axi_req_o.ar_valid = 1'b1; + // load-reserved requires exclusive access + axi_req_o.ar.lock = amo_i == ariane_pkg::AMO_LR; + + gnt_o = axi_resp_i.ar_ready; + if (type_i != ariane_axi::SINGLE_REQ) begin + assert (amo_i == ariane_pkg::AMO_NONE) + else $fatal("Bursts of atomic operations are not supported"); + + axi_req_o.ar.len = BURST_SIZE; + cnt_d = BURST_SIZE; + end + + if (axi_resp_i.ar_ready) begin + state_d = (type_i == ariane_axi::SINGLE_REQ) ? WAIT_R_VALID : WAIT_R_VALID_MULTIPLE; + addr_offset_d = addr_i[ADDR_INDEX-1+3:3]; + end + end + end + end + + // ~> from single write + WAIT_AW_READY: begin + axi_req_o.aw_valid = 1'b1; + + if (axi_resp_i.aw_ready) begin + gnt_o = 1'b1; + state_d = WAIT_B_VALID; + amo_d = amo_i; + size_d = size_i; + end + end + + // ~> we need to wait for an aw_ready and there is at least one outstanding write + WAIT_LAST_W_READY_AW_READY: begin + axi_req_o.w_valid = 1'b1; + axi_req_o.w.last = (cnt_q == '0); + if (type_i == ariane_axi::SINGLE_REQ) begin + axi_req_o.w.data = wdata_i[0]; + axi_req_o.w.strb = be_i[0]; + end else begin + axi_req_o.w.data = wdata_i[BURST_SIZE-cnt_q]; + axi_req_o.w.strb = be_i[BURST_SIZE-cnt_q]; + end + axi_req_o.aw_valid = 1'b1; + // we are here because we want to write a cache line + axi_req_o.aw.len = BURST_SIZE; + // we got an aw_ready + case ({axi_resp_i.aw_ready, axi_resp_i.w_ready}) + // we got an aw ready + 2'b01: begin + // are there any outstanding transactions? + if (cnt_q == 0) + state_d = WAIT_AW_READY_BURST; + else // yes, so reduce the count and stay here + cnt_d = cnt_q - 1; + end + 2'b10: state_d = WAIT_LAST_W_READY; + 2'b11: begin + // we are finished + if (cnt_q == 0) begin + state_d = WAIT_B_VALID; + gnt_o = 1'b1; + // there are outstanding transactions + end else begin + state_d = WAIT_LAST_W_READY; + cnt_d = cnt_q - 1; + end + end + default:; + endcase + + end + + // ~> all data has already been sent, we are only waiting for the aw_ready + WAIT_AW_READY_BURST: begin + axi_req_o.aw_valid = 1'b1; + axi_req_o.aw.len = BURST_SIZE; + + if (axi_resp_i.aw_ready) begin + state_d = WAIT_B_VALID; + gnt_o = 1'b1; + end + end + + // ~> from write, there is an outstanding write + WAIT_LAST_W_READY: begin + axi_req_o.w_valid = 1'b1; + + if (type_i != ariane_axi::SINGLE_REQ) begin + axi_req_o.w.data = wdata_i[BURST_SIZE-cnt_q]; + axi_req_o.w.strb = be_i[BURST_SIZE-cnt_q]; + end + + // this is the last write + if (cnt_q == '0) begin + axi_req_o.w.last = 1'b1; + if (axi_resp_i.w_ready) begin + state_d = WAIT_B_VALID; + gnt_o = 1'b1; + end + end else if (axi_resp_i.w_ready) begin + cnt_d = cnt_q - 1; + end + end + + // ~> finish write transaction + WAIT_B_VALID: begin + id_o = axi_resp_i.b.id; + + // Write is valid + if (axi_resp_i.b_valid) begin + axi_req_o.b_ready = 1'b1; + + // some atomics must wait for read data + // we only accept it after accepting bvalid + if (amo_returns_data(amo_q)) begin + if (axi_resp_i.r_valid) begin + // return read data if valid + valid_o = 1'b1; + axi_req_o.r_ready = 1'b1; + state_d = IDLE; + rdata_o = axi_resp_i.r.data; + end else begin + // wait otherwise + state_d = WAIT_AMO_R_VALID; + end + end else begin + valid_o = 1'b1; + state_d = IDLE; + + // store-conditional response + if (amo_q == ariane_pkg::AMO_SC) begin + if (axi_resp_i.b.resp == axi_pkg::RESP_EXOKAY) begin + // success -> return 0 + rdata_o = 1'b0; + end else begin + // failure -> when request is 64-bit, return 1; + // when request is 32-bit place a 1 in both upper + // and lower half words. The right word will be + // realigned/masked externally + rdata_o = size_q == 2'b10 ? (1'b1 << 32) | 64'b1 : 64'b1; + end + end + end + end + end + + // ~> some atomics wait for read data + WAIT_AMO_R_VALID: begin + // acknowledge data and terminate atomic + if (axi_resp_i.r_valid) begin + axi_req_o.r_ready = 1'b1; + state_d = IDLE; + valid_o = 1'b1; + rdata_o = axi_resp_i.r.data; + end + end + + // ~> cacheline read, single read + WAIT_R_VALID_MULTIPLE, WAIT_R_VALID: begin + if (CRITICAL_WORD_FIRST) + index = addr_offset_q + (BURST_SIZE-cnt_q); + else + index = BURST_SIZE-cnt_q; + + // reads are always wrapping here + axi_req_o.r_ready = 1'b1; + // this is the first read a.k.a the critical word + if (axi_resp_i.r_valid) begin + if (CRITICAL_WORD_FIRST) begin + // this is the first word of a cacheline read, e.g.: the word which was causing the miss + if (state_q == WAIT_R_VALID_MULTIPLE && cnt_q == BURST_SIZE) begin + critical_word_valid_o = 1'b1; + critical_word_o = axi_resp_i.r.data; + end + end else begin + // check if the address offset matches - then we are getting the critical word + if (index == addr_offset_q) begin + critical_word_valid_o = 1'b1; + critical_word_o = axi_resp_i.r.data; + end + end + + // this is the last read + if (axi_resp_i.r.last) begin + id_d = axi_resp_i.r.id; + state_d = COMPLETE_READ; + end + + // save the word + if (state_q == WAIT_R_VALID_MULTIPLE) begin + cache_line_d[index] = axi_resp_i.r.data; + + end else + cache_line_d[0] = axi_resp_i.r.data; + + // Decrease the counter + cnt_d = cnt_q - 1; + end + end + // ~> read is complete + COMPLETE_READ: begin + valid_o = 1'b1; + state_d = IDLE; + id_o = id_q; + end + endcase + end + + // ---------------- + // Registers + // ---------------- + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + // start in flushing state and initialize the memory + state_q <= IDLE; + cnt_q <= '0; + cache_line_q <= '0; + addr_offset_q <= '0; + id_q <= '0; + amo_q <= ariane_pkg::AMO_NONE; + size_q <= '0; + end else begin + state_q <= state_d; + cnt_q <= cnt_d; + cache_line_q <= cache_line_d; + addr_offset_q <= addr_offset_d; + id_q <= id_d; + amo_q <= amo_d; + size_q <= size_d; + end + end + + function automatic axi_pkg::atop_t atop_from_amo(ariane_pkg::amo_t amo); + axi_pkg::atop_t result = 6'b000000; + + unique case(amo) + ariane_pkg::AMO_NONE: result = {axi_pkg::ATOP_NONE, 4'b0000}; + ariane_pkg::AMO_SWAP: result = {axi_pkg::ATOP_ATOMICSWAP}; + ariane_pkg::AMO_ADD : result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_ADD}; + ariane_pkg::AMO_AND : result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_CLR}; + ariane_pkg::AMO_OR : result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_SET}; + ariane_pkg::AMO_XOR : result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_EOR}; + ariane_pkg::AMO_MAX : result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_SMAX}; + ariane_pkg::AMO_MAXU: result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_UMAX}; + ariane_pkg::AMO_MIN : result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_SMIN}; + ariane_pkg::AMO_MINU: result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_UMIN}; + ariane_pkg::AMO_CAS1: result = {axi_pkg::ATOP_NONE, 4'b0000}; // Unsupported + ariane_pkg::AMO_CAS2: result = {axi_pkg::ATOP_NONE, 4'b0000}; // Unsupported + default: result = 6'b000000; + endcase + + return result; + endfunction + + function automatic logic amo_returns_data(ariane_pkg::amo_t amo); + axi_pkg::atop_t atop = atop_from_amo(amo); + logic is_load = atop[5:4] == axi_pkg::ATOP_ATOMICLOAD; + logic is_swap_or_cmp = atop[5:4] == axi_pkg::ATOP_ATOMICSWAP[5:4]; + return is_load || is_swap_or_cmp; + endfunction + +endmodule diff --git a/core/cache_subsystem/wt_cache_subsystem.sv b/core/cache_subsystem/wt_cache_subsystem.sv index 021d78ee1a..b0d375281b 100644 --- a/core/cache_subsystem/wt_cache_subsystem.sv +++ b/core/cache_subsystem/wt_cache_subsystem.sv @@ -14,7 +14,7 @@ // coherent memory system. // // Define PITON_ARIANE if you want to use this cache. -// Define WT_DCACHE if you want to use this cache +// Define DCACHE_TYPE if you want to use this cache // with a standard 64 bit AXI interface instead of the OpenPiton // L1.5 interface. diff --git a/core/controller.sv b/core/controller.sv index 6e8a1dc2d2..95ead80d99 100644 --- a/core/controller.sv +++ b/core/controller.sv @@ -81,10 +81,10 @@ module controller import ariane_pkg::*; ( flush_ex_o = 1'b1; // this is not needed in the case since we // have a write-through cache in this case -`ifndef WT_DCACHE - flush_dcache = 1'b1; - fence_active_d = 1'b1; -`endif + if (DCACHE_TYPE == cva6_config_pkg::WB) begin + flush_dcache = 1'b1; + fence_active_d = 1'b1; + end end // --------------------------------- @@ -99,15 +99,15 @@ module controller import ariane_pkg::*; ( flush_icache_o = 1'b1; // this is not needed in the case since we // have a write-through cache in this case -`ifndef WT_DCACHE - flush_dcache = 1'b1; - fence_active_d = 1'b1; -`endif + if (DCACHE_TYPE == cva6_config_pkg::WB) begin + flush_dcache = 1'b1; + fence_active_d = 1'b1; + end end // this is not needed in the case since we // have a write-through cache in this case -`ifndef WT_DCACHE + if (DCACHE_TYPE == cva6_config_pkg::WB) begin // wait for the acknowledge here if (flush_dcache_ack_i && fence_active_q) begin fence_active_d = 1'b0; @@ -115,7 +115,7 @@ module controller import ariane_pkg::*; ( end else if (fence_active_q) begin flush_dcache = 1'b1; end -`endif + end // --------------------------------- // SFENCE.VMA // --------------------------------- diff --git a/core/cva6.sv b/core/cva6.sv index 0167ab0d82..622e6e44b3 100644 --- a/core/cva6.sv +++ b/core/cva6.sv @@ -684,7 +684,7 @@ module cva6 import ariane_pkg::*; #( // Cache Subsystem // ------------------- -`ifdef WT_DCACHE + if (DCACHE_TYPE == cva6_config_pkg::WT) begin // this is a cache subsystem that is compatible with OpenPiton wt_cache_subsystem #( .ArianeCfg ( ArianeCfg ), @@ -728,7 +728,7 @@ module cva6 import ariane_pkg::*; #( .axi_resp_i ( axi_resp_i ) `endif ); -`else + end else begin std_cache_subsystem #( // note: this only works with one cacheable region @@ -774,7 +774,7 @@ module cva6 import ariane_pkg::*; #( .axi_resp_i ( axi_resp_i ) ); assign dcache_commit_wbuffer_not_ni = 1'b1; -`endif + end // ------------------- // Parameter Check diff --git a/core/include/ariane_pkg.sv b/core/include/ariane_pkg.sv index a1e83902d8..8e06d96892 100644 --- a/core/include/ariane_pkg.sv +++ b/core/include/ariane_pkg.sv @@ -142,15 +142,14 @@ package ariane_pkg; // depth of store-buffers, this needs to be a power of two localparam int unsigned DEPTH_SPEC = 4; -`ifdef WT_DCACHE - // in this case we can use a small commit queue since we have a write buffer in the dcache + localparam int unsigned DCACHE_TYPE = cva6_config_pkg::CVA6ConfigDcacheType; + // if DCACHE_TYPE = cva6_config_pkg::WT + // we can use a small commit queue since we have a write buffer in the dcache // we could in principle do without the commit queue in this case, but the timing degrades if we do that due // to longer paths into the commit stage - localparam int unsigned DEPTH_COMMIT = 4; -`else + // if DCACHE_TYPE = cva6_config_pkg::WB // allocate more space for the commit buffer to be on the save side, this needs to be a power of two - localparam int unsigned DEPTH_COMMIT = 8; -`endif + localparam int unsigned DEPTH_COMMIT = (DCACHE_TYPE == cva6_config_pkg::WT) ? 4 : 8; localparam bit FPGA_EN = cva6_config_pkg::CVA6ConfigFPGAEn; // Is FPGA optimization of CV32A6 @@ -692,7 +691,7 @@ package ariane_pkg; localparam int unsigned DATA_TLB_ENTRIES = cva6_config_pkg::CVA6ConfigDataTlbEntries; // ------------------- - // Performance counter + // Performance counter // ------------------- localparam bit PERF_COUNTER_EN = cva6_config_pkg::CVA6ConfigPerfCounterEn; diff --git a/core/include/cv32a60x_config_pkg.sv b/core/include/cv32a60x_config_pkg.sv index 93526fd036..f7a302d8e7 100644 --- a/core/include/cv32a60x_config_pkg.sv +++ b/core/include/cv32a60x_config_pkg.sv @@ -10,6 +10,11 @@ package cva6_config_pkg; + typedef enum logic { + WB = 0, + WT = 1 + } cache_type_t ; + localparam CVA6ConfigXlen = 32; localparam CVA6ConfigFpuEn = 0; @@ -57,4 +62,6 @@ package cva6_config_pkg; localparam CVA6ConfigPerfCounterEn = 0; + localparam CVA6ConfigDcacheType = WT; + endpackage diff --git a/core/include/cv32a6_ima_sv32_fpga_config_pkg.sv b/core/include/cv32a6_ima_sv32_fpga_config_pkg.sv index 13f175bb74..b3fecc0031 100644 --- a/core/include/cv32a6_ima_sv32_fpga_config_pkg.sv +++ b/core/include/cv32a6_ima_sv32_fpga_config_pkg.sv @@ -10,6 +10,11 @@ package cva6_config_pkg; + typedef enum logic { + WB = 0, + WT = 1 + } cache_type_t ; + localparam CVA6ConfigXlen = 32; localparam CVA6ConfigFpuEn = 0; @@ -57,4 +62,6 @@ package cva6_config_pkg; localparam CVA6ConfigPerfCounterEn = 0; + localparam CVA6ConfigDcacheType = WT; + endpackage diff --git a/core/include/cv32a6_imac_sv0_config_pkg.sv b/core/include/cv32a6_imac_sv0_config_pkg.sv index 33209f6399..6240a2b338 100644 --- a/core/include/cv32a6_imac_sv0_config_pkg.sv +++ b/core/include/cv32a6_imac_sv0_config_pkg.sv @@ -10,6 +10,11 @@ package cva6_config_pkg; + typedef enum logic { + WB = 0, + WT = 1 + } cache_type_t; + localparam CVA6ConfigXlen = 32; localparam CVA6ConfigFpuEn = 0; @@ -57,4 +62,6 @@ package cva6_config_pkg; localparam CVA6ConfigPerfCounterEn = 1; + localparam CVA6ConfigDcacheType = WT; + endpackage diff --git a/core/include/cv32a6_imac_sv32_config_pkg.sv b/core/include/cv32a6_imac_sv32_config_pkg.sv index 33209f6399..e51c272263 100644 --- a/core/include/cv32a6_imac_sv32_config_pkg.sv +++ b/core/include/cv32a6_imac_sv32_config_pkg.sv @@ -10,6 +10,11 @@ package cva6_config_pkg; + typedef enum logic { + WB = 0, + WT = 1 + } cache_type_t ; + localparam CVA6ConfigXlen = 32; localparam CVA6ConfigFpuEn = 0; @@ -57,4 +62,6 @@ package cva6_config_pkg; localparam CVA6ConfigPerfCounterEn = 1; + localparam CVA6ConfigDcacheType = WT; + endpackage diff --git a/core/include/cv32a6_imafc_sv32_config_pkg.sv b/core/include/cv32a6_imafc_sv32_config_pkg.sv index 835b77b022..f91eee66cc 100644 --- a/core/include/cv32a6_imafc_sv32_config_pkg.sv +++ b/core/include/cv32a6_imafc_sv32_config_pkg.sv @@ -10,6 +10,11 @@ package cva6_config_pkg; + typedef enum logic { + WB = 0, + WT = 1 + } cache_type_t ; + localparam CVA6ConfigXlen = 32; localparam CVA6ConfigFpuEn = 1; @@ -57,4 +62,6 @@ package cva6_config_pkg; localparam CVA6ConfigPerfCounterEn = 1; + localparam CVA6ConfigDcacheType = WB; + endpackage diff --git a/core/include/cv64a6_imafdc_sv39_config_pkg.sv b/core/include/cv64a6_imafdc_sv39_config_pkg.sv index 39295b05d8..33523adb54 100644 --- a/core/include/cv64a6_imafdc_sv39_config_pkg.sv +++ b/core/include/cv64a6_imafdc_sv39_config_pkg.sv @@ -10,6 +10,11 @@ package cva6_config_pkg; + typedef enum logic { + WB = 0, + WT = 1 + } cache_type_t ; + localparam CVA6ConfigXlen = 64; localparam CVA6ConfigFpuEn = 1; @@ -57,4 +62,6 @@ package cva6_config_pkg; localparam CVA6ConfigPerfCounterEn = 1; + localparam CVA6ConfigDcacheType = WT; + endpackage diff --git a/core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv b/core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv index 03f33b8d7c..783556b789 100644 --- a/core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv +++ b/core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv @@ -10,6 +10,11 @@ package cva6_config_pkg; + typedef enum logic { + WB = 0, + WT = 1 + } cache_type_t ; + localparam CVA6ConfigXlen = 64; localparam CVA6ConfigFpuEn = 1; @@ -57,4 +62,6 @@ package cva6_config_pkg; localparam CVA6ConfigPerfCounterEn = 1; + localparam cache_type_t CVA6ConfigDcacheType = WT; + endpackage diff --git a/corev_apu/fpga/src/genesysii.svh b/corev_apu/fpga/src/genesysii.svh index cd350a9355..0456b92ef0 100644 --- a/corev_apu/fpga/src/genesysii.svh +++ b/corev_apu/fpga/src/genesysii.svh @@ -19,9 +19,3 @@ // Instantiate protocl checker // `define PROTOCOL_CHECKER - -// write-back cache -// `define WB_DCACHE - -// write-through cache -`define WT_DCACHE diff --git a/corev_apu/fpga/src/kc705.svh b/corev_apu/fpga/src/kc705.svh index a66e76383d..bd17d0aebd 100644 --- a/corev_apu/fpga/src/kc705.svh +++ b/corev_apu/fpga/src/kc705.svh @@ -19,9 +19,3 @@ // Instantiate protocl checker // `define PROTOCOL_CHECKER - -// write-back cache -// `define WB_DCACHE - -// write-through cache -`define WT_DCACHE diff --git a/corev_apu/fpga/src/vc707.svh b/corev_apu/fpga/src/vc707.svh index 3886cae984..ac7b20a9d5 100644 --- a/corev_apu/fpga/src/vc707.svh +++ b/corev_apu/fpga/src/vc707.svh @@ -17,9 +17,3 @@ // Instantiate protocl checker // `define PROTOCOL_CHECKER - -// write-back cache -// `define WB_DCACHE - -// write-through cache -`define WT_DCACHE diff --git a/pd/synth/Makefile b/pd/synth/Makefile index 4ba812be35..45b4fb0f9f 100644 --- a/pd/synth/Makefile +++ b/pd/synth/Makefile @@ -30,7 +30,7 @@ endif pre_cva6_synth: grep "CVA6_REPO_DIR\}" ../../core/Flist.cva6|grep -v "instr_tracer"|grep -v "incdir" > Flist.cva6_synth - sed -i "s/^/analyze -f sverilog -define {WT_DCACHE,RVFI_TRACE,RVFI_MEM} -lib ariane_lib /" Flist.cva6_synth + sed -i "s/^/analyze -f sverilog -define {RVFI_TRACE,RVFI_MEM} -lib ariane_lib /" Flist.cva6_synth cva6_synth: pre_cva6_synth @echo $(PERIOD)