WIP Update serpent cache subsystem AXI plugs

This commit is contained in:
Michael Schaffner 2018-10-17 18:53:04 +02:00
parent 0bd9c4fb2b
commit e5719ce34e
No known key found for this signature in database
GPG key ID: 7AA09AE049819C2C
8 changed files with 217 additions and 320 deletions

View file

@ -131,19 +131,7 @@ else
questa-cmd := -do " set StdArithNoWarnings 1; set NumericStdNoWarnings 1; log -r /*; run -all;"
endif
compile_flag_vhd += -64 -nologo -quiet -2008
<<<<<<< HEAD
=======
uvm-flags += +UVM_NO_RELNOTES +UVM_VERBOSITY=LOW
questa-flags += -t 1ns -64 -coverage -classdebug $(gui-sim)
# if defined, calls the questa targets in batch mode
ifdef batch-mode
questa-flags += -c
questa-cmd := -do "coverage save -onexit tmp/$@.ucdb; run -a; quit -code [coverage attribute -name TESTSTATUS -concise]"
else
questa-cmd := -do " log -r /*; run -all;"
endif
>>>>>>> ariane_next
# Iterate over all include directories and write them with +incdir+ prefixed
# +incdir+ works for Verilator and QuestaSim
list_incdir := $(foreach dir, ${incdir}, +incdir+$(dir))

View file

@ -394,18 +394,20 @@ package ariane_pkg;
// Atomics
// --------------------
typedef enum logic [3:0] {
AMO_NONE =4'b0000,
AMO_LR =4'b0001,
AMO_SC =4'b0010,
AMO_SWAP =4'b0011,
AMO_ADD =4'b0100,
AMO_AND =4'b0101,
AMO_OR =4'b0110,
AMO_XOR =4'b0111,
AMO_MAX =4'b1000,
AMO_MAXU =4'b1001,
AMO_MIN =4'b1010,
AMO_MINU =4'b1011
AMO_NONE =4'b0000,
AMO_LR =4'b0001,
AMO_SC =4'b0010,
AMO_SWAP =4'b0011,
AMO_ADD =4'b0100,
AMO_AND =4'b0101,
AMO_OR =4'b0110,
AMO_XOR =4'b0111,
AMO_MAX =4'b1000,
AMO_MAXU =4'b1001,
AMO_MIN =4'b1010,
AMO_MINU =4'b1011,
AMO_CAS1 =4'b1100, // unused, not part of riscv spec, but provided in OpenPiton
AMO_CAS2 =4'b1101 // unused, not part of riscv spec, but provided in OpenPiton
} amo_t;
typedef struct packed {

View file

@ -24,7 +24,7 @@ package serpent_cache_pkg;
// do not change
localparam L15_TID_WIDTH = 2;
localparam L15_TLB_CSM_WIDTH = 33;
localparam L15_WAY_WIDTH = $clog2(L15_SET_ASSOC);
localparam L1I_WAY_WIDTH = $clog2(ariane_pkg::ICACHE_SET_ASSOC);
localparam L1D_WAY_WIDTH = $clog2(ariane_pkg::DCACHE_SET_ASSOC);
@ -40,23 +40,23 @@ package serpent_cache_pkg;
localparam ICACHE_OFFSET_WIDTH = $clog2(ariane_pkg::ICACHE_LINE_WIDTH/8);
localparam ICACHE_NUM_WORDS = 2**(ariane_pkg::ICACHE_INDEX_WIDTH-ICACHE_OFFSET_WIDTH);
localparam ICACHE_CL_IDX_WIDTH = $clog2(ICACHE_NUM_WORDS);// excluding byte offset
localparam DCACHE_OFFSET_WIDTH = $clog2(ariane_pkg::DCACHE_LINE_WIDTH/8);
localparam DCACHE_NUM_WORDS = 2**(ariane_pkg::DCACHE_INDEX_WIDTH-DCACHE_OFFSET_WIDTH);
localparam DCACHE_CL_IDX_WIDTH = $clog2(DCACHE_NUM_WORDS);// excluding byte offset
localparam DCACHE_NUM_BANKS = ariane_pkg::DCACHE_LINE_WIDTH/64;
// write buffer parameterization
localparam DCACHE_WBUF_DEPTH = 8;
localparam DCACHE_MAX_TX = 4;// TODO: set to number of threads supported in
localparam DCACHE_ID_WIDTH = $clog2(DCACHE_MAX_TX);// TODO: set to number of threads supported in
localparam DCACHE_NUM_BANKS = ariane_pkg::DCACHE_LINE_WIDTH/64;
// write buffer parameterization
localparam DCACHE_WBUF_DEPTH = 8;
localparam DCACHE_MAX_TX = 2**L15_TID_WIDTH;// needs to be aligned with OpenPiton
localparam DCACHE_ID_WIDTH = $clog2(DCACHE_MAX_TX);
typedef struct packed {
logic [ariane_pkg::DCACHE_INDEX_WIDTH+ariane_pkg::DCACHE_TAG_WIDTH-1:0] wtag;
logic [63:0] data;
logic [7:0] dirty; // byte is dirty
logic [7:0] dirty; // byte is dirty
logic [7:0] valid; // byte is valid
logic [7:0] txblock; // byte is part of transaction in-flight
logic checked; // if cache state of this word has been checked
@ -66,27 +66,27 @@ package serpent_cache_pkg;
// TX status registers are indexed with the transaction ID
// they basically store which bytes from which buffer entry are part
// of that transaction
typedef struct packed {
typedef struct packed {
logic vld;
logic [7:0] be;
logic [$clog2(DCACHE_WBUF_DEPTH)-1:0] ptr;
} tx_stat_t;
// local interfaces between caches and L15 adapter
typedef enum logic [1:0] {
typedef enum logic [1:0] {
DCACHE_STORE_REQ,
DCACHE_LOAD_REQ,
DCACHE_ATOMIC_REQ,
DCACHE_INT_REQ } dcache_out_t;
typedef enum logic [2:0] {
typedef enum logic [2:0] {
DCACHE_INV_REQ, // no ack from the core required
DCACHE_STORE_ACK,// note: this may contain an invalidation vector, too
DCACHE_LOAD_ACK,
DCACHE_ATOMIC_ACK,
DCACHE_INT_ACK } dcache_in_t;
typedef enum logic [0:0] {
typedef enum logic [0:0] {
ICACHE_INV_REQ, // no ack from the core required
ICACHE_IFILL_ACK} icache_in_t;
@ -174,6 +174,8 @@ package serpent_cache_pkg;
typedef struct packed {
logic l15_val; // valid signal, asserted with request
logic l15_req_ack; // ack for response
l15_reqtypes_t l15_rqtype; // see below for encoding
logic l15_nc; // non-cacheable bit
logic [2:0] l15_size; // transaction size: 000=Byte 001=2Byte; 010=4Byte; 011=8Byte; 111=Cache line (16/32Byte)
@ -191,6 +193,9 @@ package serpent_cache_pkg;
} l15_req_t;
typedef struct packed {
logic l15_ack; // ack for request struct
logic l15_header_ack; // ack for request struct
logic l15_val; // valid signal for return struct
l15_rtrntypes_t l15_returntype; // see below for encoding
logic l15_l2miss; // unused in Ariane
logic [1:0] l15_error; // unused in openpiton
@ -225,29 +230,29 @@ package serpent_cache_pkg;
function automatic logic [ariane_pkg::ICACHE_SET_ASSOC-1:0] icache_way_bin2oh (
input logic [$clog2(ariane_pkg::ICACHE_SET_ASSOC)-1:0] in
);
);
logic [ariane_pkg::ICACHE_SET_ASSOC-1:0] out;
out = '0;
out[in] = 1'b1;
return out;
return out;
endfunction
function automatic logic [ariane_pkg::DCACHE_SET_ASSOC-1:0] dcache_way_bin2oh (
input logic [$clog2(ariane_pkg::DCACHE_SET_ASSOC)-1:0] in
);
);
logic [ariane_pkg::DCACHE_SET_ASSOC-1:0] out;
out = '0;
out[in] = 1'b1;
return out;
return out;
endfunction
function automatic logic [DCACHE_NUM_BANKS-1:0] dcache_cl_bin2oh (
input logic [$clog2(DCACHE_NUM_BANKS)-1:0] in
);
);
logic [DCACHE_NUM_BANKS-1:0] out;
out = '0;
out[in] = 1'b1;
return out;
return out;
endfunction
@ -263,16 +268,16 @@ package serpent_cache_pkg;
function automatic logic [7:0] toByteEnable8(
input logic [2:0] offset,
input logic [1:0] size
input logic [1:0] size
);
logic [7:0] be;
be = '0;
unique case(size)
2'b00: be[offset] = '1; // byte
2'b01: be[offset +:2 ] = '1; // hword
2'b10: be[offset +:4 ] = '1; // word
unique case(size)
2'b00: be[offset] = '1; // byte
2'b01: be[offset +:2 ] = '1; // hword
2'b10: be[offset +:4 ] = '1; // word
default: be = '1; // dword
endcase // size
endcase // size
return be;
endfunction : toByteEnable8
@ -280,15 +285,15 @@ package serpent_cache_pkg;
function automatic logic [63:0] repData64(
input logic [63:0] data,
input logic [2:0] offset,
input logic [1:0] size
input logic [1:0] size
);
logic [63:0] out;
unique case(size)
unique case(size)
2'b00: for(int k=0; k<8; k++) out[k*8 +: 8] = data[offset*8 +: 8]; // byte
2'b01: for(int k=0; k<4; k++) out[k*16 +: 16] = data[offset*8 +: 16]; // hword
2'b10: for(int k=0; k<2; k++) out[k*32 +: 32] = data[offset*8 +: 32]; // word
default: out = data; // dword
endcase // size
endcase // size
return out;
endfunction : repData64
@ -304,7 +309,7 @@ package serpent_cache_pkg;
8'b0000_1111, 8'b1111_0000: size = 2'b10; // word
8'b1100_0000, 8'b0011_0000, 8'b0000_1100, 8'b0000_0011: size = 2'b01; // hword
default: size = 2'b00; // individual bytes
endcase // be
endcase // be
return size;
endfunction : toSize64
@ -316,7 +321,7 @@ package serpent_cache_pkg;
// 111: DCACHE line
function automatic logic [63:0] paddrSizeAlign(
input logic [63:0] paddr,
input logic [2:0] size
input logic [2:0] size
);
logic [63:0] out;
out = paddr;
@ -324,7 +329,7 @@ package serpent_cache_pkg;
3'b001: out[0:0] = '0;
3'b010: out[1:0] = '0;
3'b011: out[2:0] = '0;
3'b111: out[DCACHE_OFFSET_WIDTH-1:0] = '0;
3'b111: out[DCACHE_OFFSET_WIDTH-1:0] = '0;
default: ;
endcase
return out;

View file

@ -44,19 +44,12 @@ module ariane #(
`ifdef AXI64_CACHE_PORTS
// memory side, AXI Master
output ariane_axi::req_t axi_req_o,
input ariane_axi::resp_t axi_resp_i,
input ariane_axi::resp_t axi_resp_i
`else
// L15 (memory side)
output logic l15_val_o,
input logic l15_ack_i,
input logic l15_header_ack_i,
output l15_req_t l15_data_o,
input logic l15_val_i,
output logic l15_req_ack_o,
input l15_rtrn_t l15_rtrn_i
// L15 (memory side)
output serpent_cache_pkg::l15_req_t l15_req_o,
input serpent_cache_pkg::l15_rtrn_t l15_rtrn_i
`endif
);
// ------------------------------------------
// Global Signals
@ -585,9 +578,6 @@ module ariane #(
`ifdef SERPENT_PULP
// this is a cache subsystem that is compatible with OpenPiton
serpent_cache_subsystem #(
`ifdef AXI64_CACHE_PORTS
.AXI_ID_WIDTH ( AXI_ID_WIDTH ),
`endif
.CACHE_START_ADDR ( CACHE_START_ADDR )
) i_cache_subsystem (
// to D$
@ -616,23 +606,16 @@ module ariane #(
.wbuffer_empty_o ( dcache_commit_wbuffer_empty ),
`ifdef AXI64_CACHE_PORTS
// 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 )
`else
.l15_val_o ( l15_val_o ),
.l15_ack_i ( l15_ack_i ),
.l15_header_ack_i ( l15_header_ack_i ),
.l15_data_o ( l15_data_o ),
.l15_val_i ( l15_val_i ),
.l15_req_ack_o ( l15_req_ack_o ),
.l15_req_o ( l15_req_o ),
.l15_rtrn_i ( l15_rtrn_i )
`endif
);
`else
std_cache_subsystem #(
.AXI_ID_WIDTH ( AXI_ID_WIDTH ),
.CACHE_START_ADDR ( CACHE_START_ADDR )
) i_cache_subsystem (
// to D$

View file

@ -17,19 +17,19 @@
// Date: 15.08.2018
// Description: Ariane cache subsystem that is compatible with the OpenPiton
// coherent memory system.
//
// Define SERPENT_PULP if you want to use this cache.
// Define AXI64_CACHE_PORTS if you want to use this cache
// with a standard 64bit AXI interace instead of the openpiton
//
// Define SERPENT_PULP if you want to use this cache.
// Define AXI64_CACHE_PORTS if you want to use this cache
// with a standard 64bit AXI interace instead of the openpiton
// L1.5 interface.
import ariane_pkg::*;
import serpent_cache_pkg::*;
module serpent_cache_subsystem #(
// `ifdef AXI64_CACHE_PORTS
// `ifdef AXI64_CACHE_PORTS
parameter int unsigned AXI_ID_WIDTH = 10,
// `endif
// `endif
parameter logic [63:0] CACHE_START_ADDR = 64'h4000_0000
)(
input logic clk_i,
@ -53,7 +53,7 @@ module serpent_cache_subsystem #(
input logic dcache_flush_i, // high until acknowledged
output logic dcache_flush_ack_o, // send a single cycle acknowledge signal when the cache is flushed
output logic dcache_miss_o, // we missed on a ld/st
// AMO interface
input amo_req_t dcache_amo_req_i,
output amo_resp_t dcache_amo_resp_o,
@ -66,21 +66,14 @@ module serpent_cache_subsystem #(
output logic wbuffer_empty_o,
`ifdef AXI64_CACHE_PORTS
// 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)
// memory side
output ariane_axi::req_t axi_req_o,
input ariane_axi::resp_t axi_resp_i
`else
// L15 (memory side)
output logic l15_val_o,
input logic l15_ack_i,
input logic l15_header_ack_i,
output l15_req_t l15_data_o,
input logic l15_val_i,
output logic l15_req_ack_o,
// L15 (memory side)
output l15_req_t l15_req_o,
input l15_rtrn_t l15_rtrn_i
`endif
`endif
// TODO: interrupt interface
);
@ -96,7 +89,7 @@ module serpent_cache_subsystem #(
serpent_icache #(
`ifdef AXI64_CACHE_PORTS
.AXI64BIT_COMPLIANT ( 1'b1 ),
.NC_ADDR_GE_LT ( 0 ),
.NC_ADDR_GE_LT ( 0 ),
`endif
.NC_ADDR_BEGIN ( CACHE_START_ADDR )
) i_serpent_icache (
@ -116,40 +109,16 @@ module serpent_cache_subsystem #(
.mem_data_o ( icache_adapter )
);
// // 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 ),
// .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 ),
// .amo_req_i ( dcache_amo_req_i ),
// .amo_resp_o ( dcache_amo_resp_o ),
// .req_ports_i ( dcache_req_ports_i ),
// .req_ports_o ( dcache_req_ports_o )
// );
// assign wbuffer_empty_o = 1'b1;
// Note:
// Ports 0/1 for PTW and LD unit are read only.
// Ports 0/1 for PTW and LD unit are read only.
// they have equal prio and are RR arbited
// Port 2 is write only and goes into the merging write buffer
serpent_dcache #(
`ifdef AXI64_CACHE_PORTS
.NC_ADDR_GE_LT ( 0 ), // std config is for openpiton, where the upper memory region is NC
`endif
.NC_ADDR_BEGIN ( CACHE_START_ADDR )
`endif
.NC_ADDR_BEGIN ( CACHE_START_ADDR )
) i_serpent_dcache (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@ -169,6 +138,26 @@ module serpent_cache_subsystem #(
.mem_data_o ( dcache_adapter )
);
// arbiter/adapter
serpent_l15_adapter #(
) i_adapter (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.icache_data_req_i ( icache_adapter_data_req ),
.icache_data_ack_o ( adapter_icache_data_ack ),
.icache_data_i ( icache_adapter ),
.icache_rtrn_vld_o ( adapter_icache_rtrn_vld ),
.icache_rtrn_o ( adapter_icache ),
.dcache_data_req_i ( dcache_adapter_data_req ),
.dcache_data_ack_o ( adapter_dcache_data_ack ),
.dcache_data_i ( dcache_adapter ),
.dcache_rtrn_vld_o ( adapter_dcache_rtrn_vld ),
.dcache_rtrn_o ( adapter_dcache ),
.l15_req_o ( l15_req_o ),
.l15_rtrn_i ( l15_port_i )
);
// different memory plumbing
`ifdef AXI64_CACHE_PORTS
@ -182,7 +171,7 @@ module serpent_cache_subsystem #(
std_cache_pkg::req_t icache_axi_req_type;
assign icache_axi_req_type = ( icache_adapter.nc ) ? std_cache_pkg::SINGLE_REQ : std_cache_pkg::CACHE_LINE_REQ;
axi_adapter #(
.DATA_WIDTH ( ICACHE_LINE_WIDTH ),
.AXI_ID_WIDTH ( AXI_ID_WIDTH )
@ -203,8 +192,8 @@ module serpent_cache_subsystem #(
.rdata_o ( adapter_icache.data ),
.id_o ( ),
.critical_word_o ( ),
.critical_word_valid_o( ),
.axi ( icache_data_if )
.axi_req_o ( axi_data_o ),
.axi_resp_i ( axi_data_i )
);
std_cache_pkg::req_t dcache_axi_req_type;
@ -232,9 +221,9 @@ module serpent_cache_subsystem #(
assign adapter_dcache.rtype = (axi_dcache_id[0]) ? serpent_cache_pkg::DCACHE_STORE_ACK : serpent_cache_pkg::DCACHE_LOAD_ACK;
assign adapter_dcache.nc = axi_dcache_id[1];
assign adapter_dcache.tid = axi_dcache_id>>2;
axi_adapter #(
.DATA_WIDTH ( DCACHE_LINE_WIDTH ),
.DATA_WIDTH ( DCACHE_LINE_WIDTH ),
.AXI_ID_WIDTH ( AXI_ID_WIDTH )
) i_dcache_axi_adapter (
.clk_i ( clk_i ),
@ -257,63 +246,6 @@ module serpent_cache_subsystem #(
.axi ( dcache_data_if )
);
// tie to zero here...
assign dcache_bypass_if.aw_valid = '0;
assign dcache_bypass_if.aw_addr = '0;
assign dcache_bypass_if.aw_prot = '0;
assign dcache_bypass_if.aw_region = '0;
assign dcache_bypass_if.aw_len = '0;
assign dcache_bypass_if.aw_size = '0;
assign dcache_bypass_if.aw_burst = '0;
assign dcache_bypass_if.aw_lock = '0;
assign dcache_bypass_if.aw_cache = '0;
assign dcache_bypass_if.aw_qos = '0;
assign dcache_bypass_if.aw_id = '0;
assign dcache_bypass_if.aw_user = '0;
assign dcache_bypass_if.ar_valid = '0;
assign dcache_bypass_if.ar_addr = '0;
assign dcache_bypass_if.ar_prot = '0;
assign dcache_bypass_if.ar_region = '0;
assign dcache_bypass_if.ar_len = '0;
assign dcache_bypass_if.ar_size = '0;
assign dcache_bypass_if.ar_burst = '0;
assign dcache_bypass_if.ar_lock = '0;
assign dcache_bypass_if.ar_cache = '0;
assign dcache_bypass_if.ar_qos = '0;
assign dcache_bypass_if.ar_id = '0;
assign dcache_bypass_if.ar_user = '0;
assign dcache_bypass_if.w_valid = '0;
assign dcache_bypass_if.w_data = '0;
assign dcache_bypass_if.w_strb = '0;
assign dcache_bypass_if.w_user = '0;
assign dcache_bypass_if.w_last = '0;
assign dcache_bypass_if.b_ready = '0;
assign dcache_bypass_if.r_ready = '0;
`else
serpent_l15_adapter #(
) i_adapter (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.icache_data_req_i ( icache_adapter_data_req ),
.icache_data_ack_o ( adapter_icache_data_ack ),
.icache_data_i ( icache_adapter ),
.icache_rtrn_vld_o ( adapter_icache_rtrn_vld ),
.icache_rtrn_o ( adapter_icache ),
.dcache_data_req_i ( dcache_adapter_data_req ),
.dcache_data_ack_o ( adapter_dcache_data_ack ),
.dcache_data_i ( dcache_adapter ),
.dcache_rtrn_vld_o ( adapter_dcache_rtrn_vld ),
.dcache_rtrn_o ( adapter_dcache ),
.l15_val_o ( l15_val_o ),
.l15_ack_i ( l15_ack_i ),
.l15_header_ack_i ( l15_header_ack_i ),
.l15_data_o ( l15_port_o ),
.l15_val_i ( l15_val_i ),
.l15_req_ack_o ( l15_req_ack_o ),
.l15_rtrn_i ( l15_port_i )
);
`endif
@ -327,37 +259,37 @@ module serpent_cache_subsystem #(
`ifdef AXI64_CACHE_PORTS
a_write_size: assert property (
@(posedge clk_i) disable iff (~rst_ni) dcache_adapter_data_req |-> adapter_dcache_data_ack |-> dcache_axi_we |-> dcache_axi_req_type==std_cache_pkg::SINGLE_REQ)
@(posedge clk_i) disable iff (~rst_ni) dcache_adapter_data_req |-> adapter_dcache_data_ack |-> dcache_axi_we |-> dcache_axi_req_type==std_cache_pkg::SINGLE_REQ)
else $fatal(1,"[l1 cache] full cacheline stores not supported at the moment");
a_paddr_align: assert property (
@(posedge clk_i) disable iff (~rst_ni) dcache_adapter_data_req |-> adapter_dcache_data_ack |-> dcache_axi_req_type==std_cache_pkg::CACHE_LINE_REQ |-> dcache_axi_paddr[2:0] == 3'b000)
@(posedge clk_i) disable iff (~rst_ni) dcache_adapter_data_req |-> adapter_dcache_data_ack |-> dcache_axi_req_type==std_cache_pkg::CACHE_LINE_REQ |-> dcache_axi_paddr[2:0] == 3'b000)
else $fatal(1,"[l1 cache] CL address must be aligned");
`endif
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
initial begin
assert (AXI_ID_WIDTH >= $clog2(serpent_cache_pkg::DCACHE_MAX_TX)+2) else
assert (AXI_ID_WIDTH >= $clog2(serpent_cache_pkg::DCACHE_MAX_TX)+2) else
$fatal(1,$psprintf("[l1 cache] AXI ID must be at least %01d bit wide", $clog2(serpent_cache_pkg::DCACHE_MAX_TX)+2));
end
end
`endif
//pragma translate_on

View file

@ -14,18 +14,18 @@
//
// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich
// Date: 08.08.2018
// Description: adapter module to connect the L1D$ and L1I$ to the native
// interface of the OpenPiton L1.5 cache.
// Description: adapter module to connect the L1D$ and L1I$ to the native
// interface of the OpenPiton L1.5 cache.
//
// A couple of notes:
// A couple of notes:
//
// 1) the L15 has been designed for an OpenSparc T1 core with 2 threads and can serve only
// 1) the L15 has been designed for an OpenSparc T1 core with 2 threads and can serve only
// 1 ld and rd request per thread. Ariane has only one hart, but the LSU can issue several write
// requests to optimize bandwidth. hence, we reuse the threadid field to issue and track multiple
// requests (up to 2 in this case).
// requests to optimize bandwidth. hence, we reuse the threadid field to issue and track multiple
// requests (up to 2 in this case).
//
// 2) the CSM (clumped shared memory = coherence domain restriction in OpenPiton)
// feature is currently not supported by Ariane.
// 2) the CSM (clumped shared memory = coherence domain restriction in OpenPiton)
// feature is currently not supported by Ariane.
//
// 3) some features like blockinitstore, prefetch, ECC errors are not used (see interface below)
//
@ -33,16 +33,16 @@
// through one streaming register, and need to be consumed unconditionally by the caches.
//
// 5) The L1.5 protocol is closely related to the CPX bus of openSPARC, see also [1,2]
//
// 6) Note on transaction data and size: if a store packet is less than 64 bits, then
// the field is filled with copies of the data. in case of an interrupt vector,
//
// 6) Note on transaction data and size: if a store packet is less than 64 bits, then
// the field is filled with copies of the data. in case of an interrupt vector,
// an 18bit interrupt vector is expected.
//
// 7) L1I$ refill requests always have precedence over L1D$ requests.
//
// 7) L1I$ refill requests always have precedence over L1D$ requests.
//
// 8) L1I$ fill requests are always complete cache lines at the moment
//
// 9) the adapter converts from little endian (Ariane) to big endian (openpiton), and vice versa.
// 9) the adapter converts from little endian (Ariane) to big endian (openpiton), and vice versa.
//
// 10) L1I$ requests to I.O space (bit39 of address = 1'b1) always return 32bit nc data
//
@ -56,38 +56,32 @@ import ariane_pkg::*;
import serpent_cache_pkg::*;
module serpent_l15_adapter #(
)(
)(
input logic clk_i,
input logic rst_ni,
// icache
input logic icache_data_req_i,
output logic icache_data_ack_o,
input icache_req_t icache_data_i,
input icache_req_t icache_data_i,
// returning packets must be consumed immediately
output logic icache_rtrn_vld_o,
output icache_rtrn_t icache_rtrn_o,
output icache_rtrn_t icache_rtrn_o,
// dcache
input logic dcache_data_req_i,
output logic dcache_data_ack_o,
input dcache_req_t dcache_data_i,
input dcache_req_t dcache_data_i,
// returning packets must be consumed immediately
output logic dcache_rtrn_vld_o,
output dcache_rtrn_t dcache_rtrn_o,
output dcache_rtrn_t dcache_rtrn_o,
// TODO: interrupt interface
// L15
output logic l15_val_o,
input logic l15_ack_i,
input logic l15_header_ack_i,
output l15_req_t l15_data_o,
// TODO: interrupt interface
input logic l15_val_i,
output logic l15_req_ack_o,
// L15
output l15_req_t l15_req_o,
input l15_rtrn_t l15_rtrn_i
);
@ -114,23 +108,23 @@ l15_rtrn_t rtrn_fifo_data;
///////////////////////////////////////////////////////
// relevant l15 signals
// l15_req_t l15_data_o.l15_rqtype; // see below for encoding
// logic l15_data_o.l15_nc; // non-cacheable bit
// logic [2:0] l15_data_o.l15_size; // transaction size: 000=Byte 001=2Byte; 010=4Byte; 011=8Byte; 111=Cache line (16/32Byte)
// logic [L15_TID_WIDTH-1:0] l15_data_o.l15_threadid; // currently 0 or 1
// logic l15_data_o.l15_invalidate_cacheline; // unused by Ariane as L1 has no ECC at the moment
// logic [L15_WAY_WIDTH-1:0] l15_data_o.l15_l1rplway; // way to replace
// logic [39:0] l15_data_o.l15_address; // physical address
// logic [63:0] l15_data_o.l15_data; // word to write
// logic [63:0] l15_data_o.l15_data_next_entry; // unused in Ariane (only used for CAS atomic requests)
// logic [L15_TLB_CSM_WIDTH-1:0] l15_data_o.l15_csm_data;
// l15_req_t l15_req_o.l15_rqtype; // see below for encoding
// logic l15_req_o.l15_nc; // non-cacheable bit
// logic [2:0] l15_req_o.l15_size; // transaction size: 000=Byte 001=2Byte; 010=4Byte; 011=8Byte; 111=Cache line (16/32Byte)
// logic [L15_TID_WIDTH-1:0] l15_req_o.l15_threadid; // currently 0 or 1
// logic l15_req_o.l15_invalidate_cacheline; // unused by Ariane as L1 has no ECC at the moment
// logic [L15_WAY_WIDTH-1:0] l15_req_o.l15_l1rplway; // way to replace
// logic [39:0] l15_req_o.l15_address; // physical address
// logic [63:0] l15_req_o.l15_data; // word to write
// logic [63:0] l15_req_o.l15_data_next_entry; // unused in Ariane (only used for CAS atomic requests)
// logic [L15_TLB_CSM_WIDTH-1:0] l15_req_o.l15_csm_data;
// need to deassert valid signal when header is acked
// can move on when packed is acked (need to clear header ack)
assign l15_val_o = (|arb_req) & ~header_ack_q;
assign header_ack_d = (l15_ack_i) ? 1'b0 : (header_ack_q | l15_header_ack_i);
assign arb_req = {~dcache_data_empty,
assign l15_req_o.l15_val = (|arb_req) & ~header_ack_q;
assign header_ack_d = (l15_rtrn_i.l15_ack) ? 1'b0 : (header_ack_q | l15_rtrn_i.l15_header_ack);
assign arb_req = {~dcache_data_empty,
~icache_data_empty};
assign dcache_data_pop = arb_ack[1];
@ -140,20 +134,20 @@ assign icache_data_ack_o = icache_data_req_i & ~ icache_data_full;
assign dcache_data_ack_o = dcache_data_req_i & ~ dcache_data_full;
// data mux
assign l15_data_o.l15_nc = (arb_idx) ? dcache_data.nc : icache_data.nc;
assign l15_data_o.l15_size = (arb_idx) ? dcache_data.size : 3'b111;// always request full cache line for icache
assign l15_data_o.l15_threadid = (arb_idx) ? dcache_data.tid : icache_data.tid;
assign l15_data_o.l15_invalidate_cacheline = 1'b0; // unused by Ariane as L1 has no ECC at the moment
assign l15_data_o.l15_l1rplway = (arb_idx) ? dcache_data.way : icache_data.way;
assign l15_data_o.l15_address = (arb_idx) ? dcache_data.paddr : icache_data.paddr;
assign l15_data_o.l15_data_next_entry = 1'b0; // unused in Ariane (only used for CAS atomic requests)
assign l15_data_o.l15_csm_data = 1'b0; // unused in Ariane (only used for coherence domain restriction features)
assign l15_data_o.l15_amo_op = dcache_data.amo_op;
assign l15_req_o.l15_nc = (arb_idx) ? dcache_data.nc : icache_data.nc;
assign l15_req_o.l15_size = (arb_idx) ? dcache_data.size : 3'b111;// always request full cache line for icache
assign l15_req_o.l15_threadid = (arb_idx) ? dcache_data.tid : icache_data.tid;
assign l15_req_o.l15_invalidate_cacheline = 1'b0; // unused by Ariane as L1 has no ECC at the moment
assign l15_req_o.l15_l1rplway = (arb_idx) ? dcache_data.way : icache_data.way;
assign l15_req_o.l15_address = (arb_idx) ? dcache_data.paddr : icache_data.paddr;
assign l15_req_o.l15_data_next_entry = 1'b0; // unused in Ariane (only used for CAS atomic requests)
assign l15_req_o.l15_csm_data = 1'b0; // unused in Ariane (only used for coherence domain restriction features)
assign l15_req_o.l15_amo_op = dcache_data.amo_op;
// swap endianess and replicate datawords if necessary
always_comb begin : p_datarepl
unique case(dcache_data.size)
unique case(dcache_data.size)
3'b000: begin // 1byte
l15_data_o.l15_data = swendian64({dcache_data.data[0],
l15_req_o.l15_data = swendian64({dcache_data.data[0],
dcache_data.data[0],
dcache_data.data[0],
dcache_data.data[0],
@ -163,17 +157,17 @@ always_comb begin : p_datarepl
dcache_data.data[0]});
end
3'b001: begin // 2byte
l15_data_o.l15_data = swendian64({dcache_data.data[1:0],
l15_req_o.l15_data = swendian64({dcache_data.data[1:0],
dcache_data.data[1:0],
dcache_data.data[1:0],
dcache_data.data[1:0]});
end
3'b010: begin // 4byte
l15_data_o.l15_data = swendian64({dcache_data.data[3:0],
l15_req_o.l15_data = swendian64({dcache_data.data[3:0],
dcache_data.data[3:0]});
end
default: begin // 8 byte
l15_data_o.l15_data = swendian64(dcache_data.data);
l15_req_o.l15_data = swendian64(dcache_data.data);
end
endcase // dcache_data.size
end
@ -183,47 +177,47 @@ end
always_comb begin : p_arb
arb_idx = '0;
arb_ack = '0;
if(arb_req[0] & l15_ack_i) begin
if(arb_req[0] & l15_rtrn_i.l15_ack) begin
arb_ack[0] = 1'b1;
arb_idx = 0;
end else if (arb_req[1] & l15_ack_i) begin
end else if (arb_req[1] & l15_rtrn_i.l15_ack) begin
arb_ack[1] = 1'b1;
arb_idx = 1;
end
end
end // p_arb
// encode packet type
always_comb begin : p_req
l15_data_o.l15_rqtype = LOAD_RQ;
l15_req_o.l15_rqtype = LOAD_RQ;
unique case (arb_idx)
unique case (arb_idx)
0: begin// icache
l15_data_o.l15_rqtype = IMISS_RQ;
l15_req_o.l15_rqtype = IMISS_RQ;
end
1: begin
unique case (dcache_data.rtype)
unique case (dcache_data.rtype)
DCACHE_STORE_REQ: begin
l15_data_o.l15_rqtype = STORE_RQ;
l15_req_o.l15_rqtype = STORE_RQ;
end
DCACHE_LOAD_REQ: begin
l15_req_o.l15_rqtype = LOAD_RQ;
end
DCACHE_LOAD_REQ: begin
l15_data_o.l15_rqtype = LOAD_RQ;
end
DCACHE_ATOMIC_REQ: begin
l15_data_o.l15_rqtype = ATOMIC_RQ;
end
l15_req_o.l15_rqtype = ATOMIC_RQ;
end
// DCACHE_INT_REQ: begin
// //TODO
// end
// end
default: begin
;
end
endcase // dcache_data.rtype
endcase // dcache_data.rtype
end
default: begin
;
end
endcase
end // p_req
end // p_req
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
@ -238,7 +232,7 @@ end
fifo_v2 #(
.dtype ( icache_req_t ),
.DEPTH ( ADAPTER_REQ_FIFO_DEPTH )
) i_icache_data_fifo (
) i_icache_data_fifo (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( 1'b0 ),
@ -251,12 +245,12 @@ fifo_v2 #(
.push_i ( icache_data_push ),
.data_o ( icache_data ),
.pop_i ( icache_data_pop )
);
);
fifo_v2 #(
.dtype ( dcache_req_t ),
.DEPTH ( ADAPTER_REQ_FIFO_DEPTH )
) i_dcache_data_fifo (
) i_dcache_data_fifo (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( 1'b0 ),
@ -269,7 +263,7 @@ fifo_v2 #(
.push_i ( dcache_data_push ),
.data_o ( dcache_data ),
.pop_i ( dcache_data_pop )
);
);
///////////////////////////////////////////////////////
// return path from L15
@ -279,19 +273,19 @@ fifo_v2 #(
// l15_rtrn_i.l15_returntype; // see below for encoding
// l15_rtrn_i.l15_noncacheable; // non-cacheable bit
// l15_rtrn_i.l15_atomic; // asserted in load return and store ack pack
// l15_rtrn_i.l15_threadid; // used as transaction ID
// l15_rtrn_i.l15_f4b; // 4byte instruction fill from I/O space (nc).
// l15_rtrn_i.l15_threadid; // used as transaction ID
// l15_rtrn_i.l15_f4b; // 4byte instruction fill from I/O space (nc).
// l15_rtrn_i.l15_data_0; // used for both caches
// l15_rtrn_i.l15_data_1; // used for both caches
// l15_rtrn_i.l15_data_2; // currently only used for I$
// l15_rtrn_i.l15_data_3; // currently only used for I$
// l15_rtrn_i.l15_inval_icache_all_way; // invalidate all ways
// l15_rtrn_i.l15_inval_icache_all_way; // invalidate all ways
// l15_rtrn_i.l15_inval_address_15_4; // invalidate selected cacheline
// l15_rtrn_i.l15_inval_dcache_inval; // invalidate selected cacheline and way
// l15_rtrn_i.l15_inval_way; // way to invalidate
// l15_rtrn_i.l15_inval_way; // way to invalidate
// acknowledge if we have space to hold this packet
assign l15_req_ack_o = l15_val_i & ~rtrn_fifo_full;
assign l15_req_o.l15_req_ack = l15_rtrn_i.l15_val & ~rtrn_fifo_full;
// packets have to be consumed immediately
assign rtrn_fifo_pop = ~rtrn_fifo_empty;
@ -302,33 +296,33 @@ always_comb begin : p_rtrn_logic
icache_rtrn_vld_o = 1'b0;
dcache_rtrn_vld_o = 1'b0;
if(~rtrn_fifo_empty) begin
unique case (rtrn_fifo_data.l15_returntype)
unique case (rtrn_fifo_data.l15_returntype)
LOAD_RET: begin
dcache_rtrn_o.rtype = DCACHE_LOAD_ACK;
dcache_rtrn_vld_o = 1'b1;
end
end
ST_ACK: begin
dcache_rtrn_o.rtype = DCACHE_STORE_ACK;
dcache_rtrn_vld_o = 1'b1;
end
end
// INT_RET: begin
// TODO: implement this
// TODO: implement this
// dcache_rtrn_o.reqType = DCACHE_INT_ACK;
// end
// end
IFILL_RET: begin
icache_rtrn_o.rtype = ICACHE_IFILL_ACK;
icache_rtrn_vld_o = 1'b1;
end
end
EVICT_REQ: begin
icache_rtrn_o.rtype = ICACHE_INV_REQ;
dcache_rtrn_o.rtype = DCACHE_INV_REQ;
icache_rtrn_vld_o = 1'b1;
dcache_rtrn_vld_o = 1'b1;
end
end
CPX_RESTYPE_ATOMIC_RES: begin
dcache_rtrn_o.rtype = DCACHE_ATOMIC_ACK;
end
default: begin
default: begin
;
end
endcase // rtrn_fifo_data.l15_returntype
@ -368,7 +362,7 @@ assign dcache_rtrn_o.inv.all = rtrn_fifo_data.l15_inval_dcache_all_way;
fifo_v2 #(
.dtype ( l15_rtrn_t ),
.DEPTH ( ADAPTER_RTRN_FIFO_DEPTH )
) i_rtrn_fifo (
) i_rtrn_fifo (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( 1'b0 ),
@ -378,10 +372,10 @@ fifo_v2 #(
.alm_full_o ( ),
.alm_empty_o ( ),
.data_i ( l15_rtrn_i ),
.push_i ( l15_req_ack_o ),
.push_i ( l15_req_o.l15_req_ack ),
.data_o ( rtrn_fifo_data ),
.pop_i ( rtrn_fifo_pop )
);
);
///////////////////////////////////////////////////////
@ -392,48 +386,48 @@ fifo_v2 #(
`ifndef verilator
iospace: assert property (
@(posedge clk_i) disable iff (~rst_ni) l15_val_o |-> l15_data_o.l15_address >= {40'h8000000000} |-> l15_data_o.l15_nc)
@(posedge clk_i) disable iff (~rst_ni) l15_req_o.l15_val |-> l15_req_o.l15_address >= {40'h8000000000} |-> l15_req_o.l15_nc)
else $fatal("[l15_adapter] accesses to I/O space must have noncacheable bit set!");
invalidations: assert property (
@(posedge clk_i) disable iff (~rst_ni) l15_val_i |-> l15_rtrn_i.l15_returntype == EVICT_REQ |-> (l15_rtrn_i.l15_inval_icache_inval |
@(posedge clk_i) disable iff (~rst_ni) l15_rtrn_i.l15_val |-> l15_rtrn_i.l15_returntype == EVICT_REQ |-> (l15_rtrn_i.l15_inval_icache_inval |
l15_rtrn_i.l15_inval_dcache_inval |
l15_rtrn_i.l15_inval_icache_all_way |
l15_rtrn_i.l15_inval_dcache_all_way))
l15_rtrn_i.l15_inval_dcache_all_way))
else $fatal("[l15_adapter] got invalidation package with zero invalidation flags");
blockstore_o: assert property (
@(posedge clk_i) disable iff (~rst_ni) l15_val_o|-> !l15_data_o.l15_blockstore)
@(posedge clk_i) disable iff (~rst_ni) l15_req_o.l15_val|-> !l15_req_o.l15_blockstore)
else $fatal("[l15_adapter] blockstores are not supported");
blockstore_i: assert property (
@(posedge clk_i) disable iff (~rst_ni) l15_val_i|-> !l15_rtrn_i.l15_blockinitstore)
@(posedge clk_i) disable iff (~rst_ni) l15_rtrn_i.l15_val|-> !l15_rtrn_i.l15_blockinitstore)
else $fatal("[l15_adapter] blockstores are not supported");
instr_fill_size: assert property (
@(posedge clk_i) disable iff (~rst_ni) (!l15_rtrn_i.l15_f4b))
@(posedge clk_i) disable iff (~rst_ni) (!l15_rtrn_i.l15_f4b))
else $fatal("[l15_adapter] 4b instruction fills not supported");
unsuported_rtrn_types: assert property (
@(posedge clk_i) disable iff (~rst_ni) (l15_val_i |-> l15_rtrn_i.l15_returntype inside {LOAD_RET, ST_ACK, IFILL_RET, EVICT_REQ}))
@(posedge clk_i) disable iff (~rst_ni) (l15_rtrn_i.l15_val |-> l15_rtrn_i.l15_returntype inside {LOAD_RET, ST_ACK, IFILL_RET, EVICT_REQ}))
else $fatal("[l15_adapter] unsupported rtrn type");
initial begin
// assert wrong parameterizations
assert (L15_SET_ASSOC == ICACHE_SET_ASSOC)
assert (L15_SET_ASSOC == ICACHE_SET_ASSOC)
else $fatal("[l15_adapter] number of icache ways not aligned with L15");
// assert wrong parameterizations
assert (L15_SET_ASSOC == DCACHE_SET_ASSOC)
assert (L15_SET_ASSOC == DCACHE_SET_ASSOC)
else $fatal("[l15_adapter] number of dcache ways not aligned with L15");
// invalidation address returned by L1.5 is 16 bit
assert (16 >= $max(ICACHE_INDEX_WIDTH, DCACHE_INDEX_WIDTH))
assert (16 >= $max(ICACHE_INDEX_WIDTH, DCACHE_INDEX_WIDTH))
else $fatal("[l15_adapter] maximum number of index bits supported by L1.5 is 16");
// assert mismatch of cache line width
assert (ICACHE_LINE_WIDTH==256)
else $fatal("[l15_adapter] ichache lines are currently restricted to 256 bits");
assert (DCACHE_LINE_WIDTH==128)
else $fatal("[l15_adapter] dchache lines are currently restricted to 128 bits");
assert (ICACHE_LINE_WIDTH==256)
else $fatal("[l15_adapter] ichache lines are currently restricted to 256 bits");
assert (DCACHE_LINE_WIDTH==128)
else $fatal("[l15_adapter] dchache lines are currently restricted to 128 bits");
end
`endif
//pragma translate_on

View file

@ -18,10 +18,6 @@ import ariane_pkg::*;
import std_cache_pkg::*;
module std_cache_subsystem #(
<<<<<<< HEAD
parameter int unsigned AXI_ID_WIDTH = 10,
=======
>>>>>>> ariane_next
parameter logic [63:0] CACHE_START_ADDR = 64'h4000_0000
)(
input logic clk_i,
@ -84,7 +80,6 @@ module std_cache_subsystem #(
// 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,

View file

@ -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
@ -128,7 +127,6 @@ module std_nbdcache #(
// Miss Handling Unit
// ------------------
miss_handler #(
.AXI_ID_WIDTH ( AXI_ID_WIDTH ),
.NR_PORTS ( 3 )
) i_miss_handler (
.flush_i ( flush_i ),