mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-20 12:17:19 -04:00
[WIP] Re-worked LSU dcache interface
LSU should comply with the new LSU D$ interface as specified in the previous commits. This is WIP, larger testbench changes will be necessary. As the interface significantly diverged.
This commit is contained in:
parent
48587017ac
commit
b3b347a636
13 changed files with 279 additions and 280 deletions
|
@ -56,29 +56,29 @@ test_mem_arbiter:
|
|||
paths:
|
||||
- covhtmlreport
|
||||
|
||||
test_store_queue:
|
||||
stage: test
|
||||
before_script:
|
||||
- make build library=store_queue_lib
|
||||
script:
|
||||
- make store_queue library=store_queue_lib
|
||||
- vcover report store_queue.ucdb
|
||||
- vcover report -html store_queue.ucdb
|
||||
artifacts:
|
||||
paths:
|
||||
- covhtmlreport
|
||||
# test_store_queue:
|
||||
# stage: test
|
||||
# before_script:
|
||||
# - make build library=store_queue_lib
|
||||
# script:
|
||||
# - make store_queue library=store_queue_lib
|
||||
# - vcover report store_queue.ucdb
|
||||
# - vcover report -html store_queue.ucdb
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - covhtmlreport
|
||||
|
||||
test_lsu:
|
||||
stage: test
|
||||
before_script:
|
||||
- make build library=lsu_lib
|
||||
script:
|
||||
- make lsu library=lsu_lib
|
||||
- vcover report lsu.ucdb
|
||||
- vcover report -html lsu.ucdb
|
||||
artifacts:
|
||||
paths:
|
||||
- covhtmlreport
|
||||
# test_lsu:
|
||||
# stage: test
|
||||
# before_script:
|
||||
# - make build library=lsu_lib
|
||||
# script:
|
||||
# - make lsu library=lsu_lib
|
||||
# - vcover report lsu.ucdb
|
||||
# - vcover report -html lsu.ucdb
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - covhtmlreport
|
||||
|
||||
|
||||
pages:
|
||||
|
|
|
@ -49,12 +49,14 @@ module ariane
|
|||
input logic instr_if_data_rvalid_i,
|
||||
input logic [31:0] instr_if_data_rdata_i,
|
||||
// Data memory interface
|
||||
output logic [63:0] data_if_address_o,
|
||||
output logic [11:0] data_if_address_index_o,
|
||||
output logic [43:0] data_if_address_tag_o,
|
||||
output logic [63:0] data_if_data_wdata_o,
|
||||
output logic data_if_data_req_o,
|
||||
output logic data_if_data_we_o,
|
||||
output logic [7:0] data_if_data_be_o,
|
||||
output logic [1:0] data_if_tag_status_o,
|
||||
output logic data_if_kill_req_o,
|
||||
output logic data_if_tag_valid_o,
|
||||
input logic data_if_data_gnt_i,
|
||||
input logic data_if_data_rvalid_i,
|
||||
input logic [63:0] data_if_data_rdata_i,
|
||||
|
|
|
@ -28,7 +28,7 @@ import ariane_pkg::*;
|
|||
`define NOT_IMPL 2'b11
|
||||
|
||||
|
||||
module mem_arbiter #(
|
||||
module dcache_arbiter #(
|
||||
parameter int NR_PORTS = 3
|
||||
)
|
||||
(
|
||||
|
@ -36,22 +36,26 @@ module mem_arbiter #(
|
|||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic flush_i,
|
||||
// slave port
|
||||
output logic [63:0] address_o,
|
||||
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 [1:0] data_tag_status_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][63:0] address_i,
|
||||
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][1:0] data_tag_status_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
|
||||
|
@ -59,7 +63,7 @@ module mem_arbiter #(
|
|||
// one-hot encoded
|
||||
localparam DATA_WIDTH = NR_PORTS;
|
||||
// registers
|
||||
enum logic [1:0] {IDLE, WAIT_GNT, WAIT_TAG, WAIT_FLUSH} CS, NS;
|
||||
enum logic {IDLE, WAIT_FLUSH} CS, NS;
|
||||
// remember the request port in case of a multi-cycle transaction
|
||||
logic [DATA_WIDTH-1:0] request_port_n, request_port_q;
|
||||
// local ports
|
||||
|
@ -123,90 +127,19 @@ module mem_arbiter #(
|
|||
// save the request port for future states
|
||||
request_port_n = i;
|
||||
request_index = i;
|
||||
// default is that we are waiting for the grant
|
||||
NS = WAIT_GNT;
|
||||
// wait for the grant
|
||||
if (data_gnt_i) begin
|
||||
// set the slave on which we are waiting
|
||||
in_data = 1'b1 << i[DATA_WIDTH-1:0];
|
||||
push = 1'b1;
|
||||
// we got a grant so we need to wait for the tag
|
||||
NS = WAIT_TAG;
|
||||
end
|
||||
// we already got a valid translation so we can proceed normally
|
||||
// from the request side the thing is over
|
||||
if (data_tag_status_i[i] == `VALID_TRANSLATION)
|
||||
NS = IDLE;
|
||||
|
||||
break; // break here as this is a priority select
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
// ----------------------------
|
||||
// Multi-cycle memory requests
|
||||
// ----------------------------
|
||||
// do we have an outstanding request e.g.: a request which is waiting for a grant or a tag_valid
|
||||
// here we need to wait for the grant
|
||||
WAIT_GNT: begin
|
||||
// keep the request stable
|
||||
data_req_o = data_req_i[request_port_q];
|
||||
// we can check for it since we only stay in this state if didn't yet receive a grant
|
||||
if (data_gnt_i) begin
|
||||
// set the slave on which we are waiting
|
||||
in_data = 1'b1 << request_port_q;
|
||||
push = 1'b1;
|
||||
// default is that we are waiting for the tag to be there
|
||||
// if we are waiting for the tag we can't accept any new instructions
|
||||
NS = WAIT_TAG;
|
||||
// two possibilities to not go into the tag wait state
|
||||
// 1. The tag is valid now
|
||||
// 2. The tag has been aborted
|
||||
if (data_tag_status_i[request_port_q] == `ABORT_TRANSLATION || data_tag_status_i[request_port_q] == `VALID_TRANSLATION) begin
|
||||
NS = IDLE;
|
||||
end
|
||||
end
|
||||
// or if the request vanished we are going back to idle
|
||||
if (!data_req_i[request_port_q])
|
||||
NS = IDLE;
|
||||
|
||||
end
|
||||
// here we are waiting for a valid (or aborted) tag
|
||||
WAIT_TAG: begin
|
||||
// if we are waiting for the tag we can't issue a new request
|
||||
if (data_tag_status_i[request_port_q] == `ABORT_TRANSLATION || data_tag_status_i[request_port_q] == `VALID_TRANSLATION) begin
|
||||
NS = IDLE;
|
||||
// if we got a valid tag we can make a new request under the same assumption as in the IDLE state
|
||||
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;
|
||||
// default is that we are waiting for the grant
|
||||
NS = WAIT_GNT;
|
||||
// wait for the grant
|
||||
if (data_gnt_i) begin
|
||||
// set the slave on which we are waiting
|
||||
in_data = i[DATA_WIDTH-1:0];
|
||||
push = 1'b1;
|
||||
// we got a grant so we need to wait for the tag
|
||||
NS = WAIT_TAG;
|
||||
end
|
||||
// we already got a valid translation so we can proceed normally
|
||||
// from the request side the thing is over
|
||||
if (data_tag_status_i[i] == `VALID_TRANSLATION)
|
||||
NS = IDLE;
|
||||
break; // break here as this is a priority select
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
// the FIFO is full so go to IDLE and wait for it
|
||||
NS = IDLE;
|
||||
end
|
||||
end
|
||||
end
|
||||
// ----------------------------
|
||||
// Flush logic
|
||||
// ----------------------------
|
||||
// here we are waiting for the FIFO to drain until we are ready to accept new requests
|
||||
|
@ -218,12 +151,15 @@ module mem_arbiter #(
|
|||
default : /* default */;
|
||||
endcase
|
||||
// pass through all signals from the correct slave port
|
||||
address_o = address_i[request_index];
|
||||
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_tag_status_o = data_tag_status_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];
|
||||
|
||||
// if we got a flush and we are not ready for the flush wait and for it and don't accept any incoming data
|
||||
// e.g.: jump to the flush wait state
|
||||
|
@ -278,7 +214,7 @@ module mem_arbiter #(
|
|||
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)) )
|
||||
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
|
|
@ -85,12 +85,14 @@ module ex_stage #(
|
|||
input logic instr_if_data_rvalid_i,
|
||||
input logic [31:0] instr_if_data_rdata_i,
|
||||
|
||||
output logic [63:0] data_if_address_o,
|
||||
output logic [11:0] data_if_address_index_o,
|
||||
output logic [43:0] data_if_address_tag_o,
|
||||
output logic [63:0] data_if_data_wdata_o,
|
||||
output logic data_if_data_req_o,
|
||||
output logic data_if_data_we_o,
|
||||
output logic [7:0] data_if_data_be_o,
|
||||
output logic [1:0] data_if_tag_status_o,
|
||||
output logic data_if_kill_req_o,
|
||||
output logic data_if_tag_valid_o,
|
||||
input logic data_if_data_gnt_i,
|
||||
input logic data_if_data_rvalid_i,
|
||||
input logic [63:0] data_if_data_rdata_i,
|
||||
|
|
|
@ -47,48 +47,57 @@ module load_unit (
|
|||
output logic [63:0] vaddr_o, // virtual address out
|
||||
input logic [63:0] paddr_i, // physical address in
|
||||
input logic translation_valid_i,
|
||||
input exception ex_i,
|
||||
input exception ex_i, // exception which may has happened earlier. for example: mis-aligned exception
|
||||
// address checker
|
||||
output logic [11:0] page_offset_o,
|
||||
input logic page_offset_matches_i,
|
||||
// memory interface
|
||||
output logic [63:0] address_o,
|
||||
// D$ interface
|
||||
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 [1:0] data_tag_status_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
|
||||
);
|
||||
enum logic [2:0] {IDLE, WAIT_GNT, SEND_TAG, ABORT_TRANSLATION, WAIT_FLUSH} NS, CS;
|
||||
|
||||
// in order to decouple the response interface from the request interface we need a
|
||||
// a queue which can hold all outstanding memory requests
|
||||
typedef struct packed {
|
||||
logic [TRANS_ID_BITS-1:0] trans_id;
|
||||
logic [2:0] address_offset;
|
||||
fu_t operator;
|
||||
} rvalid_entry_t;
|
||||
|
||||
// queue control signal
|
||||
rvalid_entry_t in_data;
|
||||
logic push;
|
||||
rvalid_entry_t out_data;
|
||||
logic pop;
|
||||
logic empty;
|
||||
|
||||
// register to save the physical address after address translation
|
||||
// going directly to memory with this address will not work in-terms of timing (e.g.: the path to the memory
|
||||
// is already super-critical with the address checker and memory arbiter on it).
|
||||
logic [63:0] paddr_n, paddr_q;
|
||||
// page offset is defined as the lower 12 bits
|
||||
// page offset is defined as the lower 12 bits, feed through for address checker
|
||||
assign page_offset_o = vaddr_i[11:0];
|
||||
// feed-through the virtual address
|
||||
// feed-through the virtual address for VA translation
|
||||
assign vaddr_o = vaddr_i;
|
||||
// this is a read-only interface so set the write enable to 0
|
||||
assign data_we_o = 1'b0;
|
||||
// compose the queue data, control is handled in the FSM
|
||||
assign in_data = {trans_id_i, vaddr_i[2:0], operator_i};
|
||||
|
||||
// output address
|
||||
// we can now output the lower 12 bit as the index to the cache
|
||||
assign address_o [11:0] = vaddr_i[11:0];
|
||||
// translation from last cycle
|
||||
assign address_o[63:12] = paddr_q[63:12];
|
||||
assign address_index_o = vaddr_i[11:0];
|
||||
// translation from last cycle, again: control is handled in the FSM
|
||||
assign address_tag_o = paddr_q[55:12];
|
||||
|
||||
// ---------------
|
||||
// Load Control
|
||||
// ---------------
|
||||
|
@ -99,7 +108,9 @@ module load_unit (
|
|||
translation_req_o = 1'b0;
|
||||
ready_o = 1'b1;
|
||||
data_req_o = 1'b0;
|
||||
data_tag_status_o = `WAIT_TRANSLATION;
|
||||
// tag control
|
||||
kill_req_o = 1'b0;
|
||||
tag_valid_o = 1'b0;
|
||||
push = 1'b0;
|
||||
data_be_o = be_i;
|
||||
ex_o = ex_i;
|
||||
|
@ -141,16 +152,20 @@ module load_unit (
|
|||
end
|
||||
end
|
||||
end
|
||||
// we are here because of a TLB miss
|
||||
// we are here because of a TLB miss, we need to abort the current request and give way for the
|
||||
// PTW walker to satisfy the TLB miss
|
||||
ABORT_TRANSLATION: begin
|
||||
// we are not ready here
|
||||
ready_o = 1'b0;
|
||||
// send an abort signal
|
||||
data_tag_status_o = `ABORT_TRANSLATION;
|
||||
tag_valid_o = 1'b1;
|
||||
kill_req_o = 1'b1;
|
||||
// wait for the translation to become valid and redo the request
|
||||
if (translation_valid_i) begin
|
||||
// we have a valid translation so tell the cache it should wait for it on the next cycle
|
||||
data_tag_status_o = `WAIT_TRANSLATION;
|
||||
// reset the the kill request
|
||||
tag_valid_o = 1'b0;
|
||||
kill_req_o = 1'b0;
|
||||
// if the request is still here, do the load
|
||||
if (valid_i) begin
|
||||
|
||||
|
@ -190,9 +205,10 @@ module load_unit (
|
|||
end
|
||||
|
||||
SEND_TAG: begin
|
||||
ready_o = 1'b1;
|
||||
ready_o = 1'b1;
|
||||
// tell the cache that this tag is valid
|
||||
tag_valid_o = 1'b1;
|
||||
// if we are sending our tag we are able to process a new request
|
||||
data_tag_status_o = `VALID_TRANSLATION;
|
||||
// -------------
|
||||
// New Request
|
||||
// -------------
|
||||
|
|
92
src/lsu.sv
92
src/lsu.sv
|
@ -59,13 +59,15 @@ module lsu #(
|
|||
input logic instr_if_data_gnt_i,
|
||||
input logic instr_if_data_rvalid_i,
|
||||
input logic [31:0] instr_if_data_rdata_i,
|
||||
// Data memory/cache
|
||||
output logic [63:0] data_if_address_o,
|
||||
// Data cache
|
||||
output logic [11:0] data_if_address_index_o,
|
||||
output logic [43:0] data_if_address_tag_o,
|
||||
output logic [63:0] data_if_data_wdata_o,
|
||||
output logic data_if_data_req_o,
|
||||
output logic data_if_data_we_o,
|
||||
output logic [7:0] data_if_data_be_o,
|
||||
output logic [1:0] data_if_tag_status_o,
|
||||
output logic data_if_kill_req_o,
|
||||
output logic data_if_tag_valid_o,
|
||||
input logic data_if_data_gnt_i,
|
||||
input logic data_if_data_rvalid_i,
|
||||
input logic [63:0] data_if_data_rdata_i,
|
||||
|
@ -131,40 +133,47 @@ module lsu #(
|
|||
// ---------------
|
||||
// Memory Arbiter
|
||||
// ---------------
|
||||
logic [2:0][63:0] address_i;
|
||||
logic [2:0][11:0] address_index_i;
|
||||
logic [2:0][43:0] address_tag_i;
|
||||
logic [2:0][63:0] data_wdata_i;
|
||||
logic [2:0] data_req_i;
|
||||
logic [2:0] data_we_i;
|
||||
logic [2:0] kill_req_i;
|
||||
logic [2:0] tag_valid_i;
|
||||
logic [2:0][7:0] data_be_i;
|
||||
logic [2:0][1:0] data_tag_status_i;
|
||||
logic [2:0] data_gnt_o;
|
||||
logic [2:0] data_rvalid_o;
|
||||
logic [2:0][63:0] data_rdata_o;
|
||||
|
||||
// decreasing priority
|
||||
// Port 0: PTW
|
||||
// Port 1: Load Unit
|
||||
// Port 2: Store Unit
|
||||
mem_arbiter mem_arbiter_i (
|
||||
dcache_arbiter dcache_arbiter_i (
|
||||
// to D$
|
||||
.address_o ( data_if_address_o ),
|
||||
.data_wdata_o ( data_if_data_wdata_o ),
|
||||
.data_req_o ( data_if_data_req_o ),
|
||||
.data_we_o ( data_if_data_we_o ),
|
||||
.data_be_o ( data_if_data_be_o ),
|
||||
.data_tag_status_o ( data_if_tag_status_o ),
|
||||
.data_gnt_i ( data_if_data_gnt_i ),
|
||||
.data_rvalid_i ( data_if_data_rvalid_i ),
|
||||
.data_rdata_i ( data_if_data_rdata_i ),
|
||||
.address_index_o ( data_if_address_index_o ),
|
||||
.address_tag_o ( data_if_address_tag_o ),
|
||||
.data_wdata_o ( data_if_data_wdata_o ),
|
||||
.data_req_o ( data_if_data_req_o ),
|
||||
.data_we_o ( data_if_data_we_o ),
|
||||
.data_be_o ( data_if_data_be_o ),
|
||||
.kill_req_o ( data_if_kill_req_o ),
|
||||
.tag_valid_o ( data_if_tag_valid_o ),
|
||||
.data_gnt_i ( data_if_data_gnt_i ),
|
||||
.data_rvalid_i ( data_if_data_rvalid_i ),
|
||||
.data_rdata_i ( data_if_data_rdata_i ),
|
||||
// from PTW, Load Unit and Store Unit
|
||||
.address_i ( address_i ),
|
||||
.data_wdata_i ( data_wdata_i ),
|
||||
.data_req_i ( data_req_i ),
|
||||
.data_we_i ( data_we_i ),
|
||||
.data_be_i ( data_be_i ),
|
||||
.data_tag_status_i ( data_tag_status_i ),
|
||||
.data_gnt_o ( data_gnt_o ),
|
||||
.data_rvalid_o ( data_rvalid_o ),
|
||||
.data_rdata_o ( data_rdata_o ),
|
||||
.address_index_i ( address_index_i ),
|
||||
.address_tag_i ( address_tag_i ),
|
||||
.data_wdata_i ( data_wdata_i ),
|
||||
.data_req_i ( data_req_i ),
|
||||
.data_we_i ( data_we_i ),
|
||||
.data_be_i ( data_be_i ),
|
||||
.kill_req_i ( kill_req_i ),
|
||||
.tag_valid_i ( tag_valid_i ),
|
||||
.data_gnt_o ( data_gnt_o ),
|
||||
.data_rvalid_o ( data_rvalid_o ),
|
||||
.data_rdata_o ( data_rdata_o ),
|
||||
.*
|
||||
);
|
||||
|
||||
|
@ -182,15 +191,17 @@ module lsu #(
|
|||
.lsu_paddr_o ( mmu_paddr ),
|
||||
.lsu_exception_o ( mmu_exception ),
|
||||
// connecting PTW to D$ IF (aka mem arbiter
|
||||
.data_if_address_o ( address_i [0] ),
|
||||
.data_if_data_wdata_o ( data_wdata_i [0] ),
|
||||
.data_if_data_req_o ( data_req_i [0] ),
|
||||
.data_if_data_we_o ( data_we_i [0] ),
|
||||
.data_if_data_be_o ( data_be_i [0] ),
|
||||
.data_if_tag_status_o ( data_tag_status_i[0] ),
|
||||
.data_if_data_gnt_i ( data_gnt_o [0] ),
|
||||
.data_if_data_rvalid_i ( data_rvalid_o [0] ),
|
||||
.data_if_data_rdata_i ( data_rdata_o [0] ),
|
||||
.data_if_address_index_o ( address_index_i [0] ),
|
||||
.data_if_address_tag_o ( address_tag_i [0] ),
|
||||
.data_if_data_wdata_o ( data_wdata_i [0] ),
|
||||
.data_if_data_req_o ( data_req_i [0] ),
|
||||
.data_if_data_we_o ( data_we_i [0] ),
|
||||
.data_if_data_be_o ( data_be_i [0] ),
|
||||
.data_if_kill_req_o ( kill_req_i [0] ),
|
||||
.data_if_tag_valid_o ( tag_valid_i [0] ),
|
||||
.data_if_data_gnt_i ( data_gnt_o [0] ),
|
||||
.data_if_data_rvalid_i ( data_rvalid_o [0] ),
|
||||
.data_if_data_rdata_i ( data_rdata_o [0] ),
|
||||
.*
|
||||
);
|
||||
// ------------------
|
||||
|
@ -219,13 +230,15 @@ module lsu #(
|
|||
.page_offset_matches_o ( page_offset_matches ),
|
||||
// misaligned bypass
|
||||
.misaligned_ex_i ( misaligned_exception ),
|
||||
// Mem Arbiter
|
||||
.address_o ( address_i [2] ),
|
||||
// to memory arbiter
|
||||
.address_index_o ( address_index_i [2] ),
|
||||
.address_tag_o ( address_tag_i [2] ),
|
||||
.data_wdata_o ( data_wdata_i [2] ),
|
||||
.data_req_o ( data_req_i [2] ),
|
||||
.data_we_o ( data_we_i [2] ),
|
||||
.data_be_o ( data_be_i [2] ),
|
||||
.data_tag_status_o ( data_tag_status_i[2] ),
|
||||
.kill_req_o ( kill_req_i [2] ),
|
||||
.tag_valid_o ( tag_valid_i [2] ),
|
||||
.data_gnt_i ( data_gnt_o [2] ),
|
||||
.data_rvalid_i ( data_rvalid_o [2] ),
|
||||
.*
|
||||
|
@ -254,12 +267,15 @@ module lsu #(
|
|||
// to store unit
|
||||
.page_offset_o ( page_offset ),
|
||||
.page_offset_matches_i ( page_offset_matches ),
|
||||
.address_o ( address_i [1] ),
|
||||
// to memory arbiter
|
||||
.address_index_o ( address_index_i [1] ),
|
||||
.address_tag_o ( address_tag_i [1] ),
|
||||
.data_wdata_o ( data_wdata_i [1] ),
|
||||
.data_req_o ( data_req_i [1] ),
|
||||
.data_we_o ( data_we_i [1] ),
|
||||
.data_be_o ( data_be_i [1] ),
|
||||
.data_tag_status_o ( data_tag_status_i[1] ),
|
||||
.kill_req_o ( kill_req_i [1] ),
|
||||
.tag_valid_o ( tag_valid_i [1] ),
|
||||
.data_gnt_i ( data_gnt_o [1] ),
|
||||
.data_rvalid_i ( data_rvalid_o [1] ),
|
||||
.data_rdata_i ( data_rdata_o [1] ),
|
||||
|
|
28
src/mmu.sv
28
src/mmu.sv
|
@ -23,8 +23,8 @@ import ariane_pkg::*;
|
|||
|
||||
module mmu #(
|
||||
parameter int INSTR_TLB_ENTRIES = 4,
|
||||
parameter int DATA_TLB_ENTRIES = 4,
|
||||
parameter int ASID_WIDTH = 1
|
||||
parameter int DATA_TLB_ENTRIES = 4,
|
||||
parameter int ASID_WIDTH = 1
|
||||
)
|
||||
(
|
||||
input logic clk_i,
|
||||
|
@ -63,12 +63,14 @@ module mmu #(
|
|||
input logic instr_if_data_rvalid_i,
|
||||
input logic [31:0] instr_if_data_rdata_i,
|
||||
// Data memory/cache
|
||||
output logic [63:0] data_if_address_o,
|
||||
output logic [11:0] data_if_address_index_o,
|
||||
output logic [43:0] data_if_address_tag_o,
|
||||
output logic [63:0] data_if_data_wdata_o,
|
||||
output logic data_if_data_req_o,
|
||||
output logic data_if_data_we_o,
|
||||
output logic [7:0] data_if_data_be_o,
|
||||
output logic [1:0] data_if_tag_status_o,
|
||||
output logic data_if_kill_req_o,
|
||||
output logic data_if_tag_valid_o,
|
||||
input logic data_if_data_gnt_i,
|
||||
input logic data_if_data_rvalid_i,
|
||||
input logic [63:0] data_if_data_rdata_i
|
||||
|
@ -169,15 +171,15 @@ module mmu #(
|
|||
.ptw_error_o ( ptw_error ),
|
||||
.enable_translation_i ( enable_translation_i ),
|
||||
|
||||
.address_o ( data_if_address_o ),
|
||||
.data_wdata_o ( data_if_data_wdata_o ),
|
||||
.data_req_o ( data_if_data_req_o ),
|
||||
.data_we_o ( data_if_data_we_o ),
|
||||
.data_be_o ( data_if_data_be_o ),
|
||||
.data_tag_status_o ( data_if_tag_status_o ),
|
||||
.data_gnt_i ( data_if_data_gnt_i ),
|
||||
.data_rvalid_i ( data_if_data_rvalid_i ),
|
||||
.data_rdata_i ( data_if_data_rdata_i ),
|
||||
.address_o ( ), // TODO
|
||||
.data_wdata_o ( ), // TODO
|
||||
.data_req_o ( ), // TODO
|
||||
.data_we_o ( ), // TODO
|
||||
.data_be_o ( ), // TODO
|
||||
.data_tag_status_o ( ), // TODO
|
||||
.data_gnt_i ( ), // TODO
|
||||
.data_rvalid_i ( ), // TODO
|
||||
.data_rdata_i ( ), // TODO
|
||||
|
||||
.itlb_update_o ( itlb_update ),
|
||||
.dtlb_update_o ( dtlb_update ),
|
||||
|
|
|
@ -38,24 +38,30 @@ module store_queue (
|
|||
input logic [63:0] paddr_i, // physical address of store which needs to be placed in the queue
|
||||
input logic [63:0] data_i, // data which is placed in the queue
|
||||
input logic [7:0] be_i, // byte enable in
|
||||
|
||||
// D$ interface
|
||||
output logic [63:0] address_o,
|
||||
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 [1:0] data_tag_status_o,
|
||||
output logic kill_req_o,
|
||||
output logic tag_valid_o,
|
||||
input logic data_gnt_i,
|
||||
input logic data_rvalid_i
|
||||
);
|
||||
// we need to keep the tag portion of the address for a cycle later
|
||||
logic [43:0] address_tag_n, address_tag_q;
|
||||
logic tag_valid_n, tag_valid_q;
|
||||
|
||||
// the store queue has two parts:
|
||||
// 1. Speculative queue
|
||||
// 2. Commit queue which is non-speculative, e.g.: the store will definitely happen.
|
||||
// For simplicity reasons we just keep those two elements and not one real queue
|
||||
// should it turn out that this bottlenecks we can still increase the capacity here
|
||||
// potentially at the cost of increased area.
|
||||
// at the cost of increased area and worse timing since we need to check all addresses which are committed for
|
||||
// potential aliasing.
|
||||
//
|
||||
// In the current implementation this is represented by a single entry and
|
||||
// differentiated by the is_speculative flag.
|
||||
|
||||
|
@ -73,11 +79,17 @@ module store_queue (
|
|||
assign be_o = commit_queue_q.be;
|
||||
assign valid_o = commit_queue_q.valid;
|
||||
|
||||
// those signals can directly be output to the memory if
|
||||
assign address_o = commit_queue_q.address;
|
||||
// those signals can directly be output to the memory
|
||||
assign address_index_o = commit_queue_q.address[11:0];
|
||||
// if we got a new request we already saved the tag from the previous cycle
|
||||
assign address_tag_o = address_tag_q;
|
||||
assign data_wdata_o = commit_queue_q.data;
|
||||
assign data_be_o = commit_queue_q.be;
|
||||
assign data_tag_status_o = 2'b01; // the tag is always ready since we are using physical addresses
|
||||
assign tag_valid_o = tag_valid_q;
|
||||
// we will never kill a request in the store buffer since we already know that the translation is valid
|
||||
// e.g.: a kill request will only be necessary if we are not sure if the requested memory address will result in a TLB fault
|
||||
assign kill_req_o = 1'b0;
|
||||
|
||||
// memory interface
|
||||
always_comb begin : store_if
|
||||
// if there is no commit pending and the uncommitted queue is empty as well we can accept the request
|
||||
|
@ -86,7 +98,9 @@ module store_queue (
|
|||
automatic logic ready = ~commit_queue_q.valid | data_gnt_i;
|
||||
ready_o = ready & ~flush_i;
|
||||
|
||||
address_tag_n = address_tag_q;
|
||||
commit_queue_n = commit_queue_q;
|
||||
tag_valid_n = 1'b0;
|
||||
|
||||
data_we_o = 1'b1; // we will always write in the store queue
|
||||
data_req_o = 1'b0;
|
||||
|
@ -99,10 +113,13 @@ module store_queue (
|
|||
// by looking at the is_speculative flag
|
||||
if (commit_queue_q.valid && (~commit_queue_q.is_speculative || commit_i)) begin
|
||||
data_req_o = 1'b1;
|
||||
// advance to the next state if we received the grant
|
||||
if (data_gnt_i) begin
|
||||
// we can evict it from the commit buffer
|
||||
commit_queue_n.valid = 1'b0;
|
||||
// save the tag portion
|
||||
address_tag_n = commit_queue_q.address[55:12];
|
||||
// signal a valid tag the cycle afterwards
|
||||
tag_valid_n = 1'b1;
|
||||
end
|
||||
end
|
||||
// we ignore the rvalid signal for now as we assume that the store
|
||||
|
@ -135,9 +152,13 @@ module store_queue (
|
|||
// registers
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_
|
||||
if(~rst_ni) begin
|
||||
commit_queue_q <= '{default: 0};
|
||||
address_tag_q <= 'b0;
|
||||
tag_valid_q <= 1'b0;
|
||||
commit_queue_q <= '{default: 0};
|
||||
end else begin
|
||||
commit_queue_q <= commit_queue_n;
|
||||
tag_valid_q <= tag_valid_n;
|
||||
address_tag_q <= address_tag_n;
|
||||
end
|
||||
end
|
||||
`ifndef SYNTHESIS
|
||||
|
|
|
@ -47,13 +47,15 @@ module store_unit (
|
|||
output logic page_offset_matches_o,
|
||||
// misaligned bypass
|
||||
input exception misaligned_ex_i,
|
||||
// memory interface
|
||||
output logic [63:0] address_o,
|
||||
// D$ interface
|
||||
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 [1:0] data_tag_status_o,
|
||||
output logic kill_req_o,
|
||||
output logic tag_valid_o,
|
||||
input logic data_gnt_i,
|
||||
input logic data_rvalid_i
|
||||
);
|
||||
|
|
|
@ -40,16 +40,16 @@ module core_mem (
|
|||
output logic [63:0] data_if_data_rdata_o
|
||||
);
|
||||
// we always grant the access
|
||||
assign instr_if_data_gnt_o = instr_if_data_req_i;
|
||||
localparam ADDRESS_WIDTH = 11;
|
||||
|
||||
logic [ADDRESS_WIDTH-1:0] instr_address;
|
||||
logic [ADDRESS_WIDTH-1:0] data_address;
|
||||
logic [2:0] instr_address_offset_q;
|
||||
logic [63:0] instr_data;
|
||||
|
||||
assign instr_address = instr_if_address_i[ADDRESS_WIDTH-1+3:3];
|
||||
|
||||
logic [63:0] instr_data;
|
||||
|
||||
assign instr_if_data_gnt_o = instr_if_data_req_i;
|
||||
assign instr_address = instr_if_address_i[ADDRESS_WIDTH-1+3:3];
|
||||
assign instr_if_data_rdata_o = (instr_address_offset_q[2]) ? instr_data[63:32] : instr_data[31:0];
|
||||
|
||||
dp_ram #(
|
||||
|
@ -63,12 +63,13 @@ module core_mem (
|
|||
.rdata_a_o ( instr_data ),
|
||||
.we_a_i ( 1'b0 ), // r/o interface
|
||||
.be_a_i ( ),
|
||||
// data RAM
|
||||
.en_b_i ( ),
|
||||
.addr_b_i ( ),
|
||||
.wdata_b_i ( ),
|
||||
.rdata_b_o ( ),
|
||||
.we_b_i ( ),
|
||||
.be_b_i ( )
|
||||
.we_b_i ( data_if_data_we_i ),
|
||||
.be_b_i ( data_if_data_be_i )
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -60,50 +60,52 @@ module core_tb;
|
|||
);
|
||||
|
||||
ariane dut (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.clock_en_i ( core_if.clock_en ),
|
||||
.test_en_i ( core_if.test_en ),
|
||||
.fetch_enable_i ( core_if.fetch_enable ),
|
||||
.core_busy_o ( core_if.core_busy ),
|
||||
.ext_perf_counters_i ( ),
|
||||
.boot_addr_i ( core_if.boot_addr ),
|
||||
.core_id_i ( core_if.core_id ),
|
||||
.cluster_id_i ( core_if.cluster_id ),
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.clock_en_i ( core_if.clock_en ),
|
||||
.test_en_i ( core_if.test_en ),
|
||||
.fetch_enable_i ( core_if.fetch_enable ),
|
||||
.core_busy_o ( core_if.core_busy ),
|
||||
.ext_perf_counters_i ( ),
|
||||
.boot_addr_i ( core_if.boot_addr ),
|
||||
.core_id_i ( core_if.core_id ),
|
||||
.cluster_id_i ( core_if.cluster_id ),
|
||||
|
||||
.instr_if_address_o ( instr_if_address ),
|
||||
.instr_if_data_req_o ( instr_if_data_req ),
|
||||
.instr_if_data_be_o ( instr_if_data_be ),
|
||||
.instr_if_data_gnt_i ( instr_if_data_gnt ),
|
||||
.instr_if_data_rvalid_i ( instr_if_data_rvalid ),
|
||||
.instr_if_data_rdata_i ( instr_if_data_rdata ),
|
||||
.instr_if_address_o ( instr_if_address ),
|
||||
.instr_if_data_req_o ( instr_if_data_req ),
|
||||
.instr_if_data_be_o ( instr_if_data_be ),
|
||||
.instr_if_data_gnt_i ( instr_if_data_gnt ),
|
||||
.instr_if_data_rvalid_i ( instr_if_data_rvalid ),
|
||||
.instr_if_data_rdata_i ( instr_if_data_rdata ),
|
||||
|
||||
.data_if_address_o ( data_if.address ),
|
||||
.data_if_data_wdata_o ( data_if.data_wdata ),
|
||||
.data_if_data_req_o ( data_if.data_req ),
|
||||
.data_if_data_we_o ( data_if.data_we ),
|
||||
.data_if_data_be_o ( data_if.data_be ),
|
||||
.data_if_tag_status_o ( ),
|
||||
.data_if_data_gnt_i ( data_if.data_gnt ),
|
||||
.data_if_data_rvalid_i ( data_if.data_rvalid ),
|
||||
.data_if_data_rdata_i ( data_if.data_rdata ),
|
||||
.data_if_address_index_o ( ),
|
||||
.data_if_address_tag_o ( ),
|
||||
.data_if_data_wdata_o ( data_if.data_wdata ),
|
||||
.data_if_data_req_o ( data_if.data_req ),
|
||||
.data_if_data_we_o ( data_if.data_we ),
|
||||
.data_if_data_be_o ( data_if.data_be ),
|
||||
.data_if_kill_req_o ( ),
|
||||
.data_if_tag_valid_o ( ),
|
||||
.data_if_data_gnt_i ( data_if.data_gnt ),
|
||||
.data_if_data_rvalid_i ( data_if.data_rvalid ),
|
||||
.data_if_data_rdata_i ( data_if.data_rdata ),
|
||||
|
||||
.irq_i ( core_if.irq ),
|
||||
.irq_id_i ( core_if.irq_id ),
|
||||
.irq_ack_o ( core_if.irq_ack ),
|
||||
.irq_sec_i ( core_if.irq_sec ),
|
||||
.sec_lvl_o ( core_if.sec_lvl ),
|
||||
.irq_i ( core_if.irq ),
|
||||
.irq_id_i ( core_if.irq_id ),
|
||||
.irq_ack_o ( core_if.irq_ack ),
|
||||
.irq_sec_i ( core_if.irq_sec ),
|
||||
.sec_lvl_o ( core_if.sec_lvl ),
|
||||
|
||||
.debug_req_i ( ),
|
||||
.debug_gnt_o ( ),
|
||||
.debug_rvalid_o ( ),
|
||||
.debug_addr_i ( ),
|
||||
.debug_we_i ( ),
|
||||
.debug_wdata_i ( ),
|
||||
.debug_rdata_o ( ),
|
||||
.debug_halted_o ( ),
|
||||
.debug_halt_i ( ),
|
||||
.debug_resume_i ( )
|
||||
.debug_req_i ( ),
|
||||
.debug_gnt_o ( ),
|
||||
.debug_rvalid_o ( ),
|
||||
.debug_addr_i ( ),
|
||||
.debug_we_i ( ),
|
||||
.debug_wdata_i ( ),
|
||||
.debug_rdata_o ( ),
|
||||
.debug_halted_o ( ),
|
||||
.debug_halt_i ( ),
|
||||
.debug_resume_i ( )
|
||||
);
|
||||
|
||||
// clock process
|
||||
|
@ -123,6 +125,7 @@ module core_tb;
|
|||
$display("Reading memory");
|
||||
$readmemh("test/add_test.v", rmem, 0);
|
||||
|
||||
// copy bitwise from verilog file
|
||||
for (int i = 0; i < 1024/8; i++) begin
|
||||
for (int j = 0; j < 8; j++)
|
||||
core_mem_i.ram_i.mem[i][j] = rmem[i*8 + j];
|
||||
|
|
84
tb/lsu_tb.sv
84
tb/lsu_tb.sv
|
@ -32,53 +32,53 @@ module lsu_tb;
|
|||
lsu_if lsu(clk);
|
||||
|
||||
lsu dut (
|
||||
.clk_i ( clk ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( 1'b0 ),
|
||||
.operator_i ( lsu.operator ),
|
||||
.operand_a_i ( lsu.operand_a ),
|
||||
.operand_b_i ( lsu.operand_b ),
|
||||
.imm_i ( lsu.imm ),
|
||||
.lsu_ready_o ( lsu.ready ),
|
||||
.lsu_valid_i ( lsu.source_valid ),
|
||||
.trans_id_i ( lsu.lsu_trans_id_id ),
|
||||
.lsu_trans_id_o ( lsu.lsu_trans_id_wb ),
|
||||
.lsu_result_o ( lsu.result ),
|
||||
.lsu_valid_o ( lsu.result_valid ),
|
||||
.commit_i ( lsu.commit ),
|
||||
.clk_i ( clk ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( 1'b0 ),
|
||||
.operator_i ( lsu.operator ),
|
||||
.operand_a_i ( lsu.operand_a ),
|
||||
.operand_b_i ( lsu.operand_b ),
|
||||
.imm_i ( lsu.imm ),
|
||||
.lsu_ready_o ( lsu.ready ),
|
||||
.lsu_valid_i ( lsu.source_valid ),
|
||||
.trans_id_i ( lsu.lsu_trans_id_id ),
|
||||
.lsu_trans_id_o ( lsu.lsu_trans_id_wb ),
|
||||
.lsu_result_o ( lsu.result ),
|
||||
.lsu_valid_o ( lsu.result_valid ),
|
||||
.commit_i ( lsu.commit ),
|
||||
// we are currently no testing the PTW and MMU
|
||||
.enable_translation_i ( 1'b0 ),
|
||||
.fetch_req_i ( 1'b0 ),
|
||||
.fetch_gnt_o ( ),
|
||||
.fetch_valid_o ( ),
|
||||
.fetch_err_o ( ),
|
||||
.fetch_vaddr_i ( 64'b0 ),
|
||||
.fetch_rdata_o ( ),
|
||||
.priv_lvl_i ( PRIV_LVL_M ),
|
||||
.flag_pum_i ( 1'b0 ),
|
||||
.flag_mxr_i ( 1'b0 ),
|
||||
.pd_ppn_i ( 38'b0 ),
|
||||
.asid_i ( 1'b0 ),
|
||||
.flush_tlb_i ( 1'b0 ),
|
||||
.enable_translation_i ( 1'b0 ),
|
||||
.fetch_req_i ( 1'b0 ),
|
||||
.fetch_gnt_o ( ),
|
||||
.fetch_valid_o ( ),
|
||||
.fetch_err_o ( ),
|
||||
.fetch_vaddr_i ( 64'b0 ),
|
||||
.fetch_rdata_o ( ),
|
||||
.priv_lvl_i ( PRIV_LVL_M ),
|
||||
.flag_pum_i ( 1'b0 ),
|
||||
.flag_mxr_i ( 1'b0 ),
|
||||
.pd_ppn_i ( 38'b0 ),
|
||||
.asid_i ( 1'b0 ),
|
||||
.flush_tlb_i ( 1'b0 ),
|
||||
|
||||
.instr_if_address_o ( instr_if.address ),
|
||||
.instr_if_data_req_o ( instr_if.data_req ),
|
||||
.instr_if_data_be_o ( instr_if.data_be[3:0] ),
|
||||
.instr_if_data_gnt_i ( instr_if.data_gnt ),
|
||||
.instr_if_data_rvalid_i ( instr_if.data_rvalid ),
|
||||
.instr_if_data_rdata_i ( instr_if.data_rdata[31:0] ),
|
||||
.instr_if_address_o ( instr_if.address ),
|
||||
.instr_if_data_req_o ( instr_if.data_req ),
|
||||
.instr_if_data_be_o ( instr_if.data_be[3:0] ),
|
||||
.instr_if_data_gnt_i ( instr_if.data_gnt ),
|
||||
.instr_if_data_rvalid_i ( instr_if.data_rvalid ),
|
||||
.instr_if_data_rdata_i ( instr_if.data_rdata[31:0] ),
|
||||
|
||||
.data_if_address_o ( slave.address ),
|
||||
.data_if_data_wdata_o ( slave.data_wdata ),
|
||||
.data_if_data_req_o ( slave.data_req ),
|
||||
.data_if_data_we_o ( slave.data_we ),
|
||||
.data_if_data_be_o ( slave.data_be ),
|
||||
.data_if_address_index_o ( slave.address ),
|
||||
.data_if_data_wdata_o ( slave.data_wdata ),
|
||||
.data_if_data_req_o ( slave.data_req ),
|
||||
.data_if_data_we_o ( slave.data_we ),
|
||||
.data_if_data_be_o ( slave.data_be ),
|
||||
// hack to not get a grant without a request
|
||||
.data_if_data_gnt_i ( slave.data_req & slave.data_gnt ),
|
||||
.data_if_data_rvalid_i ( slave.data_rvalid ),
|
||||
.data_if_data_rdata_i ( slave.data_rdata ),
|
||||
.data_if_data_gnt_i ( slave.data_req & slave.data_gnt ),
|
||||
.data_if_data_rvalid_i ( slave.data_rvalid ),
|
||||
.data_if_data_rdata_i ( slave.data_rdata ),
|
||||
|
||||
.lsu_exception_o ( lsu.exception )
|
||||
.lsu_exception_o ( lsu.exception )
|
||||
);
|
||||
|
||||
initial begin
|
||||
|
|
|
@ -37,27 +37,25 @@ module mem_arbiter_tb;
|
|||
// logic data_gnt_driver = 'z;
|
||||
// assign data_gnt = data_gnt_driver & data_req;
|
||||
|
||||
mem_arbiter dut (
|
||||
dcache_arbiter dut (
|
||||
.clk_i ( clk ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( 1'b0 ),
|
||||
|
||||
.address_o ( slave.address ),
|
||||
.address_index_o ( slave.address ),
|
||||
.data_wdata_o ( slave.data_wdata ),
|
||||
.data_req_o ( slave.data_req ),
|
||||
.data_we_o ( slave.data_we ),
|
||||
.data_be_o ( slave.data_be ),
|
||||
.data_tag_status_o ( ),
|
||||
.data_gnt_i ( slave.data_req & slave.data_gnt ),
|
||||
.data_rvalid_i ( slave.data_rvalid ),
|
||||
.data_rdata_i ( slave.data_rdata ),
|
||||
|
||||
.address_i ( {master[2].address, master[1].address, master[0].address} ),
|
||||
.address_index_i ( {master[2].address, master[1].address, master[0].address} ),
|
||||
.data_wdata_i ( {master[2].data_wdata, master[1].data_wdata, master[0].data_wdata} ),
|
||||
.data_req_i ( {master[2].data_req, master[1].data_req, master[0].data_req} ),
|
||||
.data_we_i ( {master[2].data_we, master[1].data_we, master[0].data_we} ),
|
||||
.data_be_i ( {master[2].data_be, master[1].data_be, master[0].data_be} ),
|
||||
.data_tag_status_i ( {2'b01, 2'b01, 2'b01 } ),
|
||||
.data_gnt_o ( {master[2].data_gnt, master[1].data_gnt, master[0].data_gnt} ),
|
||||
.data_rvalid_o ( {master[2].data_rvalid, master[1].data_rvalid, master[0].data_rvalid} ),
|
||||
.data_rdata_o ( {master[2].data_rdata, master[1].data_rdata, master[0].data_rdata} )
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue