mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-19 11:54:46 -04:00
Implement dcache bypass mode [ci skip]
This commit is contained in:
parent
107cd30a9d
commit
10f47425fb
10 changed files with 484 additions and 211 deletions
|
@ -16,8 +16,17 @@ package nbdcache_pkg;
|
|||
|
||||
typedef struct packed {
|
||||
logic valid;
|
||||
miss_t type;
|
||||
miss_t req_type;
|
||||
logic [55:0] addr;
|
||||
} mshr_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic valid;
|
||||
logic bypass;
|
||||
logic [63:0] addr;
|
||||
logic [7:0] be;
|
||||
logic we;
|
||||
logic [63:0] wdata;
|
||||
} miss_req_t;
|
||||
|
||||
endpackage
|
||||
|
|
|
@ -55,6 +55,7 @@ module ariane
|
|||
input logic [63:0] instr_if_data_rdata_i,
|
||||
// Data memory interface
|
||||
AXI_BUS.Master data_if,
|
||||
AXI_BUS.Master bypass_if,
|
||||
// Interrupt inputs
|
||||
input logic irq_i, // level sensitive IR lines
|
||||
input logic [4:0] irq_id_i,
|
||||
|
|
|
@ -172,7 +172,7 @@ module axi_adapter #(
|
|||
axi.aw_valid = 1'b1;
|
||||
axi.aw_len = 8'b0;
|
||||
|
||||
if (axi.aw_read)
|
||||
if (axi.aw_ready)
|
||||
state_d = WAIT_B_VALID;
|
||||
|
||||
end
|
||||
|
|
|
@ -7,10 +7,171 @@
|
|||
*
|
||||
* Description: Cache controller
|
||||
*/
|
||||
module cache_ctrl (
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni // Asynchronous reset active low
|
||||
|
||||
import ariane_pkg::*;
|
||||
import nbdcache_pkg::*;
|
||||
|
||||
module cache_ctrl #(
|
||||
parameter int unsigned SET_ASSOCIATIVITY = 8,
|
||||
parameter int unsigned INDEX_WIDTH = 12,
|
||||
parameter int unsigned TAG_WIDTH = 44,
|
||||
parameter int unsigned CACHE_LINE_WIDTH = 100
|
||||
)(
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic bypass_i, // enable cache
|
||||
// Core request ports
|
||||
input logic [INDEX_WIDTH-1:0] address_index_i,
|
||||
input logic [TAG_WIDTH-1:0] address_tag_i,
|
||||
input logic [63:0] data_wdata_i,
|
||||
input logic data_req_i,
|
||||
input logic data_we_i,
|
||||
input logic [7:0] data_be_i,
|
||||
input logic kill_req_i,
|
||||
input logic tag_valid_i,
|
||||
output logic data_gnt_o,
|
||||
output logic data_rvalid_o,
|
||||
output logic [63:0] data_rdata_o,
|
||||
input amo_t amo_op_i,
|
||||
// SRAM interface, read only
|
||||
output logic [SET_ASSOCIATIVITY-1:0] req_o, // req is valid
|
||||
output logic [SET_ASSOCIATIVITY-1:0][INDEX_WIDTH-1:0] adrr_o, // address into cache array
|
||||
input logic [SET_ASSOCIATIVITY-1:0][CACHE_LINE_WIDTH-1:0] tag_i,
|
||||
input logic [SET_ASSOCIATIVITY-1:0][TAG_WIDTH-1:0] data_i,
|
||||
output logic [SET_ASSOCIATIVITY-1:0] we_o,
|
||||
// Miss handling
|
||||
output miss_req_t miss_req_o,
|
||||
// return
|
||||
input logic miss_gnt_i,
|
||||
input logic miss_valid_i,
|
||||
input logic [63:0] miss_data_i,
|
||||
// check MSHR for aliasing
|
||||
output logic [63:0] mshr_addr_o,
|
||||
input logic mashr_addr_matches_i
|
||||
);
|
||||
|
||||
enum logic [2:0] {
|
||||
IDLE, WAIT_TAG, WAIT_TAG_BYPASSED, WAIT_REFILL_VALID, WAIT_REFILL_GNT
|
||||
} state_d, state_q;
|
||||
|
||||
typedef struct packed {
|
||||
logic [INDEX_WIDTH-1:0] index;
|
||||
logic [TAG_WIDTH-1:0] tag;
|
||||
logic [7:0] be;
|
||||
logic we;
|
||||
logic bypass;
|
||||
} mem_req_t;
|
||||
|
||||
mem_req_t mem_req_d, mem_req_q;
|
||||
|
||||
// --------------
|
||||
// Cache FSM
|
||||
// --------------
|
||||
always_comb begin : cache_ctrl_fsm
|
||||
// default assignments
|
||||
state_d = state_q;
|
||||
mem_req_d = mem_req_q;
|
||||
// output assignments
|
||||
data_gnt_o = 1'b0;
|
||||
data_rvalid_o = 1'b0;
|
||||
data_rdata_o = '0;
|
||||
|
||||
miss_req_o = '0;
|
||||
|
||||
case (state_q)
|
||||
|
||||
IDLE: begin
|
||||
|
||||
// a new request arrived
|
||||
if (data_req_i) begin
|
||||
// Bypass mode, check for uncacheable address here as well
|
||||
if (bypass_i) begin
|
||||
state_d = WAIT_TAG_BYPASSED;
|
||||
// grant this access
|
||||
data_gnt_o = 1'b1;
|
||||
// save index, be and we
|
||||
mem_req_d = { address_index_i, mem_req_q.tag, data_be_i, data_we_i, data_wdata_i, 1'b1};
|
||||
// ------------------
|
||||
// Cache is enabled
|
||||
// ------------------
|
||||
end else begin
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// cache enabled and waiting for tag
|
||||
WAIT_TAG: begin
|
||||
|
||||
// HIT CASE
|
||||
|
||||
// MISS CASE
|
||||
|
||||
end
|
||||
|
||||
// its for sure a miss
|
||||
WAIT_TAG_BYPASSED: begin
|
||||
// the request was killed
|
||||
if (kill_req_i)
|
||||
state_d = IDLE;
|
||||
else begin
|
||||
// save tag
|
||||
mem_req_d.tag = address_tag_i;
|
||||
// make request to miss unit
|
||||
miss_req_o = { 1'b1, mem_req_d.bypass, address_tag_i, mem_req_q.index, mem_req_q.be, mem_req_q.we };
|
||||
// wait for the grant
|
||||
if (!miss_gnt_i)
|
||||
state_d = WAIT_REFILL_GNT;
|
||||
else
|
||||
state_d = WAIT_REFILL_VALID;
|
||||
end
|
||||
end
|
||||
|
||||
// ~> wait for grant from miss unit
|
||||
WAIT_REFILL_GNT: begin
|
||||
|
||||
miss_req_o = {1'b1, mem_req_q.bypass, mem_req_q.tag, mem_req_q.index, mem_req_q.be, mem_req_q.we };
|
||||
|
||||
// got a grant so go to valid
|
||||
if (miss_gnt_i)
|
||||
state_d = WAIT_REFILL_VALID;
|
||||
|
||||
end
|
||||
|
||||
WAIT_REFILL_VALID: begin
|
||||
// got a valid answer
|
||||
if (miss_valid_i) begin
|
||||
data_rdata_o = miss_data_i;
|
||||
data_rvalid_o = 1'b1;
|
||||
state_d = IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
// --------------
|
||||
// Registers
|
||||
// --------------
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if(~rst_ni) begin
|
||||
state_q <= IDLE;
|
||||
mem_req_q <= '0;
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
mem_req_q <= mem_req_d;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
module AMO_alu (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
// AMO interface
|
||||
input logic amo_commit_i, // commit atomic memory operation
|
||||
output logic amo_valid_o, // we have a valid AMO result
|
||||
output logic [63:0] amo_result_o, // result of atomic memory operation
|
||||
input logic amo_flush_i // forget about AMO
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -1,193 +0,0 @@
|
|||
// Author: Florian Zaruba, ETH Zurich
|
||||
// Date: 24.4.2017
|
||||
// Description: Arbitrates the dcache ports
|
||||
//
|
||||
//
|
||||
// Copyright (C) 2017 ETH Zurich, University of Bologna
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code is under development and not yet released to the public.
|
||||
// Until it is released, the code is under the copyright of ETH Zurich and
|
||||
// the University of Bologna, and may contain confidential and/or unpublished
|
||||
// work. Any reuse/redistribution is strictly forbidden without written
|
||||
// permission from ETH Zurich.
|
||||
//
|
||||
// Bug fixes and contributions will eventually be released under the
|
||||
// SolderPad open hardware license in the context of the PULP platform
|
||||
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
|
||||
// University of Bologna.
|
||||
//
|
||||
import ariane_pkg::*;
|
||||
|
||||
module dcache_arbiter #(
|
||||
parameter int NR_PORTS = 3
|
||||
)
|
||||
(
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
// slave port
|
||||
output logic [11:0] address_index_o,
|
||||
output logic [43:0] address_tag_o,
|
||||
output logic [63:0] data_wdata_o,
|
||||
output logic data_req_o,
|
||||
output logic data_we_o,
|
||||
output logic [7:0] data_be_o,
|
||||
output logic kill_req_o,
|
||||
output logic tag_valid_o,
|
||||
input logic data_gnt_i,
|
||||
input logic data_rvalid_i,
|
||||
input logic [63:0] data_rdata_i,
|
||||
// master ports
|
||||
input logic [NR_PORTS-1:0][11:0] address_index_i,
|
||||
input logic [NR_PORTS-1:0][43:0] address_tag_i,
|
||||
input logic [NR_PORTS-1:0][63:0] data_wdata_i,
|
||||
input logic [NR_PORTS-1:0] data_req_i,
|
||||
input logic [NR_PORTS-1:0] data_we_i,
|
||||
input logic [NR_PORTS-1:0][7:0] data_be_i,
|
||||
input logic [NR_PORTS-1:0] kill_req_i,
|
||||
input logic [NR_PORTS-1:0] tag_valid_i,
|
||||
output logic [NR_PORTS-1:0] data_gnt_o,
|
||||
output logic [NR_PORTS-1:0] data_rvalid_o,
|
||||
output logic [NR_PORTS-1:0][63:0] data_rdata_o
|
||||
);
|
||||
// one-hot encoded
|
||||
localparam DATA_WIDTH = NR_PORTS;
|
||||
// remember the request port in case of a multi-cycle transaction
|
||||
logic [DATA_WIDTH-1:0] request_port_n, request_port_q;
|
||||
// local ports
|
||||
// FIFO control ports
|
||||
logic full;
|
||||
logic empty;
|
||||
logic single_element;
|
||||
// FIFO input port
|
||||
logic [DATA_WIDTH-1:0] in_data;
|
||||
logic push;
|
||||
// FIFO output port
|
||||
logic [DATA_WIDTH-1:0] out_data;
|
||||
logic pop;
|
||||
|
||||
// FIFO to keep track of the responses
|
||||
fifo #(
|
||||
.dtype ( logic [DATA_WIDTH-1:0] ),
|
||||
.DEPTH ( 4 )
|
||||
) fifo_i (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.single_element_o ( single_element ),
|
||||
// the flush is accomplished implicitly by waiting for the queue to be drained before accepting any new request
|
||||
// it is the responsibility of the attached units to make sure it handles any outstanding responses
|
||||
.flush_i ( 1'b0 ),
|
||||
.full_o ( full ),
|
||||
.empty_o ( empty ),
|
||||
.data_i ( in_data ),
|
||||
.push_i ( push ),
|
||||
.data_o ( out_data ),
|
||||
.pop_i ( pop )
|
||||
);
|
||||
|
||||
// addressing read and full write
|
||||
always_comb begin : read_req_write
|
||||
automatic logic [DATA_WIDTH-1:0] request_index = request_port_q;
|
||||
data_req_o = 1'b0;
|
||||
in_data = '{default: 0};
|
||||
push = 1'b0;
|
||||
request_port_n = request_port_q;
|
||||
|
||||
for (int i = 0; i < NR_PORTS; i++)
|
||||
data_gnt_o[i] = 1'b0;
|
||||
|
||||
// ----------------------------
|
||||
// Single-cycle memory requests
|
||||
// ----------------------------
|
||||
// only go for a new request if we can wait for the valid e.g.: we have enough space in the buffer
|
||||
if (~full) begin
|
||||
for (int unsigned i = 0; i < NR_PORTS; i++) begin
|
||||
if (data_req_i[i] == 1'b1) begin
|
||||
data_req_o = data_req_i[i];
|
||||
// save the request port for future states
|
||||
request_port_n = i;
|
||||
request_index = i;
|
||||
// wait for the grant
|
||||
// set the slave on which we are waiting
|
||||
in_data = 1'b1 << i[DATA_WIDTH-1:0];
|
||||
break; // break here as this is a priority select
|
||||
end
|
||||
end
|
||||
// only if we got a grant save it to the queue
|
||||
if (data_gnt_i) begin
|
||||
push = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// pass through all signals from the correct slave port
|
||||
address_index_o = address_index_i[request_index];
|
||||
data_wdata_o = data_wdata_i[request_index];
|
||||
data_be_o = data_be_i[request_index];
|
||||
data_we_o = data_we_i[request_index];
|
||||
data_gnt_o[request_index] = data_gnt_i;
|
||||
// the following signals are to be passed through one-cycle later
|
||||
address_tag_o = address_tag_i[request_port_q];
|
||||
kill_req_o = kill_req_i[request_port_q];
|
||||
tag_valid_o = tag_valid_i[request_port_q];
|
||||
end
|
||||
|
||||
// ------------
|
||||
// Read port
|
||||
// ------------
|
||||
// results, listening on the input signals of the slave port
|
||||
genvar i;
|
||||
// this is very timing sensitive since we can give a new request if we got an rvalid
|
||||
// hence this combines the to most critical paths (from and to memory)
|
||||
generate
|
||||
// default assignment & one hot decoder
|
||||
for (i = 0; i < NR_PORTS; i++) begin
|
||||
assign data_rvalid_o[i] = out_data[i] & data_rvalid_i;
|
||||
assign data_rdata_o[i] = data_rdata_i;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
always_comb begin : slave_read_port
|
||||
pop = 1'b0;
|
||||
// if there is a valid signal the FIFO should not be empty anyway
|
||||
if (data_rvalid_i) begin
|
||||
pop = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// sequential process
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
request_port_q <= 'b0;
|
||||
end else begin
|
||||
request_port_q <= request_port_n;
|
||||
end
|
||||
end
|
||||
|
||||
// ------------
|
||||
// Assertions
|
||||
// ------------
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
`ifndef VERILATOR
|
||||
// make sure that we eventually get an rvalid after we received a grant
|
||||
assert property (@(posedge clk_i) data_gnt_i |-> ##[1:$] data_rvalid_i )
|
||||
else begin $error("There was a grant without a rvalid"); $stop(); end
|
||||
// assert that there is no grant without a request
|
||||
assert property (@(negedge clk_i) data_gnt_i |-> data_req_o)
|
||||
else begin $error("There was a grant without a request."); $stop(); end
|
||||
// assert that the address does not contain X when request is sent
|
||||
assert property ( @(posedge clk_i) (data_req_o) |-> (!$isunknown(address_index_o)) )
|
||||
else begin $error("address contains X when request is set"); $stop(); end
|
||||
|
||||
// there should be no rvalid when we are in IDLE
|
||||
// assert property (
|
||||
// @(posedge clk) (CS == IDLE) |-> (data_rvalid_i == 1'b0) )
|
||||
// else begin $error("Received rvalid while in IDLE state"); $stop(); end
|
||||
|
||||
// assert that errors are only sent at the same time as grant or rvalid
|
||||
// assert property ( @(posedge clk) (data_err_i) |-> (data_gnt_i || data_rvalid_i) )
|
||||
// else begin $error("Error without data grant or rvalid"); $stop(); end
|
||||
|
||||
`endif
|
||||
`endif
|
||||
endmodule
|
|
@ -102,7 +102,8 @@ module ex_stage #(
|
|||
input logic instr_if_data_rvalid_i,
|
||||
input logic [63:0] instr_if_data_rdata_i,
|
||||
|
||||
AXI_BUS.Master data_if
|
||||
AXI_BUS.Master data_if,
|
||||
AXI_BUS.Master bypass_if
|
||||
);
|
||||
|
||||
// -----
|
||||
|
|
11
src/lsu.sv
11
src/lsu.sv
|
@ -65,6 +65,7 @@ module lsu #(
|
|||
input logic [63:0] instr_if_data_rdata_i,
|
||||
// Data cache refill port
|
||||
AXI_BUS.Master data_if,
|
||||
AXI_BUS.Master bypass_if,
|
||||
|
||||
output exception_t lsu_exception_o // to WB, signal exception status LD/ST exception
|
||||
|
||||
|
@ -143,6 +144,7 @@ module lsu #(
|
|||
nbdcache i_nbdcache (
|
||||
// to D$
|
||||
.data_if ( data_if ),
|
||||
.bypass_if ( bypass_if ),
|
||||
// from PTW, Load Unit and Store Unit
|
||||
.address_index_i ( address_index_i ),
|
||||
.address_tag_i ( address_tag_i ),
|
||||
|
@ -156,9 +158,12 @@ module lsu #(
|
|||
.data_rvalid_o ( data_rvalid_o ),
|
||||
.data_rdata_o ( data_rdata_o ),
|
||||
.amo_op_i ( amo_op_i ),
|
||||
.amo_commit_i (),
|
||||
.amo_valid_o (),
|
||||
.amo_result_o (),
|
||||
.amo_commit_i ( ),
|
||||
.amo_valid_o ( ),
|
||||
.amo_result_o ( ),
|
||||
.amo_flush_i ( 1'b0 ),
|
||||
.enable_i ( 1'b0 ),
|
||||
|
||||
.*
|
||||
);
|
||||
|
||||
|
|
115
src/miss_arbiter.sv
Normal file
115
src/miss_arbiter.sv
Normal file
|
@ -0,0 +1,115 @@
|
|||
// Author: Florian Zaruba, ETH Zurich
|
||||
// Date: 24.4.2017
|
||||
// Description: Arbitrates the dcache ports
|
||||
//
|
||||
//
|
||||
// Copyright (C) 2017 ETH Zurich, University of Bologna
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code is under development and not yet released to the public.
|
||||
// Until it is released, the code is under the copyright of ETH Zurich and
|
||||
// the University of Bologna, and may contain confidential and/or unpublished
|
||||
// work. Any reuse/redistribution is strictly forbidden without written
|
||||
// permission from ETH Zurich.
|
||||
//
|
||||
// Bug fixes and contributions will eventually be released under the
|
||||
// SolderPad open hardware license in the context of the PULP platform
|
||||
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
|
||||
// University of Bologna.
|
||||
//
|
||||
import ariane_pkg::*;
|
||||
|
||||
module miss_arbiter #(
|
||||
parameter int unsigned NR_PORTS = 3
|
||||
)(
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
// master ports
|
||||
input logic [NR_PORTS-1:0] data_req_i,
|
||||
input logic [NR_PORTS-1:0][63:0] address_i,
|
||||
input logic [NR_PORTS-1:0][63:0] data_wdata_i,
|
||||
input logic [NR_PORTS-1:0] data_we_i,
|
||||
input logic [NR_PORTS-1:0][7:0] data_be_i,
|
||||
output logic [NR_PORTS-1:0] data_gnt_o,
|
||||
output logic [NR_PORTS-1:0] data_rvalid_o,
|
||||
output logic [NR_PORTS-1:0][63:0] data_rdata_o,
|
||||
// slave port
|
||||
input logic [$clog2(NR_PORTS)-1:0] id_i,
|
||||
output logic [$clog2(NR_PORTS)-1:0] id_o,
|
||||
output logic data_req_o,
|
||||
output logic [63:0] address_o,
|
||||
output logic [63:0] data_wdata_o,
|
||||
output logic data_we_o,
|
||||
output logic [7:0] data_be_o,
|
||||
input logic data_gnt_i,
|
||||
input logic data_rvalid_i,
|
||||
input logic [63:0] data_rdata_i
|
||||
);
|
||||
|
||||
|
||||
// addressing read and full write
|
||||
always_comb begin : read_req_write
|
||||
automatic logic [$clog2(NR_PORTS)-1:0] request_index = 0;
|
||||
|
||||
data_req_o = 1'b0;
|
||||
data_gnt_o = '0;
|
||||
|
||||
for (int unsigned i = 0; i < NR_PORTS; i++) begin
|
||||
if (data_req_i[i] == 1'b1) begin
|
||||
data_req_o = data_req_i[i];
|
||||
request_index = i;
|
||||
break; // break here as this is a priority select
|
||||
end
|
||||
end
|
||||
|
||||
// pass through all signals from the correct slave port
|
||||
address_o = address_i[request_index];
|
||||
data_wdata_o = data_wdata_i[request_index];
|
||||
data_be_o = data_be_i[request_index];
|
||||
data_we_o = data_we_i[request_index];
|
||||
data_gnt_o[request_index] = data_gnt_i;
|
||||
id_o = request_index;
|
||||
end
|
||||
|
||||
// ------------
|
||||
// Read port
|
||||
// ------------
|
||||
|
||||
always_comb begin : slave_read_port
|
||||
data_rvalid_o = '0;
|
||||
data_rdata_o = '0;
|
||||
// if there is a valid signal the FIFO should not be empty anyway
|
||||
if (data_rvalid_i) begin
|
||||
data_rvalid_o[id_i] = data_rvalid_i;
|
||||
data_rdata_o [id_i] = data_rdata_i;
|
||||
end
|
||||
end
|
||||
|
||||
// ------------
|
||||
// Assertions
|
||||
// ------------
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
`ifndef VERILATOR
|
||||
// make sure that we eventually get an rvalid after we received a grant
|
||||
assert property (@(posedge clk_i) data_gnt_i |-> ##[1:$] data_rvalid_i )
|
||||
else begin $error("There was a grant without a rvalid"); $stop(); end
|
||||
// assert that there is no grant without a request
|
||||
assert property (@(negedge clk_i) data_gnt_i |-> data_req_o)
|
||||
else begin $error("There was a grant without a request."); $stop(); end
|
||||
// assert that the address does not contain X when request is sent
|
||||
assert property ( @(posedge clk_i) (data_req_o) |-> (!$isunknown(address_o)) )
|
||||
else begin $error("address contains X when request is set"); $stop(); end
|
||||
|
||||
// there should be no rvalid when we are in IDLE
|
||||
// assert property (
|
||||
// @(posedge clk) (CS == IDLE) |-> (data_rvalid_i == 1'b0) )
|
||||
// else begin $error("Received rvalid while in IDLE state"); $stop(); end
|
||||
|
||||
// assert that errors are only sent at the same time as grant or rvalid
|
||||
// assert property ( @(posedge clk) (data_err_i) |-> (data_gnt_i || data_rvalid_i) )
|
||||
// else begin $error("Error without data grant or rvalid"); $stop(); end
|
||||
|
||||
`endif
|
||||
`endif
|
||||
endmodule
|
84
src/miss_handler.sv
Executable file
84
src/miss_handler.sv
Executable file
|
@ -0,0 +1,84 @@
|
|||
// --------------
|
||||
// MISS Handler
|
||||
// --------------
|
||||
//
|
||||
// Description: Handles cache misses.
|
||||
//
|
||||
import nbdcache_pkg::*;
|
||||
|
||||
module miss_handler #(
|
||||
parameter int unsigned NR_PORTS = 3
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic [NR_PORTS-1:0][$bits(miss_req_t)-1:0] miss_req_i,
|
||||
output logic [NR_PORTS-1:0] miss_gnt_o,
|
||||
output logic [NR_PORTS-1:0] miss_valid_o,
|
||||
output logic [NR_PORTS-1:0][63:0] miss_data_o,
|
||||
AXI_BUS.Master bypass_if
|
||||
// update cache
|
||||
);
|
||||
|
||||
// ------------------
|
||||
// Cacheline Refills
|
||||
// ------------------
|
||||
|
||||
// ------------------
|
||||
// Bypass
|
||||
// ------------------
|
||||
// AXI Adapter
|
||||
// request from FSM
|
||||
|
||||
// Hack as system verilog support in modelsim seems to be buggy here
|
||||
miss_req_t miss_req;
|
||||
assign miss_req = miss_req_t'(miss_req_i);
|
||||
|
||||
miss_req_t req_fsm_bypass;
|
||||
logic gnt_bypass_fsm;
|
||||
logic valid_bypass_fsm;
|
||||
logic [63:0] data_bypass_fsm;
|
||||
logic [$clog2(NR_PORTS)-1:0] id_bypass_fsm, id_fsm_bypass;
|
||||
|
||||
miss_arbiter i_bypass_arbiter (
|
||||
// Master Side
|
||||
.data_req_i ( miss_req.valid & miss_req.bypass ),
|
||||
.address_i ( miss_req.addr ),
|
||||
.data_wdata_i ( miss_req.wdata ),
|
||||
.data_we_i ( miss_req.we ),
|
||||
.data_be_i ( miss_req.be ),
|
||||
.data_gnt_o ( miss_gnt_o ),
|
||||
.data_rvalid_o ( miss_valid_o ),
|
||||
.data_rdata_o ( miss_data_o ),
|
||||
// Slave Side
|
||||
.id_i ( id_bypass_fsm ),
|
||||
.id_o ( id_fsm_bypass ),
|
||||
.address_o ( req_fsm_bypass.addr ),
|
||||
.data_wdata_o ( req_fsm_bypass.wdata ),
|
||||
.data_req_o ( req_fsm_bypass.valid ),
|
||||
.data_we_o ( req_fsm_bypass.we ),
|
||||
.data_be_o ( req_fsm_bypass.be ),
|
||||
.data_gnt_i ( gnt_bypass_fsm ),
|
||||
.data_rvalid_i ( valid_bypass_fsm ),
|
||||
.data_rdata_i ( data_bypass_fsm ),
|
||||
.*
|
||||
);
|
||||
|
||||
axi_adapter i_bypass_axi_adapter (
|
||||
.req_i ( miss_req.valid ),
|
||||
.type_i ( SINGLE_REQ ),
|
||||
.gnt_o ( gnt_bypass_fsm ),
|
||||
.addr_i ( req_fsm_bypass.addr ),
|
||||
.we_i ( req_fsm_bypass.we ),
|
||||
.wdata_i ( req_fsm_bypass.wdata ),
|
||||
.be_i ( req_fsm_bypass.be ),
|
||||
.id_i ( id_fsm_bypass ),
|
||||
.valid_o ( miss_valid_o ),
|
||||
.rdata_o ( miss_data_o ),
|
||||
.id_o ( id_bypass_fsm ),
|
||||
.critical_word_o ( ), // not used for single requests
|
||||
.critical_word_valid ( ), // not used for single requests
|
||||
.axi ( bypass_if ),
|
||||
.*
|
||||
);
|
||||
|
||||
endmodule
|
108
src/nbdcache.sv
108
src/nbdcache.sv
|
@ -19,7 +19,7 @@
|
|||
import ariane_pkg::*;
|
||||
import nbdcache_pkg::*;
|
||||
|
||||
module nb_dcache #(
|
||||
module nbdcache #(
|
||||
parameter int unsigned INDEX_WIDTH = 12,
|
||||
parameter int unsigned TAG_WIDTH = 44,
|
||||
parameter int unsigned CACHE_LINE_WIDTH = 256,
|
||||
|
@ -27,10 +27,13 @@ module nb_dcache #(
|
|||
parameter int unsigned AXI_ID_WIDTH = 10,
|
||||
parameter int unsigned AXI_USER_WIDTH = 10
|
||||
)(
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
// AXI refill port
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
// Cache control
|
||||
input logic enable_i, // from CSR
|
||||
// Cache AXI refill port
|
||||
AXI_BUS.Master data_if,
|
||||
AXI_BUS.Master bypass_if,
|
||||
// AMO interface
|
||||
input logic amo_commit_i, // commit atomic memory operation
|
||||
output logic amo_valid_o, // we have a valid AMO result
|
||||
|
@ -54,14 +57,72 @@ module nb_dcache #(
|
|||
localparam NUM_WORDS = 2**INDEX_WIDTH;
|
||||
localparam DIRTY_WIDTH = (CACHE_LINE_WIDTH/64)*SET_ASSOCIATIVITY;
|
||||
|
||||
// AMO ALU
|
||||
logic [2:0][$bits(miss_req_t)-1:0] miss_req;
|
||||
logic [2:0] miss_gnt;
|
||||
logic [2:0] miss_valid;
|
||||
logic [2:0][63:0] miss_data;
|
||||
|
||||
logic [SET_ASSOCIATIVITY-1:0] req;
|
||||
logic [SET_ASSOCIATIVITY-1:0][INDEX_WIDTH-1:0] adrr;
|
||||
logic [SET_ASSOCIATIVITY-1:0][CACHE_LINE_WIDTH-1:0] tag;
|
||||
logic [SET_ASSOCIATIVITY-1:0][TAG_WIDTH-1:0] data;
|
||||
logic [SET_ASSOCIATIVITY-1:0] we;
|
||||
|
||||
// Cache FSM
|
||||
// ------------------
|
||||
// Cache Controller
|
||||
// ------------------
|
||||
generate
|
||||
for (genvar i = 0; i < 3; i++) begin : master_ports
|
||||
cache_ctrl #(
|
||||
.SET_ASSOCIATIVITY ( SET_ASSOCIATIVITY ),
|
||||
.INDEX_WIDTH ( INDEX_WIDTH ),
|
||||
.TAG_WIDTH ( TAG_WIDTH ),
|
||||
.CACHE_LINE_WIDTH ( CACHE_LINE_WIDTH )
|
||||
) i_cache_ctrl (
|
||||
.bypass_i ( ~enable_i ),
|
||||
.address_index_i ( address_index_i [i] ),
|
||||
.address_tag_i ( address_tag_i [i] ),
|
||||
.data_wdata_i ( data_wdata_i [i] ),
|
||||
.data_req_i ( data_req_i [i] ),
|
||||
.data_we_i ( data_we_i [i] ),
|
||||
.data_be_i ( data_be_i [i] ),
|
||||
.kill_req_i ( kill_req_i [i] ),
|
||||
.tag_valid_i ( tag_valid_i [i] ),
|
||||
.data_gnt_o ( data_gnt_o [i] ),
|
||||
.data_rvalid_o ( data_rvalid_o [i] ),
|
||||
.data_rdata_o ( data_rdata_o [i] ),
|
||||
.amo_op_i ( amo_op_i [i] ),
|
||||
|
||||
.req_o ( req ),
|
||||
.adrr_o ( adrr ),
|
||||
.tag_i ( tag ),
|
||||
.data_i ( data ),
|
||||
.we_o ( we ),
|
||||
|
||||
.miss_req_o ( miss_req [i] ),
|
||||
.miss_gnt_i ( miss_gnt [i] ),
|
||||
.miss_valid_i ( miss_valid [i] ),
|
||||
.miss_data_i ( miss_data [i] ),
|
||||
.mshr_addr_o ( ), // TODO
|
||||
.mashr_addr_matches_i ( ), // TODO
|
||||
.*
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// ------------------
|
||||
// Miss Handling Unit
|
||||
// ------------------
|
||||
miss_handler i_miss_handler (
|
||||
.miss_req_i ( miss_req ),
|
||||
.miss_gnt_o ( miss_gnt ),
|
||||
.miss_valid_o ( miss_valid ),
|
||||
.miss_data_o ( miss_data ),
|
||||
.*
|
||||
);
|
||||
|
||||
// --------------
|
||||
// Memories
|
||||
// Memory Arrays
|
||||
// --------------
|
||||
// TODO: Re-work
|
||||
generate
|
||||
|
@ -108,8 +169,6 @@ module nb_dcache #(
|
|||
.rdata_o ( )
|
||||
);
|
||||
|
||||
// AXI Module
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
initial begin
|
||||
assert ($bits(data_if.aw_addr) == 64) else $fatal(1, "Ariane needs a 64-bit bus");
|
||||
|
@ -117,3 +176,34 @@ module nb_dcache #(
|
|||
end
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
// --------------
|
||||
// Memory Arbiter
|
||||
// --------------
|
||||
//
|
||||
// Description: Arbitrates access to cache memories
|
||||
//
|
||||
module sram_arbiter #(
|
||||
parameter int unsigned NR_PORTS = 3
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic [NR_PORTS-1:0] req_i,
|
||||
output logic [NR_PORTS-1:0] gnt_o
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
|
||||
gnt_o = '0;
|
||||
|
||||
// priority select
|
||||
for (int i = 0; i < NR_PORTS; i++) begin
|
||||
if (req_i[i]) begin
|
||||
gnt_o[i] = 1'b1;
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue