diff --git a/include/ariane_pkg.sv b/include/ariane_pkg.sv index 3fca0b5ea..b48bc082a 100644 --- a/include/ariane_pkg.sv +++ b/include/ariane_pkg.sv @@ -20,8 +20,10 @@ // configuration in case Ariane is // instantiated in OpenPiton `ifdef PITON_ARIANE +`ifndef AXI64_CACHE_PORTS `include "l15.tmp.h" `endif +`endif package ariane_pkg; @@ -284,7 +286,7 @@ package ariane_pkg; `define CONFIG_L1D_ASSOCIATIVITY 4 `endif -`ifndef CONFIG_L1I_SIZE +`ifndef CONFIG_L1D_SIZE `define CONFIG_L1D_SIZE 16*1024 `endif @@ -298,7 +300,7 @@ package ariane_pkg; localparam int unsigned DCACHE_SET_ASSOC = `CONFIG_L1D_ASSOCIATIVITY; localparam int unsigned DCACHE_INDEX_WIDTH = $clog2(`CONFIG_L1D_SIZE / DCACHE_SET_ASSOC); localparam int unsigned DCACHE_TAG_WIDTH = 56 - DCACHE_INDEX_WIDTH; - `else +`else // align to openpiton for the time being (this should be more configurable in the future) // I$ localparam int unsigned ICACHE_INDEX_WIDTH = 12; // in bit diff --git a/include/serpent_cache_pkg.sv b/include/serpent_cache_pkg.sv index 71863ba2e..9d192de17 100644 --- a/include/serpent_cache_pkg.sv +++ b/include/serpent_cache_pkg.sv @@ -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: Michael Schaffner , ETH Zurich // Date: 15.08.2018 @@ -20,334 +16,349 @@ // configuration in case Ariane is // instantiated in OpenPiton `ifdef PITON_ARIANE +`ifndef AXI64_CACHE_PORTS `include "l15.tmp.h" `include "define.tmp.h" `endif +`endif package serpent_cache_pkg; - // these parames need to coincide with the - // L1.5 parameterization, do not change + // these parames need to coincide with the + // L1.5 parameterization, do not change `ifdef PITON_ARIANE - localparam L15_SET_ASSOC = `CONFIG_L15_ASSOCIATIVITY; - localparam L15_TID_WIDTH = `L15_THREADID_WIDTH; - localparam L15_TLB_CSM_WIDTH = `TLB_CSM_WIDTH; -`else - localparam L15_SET_ASSOC = ariane_pkg::DCACHE_SET_ASSOC;// align with dcache for compatibility with the standard Ariane setup - localparam L15_TID_WIDTH = 2; - localparam L15_TLB_CSM_WIDTH = 33; + +`ifndef CONFIG_L15_ASSOCIATIVITY + `define CONFIG_L15_ASSOCIATIVITY 4 `endif - 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); - // FIFO depths of L15 adapter - localparam ADAPTER_REQ_FIFO_DEPTH = 2; - localparam ADAPTER_RTRN_FIFO_DEPTH = 2; +`ifndef L15_THREADID_WIDTH + `define L15_THREADID_WIDTH 1 +`endif + +`ifndef TLB_CSM_WIDTH + `define TLB_CSM_WIDTH 33 +`endif + + localparam L15_SET_ASSOC = `CONFIG_L15_ASSOCIATIVITY; + localparam L15_TID_WIDTH = `L15_THREADID_WIDTH; + localparam L15_TLB_CSM_WIDTH = `TLB_CSM_WIDTH; +`else + localparam L15_SET_ASSOC = ariane_pkg::DCACHE_SET_ASSOC;// align with dcache for compatibility with the standard Ariane setup + localparam L15_TID_WIDTH = 2; + localparam L15_TLB_CSM_WIDTH = 33; +`endif + 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); + + // FIFO depths of L15 adapter + localparam ADAPTER_REQ_FIFO_DEPTH = 2; + localparam ADAPTER_RTRN_FIFO_DEPTH = 2; - // Calculated parameter - 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 + // Calculated parameter + 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_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; + 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; - localparam DCACHE_ID_WIDTH = $clog2(DCACHE_MAX_TX); + // write buffer parameterization + localparam DCACHE_WBUF_DEPTH = 8; + localparam DCACHE_MAX_TX = 2**L15_TID_WIDTH; + 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] 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 - logic [ariane_pkg::DCACHE_SET_ASSOC-1:0] hit_oh; // valid way in the cache - } wbuffer_t; + 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] 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 + logic [ariane_pkg::DCACHE_SET_ASSOC-1:0] hit_oh; // valid way in the cache + } wbuffer_t; - // 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 { - logic vld; - logic [7:0] be; - logic [$clog2(DCACHE_WBUF_DEPTH)-1:0] ptr; - } tx_stat_t; + // 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 { + 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] { - DCACHE_STORE_REQ, - DCACHE_LOAD_REQ, - DCACHE_ATOMIC_REQ, - DCACHE_INT_REQ } dcache_out_t; + // local interfaces between caches and L15 adapter + 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] { - 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 [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] { - ICACHE_INV_REQ, // no ack from the core required - ICACHE_IFILL_ACK} icache_in_t; + typedef enum logic [0:0] { + ICACHE_INV_REQ, // no ack from the core required + ICACHE_IFILL_ACK + } icache_in_t; - typedef struct packed { - logic vld; // invalidate only affected way - logic all; // invalidate all ways - logic [ariane_pkg::ICACHE_INDEX_WIDTH-1:0] idx; // physical address to invalidate - logic [L15_WAY_WIDTH-1:0] way; // way to invalidate - } cache_inval_t; + typedef struct packed { + logic vld; // invalidate only affected way + logic all; // invalidate all ways + logic [ariane_pkg::ICACHE_INDEX_WIDTH-1:0] idx; // physical address to invalidate + logic [L15_WAY_WIDTH-1:0] way; // way to invalidate + } cache_inval_t; - // icache interface - typedef struct packed { - logic [$clog2(ariane_pkg::ICACHE_SET_ASSOC)-1:0] way; // way to replace - logic [63:0] paddr; // physical address - logic nc; // noncacheable - logic [L15_TID_WIDTH-1:0] tid; // threadi id (used as transaction id in Ariane) - } icache_req_t; + // icache interface + typedef struct packed { + logic [$clog2(ariane_pkg::ICACHE_SET_ASSOC)-1:0] way; // way to replace + logic [63:0] paddr; // physical address + logic nc; // noncacheable + logic [L15_TID_WIDTH-1:0] tid; // threadi id (used as transaction id in Ariane) + } icache_req_t; - typedef struct packed { - icache_in_t rtype; // see definitions above - logic [ariane_pkg::ICACHE_LINE_WIDTH-1:0] data; // full cache line width - cache_inval_t inv; // invalidation vector - logic nc; // noncacheable - logic [L15_TID_WIDTH-1:0] tid; // threadi id (used as transaction id in Ariane) - logic f4b; // fetch 4 bytes only (from I/O space) - } icache_rtrn_t; + typedef struct packed { + icache_in_t rtype; // see definitions above + logic [ariane_pkg::ICACHE_LINE_WIDTH-1:0] data; // full cache line width + cache_inval_t inv; // invalidation vector + logic nc; // noncacheable + logic [L15_TID_WIDTH-1:0] tid; // threadi id (used as transaction id in Ariane) + logic f4b; // fetch 4 bytes only (from I/O space) + } icache_rtrn_t; - // dcache interface - typedef struct packed { - dcache_out_t rtype; // see definitions above - logic [2:0] size; // transaction size: 000=Byte 001=2Byte; 010=4Byte; 011=8Byte; 111=Cache line (16/32Byte) - logic [L1D_WAY_WIDTH-1:0] way; // way to replace - logic [63:0] paddr; // physical address - logic [63:0] data; // word width of processor (no block stores at the moment) - logic nc; // noncacheable - logic [L15_TID_WIDTH-1:0] tid; // threadi id (used as transaction id in Ariane) - ariane_pkg::amo_t amo_op; // amo opcode - } dcache_req_t; + // dcache interface + typedef struct packed { + dcache_out_t rtype; // see definitions above + logic [2:0] size; // transaction size: 000=Byte 001=2Byte; 010=4Byte; 011=8Byte; 111=Cache line (16/32Byte) + logic [L1D_WAY_WIDTH-1:0] way; // way to replace + logic [63:0] paddr; // physical address + logic [63:0] data; // word width of processor (no block stores at the moment) + logic nc; // noncacheable + logic [L15_TID_WIDTH-1:0] tid; // threadi id (used as transaction id in Ariane) + ariane_pkg::amo_t amo_op; // amo opcode + } dcache_req_t; - typedef struct packed { - dcache_in_t rtype; // see definitions above - logic [ariane_pkg::DCACHE_LINE_WIDTH-1:0] data; // full cache line width - cache_inval_t inv; // invalidation vector - logic nc; // noncacheable - logic [L15_TID_WIDTH-1:0] tid; // threadi id (used as transaction id in Ariane) - } dcache_rtrn_t; + typedef struct packed { + dcache_in_t rtype; // see definitions above + logic [ariane_pkg::DCACHE_LINE_WIDTH-1:0] data; // full cache line width + cache_inval_t inv; // invalidation vector + logic nc; // noncacheable + logic [L15_TID_WIDTH-1:0] tid; // threadi id (used as transaction id in Ariane) + } dcache_rtrn_t; - // taken from iop.h in openpiton - // to l1.5 (only marked subset is used) - typedef enum logic [4:0] { - L15_LOAD_RQ = 5'b00000, // load request - L15_IMISS_RQ = 5'b10000, // instruction fill request - L15_STORE_RQ = 5'b00001, // store request - L15_ATOMIC_RQ = 5'b00110, // atomic op - //L15_CAS1_RQ = 5'b00010, // compare and swap1 packet (OpenSparc atomics) - //L15_CAS2_RQ = 5'b00011, // compare and swap2 packet (OpenSparc atomics) - //L15_SWAP_RQ = 5'b00110, // swap packet (OpenSparc atomics) - L15_STRLOAD_RQ = 5'b00100, // unused - L15_STRST_RQ = 5'b00101, // unused - L15_STQ_RQ = 5'b00111, // unused - L15_INT_RQ = 5'b01001, // interrupt request - L15_FWD_RQ = 5'b01101, // unused - L15_FWD_RPY = 5'b01110, // unused - L15_RSVD_RQ = 5'b11111 // unused - } l15_reqtypes_t; + // taken from iop.h in openpiton + // to l1.5 (only marked subset is used) + typedef enum logic [4:0] { + L15_LOAD_RQ = 5'b00000, // load request + L15_IMISS_RQ = 5'b10000, // instruction fill request + L15_STORE_RQ = 5'b00001, // store request + L15_ATOMIC_RQ = 5'b00110, // atomic op + //L15_CAS1_RQ = 5'b00010, // compare and swap1 packet (OpenSparc atomics) + //L15_CAS2_RQ = 5'b00011, // compare and swap2 packet (OpenSparc atomics) + //L15_SWAP_RQ = 5'b00110, // swap packet (OpenSparc atomics) + L15_STRLOAD_RQ = 5'b00100, // unused + L15_STRST_RQ = 5'b00101, // unused + L15_STQ_RQ = 5'b00111, // unused + L15_INT_RQ = 5'b01001, // interrupt request + L15_FWD_RQ = 5'b01101, // unused + L15_FWD_RPY = 5'b01110, // unused + L15_RSVD_RQ = 5'b11111 // unused + } l15_reqtypes_t; - // from l1.5 (only marked subset is used) - typedef enum logic [3:0] { - L15_LOAD_RET = 4'b0000, // load packet - // L15_INV_RET = 4'b0011, // invalidate packet, not unique... - L15_ST_ACK = 4'b0100, // store ack packet - //L15_AT_ACK = 4'b0011, // unused, not unique... - L15_INT_RET = 4'b0111, // interrupt packet - L15_TEST_RET = 4'b0101, // unused - L15_FP_RET = 4'b1000, // unused - L15_IFILL_RET = 4'b0001, // instruction fill packet - L15_EVICT_REQ = 4'b0011, // eviction request - L15_ERR_RET = 4'b1100, // unused - L15_STRLOAD_RET = 4'b0010, // unused - L15_STRST_ACK = 4'b0110, // unused - L15_FWD_RQ_RET = 4'b1010, // unused - L15_FWD_RPY_RET = 4'b1011, // unused - L15_RSVD_RET = 4'b1111, // unused - L15_CPX_RESTYPE_ATOMIC_RES = 4'b1110 // custom type for atomic responses - } l15_rtrntypes_t; + // from l1.5 (only marked subset is used) + typedef enum logic [3:0] { + L15_LOAD_RET = 4'b0000, // load packet + // L15_INV_RET = 4'b0011, // invalidate packet, not unique... + L15_ST_ACK = 4'b0100, // store ack packet + //L15_AT_ACK = 4'b0011, // unused, not unique... + L15_INT_RET = 4'b0111, // interrupt packet + L15_TEST_RET = 4'b0101, // unused + L15_FP_RET = 4'b1000, // unused + L15_IFILL_RET = 4'b0001, // instruction fill packet + L15_EVICT_REQ = 4'b0011, // eviction request + L15_ERR_RET = 4'b1100, // unused + L15_STRLOAD_RET = 4'b0010, // unused + L15_STRST_ACK = 4'b0110, // unused + L15_FWD_RQ_RET = 4'b1010, // unused + L15_FWD_RPY_RET = 4'b1011, // unused + L15_RSVD_RET = 4'b1111, // unused + L15_CPX_RESTYPE_ATOMIC_RES = 4'b1110 // custom type for atomic responses + } l15_rtrntypes_t; - 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) - logic [L15_TID_WIDTH-1:0] l15_threadid; // currently 0 or 1 - logic l15_prefetch; // unused in openpiton - logic l15_invalidate_cacheline; // unused by Ariane as L1 has no ECC at the moment - logic l15_blockstore; // unused in openpiton - logic l15_blockinitstore; // unused in openpiton - logic [L15_WAY_WIDTH-1:0] l15_l1rplway; // way to replace - logic [39:0] l15_address; // physical address - logic [63:0] l15_data; // word to write - logic [63:0] l15_data_next_entry; // unused in Ariane (only used for CAS atomic requests) - logic [L15_TLB_CSM_WIDTH-1:0] l15_csm_data; // unused in Ariane - logic [3:0] l15_amo_op; // atomic operation type - } l15_req_t; + 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) + logic [L15_TID_WIDTH-1:0] l15_threadid; // currently 0 or 1 + logic l15_prefetch; // unused in openpiton + logic l15_invalidate_cacheline; // unused by Ariane as L1 has no ECC at the moment + logic l15_blockstore; // unused in openpiton + logic l15_blockinitstore; // unused in openpiton + logic [L15_WAY_WIDTH-1:0] l15_l1rplway; // way to replace + logic [39:0] l15_address; // physical address + logic [63:0] l15_data; // word to write + logic [63:0] l15_data_next_entry; // unused in Ariane (only used for CAS atomic requests) + logic [L15_TLB_CSM_WIDTH-1:0] l15_csm_data; // unused in Ariane + logic [3:0] l15_amo_op; // atomic operation type + } 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 - logic l15_noncacheable; // non-cacheable bit - logic l15_atomic; // asserted in load return and store ack packets of atomic tx - logic [L15_TID_WIDTH-1:0] l15_threadid; // used as transaction ID - logic l15_prefetch; // unused in openpiton - logic l15_f4b; // 4byte instruction fill from I/O space (nc). - logic [63:0] l15_data_0; // used for both caches - logic [63:0] l15_data_1; // used for both caches - logic [63:0] l15_data_2; // currently only used for I$ - logic [63:0] l15_data_3; // currently only used for I$ - logic l15_inval_icache_all_way; // invalidate all ways - logic l15_inval_dcache_all_way; // unused in openpiton - logic [15:4] l15_inval_address_15_4; // invalidate selected cacheline - logic l15_cross_invalidate; // unused in openpiton - logic [L15_WAY_WIDTH-1:0] l15_cross_invalidate_way; // unused in openpiton - logic l15_inval_dcache_inval; // invalidate selected cacheline and way - logic l15_inval_icache_inval; // unused in openpiton - logic [L15_WAY_WIDTH-1:0] l15_inval_way; // way to invalidate - logic l15_blockinitstore; // unused in openpiton - } l15_rtrn_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 + logic l15_noncacheable; // non-cacheable bit + logic l15_atomic; // asserted in load return and store ack packets of atomic tx + logic [L15_TID_WIDTH-1:0] l15_threadid; // used as transaction ID + logic l15_prefetch; // unused in openpiton + logic l15_f4b; // 4byte instruction fill from I/O space (nc). + logic [63:0] l15_data_0; // used for both caches + logic [63:0] l15_data_1; // used for both caches + logic [63:0] l15_data_2; // currently only used for I$ + logic [63:0] l15_data_3; // currently only used for I$ + logic l15_inval_icache_all_way; // invalidate all ways + logic l15_inval_dcache_all_way; // unused in openpiton + logic [15:4] l15_inval_address_15_4; // invalidate selected cacheline + logic l15_cross_invalidate; // unused in openpiton + logic [L15_WAY_WIDTH-1:0] l15_cross_invalidate_way; // unused in openpiton + logic l15_inval_dcache_inval; // invalidate selected cacheline and way + logic l15_inval_icache_inval; // unused in openpiton + logic [L15_WAY_WIDTH-1:0] l15_inval_way; // way to invalidate + logic l15_blockinitstore; // unused in openpiton + } l15_rtrn_t; - // swap endianess in a 64bit word - function automatic logic[63:0] swendian64(input logic[63:0] in); - automatic logic[63:0] out; - for(int k=0; k<64;k+=8)begin - out[k +: 8] = in[63-k -: 8]; - end - return out; - endfunction + // swap endianess in a 64bit word + function automatic logic[63:0] swendian64(input logic[63:0] in); + automatic logic[63:0] out; + for(int k=0; k<64;k+=8)begin + out[k +: 8] = in[63-k -: 8]; + end + return out; + endfunction - 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; - endfunction + 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; + 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; - 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; + 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; - 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; + endfunction - function automatic logic [5:0] popcnt64 ( - input logic [63:0] in - ); - logic [5:0] cnt= 0; - foreach (in[k]) begin - cnt += in[k]; - end - return cnt; - endfunction : popcnt64 + function automatic logic [5:0] popcnt64 ( + input logic [63:0] in + ); + logic [5:0] cnt= 0; + foreach (in[k]) begin + cnt += in[k]; + end + return cnt; + endfunction : popcnt64 - function automatic logic [7:0] toByteEnable8( - input logic [2:0] offset, - 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 - default: be = '1; // dword - endcase // size - return be; - endfunction : toByteEnable8 - - // openpiton requires the data to be replicated in case of smaller sizes than dwords - function automatic logic [63:0] repData64( - input logic [63:0] data, - input logic [2:0] offset, - input logic [1:0] size - ); - logic [63:0] out; - 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 - return out; - endfunction : repData64 - - // note: this is openpiton specific. cannot transmit unaligned words. - // hence we default to individual bytes in that case, and they have to be transmitted - // one after the other - function automatic logic [1:0] toSize64( - input logic [7:0] be - ); - logic [1:0] size; - unique case(be) - 8'b1111_1111: size = 2'b11; // dword - 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 - return size; - endfunction : toSize64 - - // align the physical address to the specified size: - // 000: bytes - // 001: hword - // 010: word - // 011: dword - // 111: DCACHE line - function automatic logic [63:0] paddrSizeAlign( - input logic [63:0] paddr, - input logic [2:0] size - ); - logic [63:0] out; - out = paddr; - unique case (size) - 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; - default: ; - endcase - return out; - endfunction : paddrSizeAlign + function automatic logic [7:0] toByteEnable8( + input logic [2:0] offset, + 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 + default: be = '1; // dword + endcase // size + return be; + endfunction : toByteEnable8 + // openpiton requires the data to be replicated in case of smaller sizes than dwords + function automatic logic [63:0] repData64( + input logic [63:0] data, + input logic [2:0] offset, + input logic [1:0] size + ); + logic [63:0] out; + 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 + return out; + endfunction : repData64 + // note: this is openpiton specific. cannot transmit unaligned words. + // hence we default to individual bytes in that case, and they have to be transmitted + // one after the other + function automatic logic [1:0] toSize64( + input logic [7:0] be + ); + logic [1:0] size; + unique case(be) + 8'b1111_1111: size = 2'b11; // dword + 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 + return size; + endfunction : toSize64 + // align the physical address to the specified size: + // 000: bytes + // 001: hword + // 010: word + // 011: dword + // 111: DCACHE line + function automatic logic [63:0] paddrSizeAlign( + input logic [63:0] paddr, + input logic [2:0] size + ); + logic [63:0] out; + out = paddr; + unique case (size) + 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; + default: ; + endcase + return out; + endfunction : paddrSizeAlign endpackage : serpent_cache_pkg diff --git a/openpiton/ariane_verilog_wrap.sv b/openpiton/ariane_verilog_wrap.sv index 9c89abef9..dae3f281d 100644 --- a/openpiton/ariane_verilog_wrap.sv +++ b/openpiton/ariane_verilog_wrap.sv @@ -8,7 +8,7 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. // -// Author: Michael Schaffner, ETH Zurich +// Author: Michael Schaffner , ETH Zurich // Date: 19.03.2017 // Description: Ariane Top-level wrapper to break out SV structs to logic vectors. diff --git a/src/cache_subsystem/serpent_cache_subsystem.sv b/src/cache_subsystem/serpent_cache_subsystem.sv index 04e0c2b38..0505ecd43 100644 --- a/src/cache_subsystem/serpent_cache_subsystem.sv +++ b/src/cache_subsystem/serpent_cache_subsystem.sv @@ -1,19 +1,14 @@ -// Copyright (c) 2018 ETH Zurich, University of Bologna -// All rights reserved. +// 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. // -// 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. -// -// Author: Florian Zaruba , ETH Zurich -// Michael Schaffner , ETH Zurich +// Author: Michael Schaffner , ETH Zurich // Date: 15.08.2018 // Description: Ariane cache subsystem that is compatible with the OpenPiton // coherent memory system. diff --git a/src/cache_subsystem/serpent_icache.sv b/src/cache_subsystem/serpent_icache.sv index 461a746aa..925fa1c0f 100644 --- a/src/cache_subsystem/serpent_icache.sv +++ b/src/cache_subsystem/serpent_icache.sv @@ -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: Michael Schaffner , ETH Zurich // Date: 15.08.2018 diff --git a/src/cache_subsystem/serpent_l15_adapter.sv b/src/cache_subsystem/serpent_l15_adapter.sv index 925427134..7f8f77c6f 100644 --- a/src/cache_subsystem/serpent_l15_adapter.sv +++ b/src/cache_subsystem/serpent_l15_adapter.sv @@ -1,18 +1,14 @@ -// Copyright (c) 2018 ETH Zurich, University of Bologna -// All rights reserved. +// 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. // -// 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. -// -// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich +// Author: Michael Schaffner , 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. diff --git a/src/serdiv.sv b/src/serdiv.sv index 67ca5ef97..d71baf202 100644 --- a/src/serdiv.sv +++ b/src/serdiv.sv @@ -8,8 +8,8 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. // -// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich -// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich +// Author: Michael Schaffner , ETH Zurich +// Andreas Traber , ETH Zurich // // Date: 18.10.2018 // Description: simple 64bit serial divider @@ -17,61 +17,61 @@ import ariane_pkg::*; module serdiv #( - parameter WIDTH = 64 -)( - input logic clk_i, - input logic rst_ni, - // input IF - input logic [TRANS_ID_BITS-1:0] id_i, - input logic [WIDTH-1:0] op_a_i, - input logic [WIDTH-1:0] op_b_i, - input logic [1:0] opcode_i, // 0: udiv, 2: urem, 1: div, 3: rem - // handshake - input logic in_vld_i, // there is a cycle delay from in_rdy_o->in_vld_i, see issue_read_operands.sv stage - output logic in_rdy_o, - input logic flush_i, - // output IF - output logic out_vld_o, - input logic out_rdy_i, - output logic [TRANS_ID_BITS-1:0] id_o, - output logic [WIDTH-1:0] res_o + parameter WIDTH = 64 +) ( + input logic clk_i, + input logic rst_ni, + // input IF + input logic [TRANS_ID_BITS-1:0] id_i, + input logic [WIDTH-1:0] op_a_i, + input logic [WIDTH-1:0] op_b_i, + input logic [1:0] opcode_i, // 0: udiv, 2: urem, 1: div, 3: rem + // handshake + input logic in_vld_i, // there is a cycle delay from in_rdy_o->in_vld_i, see issue_read_operands.sv stage + output logic in_rdy_o, + input logic flush_i, + // output IF + output logic out_vld_o, + input logic out_rdy_i, + output logic [TRANS_ID_BITS-1:0] id_o, + output logic [WIDTH-1:0] res_o ); ///////////////////////////////////// // signal declarations ///////////////////////////////////// - enum logic [1:0] {IDLE, DIVIDE, FINISH} state_d, state_q; + enum logic [1:0] {IDLE, DIVIDE, FINISH} state_d, state_q; - logic [WIDTH-1:0] res_q, res_d; - logic [WIDTH-1:0] op_a_q, op_a_d; - logic [WIDTH-1:0] op_b_q, op_b_d; - logic op_a_sign, op_b_sign; - logic op_b_zero, op_b_zero_q, op_b_zero_d; + logic [WIDTH-1:0] res_q, res_d; + logic [WIDTH-1:0] op_a_q, op_a_d; + logic [WIDTH-1:0] op_b_q, op_b_d; + logic op_a_sign, op_b_sign; + logic op_b_zero, op_b_zero_q, op_b_zero_d; - logic [TRANS_ID_BITS-1:0] id_q, id_d; + logic [TRANS_ID_BITS-1:0] id_q, id_d; - logic rem_sel_d, rem_sel_q; - logic comp_inv_d, comp_inv_q; - logic res_inv_d, res_inv_q; + logic rem_sel_d, rem_sel_q; + logic comp_inv_d, comp_inv_q; + logic res_inv_d, res_inv_q; - logic [WIDTH-1:0] add_mux; - logic [WIDTH-1:0] add_out; - logic [WIDTH-1:0] add_tmp; - logic [WIDTH-1:0] b_mux; - logic [WIDTH-1:0] out_mux; + logic [WIDTH-1:0] add_mux; + logic [WIDTH-1:0] add_out; + logic [WIDTH-1:0] add_tmp; + logic [WIDTH-1:0] b_mux; + logic [WIDTH-1:0] out_mux; - logic [$clog2(WIDTH+1)-1:0] cnt_q, cnt_d; - logic cnt_zero; + logic [$clog2(WIDTH+1)-1:0] cnt_q, cnt_d; + logic cnt_zero; - logic [WIDTH-1:0] lzc_a_input, lzc_b_input, op_b; - logic [$clog2(WIDTH)-1:0] lzc_a_result, lzc_b_result; - logic [$clog2(WIDTH+1)-1:0] shift_a; - logic [$clog2(WIDTH+1):0] div_shift; + logic [WIDTH-1:0] lzc_a_input, lzc_b_input, op_b; + logic [$clog2(WIDTH)-1:0] lzc_a_result, lzc_b_result; + logic [$clog2(WIDTH+1)-1:0] shift_a; + logic [$clog2(WIDTH+1):0] div_shift; - logic a_reg_en, b_reg_en, res_reg_en, ab_comp, pm_sel, load_en; - logic lzc_a_no_one, lzc_b_no_one; - logic div_res_zero_d, div_res_zero_q; + logic a_reg_en, b_reg_en, res_reg_en, ab_comp, pm_sel, load_en; + logic lzc_a_no_one, lzc_b_no_one; + logic div_res_zero_d, div_res_zero_q; ///////////////////////////////////// @@ -79,180 +79,179 @@ module serdiv #( // for faster division ///////////////////////////////////// - assign op_b_zero = (op_b_i == 0); - assign op_a_sign = op_a_i[$high(op_a_i)]; - assign op_b_sign = op_b_i[$high(op_b_i)]; + assign op_b_zero = (op_b_i == 0); + assign op_a_sign = op_a_i[$high(op_a_i)]; + assign op_b_sign = op_b_i[$high(op_b_i)]; - assign lzc_a_input = (opcode_i[0] & op_a_sign) ? {~op_a_i, 1'b0} : op_a_i; - assign lzc_b_input = (opcode_i[0] & op_b_sign) ? ~op_b_i : op_b_i; + assign lzc_a_input = (opcode_i[0] & op_a_sign) ? {~op_a_i, 1'b0} : op_a_i; + assign lzc_b_input = (opcode_i[0] & op_b_sign) ? ~op_b_i : op_b_i; - lzc #( - .MODE ( 1 ), // count leading zeros - .WIDTH ( WIDTH ) - ) i_lzc_a ( - .in_i ( lzc_a_input ), - .cnt_o ( lzc_a_result ), - .empty_o ( lzc_a_no_one ) - ); + lzc #( + .MODE ( 1 ), // count leading zeros + .WIDTH ( WIDTH ) + ) i_lzc_a ( + .in_i ( lzc_a_input ), + .cnt_o ( lzc_a_result ), + .empty_o ( lzc_a_no_one ) + ); - lzc #( - .MODE ( 1 ), // count leading zeros - .WIDTH ( WIDTH ) - ) i_lzc_b ( - .in_i ( lzc_b_input ), - .cnt_o ( lzc_b_result ), - .empty_o ( lzc_b_no_one ) - ); + lzc #( + .MODE ( 1 ), // count leading zeros + .WIDTH ( WIDTH ) + ) i_lzc_b ( + .in_i ( lzc_b_input ), + .cnt_o ( lzc_b_result ), + .empty_o ( lzc_b_no_one ) + ); - assign shift_a = (lzc_a_no_one) ? WIDTH : lzc_a_result; - assign div_shift = (lzc_b_no_one) ? WIDTH : lzc_b_result-shift_a; + assign shift_a = (lzc_a_no_one) ? WIDTH : lzc_a_result; + assign div_shift = (lzc_b_no_one) ? WIDTH : lzc_b_result-shift_a; - assign op_b = op_b_i <<< $unsigned(div_shift); + assign op_b = op_b_i <<< $unsigned(div_shift); - // the division is zero if |opB| > |opA| and can be terminated - assign div_res_zero_d = (load_en) ? ($signed(div_shift) < 0) : div_res_zero_q; + // the division is zero if |opB| > |opA| and can be terminated + assign div_res_zero_d = (load_en) ? ($signed(div_shift) < 0) : div_res_zero_q; ///////////////////////////////////// // Datapath ///////////////////////////////////// - assign pm_sel = load_en & ~(opcode_i[0] & (op_a_sign ^ op_b_sign)); + assign pm_sel = load_en & ~(opcode_i[0] & (op_a_sign ^ op_b_sign)); - // muxes - assign add_mux = (load_en) ? op_a_i : op_b_q; + // muxes + assign add_mux = (load_en) ? op_a_i : op_b_q; - // attention: logical shift by one in case of negative operand B! - assign b_mux = (load_en) ? op_b : {comp_inv_q, (op_b_q[$high(op_b_q):1])}; + // attention: logical shift by one in case of negative operand B! + assign b_mux = (load_en) ? op_b : {comp_inv_q, (op_b_q[$high(op_b_q):1])}; - // in case of bad timing, we could output from regs -> needs a cycle more in the FSM - assign out_mux = (rem_sel_q) ? op_a_q : res_q; - // assign out_mux = (rem_sel_q) ? op_a_d : res_d; + // in case of bad timing, we could output from regs -> needs a cycle more in the FSM + assign out_mux = (rem_sel_q) ? op_a_q : res_q; + // assign out_mux = (rem_sel_q) ? op_a_d : res_d; - // invert if necessary - assign res_o = (res_inv_q) ? -$signed(out_mux) : out_mux; + // invert if necessary + assign res_o = (res_inv_q) ? -$signed(out_mux) : out_mux; - // main comparator - assign ab_comp = ((op_a_q == op_b_q) | ((op_a_q > op_b_q) ^ comp_inv_q)) & ((|op_a_q) | op_b_zero_q); + // main comparator + assign ab_comp = ((op_a_q == op_b_q) | ((op_a_q > op_b_q) ^ comp_inv_q)) & ((|op_a_q) | op_b_zero_q); - // main adder - assign add_tmp = (load_en) ? 0 : op_a_q; - assign add_out = (pm_sel) ? add_tmp + add_mux : add_tmp - $signed(add_mux); + // main adder + assign add_tmp = (load_en) ? 0 : op_a_q; + assign add_out = (pm_sel) ? add_tmp + add_mux : add_tmp - $signed(add_mux); ///////////////////////////////////// // FSM, counter ///////////////////////////////////// - assign cnt_zero = (cnt_q == 0); - assign cnt_d = (load_en) ? div_shift : - (~cnt_zero) ? cnt_q - 1 : cnt_q; + assign cnt_zero = (cnt_q == 0); + assign cnt_d = (load_en) ? div_shift : + (~cnt_zero) ? cnt_q - 1 : cnt_q; - always_comb begin : p_fsm - // default - state_d = state_q; - in_rdy_o = 1'b0; - out_vld_o = 1'b0; - load_en = 1'b0; - a_reg_en = 1'b0; - b_reg_en = 1'b0; - res_reg_en = 1'b0; + always_comb begin : p_fsm + // default + state_d = state_q; + in_rdy_o = 1'b0; + out_vld_o = 1'b0; + load_en = 1'b0; + a_reg_en = 1'b0; + b_reg_en = 1'b0; + res_reg_en = 1'b0; - unique case (state_q) - IDLE: begin - in_rdy_o = 1'b1; + unique case (state_q) + IDLE: begin + in_rdy_o = 1'b1; - if (in_vld_i) begin - in_rdy_o = 1'b0;// there is a cycle delay until the valid signal is asserted by the id stage - a_reg_en = 1'b1; - b_reg_en = 1'b1; - load_en = 1'b1; - state_d = DIVIDE; - end - end - DIVIDE: begin - if(~div_res_zero_q) begin - a_reg_en = ab_comp; - b_reg_en = 1'b1; - res_reg_en = 1'b1; - end - // can end the division now if the result is clearly 0 - if(div_res_zero_q) begin - out_vld_o = 1'b1; - state_d = FINISH; - if(out_rdy_i) begin - // in_rdy_o = 1'b1;// there is a cycle delay until the valid signal is asserted by the id stage - state_d = IDLE; - end - end else if (cnt_zero) begin - state_d = FINISH; - end - end - FINISH: begin - out_vld_o = 1'b1; - - if (out_rdy_i) begin - // in_rdy_o = 1'b1;// there is a cycle delay until the valid signal is asserted by the id stage - state_d = IDLE; - end - end - default : state_d = IDLE; - endcase - - if (flush_i) begin - in_rdy_o = 1'b0; - out_vld_o = 1'b0; - a_reg_en = 1'b0; - b_reg_en = 1'b0; - load_en = 1'b0; - state_d = IDLE; - end + if (in_vld_i) begin + in_rdy_o = 1'b0;// there is a cycle delay until the valid signal is asserted by the id stage + a_reg_en = 1'b1; + b_reg_en = 1'b1; + load_en = 1'b1; + state_d = DIVIDE; end + end + DIVIDE: begin + if(~div_res_zero_q) begin + a_reg_en = ab_comp; + b_reg_en = 1'b1; + res_reg_en = 1'b1; + end + // can end the division now if the result is clearly 0 + if(div_res_zero_q) begin + out_vld_o = 1'b1; + state_d = FINISH; + if(out_rdy_i) begin + // in_rdy_o = 1'b1;// there is a cycle delay until the valid signal is asserted by the id stage + state_d = IDLE; + end + end else if (cnt_zero) begin + state_d = FINISH; + end + end + FINISH: begin + out_vld_o = 1'b1; + if (out_rdy_i) begin + // in_rdy_o = 1'b1;// there is a cycle delay until the valid signal is asserted by the id stage + state_d = IDLE; + end + end + default : state_d = IDLE; + endcase + + if (flush_i) begin + in_rdy_o = 1'b0; + out_vld_o = 1'b0; + a_reg_en = 1'b0; + b_reg_en = 1'b0; + load_en = 1'b0; + state_d = IDLE; + end + end ///////////////////////////////////// // regs, flags ///////////////////////////////////// - // get flags - assign rem_sel_d = (load_en) ? opcode_i[1] : rem_sel_q; - assign comp_inv_d = (load_en) ? opcode_i[0] & op_b_sign : comp_inv_q; - assign op_b_zero_d = (load_en) ? op_b_zero : op_b_zero_q; - assign res_inv_d = (load_en) ? (~op_b_zero | opcode_i[1]) & opcode_i[0] & (op_a_sign ^ op_b_sign) : res_inv_q; + // get flags + assign rem_sel_d = (load_en) ? opcode_i[1] : rem_sel_q; + assign comp_inv_d = (load_en) ? opcode_i[0] & op_b_sign : comp_inv_q; + assign op_b_zero_d = (load_en) ? op_b_zero : op_b_zero_q; + assign res_inv_d = (load_en) ? (~op_b_zero | opcode_i[1]) & opcode_i[0] & (op_a_sign ^ op_b_sign) : res_inv_q; - // transaction id - assign id_d = (load_en) ? id_i : id_q; - assign id_o = id_q; + // transaction id + assign id_d = (load_en) ? id_i : id_q; + assign id_o = id_q; - assign op_a_d = (a_reg_en) ? add_out : op_a_q; - assign op_b_d = (b_reg_en) ? b_mux : op_b_q; - assign res_d = (load_en) ? '0 : - (res_reg_en) ? {res_q[$high(res_q)-1:0], ab_comp} : res_q; + assign op_a_d = (a_reg_en) ? add_out : op_a_q; + assign op_b_d = (b_reg_en) ? b_mux : op_b_q; + assign res_d = (load_en) ? '0 : + (res_reg_en) ? {res_q[$high(res_q)-1:0], ab_comp} : res_q; - always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs - if (~rst_ni) begin - state_q <= IDLE; - op_a_q <= '0; - op_b_q <= '0; - res_q <= '0; - cnt_q <= '0; - id_q <= '0; - rem_sel_q <= 1'b0; - comp_inv_q <= 1'b0; - res_inv_q <= 1'b0; - op_b_zero_q <= 1'b0; - div_res_zero_q <= 1'b0; - end else begin - state_q <= state_d; - op_a_q <= op_a_d; - op_b_q <= op_b_d; - res_q <= res_d; - cnt_q <= cnt_d; - id_q <= id_d; - rem_sel_q <= rem_sel_d; - comp_inv_q <= comp_inv_d; - res_inv_q <= res_inv_d; - op_b_zero_q <= op_b_zero_d; - div_res_zero_q <= div_res_zero_d; - end + always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs + if (~rst_ni) begin + state_q <= IDLE; + op_a_q <= '0; + op_b_q <= '0; + res_q <= '0; + cnt_q <= '0; + id_q <= '0; + rem_sel_q <= 1'b0; + comp_inv_q <= 1'b0; + res_inv_q <= 1'b0; + op_b_zero_q <= 1'b0; + div_res_zero_q <= 1'b0; + end else begin + state_q <= state_d; + op_a_q <= op_a_d; + op_b_q <= op_b_d; + res_q <= res_d; + cnt_q <= cnt_d; + id_q <= id_d; + rem_sel_q <= rem_sel_d; + comp_inv_q <= comp_inv_d; + res_inv_q <= res_inv_d; + op_b_zero_q <= op_b_zero_d; + div_res_zero_q <= div_res_zero_d; end + end endmodule \ No newline at end of file diff --git a/tb/tb_serdiv/hdl/tb.svh b/tb/common/tb.svh similarity index 100% rename from tb/tb_serdiv/hdl/tb.svh rename to tb/common/tb.svh diff --git a/tb/tb_serdiv/.gitignore b/tb/tb_serdiv/.gitignore new file mode 100644 index 000000000..f8cb65465 --- /dev/null +++ b/tb/tb_serdiv/.gitignore @@ -0,0 +1,7 @@ +work +*.rep +transcript +*.ini +*.wlf +*.log + diff --git a/tb/tb_serdiv/Makefile b/tb/tb_serdiv/Makefile index aaee6ad2f..8c5e4f5d4 100755 --- a/tb/tb_serdiv/Makefile +++ b/tb/tb_serdiv/Makefile @@ -1,16 +1,30 @@ +# 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: Michael Schaffner , ETH Zurich +# Date: 15.08.2018 +# Description: Makefile for the serial divider testbench. + library ?= work toplevel ?= tb src-list := tb.list inc-path := $(shell pwd)/hdl/ src := $(shell xargs printf '\n%s' < $(src-list) | cut -b 1-) -compile_flag += +cover+i_dut -incr -64 -nologo +compile_flag += +cover+i_dut -incr -64 -nologo sim_opts += -64 -coverage -classdebug -voptargs="+acc" questa_version ?= ${QUESTASIM_VERSION} - +incdir += ../common/ build: clean vlib${questa_version} $(library) - vlog${questa_version} -work $(library) -pedanticerrors $(src) $(compile_flag) +incdir+$(inc-path) + vlog${questa_version} -work $(library) -pedanticerrors $(src) $(compile_flag) +incdir+$(incdir) touch $(library)/.build sim: build @@ -19,7 +33,7 @@ sim: build simc: build vsim${questa_version} -lib $(library) $(toplevel) -c -do "run -all; exit" $(sim_opts) - + clean: rm -rf $(library) diff --git a/tb/tb_serpent_dcache/.gitignore b/tb/tb_serpent_dcache/.gitignore index 0a96ce419..f8cb65465 100644 --- a/tb/tb_serpent_dcache/.gitignore +++ b/tb/tb_serpent_dcache/.gitignore @@ -1,3 +1,7 @@ work -modelsim.ini *.rep +transcript +*.ini +*.wlf +*.log + diff --git a/tb/tb_serpent_dcache/Makefile b/tb/tb_serpent_dcache/Makefile index aaee6ad2f..f50c9e254 100755 --- a/tb/tb_serpent_dcache/Makefile +++ b/tb/tb_serpent_dcache/Makefile @@ -1,25 +1,40 @@ +# 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: Michael Schaffner , ETH Zurich +# Date: 15.08.2018 +# Description: Makefile for the dcache testbench. + library ?= work toplevel ?= tb src-list := tb.list inc-path := $(shell pwd)/hdl/ src := $(shell xargs printf '\n%s' < $(src-list) | cut -b 1-) -compile_flag += +cover+i_dut -incr -64 -nologo +compile_flag += +cover+i_dut -incr -64 -nologo sim_opts += -64 -coverage -classdebug -voptargs="+acc" questa_version ?= ${QUESTASIM_VERSION} - +incdir += ../common/ build: clean vlib${questa_version} $(library) - vlog${questa_version} -work $(library) -pedanticerrors $(src) $(compile_flag) +incdir+$(inc-path) + vlog${questa_version} -work $(library) -pedanticerrors $(src) $(compile_flag) +incdir+$(incdir) touch $(library)/.build +# this starts modelsim with gui sim: build vsim${questa_version} -lib $(library) $(toplevel) -do "do wave.do" $(sim_opts) +# batch mode without gui simc: build vsim${questa_version} -lib $(library) $(toplevel) -c -do "run -all; exit" $(sim_opts) - clean: rm -rf $(library) diff --git a/tb/tb_serpent_dcache/hdl/tb.sv b/tb/tb_serpent_dcache/hdl/tb.sv index 9a0a4dd90..9c0a388e0 100644 --- a/tb/tb_serpent_dcache/hdl/tb.sv +++ b/tb/tb_serpent_dcache/hdl/tb.sv @@ -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: Michael Schaffner , ETH Zurich // Date: 15.08.2018 @@ -33,346 +29,346 @@ import tb_pkg::*; module tb; - // leave this - timeunit 1ps; - timeprecision 1ps; + // leave this + timeunit 1ps; + timeprecision 1ps; - // memory configuration (64bit words) - parameter MemBytes = 2**DCACHE_INDEX_WIDTH * 4 * 32; - parameter MemWords = MemBytes>>3; - // noncacheable portion - parameter logic [63:0] CachedAddrBeg = MemBytes>>3;//1/8th of the memory is NC - parameter logic [63:0] CachedAddrEnd = 64'hFFFF_FFFF_FFFF_FFFF; + // memory configuration (64bit words) + parameter MemBytes = 2**DCACHE_INDEX_WIDTH * 4 * 32; + parameter MemWords = MemBytes>>3; + // noncacheable portion + parameter logic [63:0] CachedAddrBeg = MemBytes>>3;//1/8th of the memory is NC + parameter logic [63:0] CachedAddrEnd = 64'hFFFF_FFFF_FFFF_FFFF; - // contention and invalidation rates (in %) - parameter MemRandHitRate = 75; - parameter MemRandInvRate = 10; - parameter TlbHitRate = 95; + // contention and invalidation rates (in %) + parameter MemRandHitRate = 75; + parameter MemRandInvRate = 10; + parameter TlbHitRate = 95; - // parameters for random read sequences (in %) - parameter FlushRate = 10; - parameter KillRate = 5; + // parameters for random read sequences (in %) + parameter FlushRate = 10; + parameter KillRate = 5; - parameter Verbose = 0; + parameter Verbose = 0; /////////////////////////////////////////////////////////////////////////////// // MUT signal declarations /////////////////////////////////////////////////////////////////////////////// - logic enable_i; - logic flush_i; - logic flush_ack_o; - logic miss_o; - logic wbuffer_empty_o; - amo_req_t amo_req_i; - amo_resp_t amo_resp_o; - dcache_req_i_t [2:0] req_ports_i; - dcache_req_o_t [2:0] req_ports_o; - logic mem_rtrn_vld_i; - dcache_rtrn_t mem_rtrn_i; - logic mem_data_req_o; - logic mem_data_ack_i; - dcache_req_t mem_data_o; + logic enable_i; + logic flush_i; + logic flush_ack_o; + logic miss_o; + logic wbuffer_empty_o; + amo_req_t amo_req_i; + amo_resp_t amo_resp_o; + dcache_req_i_t [2:0] req_ports_i; + dcache_req_o_t [2:0] req_ports_o; + logic mem_rtrn_vld_i; + dcache_rtrn_t mem_rtrn_i; + logic mem_data_req_o; + logic mem_data_ack_i; + dcache_req_t mem_data_o; /////////////////////////////////////////////////////////////////////////////// // TB signal declarations /////////////////////////////////////////////////////////////////////////////// - logic [63:0] mem_array[MemWords-1:0]; + logic [63:0] mem_array[MemWords-1:0]; - string test_name; - logic clk_i, rst_ni; - logic [31:0] seq_num_resp, seq_num_write; - seq_t [2:0] seq_type; - logic [2:0] seq_done; - logic [6:0] req_rate[2:0]; - logic seq_run, seq_last; - logic end_of_sim; + string test_name; + logic clk_i, rst_ni; + logic [31:0] seq_num_resp, seq_num_write; + seq_t [2:0] seq_type; + logic [2:0] seq_done; + logic [6:0] req_rate[2:0]; + logic seq_run, seq_last; + logic end_of_sim; - logic mem_rand_en; - logic inv_rand_en; - logic amo_rand_en; - logic tlb_rand_en; + logic mem_rand_en; + logic inv_rand_en; + logic amo_rand_en; + logic tlb_rand_en; - logic write_en; - logic [63:0] write_paddr, write_data; - logic [7:0] write_be; + logic write_en; + logic [63:0] write_paddr, write_data; + logic [7:0] write_be; - logic check_en; - logic [7:0] commit_be; - logic [63:0] commit_paddr; - logic commit_en; + logic check_en; + logic [7:0] commit_be; + logic [63:0] commit_paddr; + logic commit_en; - typedef struct packed { - logic [1:0] size; - logic [63:0] paddr; - } resp_fifo_t; + typedef struct packed { + logic [1:0] size; + logic [63:0] paddr; + } resp_fifo_t; - logic [63:0] act_paddr[1:0]; - logic [63:0] exp_rdata[1:0]; - logic [63:0] exp_paddr[1:0]; - resp_fifo_t fifo_data_in[1:0]; - resp_fifo_t fifo_data[1:0]; - logic [1:0] fifo_push, fifo_pop, fifo_flush; - logic [2:0] flush; - logic flush_rand_en; + logic [63:0] act_paddr[1:0]; + logic [63:0] exp_rdata[1:0]; + logic [63:0] exp_paddr[1:0]; + resp_fifo_t fifo_data_in[1:0]; + resp_fifo_t fifo_data[1:0]; + logic [1:0] fifo_push, fifo_pop, fifo_flush; + logic [2:0] flush; + logic flush_rand_en; /////////////////////////////////////////////////////////////////////////////// // helper tasks /////////////////////////////////////////////////////////////////////////////// - task automatic runSeq(input int nReadVectors, input int nWriteVectors = 0, input logic last =1'b0); - seq_last = last; - seq_run = 1'b1; - seq_num_resp = nReadVectors; - seq_num_write = nWriteVectors; - `APPL_WAIT_CYC(clk_i,1) - seq_run = 1'b0; - `APPL_WAIT_SIG(clk_i, &seq_done) - `APPL_WAIT_CYC(clk_i,1) - endtask : runSeq + task automatic runSeq(input int nReadVectors, input int nWriteVectors = 0, input logic last =1'b0); + seq_last = last; + seq_run = 1'b1; + seq_num_resp = nReadVectors; + seq_num_write = nWriteVectors; + `APPL_WAIT_CYC(clk_i,1) + seq_run = 1'b0; + `APPL_WAIT_SIG(clk_i, &seq_done) + `APPL_WAIT_CYC(clk_i,1) + endtask : runSeq - task automatic flushCache(); - flush[2] = 1'b1; - `APPL_WAIT_SIG(clk_i, flush_ack_o); - flush[2] = 0'b0; - `APPL_WAIT_CYC(clk_i,1) - endtask : flushCache + task automatic flushCache(); + flush[2] = 1'b1; + `APPL_WAIT_SIG(clk_i, flush_ack_o); + flush[2] = 0'b0; + `APPL_WAIT_CYC(clk_i,1) + endtask : flushCache - task automatic memCheck(); - check_en = 1'b1; - `APPL_WAIT_CYC(clk_i,1) - check_en = 0'b0; - `APPL_WAIT_CYC(clk_i,1) - endtask : memCheck + task automatic memCheck(); + check_en = 1'b1; + `APPL_WAIT_CYC(clk_i,1) + check_en = 0'b0; + `APPL_WAIT_CYC(clk_i,1) + endtask : memCheck /////////////////////////////////////////////////////////////////////////////// // Clock Process /////////////////////////////////////////////////////////////////////////////// - always @* - begin - do begin - clk_i = 1;#(CLK_HI); - clk_i = 0;#(CLK_LO); - end while (end_of_sim == 1'b0); - repeat (100) begin - // generate a few extra cycle to allow - // response acquisition to complete - clk_i = 1;#(CLK_HI); - clk_i = 0;#(CLK_LO); - end - end + always @* + begin + do begin + clk_i = 1;#(CLK_HI); + clk_i = 0;#(CLK_LO); + end while (end_of_sim == 1'b0); + repeat (100) begin + // generate a few extra cycle to allow + // response acquisition to complete + clk_i = 1;#(CLK_HI); + clk_i = 0;#(CLK_LO); + end + end /////////////////////////////////////////////////////////////////////////////// // memory emulation /////////////////////////////////////////////////////////////////////////////// - tb_mem #( - .MemRandHitRate ( MemRandHitRate ), - .MemRandInvRate ( MemRandInvRate ), - .MemWords ( MemWords ), - .CachedAddrBeg ( CachedAddrBeg ), - .CachedAddrEnd ( CachedAddrEnd ) - ) i_tb_mem ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .mem_rand_en_i ( mem_rand_en ), - .inv_rand_en_i ( inv_rand_en ), - .amo_rand_en_i ( amo_rand_en ), - .mem_data_req_i ( mem_data_req_o ), - .mem_data_ack_o ( mem_data_ack_i ), - .mem_data_i ( mem_data_o ), - .mem_rtrn_vld_o ( mem_rtrn_vld_i ), - .mem_rtrn_o ( mem_rtrn_i ), - // for verification - .seq_last_i ( seq_last ), - .check_en_i ( check_en ), - .commit_en_i ( commit_en ), - .commit_be_i ( commit_be ), - .commit_paddr_i ( commit_paddr ), - .write_en_i ( write_en ), - .write_be_i ( write_be ), - .write_data_i ( write_data ), - .write_paddr_i ( write_paddr ), - .mem_array_o ( mem_array ) - ); + tb_mem #( + .MemRandHitRate ( MemRandHitRate ), + .MemRandInvRate ( MemRandInvRate ), + .MemWords ( MemWords ), + .CachedAddrBeg ( CachedAddrBeg ), + .CachedAddrEnd ( CachedAddrEnd ) + ) i_tb_mem ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .mem_rand_en_i ( mem_rand_en ), + .inv_rand_en_i ( inv_rand_en ), + .amo_rand_en_i ( amo_rand_en ), + .mem_data_req_i ( mem_data_req_o ), + .mem_data_ack_o ( mem_data_ack_i ), + .mem_data_i ( mem_data_o ), + .mem_rtrn_vld_o ( mem_rtrn_vld_i ), + .mem_rtrn_o ( mem_rtrn_i ), + // for verification + .seq_last_i ( seq_last ), + .check_en_i ( check_en ), + .commit_en_i ( commit_en ), + .commit_be_i ( commit_be ), + .commit_paddr_i ( commit_paddr ), + .write_en_i ( write_en ), + .write_be_i ( write_be ), + .write_data_i ( write_data ), + .write_paddr_i ( write_paddr ), + .mem_array_o ( mem_array ) + ); /////////////////////////////////////////////////////////////////////////////// // MUT /////////////////////////////////////////////////////////////////////////////// - serpent_dcache #( - .CachedAddrBeg ( CachedAddrBeg ), - .CachedAddrEnd ( CachedAddrEnd ) - ) i_dut ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .flush_i ( flush_i ), - .flush_ack_o ( flush_ack_o ), - .enable_i ( enable_i ), - .miss_o ( miss_o ), - .wbuffer_empty_o ( wbuffer_empty_o ), - .amo_req_i ( amo_req_i ), - .amo_resp_o ( amo_resp_o ), - .req_ports_i ( req_ports_i ), - .req_ports_o ( req_ports_o ), - .mem_rtrn_vld_i ( mem_rtrn_vld_i ), - .mem_rtrn_i ( mem_rtrn_i ), - .mem_data_req_o ( mem_data_req_o ), - .mem_data_ack_i ( mem_data_ack_i ), - .mem_data_o ( mem_data_o ) - ); + serpent_dcache #( + .CachedAddrBeg ( CachedAddrBeg ), + .CachedAddrEnd ( CachedAddrEnd ) + ) i_dut ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .flush_i ( flush_i ), + .flush_ack_o ( flush_ack_o ), + .enable_i ( enable_i ), + .miss_o ( miss_o ), + .wbuffer_empty_o ( wbuffer_empty_o ), + .amo_req_i ( amo_req_i ), + .amo_resp_o ( amo_resp_o ), + .req_ports_i ( req_ports_i ), + .req_ports_o ( req_ports_o ), + .mem_rtrn_vld_i ( mem_rtrn_vld_i ), + .mem_rtrn_i ( mem_rtrn_i ), + .mem_data_req_o ( mem_data_req_o ), + .mem_data_ack_i ( mem_data_ack_i ), + .mem_data_o ( mem_data_o ) + ); /////////////////////////////////////////////////////////////////////////////// // port emulation programs /////////////////////////////////////////////////////////////////////////////// - // get actual paddr from read controllers - assign act_paddr[0] = {i_dut.genblk1[0].i_serpent_dcache_ctrl.address_tag_d, - i_dut.genblk1[0].i_serpent_dcache_ctrl.address_idx_q, - i_dut.genblk1[0].i_serpent_dcache_ctrl.address_off_q}; - assign act_paddr[1] = {i_dut.genblk1[1].i_serpent_dcache_ctrl.address_tag_d, - i_dut.genblk1[1].i_serpent_dcache_ctrl.address_idx_q, - i_dut.genblk1[1].i_serpent_dcache_ctrl.address_off_q}; + // get actual paddr from read controllers + assign act_paddr[0] = {i_dut.genblk1[0].i_serpent_dcache_ctrl.address_tag_d, + i_dut.genblk1[0].i_serpent_dcache_ctrl.address_idx_q, + i_dut.genblk1[0].i_serpent_dcache_ctrl.address_off_q}; + assign act_paddr[1] = {i_dut.genblk1[1].i_serpent_dcache_ctrl.address_tag_d, + i_dut.genblk1[1].i_serpent_dcache_ctrl.address_idx_q, + i_dut.genblk1[1].i_serpent_dcache_ctrl.address_off_q}; - // generate fifo queues for expected responses - generate - for(genvar k=0; k<2;k++) begin - assign fifo_data_in[k] = {req_ports_i[k].data_size, - exp_paddr[k]}; + // generate fifo queues for expected responses + generate + for(genvar k=0; k<2;k++) begin + assign fifo_data_in[k] = {req_ports_i[k].data_size, + exp_paddr[k]}; - assign exp_rdata[k] = mem_array[fifo_data[k].paddr>>3]; - assign fifo_push[k] = req_ports_i[k].data_req & req_ports_o[k].data_gnt; - assign fifo_flush[k] = req_ports_i[k].kill_req; - assign fifo_pop[k] = req_ports_o[k].data_rvalid; + assign exp_rdata[k] = mem_array[fifo_data[k].paddr>>3]; + assign fifo_push[k] = req_ports_i[k].data_req & req_ports_o[k].data_gnt; + assign fifo_flush[k] = req_ports_i[k].kill_req; + assign fifo_pop[k] = req_ports_o[k].data_rvalid; - fifo_v2 #( - .dtype(resp_fifo_t) - ) i_resp_fifo ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .flush_i ( fifo_flush[k] ), - .testmode_i ( '0 ), - .full_o ( ), - .empty_o ( ), - .alm_full_o ( ), - .alm_empty_o ( ), - .data_i ( fifo_data_in[k] ), - .push_i ( fifo_push[k] ), - .data_o ( fifo_data[k] ), - .pop_i ( fifo_pop[k] ) - ); - end - endgenerate + fifo_v2 #( + .dtype(resp_fifo_t) + ) i_resp_fifo ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .flush_i ( fifo_flush[k] ), + .testmode_i ( '0 ), + .full_o ( ), + .empty_o ( ), + .alm_full_o ( ), + .alm_empty_o ( ), + .data_i ( fifo_data_in[k] ), + .push_i ( fifo_push[k] ), + .data_o ( fifo_data[k] ), + .pop_i ( fifo_pop[k] ) + ); + end + endgenerate - tb_readport #( - .PortName ( "RD0" ), - .FlushRate ( FlushRate ), - .KillRate ( KillRate ), - .TlbHitRate ( TlbHitRate ), - .MemWords ( MemWords ), - .CachedAddrBeg ( CachedAddrBeg ), - .CachedAddrEnd ( CachedAddrEnd ), - .RndSeed ( 5555555 ), - .Verbose ( Verbose ) - ) i_tb_readport0 ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .test_name_i ( test_name ), - .req_rate_i ( req_rate[0] ), - .seq_type_i ( seq_type[0] ), - .tlb_rand_en_i ( tlb_rand_en ), - .flush_rand_en_i ( flush_rand_en ), - .seq_run_i ( seq_run ), - .seq_num_resp_i ( seq_num_resp ), - .seq_last_i ( seq_last ), - .seq_done_o ( seq_done[0] ), - .exp_paddr_o ( exp_paddr[0] ), - .exp_size_i ( fifo_data[0].size ), - .exp_paddr_i ( fifo_data[0].paddr ), - .exp_rdata_i ( exp_rdata[0] ), - .act_paddr_i ( act_paddr[0] ), - .flush_o ( flush[0] ), - .flush_ack_i ( flush_ack_o ), - .dut_req_port_o ( req_ports_i[0] ), - .dut_req_port_i ( req_ports_o[0] ) - ); + tb_readport #( + .PortName ( "RD0" ), + .FlushRate ( FlushRate ), + .KillRate ( KillRate ), + .TlbHitRate ( TlbHitRate ), + .MemWords ( MemWords ), + .CachedAddrBeg ( CachedAddrBeg ), + .CachedAddrEnd ( CachedAddrEnd ), + .RndSeed ( 5555555 ), + .Verbose ( Verbose ) + ) i_tb_readport0 ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .test_name_i ( test_name ), + .req_rate_i ( req_rate[0] ), + .seq_type_i ( seq_type[0] ), + .tlb_rand_en_i ( tlb_rand_en ), + .flush_rand_en_i ( flush_rand_en ), + .seq_run_i ( seq_run ), + .seq_num_resp_i ( seq_num_resp ), + .seq_last_i ( seq_last ), + .seq_done_o ( seq_done[0] ), + .exp_paddr_o ( exp_paddr[0] ), + .exp_size_i ( fifo_data[0].size ), + .exp_paddr_i ( fifo_data[0].paddr ), + .exp_rdata_i ( exp_rdata[0] ), + .act_paddr_i ( act_paddr[0] ), + .flush_o ( flush[0] ), + .flush_ack_i ( flush_ack_o ), + .dut_req_port_o ( req_ports_i[0] ), + .dut_req_port_i ( req_ports_o[0] ) + ); - tb_readport #( - .PortName ( "RD1" ), - .FlushRate ( FlushRate ), - .KillRate ( KillRate ), - .TlbHitRate ( TlbHitRate ), - .MemWords ( MemWords ), - .CachedAddrBeg ( CachedAddrBeg ), - .CachedAddrEnd ( CachedAddrEnd ), - .RndSeed ( 3333333 ), - .Verbose ( Verbose ) - ) i_tb_readport1 ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .test_name_i ( test_name ), - .req_rate_i ( req_rate[1] ), - .seq_type_i ( seq_type[1] ), - .tlb_rand_en_i ( tlb_rand_en ), - .flush_rand_en_i ( flush_rand_en ), - .seq_run_i ( seq_run ), - .seq_num_resp_i ( seq_num_resp ), - .seq_last_i ( seq_last ), - .exp_paddr_o ( exp_paddr[1] ), - .exp_size_i ( fifo_data[1].size ), - .exp_paddr_i ( fifo_data[1].paddr ), - .exp_rdata_i ( exp_rdata[1] ), - .act_paddr_i ( act_paddr[1] ), - .seq_done_o ( seq_done[1] ), - .flush_o ( flush[1] ), - .flush_ack_i ( flush_ack_o ), - .dut_req_port_o ( req_ports_i[1] ), - .dut_req_port_i ( req_ports_o[1] ) - ); + tb_readport #( + .PortName ( "RD1" ), + .FlushRate ( FlushRate ), + .KillRate ( KillRate ), + .TlbHitRate ( TlbHitRate ), + .MemWords ( MemWords ), + .CachedAddrBeg ( CachedAddrBeg ), + .CachedAddrEnd ( CachedAddrEnd ), + .RndSeed ( 3333333 ), + .Verbose ( Verbose ) + ) i_tb_readport1 ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .test_name_i ( test_name ), + .req_rate_i ( req_rate[1] ), + .seq_type_i ( seq_type[1] ), + .tlb_rand_en_i ( tlb_rand_en ), + .flush_rand_en_i ( flush_rand_en ), + .seq_run_i ( seq_run ), + .seq_num_resp_i ( seq_num_resp ), + .seq_last_i ( seq_last ), + .exp_paddr_o ( exp_paddr[1] ), + .exp_size_i ( fifo_data[1].size ), + .exp_paddr_i ( fifo_data[1].paddr ), + .exp_rdata_i ( exp_rdata[1] ), + .act_paddr_i ( act_paddr[1] ), + .seq_done_o ( seq_done[1] ), + .flush_o ( flush[1] ), + .flush_ack_i ( flush_ack_o ), + .dut_req_port_o ( req_ports_i[1] ), + .dut_req_port_i ( req_ports_o[1] ) + ); - tb_writeport #( - .PortName ( "WR0" ), - .MemWords ( MemWords ), - .CachedAddrBeg ( CachedAddrBeg ), - .CachedAddrEnd ( CachedAddrEnd ), - .RndSeed ( 7777777 ), - .Verbose ( Verbose ) - ) i_tb_writeport ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .test_name_i ( test_name ), - .req_rate_i ( req_rate[2] ), - .seq_type_i ( seq_type[2] ), - .seq_run_i ( seq_run ), - .seq_num_vect_i ( seq_num_write ), - .seq_last_i ( seq_last ), - .seq_done_o ( seq_done[2] ), - .dut_req_port_o ( req_ports_i[2] ), - .dut_req_port_i ( req_ports_o[2] ) - ); + tb_writeport #( + .PortName ( "WR0" ), + .MemWords ( MemWords ), + .CachedAddrBeg ( CachedAddrBeg ), + .CachedAddrEnd ( CachedAddrEnd ), + .RndSeed ( 7777777 ), + .Verbose ( Verbose ) + ) i_tb_writeport ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .test_name_i ( test_name ), + .req_rate_i ( req_rate[2] ), + .seq_type_i ( seq_type[2] ), + .seq_run_i ( seq_run ), + .seq_num_vect_i ( seq_num_write ), + .seq_last_i ( seq_last ), + .seq_done_o ( seq_done[2] ), + .dut_req_port_o ( req_ports_i[2] ), + .dut_req_port_i ( req_ports_o[2] ) + ); - assign write_en = req_ports_i[2].data_req & req_ports_o[2].data_gnt & req_ports_i[2].data_we; - assign write_paddr = {req_ports_i[2].address_tag, req_ports_i[2].address_index}; - assign write_data = req_ports_i[2].data_wdata; - assign write_be = req_ports_i[2].data_be; + assign write_en = req_ports_i[2].data_req & req_ports_o[2].data_gnt & req_ports_i[2].data_we; + assign write_paddr = {req_ports_i[2].address_tag, req_ports_i[2].address_index}; + assign write_data = req_ports_i[2].data_wdata; + assign write_be = req_ports_i[2].data_be; - // generate write buffer commit signals based on internal eviction status - assign commit_be = i_dut.i_serpent_dcache_wbuffer.wr_data_be_o; - assign commit_paddr = i_dut.i_serpent_dcache_wbuffer.wr_paddr; - assign commit_en = i_dut.i_serpent_dcache_wbuffer.evict; + // generate write buffer commit signals based on internal eviction status + assign commit_be = i_dut.i_serpent_dcache_wbuffer.wr_data_be_o; + assign commit_paddr = i_dut.i_serpent_dcache_wbuffer.wr_paddr; + assign commit_en = i_dut.i_serpent_dcache_wbuffer.evict; - // TODO: implement AMO agent - assign amo_req_i.req = '0; - assign amo_req_i.amo_op = AMO_NONE; - assign amo_req_i.size = '0; - assign amo_req_i.operand_a = '0; - assign amo_req_i.operand_b = '0; - // amo_resp_o + // TODO: implement AMO agent + assign amo_req_i.req = '0; + assign amo_req_i.amo_op = AMO_NONE; + assign amo_req_i.size = '0; + assign amo_req_i.operand_a = '0; + assign amo_req_i.operand_b = '0; + // amo_resp_o - assign flush_i = |flush; + assign flush_i = |flush; /////////////////////////////////////////////////////////////////////////////// // simulation coordinator process @@ -382,244 +378,244 @@ module tb; // flush_i, flush_ack_o, enable_i, miss_o, wbuffer_empty_o - initial begin : p_stim - test_name = ""; - seq_type = '{default: RANDOM_SEQ}; - req_rate = '{default: 7'd75}; - seq_run = 1'b0; - seq_last = 1'b0; - seq_num_resp = '0; - seq_num_write = '0; - check_en = '0; - // seq_done - end_of_sim = 0; - rst_ni = 0; - // randomization settings - mem_rand_en = 0; - tlb_rand_en = 0; - inv_rand_en = 0; - amo_rand_en = 0; - flush_rand_en = 0; - // cache ctrl - flush[2] = 0; - // flush_ack_o - // wbuffer_empty_o - enable_i = 0; - // miss_o + initial begin : p_stim + test_name = ""; + seq_type = '{default: RANDOM_SEQ}; + req_rate = '{default: 7'd75}; + seq_run = 1'b0; + seq_last = 1'b0; + seq_num_resp = '0; + seq_num_write = '0; + check_en = '0; + // seq_done + end_of_sim = 0; + rst_ni = 0; + // randomization settings + mem_rand_en = 0; + tlb_rand_en = 0; + inv_rand_en = 0; + amo_rand_en = 0; + flush_rand_en = 0; + // cache ctrl + flush[2] = 0; + // flush_ack_o + // wbuffer_empty_o + enable_i = 0; + // miss_o - // print some info - $display("TB> current configuration:"); - $display("TB> MemWords %d", MemWords); - $display("TB> CachedAddrBeg %16X", CachedAddrBeg); - $display("TB> CachedAddrEnd %16X", CachedAddrEnd); - $display("TB> MemRandHitRate %d", MemRandHitRate); - $display("TB> MemRandInvRate %d", MemRandInvRate); + // print some info + $display("TB> current configuration:"); + $display("TB> MemWords %d", MemWords); + $display("TB> CachedAddrBeg %16X", CachedAddrBeg); + $display("TB> CachedAddrEnd %16X", CachedAddrEnd); + $display("TB> MemRandHitRate %d", MemRandHitRate); + $display("TB> MemRandInvRate %d", MemRandInvRate); - // reset cycles - `APPL_WAIT_CYC(clk_i,100) - rst_ni = 1'b1; - `APPL_WAIT_CYC(clk_i,100) + // reset cycles + `APPL_WAIT_CYC(clk_i,100) + rst_ni = 1'b1; + `APPL_WAIT_CYC(clk_i,100) - $display("TB> start with test sequences"); - // apply each test until seq_num_resp memory - // requests have successfully completed - /////////////////////////////////////////////// - test_name = "TEST 0 -- random read -- disabled cache"; - // config - enable_i = 0; - seq_type = '{default: RANDOM_SEQ}; - req_rate = '{default: 7'd50}; - runSeq(10000); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 1 -- sequential read -- disabled cache"; - // config - enable_i = 0; - seq_type = '{default: LINEAR_SEQ}; - req_rate = '{default: 7'd50}; - runSeq(10000); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 2 -- random read -- enabled cache"; - // config - enable_i = 1; - seq_type = '{default: RANDOM_SEQ}; - req_rate = '{default: 7'd50}; - runSeq(10000); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 3 -- linear read -- enabled cache"; - // config - enable_i = 1; - seq_type = '{default: LINEAR_SEQ}; - req_rate = '{default: 7'd50}; - runSeq(10000); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 4 -- random read -- enabled cache + tlb, mem contentions"; - // config - enable_i = 1; - tlb_rand_en = 1; - mem_rand_en = 1; - seq_type = '{default: RANDOM_SEQ}; - req_rate = '{default: 7'd50}; - runSeq(10000); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 5 -- linear read -- enabled cache + tlb, mem contentions"; - // config - enable_i = 1; - tlb_rand_en = 1; - mem_rand_en = 1; - seq_type = '{default: LINEAR_SEQ}; - req_rate = '{default: 7'd50}; - runSeq(10000); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 6 -- random read -- enabled cache + tlb, mem contentions + invalidations"; - // config - enable_i = 1; - tlb_rand_en = 1; - mem_rand_en = 1; - inv_rand_en = 1; - seq_type = '{default: RANDOM_SEQ}; - req_rate = '{default: 7'd50}; - runSeq(10000); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 7 -- random read/write -- disabled cache"; - // config - enable_i = 0; - tlb_rand_en = 0; - mem_rand_en = 0; - inv_rand_en = 0; - seq_type = '{default: RANDOM_SEQ}; - req_rate = '{default: 7'd25}; - runSeq(10000,10000); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 8 -- random read/write -- enabled cache"; - // config - enable_i = 1; - tlb_rand_en = 0; - mem_rand_en = 0; - inv_rand_en = 0; - seq_type = '{default: RANDOM_SEQ}; - req_rate = '{default: 7'd25}; - runSeq(10000,20000);// last sequence flag, terminates agents - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 9 -- random read/write -- enabled cache + tlb, mem contentions + invalidations"; - // config - enable_i = 1; - tlb_rand_en = 1; - mem_rand_en = 1; - inv_rand_en = 1; - seq_type = '{default: RANDOM_SEQ}; - req_rate = '{default: 7'd25}; - runSeq(10000,20000); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 10 -- linear burst write -- enabled cache"; - // config - enable_i = 1; - tlb_rand_en = 0; - mem_rand_en = 0; - inv_rand_en = 0; - seq_type = '{LINEAR_SEQ, IDLE_SEQ, IDLE_SEQ}; - req_rate = '{100, 0, 0}; - runSeq(0,5000); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 11 -- linear burst write with hot cache"; - // config - enable_i = 1; - tlb_rand_en = 0; - mem_rand_en = 0; - inv_rand_en = 0; - seq_type = '{IDLE_SEQ, IDLE_SEQ, LINEAR_SEQ}; - req_rate = '{default:100}; - runSeq((CachedAddrBeg>>3)+(2**(DCACHE_INDEX_WIDTH-3))*DCACHE_SET_ASSOC,0); - seq_type = '{LINEAR_SEQ, IDLE_SEQ, IDLE_SEQ}; - runSeq(0,(CachedAddrBeg>>3)+(2**(DCACHE_INDEX_WIDTH-3))*DCACHE_SET_ASSOC,1); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 12 -- random write bursts -- enabled cache"; - // config - enable_i = 1; - tlb_rand_en = 0; - mem_rand_en = 0; - inv_rand_en = 0; - seq_type = '{BURST_SEQ, RANDOM_SEQ, RANDOM_SEQ}; - req_rate = '{75, 0, 0}; - runSeq(0,5000,0); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 13 -- random write bursts -- enabled cache + tlb, mem contentions + invalidations"; - // config - enable_i = 1; - tlb_rand_en = 1; - mem_rand_en = 1; - inv_rand_en = 1; - seq_type = '{BURST_SEQ, IDLE_SEQ, IDLE_SEQ}; - req_rate = '{75, 0, 0}; - runSeq(0,5000); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 14 -- random write/read-- enabled cache + tlb, mem contentions + invalidations"; - // config - enable_i = 1; - tlb_rand_en = 1; - mem_rand_en = 1; - inv_rand_en = 1; - seq_type = '{RANDOM_SEQ, RANDOM_SEQ, RANDOM_SEQ}; - req_rate = '{default:25}; - runSeq(5000,5000); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 15 -- short wrapping sequences to provoke writebuffer hits"; - // config - enable_i = 1; - tlb_rand_en = 0; - mem_rand_en = 0; - inv_rand_en = 0; - seq_type = '{WRAP_SEQ, IDLE_SEQ, WRAP_SEQ}; - req_rate = '{100,0,20}; - runSeq(5000,5000); - flushCache(); - memCheck(); - /////////////////////////////////////////////// - test_name = "TEST 16 -- random write/read-- enabled cache + tlb, mem contentions + invalidations + random flushes"; - // config - enable_i = 1; - tlb_rand_en = 1; - mem_rand_en = 1; - inv_rand_en = 1; - flush_rand_en = 1; - seq_type = '{RANDOM_SEQ, RANDOM_SEQ, RANDOM_SEQ}; - req_rate = '{default:25}; - runSeq(5000,5000,1);// last sequence flag, terminates agents - flushCache(); - memCheck(); - /////////////////////////////////////////////// - end_of_sim = 1; - $display("TB> end test sequences"); - end + $display("TB> start with test sequences"); + // apply each test until seq_num_resp memory + // requests have successfully completed + /////////////////////////////////////////////// + test_name = "TEST 0 -- random read -- disabled cache"; + // config + enable_i = 0; + seq_type = '{default: RANDOM_SEQ}; + req_rate = '{default: 7'd50}; + runSeq(10000); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 1 -- sequential read -- disabled cache"; + // config + enable_i = 0; + seq_type = '{default: LINEAR_SEQ}; + req_rate = '{default: 7'd50}; + runSeq(10000); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 2 -- random read -- enabled cache"; + // config + enable_i = 1; + seq_type = '{default: RANDOM_SEQ}; + req_rate = '{default: 7'd50}; + runSeq(10000); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 3 -- linear read -- enabled cache"; + // config + enable_i = 1; + seq_type = '{default: LINEAR_SEQ}; + req_rate = '{default: 7'd50}; + runSeq(10000); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 4 -- random read -- enabled cache + tlb, mem contentions"; + // config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + seq_type = '{default: RANDOM_SEQ}; + req_rate = '{default: 7'd50}; + runSeq(10000); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 5 -- linear read -- enabled cache + tlb, mem contentions"; + // config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + seq_type = '{default: LINEAR_SEQ}; + req_rate = '{default: 7'd50}; + runSeq(10000); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 6 -- random read -- enabled cache + tlb, mem contentions + invalidations"; + // config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + inv_rand_en = 1; + seq_type = '{default: RANDOM_SEQ}; + req_rate = '{default: 7'd50}; + runSeq(10000); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 7 -- random read/write -- disabled cache"; + // config + enable_i = 0; + tlb_rand_en = 0; + mem_rand_en = 0; + inv_rand_en = 0; + seq_type = '{default: RANDOM_SEQ}; + req_rate = '{default: 7'd25}; + runSeq(10000,10000); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 8 -- random read/write -- enabled cache"; + // config + enable_i = 1; + tlb_rand_en = 0; + mem_rand_en = 0; + inv_rand_en = 0; + seq_type = '{default: RANDOM_SEQ}; + req_rate = '{default: 7'd25}; + runSeq(10000,20000);// last sequence flag, terminates agents + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 9 -- random read/write -- enabled cache + tlb, mem contentions + invalidations"; + // config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + inv_rand_en = 1; + seq_type = '{default: RANDOM_SEQ}; + req_rate = '{default: 7'd25}; + runSeq(10000,20000); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 10 -- linear burst write -- enabled cache"; + // config + enable_i = 1; + tlb_rand_en = 0; + mem_rand_en = 0; + inv_rand_en = 0; + seq_type = '{LINEAR_SEQ, IDLE_SEQ, IDLE_SEQ}; + req_rate = '{100, 0, 0}; + runSeq(0,5000); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 11 -- linear burst write with hot cache"; + // config + enable_i = 1; + tlb_rand_en = 0; + mem_rand_en = 0; + inv_rand_en = 0; + seq_type = '{IDLE_SEQ, IDLE_SEQ, LINEAR_SEQ}; + req_rate = '{default:100}; + runSeq((CachedAddrBeg>>3)+(2**(DCACHE_INDEX_WIDTH-3))*DCACHE_SET_ASSOC,0); + seq_type = '{LINEAR_SEQ, IDLE_SEQ, IDLE_SEQ}; + runSeq(0,(CachedAddrBeg>>3)+(2**(DCACHE_INDEX_WIDTH-3))*DCACHE_SET_ASSOC,1); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 12 -- random write bursts -- enabled cache"; + // config + enable_i = 1; + tlb_rand_en = 0; + mem_rand_en = 0; + inv_rand_en = 0; + seq_type = '{BURST_SEQ, RANDOM_SEQ, RANDOM_SEQ}; + req_rate = '{75, 0, 0}; + runSeq(0,5000,0); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 13 -- random write bursts -- enabled cache + tlb, mem contentions + invalidations"; + // config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + inv_rand_en = 1; + seq_type = '{BURST_SEQ, IDLE_SEQ, IDLE_SEQ}; + req_rate = '{75, 0, 0}; + runSeq(0,5000); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 14 -- random write/read-- enabled cache + tlb, mem contentions + invalidations"; + // config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + inv_rand_en = 1; + seq_type = '{RANDOM_SEQ, RANDOM_SEQ, RANDOM_SEQ}; + req_rate = '{default:25}; + runSeq(5000,5000); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 15 -- short wrapping sequences to provoke writebuffer hits"; + // config + enable_i = 1; + tlb_rand_en = 0; + mem_rand_en = 0; + inv_rand_en = 0; + seq_type = '{WRAP_SEQ, IDLE_SEQ, WRAP_SEQ}; + req_rate = '{100,0,20}; + runSeq(5000,5000); + flushCache(); + memCheck(); + /////////////////////////////////////////////// + test_name = "TEST 16 -- random write/read-- enabled cache + tlb, mem contentions + invalidations + random flushes"; + // config + enable_i = 1; + tlb_rand_en = 1; + mem_rand_en = 1; + inv_rand_en = 1; + flush_rand_en = 1; + seq_type = '{RANDOM_SEQ, RANDOM_SEQ, RANDOM_SEQ}; + req_rate = '{default:25}; + runSeq(5000,5000,1);// last sequence flag, terminates agents + flushCache(); + memCheck(); + /////////////////////////////////////////////// + end_of_sim = 1; + $display("TB> end test sequences"); + end endmodule diff --git a/tb/tb_serpent_dcache/hdl/tb.svh b/tb/tb_serpent_dcache/hdl/tb.svh deleted file mode 100644 index d25d4d830..000000000 --- a/tb/tb_serpent_dcache/hdl/tb.svh +++ /dev/null @@ -1,66 +0,0 @@ -// 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. -// -// Author: Michael Schaffner , ETH Zurich -// Date: 15.08.2018 -// Description: -// - -////////////////////////////////////////////////////////////////////////////// -// use to ensure proper ATI timing -/////////////////////////////////////////////////////////////////////////////// - -`define APPL_ACQ_WAIT #(ACQ_DEL-APPL_DEL); - -`define WAIT_CYC(CLK, N) \ -repeat(N) @(posedge(CLK)); - -`define WAIT(CLK, SIG) \ -do begin \ - @(posedge(CLK)); \ -end while(SIG == 1'b0); - -`define WAIT_SIG(CLK,SIG) \ -do begin \ - @(posedge(CLK)); \ -end while(SIG == 1'b0); - -`define APPL_WAIT_COMB_SIG(CLK,SIG) \ -`APPL_ACQ_WAIT \ -while(SIG == 1'b0) begin \ - @(posedge(CLK)); \ - #(ACQ_DEL); \ -end - -`define APPL_WAIT_SIG(CLK,SIG) \ -do begin \ - @(posedge(CLK)); \ - #(APPL_DEL); \ -end while(SIG == 1'b0); - -`define ACQ_WAIT_SIG(CLK,SIG) \ -do begin \ - @(posedge(CLK)); \ - #(ACQ_DEL); \ -end while(SIG == 1'b0); - - -`define APPL_WAIT_CYC(CLK, N) \ -repeat(N) @(posedge(CLK)); \ -#(tb_pkg::APPL_DEL); - -`define ACQ_WAIT_CYC(CLK, N) \ -repeat(N) @(posedge(CLK)); \ -#(tb_pkg::ACQ_DEL); - diff --git a/tb/tb_serpent_dcache/hdl/tb_mem.sv b/tb/tb_serpent_dcache/hdl/tb_mem.sv index 2e4ec3344..9cb7a200d 100644 --- a/tb/tb_serpent_dcache/hdl/tb_mem.sv +++ b/tb/tb_serpent_dcache/hdl/tb_mem.sv @@ -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: Michael Schaffner , ETH Zurich // Date: 15.08.2018 @@ -25,7 +21,7 @@ import serpent_cache_pkg::*; import tb_pkg::*; module tb_mem #( - parameter string MemName = "TB_MEM", + parameter string MemName = "TB_MEM", parameter MemRandHitRate = 10, //in percent parameter MemRandInvRate = 5, //in percent parameter MemWords = 1024*1024,// in 64bit words @@ -75,7 +71,7 @@ module tb_mem #( logic [63:0] mem_array_q[MemWords-1:0]; // this shadow memory provides a view that is consistent with the one from the core - // i.e., pending writes are present in this view, and invalidations will not overwrite + // i.e., pending writes are present in this view, and invalidations will not overwrite // the corresponding bytes until they have been commited to the normal memory. logic [63:0] mem_array_shadow_q[MemWords-1:0]; logic [7:0] mem_array_dirty_q[MemWords-1:0]; @@ -85,8 +81,8 @@ module tb_mem #( // sequential process holding the state of the memory readout process always_ff @(posedge clk_i or negedge rst_ni) begin : p_tlb_rand automatic int rnd = 0; - automatic logic [63:0] val; - automatic logic [63:0] lval; + automatic logic [63:0] val; + automatic logic [63:0] lval; if(~rst_ni) begin mem_ready_q <= '0; @@ -94,26 +90,26 @@ module tb_mem #( rand_addr_q <= '0; initialized_q <= '0; end else begin - + // fill the memory once with random data if (initialized_q) begin // commit "virtual" writes (i.e., clear the dirty flags) if(commit_en_i) begin for(int k=0; k<8; k++) begin if(commit_be_i[k]) begin - mem_array_dirty_q[commit_paddr_i>>3][k] <= 1'b0; + mem_array_dirty_q[commit_paddr_i>>3][k] <= 1'b0; end - end - end - + end + end + // "virtual" writes coming from TB agent, used to generate expected responses if(write_en_i) begin for(int k=0; k<8; k++) begin if(write_be_i[k]) begin mem_array_shadow_q[write_paddr_i>>3][k*8 +: 8] <= write_data_i[k*8 +: 8]; - mem_array_dirty_q[write_paddr_i>>3][k] <= 1'b1; + mem_array_dirty_q[write_paddr_i>>3][k] <= 1'b1; end - end + end end // "real" writes coming via the miss controller @@ -125,22 +121,22 @@ module tb_mem #( 3'b011: mem_array_q[outfifo_data.paddr>>3] = outfifo_data.data[0 +: 64]; default: begin $fatal(1,"unsupported transfer size for write"); - end - endcase // infifo_data.size - end - // initialization with random data + end + endcase // infifo_data.size + end + // initialization with random data end else begin mem_array_dirty_q <= '{default:'0}; - + for (int k=0; k 0; rnd <= 100;}); @@ -150,7 +146,7 @@ module tb_mem #( mem_ready_q <= '0; end end else begin - mem_ready_q <= '1; + mem_ready_q <= '1; end // generate random invalidations @@ -161,20 +157,20 @@ module tb_mem #( void'(randomize(lval) with {lval>=0; lval<(MemWords>>3);}); void'(randomize(val)); rand_addr_q <= lval<<3; - - // with the current TB setup, we cannot invalidate a memory location if a write response to the same address is + + // with the current TB setup, we cannot invalidate a memory location if a write response to the same address is // in flight, since this could lead to an incosistent state between the real memory and the shadow memory view. - // the workaround is not to overwrite shadow memory regions that are still pending in the write buffer + // the workaround is not to overwrite shadow memory regions that are still pending in the write buffer // this can be improved. for(int k=0; k<8; k++) begin if(~mem_array_dirty_q[lval][k]) begin mem_array_q [lval][k*8 +: 8] <= val[k*8 +: 8]; mem_array_shadow_q[lval][k*8 +: 8] <= val[k*8 +: 8]; - end + end end end else begin mem_inv_q <= '0; - end + end end else begin mem_inv_q <= '0; end @@ -217,7 +213,7 @@ module tb_mem #( infifo_push = 1'b1; end else if ((~outfifo_empty) && (~infifo_full) && mem_ready_q) begin - + outfifo_pop = 1'b1; infifo_push = 1'b1; @@ -233,20 +229,20 @@ module tb_mem #( 3'b011: infifo_data.data[0+:64] = mem_array_q[outfifo_data.paddr>>3]; 3'b111: for(int k=0; k>3) + k]; default: $fatal(1,"unsupported transfer size for read"); - endcase // infifo_data.size - end + endcase // infifo_data.size + end DCACHE_STORE_REQ: begin infifo_data.tid = outfifo_data.tid; infifo_data.rtype = DCACHE_STORE_ACK; infifo_data.nc = outfifo_data.nc; write_en = 1'b1; end - // DCACHE_ATOMIC_REQ: $fatal(1, "DCACHE_ATOMIC_REQ not implemented yet"); - // DCACHE_INT_REQ: $fatal(1, "DCACHE_INT_REQ not implemented yet"); + // DCACHE_ATOMIC_REQ: $fatal(1, "DCACHE_ATOMIC_REQ not implemented yet"); + // DCACHE_INT_REQ: $fatal(1, "DCACHE_INT_REQ not implemented yet"); default: begin - // $fatal(1, "unsupported request type"); - end - endcase // outfifo_data.rtype + // $fatal(1, "unsupported request type"); + end + endcase // outfifo_data.rtype end end @@ -301,10 +297,10 @@ module tb_mem #( bit ok; progress status; status = new(MemName); - + `ACQ_WAIT_CYC(clk_i,10) `ACQ_WAIT_SIG(clk_i,~rst_ni) - + while(~seq_last_i) begin `ACQ_WAIT_SIG(clk_i,check_en_i) status.reset(MemWords); @@ -312,15 +308,15 @@ module tb_mem #( for(int k=0; k dirty bytes at k=%016X: real[k>>3]=%016X, shadow[k>>3]=%016X, dirty[k>>3]=%02X", + $display("%s> dirty bytes at k=%016X: real[k>>3]=%016X, shadow[k>>3]=%016X, dirty[k>>3]=%02X", MemName, k<<3, mem_array_q[k], mem_array_shadow_q[k], mem_array_dirty_q[k]); end status.addRes(!ok); status.print(); - end - end - status.printToFile({MemName, "_summary.rep"}, 1); - + end + end + status.printToFile({MemName, "_summary.rep"}, 1); + if(status.totErrCnt == 0) begin $display("%s> ----------------------------------------------------------------------", MemName); $display("%s> PASSED %0d VECTORS", MemName, status.totAcqCnt); @@ -330,10 +326,10 @@ module tb_mem #( $display("%s> FAILED %0d OF %0d VECTORS\n", MemName , status.totErrCnt, status.totAcqCnt); $display("%s> ----------------------------------------------------------------------\n", MemName); end - end + end + + - - /////////////////////////////////////////////////////// // assertions @@ -343,23 +339,23 @@ module tb_mem #( `ifndef verilator nc_region: assert property ( - @(posedge clk_i) disable iff (~rst_ni) mem_data_req_i |-> mem_data_i.paddr >= CachedAddrEnd || mem_data_i.paddr < CachedAddrBeg |-> mem_data_i.nc) + @(posedge clk_i) disable iff (~rst_ni) mem_data_req_i |-> mem_data_i.paddr >= CachedAddrEnd || mem_data_i.paddr < CachedAddrBeg |-> mem_data_i.nc) else $fatal(1, "cached access into noncached region"); cached_reads: assert property ( - @(posedge clk_i) disable iff (~rst_ni) mem_data_req_i |-> mem_data_i.rtype==DCACHE_LOAD_REQ |-> ~mem_data_i.nc |-> mem_data_i.size == 3'b111) + @(posedge clk_i) disable iff (~rst_ni) mem_data_req_i |-> mem_data_i.rtype==DCACHE_LOAD_REQ |-> ~mem_data_i.nc |-> mem_data_i.size == 3'b111) else $fatal(1, "cached read accesses always have to be one CL wide"); nc_reads: assert property ( - @(posedge clk_i) disable iff (~rst_ni) mem_data_req_i |-> mem_data_i.rtype==DCACHE_LOAD_REQ |-> mem_data_i.nc |-> mem_data_i.size inside {3'b000, 3'b001, 3'b010, 3'b011}) + @(posedge clk_i) disable iff (~rst_ni) mem_data_req_i |-> mem_data_i.rtype==DCACHE_LOAD_REQ |-> mem_data_i.nc |-> mem_data_i.size inside {3'b000, 3'b001, 3'b010, 3'b011}) else $fatal(1, "nc read size can only be one of the following: byte, halfword, word, dword"); write_size: assert property ( - @(posedge clk_i) disable iff (~rst_ni) mem_data_req_i |-> mem_data_i.rtype==DCACHE_STORE_REQ |-> mem_data_i.size inside {3'b000, 3'b001, 3'b010, 3'b011}) + @(posedge clk_i) disable iff (~rst_ni) mem_data_req_i |-> mem_data_i.rtype==DCACHE_STORE_REQ |-> mem_data_i.size inside {3'b000, 3'b001, 3'b010, 3'b011}) else $fatal(1, "write size can only be one of the following: byte, halfword, word, dword"); addr_range: assert property ( - @(posedge clk_i) disable iff (~rst_ni) mem_data_req_i |-> mem_data_i.rtype inside {DCACHE_STORE_REQ, DCACHE_STORE_REQ} |-> mem_data_i.paddr < (MemWords<<3)) + @(posedge clk_i) disable iff (~rst_ni) mem_data_req_i |-> mem_data_i.rtype inside {DCACHE_STORE_REQ, DCACHE_STORE_REQ} |-> mem_data_i.paddr < (MemWords<<3)) else $fatal(1, "address is out of bounds"); `endif diff --git a/tb/tb_serpent_dcache/hdl/tb_pkg.sv b/tb/tb_serpent_dcache/hdl/tb_pkg.sv index 2cda6a4b7..1ee8f9686 100644 --- a/tb/tb_serpent_dcache/hdl/tb_pkg.sv +++ b/tb/tb_serpent_dcache/hdl/tb_pkg.sv @@ -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: Michael Schaffner , ETH Zurich // Date: 15.08.2018 @@ -20,7 +16,7 @@ package tb_pkg; // // for abs(double) function - // import mti_cstdlib::*; + // import mti_cstdlib::*; // for timestamps import "DPI-C" \time = function int _time (inout int tloc[4]); @@ -29,13 +25,13 @@ package tb_pkg; /////////////////////////////////////////////////////////////////////////////// // parameters /////////////////////////////////////////////////////////////////////////////// - - // creates a 10ns ATI timing cycle - time CLK_HI = 5ns; // set clock high time - time CLK_LO = 5ns; // set clock low time + + // creates a 10ns ATI timing cycle + time CLK_HI = 5ns; // set clock high time + time CLK_LO = 5ns; // set clock low time time CLK_PERIOD = CLK_HI+CLK_LO; - time APPL_DEL = 2ns; // set stimuli application delay - time ACQ_DEL = 8ns; // set response aquisition delay + time APPL_DEL = 2ns; // set stimuli application delay + time ACQ_DEL = 8ns; // set response aquisition delay parameter ERROR_CNT_STOP_LEVEL = 1; // use 1 for debugging. 0 runs the complete simulation... @@ -43,9 +39,9 @@ package tb_pkg; typedef enum logic [2:0] { RANDOM_SEQ, LINEAR_SEQ, BURST_SEQ, IDLE_SEQ, WRAP_SEQ } seq_t; /////////////////////////////////////////////////////////////////////////////// -// progress +// progress /////////////////////////////////////////////////////////////////////////////// - + class progress; real newState, oldState; longint numResp, acqCnt, errCnt, totAcqCnt, totErrCnt; @@ -62,20 +58,20 @@ package tb_pkg; this.totAcqCnt = 0; this.totErrCnt = 0; - end + end endfunction : new - + function void reset(longint numResp_); begin this.acqCnt = 0; this.errCnt = 0; this.newState = 0.0; this.oldState = 0.0; - this.numResp = numResp_; - end + this.numResp = numResp_; + end endfunction : reset - function void addRes(int isError); + function void addRes(int isError); begin this.acqCnt++; this.totAcqCnt++; @@ -83,16 +79,16 @@ package tb_pkg; this.totErrCnt += isError; if(ERROR_CNT_STOP_LEVEL <= this.errCnt && ERROR_CNT_STOP_LEVEL > 0) begin - $error("%s> simulation stopped (ERROR_CNT_STOP_LEVEL = %d reached).", this.name, ERROR_CNT_STOP_LEVEL); + $error("%s> simulation stopped (ERROR_CNT_STOP_LEVEL = %d reached).", this.name, ERROR_CNT_STOP_LEVEL); $stop(); - end - end + end + end endfunction : addRes - function void print(); + function void print(); begin this.newState = $itor(this.acqCnt) / $itor(this.numResp); - if(this.newState - this.oldState >= 0.01) begin + if(this.newState - this.oldState >= 0.01) begin $display("%s> validated %03d%% -- %01d failed (%03.3f%%) ", this.name, $rtoi(this.newState*100.0), @@ -104,10 +100,10 @@ package tb_pkg; end endfunction : print - function void printToFile(string file, bit summary = 0); + function void printToFile(string file, bit summary = 0); begin int fptr; - + // sanitize string for(fptr=0; fptr<$size(file);fptr++) begin if(file[fptr] == " " || file[fptr] == "/" || file[fptr] == "\\") begin @@ -128,13 +124,13 @@ package tb_pkg; end else begin $fdisplay(fptr, "CI: FAILED"); end - end else begin + end else begin $fdisplay(fptr, "test name: %s", file); $fdisplay(fptr, "this test: %01d of %01d vectors failed (%03.3f%%) ", this.errCnt, this.acqCnt, $itor(this.errCnt) / $itor(this.acqCnt) * 100.0); - + $fdisplay(fptr, "total so far: %01d of %01d vectors failed (%03.3f%%) ", this.totErrCnt, this.totAcqCnt, diff --git a/tb/tb_serpent_dcache/hdl/tb_readport.sv b/tb/tb_serpent_dcache/hdl/tb_readport.sv index 5133446cd..cc71cd4ed 100644 --- a/tb/tb_serpent_dcache/hdl/tb_readport.sv +++ b/tb/tb_serpent_dcache/hdl/tb_readport.sv @@ -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: Michael Schaffner , ETH Zurich // Date: 15.08.2018 @@ -26,379 +22,367 @@ import serpent_cache_pkg::*; import tb_pkg::*; program tb_readport #( - parameter string PortName = "read port 0", - parameter FlushRate = 1, - parameter KillRate = 5, - parameter TlbHitRate = 95, - parameter MemWords = 1024*1024,// in 64bit words - parameter logic [63:0] CachedAddrBeg = 0, - parameter logic [63:0] CachedAddrEnd = 0, - parameter RndSeed = 1110, - parameter Verbose = 0 + parameter string PortName = "read port 0", + parameter FlushRate = 1, + parameter KillRate = 5, + parameter TlbHitRate = 95, + parameter MemWords = 1024*1024,// in 64bit words + parameter logic [63:0] CachedAddrBeg = 0, + parameter logic [63:0] CachedAddrEnd = 0, + parameter RndSeed = 1110, + parameter Verbose = 0 ) ( - input logic clk_i, - input logic rst_ni, + input logic clk_i, + input logic rst_ni, - // to testbench master - ref string test_name_i, - input logic [6:0] req_rate_i, //a rate between 0 and 100 percent - input seq_t seq_type_i, - input logic tlb_rand_en_i, - input logic flush_rand_en_i, - input logic seq_run_i, - input logic [31:0] seq_num_resp_i, - input logic seq_last_i, - output logic seq_done_o, + // to testbench master + ref string test_name_i, + input logic [6:0] req_rate_i, //a rate between 0 and 100 percent + input seq_t seq_type_i, + input logic tlb_rand_en_i, + input logic flush_rand_en_i, + input logic seq_run_i, + input logic [31:0] seq_num_resp_i, + input logic seq_last_i, + output logic seq_done_o, - // expresp interface - output logic [63:0] exp_paddr_o, - input logic [1:0] exp_size_i, - input logic [63:0] exp_rdata_i, - input logic [63:0] exp_paddr_i, - input logic [63:0] act_paddr_i, + // expresp interface + output logic [63:0] exp_paddr_o, + input logic [1:0] exp_size_i, + input logic [63:0] exp_rdata_i, + input logic [63:0] exp_paddr_i, + input logic [63:0] act_paddr_i, - // interface to DUT - output logic flush_o, - input logic flush_ack_i, - output dcache_req_i_t dut_req_port_o, - input dcache_req_o_t dut_req_port_i - ); + // interface to DUT + output logic flush_o, + input logic flush_ack_i, + output dcache_req_i_t dut_req_port_o, + input dcache_req_o_t dut_req_port_i +); - // leave this - timeunit 1ps; - timeprecision 1ps; + // leave this + timeunit 1ps; + timeprecision 1ps; - logic [63:0] paddr; - logic seq_end_req, seq_end_ack, prog_end; - logic [DCACHE_TAG_WIDTH-1:0] tag_q; - logic [DCACHE_TAG_WIDTH-1:0] tag_vld_q; + logic [63:0] paddr; + logic seq_end_req, seq_end_ack, prog_end; + logic [DCACHE_TAG_WIDTH-1:0] tag_q; + logic [DCACHE_TAG_WIDTH-1:0] tag_vld_q; /////////////////////////////////////////////////////////////////////////////// // Randomly delay the tag by at least one cycle /////////////////////////////////////////////////////////////////////////////// - // // TODO: add randomization - initial begin : p_tag_delay - logic [63:0] tmp_paddr, val; - int unsigned cnt; - logic tmp_vld; + // // TODO: add randomization + initial begin : p_tag_delay + logic [63:0] tmp_paddr, val; + int unsigned cnt; + logic tmp_vld; - tag_q <= '0; - tag_vld_q <= 1'b0; + tag_q <= '0; + tag_vld_q <= 1'b0; - `APPL_WAIT_CYC(clk_i, 10) - `APPL_WAIT_SIG(clk_i,~rst_ni) - `APPL_WAIT_CYC(clk_i,1) + `APPL_WAIT_CYC(clk_i, 10) + `APPL_WAIT_SIG(clk_i,~rst_ni) + `APPL_WAIT_CYC(clk_i,1) - tmp_vld = 0; - cnt = 0; - forever begin - `APPL_WAIT_CYC(clk_i,1) - - if(cnt==0) begin - if(tmp_vld) begin - tmp_vld = 0; - tag_q <= tmp_paddr[DCACHE_TAG_WIDTH+DCACHE_INDEX_WIDTH-1:DCACHE_INDEX_WIDTH]; - tag_vld_q <= 1'b1; - end else begin - tag_vld_q <= 1'b0; - end - - `APPL_ACQ_WAIT; - if(dut_req_port_o.data_req) begin - tmp_paddr = paddr; - tmp_vld = 1; - - if(tlb_rand_en_i) begin - void'(randomize(val) with {val>0; val<=100;}); - if(val>=TlbHitRate) begin - void'(randomize(cnt) with {cnt>0; cnt<=50;}); - end - end - end - - end else begin - tag_vld_q <= 1'b0; - cnt -= 1; - `APPL_ACQ_WAIT; - end - - if(dut_req_port_o.kill_req) begin - tmp_vld = 0; - cnt = 0; - end + tmp_vld = 0; + cnt = 0; + forever begin + `APPL_WAIT_CYC(clk_i,1) + if(cnt==0) begin + if(tmp_vld) begin + tmp_vld = 0; + tag_q <= tmp_paddr[DCACHE_TAG_WIDTH+DCACHE_INDEX_WIDTH-1:DCACHE_INDEX_WIDTH]; + tag_vld_q <= 1'b1; + end else begin + tag_vld_q <= 1'b0; end - end - assign dut_req_port_o.address_tag = tag_q; - assign dut_req_port_o.tag_valid = tag_vld_q; - assign dut_req_port_o.address_index = paddr[DCACHE_INDEX_WIDTH-1:0]; - assign exp_paddr_o = paddr; + `APPL_ACQ_WAIT; + if(dut_req_port_o.data_req) begin + tmp_paddr = paddr; + tmp_vld = 1; + + if(tlb_rand_en_i) begin + void'(randomize(val) with {val>0; val<=100;}); + if(val>=TlbHitRate) begin + void'(randomize(cnt) with {cnt>0; cnt<=50;}); + end + end + end + end else begin + tag_vld_q <= 1'b0; + cnt -= 1; + `APPL_ACQ_WAIT; + end + + if(dut_req_port_o.kill_req) begin + tmp_vld = 0; + cnt = 0; + end + end + end + + assign dut_req_port_o.address_tag = tag_q; + assign dut_req_port_o.tag_valid = tag_vld_q; + assign dut_req_port_o.address_index = paddr[DCACHE_INDEX_WIDTH-1:0]; + assign exp_paddr_o = paddr; /////////////////////////////////////////////////////////////////////////////// // Helper tasks /////////////////////////////////////////////////////////////////////////////// - task automatic flushCache(); - flush_o = 1'b1; - `APPL_WAIT_SIG(clk_i, flush_ack_i); - flush_o = 0'b0; + task automatic flushCache(); + flush_o = 1'b1; + `APPL_WAIT_SIG(clk_i, flush_ack_i); + flush_o = 0'b0; + `APPL_WAIT_CYC(clk_i,1) + endtask : flushCache + + + task automatic genRandReq(); + automatic logic [63:0] val; + automatic logic [1:0] size; + + void'($urandom(RndSeed)); + + paddr = '0; + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.kill_req = '0; + + while(~seq_end_req) begin + // randomize request + dut_req_port_o.data_req = '0; + // generate random control events + void'(randomize(val) with {val > 0; val <= 100;}); + if(val < KillRate) begin + dut_req_port_o.kill_req = 1'b1; `APPL_WAIT_CYC(clk_i,1) - endtask : flushCache + dut_req_port_o.kill_req = 1'b0; + end else begin + void'(randomize(val) with {val > 0; val <= 100;}); + if(val < FlushRate && flush_rand_en_i) begin + flushCache(); + end else begin + void'(randomize(val) with {val > 0; val <= 100;}); + if(val < req_rate_i) begin + dut_req_port_o.data_req = 1'b1; + // generate random address + void'(randomize(val) with {val >= 0; val < (MemWords<<3);}); + void'(randomize(size)); - - task automatic genRandReq(); - automatic logic [63:0] val; - automatic logic [1:0] size; - - void'($urandom(RndSeed)); - - paddr = '0; - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.kill_req = '0; - - while(~seq_end_req) begin - // randomize request - dut_req_port_o.data_req = '0; - // generate random control events - void'(randomize(val) with {val > 0; val <= 100;}); - if(val < KillRate) begin - dut_req_port_o.kill_req = 1'b1; - `APPL_WAIT_CYC(clk_i,1) - dut_req_port_o.kill_req = 1'b0; - end else begin - void'(randomize(val) with {val > 0; val <= 100;}); - if(val < FlushRate && flush_rand_en_i) begin - flushCache(); - end else begin - void'(randomize(val) with {val > 0; val <= 100;}); - if(val < req_rate_i) begin - dut_req_port_o.data_req = 1'b1; - // generate random address - void'(randomize(val) with {val >= 0; val < (MemWords<<3);}); - void'(randomize(size)); - - dut_req_port_o.data_size = size; - paddr = val; - - // align to size - unique case(size) - 2'b01: paddr[0] = 1'b0; - 2'b10: paddr[1:0] = 2'b00; - 2'b11: paddr[2:0] = 3'b000; - default: ; - endcase - - `APPL_WAIT_COMB_SIG(clk_i, dut_req_port_i.data_gnt) - end - `APPL_WAIT_CYC(clk_i,1) - end - end - end - - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.kill_req = '0; - - endtask : genRandReq - - task automatic genSeqRead(); - automatic logic [63:0] val; - paddr = '0; - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.kill_req = '0; - val = '0; - while(~seq_end_req) begin - dut_req_port_o.data_req = 1'b1; - dut_req_port_o.data_size = 2'b11; + dut_req_port_o.data_size = size; paddr = val; - // generate linear read - val = (val + 8) % (MemWords<<3); - `APPL_WAIT_COMB_SIG(clk_i, dut_req_port_i.data_gnt) - `APPL_WAIT_CYC(clk_i,1) - end - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.kill_req = '0; - endtask : genSeqRead - task automatic genWrapSeq(); - automatic logic [63:0] val; - paddr = CachedAddrBeg; - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.kill_req = '0; - val = '0; - while(~seq_end_req) begin - dut_req_port_o.data_req = 1'b1; - dut_req_port_o.data_size = 2'b11; - paddr = val; - // generate wrapping read of 1 cachelines - paddr = CachedAddrBeg + val; - val = (val + 8) % (1*(DCACHE_LINE_WIDTH/64)*8); + // align to size + unique case(size) + 2'b01: paddr[0] = 1'b0; + 2'b10: paddr[1:0] = 2'b00; + 2'b11: paddr[2:0] = 3'b000; + default: ; + endcase + `APPL_WAIT_COMB_SIG(clk_i, dut_req_port_i.data_gnt) - `APPL_WAIT_CYC(clk_i,1) + end + `APPL_WAIT_CYC(clk_i,1) end - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.kill_req = '0; - endtask : genWrapSeq + end + end + + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.kill_req = '0; + + endtask : genRandReq + + task automatic genSeqRead(); + automatic logic [63:0] val; + paddr = '0; + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.kill_req = '0; + val = '0; + while(~seq_end_req) begin + dut_req_port_o.data_req = 1'b1; + dut_req_port_o.data_size = 2'b11; + paddr = val; + // generate linear read + val = (val + 8) % (MemWords<<3); + `APPL_WAIT_COMB_SIG(clk_i, dut_req_port_i.data_gnt) + `APPL_WAIT_CYC(clk_i,1) + end + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.kill_req = '0; + endtask : genSeqRead + + task automatic genWrapSeq(); + automatic logic [63:0] val; + paddr = CachedAddrBeg; + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.kill_req = '0; + val = '0; + while(~seq_end_req) begin + dut_req_port_o.data_req = 1'b1; + dut_req_port_o.data_size = 2'b11; + paddr = val; + // generate wrapping read of 1 cachelines + paddr = CachedAddrBeg + val; + val = (val + 8) % (1*(DCACHE_LINE_WIDTH/64)*8); + `APPL_WAIT_COMB_SIG(clk_i, dut_req_port_i.data_gnt) + `APPL_WAIT_CYC(clk_i,1) + end + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.kill_req = '0; + endtask : genWrapSeq /////////////////////////////////////////////////////////////////////////////// // Sequence application /////////////////////////////////////////////////////////////////////////////// - initial begin : p_stim - paddr = '0; - dut_req_port_o.data_wdata = '0; - dut_req_port_o.data_req = '0; - dut_req_port_o.data_we = '0; - dut_req_port_o.data_be = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.kill_req = '0; - seq_end_ack = '0; - flush_o = '0; + initial begin : p_stim + paddr = '0; + dut_req_port_o.data_wdata = '0; + dut_req_port_o.data_req = '0; + dut_req_port_o.data_we = '0; + dut_req_port_o.data_be = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.kill_req = '0; + seq_end_ack = '0; + flush_o = '0; - // print some info - $display("%s> current configuration:", PortName); - $display("%s> KillRate %d", PortName, KillRate); - $display("%s> FlushRate %d", PortName, FlushRate); - $display("%s> TlbHitRate %d", PortName, TlbHitRate); - $display("%s> RndSeed %d", PortName, RndSeed); + // print some info + $display("%s> current configuration:", PortName); + $display("%s> KillRate %d", PortName, KillRate); + $display("%s> FlushRate %d", PortName, FlushRate); + $display("%s> TlbHitRate %d", PortName, TlbHitRate); + $display("%s> RndSeed %d", PortName, RndSeed); - `APPL_WAIT_CYC(clk_i,1) - `APPL_WAIT_SIG(clk_i,~rst_ni) + `APPL_WAIT_CYC(clk_i,1) + `APPL_WAIT_SIG(clk_i,~rst_ni) - $display("%s> starting application", PortName); - while(~seq_last_i) begin - `APPL_WAIT_SIG(clk_i,seq_run_i) - unique case(seq_type_i) - RANDOM_SEQ: begin - $display("%s> start random sequence with %04d responses and req_rate %03d", PortName, seq_num_resp_i, req_rate_i); - genRandReq(); - end - LINEAR_SEQ: begin - $display("%s> start linear sequence with %04d responses and req_rate %03d", PortName, seq_num_resp_i, req_rate_i); - genSeqRead(); - end - WRAP_SEQ: begin - $display("%s> start wrapping sequence with %04d responses and req_rate %03d", PortName, seq_num_resp_i, req_rate_i); - genWrapSeq(); - end - IDLE_SEQ: begin - `APPL_WAIT_SIG(clk_i,seq_end_req) - end - BURST_SEQ: begin - $fatal(1, "Burst sequence not implemented for read port agent"); - end - endcase // seq_type_i - seq_end_ack = 1'b1; - $display("%s> stop sequence", PortName); - `APPL_WAIT_CYC(clk_i,1) - seq_end_ack = 1'b0; + $display("%s> starting application", PortName); + while(~seq_last_i) begin + `APPL_WAIT_SIG(clk_i,seq_run_i) + unique case(seq_type_i) + RANDOM_SEQ: begin + $display("%s> start random sequence with %04d responses and req_rate %03d", PortName, seq_num_resp_i, req_rate_i); + genRandReq(); end - $display("%s> ending application", PortName); + LINEAR_SEQ: begin + $display("%s> start linear sequence with %04d responses and req_rate %03d", PortName, seq_num_resp_i, req_rate_i); + genSeqRead(); + end + WRAP_SEQ: begin + $display("%s> start wrapping sequence with %04d responses and req_rate %03d", PortName, seq_num_resp_i, req_rate_i); + genWrapSeq(); + end + IDLE_SEQ: begin + `APPL_WAIT_SIG(clk_i,seq_end_req) + end + BURST_SEQ: begin + $fatal(1, "Burst sequence not implemented for read port agent"); + end + endcase // seq_type_i + seq_end_ack = 1'b1; + $display("%s> stop sequence", PortName); + `APPL_WAIT_CYC(clk_i,1) + seq_end_ack = 1'b0; end + $display("%s> ending application", PortName); + end /////////////////////////////////////////////////////////////////////////////// // Response acquisition /////////////////////////////////////////////////////////////////////////////// - initial begin : p_acq - bit ok; - progress status; - string failingTests, tmpstr1, tmpstr2; - int n; - logic [63:0] exp_rdata, exp_paddr; - logic [1:0] exp_size; + initial begin : p_acq + bit ok; + progress status; + string failingTests, tmpstr1, tmpstr2; + int n; + logic [63:0] exp_rdata, exp_paddr; + logic [1:0] exp_size; - status = new(PortName); - failingTests = ""; - seq_done_o = 1'b0; - seq_end_req = 1'b0; - prog_end = 1'b0; + status = new(PortName); + failingTests = ""; + seq_done_o = 1'b0; + seq_end_req = 1'b0; + prog_end = 1'b0; - `ACQ_WAIT_CYC(clk_i,1) - `ACQ_WAIT_SIG(clk_i,~rst_ni) + `ACQ_WAIT_CYC(clk_i,1) + `ACQ_WAIT_SIG(clk_i,~rst_ni) - /////////////////////////////////////////////// - // loop over tests - n=0; - while(~seq_last_i) begin - `ACQ_WAIT_SIG(clk_i,seq_run_i) - seq_done_o = 1'b0; + /////////////////////////////////////////////// + // loop over tests + n=0; + while(~seq_last_i) begin + `ACQ_WAIT_SIG(clk_i,seq_run_i) + seq_done_o = 1'b0; - $display("%s> %s", PortName, test_name_i); - status.reset(seq_num_resp_i); - for (int k=0;k %s", PortName, test_name_i); + status.reset(seq_num_resp_i); + for (int k=0;k %s", PortName, tmpstr1); - $display("%s> %s", PortName, tmpstr2); - end - - if(!ok) begin - failingTests = $psprintf("%s%s> %s\n%s> %s\n", failingTests, PortName, tmpstr1, PortName, tmpstr2); - end - status.addRes(!ok); - status.print(); - end - seq_end_req = 1'b1; - `ACQ_WAIT_SIG(clk_i, seq_end_ack) - seq_end_req = 1'b0; - - `ACQ_WAIT_CYC(clk_i,1) - seq_done_o = 1'b1; - n++; + if(Verbose | !ok) begin + tmpstr1 = $psprintf("vector: %02d - %06d -- exp_paddr: %16X -- exp_data: %16X -- access size: %01d Byte", + n, k, exp_paddr_i, exp_rdata, 2**exp_size_i); + tmpstr2 = $psprintf("vector: %02d - %06d -- act_paddr: %16X -- act_data: %16X -- access size: %01d Byte", + n, k, act_paddr_i, dut_req_port_i.data_rdata, 2**exp_size_i); + $display("%s> %s", PortName, tmpstr1); + $display("%s> %s", PortName, tmpstr2); end - /////////////////////////////////////////////// - status.printToFile({PortName, "_summary.rep"}, 1); - - if(status.totErrCnt == 0) begin - $display("%s> ----------------------------------------------------------------------", PortName); - $display("%s> PASSED %0d VECTORS", PortName, status.totAcqCnt); - $display("%s> ----------------------------------------------------------------------\n", PortName); - end else begin - $display("%s> ----------------------------------------------------------------------\n", PortName); - $display("%s> FAILED %0d OF %0d VECTORS\n", PortName , status.totErrCnt, status.totAcqCnt); - $display("%s> failing tests:", PortName); - $display("%s", failingTests); - $display("%s> ----------------------------------------------------------------------\n", PortName); + if(!ok) begin + failingTests = $psprintf("%s%s> %s\n%s> %s\n", failingTests, PortName, tmpstr1, PortName, tmpstr2); end - prog_end = 1'b1; + status.addRes(!ok); + status.print(); + end + seq_end_req = 1'b1; + `ACQ_WAIT_SIG(clk_i, seq_end_ack) + seq_end_req = 1'b0; + + `ACQ_WAIT_CYC(clk_i,1) + seq_done_o = 1'b1; + n++; end + /////////////////////////////////////////////// -/////////////////////////////////////////////////////// -// assertions -/////////////////////////////////////////////////////// + status.printToFile({PortName, "_summary.rep"}, 1); -//pragma translate_off -// `ifndef VERILATOR - -// `endif -//pragma translate_on + if(status.totErrCnt == 0) begin + $display("%s> ----------------------------------------------------------------------", PortName); + $display("%s> PASSED %0d VECTORS", PortName, status.totAcqCnt); + $display("%s> ----------------------------------------------------------------------\n", PortName); + end else begin + $display("%s> ----------------------------------------------------------------------\n", PortName); + $display("%s> FAILED %0d OF %0d VECTORS\n", PortName , status.totErrCnt, status.totAcqCnt); + $display("%s> failing tests:", PortName); + $display("%s", failingTests); + $display("%s> ----------------------------------------------------------------------\n", PortName); + end + prog_end = 1'b1; + end endprogram // tb_readport diff --git a/tb/tb_serpent_dcache/hdl/tb_writeport.sv b/tb/tb_serpent_dcache/hdl/tb_writeport.sv index 81d425347..205708393 100644 --- a/tb/tb_serpent_dcache/hdl/tb_writeport.sv +++ b/tb/tb_serpent_dcache/hdl/tb_writeport.sv @@ -1,22 +1,18 @@ -// 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: Michael Schaffner , ETH Zurich // Date: 15.08.2018 // Description: program that emulates a cache write port. the program can generate // randomized or linear read sequences. -// +// `include "tb.svh" @@ -25,276 +21,261 @@ import serpent_cache_pkg::*; import tb_pkg::*; program tb_writeport #( - parameter string PortName = "write port 0", - parameter MemWords = 1024*1024,// in 64bit words - parameter logic [63:0] CachedAddrBeg = 0, - parameter logic [63:0] CachedAddrEnd = 0, - parameter RndSeed = 1110, - parameter Verbose = 0 + parameter string PortName = "write port 0", + parameter MemWords = 1024*1024,// in 64bit words + parameter logic [63:0] CachedAddrBeg = 0, + parameter logic [63:0] CachedAddrEnd = 0, + parameter RndSeed = 1110, + parameter Verbose = 0 ) ( - input logic clk_i, - input logic rst_ni, + input logic clk_i, + input logic rst_ni, - // to testbench master - ref string test_name_i, - input logic [6:0] req_rate_i, - input seq_t seq_type_i, - input logic seq_run_i, - input logic [31:0] seq_num_vect_i, - input logic seq_last_i, - output logic seq_done_o, - - // interface to DUT - output dcache_req_i_t dut_req_port_o, - input dcache_req_o_t dut_req_port_i - ); + // to testbench master + ref string test_name_i, + input logic [6:0] req_rate_i, + input seq_t seq_type_i, + input logic seq_run_i, + input logic [31:0] seq_num_vect_i, + input logic seq_last_i, + output logic seq_done_o, - // leave this - timeunit 1ps; - timeprecision 1ps; + // interface to DUT + output dcache_req_i_t dut_req_port_o, + input dcache_req_o_t dut_req_port_i + ); - logic [63:0] paddr; - - assign dut_req_port_o.address_tag = paddr[DCACHE_TAG_WIDTH+DCACHE_INDEX_WIDTH-1:DCACHE_INDEX_WIDTH]; - assign dut_req_port_o.address_index = paddr[DCACHE_INDEX_WIDTH-1:0]; - assign dut_req_port_o.data_we = dut_req_port_o.data_req; + // leave this + timeunit 1ps; + timeprecision 1ps; + + logic [63:0] paddr; + + assign dut_req_port_o.address_tag = paddr[DCACHE_TAG_WIDTH+DCACHE_INDEX_WIDTH-1:DCACHE_INDEX_WIDTH]; + assign dut_req_port_o.address_index = paddr[DCACHE_INDEX_WIDTH-1:0]; + assign dut_req_port_o.data_we = dut_req_port_o.data_req; /////////////////////////////////////////////////////////////////////////////// // Helper tasks /////////////////////////////////////////////////////////////////////////////// - task automatic applyRandData(); - automatic logic [63:0] val; - automatic logic [7:0] be; - automatic logic [1:0] size; + task automatic applyRandData(); + automatic logic [63:0] val; + automatic logic [7:0] be; + automatic logic [1:0] size; - void'(randomize(size)); - // align to size, set correct byte enables - be = '0; - unique case(size) - 2'b00: be[paddr[2:0] +: 1] = '1; - 2'b01: be[paddr[2:1]<<1 +: 2] = '1; - 2'b10: be[paddr[2:2]<<2 +: 4] = '1; - 2'b11: be = '1; - default: ; - endcase - paddr[2:0] = '0; - - - void'(randomize(val)); - for(int k=0; k<8; k++) begin - if( be[k] ) begin - dut_req_port_o.data_wdata[k*8 +: 8] = val[k*8 +: 8]; - end - end - - dut_req_port_o.data_be = be; - dut_req_port_o.data_size = size; - endtask : applyRandData + void'(randomize(size)); + // align to size, set correct byte enables + be = '0; + unique case(size) + 2'b00: be[paddr[2:0] +: 1] = '1; + 2'b01: be[paddr[2:1]<<1 +: 2] = '1; + 2'b10: be[paddr[2:2]<<2 +: 4] = '1; + 2'b11: be = '1; + default: ; + endcase + paddr[2:0] = '0; - task automatic genRandReq(); - automatic logic [63:0] val; + void'(randomize(val)); + for(int k=0; k<8; k++) begin + if( be[k] ) begin + dut_req_port_o.data_wdata[k*8 +: 8] = val[k*8 +: 8]; + end + end - void'($urandom(RndSeed)); + dut_req_port_o.data_be = be; + dut_req_port_o.data_size = size; + endtask : applyRandData - paddr = '0; - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.data_be = '0; - dut_req_port_o.data_wdata = 'x; - repeat(seq_num_vect_i) begin - // randomize request - dut_req_port_o.data_req = '0; - dut_req_port_o.data_be = '0; - dut_req_port_o.data_wdata = 'x; - void'(randomize(val) with {val > 0; val <= 100;}); - if(val < req_rate_i) begin - dut_req_port_o.data_req = 1'b1; - // generate random address - void'(randomize(paddr) with {paddr >= 0; paddr < (MemWords<<3);}); - applyRandData(); - `APPL_WAIT_COMB_SIG(clk_i, dut_req_port_i.data_gnt) - end - `APPL_WAIT_CYC(clk_i,1) + task automatic genRandReq(); + automatic logic [63:0] val; + + void'($urandom(RndSeed)); + + paddr = '0; + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.data_be = '0; + dut_req_port_o.data_wdata = 'x; + + repeat(seq_num_vect_i) begin + // randomize request + dut_req_port_o.data_req = '0; + dut_req_port_o.data_be = '0; + dut_req_port_o.data_wdata = 'x; + void'(randomize(val) with {val > 0; val <= 100;}); + if(val < req_rate_i) begin + dut_req_port_o.data_req = 1'b1; + // generate random address + void'(randomize(paddr) with {paddr >= 0; paddr < (MemWords<<3);}); + applyRandData(); + `APPL_WAIT_COMB_SIG(clk_i, dut_req_port_i.data_gnt) + end + `APPL_WAIT_CYC(clk_i,1) + end + + paddr = '0; + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.data_be = '0; + dut_req_port_o.data_wdata = 'x; + + endtask : genRandReq + + task automatic genSeqWrite(); + automatic logic [63:0] val; + paddr = '0; + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.data_be = '0; + dut_req_port_o.data_wdata = 'x; + val = '0; + repeat(seq_num_vect_i) begin + dut_req_port_o.data_req = 1'b1; + dut_req_port_o.data_size = 2'b11; + dut_req_port_o.data_be = '1; + dut_req_port_o.data_wdata = val; + paddr = val; + // generate linear read + val = (val + 8) % (MemWords<<3); + `APPL_WAIT_COMB_SIG(clk_i, dut_req_port_i.data_gnt) + `APPL_WAIT_CYC(clk_i,1) + end + paddr = '0; + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.data_be = '0; + dut_req_port_o.data_wdata = 'x; + endtask : genSeqWrite + + task automatic genWrapSeq(); + automatic logic [63:0] val; + void'($urandom(RndSeed)); + + paddr = CachedAddrBeg; + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.data_be = '0; + dut_req_port_o.data_wdata = 'x; + val = '0; + repeat(seq_num_vect_i) begin + dut_req_port_o.data_req = 1'b1; + applyRandData(); + // generate wrapping read of 1 cacheline + paddr = CachedAddrBeg + val; + val = (val + 8) % (1*(DCACHE_LINE_WIDTH/64)*8); + `APPL_WAIT_COMB_SIG(clk_i, dut_req_port_i.data_gnt) + `APPL_WAIT_CYC(clk_i,1) + end + paddr = '0; + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.data_be = '0; + dut_req_port_o.data_wdata = 'x; + + endtask : genWrapSeq + + task automatic genSeqBurst(); + automatic logic [63:0] val; + automatic logic [7:0] be; + automatic logic [1:0] size; + automatic int cnt, burst_len; + + void'($urandom(RndSeed)); + + paddr = '0; + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.data_be = '0; + dut_req_port_o.data_wdata = 'x; + cnt = 0; + while(cnt < seq_num_vect_i) begin + // randomize request + dut_req_port_o.data_req = '0; + dut_req_port_o.data_be = '0; + dut_req_port_o.data_wdata = 'x; + void'(randomize(val) with {val > 0; val <= 100;}); + if(val < req_rate_i) begin + dut_req_port_o.data_req = 1'b1; + // generate random address base + void'(randomize(paddr) with {paddr >= 0; paddr < (MemWords<<3);}); + + // do a random burst + void'(randomize(burst_len) with {burst_len >= 0; burst_len < 100;}); + for(int k=0; k=0 val<=8;};); + paddr += 8; + cnt ++; end + end + `APPL_WAIT_CYC(clk_i,1) + end - paddr = '0; - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.data_be = '0; - dut_req_port_o.data_wdata = 'x; - - endtask : genRandReq - - task automatic genSeqWrite(); - automatic logic [63:0] val; - paddr = '0; - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.data_be = '0; - dut_req_port_o.data_wdata = 'x; - val = '0; - repeat(seq_num_vect_i) begin - dut_req_port_o.data_req = 1'b1; - dut_req_port_o.data_size = 2'b11; - dut_req_port_o.data_be = '1; - dut_req_port_o.data_wdata = val; - paddr = val; - // generate linear read - val = (val + 8) % (MemWords<<3); - `APPL_WAIT_COMB_SIG(clk_i, dut_req_port_i.data_gnt) - `APPL_WAIT_CYC(clk_i,1) - end - paddr = '0; - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.data_be = '0; - dut_req_port_o.data_wdata = 'x; - - endtask : genSeqWrite - - task automatic genWrapSeq(); - automatic logic [63:0] val; - void'($urandom(RndSeed)); - - paddr = CachedAddrBeg; - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.data_be = '0; - dut_req_port_o.data_wdata = 'x; - val = '0; - repeat(seq_num_vect_i) begin - dut_req_port_o.data_req = 1'b1; - applyRandData(); - // generate wrapping read of 1 cacheline - paddr = CachedAddrBeg + val; - val = (val + 8) % (1*(DCACHE_LINE_WIDTH/64)*8); - `APPL_WAIT_COMB_SIG(clk_i, dut_req_port_i.data_gnt) - `APPL_WAIT_CYC(clk_i,1) - end - paddr = '0; - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.data_be = '0; - dut_req_port_o.data_wdata = 'x; - - endtask : genWrapSeq - - task automatic genSeqBurst(); - automatic logic [63:0] val; - automatic logic [7:0] be; - automatic logic [1:0] size; - automatic int cnt, burst_len; - - void'($urandom(RndSeed)); - - paddr = '0; - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.data_be = '0; - dut_req_port_o.data_wdata = 'x; - cnt = 0; - while(cnt < seq_num_vect_i) begin - // randomize request - dut_req_port_o.data_req = '0; - dut_req_port_o.data_be = '0; - dut_req_port_o.data_wdata = 'x; - void'(randomize(val) with {val > 0; val <= 100;}); - if(val < req_rate_i) begin - dut_req_port_o.data_req = 1'b1; - // generate random address base - void'(randomize(paddr) with {paddr >= 0; paddr < (MemWords<<3);}); - - // do a random burst - void'(randomize(burst_len) with {burst_len >= 0; burst_len < 100;}); - for(int k=0; k=0 val<=8;};); - paddr += 8; - cnt ++; - end - end - `APPL_WAIT_CYC(clk_i,1) - end - - paddr = '0; - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.data_be = '0; - dut_req_port_o.data_wdata = 'x; - - endtask : genSeqBurst + paddr = '0; + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.data_be = '0; + dut_req_port_o.data_wdata = 'x; + endtask : genSeqBurst /////////////////////////////////////////////////////////////////////////////// // Sequence application /////////////////////////////////////////////////////////////////////////////// - initial begin : p_stim - paddr = '0; - - dut_req_port_o.data_req = '0; - dut_req_port_o.data_size = '0; - dut_req_port_o.data_be = '0; - dut_req_port_o.data_wdata = '0; - dut_req_port_o.tag_valid = '0; - dut_req_port_o.kill_req = '0; + initial begin : p_stim + paddr = '0; - seq_done_o = 1'b0; + dut_req_port_o.data_req = '0; + dut_req_port_o.data_size = '0; + dut_req_port_o.data_be = '0; + dut_req_port_o.data_wdata = '0; + dut_req_port_o.tag_valid = '0; + dut_req_port_o.kill_req = '0; - // print some info - $display("%s> current configuration:", PortName); - $display("%s> RndSeed %d", PortName, RndSeed); + seq_done_o = 1'b0; - `APPL_WAIT_CYC(clk_i,1) - `APPL_WAIT_SIG(clk_i,~rst_ni) - - $display("%s> starting application", PortName); - while(~seq_last_i) begin - `APPL_WAIT_SIG(clk_i,seq_run_i) - seq_done_o = 1'b0; - unique case(seq_type_i) - RANDOM_SEQ: begin - $display("%s> start random sequence with %04d vectors and req_rate %03d", PortName, seq_num_vect_i, req_rate_i); - genRandReq(); - end - LINEAR_SEQ: begin - $display("%s> start linear sequence with %04d vectors and req_rate %03d", PortName, seq_num_vect_i, req_rate_i); - genSeqWrite(); - end - WRAP_SEQ: begin - $display("%s> start wrapping sequence with %04d vectors and req_rate %03d", PortName, seq_num_vect_i, req_rate_i); - genWrapSeq(); - end - IDLE_SEQ: ;// do nothing - BURST_SEQ: begin - $display("%s> start burst sequence with %04d vectors and req_rate %03d", PortName, seq_num_vect_i, req_rate_i); - genSeqBurst(); - end - endcase // seq_type_i - seq_done_o = 1'b1; - $display("%s> stop sequence", PortName); - `APPL_WAIT_CYC(clk_i,1) + // print some info + $display("%s> current configuration:", PortName); + $display("%s> RndSeed %d", PortName, RndSeed); + + `APPL_WAIT_CYC(clk_i,1) + `APPL_WAIT_SIG(clk_i,~rst_ni) + + $display("%s> starting application", PortName); + while(~seq_last_i) begin + `APPL_WAIT_SIG(clk_i,seq_run_i) + seq_done_o = 1'b0; + unique case(seq_type_i) + RANDOM_SEQ: begin + $display("%s> start random sequence with %04d vectors and req_rate %03d", PortName, seq_num_vect_i, req_rate_i); + genRandReq(); end - $display("%s> ending application", PortName); + LINEAR_SEQ: begin + $display("%s> start linear sequence with %04d vectors and req_rate %03d", PortName, seq_num_vect_i, req_rate_i); + genSeqWrite(); + end + WRAP_SEQ: begin + $display("%s> start wrapping sequence with %04d vectors and req_rate %03d", PortName, seq_num_vect_i, req_rate_i); + genWrapSeq(); + end + IDLE_SEQ: ;// do nothing + BURST_SEQ: begin + $display("%s> start burst sequence with %04d vectors and req_rate %03d", PortName, seq_num_vect_i, req_rate_i); + genSeqBurst(); + end + endcase // seq_type_i + seq_done_o = 1'b1; + $display("%s> stop sequence", PortName); + `APPL_WAIT_CYC(clk_i,1) end - -/////////////////////////////////////////////////////// -// assertions -/////////////////////////////////////////////////////// - -//pragma translate_off -// `ifndef verilator -// exp_resp_vld: assert property ( -// @(posedge clk_i) disable iff (~rst_ni) dut_req_port_i.data_rvalid |-> exp_rdata_queue.size()>0 && exp_size_queue.size()>0 && exp_paddr_queue.size()>0) -// else $fatal(1, "expected response must be in the queue when DUT response returns"); - -// `endif -//pragma translate_on + $display("%s> ending application", PortName); + end endprogram // tb_readport diff --git a/tb/tb_serpent_icache/.gitignore b/tb/tb_serpent_icache/.gitignore index 0a96ce419..f8cb65465 100644 --- a/tb/tb_serpent_icache/.gitignore +++ b/tb/tb_serpent_icache/.gitignore @@ -1,3 +1,7 @@ work -modelsim.ini *.rep +transcript +*.ini +*.wlf +*.log + diff --git a/tb/tb_serpent_icache/Makefile b/tb/tb_serpent_icache/Makefile index 1e80149ae..7a1c9af73 100755 --- a/tb/tb_serpent_icache/Makefile +++ b/tb/tb_serpent_icache/Makefile @@ -1,23 +1,40 @@ +# 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: Michael Schaffner , ETH Zurich +# Date: 15.08.2018 +# Description: Makefile for the icache testbench. + + library ?= work toplevel ?= tb src-list := tb.list src := $(shell xargs printf '\n%s' < $(src-list) | cut -b 1-) -compile_flag += +cover+/dut -incr -64 -nologo +compile_flag += +cover+/dut -incr -64 -nologo sim_opts += -64 -coverage -classdebug -voptargs="+acc" questa_version ?= ${QUESTASIM_VERSION} +incdir += ../common/ build: clean vlib${questa_version} $(library) - vlog${questa_version} -work $(library) -pedanticerrors $(src) $(compile_flag) + vlog${questa_version} -work $(library) -pedanticerrors $(src) $(compile_flag) +incdir+$(incdir) touch $(library)/.build +# this starts modelsim with gui sim: build vsim${questa_version} -lib $(library) $(toplevel) -do "do wave.do" $(sim_opts) +# batch mode without gui simc: build vsim${questa_version} -lib $(library) $(toplevel) -c -do "run -all; exit" $(sim_opts) - clean: rm -rf $(library) diff --git a/tb/tb_serpent_icache/hdl/mem_emul.sv b/tb/tb_serpent_icache/hdl/mem_emul.sv index 39e376387..cf4279714 100644 --- a/tb/tb_serpent_icache/hdl/mem_emul.sv +++ b/tb/tb_serpent_icache/hdl/mem_emul.sv @@ -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: Michael Schaffner , ETH Zurich // Date: 15.08.2018 diff --git a/tb/tb_serpent_icache/hdl/tb.sv b/tb/tb_serpent_icache/hdl/tb.sv index 192458af9..dbf50148b 100644 --- a/tb/tb_serpent_icache/hdl/tb.sv +++ b/tb/tb_serpent_icache/hdl/tb.sv @@ -1,27 +1,23 @@ -// 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: Michael Schaffner , ETH Zurich // Date: 15.08.2018 // Description: testbench for piton_icache. includes the following tests: -// +// // 0) random accesses with disabled cache // 1) random accesses with enabled cache to cacheable and noncacheable memory // 2) linear, wrapping sweep with enabled cache -// 3) 1) with random stalls on the memory side and TLB side +// 3) 1) with random stalls on the memory side and TLB side // 4) nr 3) with random invalidations -// +// // note that we use a simplified address translation scheme to emulate the TLB. // (random offsets). @@ -29,8 +25,10 @@ import ariane_pkg::*; import serpent_cache_pkg::*; import tb_pkg::*; +`include "tb.svh" + module tb; - + // leave this timeunit 1ps; timeprecision 1ps; @@ -40,7 +38,7 @@ module tb; parameter MemWords = MemBytes>>2; parameter logic [63:0] CachedAddrBeg = MemBytes/4; parameter logic [63:0] CachedAddrEnd = 64'hFFFF_FFFF_FFFF_FFFF; - + // rates are in percent parameter TlbRandHitRate = 50; parameter MemRandHitRate = 50; @@ -95,22 +93,22 @@ module tb; logic exp_empty, exp_pop; logic dut_out_vld, dut_in_rdy; - + /////////////////////////////////////////////////////////////////////////////// // Clock Process /////////////////////////////////////////////////////////////////////////////// - + always @* begin do begin - clk_i = 1;#(CLK_HI); - clk_i = 0;#(CLK_LO); + clk_i = 1;#(CLK_HI); + clk_i = 0;#(CLK_LO); end while (end_of_sim == 1'b0); repeat (100) begin - // generate a few extra cycle to allow response acquisition to complete - clk_i = 1;#(CLK_HI); - clk_i = 0;#(CLK_LO); - end + // generate a few extra cycle to allow response acquisition to complete + clk_i = 1;#(CLK_HI); + clk_i = 0;#(CLK_LO); + end end /////////////////////////////////////////////////////////////////////////////// @@ -129,23 +127,23 @@ module tb; stim_end = 0; stim_start = 1; - applWaitCyc(clk_i,10); + `APPL_WAIT_CYC(clk_i,10) stim_start = 0; - + // start with clean cache flush_i = 1; - applWaitCyc(clk_i,1); + `APPL_WAIT_CYC(clk_i,1) flush_i = 0; while(~acq_done) begin // randomize request dreq_i.req = 0; ok = randomize(val) with {val > 0; val <= 100;}; - if (val < SeqRate) begin + if (val < SeqRate) begin dreq_i.req = 1; // generate random address ok = randomize(val) with {val >= 0; val < (MemBytes-TlbOffset)>>2;}; - dreq_i.vaddr = val<<2;// align to 4Byte + dreq_i.vaddr = val<<2;// align to 4Byte // generate random control events ok = randomize(val) with {val > 0; val <= 100;}; dreq_i.kill_s1 = (val < S1KillRate); @@ -153,11 +151,11 @@ module tb; dreq_i.kill_s2 = (val < S2KillRate); ok = randomize(val) with {val > 0; val <= 100;}; flush_i = (val < FlushRate); - applWait(clk_i, dut_in_rdy); + `APPL_WAIT_SIG(clk_i, dut_in_rdy) end else begin - applWaitCyc(clk_i,1); + `APPL_WAIT_CYC(clk_i,1) end - end + end stim_end = 1; endtask : genRandReq @@ -174,12 +172,12 @@ module tb; stim_end = 0; stim_start = 1; - applWaitCyc(clk_i,10); + `APPL_WAIT_CYC(clk_i,10) stim_start = 0; // start with clean cache flush_i = 1; - applWaitCyc(clk_i,1); + `APPL_WAIT_CYC(clk_i,1) flush_i = 0; while(~acq_done) begin @@ -187,8 +185,8 @@ module tb; dreq_i.vaddr = addr; // generate linear read addr = (addr + 4) % (MemBytes - TlbOffset); - applWait(clk_i, dut_in_rdy); - end + `APPL_WAIT_SIG(clk_i, dut_in_rdy) + end stim_end = 1; endtask : genSeqRead @@ -196,10 +194,10 @@ module tb; /////////////////////////////////////////////////////////////////////////////// // TLB and memory emulation /////////////////////////////////////////////////////////////////////////////// - -tlb_emul #( + + tlb_emul #( .TlbRandHitRate(TlbRandHitRate) -) i_tlb_emul ( + ) i_tlb_emul ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .tlb_rand_en_i ( tlb_rand_en ), @@ -208,87 +206,87 @@ tlb_emul #( // icache interface .req_i ( areq_o ), .req_o ( areq_i ) -); + ); -mem_emul #( - .MemRandHitRate ( MemRandHitRate ), - .MemRandInvRate ( MemRandInvRate ), - .MemWords ( MemWords ), - .CachedAddrBeg ( CachedAddrBeg ) -) i_mem_emul ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .mem_rand_en_i ( mem_rand_en ), - .io_rand_en_i ( io_rand_en ), - .inv_rand_en_i ( inv_rand_en ), - .tlb_offset_i ( TlbOffset ), - .stim_vaddr_i ( stim_vaddr ), - .stim_push_i ( stim_push ), - .stim_flush_i ( stim_flush ), - .stim_full_o ( stim_full ), - .exp_data_o ( exp_data ), - .exp_vaddr_o ( exp_vaddr ), - .exp_empty_o ( exp_empty ), - .exp_pop_i ( exp_pop ), - .mem_data_req_i ( mem_data_req_o ), - .mem_data_ack_o ( mem_data_ack_i ), - .mem_data_i ( mem_data_o ), - .mem_rtrn_vld_o ( mem_rtrn_vld_i ), - .mem_rtrn_o ( mem_rtrn_i ) -); + mem_emul #( + .MemRandHitRate ( MemRandHitRate ), + .MemRandInvRate ( MemRandInvRate ), + .MemWords ( MemWords ), + .CachedAddrBeg ( CachedAddrBeg ) + ) i_mem_emul ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .mem_rand_en_i ( mem_rand_en ), + .io_rand_en_i ( io_rand_en ), + .inv_rand_en_i ( inv_rand_en ), + .tlb_offset_i ( TlbOffset ), + .stim_vaddr_i ( stim_vaddr ), + .stim_push_i ( stim_push ), + .stim_flush_i ( stim_flush ), + .stim_full_o ( stim_full ), + .exp_data_o ( exp_data ), + .exp_vaddr_o ( exp_vaddr ), + .exp_empty_o ( exp_empty ), + .exp_pop_i ( exp_pop ), + .mem_data_req_i ( mem_data_req_o ), + .mem_data_ack_o ( mem_data_ack_i ), + .mem_data_i ( mem_data_o ), + .mem_rtrn_vld_o ( mem_rtrn_vld_i ), + .mem_rtrn_o ( mem_rtrn_i ) + ); /////////////////////////////////////////////////////////////////////////////// // MUT /////////////////////////////////////////////////////////////////////////////// -serpent_icache #( - .CachedAddrBeg(CachedAddrBeg), - .CachedAddrEnd(CachedAddrEnd) - ) dut ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .flush_i ( flush_i ), - .en_i ( en_i ), - .miss_o ( miss_o ), - .areq_i ( areq_i ), - .areq_o ( areq_o ), - .dreq_i ( dreq_i ), - .dreq_o ( dreq_o ), - .mem_rtrn_vld_i ( mem_rtrn_vld_i ), - .mem_rtrn_i ( mem_rtrn_i ), - .mem_data_req_o ( mem_data_req_o ), - .mem_data_ack_i ( mem_data_ack_i ), - .mem_data_o ( mem_data_o ) -); + serpent_icache #( + .CachedAddrBeg(CachedAddrBeg), + .CachedAddrEnd(CachedAddrEnd) + ) dut ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .flush_i ( flush_i ), + .en_i ( en_i ), + .miss_o ( miss_o ), + .areq_i ( areq_i ), + .areq_o ( areq_o ), + .dreq_i ( dreq_i ), + .dreq_o ( dreq_o ), + .mem_rtrn_vld_i ( mem_rtrn_vld_i ), + .mem_rtrn_i ( mem_rtrn_i ), + .mem_data_req_o ( mem_data_req_o ), + .mem_data_ack_i ( mem_data_ack_i ), + .mem_data_o ( mem_data_o ) + ); -// connect interface to expected response channel of memory emulation -assign stim_vaddr = dreq_i.vaddr; -assign stim_push = dreq_i.req & dreq_o.ready & (~dreq_i.kill_s1) & (~flush_i); -assign stim_flush = 0; -assign exp_pop = (dreq_o.valid | dreq_i.kill_s2) & (~exp_empty); + // connect interface to expected response channel of memory emulation + assign stim_vaddr = dreq_i.vaddr; + assign stim_push = dreq_i.req & dreq_o.ready & (~dreq_i.kill_s1) & (~flush_i); + assign stim_flush = 0; + assign exp_pop = (dreq_o.valid | dreq_i.kill_s2) & (~exp_empty); /////////////////////////////////////////////////////////////////////////////// // stimuli application process /////////////////////////////////////////////////////////////////////////////// - + assign dut_in_rdy = dreq_o.ready; initial // process runs just once - begin : p_stim - end_of_sim = 0; + begin : p_stim + end_of_sim = 0; num_vectors = 0; stim_start = 0; stim_end = 0; - + rst_ni = 0; - + mem_rand_en = 0; tlb_rand_en = 0; inv_rand_en = 0; exception_en = 0; io_rand_en = 0; - dreq_i.req = 0; + dreq_i.req = 0; dreq_i.kill_s1 = 0; dreq_i.kill_s2 = 0; dreq_i.vaddr = 0; @@ -305,35 +303,35 @@ assign exp_pop = (dreq_o.valid | dreq_i.kill_s2) & (~exp_empty); $display("TB> S1KillRate %d", S1KillRate); $display("TB> S2KillRate %d", S2KillRate); $display("TB> FlushRate %d", FlushRate); - - applWaitCyc(clk_i,100); + + `APPL_WAIT_CYC(clk_i,100); $display("TB> choose TLB offset %16X", TlbOffset); // reset cycles - applWaitCyc(clk_i,100); - rst_ni = 1'b1; - applWaitCyc(clk_i,100); - - $display("TB> stimuli application started"); - // apply each test until NUM_ACCESSES memory + `APPL_WAIT_CYC(clk_i,100); + rst_ni = 1'b1; + `APPL_WAIT_CYC(clk_i,100); + + $display("TB> stimuli application started"); + // apply each test until NUM_ACCESSES memory // requests have successfully completed /////////////////////////////////////////////// // TEST 0 en_i = 0; genRandReq(); - applWaitCyc(clk_i,40); + `APPL_WAIT_CYC(clk_i,40); /////////////////////////////////////////////// // TEST 1 test_name = "TEST1, enabled cache"; en_i = 1; genRandReq(); - applWaitCyc(clk_i,40); + `APPL_WAIT_CYC(clk_i,40); /////////////////////////////////////////////// // TEST 2 test_name = "TEST2, enabled cache, sequential reads"; en_i = 1; genSeqRead(); - applWaitCyc(clk_i,40); + `APPL_WAIT_CYC(clk_i,40); /////////////////////////////////////////////// // TEST 3 test_name = "TEST3, enabled cache, random stalls in mem and TLB side"; @@ -341,7 +339,7 @@ assign exp_pop = (dreq_o.valid | dreq_i.kill_s2) & (~exp_empty); mem_rand_en = 1; tlb_rand_en = 1; genRandReq(); - applWaitCyc(clk_i,40); + `APPL_WAIT_CYC(clk_i,40); /////////////////////////////////////////////// // TEST 4 test_name = "TEST4, +random invalidations"; @@ -350,20 +348,20 @@ assign exp_pop = (dreq_o.valid | dreq_i.kill_s2) & (~exp_empty); tlb_rand_en = 1; inv_rand_en = 1; genRandReq(); - applWaitCyc(clk_i,40); + `APPL_WAIT_CYC(clk_i,40); /////////////////////////////////////////////// end_of_sim = 1; - $display("TB> stimuli application ended"); - end + $display("TB> stimuli application ended"); + end /////////////////////////////////////////////////////////////////////////////// // stimuli acquisition process /////////////////////////////////////////////////////////////////////////////// - + assign dut_out_vld = dreq_o.valid; initial // process runs just once - begin : p_acq + begin : p_acq bit ok; progress status; @@ -379,39 +377,39 @@ assign exp_pop = (dreq_o.valid | dreq_i.kill_s2) & (~exp_empty); n=0; while (~end_of_sim) begin // wait for stimuli application - acqWait(clk_i, stim_start); + `ACQ_WAIT_SIG(clk_i, stim_start); $display("TB: ----------------------------------------------------------------------\n"); - $display("TB> %s", test_name); - + $display("TB> %s", test_name); + status.reset(num_vectors); acq_done = 0; for (int k=0;k %s", tmpstr); - end + end status.addRes(!ok); status.print(); end acq_done = 1; n++; // wait for stimuli application end - acqWait(clk_i, stim_end); - acqWaitCyc(clk_i,100); - end + `ACQ_WAIT_SIG(clk_i, stim_end); + `ACQ_WAIT_CYC(clk_i,100); + end /////////////////////////////////////////////// - - status.printToFile("summary.rep", 1); - + + status.printToFile("summary.rep", 1); + if(status.totErrCnt == 0) begin $display("TB: ----------------------------------------------------------------------\n"); $display("TB: PASSED %0d VECTORS", status.totAcqCnt); @@ -423,12 +421,12 @@ assign exp_pop = (dreq_o.valid | dreq_i.kill_s2) & (~exp_empty); $display("%s", failingTests); $display("TB: ----------------------------------------------------------------------\n"); end - end + end endmodule - + diff --git a/tb/tb_serpent_icache/hdl/tb_pkg.sv b/tb/tb_serpent_icache/hdl/tb_pkg.sv index 57326067a..ae461862a 100644 --- a/tb/tb_serpent_icache/hdl/tb_pkg.sv +++ b/tb/tb_serpent_icache/hdl/tb_pkg.sv @@ -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: Michael Schaffner , ETH Zurich // Date: 15.08.2018 @@ -20,7 +16,7 @@ package tb_pkg; // // for abs(double) function - // import mti_cstdlib::*; + // import mti_cstdlib::*; // for timestamps import "DPI-C" \time = function int _time (inout int tloc[4]); @@ -29,53 +25,19 @@ package tb_pkg; /////////////////////////////////////////////////////////////////////////////// // parameters /////////////////////////////////////////////////////////////////////////////// - - // creates a 10ns ATI timing cycle - time CLK_HI = 5ns; // set clock high time - time CLK_LO = 5ns; // set clock low time - time APPL_DEL = 2ns; // set stimuli application delay - time ACQ_DEL = 8ns; // set response aquisition delay + + // creates a 10ns ATI timing cycle + time CLK_HI = 5ns; // set clock high time + time CLK_LO = 5ns; // set clock low time + time APPL_DEL = 2ns; // set stimuli application delay + time ACQ_DEL = 8ns; // set response aquisition delay parameter ERROR_CNT_STOP_LEVEL = 1; // use 1 for debugging. 0 runs the complete simulation... -////////////////////////////////////////////////////////////////////////////// -// use to ensure proper ATI timing +/////////////////////////////////////////////////////////////////////////////// +// progress /////////////////////////////////////////////////////////////////////////////// - task automatic applWaitCyc(ref logic Clk_C, input int unsigned n); - if (n > 0) begin - repeat (n) @(posedge(Clk_C)); - #(APPL_DEL); - end - endtask - - task automatic acqWaitCyc(ref logic Clk_C, input int unsigned n); - if (n > 0) begin - repeat (n) @(posedge(Clk_C)); - #(ACQ_DEL); - end - endtask - - // sample right on active clock edge - task automatic applWait(ref logic Clk_C, ref logic SigToWaitFor_S); - do begin - @(posedge(Clk_C)); - end while(SigToWaitFor_S == 1'b0); - #(APPL_DEL); - endtask - - // sample right on active clock edge - task automatic acqWait(ref logic Clk_C, ref logic SigToWaitFor_S); - do begin - @(posedge(Clk_C)); - end while(SigToWaitFor_S == 1'b0); - //#(ACQ_DEL); - endtask - -/////////////////////////////////////////////////////////////////////////////// -// progress -/////////////////////////////////////////////////////////////////////////////// - class progress; real newState, oldState; longint numResp, acqCnt, errCnt, totAcqCnt, totErrCnt; @@ -90,20 +52,20 @@ package tb_pkg; this.totAcqCnt = 0; this.totErrCnt = 0; - end + end endfunction : new - + function void reset(longint numResp_); begin this.acqCnt = 0; this.errCnt = 0; this.newState = 0.0; this.oldState = 0.0; - this.numResp = numResp_; - end + this.numResp = numResp_; + end endfunction : reset - function void addRes(int isError); + function void addRes(int isError); begin this.acqCnt++; this.totAcqCnt++; @@ -111,16 +73,16 @@ package tb_pkg; this.totErrCnt += isError; if(ERROR_CNT_STOP_LEVEL <= this.errCnt && ERROR_CNT_STOP_LEVEL > 0) begin - $error("TB> simulation stopped (ERROR_CNT_STOP_LEVEL = %d reached).", ERROR_CNT_STOP_LEVEL); + $error("TB> simulation stopped (ERROR_CNT_STOP_LEVEL = %d reached).", ERROR_CNT_STOP_LEVEL); $stop(); - end - end + end + end endfunction : addRes - function void print(); + function void print(); begin this.newState = $itor(this.acqCnt) / $itor(this.numResp); - if(this.newState - this.oldState >= 0.01) begin + if(this.newState - this.oldState >= 0.01) begin $display("TB> validated %03d%% -- %01d failed (%03.3f%%) ", $rtoi(this.newState*100.0), this.errCnt, @@ -131,10 +93,10 @@ package tb_pkg; end endfunction : print - function void printToFile(string file, bit summary = 0); + function void printToFile(string file, bit summary = 0); begin int fptr; - + // sanitize string for(fptr=0; fptr<$size(file);fptr++) begin if(file[fptr] == " " || file[fptr] == "/" || file[fptr] == "\\") begin @@ -155,13 +117,13 @@ package tb_pkg; end else begin $fdisplay(fptr, "CI: FAILED"); end - end else begin + end else begin $fdisplay(fptr, "test name: %s", file); $fdisplay(fptr, "this test: %01d of %01d vectors failed (%03.3f%%) ", this.errCnt, this.acqCnt, $itor(this.errCnt) / $itor(this.acqCnt) * 100.0); - + $fdisplay(fptr, "total so far: %01d of %01d vectors failed (%03.3f%%) ", this.totErrCnt, this.totAcqCnt, diff --git a/tb/tb_serpent_icache/hdl/tlb_emul.sv b/tb/tb_serpent_icache/hdl/tlb_emul.sv index b58debf0c..e296bc85b 100644 --- a/tb/tb_serpent_icache/hdl/tlb_emul.sv +++ b/tb/tb_serpent_icache/hdl/tlb_emul.sv @@ -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: Michael Schaffner , ETH Zurich // Date: 15.08.2018 @@ -21,55 +17,54 @@ import ariane_pkg::*; import serpent_cache_pkg::*; module tlb_emul #( - parameter TlbRandHitRate = 10 //in percent -)( + parameter TlbRandHitRate = 10 //in percent +) ( + input logic clk_i, + input logic rst_ni, - input logic clk_i, - input logic rst_ni, - - input logic tlb_rand_en_i, - input logic exception_en_i, - input logic [63:0] tlb_offset_i, - - // icache interface - input icache_areq_o_t req_i, - output icache_areq_i_t req_o + input logic tlb_rand_en_i, + input logic exception_en_i, + input logic [63:0] tlb_offset_i, + + // icache interface + input icache_areq_o_t req_i, + output icache_areq_i_t req_o ); - -logic tlb_ready_d, tlb_ready_q; + +logic tlb_ready_d, tlb_ready_q; always_ff @(posedge clk_i or negedge rst_ni) begin : p_tlb_rand - automatic bit ok = 0; - automatic int rnd = 0; + automatic bit ok = 0; + automatic int rnd = 0; - assert(TlbRandHitRate<=100 && TlbRandHitRate>=0) else - $fatal("TlbRandHitRate must be a percentage"); + assert(TlbRandHitRate<=100 && TlbRandHitRate>=0) else + $fatal("TlbRandHitRate must be a percentage"); - if(~rst_ni) begin - tlb_ready_q <= '0; + if(~rst_ni) begin + tlb_ready_q <= '0; + end else begin + if (tlb_rand_en_i) begin + ok = randomize(rnd) with {rnd > 0; rnd <= 100;}; + if(rnd < TlbRandHitRate) begin + tlb_ready_q = '1; + end else + tlb_ready_q = '0; end else begin - if (tlb_rand_en_i) begin - ok = randomize(rnd) with {rnd > 0; rnd <= 100;}; - if(rnd < TlbRandHitRate) begin - tlb_ready_q = '1; - end else - tlb_ready_q = '0; - end else begin - tlb_ready_q = '1; - end + tlb_ready_q = '1; end + end end // TODO: add random exceptions always_comb begin : proc_tlb - req_o.fetch_valid = '0; - req_o.fetch_paddr = '0; - req_o.fetch_exception = '0; + req_o.fetch_valid = '0; + req_o.fetch_paddr = '0; + req_o.fetch_exception = '0; - if (req_i.fetch_req && tlb_ready_q) begin - req_o.fetch_valid = 1'b1; - req_o.fetch_paddr = req_i.fetch_vaddr + tlb_offset_i; - end + if (req_i.fetch_req && tlb_ready_q) begin + req_o.fetch_valid = 1'b1; + req_o.fetch_paddr = req_i.fetch_vaddr + tlb_offset_i; + end end endmodule // tlb_emul