+ Microarchitecture optimizations + 64-bit support + Xilinx FPGA support + LLVM-16 support + Refactoring and quality control fixes
550 lines
21 KiB
Systemverilog
550 lines
21 KiB
Systemverilog
// Copyright © 2019-2023
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// 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.
|
|
|
|
`include "VX_cache_define.vh"
|
|
|
|
module VX_cache_bank #(
|
|
parameter `STRING INSTANCE_ID= "",
|
|
parameter BANK_ID = 0,
|
|
|
|
// Number of Word requests per cycle
|
|
parameter NUM_REQS = 1,
|
|
|
|
// Size of cache in bytes
|
|
parameter CACHE_SIZE = 1024,
|
|
// Size of line inside a bank in bytes
|
|
parameter LINE_SIZE = 16,
|
|
// Number of banks
|
|
parameter NUM_BANKS = 1,
|
|
// Number of associative ways
|
|
parameter NUM_WAYS = 1,
|
|
// Size of a word in bytes
|
|
parameter WORD_SIZE = 4,
|
|
|
|
// Core Response Queue Size
|
|
parameter CRSQ_SIZE = 1,
|
|
// Miss Reserv Queue Knob
|
|
parameter MSHR_SIZE = 1,
|
|
// Memory Request Queue Size
|
|
parameter MREQ_SIZE = 1,
|
|
|
|
// Enable cache writeable
|
|
parameter WRITE_ENABLE = 1,
|
|
|
|
// Request debug identifier
|
|
parameter UUID_WIDTH = 0,
|
|
|
|
// core request tag size
|
|
parameter TAG_WIDTH = UUID_WIDTH + 1,
|
|
|
|
// Core response output register
|
|
parameter CORE_OUT_REG = 0,
|
|
|
|
// Memory request output register
|
|
parameter MEM_OUT_REG = 0,
|
|
|
|
parameter MSHR_ADDR_WIDTH = `LOG2UP(MSHR_SIZE),
|
|
parameter REQ_SEL_WIDTH = `UP(`CS_REQ_SEL_BITS),
|
|
parameter WORD_SEL_WIDTH = `UP(`CS_WORD_SEL_BITS)
|
|
) (
|
|
input wire clk,
|
|
input wire reset,
|
|
|
|
`ifdef PERF_ENABLE
|
|
output wire perf_read_misses,
|
|
output wire perf_write_misses,
|
|
output wire perf_mshr_stalls,
|
|
`endif
|
|
|
|
// Core Request
|
|
input wire core_req_valid,
|
|
input wire [`CS_LINE_ADDR_WIDTH-1:0] core_req_addr,
|
|
input wire core_req_rw,
|
|
input wire [WORD_SEL_WIDTH-1:0] core_req_wsel,
|
|
input wire [WORD_SIZE-1:0] core_req_byteen,
|
|
input wire [`CS_WORD_WIDTH-1:0] core_req_data,
|
|
input wire [TAG_WIDTH-1:0] core_req_tag,
|
|
input wire [REQ_SEL_WIDTH-1:0] core_req_idx,
|
|
output wire core_req_ready,
|
|
|
|
// Core Response
|
|
output wire core_rsp_valid,
|
|
output wire [`CS_WORD_WIDTH-1:0] core_rsp_data,
|
|
output wire [TAG_WIDTH-1:0] core_rsp_tag,
|
|
output wire [REQ_SEL_WIDTH-1:0] core_rsp_idx,
|
|
input wire core_rsp_ready,
|
|
|
|
// Memory request
|
|
output wire mem_req_valid,
|
|
output wire [`CS_LINE_ADDR_WIDTH-1:0] mem_req_addr,
|
|
output wire mem_req_rw,
|
|
output wire [WORD_SEL_WIDTH-1:0] mem_req_wsel,
|
|
output wire [WORD_SIZE-1:0] mem_req_byteen,
|
|
output wire [`CS_WORD_WIDTH-1:0] mem_req_data,
|
|
output wire [MSHR_ADDR_WIDTH-1:0] mem_req_id,
|
|
input wire mem_req_ready,
|
|
|
|
// Memory response
|
|
input wire mem_rsp_valid,
|
|
input wire [`CS_LINE_WIDTH-1:0] mem_rsp_data,
|
|
input wire [MSHR_ADDR_WIDTH-1:0] mem_rsp_id,
|
|
output wire mem_rsp_ready,
|
|
|
|
// initialization
|
|
input wire init_enable,
|
|
input wire [`CS_LINE_SEL_BITS-1:0] init_line_sel
|
|
);
|
|
|
|
`IGNORE_UNUSED_BEGIN
|
|
wire [`UP(UUID_WIDTH)-1:0] req_uuid_sel, req_uuid_st0, req_uuid_st1;
|
|
`IGNORE_UNUSED_END
|
|
|
|
wire crsq_stall;
|
|
wire mshr_alm_full;
|
|
wire mreq_alm_full;
|
|
|
|
wire [`CS_LINE_ADDR_WIDTH-1:0] mem_rsp_addr;
|
|
|
|
wire replay_valid;
|
|
wire [`CS_LINE_ADDR_WIDTH-1:0] replay_addr;
|
|
wire replay_rw;
|
|
wire [WORD_SEL_WIDTH-1:0] replay_wsel;
|
|
wire [WORD_SIZE-1:0] replay_byteen;
|
|
wire [`CS_WORD_WIDTH-1:0] replay_data;
|
|
wire [TAG_WIDTH-1:0] replay_tag;
|
|
wire [REQ_SEL_WIDTH-1:0] replay_idx;
|
|
wire [MSHR_ADDR_WIDTH-1:0] replay_id;
|
|
wire replay_ready;
|
|
|
|
wire [`CS_LINE_ADDR_WIDTH-1:0] addr_sel, addr_st0, addr_st1;
|
|
wire rw_st0, rw_st1;
|
|
wire [WORD_SEL_WIDTH-1:0] wsel_st0, wsel_st1;
|
|
wire [WORD_SIZE-1:0] byteen_st0, byteen_st1;
|
|
wire [REQ_SEL_WIDTH-1:0] req_idx_st0, req_idx_st1;
|
|
wire [TAG_WIDTH-1:0] tag_st0, tag_st1;
|
|
wire [`CS_WORD_WIDTH-1:0] read_data_st1;
|
|
wire [`CS_LINE_WIDTH-1:0] data_sel, data_st0, data_st1;
|
|
wire [MSHR_ADDR_WIDTH-1:0] replay_id_st0, mshr_id_st0, mshr_id_st1;
|
|
wire valid_sel, valid_st0, valid_st1;
|
|
wire is_init_st0;
|
|
wire is_creq_st0, is_creq_st1;
|
|
wire is_fill_st0, is_fill_st1;
|
|
wire is_replay_st0, is_replay_st1;
|
|
wire [MSHR_ADDR_WIDTH-1:0] mshr_alloc_id_st0;
|
|
wire [MSHR_ADDR_WIDTH-1:0] mshr_tail_st0, mshr_tail_st1;
|
|
wire mshr_pending_st0, mshr_pending_st1;
|
|
|
|
wire rdw_hazard_st0;
|
|
reg rdw_hazard_st1;
|
|
|
|
wire pipe_stall = crsq_stall || rdw_hazard_st1;
|
|
|
|
// inputs arbitration:
|
|
// mshr replay has highest priority to maximize utilization since there is no miss.
|
|
// handle memory responses next to prevent deadlock with potential memory request from a miss.
|
|
wire replay_grant = ~init_enable;
|
|
wire replay_enable = replay_grant && replay_valid;
|
|
|
|
wire fill_grant = ~init_enable && ~replay_enable;
|
|
wire fill_enable = fill_grant && mem_rsp_valid;
|
|
|
|
wire creq_grant = ~init_enable && ~replay_enable && ~fill_enable;
|
|
wire creq_enable = creq_grant && core_req_valid;
|
|
|
|
assign replay_ready = replay_grant
|
|
&& ~rdw_hazard_st0
|
|
&& ~pipe_stall;
|
|
|
|
assign mem_rsp_ready = fill_grant
|
|
&& ~pipe_stall;
|
|
|
|
assign core_req_ready = creq_grant
|
|
&& ~mreq_alm_full
|
|
&& ~mshr_alm_full
|
|
&& ~pipe_stall;
|
|
|
|
wire init_fire = init_enable;
|
|
wire replay_fire = replay_valid && replay_ready;
|
|
wire mem_rsp_fire = mem_rsp_valid && mem_rsp_ready;
|
|
wire core_req_fire = core_req_valid && core_req_ready;
|
|
|
|
wire [TAG_WIDTH-1:0] mshr_creq_tag = replay_enable ? replay_tag : core_req_tag;
|
|
|
|
if (UUID_WIDTH != 0) begin
|
|
assign req_uuid_sel = mshr_creq_tag[TAG_WIDTH-1 -: UUID_WIDTH];
|
|
end else begin
|
|
assign req_uuid_sel = 0;
|
|
end
|
|
|
|
`UNUSED_VAR (mshr_creq_tag)
|
|
|
|
assign valid_sel = init_fire || replay_fire || mem_rsp_fire || core_req_fire;
|
|
|
|
assign addr_sel = init_enable ? `CS_LINE_ADDR_WIDTH'(init_line_sel) :
|
|
(replay_valid ? replay_addr :
|
|
(mem_rsp_valid ? mem_rsp_addr : core_req_addr));
|
|
|
|
assign data_sel[`CS_WORD_WIDTH-1:0] = (mem_rsp_valid || !WRITE_ENABLE) ? mem_rsp_data[`CS_WORD_WIDTH-1:0] : (replay_valid ? replay_data : core_req_data);
|
|
for (genvar i = `CS_WORD_WIDTH; i < `CS_LINE_WIDTH; ++i) begin
|
|
assign data_sel[i] = mem_rsp_data[i];
|
|
end
|
|
|
|
VX_pipe_register #(
|
|
.DATAW (1 + 1 + 1 + 1 + 1 + `CS_LINE_ADDR_WIDTH + `CS_LINE_WIDTH + 1 + WORD_SIZE + WORD_SEL_WIDTH + REQ_SEL_WIDTH + TAG_WIDTH + MSHR_ADDR_WIDTH),
|
|
.RESETW (1)
|
|
) pipe_reg0 (
|
|
.clk (clk),
|
|
.reset (reset),
|
|
.enable (~pipe_stall),
|
|
.data_in ({
|
|
valid_sel,
|
|
init_enable,
|
|
replay_enable,
|
|
fill_enable,
|
|
creq_enable,
|
|
addr_sel,
|
|
data_sel,
|
|
replay_valid ? replay_rw : core_req_rw,
|
|
replay_valid ? replay_byteen : core_req_byteen,
|
|
replay_valid ? replay_wsel : core_req_wsel,
|
|
replay_valid ? replay_idx : core_req_idx,
|
|
replay_valid ? replay_tag : core_req_tag,
|
|
replay_id
|
|
}),
|
|
.data_out ({valid_st0, is_init_st0, is_replay_st0, is_fill_st0, is_creq_st0, addr_st0, data_st0, rw_st0, byteen_st0, wsel_st0, req_idx_st0, tag_st0, replay_id_st0})
|
|
);
|
|
|
|
if (UUID_WIDTH != 0) begin
|
|
assign req_uuid_st0 = tag_st0[TAG_WIDTH-1 -: UUID_WIDTH];
|
|
end else begin
|
|
assign req_uuid_st0 = 0;
|
|
end
|
|
|
|
wire do_creq_rd_st0 = valid_st0 && is_creq_st0 && ~rw_st0;
|
|
wire do_fill_st0 = valid_st0 && is_fill_st0;
|
|
wire do_init_st0 = valid_st0 && is_init_st0;
|
|
wire do_lookup_st0 = valid_st0 && ~(is_fill_st0 || is_init_st0);
|
|
|
|
wire [`CS_WORD_WIDTH-1:0] write_data_st0 = data_st0[`CS_WORD_WIDTH-1:0];
|
|
|
|
wire [NUM_WAYS-1:0] tag_matches_st0, tag_matches_st1;
|
|
wire [NUM_WAYS-1:0] way_sel_st0, way_sel_st1;
|
|
|
|
`RESET_RELAY (tag_reset, reset);
|
|
|
|
VX_cache_tags #(
|
|
.INSTANCE_ID(INSTANCE_ID),
|
|
.BANK_ID (BANK_ID),
|
|
.CACHE_SIZE (CACHE_SIZE),
|
|
.LINE_SIZE (LINE_SIZE),
|
|
.NUM_BANKS (NUM_BANKS),
|
|
.NUM_WAYS (NUM_WAYS),
|
|
.WORD_SIZE (WORD_SIZE),
|
|
.UUID_WIDTH (UUID_WIDTH)
|
|
) cache_tags (
|
|
.clk (clk),
|
|
.reset (tag_reset),
|
|
|
|
.req_uuid (req_uuid_st0),
|
|
|
|
.stall (pipe_stall),
|
|
|
|
// read/Fill
|
|
.lookup (do_lookup_st0),
|
|
.line_addr (addr_st0),
|
|
.fill (do_fill_st0),
|
|
.init (do_init_st0),
|
|
.way_sel (way_sel_st0),
|
|
.tag_matches(tag_matches_st0)
|
|
);
|
|
|
|
assign mshr_id_st0 = is_creq_st0 ? mshr_alloc_id_st0 : replay_id_st0;
|
|
|
|
VX_pipe_register #(
|
|
.DATAW (1 + 1 + 1 + 1 + 1 + `CS_LINE_ADDR_WIDTH + `CS_LINE_WIDTH + WORD_SIZE + WORD_SEL_WIDTH + REQ_SEL_WIDTH + TAG_WIDTH + MSHR_ADDR_WIDTH + MSHR_ADDR_WIDTH + NUM_WAYS + NUM_WAYS + 1),
|
|
.RESETW (1)
|
|
) pipe_reg1 (
|
|
.clk (clk),
|
|
.reset (reset),
|
|
.enable (~pipe_stall),
|
|
.data_in ({valid_st0, is_replay_st0, is_fill_st0, is_creq_st0, rw_st0, addr_st0, data_st0, byteen_st0, wsel_st0, req_idx_st0, tag_st0, mshr_id_st0, mshr_tail_st0, tag_matches_st0, way_sel_st0, mshr_pending_st0}),
|
|
.data_out ({valid_st1, is_replay_st1, is_fill_st1, is_creq_st1, rw_st1, addr_st1, data_st1, byteen_st1, wsel_st1, req_idx_st1, tag_st1, mshr_id_st1, mshr_tail_st1, tag_matches_st1, way_sel_st1, mshr_pending_st1})
|
|
);
|
|
|
|
// we have a tag hit
|
|
wire is_hit_st1 = (| tag_matches_st1);
|
|
|
|
if (UUID_WIDTH != 0) begin
|
|
assign req_uuid_st1 = tag_st1[TAG_WIDTH-1 -: UUID_WIDTH];
|
|
end else begin
|
|
assign req_uuid_st1 = 0;
|
|
end
|
|
|
|
wire do_creq_rd_st1 = valid_st1 && is_creq_st1 && ~rw_st1;
|
|
wire do_creq_wr_st1 = valid_st1 && is_creq_st1 && rw_st1;
|
|
wire do_fill_st1 = valid_st1 && is_fill_st1;
|
|
wire do_replay_rd_st1 = valid_st1 && is_replay_st1 && ~rw_st1;
|
|
wire do_replay_wr_st1 = valid_st1 && is_replay_st1 && rw_st1;
|
|
|
|
wire do_read_hit_st1 = do_creq_rd_st1 && is_hit_st1;
|
|
wire do_read_miss_st1 = do_creq_rd_st1 && ~is_hit_st1;
|
|
|
|
wire do_write_hit_st1 = do_creq_wr_st1 && is_hit_st1;
|
|
wire do_write_miss_st1= do_creq_wr_st1 && ~is_hit_st1;
|
|
|
|
`UNUSED_VAR (do_write_miss_st1)
|
|
|
|
// ensure mshr replay always get a hit
|
|
`RUNTIME_ASSERT (~(valid_st1 && is_replay_st1) || is_hit_st1, ("runtime error: invalid mshr replay"));
|
|
|
|
// detect BRAM's read-during-write hazard
|
|
assign rdw_hazard_st0 = do_fill_st0; // after a fill
|
|
always @(posedge clk) begin
|
|
rdw_hazard_st1 <= (do_creq_rd_st0 && do_write_hit_st1 && (addr_st0 == addr_st1))
|
|
&& ~rdw_hazard_st1; // after a write to same address
|
|
end
|
|
|
|
wire [`CS_WORD_WIDTH-1:0] write_data_st1 = data_st1[`CS_WORD_WIDTH-1:0];
|
|
wire [`CS_LINE_WIDTH-1:0] fill_data_st1 = data_st1;
|
|
|
|
`RESET_RELAY (data_reset, reset);
|
|
|
|
VX_cache_data #(
|
|
.INSTANCE_ID (INSTANCE_ID),
|
|
.BANK_ID (BANK_ID),
|
|
.CACHE_SIZE (CACHE_SIZE),
|
|
.LINE_SIZE (LINE_SIZE),
|
|
.NUM_BANKS (NUM_BANKS),
|
|
.NUM_WAYS (NUM_WAYS),
|
|
.WORD_SIZE (WORD_SIZE),
|
|
.WRITE_ENABLE (WRITE_ENABLE),
|
|
.UUID_WIDTH (UUID_WIDTH)
|
|
) cache_data (
|
|
.clk (clk),
|
|
.reset (data_reset),
|
|
|
|
.req_uuid (req_uuid_st1),
|
|
|
|
.stall (pipe_stall),
|
|
|
|
.read (do_read_hit_st1 || do_replay_rd_st1),
|
|
.fill (do_fill_st1),
|
|
.write (do_write_hit_st1 || do_replay_wr_st1),
|
|
.way_sel (way_sel_st1 | tag_matches_st1),
|
|
.line_addr (addr_st1),
|
|
.wsel (wsel_st1),
|
|
.byteen (byteen_st1),
|
|
.fill_data (fill_data_st1),
|
|
.write_data (write_data_st1),
|
|
.read_data (read_data_st1)
|
|
);
|
|
|
|
wire [MSHR_SIZE-1:0] mshr_matches_st0;
|
|
wire mshr_allocate_st0 = valid_st0 && is_creq_st0 && ~pipe_stall;
|
|
wire mshr_lookup_st0 = mshr_allocate_st0;
|
|
wire mshr_finalize_st1 = valid_st1 && is_creq_st1 && ~pipe_stall;
|
|
wire mshr_release_st1 = is_hit_st1 || (rw_st1 && ~mshr_pending_st1);
|
|
|
|
VX_pending_size #(
|
|
.SIZE (MSHR_SIZE)
|
|
) mshr_pending_size (
|
|
.clk (clk),
|
|
.reset (reset),
|
|
.incr (core_req_fire),
|
|
.decr (replay_fire || (mshr_finalize_st1 && mshr_release_st1)),
|
|
.full (mshr_alm_full),
|
|
`UNUSED_PIN (size),
|
|
`UNUSED_PIN (empty)
|
|
);
|
|
|
|
`RESET_RELAY (mshr_reset, reset);
|
|
|
|
VX_cache_mshr #(
|
|
.INSTANCE_ID (INSTANCE_ID),
|
|
.BANK_ID (BANK_ID),
|
|
.LINE_SIZE (LINE_SIZE),
|
|
.NUM_BANKS (NUM_BANKS),
|
|
.MSHR_SIZE (MSHR_SIZE),
|
|
.UUID_WIDTH (UUID_WIDTH),
|
|
.DATA_WIDTH (WORD_SEL_WIDTH + WORD_SIZE + `CS_WORD_WIDTH + TAG_WIDTH + REQ_SEL_WIDTH)
|
|
) cache_mshr (
|
|
.clk (clk),
|
|
.reset (mshr_reset),
|
|
|
|
.deq_req_uuid (req_uuid_sel),
|
|
.lkp_req_uuid (req_uuid_st0),
|
|
.fin_req_uuid (req_uuid_st1),
|
|
|
|
// memory fill
|
|
.fill_valid (mem_rsp_fire),
|
|
.fill_id (mem_rsp_id),
|
|
.fill_addr (mem_rsp_addr),
|
|
|
|
// dequeue
|
|
.dequeue_valid (replay_valid),
|
|
.dequeue_addr (replay_addr),
|
|
.dequeue_rw (replay_rw),
|
|
.dequeue_data ({replay_wsel, replay_byteen, replay_data, replay_tag, replay_idx}),
|
|
.dequeue_id (replay_id),
|
|
.dequeue_ready (replay_ready),
|
|
|
|
// allocate
|
|
.allocate_valid (mshr_allocate_st0),
|
|
.allocate_addr (addr_st0),
|
|
.allocate_rw (rw_st0),
|
|
.allocate_data ({wsel_st0, byteen_st0, write_data_st0, tag_st0, req_idx_st0}),
|
|
.allocate_id (mshr_alloc_id_st0),
|
|
.allocate_tail (mshr_tail_st0),
|
|
`UNUSED_PIN (allocate_ready),
|
|
|
|
// lookup
|
|
.lookup_valid (mshr_lookup_st0),
|
|
.lookup_addr (addr_st0),
|
|
.lookup_matches (mshr_matches_st0),
|
|
|
|
// finalize
|
|
.finalize_valid (mshr_finalize_st1),
|
|
.finalize_release(mshr_release_st1),
|
|
.finalize_pending(mshr_pending_st1),
|
|
.finalize_id (mshr_id_st1),
|
|
.finalize_tail (mshr_tail_st1)
|
|
);
|
|
|
|
// ignore allocated id from mshr matches
|
|
wire [MSHR_SIZE-1:0] lookup_matches;
|
|
for (genvar i = 0; i < MSHR_SIZE; ++i) begin
|
|
assign lookup_matches[i] = (i != mshr_alloc_id_st0) && mshr_matches_st0[i];
|
|
end
|
|
assign mshr_pending_st0 = (| lookup_matches);
|
|
|
|
// schedule core response
|
|
|
|
wire crsq_valid, crsq_ready;
|
|
wire [`CS_WORD_WIDTH-1:0] crsq_data;
|
|
wire [REQ_SEL_WIDTH-1:0] crsq_idx;
|
|
wire [TAG_WIDTH-1:0] crsq_tag;
|
|
|
|
assign crsq_valid = do_read_hit_st1 || do_replay_rd_st1;
|
|
assign crsq_idx = req_idx_st1;
|
|
assign crsq_data = read_data_st1;
|
|
assign crsq_tag = tag_st1;
|
|
|
|
`RESET_RELAY (crsp_reset, reset);
|
|
|
|
VX_elastic_buffer #(
|
|
.DATAW (TAG_WIDTH + `CS_WORD_WIDTH + REQ_SEL_WIDTH),
|
|
.SIZE (CRSQ_SIZE),
|
|
.OUT_REG (CORE_OUT_REG)
|
|
) core_rsp_queue (
|
|
.clk (clk),
|
|
.reset (crsp_reset),
|
|
.valid_in (crsq_valid && ~rdw_hazard_st1),
|
|
.ready_in (crsq_ready),
|
|
.data_in ({crsq_tag, crsq_data, crsq_idx}),
|
|
.data_out ({core_rsp_tag, core_rsp_data, core_rsp_idx}),
|
|
.valid_out (core_rsp_valid),
|
|
.ready_out (core_rsp_ready)
|
|
);
|
|
|
|
assign crsq_stall = crsq_valid && ~crsq_ready;
|
|
|
|
// schedule memory request
|
|
|
|
wire mreq_push, mreq_pop, mreq_empty;
|
|
wire [`CS_WORD_WIDTH-1:0] mreq_data;
|
|
wire [WORD_SIZE-1:0] mreq_byteen;
|
|
wire [WORD_SEL_WIDTH-1:0] mreq_wsel;
|
|
wire [`CS_LINE_ADDR_WIDTH-1:0] mreq_addr;
|
|
wire [MSHR_ADDR_WIDTH-1:0] mreq_id;
|
|
wire mreq_rw;
|
|
|
|
assign mreq_push = (do_read_miss_st1 && ~mshr_pending_st1)
|
|
|| do_creq_wr_st1;
|
|
|
|
assign mreq_pop = mem_req_valid && mem_req_ready;
|
|
|
|
assign mreq_rw = WRITE_ENABLE && rw_st1;
|
|
assign mreq_addr = addr_st1;
|
|
assign mreq_id = mshr_id_st1;
|
|
assign mreq_wsel = wsel_st1;
|
|
assign mreq_byteen = byteen_st1;
|
|
assign mreq_data = write_data_st1;
|
|
|
|
`RESET_RELAY (mreq_reset, reset);
|
|
|
|
VX_fifo_queue #(
|
|
.DATAW (1 + `CS_LINE_ADDR_WIDTH + MSHR_ADDR_WIDTH + WORD_SIZE + WORD_SEL_WIDTH + `CS_WORD_WIDTH),
|
|
.DEPTH (MREQ_SIZE),
|
|
.ALM_FULL (MREQ_SIZE-2),
|
|
.OUT_REG (MEM_OUT_REG)
|
|
) mem_req_queue (
|
|
.clk (clk),
|
|
.reset (mreq_reset),
|
|
.push (mreq_push),
|
|
.pop (mreq_pop),
|
|
.data_in ({mreq_rw, mreq_addr, mreq_id, mreq_byteen, mreq_wsel, mreq_data}),
|
|
.data_out ({mem_req_rw, mem_req_addr, mem_req_id, mem_req_byteen, mem_req_wsel, mem_req_data}),
|
|
.empty (mreq_empty),
|
|
.alm_full (mreq_alm_full),
|
|
`UNUSED_PIN (full),
|
|
`UNUSED_PIN (alm_empty),
|
|
`UNUSED_PIN (size)
|
|
);
|
|
|
|
assign mem_req_valid = ~mreq_empty;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
`ifdef PERF_ENABLE
|
|
assign perf_read_misses = do_read_miss_st1;
|
|
assign perf_write_misses = do_write_miss_st1;
|
|
assign perf_mshr_stalls = mshr_alm_full;
|
|
`endif
|
|
|
|
`ifdef DBG_TRACE_CACHE_BANK
|
|
wire crsq_fire = crsq_valid && crsq_ready;
|
|
wire pipeline_stall = (replay_valid || mem_rsp_valid || core_req_valid)
|
|
&& ~(replay_fire || mem_rsp_fire || core_req_fire);
|
|
always @(posedge clk) begin
|
|
if (pipeline_stall) begin
|
|
`TRACE(3, ("%d: *** %s-bank%0d stall: crsq=%b, mreq=%b, mshr=%b\n", $time, INSTANCE_ID, BANK_ID, crsq_stall, mreq_alm_full, mshr_alm_full));
|
|
end
|
|
if (init_enable) begin
|
|
`TRACE(2, ("%d: %s-bank%0d init: addr=0x%0h\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(init_line_sel, BANK_ID)));
|
|
end
|
|
if (mem_rsp_fire) begin
|
|
`TRACE(2, ("%d: %s-bank%0d fill-rsp: addr=0x%0h, mshr_id=%0d, data=0x%0h\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(mem_rsp_addr, BANK_ID), mem_rsp_id, mem_rsp_data));
|
|
end
|
|
if (replay_fire) begin
|
|
`TRACE(2, ("%d: %s-bank%0d mshr-pop: addr=0x%0h, tag=0x%0h, req_idx=%0d (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(replay_addr, BANK_ID), replay_tag, replay_idx, req_uuid_sel));
|
|
end
|
|
if (core_req_fire) begin
|
|
if (core_req_rw)
|
|
`TRACE(2, ("%d: %s-bank%0d core-wr-req: addr=0x%0h, tag=0x%0h, req_idx=%0d, byteen=%b, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(core_req_addr, BANK_ID), core_req_tag, core_req_idx, core_req_byteen, core_req_data, req_uuid_sel));
|
|
else
|
|
`TRACE(2, ("%d: %s-bank%0d core-rd-req: addr=0x%0h, tag=0x%0h, req_idx=%0d (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(core_req_addr, BANK_ID), core_req_tag, core_req_idx, req_uuid_sel));
|
|
end
|
|
if (crsq_fire) begin
|
|
`TRACE(2, ("%d: %s-bank%0d core-rd-rsp: addr=0x%0h, tag=0x%0h, req_idx=%0d, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(addr_st1, BANK_ID), crsq_tag, crsq_idx, crsq_data, req_uuid_st1));
|
|
end
|
|
if (mreq_push) begin
|
|
if (do_creq_wr_st1)
|
|
`TRACE(2, ("%d: %s-bank%0d writethrough: addr=0x%0h, byteen=%b, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(mreq_addr, BANK_ID), mreq_byteen, mreq_data, req_uuid_st1));
|
|
else
|
|
`TRACE(2, ("%d: %s-bank%0d fill-req: addr=0x%0h, mshr_id=%0d (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(mreq_addr, BANK_ID), mreq_id, req_uuid_st1));
|
|
end
|
|
end
|
|
`endif
|
|
|
|
endmodule
|