mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-20 04:07:36 -04:00
* Switch to AXI structs
* Fix problems with ID width mismatches
* 📝 Update CHANGELOG
This commit is contained in:
parent
8468544156
commit
25a0470df6
18 changed files with 654 additions and 284 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -22,4 +22,4 @@ build/
|
|||
*.vcd
|
||||
*.log
|
||||
*.out
|
||||
work-ver/*
|
||||
work-*/*
|
||||
|
|
|
@ -11,10 +11,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
- Commit log feature
|
||||
- Support for A-Extension
|
||||
- Preliminary FP support
|
||||
- Provisioned `aw_top` signal for close to memory atomics
|
||||
|
||||
### Changed
|
||||
|
||||
- core_id / cluster_id inputs have been merged to hard_id input
|
||||
- Three AXI ports have been merged into one
|
||||
|
||||
### 3.0.0
|
||||
|
||||
|
|
5
Makefile
5
Makefile
|
@ -35,6 +35,7 @@ ariane_pkg := include/riscv_pkg.sv \
|
|||
include/std_cache_pkg.sv \
|
||||
src/axi/src/axi_pkg.sv \
|
||||
include/axi_intf.sv \
|
||||
include/ariane_axi_pkg.sv \
|
||||
src/fpu/src/pkg/fpnew_pkg.vhd \
|
||||
src/fpu/src/pkg/fpnew_fmts_pkg.vhd \
|
||||
src/fpu/src/pkg/fpnew_comps_pkg.vhd \
|
||||
|
@ -75,6 +76,9 @@ src := $(filter-out src/ariane_regfile.sv, $(wildcard src/*.sv)) \
|
|||
src/common_cells/src/deprecated/pulp_sync.sv \
|
||||
src/common_cells/src/deprecated/find_first_one.sv \
|
||||
src/common_cells/src/rstgen_bypass.sv \
|
||||
src/common_cells/src/stream_mux.sv \
|
||||
src/common_cells/src/stream_demux.sv \
|
||||
src/util/axi_connect.sv \
|
||||
src/axi/src/axi_cut.sv \
|
||||
src/axi/src/axi_join.sv \
|
||||
src/fpga-support/rtl/SyncSpRamBeNx64.sv \
|
||||
|
@ -82,6 +86,7 @@ src := $(filter-out src/ariane_regfile.sv, $(wildcard src/*.sv)) \
|
|||
src/common_cells/src/cdc_2phase.sv \
|
||||
src/common_cells/src/spill_register.sv \
|
||||
src/common_cells/src/sync_wedge.sv \
|
||||
src/common_cells/src/fifo_v3.sv \
|
||||
src/common_cells/src/fifo_v2.sv \
|
||||
src/common_cells/src/fifo_v1.sv \
|
||||
src/common_cells/src/lzc.sv \
|
||||
|
|
103
include/ariane_axi_pkg.sv
Normal file
103
include/ariane_axi_pkg.sv
Normal file
|
@ -0,0 +1,103 @@
|
|||
/* 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: ariane_axi_pkg.sv
|
||||
* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
|
||||
* Date: 17.8.2018
|
||||
*
|
||||
* Description: Contains Ariane's AXI ports, does not contain user ports
|
||||
*/
|
||||
|
||||
package ariane_axi;
|
||||
// 4 is recommended by AXI standard, so lets stick to it, do not change
|
||||
localparam IdWidth = 4;
|
||||
localparam UserWidth = 1;
|
||||
localparam AddrWidth = 64;
|
||||
localparam DataWidth = 64;
|
||||
localparam StrbWidth = DataWidth / 8;
|
||||
|
||||
typedef logic [IdWidth-1:0] id_t;
|
||||
typedef logic [AddrWidth-1:0] addr_t;
|
||||
typedef logic [DataWidth-1:0] data_t;
|
||||
typedef logic [StrbWidth-1:0] strb_t;
|
||||
typedef logic [UserWidth-1:0] user_t;
|
||||
|
||||
// AW Channel
|
||||
typedef struct packed {
|
||||
id_t id;
|
||||
addr_t addr;
|
||||
axi_pkg::len_t len;
|
||||
axi_pkg::size_t size;
|
||||
axi_pkg::burst_t burst;
|
||||
logic lock;
|
||||
axi_pkg::cache_t cache;
|
||||
axi_pkg::prot_t prot;
|
||||
axi_pkg::qos_t qos;
|
||||
axi_pkg::region_t region;
|
||||
axi_pkg::atop_t atop;
|
||||
} aw_chan_t;
|
||||
|
||||
// W Channel
|
||||
typedef struct packed {
|
||||
data_t data;
|
||||
strb_t strb;
|
||||
logic last;
|
||||
} w_chan_t;
|
||||
|
||||
// B Channel
|
||||
typedef struct packed {
|
||||
id_t id;
|
||||
axi_pkg::resp_t resp;
|
||||
} b_chan_t;
|
||||
|
||||
// AR Channel
|
||||
typedef struct packed {
|
||||
id_t id;
|
||||
addr_t addr;
|
||||
axi_pkg::len_t len;
|
||||
axi_pkg::size_t size;
|
||||
axi_pkg::burst_t burst;
|
||||
logic lock;
|
||||
axi_pkg::cache_t cache;
|
||||
axi_pkg::prot_t prot;
|
||||
axi_pkg::qos_t qos;
|
||||
axi_pkg::region_t region;
|
||||
} ar_chan_t;
|
||||
|
||||
// R Channel
|
||||
typedef struct packed {
|
||||
id_t id;
|
||||
data_t data;
|
||||
axi_pkg::resp_t resp;
|
||||
logic last;
|
||||
} r_chan_t;
|
||||
|
||||
typedef struct packed {
|
||||
aw_chan_t aw;
|
||||
logic aw_valid;
|
||||
w_chan_t w;
|
||||
logic w_valid;
|
||||
logic b_ready;
|
||||
ar_chan_t ar;
|
||||
logic ar_valid;
|
||||
logic r_ready;
|
||||
} req_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic aw_ready;
|
||||
logic ar_ready;
|
||||
logic w_ready;
|
||||
logic b_valid;
|
||||
b_chan_t b;
|
||||
logic r_valid;
|
||||
r_chan_t r;
|
||||
} resp_t;
|
||||
|
||||
endpackage
|
|
@ -20,27 +20,23 @@ import instruction_tracer_pkg::*;
|
|||
//pragma translate_on
|
||||
|
||||
module ariane #(
|
||||
parameter logic [63:0] CACHE_START_ADDR = 64'h8000_0000, // address on which to decide whether the request is cache-able or not
|
||||
parameter int unsigned AXI_ID_WIDTH = 10, // minimum 1
|
||||
parameter int unsigned AXI_USER_WIDTH = 1 // minimum 1
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
// Core ID, Cluster ID and boot address are considered more or less static
|
||||
input logic [63:0] boot_addr_i, // reset boot address
|
||||
input logic [63:0] hart_id_i, // hart id in a multicore environment (reflected in a CSR)
|
||||
// Instruction memory interface
|
||||
AXI_BUS.Master instr_if,
|
||||
// Data memory interface
|
||||
AXI_BUS.Master data_if, // data cache refill port
|
||||
AXI_BUS.Master bypass_if, // bypass axi port (disabled cache or uncacheable access)
|
||||
// Interrupt inputs
|
||||
input logic [1:0] irq_i, // level sensitive IR lines, mip & sip (async)
|
||||
input logic ipi_i, // inter-processor interrupts (async)
|
||||
// Timer facilities
|
||||
input logic time_irq_i, // timer interrupt in (async)
|
||||
input logic debug_req_i // debug request (async)
|
||||
);
|
||||
parameter logic [63:0] CACHE_START_ADDR = 64'h8000_0000 // address on which to decide whether the request is cache-able or not
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
// Core ID, Cluster ID and boot address are considered more or less static
|
||||
input logic [63:0] boot_addr_i, // reset boot address
|
||||
input logic [63:0] hart_id_i, // hart id in a multicore environment (reflected in a CSR)
|
||||
// memory side, AXI Master
|
||||
output ariane_axi::req_t axi_req_o,
|
||||
input ariane_axi::resp_t axi_resp_i,
|
||||
// Interrupt inputs
|
||||
input logic [1:0] irq_i, // level sensitive IR lines, mip & sip (async)
|
||||
input logic ipi_i, // inter-processor interrupts (async)
|
||||
// Timer facilities
|
||||
input logic time_irq_i, // timer interrupt in (async)
|
||||
input logic debug_req_i // debug request (async)
|
||||
);
|
||||
|
||||
// ------------------------------------------
|
||||
// Global Signals
|
||||
|
@ -564,6 +560,7 @@ module ariane #(
|
|||
// to D$
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.priv_lvl_i ( priv_lvl ),
|
||||
// I$
|
||||
.icache_en_i ( icache_en_csr ),
|
||||
.icache_flush_i ( icache_flush_ctrl_cache ),
|
||||
|
@ -584,9 +581,8 @@ module ariane #(
|
|||
.dcache_req_ports_i ( dcache_req_ports_ex_cache ),
|
||||
.dcache_req_ports_o ( dcache_req_ports_cache_ex ),
|
||||
// memory side
|
||||
.icache_data_if ( instr_if ),
|
||||
.dcache_data_if ( data_if ),
|
||||
.dcache_bypass_if ( bypass_if )
|
||||
.axi_req_o ( axi_req_o ),
|
||||
.axi_resp_i ( axi_resp_i )
|
||||
);
|
||||
|
||||
// -------------------
|
||||
|
|
2
src/axi
2
src/axi
|
@ -1 +1 @@
|
|||
Subproject commit 328cbe05a42a31aae6f57f780351a2ba22954fef
|
||||
Subproject commit 50c23985e4ea063dd4aa919101ce16c4e48624ac
|
|
@ -42,7 +42,8 @@ module axi_adapter #(
|
|||
output logic [63:0] critical_word_o,
|
||||
output logic critical_word_valid_o,
|
||||
// AXI port
|
||||
AXI_BUS.Master axi
|
||||
output ariane_axi::req_t axi_req_o,
|
||||
input ariane_axi::resp_t axi_resp_i
|
||||
);
|
||||
localparam BURST_SIZE = DATA_WIDTH/64-1;
|
||||
localparam ADDR_INDEX = ($clog2(DATA_WIDTH/64) > 0) ? $clog2(DATA_WIDTH/64) : 1;
|
||||
|
@ -62,50 +63,47 @@ module axi_adapter #(
|
|||
|
||||
always_comb begin : axi_fsm
|
||||
// Default assignments
|
||||
axi.aw_valid = 1'b0;
|
||||
axi.aw_addr = addr_i;
|
||||
axi.aw_prot = 3'b0;
|
||||
axi.aw_region = 4'b0;
|
||||
axi.aw_len = 8'b0;
|
||||
axi.aw_size = {1'b0, size_i};
|
||||
axi.aw_burst = (type_i == SINGLE_REQ) ? 2'b00 : 2'b01; // fixed size for single request and incremental transfer for everything else
|
||||
axi.aw_lock = 1'b0;
|
||||
axi.aw_cache = 4'b0;
|
||||
axi.aw_qos = 4'b0;
|
||||
axi.aw_id = id_i;
|
||||
axi.aw_user = '0;
|
||||
axi_req_o.aw_valid = 1'b0;
|
||||
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};
|
||||
axi_req_o.aw.burst = (type_i == SINGLE_REQ) ? 2'b00 : 2'b01; // fixed size for single request and incremental transfer for everything else
|
||||
axi_req_o.aw.lock = 1'b0;
|
||||
axi_req_o.aw.cache = 4'b0;
|
||||
axi_req_o.aw.qos = 4'b0;
|
||||
axi_req_o.aw.id = id_i;
|
||||
axi_req_o.aw.atop = '0; // currently not used
|
||||
|
||||
axi.ar_valid = 1'b0;
|
||||
axi_req_o.ar_valid = 1'b0;
|
||||
// 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
|
||||
axi.ar_addr = (CRITICAL_WORD_FIRST || type_i == SINGLE_REQ) ? addr_i : { addr_i[63:DCACHE_BYTE_OFFSET], {{DCACHE_BYTE_OFFSET}{1'b0}}};
|
||||
axi.ar_prot = 3'b0;
|
||||
axi.ar_region = 4'b0;
|
||||
axi.ar_len = 8'b0;
|
||||
axi.ar_size = {1'b0, size_i}; // 8 bytes
|
||||
axi.ar_burst = (type_i == SINGLE_REQ) ? 2'b00 : (CRITICAL_WORD_FIRST ? 2'b10 : 2'b01); // wrapping transfer in case of a critical word first strategy
|
||||
axi.ar_lock = 1'b0;
|
||||
axi.ar_cache = 4'b0;
|
||||
axi.ar_qos = 4'b0;
|
||||
axi.ar_id = id_i;
|
||||
axi.ar_user = '0;
|
||||
axi_req_o.ar.addr = (CRITICAL_WORD_FIRST || type_i == SINGLE_REQ) ? addr_i : { addr_i[63:DCACHE_BYTE_OFFSET], {{DCACHE_BYTE_OFFSET}{1'b0}}};
|
||||
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}; // 8 bytes
|
||||
axi_req_o.ar.burst = (type_i == SINGLE_REQ) ? 2'b00 : (CRITICAL_WORD_FIRST ? 2'b10 : 2'b01); // wrapping transfer in case of a critical word first strategy
|
||||
axi_req_o.ar.lock = 1'b0;
|
||||
axi_req_o.ar.cache = 4'b0;
|
||||
axi_req_o.ar.qos = 4'b0;
|
||||
axi_req_o.ar.id = id_i;
|
||||
|
||||
axi.w_valid = 1'b0;
|
||||
axi.w_data = wdata_i[0];
|
||||
axi.w_strb = be_i[0];
|
||||
axi.w_user = '0;
|
||||
axi.w_last = 1'b0;
|
||||
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.b_ready = 1'b0;
|
||||
axi.r_ready = 1'b0;
|
||||
axi_req_o.b_ready = 1'b0;
|
||||
axi_req_o.r_ready = 1'b0;
|
||||
|
||||
gnt_o = 1'b0;
|
||||
gnt_id_o = id_i;
|
||||
valid_o = 1'b0;
|
||||
id_o = axi.r_id;
|
||||
id_o = axi_resp_i.r.id;
|
||||
|
||||
// rdata_o = axi.r_data;
|
||||
critical_word_o = axi.r_data;
|
||||
critical_word_o = axi_resp_i.r.data;
|
||||
critical_word_valid_o = 1'b0;
|
||||
rdata_o = cache_line_q;
|
||||
|
||||
|
@ -126,51 +124,51 @@ module axi_adapter #(
|
|||
// write
|
||||
if (we_i) begin
|
||||
// the data is valid
|
||||
axi.aw_valid = 1'b1;
|
||||
axi.w_valid = 1'b1;
|
||||
axi_req_o.aw_valid = 1'b1;
|
||||
axi_req_o.w_valid = 1'b1;
|
||||
// its a single write
|
||||
if (type_i == SINGLE_REQ) begin
|
||||
// only a single write so the data is already the last one
|
||||
axi.w_last = 1'b1;
|
||||
axi_req_o.w.last = 1'b1;
|
||||
// single req can be granted here
|
||||
gnt_o = axi.aw_ready & axi.w_ready;
|
||||
case ({axi.aw_ready, axi.w_ready})
|
||||
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
|
||||
|
||||
// its a request for the whole cache line
|
||||
end else begin
|
||||
axi.aw_len = BURST_SIZE; // number of bursts to do
|
||||
axi.w_data = wdata_i[0];
|
||||
axi.w_strb = be_i[0];
|
||||
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.w_ready)
|
||||
if (axi_resp_i.w_ready)
|
||||
cnt_d = BURST_SIZE - 1;
|
||||
else
|
||||
cnt_d = BURST_SIZE;
|
||||
|
||||
case ({axi.aw_ready, axi.w_ready})
|
||||
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.ar_valid = 1'b1;
|
||||
gnt_o = axi.ar_ready;
|
||||
|
||||
axi_req_o.ar_valid = 1'b1;
|
||||
gnt_o = axi_resp_i.ar_ready;
|
||||
|
||||
if (type_i != SINGLE_REQ) begin
|
||||
axi.ar_len = BURST_SIZE;
|
||||
axi_req_o.ar.len = BURST_SIZE;
|
||||
cnt_d = BURST_SIZE;
|
||||
end
|
||||
|
||||
if (axi.ar_ready) begin
|
||||
if (axi_resp_i.ar_ready) begin
|
||||
state_d = (type_i == SINGLE_REQ) ? WAIT_R_VALID : WAIT_R_VALID_MULTIPLE;
|
||||
addr_offset_d = addr_i[ADDR_INDEX-1+3:3];
|
||||
end
|
||||
|
@ -180,32 +178,33 @@ module axi_adapter #(
|
|||
|
||||
// ~> from single write
|
||||
WAIT_AW_READY: begin
|
||||
axi.aw_valid = 1'b1;
|
||||
|
||||
if (axi.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;
|
||||
end
|
||||
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.w_valid = 1'b1;
|
||||
axi.w_last = (cnt_q == '0);
|
||||
axi_req_o.w_valid = 1'b1;
|
||||
axi_req_o.w.last = (cnt_q == '0);
|
||||
|
||||
if (type_i == SINGLE_REQ) begin
|
||||
axi.w_data = wdata_i[0];
|
||||
axi.w_strb = be_i[0];
|
||||
axi_req_o.w.data = wdata_i[0];
|
||||
axi_req_o.w.strb = be_i[0];
|
||||
end else begin
|
||||
axi.w_data = wdata_i[BURST_SIZE-cnt_q];
|
||||
axi.w_strb = be_i[BURST_SIZE-cnt_q];
|
||||
axi_req_o.w.data = wdata_i[BURST_SIZE-cnt_q];
|
||||
axi_req_o.w.strb = be_i[BURST_SIZE-cnt_q];
|
||||
end
|
||||
axi.aw_valid = 1'b1;
|
||||
axi_req_o.aw_valid = 1'b1;
|
||||
// we are here because we want to write a cache line
|
||||
axi.aw_len = BURST_SIZE;
|
||||
axi_req_o.aw.len = BURST_SIZE;
|
||||
// we got an aw_ready
|
||||
case ({axi.aw_ready, axi.w_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?
|
||||
|
@ -233,10 +232,10 @@ module axi_adapter #(
|
|||
|
||||
// ~> all data has already been sent, we are only waiting for the aw_ready
|
||||
WAIT_AW_READY_BURST: begin
|
||||
axi.aw_valid = 1'b1;
|
||||
axi.aw_len = BURST_SIZE;
|
||||
axi_req_o.aw_valid = 1'b1;
|
||||
axi_req_o.aw.len = BURST_SIZE;
|
||||
|
||||
if (axi.aw_ready) begin
|
||||
if (axi_resp_i.aw_ready) begin
|
||||
state_d = WAIT_B_VALID;
|
||||
gnt_o = 1'b1;
|
||||
end
|
||||
|
@ -244,32 +243,32 @@ module axi_adapter #(
|
|||
|
||||
// ~> from write, there is an outstanding write
|
||||
WAIT_LAST_W_READY: begin
|
||||
axi.w_valid = 1'b1;
|
||||
|
||||
axi_req_o.w_valid = 1'b1;
|
||||
|
||||
if (type_i != SINGLE_REQ) begin
|
||||
axi.w_data = wdata_i[BURST_SIZE-cnt_q];
|
||||
axi.w_strb = be_i[BURST_SIZE-cnt_q];
|
||||
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.w_last = 1'b1;
|
||||
if (axi.w_ready) begin
|
||||
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.w_ready) begin
|
||||
end else if (axi_resp_i.w_ready) begin
|
||||
cnt_d = cnt_q - 1;
|
||||
end
|
||||
end
|
||||
|
||||
// ~> finish write transaction
|
||||
WAIT_B_VALID: begin
|
||||
axi.b_ready = 1'b1;
|
||||
id_o = axi.b_id;
|
||||
axi_req_o.b_ready = 1'b1;
|
||||
id_o = axi_resp_i.b.id;
|
||||
|
||||
// Write is valid
|
||||
if (axi.b_valid) begin
|
||||
if (axi_resp_i.b_valid) begin
|
||||
state_d = IDLE;
|
||||
valid_o = 1'b1;
|
||||
end
|
||||
|
@ -283,35 +282,35 @@ module axi_adapter #(
|
|||
index = BURST_SIZE-cnt_q;
|
||||
|
||||
// reads are always wrapping here
|
||||
axi.r_ready = 1'b1;
|
||||
axi_req_o.r_ready = 1'b1;
|
||||
// this is the first read a.k.a the critical word
|
||||
if (axi.r_valid) begin
|
||||
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.r_data;
|
||||
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.r_data;
|
||||
critical_word_o = axi_resp_i.r.data;
|
||||
end
|
||||
end
|
||||
|
||||
// this is the last read
|
||||
if (axi.r_last) begin
|
||||
id_d = axi.r_id;
|
||||
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.r_data;
|
||||
cache_line_d[index] = axi_resp_i.r.data;
|
||||
|
||||
end else
|
||||
cache_line_d[0] = axi.r_data;
|
||||
cache_line_d[0] = axi_resp_i.r.data;
|
||||
|
||||
// Decrease the counter
|
||||
cnt_d = cnt_q - 1;
|
||||
|
|
|
@ -19,9 +19,7 @@ import ariane_pkg::*;
|
|||
import std_cache_pkg::*;
|
||||
|
||||
module miss_handler #(
|
||||
parameter int unsigned NR_PORTS = 3,
|
||||
parameter int unsigned AXI_ID_WIDTH = 10,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1
|
||||
parameter int unsigned NR_PORTS = 3
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
@ -35,14 +33,19 @@ module miss_handler #(
|
|||
output logic [NR_PORTS-1:0] bypass_gnt_o,
|
||||
output logic [NR_PORTS-1:0] bypass_valid_o,
|
||||
output logic [NR_PORTS-1:0][63:0] bypass_data_o,
|
||||
AXI_BUS.Master bypass_if,
|
||||
|
||||
// AXI port
|
||||
output ariane_axi::req_t axi_bypass_o,
|
||||
input ariane_axi::resp_t axi_bypass_i,
|
||||
|
||||
// Miss handling (~> cacheline refill)
|
||||
output logic [NR_PORTS-1:0] miss_gnt_o,
|
||||
output logic [NR_PORTS-1:0] active_serving_o,
|
||||
|
||||
output logic [63:0] critical_word_o,
|
||||
output logic critical_word_valid_o,
|
||||
AXI_BUS.Master data_if,
|
||||
output ariane_axi::req_t axi_data_o,
|
||||
input ariane_axi::resp_t axi_data_i,
|
||||
|
||||
input logic [NR_PORTS-1:0][55:0] mshr_addr_i,
|
||||
output logic [NR_PORTS-1:0] mshr_addr_matches_o,
|
||||
|
@ -513,8 +516,8 @@ module miss_handler #(
|
|||
logic valid_bypass_fsm;
|
||||
logic [63:0] data_bypass_fsm;
|
||||
logic [$clog2(NR_PORTS)-1:0] id_fsm_bypass;
|
||||
logic [AXI_ID_WIDTH-1:0] id_bypass_fsm;
|
||||
logic [AXI_ID_WIDTH-1:0] gnt_id_bypass_fsm;
|
||||
logic [3:0] id_bypass_fsm;
|
||||
logic [3:0] gnt_id_bypass_fsm;
|
||||
|
||||
arbiter #(
|
||||
.NR_PORTS ( NR_PORTS ),
|
||||
|
@ -547,35 +550,39 @@ module miss_handler #(
|
|||
);
|
||||
|
||||
axi_adapter #(
|
||||
.DATA_WIDTH ( 64 ),
|
||||
.AXI_ID_WIDTH ( AXI_ID_WIDTH )
|
||||
.DATA_WIDTH ( 64 ),
|
||||
.AXI_ID_WIDTH ( 4 )
|
||||
) i_bypass_axi_adapter (
|
||||
.req_i ( req_fsm_bypass_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 ),
|
||||
.size_i ( req_fsm_bypass_size ),
|
||||
.id_i ( {{{AXI_ID_WIDTH-$clog2(NR_PORTS)}{1'b0}}, id_fsm_bypass} ),
|
||||
.valid_o ( valid_bypass_fsm ),
|
||||
.rdata_o ( data_bypass_fsm ),
|
||||
.gnt_id_o ( gnt_id_bypass_fsm ),
|
||||
.id_o ( id_bypass_fsm ),
|
||||
.critical_word_o ( ), // not used for single requests
|
||||
.critical_word_valid_o ( ), // not used for single requests
|
||||
.axi ( bypass_if ),
|
||||
.*
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.req_i ( req_fsm_bypass_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 ),
|
||||
.size_i ( req_fsm_bypass_size ),
|
||||
.id_i ( {2'b10, id_fsm_bypass} ),
|
||||
.valid_o ( valid_bypass_fsm ),
|
||||
.rdata_o ( data_bypass_fsm ),
|
||||
.gnt_id_o ( gnt_id_bypass_fsm ),
|
||||
.id_o ( id_bypass_fsm ),
|
||||
.critical_word_o ( ), // not used for single requests
|
||||
.critical_word_valid_o ( ), // not used for single requests
|
||||
.axi_req_o ( axi_bypass_o ),
|
||||
.axi_resp_i ( axi_bypass_i )
|
||||
);
|
||||
|
||||
// ----------------------
|
||||
// Cache Line AXI Refill
|
||||
// ----------------------
|
||||
axi_adapter #(
|
||||
.DATA_WIDTH ( DCACHE_LINE_WIDTH ),
|
||||
.AXI_ID_WIDTH ( AXI_ID_WIDTH )
|
||||
.DATA_WIDTH ( DCACHE_LINE_WIDTH ),
|
||||
.AXI_ID_WIDTH ( 4 )
|
||||
) i_miss_axi_adapter (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.req_i ( req_fsm_miss_valid ),
|
||||
.type_i ( req_fsm_miss_req ),
|
||||
.gnt_o ( gnt_miss_fsm ),
|
||||
|
@ -584,13 +591,15 @@ module miss_handler #(
|
|||
.wdata_i ( req_fsm_miss_wdata ),
|
||||
.be_i ( req_fsm_miss_be ),
|
||||
.size_i ( req_fsm_miss_size ),
|
||||
.id_i ( '0 ),
|
||||
.id_i ( 4'b1100 ),
|
||||
.gnt_id_o ( ), // open
|
||||
.valid_o ( valid_miss_fsm ),
|
||||
.rdata_o ( data_miss_fsm ),
|
||||
.id_o ( ),
|
||||
.axi ( data_if ),
|
||||
.*
|
||||
.critical_word_o,
|
||||
.critical_word_valid_o,
|
||||
.axi_req_o ( axi_data_o ),
|
||||
.axi_resp_i ( axi_data_i )
|
||||
);
|
||||
|
||||
// -----------------
|
||||
|
@ -631,13 +640,6 @@ module miss_handler #(
|
|||
miss_req_size [i] = miss_req.size;
|
||||
end
|
||||
end
|
||||
|
||||
//pragma translate_off
|
||||
initial begin
|
||||
assert (AXI_ID_WIDTH >= $clog2(NR_PORTS)) else $fatal (1, "AXI ID Width needs to be larger than number of requestors");
|
||||
end
|
||||
//pragma translate_on
|
||||
|
||||
endmodule
|
||||
|
||||
// --------------
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
// Copyright (c) 2018 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.
|
||||
// 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: Florian Zaruba <zarubaf@iis.ee.ethz.ch>, ETH Zurich
|
||||
// Michael Schaffner <schaffner@iis.ee.ethz.ch>, ETH Zurich
|
||||
|
@ -22,11 +18,11 @@ import ariane_pkg::*;
|
|||
import std_cache_pkg::*;
|
||||
|
||||
module std_cache_subsystem #(
|
||||
parameter int unsigned AXI_ID_WIDTH = 10,
|
||||
parameter logic [63:0] CACHE_START_ADDR = 64'h4000_0000
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input riscv::priv_lvl_t priv_lvl_i,
|
||||
// I$
|
||||
input logic icache_en_i, // enable icache (or bypass e.g: in debug mode)
|
||||
input logic icache_flush_i, // flush the icache, flush and kill have to be asserted together
|
||||
|
@ -50,74 +46,257 @@ module std_cache_subsystem #(
|
|||
input dcache_req_i_t [2:0] dcache_req_ports_i, // to/from LSU
|
||||
output dcache_req_o_t [2:0] dcache_req_ports_o, // to/from LSU
|
||||
// memory side
|
||||
AXI_BUS.Master icache_data_if, // I$ refill port
|
||||
AXI_BUS.Master dcache_data_if, // D$ refill port
|
||||
AXI_BUS.Master dcache_bypass_if // bypass axi port (disabled D$ or uncacheable access)
|
||||
output ariane_axi::req_t axi_req_o,
|
||||
input ariane_axi::resp_t axi_resp_i
|
||||
);
|
||||
|
||||
std_icache #(
|
||||
) i_icache (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( icache_flush_i ),
|
||||
.en_i ( icache_en_i ),
|
||||
.miss_o ( icache_miss_o ),
|
||||
.areq_i ( icache_areq_i ),
|
||||
.areq_o ( icache_areq_o ),
|
||||
.dreq_i ( icache_dreq_i ),
|
||||
.dreq_o ( icache_dreq_o ),
|
||||
.axi ( icache_data_if )
|
||||
);
|
||||
ariane_axi::req_t axi_req_icache;
|
||||
ariane_axi::resp_t axi_resp_icache;
|
||||
ariane_axi::req_t axi_req_bypass;
|
||||
ariane_axi::resp_t axi_resp_bypass;
|
||||
ariane_axi::req_t axi_req_data;
|
||||
ariane_axi::resp_t axi_resp_data;
|
||||
|
||||
std_icache i_icache (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.priv_lvl_i ( priv_lvl_i ),
|
||||
.flush_i ( icache_flush_i ),
|
||||
.en_i ( icache_en_i ),
|
||||
.miss_o ( icache_miss_o ),
|
||||
.areq_i ( icache_areq_i ),
|
||||
.areq_o ( icache_areq_o ),
|
||||
.dreq_i ( icache_dreq_i ),
|
||||
.dreq_o ( icache_dreq_o ),
|
||||
.axi_req_o ( axi_req_icache ),
|
||||
.axi_resp_i ( axi_resp_icache )
|
||||
);
|
||||
|
||||
// decreasing priority
|
||||
// Port 0: PTW
|
||||
// Port 1: Load Unit
|
||||
// Port 2: Store Unit
|
||||
std_nbdcache #(
|
||||
.AXI_ID_WIDTH ( AXI_ID_WIDTH ),
|
||||
.CACHE_START_ADDR ( CACHE_START_ADDR )
|
||||
) i_nbdcache (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.enable_i ( dcache_enable_i ),
|
||||
.flush_i ( dcache_flush_i ),
|
||||
.flush_ack_o ( dcache_flush_ack_o ),
|
||||
.miss_o ( dcache_miss_o ),
|
||||
.data_if ( dcache_data_if ),
|
||||
.bypass_if ( dcache_bypass_if ),
|
||||
.axi_bypass_o ( axi_req_bypass ),
|
||||
.axi_bypass_i ( axi_resp_bypass ),
|
||||
.axi_data_o ( axi_req_data ),
|
||||
.axi_data_i ( axi_resp_data ),
|
||||
.req_ports_i ( dcache_req_ports_i ),
|
||||
.req_ports_o ( dcache_req_ports_o ),
|
||||
.amo_req_i ( amo_req_i ),
|
||||
.amo_resp_o ( amo_resp_o )
|
||||
.amo_req_i,
|
||||
.amo_resp_o
|
||||
);
|
||||
|
||||
// -----------------------
|
||||
// Arbitrate AXI Ports
|
||||
// -----------------------
|
||||
logic [1:0] aw_select, ar_select, w_select;
|
||||
logic aw_arbiter_valid, ar_arbiter_valid, w_arbiter_valid;
|
||||
logic aw_enable_d, aw_enable_q;
|
||||
logic ar_enable_d, ar_enable_q;
|
||||
logic w_enable_d, w_enable_q;
|
||||
|
||||
// AW Channel
|
||||
rrarbiter #(
|
||||
.NUM_REQ ( 3 ),
|
||||
.LOCK_IN ( 1 )
|
||||
) i_rrarbiter_aw (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.flush_i ( 1'b0 ),
|
||||
.en_i ( aw_enable_q ),
|
||||
.req_i ( {axi_req_icache.aw_valid, axi_req_bypass.aw_valid, axi_req_data.aw_valid} ),
|
||||
.ack_o ( ),
|
||||
.vld_o ( aw_arbiter_valid ),
|
||||
.idx_o ( aw_select )
|
||||
);
|
||||
|
||||
stream_mux #(
|
||||
.DATA_T ( ariane_axi::aw_chan_t ),
|
||||
.N_INP ( 3 )
|
||||
) i_stream_mux_aw (
|
||||
.inp_data_i ( {axi_req_icache.aw, axi_req_bypass.aw, axi_req_data.aw} ),
|
||||
.inp_valid_i ( {axi_req_icache.aw_valid, axi_req_bypass.aw_valid, axi_req_data.aw_valid} ),
|
||||
.inp_ready_o ( {axi_resp_icache.aw_ready, axi_resp_bypass.aw_ready, axi_resp_data.aw_ready} ),
|
||||
.inp_sel_i ( aw_select ),
|
||||
.oup_data_o ( axi_req_o.aw ),
|
||||
.oup_valid_o ( axi_req_o.aw_valid ),
|
||||
.oup_ready_i ( axi_resp_i.aw_ready )
|
||||
);
|
||||
|
||||
// AR Channel
|
||||
rrarbiter #(
|
||||
.NUM_REQ ( 3 ),
|
||||
.LOCK_IN ( 1 )
|
||||
) i_rrarbiter_ar (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.flush_i ( 1'b0 ),
|
||||
.en_i ( ar_enable_q ),
|
||||
.req_i ( {axi_req_icache.ar_valid, axi_req_bypass.ar_valid, axi_req_data.ar_valid} ),
|
||||
.ack_o ( ),
|
||||
.vld_o ( ar_arbiter_valid ),
|
||||
.idx_o ( ar_select )
|
||||
);
|
||||
|
||||
stream_mux #(
|
||||
.DATA_T ( ariane_axi::ar_chan_t ),
|
||||
.N_INP ( 3 )
|
||||
) i_stream_mux_ar (
|
||||
.inp_data_i ( {axi_req_icache.ar, axi_req_bypass.ar, axi_req_data.ar} ),
|
||||
.inp_valid_i ( {axi_req_icache.ar_valid, axi_req_bypass.ar_valid, axi_req_data.ar_valid} ),
|
||||
.inp_ready_o ( {axi_resp_icache.ar_ready, axi_resp_bypass.ar_ready, axi_resp_data.ar_ready} ),
|
||||
.inp_sel_i ( ar_select ),
|
||||
.oup_data_o ( axi_req_o.ar ),
|
||||
.oup_valid_o ( axi_req_o.ar_valid ),
|
||||
.oup_ready_i ( axi_resp_i.ar_ready )
|
||||
);
|
||||
|
||||
// W Channel
|
||||
rrarbiter #(
|
||||
.NUM_REQ ( 3 ),
|
||||
.LOCK_IN ( 1 )
|
||||
) i_rrarbiter_w (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.flush_i ( 1'b0 ),
|
||||
.en_i ( w_enable_q ),
|
||||
.req_i ( {axi_req_icache.w_valid, axi_req_bypass.w_valid, axi_req_data.w_valid} ),
|
||||
.ack_o ( ),
|
||||
.vld_o ( w_arbiter_valid ),
|
||||
.idx_o ( w_select )
|
||||
);
|
||||
|
||||
stream_mux #(
|
||||
.DATA_T ( ariane_axi::w_chan_t ),
|
||||
.N_INP ( 3 )
|
||||
) i_stream_mux_w (
|
||||
.inp_data_i ( {axi_req_icache.w, axi_req_bypass.w, axi_req_data.w} ),
|
||||
.inp_valid_i ( {axi_req_icache.w_valid, axi_req_bypass.w_valid, axi_req_data.w_valid} ),
|
||||
.inp_ready_o ( {axi_resp_icache.w_ready, axi_resp_bypass.w_ready, axi_resp_data.w_ready} ),
|
||||
.inp_sel_i ( w_select ),
|
||||
.oup_data_o ( axi_req_o.w ),
|
||||
.oup_valid_o ( axi_req_o.w_valid ),
|
||||
.oup_ready_i ( axi_resp_i.w_ready )
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
aw_enable_d = aw_enable_q;
|
||||
ar_enable_d = ar_enable_q;
|
||||
w_enable_d = w_enable_q;
|
||||
|
||||
// freeze the arbiter
|
||||
if (aw_arbiter_valid) aw_enable_d = 1'b0;
|
||||
if (ar_arbiter_valid) ar_enable_d = 1'b0;
|
||||
if (w_arbiter_valid) w_enable_d = 1'b0;
|
||||
// we've got a valid transaction, free the arbitration decision
|
||||
if (axi_resp_i.aw_ready && axi_req_o.aw_valid) aw_enable_d = 1'b1;
|
||||
if (axi_resp_i.ar_ready && axi_req_o.ar_valid) ar_enable_d = 1'b1;
|
||||
if (axi_resp_i.w_ready && axi_req_o.w_valid) w_enable_d = 1'b1;
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
aw_enable_q <= 1'b1;
|
||||
ar_enable_q <= 1'b1;
|
||||
w_enable_q <= 1'b1;
|
||||
end else begin
|
||||
aw_enable_q <= aw_enable_d;
|
||||
ar_enable_q <= ar_enable_d;
|
||||
w_enable_q <= w_enable_d;
|
||||
end
|
||||
end
|
||||
|
||||
// Route responses based on ID
|
||||
// 0000 -> I$
|
||||
// 10[00|10|01|11] -> Bypass
|
||||
// 1111 -> D$
|
||||
// R Channel
|
||||
assign axi_resp_icache.r = axi_resp_i.r;
|
||||
assign axi_resp_bypass.r = axi_resp_i.r;
|
||||
assign axi_resp_data.r = axi_resp_i.r;
|
||||
|
||||
logic [1:0] r_select;
|
||||
|
||||
always_comb begin
|
||||
r_select = 0;
|
||||
unique case (axi_resp_i.r.id)
|
||||
4'b0000: r_select = 2; // icache
|
||||
4'b1111: r_select = 0; // dcache
|
||||
4'b1000, 4'b1001, 4'b1010, 4'b1011: r_select = 1; // bypass
|
||||
default: r_select = 0;
|
||||
endcase
|
||||
end
|
||||
|
||||
stream_demux #(
|
||||
.N_OUP ( 3 )
|
||||
) i_stream_demux_r (
|
||||
.inp_valid_i ( axi_resp_i.r_valid ),
|
||||
.inp_ready_o ( axi_req_o.r_ready ),
|
||||
.oup_sel_i ( r_select ),
|
||||
.oup_valid_o ( {axi_resp_icache.r_valid, axi_resp_bypass.r_valid, axi_resp_data.r_valid} ),
|
||||
.oup_ready_i ( {axi_req_icache.r_ready, axi_req_bypass.r_ready, axi_req_data.r_ready} )
|
||||
);
|
||||
|
||||
// B Channel
|
||||
logic [1:0] b_select;
|
||||
|
||||
assign axi_resp_icache.b = axi_resp_i.b;
|
||||
assign axi_resp_bypass.b = axi_resp_i.b;
|
||||
assign axi_resp_data.b = axi_resp_i.b;
|
||||
|
||||
always_comb begin
|
||||
b_select = 0;
|
||||
unique case (axi_resp_i.b.id)
|
||||
4'b0000: b_select = 2; // icache
|
||||
4'b1111: b_select = 0; // dcache
|
||||
4'b1000, 4'b1001, 4'b1010, 4'b1011: b_select = 1; // bypass
|
||||
default: b_select = 0;
|
||||
endcase
|
||||
end
|
||||
|
||||
stream_demux #(
|
||||
.N_OUP ( 3 )
|
||||
) i_stream_demux_b (
|
||||
.inp_valid_i ( axi_resp_i.b_valid ),
|
||||
.inp_ready_o ( axi_req_o.b_ready ),
|
||||
.oup_sel_i ( b_select ),
|
||||
.oup_valid_o ( {axi_resp_icache.b_valid, axi_resp_bypass.b_valid, axi_resp_data.b_valid} ),
|
||||
.oup_ready_i ( {axi_req_icache.b_ready, axi_req_bypass.b_ready, axi_req_data.b_ready} )
|
||||
);
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// assertions
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
|
||||
//pragma translate_off
|
||||
`ifndef VERILATOR
|
||||
|
||||
a_invalid_instruction_fetch: assert property (
|
||||
@(posedge clk_i) disable iff (~rst_ni) icache_dreq_o.valid |-> (|icache_dreq_o.data) !== 1'hX)
|
||||
else $warning(1,"[l1 dcache] reading invalid instructions: vaddr=%08X, data=%08X",
|
||||
@(posedge clk_i) disable iff (~rst_ni) icache_dreq_o.valid |-> (|icache_dreq_o.data) !== 1'hX)
|
||||
else $warning(1,"[l1 dcache] reading invalid instructions: vaddr=%08X, data=%08X",
|
||||
icache_dreq_o.vaddr, icache_dreq_o.data);
|
||||
|
||||
a_invalid_write_data: assert property (
|
||||
@(posedge clk_i) disable iff (~rst_ni) dcache_req_ports_i[2].data_req |-> |dcache_req_ports_i[2].data_be |-> (|dcache_req_ports_i[2].data_wdata) !== 1'hX)
|
||||
else $warning(1,"[l1 dcache] writing invalid data: paddr=%016X, be=%02X, data=%016X",
|
||||
@(posedge clk_i) disable iff (~rst_ni) dcache_req_ports_i[2].data_req |-> |dcache_req_ports_i[2].data_be |-> (|dcache_req_ports_i[2].data_wdata) !== 1'hX)
|
||||
else $warning(1,"[l1 dcache] writing invalid data: paddr=%016X, be=%02X, data=%016X",
|
||||
{dcache_req_ports_i[2].address_tag, dcache_req_ports_i[2].address_index}, dcache_req_ports_i[2].data_be, dcache_req_ports_i[2].data_wdata);
|
||||
generate
|
||||
generate
|
||||
for(genvar j=0; j<2; j++) begin
|
||||
a_invalid_read_data: assert property (
|
||||
@(posedge clk_i) disable iff (~rst_ni) dcache_req_ports_o[j].data_rvalid |-> (|dcache_req_ports_o[j].data_rdata) !== 1'hX)
|
||||
else $warning(1,"[l1 dcache] reading invalid data on port %01d: data=%016X",
|
||||
@(posedge clk_i) disable iff (~rst_ni) dcache_req_ports_o[j].data_rvalid |-> (|dcache_req_ports_o[j].data_rdata) !== 1'hX)
|
||||
else $warning(1,"[l1 dcache] reading invalid data on port %01d: data=%016X",
|
||||
j, dcache_req_ports_o[j].data_rdata);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endgenerate
|
||||
|
||||
`endif
|
||||
//pragma translate_on
|
||||
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
import ariane_pkg::*;
|
||||
import std_cache_pkg::*;
|
||||
|
||||
module std_icache #(
|
||||
)(
|
||||
module std_icache (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input riscv::priv_lvl_t priv_lvl_i,
|
||||
|
||||
input logic flush_i, // flush the icache, flush and kill have to be asserted together
|
||||
input logic en_i, // enable icache
|
||||
|
@ -30,8 +30,9 @@ module std_icache #(
|
|||
// data requests
|
||||
input icache_dreq_i_t dreq_i,
|
||||
output icache_dreq_o_t dreq_o,
|
||||
// refill port
|
||||
AXI_BUS.Master axi
|
||||
// AXI refill port
|
||||
output ariane_axi::req_t axi_req_o,
|
||||
input ariane_axi::resp_t axi_resp_i
|
||||
);
|
||||
|
||||
localparam int unsigned ICACHE_BYTE_OFFSET = $clog2(ICACHE_LINE_WIDTH/8); // 3
|
||||
|
@ -134,42 +135,40 @@ module std_icache #(
|
|||
dreq_o.data |= cl_sel[i];
|
||||
end
|
||||
|
||||
|
||||
// ------------------
|
||||
// AXI Plumbing
|
||||
// ------------------
|
||||
assign axi.aw_valid = '0;
|
||||
assign axi.aw_addr = '0;
|
||||
assign axi.aw_prot = '0;
|
||||
assign axi.aw_region = '0;
|
||||
assign axi.aw_len = '0;
|
||||
assign axi.aw_size = 3'b000;
|
||||
assign axi.aw_burst = 2'b00;
|
||||
assign axi.aw_lock = '0;
|
||||
assign axi.aw_cache = '0;
|
||||
assign axi.aw_qos = '0;
|
||||
assign axi.aw_id = '0;
|
||||
assign axi.aw_user = '0;
|
||||
// instruction cache is read-only
|
||||
assign axi_req_o.aw_valid = '0;
|
||||
assign axi_req_o.aw.addr = '0;
|
||||
assign axi_req_o.aw.prot = '0;
|
||||
assign axi_req_o.aw.region = '0;
|
||||
assign axi_req_o.aw.len = '0;
|
||||
assign axi_req_o.aw.size = 3'b000;
|
||||
assign axi_req_o.aw.burst = 2'b00;
|
||||
assign axi_req_o.aw.lock = '0;
|
||||
assign axi_req_o.aw.cache = '0;
|
||||
assign axi_req_o.aw.qos = '0;
|
||||
assign axi_req_o.aw.id = '0;
|
||||
assign axi_req_o.aw.atop = '0;
|
||||
assign axi_req_o.w_valid = '0;
|
||||
assign axi_req_o.w.data = '0;
|
||||
assign axi_req_o.w.strb = '0;
|
||||
assign axi_req_o.w.last = 1'b0;
|
||||
assign axi_req_o.b_ready = 1'b0;
|
||||
|
||||
assign axi.w_valid = '0;
|
||||
assign axi.w_data = '0;
|
||||
assign axi.w_strb = '0;
|
||||
assign axi.w_user = '0;
|
||||
assign axi.w_last = 1'b0;
|
||||
assign axi.b_ready = 1'b0;
|
||||
// set protection flag, MSB -> instruction fetch, LSB -> privileged access or not
|
||||
assign axi_req_o.ar.prot = {1'b1, 1'b0, (priv_lvl_i == riscv::PRIV_LVL_M)};
|
||||
assign axi_req_o.ar.region = '0;
|
||||
assign axi_req_o.ar.len = (2**NR_AXI_REFILLS) - 1;
|
||||
assign axi_req_o.ar.size = 3'b011;
|
||||
assign axi_req_o.ar.burst = 2'b01;
|
||||
assign axi_req_o.ar.lock = '0;
|
||||
assign axi_req_o.ar.cache = '0;
|
||||
assign axi_req_o.ar.qos = '0;
|
||||
assign axi_req_o.ar.id = '0;
|
||||
|
||||
assign axi.ar_prot = '0;
|
||||
assign axi.ar_region = '0;
|
||||
assign axi.ar_len = (2**NR_AXI_REFILLS) - 1;
|
||||
assign axi.ar_size = 3'b011;
|
||||
assign axi.ar_burst = 2'b01;
|
||||
assign axi.ar_lock = '0;
|
||||
assign axi.ar_cache = '0;
|
||||
assign axi.ar_qos = '0;
|
||||
assign axi.ar_id = '0;
|
||||
assign axi.ar_user = '0;
|
||||
|
||||
assign axi.r_ready = 1'b1;
|
||||
assign axi_req_o.r_ready = 1'b1;
|
||||
|
||||
assign data_be = be;
|
||||
assign data_wdata = wdata;
|
||||
|
@ -178,7 +177,6 @@ module std_icache #(
|
|||
|
||||
assign addr = (state_q==FLUSH) ? cnt_q : vaddr_d[ICACHE_INDEX_WIDTH-1:ICACHE_BYTE_OFFSET];
|
||||
|
||||
|
||||
// ------------------
|
||||
// Cache Ctrl
|
||||
// ------------------
|
||||
|
@ -208,8 +206,8 @@ module std_icache #(
|
|||
update_lfsr = 1'b0;
|
||||
miss_o = 1'b0;
|
||||
|
||||
axi.ar_valid = 1'b0;
|
||||
axi.ar_addr = '0;
|
||||
axi_req_o.ar_valid = 1'b0;
|
||||
axi_req_o.ar.addr = '0;
|
||||
|
||||
areq_o.fetch_req = 1'b0;
|
||||
areq_o.fetch_vaddr = vaddr_q;
|
||||
|
@ -319,15 +317,15 @@ module std_icache #(
|
|||
end
|
||||
// ~> request a cache-line refill
|
||||
REFILL, WAIT_KILLED_REFILL: begin
|
||||
axi.ar_valid = 1'b1;
|
||||
axi.ar_addr[ICACHE_INDEX_WIDTH+ICACHE_TAG_WIDTH-1:0] = {tag_q, vaddr_q[ICACHE_INDEX_WIDTH-1:ICACHE_BYTE_OFFSET], {ICACHE_BYTE_OFFSET{1'b0}}};
|
||||
axi_req_o.ar_valid = 1'b1;
|
||||
axi_req_o.ar.addr[ICACHE_INDEX_WIDTH+ICACHE_TAG_WIDTH-1:0] = {tag_q, vaddr_q[ICACHE_INDEX_WIDTH-1:ICACHE_BYTE_OFFSET], {ICACHE_BYTE_OFFSET{1'b0}}};
|
||||
burst_cnt_d = '0;
|
||||
|
||||
if (dreq_i.kill_s2)
|
||||
state_d = WAIT_KILLED_REFILL;
|
||||
|
||||
// we need to finish this AXI transfer
|
||||
if (axi.ar_ready)
|
||||
if (axi_resp_i.ar_ready)
|
||||
state_d = (dreq_i.kill_s2 || (state_q == WAIT_KILLED_REFILL)) ? WAIT_KILLED_AXI_R_RESP : WAIT_AXI_R_RESP;
|
||||
end
|
||||
// ~> wait for the read response
|
||||
|
@ -336,11 +334,11 @@ module std_icache #(
|
|||
req = evict_way_q;
|
||||
vld_req = evict_way_q;
|
||||
|
||||
if (axi.r_valid) begin
|
||||
if (axi_resp_i.r_valid) begin
|
||||
we = 1'b1;
|
||||
tag_wdata.tag = tag_q;
|
||||
tag_wdata.valid = 1'b1;
|
||||
wdata[burst_cnt_q] = axi.r_data;
|
||||
wdata[burst_cnt_q] = axi_resp_i.r.data;
|
||||
// enable the right write path
|
||||
be[burst_cnt_q] = '1;
|
||||
// increase burst count
|
||||
|
@ -350,11 +348,11 @@ module std_icache #(
|
|||
if (dreq_i.kill_s2)
|
||||
state_d = WAIT_KILLED_AXI_R_RESP;
|
||||
|
||||
if (axi.r_valid && axi.r_last) begin
|
||||
if (axi_resp_i.r_valid && axi_resp_i.r.last) begin
|
||||
state_d = (dreq_i.kill_s2) ? IDLE : REDO_REQ;
|
||||
end
|
||||
|
||||
if ((state_q == WAIT_KILLED_AXI_R_RESP) && axi.r_last && axi.r_valid)
|
||||
if ((state_q == WAIT_KILLED_AXI_R_RESP) && axi_resp_i.r.last && axi_resp_i.r_valid)
|
||||
state_d = IDLE;
|
||||
end
|
||||
// ~> redo the request,
|
||||
|
@ -450,7 +448,7 @@ module std_icache #(
|
|||
//pragma translate_off
|
||||
`ifndef VERILATOR
|
||||
initial begin
|
||||
assert ($bits(axi.aw_addr) == 64)
|
||||
assert ($bits(axi_req_o.aw.addr) == 64)
|
||||
else $fatal(1, "[icache] Ariane needs a 64-bit bus");
|
||||
end
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ import ariane_pkg::*;
|
|||
import std_cache_pkg::*;
|
||||
|
||||
module std_nbdcache #(
|
||||
parameter int unsigned AXI_ID_WIDTH = 10,
|
||||
parameter logic [63:0] CACHE_START_ADDR = 64'h8000_0000
|
||||
)(
|
||||
input logic clk_i, // Clock
|
||||
|
@ -33,8 +32,10 @@ module std_nbdcache #(
|
|||
input dcache_req_i_t [2:0] req_ports_i, // request ports
|
||||
output dcache_req_o_t [2:0] req_ports_o, // request ports
|
||||
// Cache AXI refill port
|
||||
AXI_BUS.Master data_if,
|
||||
AXI_BUS.Master bypass_if
|
||||
output ariane_axi::req_t axi_data_o,
|
||||
input ariane_axi::resp_t axi_data_i,
|
||||
output ariane_axi::req_t axi_bypass_o,
|
||||
input ariane_axi::resp_t axi_bypass_i
|
||||
);
|
||||
|
||||
// -------------------------------
|
||||
|
@ -126,14 +127,13 @@ module std_nbdcache #(
|
|||
// Miss Handling Unit
|
||||
// ------------------
|
||||
miss_handler #(
|
||||
.AXI_ID_WIDTH ( AXI_ID_WIDTH ),
|
||||
.NR_PORTS ( 3 )
|
||||
) i_miss_handler (
|
||||
.flush_i ( flush_i ),
|
||||
.busy_i ( |busy ),
|
||||
// AMOs
|
||||
.amo_req_i ( amo_req_i ),
|
||||
.amo_resp_o ( amo_resp_o ),
|
||||
.amo_req_i ( amo_req_i ),
|
||||
.amo_resp_o ( amo_resp_o ),
|
||||
.miss_req_i ( miss_req ),
|
||||
.miss_gnt_o ( miss_gnt ),
|
||||
.bypass_gnt_o ( bypass_gnt ),
|
||||
|
@ -151,8 +151,10 @@ module std_nbdcache #(
|
|||
.be_o ( be [0] ),
|
||||
.data_o ( wdata [0] ),
|
||||
.we_o ( we [0] ),
|
||||
.bypass_if,
|
||||
.data_if,
|
||||
.axi_bypass_o,
|
||||
.axi_bypass_i,
|
||||
.axi_data_o,
|
||||
.axi_data_i,
|
||||
.*
|
||||
);
|
||||
|
||||
|
@ -252,7 +254,7 @@ module std_nbdcache #(
|
|||
|
||||
//pragma translate_off
|
||||
initial begin
|
||||
assert ($bits(data_if.aw_addr) == 64) else $fatal(1, "Ariane needs a 64-bit bus");
|
||||
assert ($bits(axi_data_o.aw.addr) == 64) else $fatal(1, "Ariane needs a 64-bit bus");
|
||||
assert (DCACHE_LINE_WIDTH/64 inside {2, 4, 8, 16}) else $fatal(1, "Cache line size needs to be a power of two multiple of 64");
|
||||
end
|
||||
//pragma translate_on
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 21a060d2c2c75173312b82cc72db96a2c62e66c5
|
||||
Subproject commit 3b18d9ce9889fb140cd39c8d7c86b3a6cc68872e
|
|
@ -20,8 +20,9 @@ module dm_sba (
|
|||
input logic clk_i, // Clock
|
||||
input logic rst_ni,
|
||||
input logic dmactive_i, // synchronous reset active low
|
||||
|
||||
AXI_BUS.Master axi_master,
|
||||
// AXI port
|
||||
output ariane_axi::req_t axi_req_o,
|
||||
input ariane_axi::resp_t axi_resp_i,
|
||||
|
||||
input logic [63:0] sbaddress_i,
|
||||
input logic sbaddress_write_valid_i,
|
||||
|
@ -150,7 +151,8 @@ module dm_sba (
|
|||
.id_o ( ),
|
||||
.critical_word_o ( ), // not needed here
|
||||
.critical_word_valid_o ( ), // not needed here
|
||||
.axi ( axi_master )
|
||||
.axi_req_o,
|
||||
.axi_resp_i
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -33,7 +33,10 @@ module dm_top #(
|
|||
input logic [NrHarts-1:0] unavailable_i, // communicate whether the hart is unavailable (e.g.: power down)
|
||||
|
||||
AXI_BUS.Slave axi_slave, // bus slave, for an execution based technique
|
||||
AXI_BUS.Master axi_master, // bus master, for system bus accesses
|
||||
// bus master, for system bus accesses
|
||||
output ariane_axi::req_t axi_req_o,
|
||||
input ariane_axi::resp_t axi_resp_i,
|
||||
|
||||
// Connection to DTM - compatible to RocketChip Debug Module
|
||||
input logic dmi_rst_ni,
|
||||
input logic dmi_req_valid_i,
|
||||
|
@ -145,7 +148,8 @@ module dm_top #(
|
|||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.dmactive_i ( dmactive_o ),
|
||||
.axi_master,
|
||||
.axi_req_o,
|
||||
.axi_resp_i,
|
||||
.sbaddress_i ( sbaddress_csrs_sba ),
|
||||
.sbaddress_o ( sbaddress_sba_csrs ),
|
||||
.sbaddress_write_valid_i ( sbaddress_write_valid ),
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 20cccce06886ef21f263e63dbb38b008ff87419e
|
||||
Subproject commit a3ba269c0fc6cfcee6f81e5d9af018a08e479d2b
|
67
src/util/axi_connect.sv
Normal file
67
src/util/axi_connect.sv
Normal file
|
@ -0,0 +1,67 @@
|
|||
// 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.
|
||||
//
|
||||
// Description: Connects SV AXI interface to structs used by Ariane
|
||||
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
|
||||
|
||||
module axi_connect (
|
||||
input ariane_axi::req_t axi_req_i,
|
||||
output ariane_axi::resp_t axi_resp_o,
|
||||
AXI_BUS.out master
|
||||
);
|
||||
|
||||
assign master.aw_id = axi_req_i.aw.id;
|
||||
assign master.aw_addr = axi_req_i.aw.addr;
|
||||
assign master.aw_len = axi_req_i.aw.len;
|
||||
assign master.aw_size = axi_req_i.aw.size;
|
||||
assign master.aw_burst = axi_req_i.aw.burst;
|
||||
assign master.aw_lock = axi_req_i.aw.lock;
|
||||
assign master.aw_cache = axi_req_i.aw.cache;
|
||||
assign master.aw_prot = axi_req_i.aw.prot;
|
||||
assign master.aw_qos = axi_req_i.aw.qos;
|
||||
assign master.aw_region = axi_req_i.aw.region;
|
||||
assign master.aw_user = '0;
|
||||
assign master.aw_valid = axi_req_i.aw_valid;
|
||||
assign axi_resp_o.aw_ready = master.aw_ready;
|
||||
|
||||
assign master.w_data = axi_req_i.w.data;
|
||||
assign master.w_strb = axi_req_i.w.strb;
|
||||
assign master.w_last = axi_req_i.w.last;
|
||||
assign master.w_user = '0;
|
||||
assign master.w_valid = axi_req_i.w_valid;
|
||||
assign axi_resp_o.w_ready = master.w_ready;
|
||||
|
||||
assign axi_resp_o.b.id = master.b_id;
|
||||
assign axi_resp_o.b.resp = master.b_resp;
|
||||
assign axi_resp_o.b_valid = master.b_valid;
|
||||
assign master.b_ready = axi_req_i.b_ready;
|
||||
|
||||
assign master.ar_id = axi_req_i.ar.id;
|
||||
assign master.ar_addr = axi_req_i.ar.addr;
|
||||
assign master.ar_len = axi_req_i.ar.len;
|
||||
assign master.ar_size = axi_req_i.ar.size;
|
||||
assign master.ar_burst = axi_req_i.ar.burst;
|
||||
assign master.ar_lock = axi_req_i.ar.lock;
|
||||
assign master.ar_cache = axi_req_i.ar.cache;
|
||||
assign master.ar_prot = axi_req_i.ar.prot;
|
||||
assign master.ar_qos = axi_req_i.ar.qos;
|
||||
assign master.ar_region = axi_req_i.ar.region;
|
||||
assign master.ar_user = '0;
|
||||
assign master.ar_valid = axi_req_i.ar_valid;
|
||||
assign axi_resp_o.ar_ready = master.ar_ready;
|
||||
|
||||
assign axi_resp_o.r.id = master.r_id;
|
||||
assign axi_resp_o.r.data = master.r_data;
|
||||
assign axi_resp_o.r.resp = master.r_resp;
|
||||
assign axi_resp_o.r.last = master.r_last;
|
||||
assign axi_resp_o.r_valid = master.r_valid;
|
||||
assign master.r_ready = axi_req_i.r_ready;
|
||||
|
||||
endmodule
|
|
@ -13,15 +13,15 @@
|
|||
// Date: 15.08.2018
|
||||
// Description: SRAM wrapper for FPGA (requires the fpga-support submodule)
|
||||
//
|
||||
// Note: the wrapped module contains two different implementations for
|
||||
// ALTERA and XILINX tools, since these follow different coding styles for
|
||||
// inferrable RAMS with byte enable. define `FPGA_TARGET_XILINX or
|
||||
// Note: the wrapped module contains two different implementations for
|
||||
// ALTERA and XILINX tools, since these follow different coding styles for
|
||||
// inferrable RAMS with byte enable. define `FPGA_TARGET_XILINX or
|
||||
// `FPGA_TARGET_ALTERA in your build environment (default is ALTERA)
|
||||
|
||||
|
||||
module sram #(
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter NUM_WORDS = 1024,
|
||||
parameter OUT_REGS = 0 // enables output registers in FPGA macro (read lat = 2)
|
||||
parameter OUT_REGS = 0 // enables output registers in FPGA macro (read lat = 2)
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
@ -52,23 +52,24 @@ end
|
|||
|
||||
genvar k;
|
||||
generate
|
||||
for (k = 0; k<(DATA_WIDTH+63)/64; k++) begin
|
||||
for (k = 0; k<(DATA_WIDTH+63)/64; k++) begin
|
||||
// unused byte-enable segments (8bits) are culled by the tool
|
||||
SyncSpRamBeNx64 #(
|
||||
.ADDR_WIDTH($clog2(NUM_WORDS)),
|
||||
.DATA_DEPTH(NUM_WORDS),
|
||||
.OUT_REGS (0)
|
||||
.DATA_DEPTH(NUM_WORDS),
|
||||
.OUT_REGS (0),
|
||||
.SIM_INIT (2)
|
||||
) i_ram (
|
||||
.Clk_CI ( clk_i ),
|
||||
.Rst_RBI ( rst_ni ),
|
||||
.CSel_SI ( req_i ),
|
||||
.WrEn_SI ( we_i ),
|
||||
.BEn_SI ( be_aligned[k*8 +: 8] ),
|
||||
.WrData_DI ( wdata_aligned[k*64 +: 64] ),
|
||||
.Addr_DI ( addr_i ),
|
||||
.WrData_DI ( wdata_aligned[k*64 +: 64] ),
|
||||
.Addr_DI ( addr_i ),
|
||||
.RdData_DO ( rdata_aligned[k*64 +: 64] )
|
||||
);
|
||||
end
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule : sram
|
||||
|
|
|
@ -15,15 +15,15 @@
|
|||
|
||||
module ariane_testharness #(
|
||||
parameter logic [63:0] CACHE_START_ADDR = 64'h8000_0000, // address on which to decide whether the request is cache-able or not
|
||||
parameter int unsigned AXI_ID_WIDTH = 10,
|
||||
parameter int unsigned AXI_ID_WIDTH = 4,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_ADDRESS_WIDTH = 64,
|
||||
parameter int unsigned AXI_DATA_WIDTH = 64,
|
||||
parameter int unsigned NUM_WORDS = 2**24 // memory size
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
output logic [31:0] exit_o
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
output logic [31:0] exit_o
|
||||
);
|
||||
|
||||
// disable test-enable
|
||||
|
@ -70,7 +70,7 @@ module ariane_testharness #(
|
|||
assign test_en = 1'b0;
|
||||
assign ndmreset_n = ~ndmreset ;
|
||||
|
||||
localparam NB_SLAVE = 4;
|
||||
localparam NB_SLAVE = 2;
|
||||
localparam NB_MASTER = 4;
|
||||
|
||||
localparam AXI_ID_WIDTH_SLAVES = AXI_ID_WIDTH + $clog2(NB_SLAVE);
|
||||
|
@ -166,6 +166,9 @@ module ariane_testharness #(
|
|||
.exit ( dmi_exit )
|
||||
);
|
||||
|
||||
ariane_axi::req_t axi_sba_req;
|
||||
ariane_axi::resp_t axi_sba_resp;
|
||||
|
||||
// debug module
|
||||
dm_top #(
|
||||
// current implementation only supports 1 hart
|
||||
|
@ -182,8 +185,9 @@ module ariane_testharness #(
|
|||
.dmactive_o ( ), // active debug session
|
||||
.debug_req_o ( debug_req_core ),
|
||||
.unavailable_i ( '0 ),
|
||||
.axi_master ( slave[3] ),
|
||||
.axi_slave ( master[3] ),
|
||||
.axi_req_o ( axi_sba_req ),
|
||||
.axi_resp_i ( axi_sba_resp ),
|
||||
.dmi_rst_ni ( rst_ni ),
|
||||
.dmi_req_valid_i ( debug_req_valid ),
|
||||
.dmi_req_ready_o ( debug_req_ready ),
|
||||
|
@ -193,6 +197,9 @@ module ariane_testharness #(
|
|||
.dmi_resp_o ( debug_resp )
|
||||
);
|
||||
|
||||
axi_connect i_axi_connect_sba (.axi_req_i(axi_sba_req), .axi_resp_o(axi_sba_resp), .master(slave[1]));
|
||||
|
||||
|
||||
// ---------------
|
||||
// ROM
|
||||
// ---------------
|
||||
|
@ -311,10 +318,11 @@ module ariane_testharness #(
|
|||
// ---------------
|
||||
// Core
|
||||
// ---------------
|
||||
ariane_axi::req_t axi_ariane_req;
|
||||
ariane_axi::resp_t axi_ariane_resp;
|
||||
|
||||
ariane #(
|
||||
.CACHE_START_ADDR ( CACHE_START_ADDR ),
|
||||
.AXI_ID_WIDTH ( AXI_ID_WIDTH ),
|
||||
.AXI_USER_WIDTH ( AXI_USER_WIDTH )
|
||||
.CACHE_START_ADDR ( CACHE_START_ADDR )
|
||||
) i_ariane (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( ndmreset_n ),
|
||||
|
@ -324,10 +332,12 @@ module ariane_testharness #(
|
|||
.ipi_i ( ipi ),
|
||||
.time_irq_i ( timer_irq ),
|
||||
.debug_req_i ( debug_req_core ),
|
||||
.data_if ( slave[2] ),
|
||||
.bypass_if ( slave[1] ),
|
||||
.instr_if ( slave[0] )
|
||||
.axi_req_o ( axi_ariane_req ),
|
||||
.axi_resp_i ( axi_ariane_resp )
|
||||
);
|
||||
|
||||
axi_connect i_axi_connect_ariane (.axi_req_i(axi_ariane_req), .axi_resp_o(axi_ariane_resp), .master(slave[0]));
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue