Implement dcache bypass mode [ci skip]

This commit is contained in:
Florian Zaruba 2017-10-17 20:00:33 +02:00
parent 107cd30a9d
commit 10f47425fb
No known key found for this signature in database
GPG key ID: E742FFE8EC38A792
10 changed files with 484 additions and 211 deletions

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
);
// -----

View file

@ -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
View 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
View 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

View file

@ -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