cva6/core/cache_subsystem/wt_dcache.sv
André Sintzoff 7cd183b710
verible-verilog-format: apply it on core directory (#1540)
using verible-v0.0-3422-g520ca4b9/bin/verible-verilog-format
with default configuration

Note: two files are not correctly handled by verible
- core/include/std_cache_pkg.sv
- core/cache_subsystem/cva6_hpdcache_if_adapter.sv
2023-10-18 16:36:00 +02:00

341 lines
13 KiB
Systemverilog

// 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.
//
// Author: Michael Schaffner <schaffner@iis.ee.ethz.ch>, ETH Zurich
// Date: 13.09.2018
// Description: Write-Through Data cache that is compatible with openpiton.
module wt_dcache
import ariane_pkg::*;
import wt_cache_pkg::*;
#(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
parameter int unsigned NumPorts = 4, // number of miss ports
// ID to be used for read and AMO transactions.
// note that the write buffer uses all IDs up to DCACHE_MAX_TX-1 for write transactions
parameter logic [CACHE_ID_WIDTH-1:0] RdAmoTxId = 1
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
// Cache management
input logic enable_i, // from CSR
input logic flush_i, // high until acknowledged
output logic flush_ack_o, // send a single cycle acknowledge signal when the cache is flushed
output logic miss_o, // we missed on a ld/st
output logic wbuffer_empty_o,
output logic wbuffer_not_ni_o,
// AMO interface
input amo_req_t amo_req_i,
output amo_resp_t amo_resp_o,
// Request ports
input dcache_req_i_t [NumPorts-1:0] req_ports_i,
output dcache_req_o_t [NumPorts-1:0] req_ports_o,
output logic [NumPorts-1:0][DCACHE_SET_ASSOC-1:0] miss_vld_bits_o,
input logic mem_rtrn_vld_i,
input dcache_rtrn_t mem_rtrn_i,
output logic mem_data_req_o,
input logic mem_data_ack_i,
output dcache_req_t mem_data_o
);
// miss unit <-> read controllers
logic cache_en;
// miss unit <-> memory
logic wr_cl_vld;
logic wr_cl_nc;
logic [ DCACHE_SET_ASSOC-1:0] wr_cl_we;
logic [ DCACHE_TAG_WIDTH-1:0] wr_cl_tag;
logic [ DCACHE_CL_IDX_WIDTH-1:0] wr_cl_idx;
logic [ DCACHE_OFFSET_WIDTH-1:0] wr_cl_off;
logic [ DCACHE_LINE_WIDTH-1:0] wr_cl_data;
logic [DCACHE_USER_LINE_WIDTH-1:0] wr_cl_user;
logic [ DCACHE_LINE_WIDTH/8-1:0] wr_cl_data_be;
logic [ DCACHE_SET_ASSOC-1:0] wr_vld_bits;
logic [ DCACHE_SET_ASSOC-1:0] wr_req;
logic wr_ack;
logic [ DCACHE_CL_IDX_WIDTH-1:0] wr_idx;
logic [ DCACHE_OFFSET_WIDTH-1:0] wr_off;
riscv::xlen_t wr_data;
logic [ (riscv::XLEN/8)-1:0] wr_data_be;
logic [ DCACHE_USER_WIDTH-1:0] wr_user;
// miss unit <-> controllers/wbuffer
logic [ NumPorts-1:0] miss_req;
logic [ NumPorts-1:0] miss_ack;
logic [ NumPorts-1:0] miss_nc;
logic [ NumPorts-1:0] miss_we;
logic [ NumPorts-1:0][ riscv::XLEN-1:0] miss_wdata;
logic [ NumPorts-1:0][ DCACHE_USER_WIDTH-1:0] miss_wuser;
logic [ NumPorts-1:0][ riscv::PLEN-1:0] miss_paddr;
logic [ NumPorts-1:0][ 2:0] miss_size;
logic [ NumPorts-1:0][ CACHE_ID_WIDTH-1:0] miss_id;
logic [ NumPorts-1:0] miss_replay;
logic [ NumPorts-1:0] miss_rtrn_vld;
logic [ CACHE_ID_WIDTH-1:0] miss_rtrn_id;
// memory <-> read controllers/miss unit
logic [ NumPorts-1:0] rd_prio;
logic [ NumPorts-1:0] rd_tag_only;
logic [ NumPorts-1:0] rd_req;
logic [ NumPorts-1:0] rd_ack;
logic [ NumPorts-1:0][ DCACHE_TAG_WIDTH-1:0] rd_tag;
logic [ NumPorts-1:0][DCACHE_CL_IDX_WIDTH-1:0] rd_idx;
logic [ NumPorts-1:0][DCACHE_OFFSET_WIDTH-1:0] rd_off;
riscv::xlen_t rd_data;
logic [ DCACHE_USER_WIDTH-1:0] rd_user;
logic [ DCACHE_SET_ASSOC-1:0] rd_vld_bits;
logic [ DCACHE_SET_ASSOC-1:0] rd_hit_oh;
// miss unit <-> wbuffer
logic [ DCACHE_MAX_TX-1:0][ riscv::PLEN-1:0] tx_paddr;
logic [ DCACHE_MAX_TX-1:0] tx_vld;
// wbuffer <-> memory
wbuffer_t [ DCACHE_WBUF_DEPTH-1:0] wbuffer_data;
///////////////////////////////////////////////////////
// miss handling unit
///////////////////////////////////////////////////////
wt_dcache_missunit #(
.CVA6Cfg (CVA6Cfg),
.AmoTxId (RdAmoTxId),
.NumPorts(NumPorts)
) i_wt_dcache_missunit (
.clk_i (clk_i),
.rst_ni (rst_ni),
.enable_i (enable_i),
.flush_i (flush_i),
.flush_ack_o (flush_ack_o),
.miss_o (miss_o),
.wbuffer_empty_i(wbuffer_empty_o),
.cache_en_o (cache_en),
// amo interface
.amo_req_i (amo_req_i),
.amo_resp_o (amo_resp_o),
// miss handling interface
.miss_req_i (miss_req),
.miss_ack_o (miss_ack),
.miss_nc_i (miss_nc),
.miss_we_i (miss_we),
.miss_wdata_i (miss_wdata),
.miss_wuser_i (miss_wuser),
.miss_paddr_i (miss_paddr),
.miss_vld_bits_i(miss_vld_bits_o),
.miss_size_i (miss_size),
.miss_id_i (miss_id),
.miss_replay_o (miss_replay),
.miss_rtrn_vld_o(miss_rtrn_vld),
.miss_rtrn_id_o (miss_rtrn_id),
// from writebuffer
.tx_paddr_i (tx_paddr),
.tx_vld_i (tx_vld),
// cache memory interface
.wr_cl_vld_o (wr_cl_vld),
.wr_cl_nc_o (wr_cl_nc),
.wr_cl_we_o (wr_cl_we),
.wr_cl_tag_o (wr_cl_tag),
.wr_cl_idx_o (wr_cl_idx),
.wr_cl_off_o (wr_cl_off),
.wr_cl_data_o (wr_cl_data),
.wr_cl_user_o (wr_cl_user),
.wr_cl_data_be_o(wr_cl_data_be),
.wr_vld_bits_o (wr_vld_bits),
// memory interface
.mem_rtrn_vld_i (mem_rtrn_vld_i),
.mem_rtrn_i (mem_rtrn_i),
.mem_data_req_o (mem_data_req_o),
.mem_data_ack_i (mem_data_ack_i),
.mem_data_o (mem_data_o)
);
///////////////////////////////////////////////////////
// read controllers (LD unit and PTW/MMU)
///////////////////////////////////////////////////////
// note: last read port is used by the write buffer
for (genvar k = 0; k < NumPorts - 1; k++) begin : gen_rd_ports
// set these to high prio ports
assign rd_prio[k] = 1'b1;
wt_dcache_ctrl #(
.CVA6Cfg(CVA6Cfg),
.RdTxId (RdAmoTxId)
) i_wt_dcache_ctrl (
.clk_i (clk_i),
.rst_ni (rst_ni),
.cache_en_i (cache_en),
// reqs from core
.req_port_i (req_ports_i[k]),
.req_port_o (req_ports_o[k]),
// miss interface
.miss_req_o (miss_req[k]),
.miss_ack_i (miss_ack[k]),
.miss_we_o (miss_we[k]),
.miss_wdata_o (miss_wdata[k]),
.miss_wuser_o (miss_wuser[k]),
.miss_vld_bits_o(miss_vld_bits_o[k]),
.miss_paddr_o (miss_paddr[k]),
.miss_nc_o (miss_nc[k]),
.miss_size_o (miss_size[k]),
.miss_id_o (miss_id[k]),
.miss_replay_i (miss_replay[k]),
.miss_rtrn_vld_i(miss_rtrn_vld[k]),
// used to detect readout mux collisions
.wr_cl_vld_i (wr_cl_vld),
// cache mem interface
.rd_tag_o (rd_tag[k]),
.rd_idx_o (rd_idx[k]),
.rd_off_o (rd_off[k]),
.rd_req_o (rd_req[k]),
.rd_tag_only_o (rd_tag_only[k]),
.rd_ack_i (rd_ack[k]),
.rd_data_i (rd_data),
.rd_user_i (rd_user),
.rd_vld_bits_i (rd_vld_bits),
.rd_hit_oh_i (rd_hit_oh)
);
end
///////////////////////////////////////////////////////
// store unit controller
///////////////////////////////////////////////////////
// set read port to low priority
assign rd_prio[NumPorts-1] = 1'b0;
wt_dcache_wbuffer #(
.CVA6Cfg(CVA6Cfg)
) i_wt_dcache_wbuffer (
.clk_i (clk_i),
.rst_ni (rst_ni),
.empty_o (wbuffer_empty_o),
.not_ni_o (wbuffer_not_ni_o),
// TODO: fix this
.cache_en_i (cache_en),
// .cache_en_i ( '0 ),
// request ports from core (store unit)
.req_port_i (req_ports_i[NumPorts-1]),
.req_port_o (req_ports_o[NumPorts-1]),
// miss unit interface
.miss_req_o (miss_req[NumPorts-1]),
.miss_ack_i (miss_ack[NumPorts-1]),
.miss_we_o (miss_we[NumPorts-1]),
.miss_wdata_o (miss_wdata[NumPorts-1]),
.miss_wuser_o (miss_wuser[NumPorts-1]),
.miss_vld_bits_o(miss_vld_bits_o[NumPorts-1]),
.miss_paddr_o (miss_paddr[NumPorts-1]),
.miss_nc_o (miss_nc[NumPorts-1]),
.miss_size_o (miss_size[NumPorts-1]),
.miss_id_o (miss_id[NumPorts-1]),
.miss_rtrn_vld_i(miss_rtrn_vld[NumPorts-1]),
.miss_rtrn_id_i (miss_rtrn_id),
// cache read interface
.rd_tag_o (rd_tag[NumPorts-1]),
.rd_idx_o (rd_idx[NumPorts-1]),
.rd_off_o (rd_off[NumPorts-1]),
.rd_req_o (rd_req[NumPorts-1]),
.rd_tag_only_o (rd_tag_only[NumPorts-1]),
.rd_ack_i (rd_ack[NumPorts-1]),
.rd_data_i (rd_data),
.rd_vld_bits_i (rd_vld_bits),
.rd_hit_oh_i (rd_hit_oh),
// incoming invalidations/cache refills
.wr_cl_vld_i (wr_cl_vld),
.wr_cl_idx_i (wr_cl_idx),
// single word write interface
.wr_req_o (wr_req),
.wr_ack_i (wr_ack),
.wr_idx_o (wr_idx),
.wr_off_o (wr_off),
.wr_data_o (wr_data),
.wr_user_o (wr_user),
.wr_data_be_o (wr_data_be),
// write buffer forwarding
.wbuffer_data_o (wbuffer_data),
.tx_paddr_o (tx_paddr),
.tx_vld_o (tx_vld)
);
///////////////////////////////////////////////////////
// memory arrays, arbitration and tag comparison
///////////////////////////////////////////////////////
wt_dcache_mem #(
.CVA6Cfg (CVA6Cfg),
.NumPorts(NumPorts)
) i_wt_dcache_mem (
.clk_i (clk_i),
.rst_ni (rst_ni),
// read ports
.rd_prio_i (rd_prio),
.rd_tag_i (rd_tag),
.rd_idx_i (rd_idx),
.rd_off_i (rd_off),
.rd_req_i (rd_req),
.rd_tag_only_i (rd_tag_only),
.rd_ack_o (rd_ack),
.rd_vld_bits_o (rd_vld_bits),
.rd_hit_oh_o (rd_hit_oh),
.rd_data_o (rd_data),
.rd_user_o (rd_user),
// cacheline write port
.wr_cl_vld_i (wr_cl_vld),
.wr_cl_nc_i (wr_cl_nc),
.wr_cl_we_i (wr_cl_we),
.wr_cl_tag_i (wr_cl_tag),
.wr_cl_idx_i (wr_cl_idx),
.wr_cl_off_i (wr_cl_off),
.wr_cl_data_i (wr_cl_data),
.wr_cl_user_i (wr_cl_user),
.wr_cl_data_be_i(wr_cl_data_be),
.wr_vld_bits_i (wr_vld_bits),
// single word write port
.wr_req_i (wr_req),
.wr_ack_o (wr_ack),
.wr_idx_i (wr_idx),
.wr_off_i (wr_off),
.wr_data_i (wr_data),
.wr_user_i (wr_user),
.wr_data_be_i (wr_data_be),
// write buffer forwarding
.wbuffer_data_i (wbuffer_data)
);
///////////////////////////////////////////////////////
// assertions
///////////////////////////////////////////////////////
// check for concurrency issues
//pragma translate_off
`ifndef VERILATOR
flush :
assert property (
@(posedge clk_i) disable iff (!rst_ni) flush_i |-> flush_ack_o |-> wbuffer_empty_o)
else $fatal(1, "[l1 dcache] flushed cache implies flushed wbuffer");
initial begin
// assert wrong parameterizations
assert (DCACHE_INDEX_WIDTH <= 12)
else $fatal(1, "[l1 dcache] cache index width can be maximum 12bit since VM uses 4kB pages");
end
`endif
//pragma translate_on
endmodule // wt_dcache