Adds cacheable region rules to the configuration script, modify instruction traces such that it can be used with VCS

This commit is contained in:
Michael Schaffner 2019-04-25 16:33:35 +02:00
parent 50b4a5d58b
commit 0b95796858
No known key found for this signature in database
GPG key ID: 7AA09AE049819C2C
19 changed files with 272 additions and 426 deletions

View file

@ -68,8 +68,8 @@ ariane_pkg := $(addprefix $(root-dir), $(ariane_pkg))
# utility modules
util := $(wildcard src/util/*.svh) \
src/util/instruction_tracer_pkg.sv \
src/util/instruction_tracer_if.sv \
src/util/instruction_tracer.sv \
src/tech_cells_generic/src/cluster_clock_gating.sv \
tb/common/mock_uart.sv \
src/util/sram.sv

View file

@ -86,7 +86,6 @@ module ariane_xilinx (
// 24 MByte in 8 byte words
localparam NumWords = (24 * 1024 * 1024) / 8;
localparam NBSlave = 2; // debug, ariane
localparam logic [63:0] CacheStartAddr = 64'h8000_0000;
localparam AxiAddrWidth = 64;
localparam AxiDataWidth = 64;
localparam AxiIdWidthMaster = 4;
@ -347,7 +346,7 @@ ariane_axi::req_t axi_ariane_req;
ariane_axi::resp_t axi_ariane_resp;
ariane #(
.CachedAddrBeg ( CacheStartAddr )
.ArianeCfg ( ArianeSocCfg )
) i_ariane (
.clk_i ( clk ),
.rst_ni ( ndmreset_n ),

View file

@ -31,46 +31,101 @@ package ariane_pkg;
// This is the new user config interface system. If you need to parameterize something
// within Ariane add a field here and assign a default value to the config. Please make
// sure to add a propper parameter check to the `check_cfg` function.
localparam NrMaxRules = 16;
typedef struct packed {
int NrNonIdempotentRules; // Number of non idempotent rules
logic [15:0][63:0] NonIdempotentAddrBase; // base which needs to match
logic [15:0][63:0] NonIdempotentLength; // bit mask which bits to consider when matching the rule
int NrExecuteRegionRules; // Number of regions which have execute property
logic [15:0][63:0] ExecuteRegionAddrBase; // base which needs to match
logic [15:0][63:0] ExecuteRegionLength; // bit mask which bits to consider when matching the rule
// PMAs
int NrNonIdempotentRules; // Number of non idempotent rules
logic [NrMaxRules-1:0][63:0] NonIdempotentAddrBase; // base which needs to match
logic [NrMaxRules-1:0][63:0] NonIdempotentLength; // bit mask which bits to consider when matching the rule
int NrExecuteRegionRules; // Number of regions which have execute property
logic [NrMaxRules-1:0][63:0] ExecuteRegionAddrBase; // base which needs to match
logic [NrMaxRules-1:0][63:0] ExecuteRegionLength; // bit mask which bits to consider when matching the rule
int NrCachedRegionRules; // Number of regions which have cached property
logic [NrMaxRules-1:0][63:0] CachedRegionAddrBase; // base which needs to match
logic [NrMaxRules-1:0][63:0] CachedRegionLength; // bit mask which bits to consider when matching the rule
// cache config
bit Axi64BitCompliant; // set to 1 when using in conjunction with 64bit AXI bus adapter
bit SwapEndianess; // set to 1 to swap endianess inside L1.5 openpiton adapter
//
logic [63:0] DmBaseAddress; // offset of the debug module
} ariane_cfg_t;
localparam ariane_cfg_t ArianeDefaultConfig = '{
// idempotent region
NrNonIdempotentRules: 2,
NonIdempotentAddrBase: {64'b0, 64'b0},
NonIdempotentLength: {64'b0, 64'b0},
NrExecuteRegionRules: 3,
// DRAM, Boot ROM, Debug Module
ExecuteRegionAddrBase: {64'h8000_0000, 64'h1_0000, 64'h0},
ExecuteRegionLength: {64'h40000000, 64'h10000, 64'h1000}
ExecuteRegionLength: {64'h40000000, 64'h10000, 64'h1000},
// cached region
NrCachedRegionRules: 1,
CachedRegionAddrBase: {64'h8000_0000},
CachedRegionLength: {64'h40000000},
// cache config
Axi64BitCompliant: 1'b1,
SwapEndianess: 1'b0,
// debug
DmBaseAddress: 64'h0
};
// Function being called to check parameters
function automatic void check_cfg (ariane_cfg_t Cfg);
// pragma translate_off
`ifndef VERILATOR
assert(Cfg.NrNonIdempotentRules <= 16);
assert(Cfg.NrExecuteRegionRules <= 16);
assert(Cfg.NrNonIdempotentRules <= NrMaxRules);
assert(Cfg.NrExecuteRegionRules <= NrMaxRules);
assert(Cfg.NrCachedRegionRules <= NrMaxRules);
`endif
// pragma translate_on
endfunction
// Generate a mask for a given power of two length
function logic [63:0] gen_mask (input logic [63:0] len);
// pragma translate_off
`ifndef VERILATOR
// check that the region we want is actually power of two aligned
assert (2**$clog2(len) == len) else $error("Length must be a power of two");
`endif
// pragma translate_on
return {64{1'b1}} << $clog2(len);
endfunction
function automatic logic range_check(logic[63:0] base, logic[63:0] len, logic[63:0] address);
// if len is a power of two, and base is properly aligned, this chack can be simplified
automatic logic[63:0] mask;
// mask = gen_mask(len);
// if ((64'b1<<$clog2(len) == len) && (mask & base == base)) begin
// return (address & mask) == (base & mask);
// end else begin
return (address >= base) && (address < (base+len));
// end
endfunction : range_check
function automatic logic is_inside_nonidempotent_regions (ariane_cfg_t Cfg, logic[63:0] address);
logic[NrMaxRules-1:0] pass;
pass = '0;
for (int unsigned k=0; k<Cfg.NrNonIdempotentRules; k++) begin
pass[k] = range_check(Cfg.NonIdempotentAddrBase[k], Cfg.NonIdempotentLength[k], address);
end
return |pass;
endfunction : is_inside_nonidempotent_regions
function automatic logic is_inside_execute_regions (ariane_cfg_t Cfg, logic[63:0] address);
// if we don't specify any region we assume everything is accessible
logic[NrMaxRules-1:0] pass;
pass = '0;
for (int unsigned k=0; k<Cfg.NrExecuteRegionRules; k++) begin
pass[k] = range_check(Cfg.ExecuteRegionAddrBase[k], Cfg.ExecuteRegionLength[k], address);
end
return |pass;
endfunction : is_inside_execute_regions
function automatic logic is_inside_cacheable_regions (ariane_cfg_t Cfg, logic[63:0] address);
automatic logic[NrMaxRules-1:0] pass;
pass = '0;
for (int unsigned k=0; k<Cfg.NrCachedRegionRules; k++) begin
pass[k] = range_check(Cfg.CachedRegionAddrBase[k], Cfg.CachedRegionLength[k], address);
end
return |pass;
endfunction : is_inside_cacheable_regions
// TODO: Slowly move those parameters to the new system.
localparam NR_SB_ENTRIES = 8; // number of scoreboard entries
localparam TRANS_ID_BITS = $clog2(NR_SB_ENTRIES); // depending on the number of scoreboard entries we need that many bits

View file

@ -14,10 +14,23 @@
module ariane_verilog_wrap #(
parameter logic [63:0] DmBaseAddress = 64'h0, // debug module base address
parameter bit SwapEndianess = 1, // swap endianess in l15 adapter
parameter logic [63:0] CachedAddrEnd = 64'h80_0000_0000, // end of cached region
parameter logic [63:0] CachedAddrBeg = 64'h00_8000_0000 // begin of cached region
// debug module base address
parameter logic [63:0] DmBaseAddress = 64'h0,
// swap endianess in l15 adapter
parameter bit SwapEndianess = 1,
// PMA configuration
// idempotent region
parameter int NrNonIdempotentRules = 0,
parameter logic [NrMaxRules*64-1:0] NonIdempotentAddrBase = '0,
parameter logic [NrMaxRules*64-1:0] NonIdempotentLength = '0,
// executable regions
parameter int NrExecuteRegionRules = 0,
parameter logic [NrMaxRules*64-1:0] ExecuteRegionAddrBase = '0,
parameter logic [NrMaxRules*64-1:0] ExecuteRegionLength = '0,
// cacheable regions
parameter int NrCachedRegionRules = 0,
parameter logic [NrMaxRules*64-1:0] CachedRegionAddrBase = '0,
parameter logic [NrMaxRules*64-1:0] CachedRegionLength = '0
) (
input clk_i,
input reset_l, // this is an openpiton-specific name, do not change (hier. paths in TB use this)
@ -150,11 +163,27 @@ module ariane_verilog_wrap #(
// ariane instance
/////////////////////////////
localparam ariane_pkg::ariane_cfg_t ArianeOpenPitonCfg = '{
// idempotent region
NrNonIdempotentRules: NrNonIdempotentRules,
NonIdempotentAddrBase: NonIdempotentAddrBase,
NonIdempotentLength: NonIdempotentLength,
NrExecuteRegionRules: NrExecuteRegionRules,
ExecuteRegionAddrBase: ExecuteRegionAddrBase,
ExecuteRegionLength: ExecuteRegionLength,
// cached region
NrCachedRegionRules: NrCachedRegionRules,
CachedRegionAddrBase: CachedRegionAddrBase,
CachedRegionLength: CachedRegionLength,
// cache config
Axi64BitCompliant: 1'b0,
SwapEndianess: SwapEndianess,
// debug
DmBaseAddress: DmBaseAddress
};
ariane #(
.DmBaseAddress ( DmBaseAddress ),
.SwapEndianess ( SwapEndianess ),
.CachedAddrEnd ( CachedAddrEnd ),
.CachedAddrBeg ( CachedAddrBeg )
.ArianeCfg ( ArianeOpenPitonCfg )
) ariane (
.clk_i ( clk_i ),
.rst_ni ( spc_grst_l ),

View file

@ -13,20 +13,11 @@
// Description: Ariane Top-level module
import ariane_pkg::*;
// pragma translate_off
`ifndef VERILATOR
import instruction_tracer_pkg::*;
`endif
// pragma translate_on
module ariane #(
parameter logic [63:0] DmBaseAddress = 64'h0, // debug module base address
parameter int unsigned AxiIdWidth = 4,
parameter bit SwapEndianess = 0, // swap endianess in l15 adapter
parameter logic [63:0] CachedAddrEnd = 64'h80_0000_0000, // end of cached region
parameter logic [63:0] CachedAddrBeg = 64'h00_8000_0000, // begin of cached region
parameter ariane_pkg::ariane_cfg_t Cfg = ariane_pkg::ArianeDefaultConfig
parameter int unsigned AxiIdWidth = 4,
parameter bit SwapEndianess = 0, // swap endianess in l15 adapter
parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig
) (
input logic clk_i,
input logic rst_ni,
@ -231,7 +222,7 @@ module ariane #(
// Frontend
// --------------
frontend #(
.DmBaseAddress ( DmBaseAddress )
.DmBaseAddress ( ArianeCfg.DmBaseAddress )
) i_frontend (
.flush_i ( flush_ctrl_if ), // not entirely correct
.flush_bp_i ( 1'b0 ),
@ -341,7 +332,7 @@ module ariane #(
// EX
// ---------
ex_stage #(
.Cfg ( Cfg )
.ArianeCfg ( ArianeCfg )
) ex_stage_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@ -465,7 +456,7 @@ module ariane #(
// ---------
csr_regfile #(
.AsidWidth ( ASID_WIDTH ),
.DmBaseAddress ( DmBaseAddress )
.DmBaseAddress ( ArianeCfg.DmBaseAddress )
) csr_regfile_i (
.flush_o ( flush_csr_ctrl ),
.halt_csr_o ( halt_csr_ctrl ),
@ -580,9 +571,7 @@ module ariane #(
// this is a cache subsystem that is compatible with OpenPiton
wt_cache_subsystem #(
.AxiIdWidth ( AxiIdWidth ),
.CachedAddrBeg ( CachedAddrBeg ),
.CachedAddrEnd ( CachedAddrEnd ),
.SwapEndianess ( SwapEndianess )
.ArianeCfg ( ArianeCfg )
) i_cache_subsystem (
// to D$
.clk_i ( clk_i ),
@ -620,7 +609,10 @@ module ariane #(
`else
std_cache_subsystem #(
.CACHE_START_ADDR ( CachedAddrBeg )
// note: this only works with one cacheable region
// not as important since this cache subsystem is about to be
// deprecated
.CACHE_START_ADDR ( ArianeCfg.CachedRegionAddrBase )
) i_cache_subsystem (
// to D$
.clk_i ( clk_i ),
@ -658,7 +650,7 @@ module ariane #(
// -------------------
// pragma translate_off
`ifndef VERILATOR
initial ariane_pkg::check_cfg(Cfg);
initial ariane_pkg::check_cfg(ArianeCfg);
`endif
// pragma translate_on
@ -748,25 +740,11 @@ module ariane #(
// assign current privilege level
assign tracer_if.priv_lvl = priv_lvl;
assign tracer_if.debug_mode = debug_mode;
instr_tracer instr_tracer_i (tracer_if, hart_id_i);
program instr_tracer (
instruction_tracer_if tracer_if,
input logic [63:0] hart_id_i
);
instruction_tracer it = new (tracer_if, 1'b0);
initial begin
#15ns;
it.create_file(hart_id_i);
it.trace();
end
final begin
it.close();
end
endprogram
instruction_tracer instr_tracer_i (
.tracer_if(tracer_if),
.hart_id_i
);
// mock tracer for Verilator, to be used with spike-dasm
`else

View file

@ -22,10 +22,8 @@ import ariane_pkg::*;
import wt_cache_pkg::*;
module wt_cache_subsystem #(
parameter int unsigned AxiIdWidth = 10,
parameter logic [63:0] CachedAddrBeg = 64'h00_8000_0000, // begin of cached region
parameter logic [63:0] CachedAddrEnd = 64'h80_0000_0000, // end of cached region
parameter bit SwapEndianess = 0 // swap endianess in l15 adapter
parameter int unsigned AxiIdWidth = 10,
parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig // contains cacheable regions
) (
input logic clk_i,
input logic rst_ni,
@ -75,15 +73,9 @@ module wt_cache_subsystem #(
wt_cache_pkg::dcache_rtrn_t adapter_dcache;
wt_icache #(
`ifdef PITON_ARIANE
.Axi64BitCompliant ( 1'b0 ),
`else
.Axi64BitCompliant ( 1'b1 ),
`endif
// use ID 0 for icache reads
.RdTxId ( 0 ),
.CachedAddrBeg ( CachedAddrBeg ),
.CachedAddrEnd ( CachedAddrEnd )
.ArianeCfg ( ArianeCfg )
) i_wt_icache (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@ -107,16 +99,10 @@ module wt_cache_subsystem #(
// they have equal prio and are RR arbited
// Port 2 is write only and goes into the merging write buffer
wt_dcache #(
`ifdef PITON_ARIANE
.Axi64BitCompliant ( 1'b0 ),
`else
.Axi64BitCompliant ( 1'b1 ),
`endif
// use ID 1 for dcache reads and amos. note that the writebuffer
// uses all IDs up to DCACHE_MAX_TX-1 for write transactions.
.RdAmoTxId ( 1 ),
.CachedAddrBeg ( CachedAddrBeg ),
.CachedAddrEnd ( CachedAddrEnd )
.ArianeCfg ( ArianeCfg )
) i_wt_dcache (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@ -144,7 +130,7 @@ module wt_cache_subsystem #(
`ifdef PITON_ARIANE
wt_l15_adapter #(
.SwapEndianess ( SwapEndianess )
.SwapEndianess ( ArianeCfg.SwapEndianess )
) i_adapter (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),

View file

@ -16,12 +16,11 @@ import ariane_pkg::*;
import wt_cache_pkg::*;
module wt_dcache #(
parameter bit Axi64BitCompliant = 1'b0, // set this to 1 when using in conjunction with 64bit AXI bus adapter
// ID to be used for read and AMO transactions.
// note that the write buffer uses all IDs up to DCACHE_MAX_TX-1 for write transactions
parameter logic [CACHE_ID_WIDTH-1:0] RdAmoTxId = 1,
parameter logic [63:0] CachedAddrBeg = 64'h00_8000_0000, // begin of cached region
parameter logic [63:0] CachedAddrEnd = 64'h80_0000_0000 // end of cached region
// contains cacheable regions
parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
@ -110,9 +109,9 @@ module wt_dcache #(
///////////////////////////////////////////////////////
wt_dcache_missunit #(
.Axi64BitCompliant ( Axi64BitCompliant ),
.AmoTxId ( RdAmoTxId ),
.NumPorts ( NumPorts )
.Axi64BitCompliant ( ArianeCfg.Axi64BitCompliant ),
.AmoTxId ( RdAmoTxId ),
.NumPorts ( NumPorts )
) i_wt_dcache_missunit (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@ -170,8 +169,7 @@ module wt_dcache #(
wt_dcache_ctrl #(
.RdTxId ( RdAmoTxId ),
.CachedAddrBeg ( CachedAddrBeg ),
.CachedAddrEnd ( CachedAddrEnd )
.ArianeCfg ( ArianeCfg )
) i_wt_dcache_ctrl (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@ -213,8 +211,7 @@ module wt_dcache #(
assign rd_prio[2] = 1'b0;
wt_dcache_wbuffer #(
.CachedAddrBeg ( CachedAddrBeg ),
.CachedAddrEnd ( CachedAddrEnd )
.ArianeCfg ( ArianeCfg )
) i_wt_dcache_wbuffer (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@ -268,8 +265,8 @@ module wt_dcache #(
///////////////////////////////////////////////////////
wt_dcache_mem #(
.Axi64BitCompliant ( Axi64BitCompliant ),
.NumPorts ( NumPorts )
.Axi64BitCompliant ( ArianeCfg.Axi64BitCompliant ),
.NumPorts ( NumPorts )
) i_wt_dcache_mem (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),

View file

@ -16,9 +16,8 @@ import ariane_pkg::*;
import wt_cache_pkg::*;
module wt_dcache_ctrl #(
parameter logic [CACHE_ID_WIDTH-1:0] RdTxId = 1, // ID to use for read transactions
parameter logic [63:0] CachedAddrBeg = 64'h00_8000_0000, // begin of cached region
parameter logic [63:0] CachedAddrEnd = 64'h80_0000_0000 // end of cached region
parameter logic [CACHE_ID_WIDTH-1:0] RdTxId = 1, // ID to use for read transactions
parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig // contains cacheable regions
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
@ -84,9 +83,9 @@ module wt_dcache_ctrl #(
assign miss_paddr_o = {address_tag_q, address_idx_q, address_off_q};
assign miss_size_o = (miss_nc_o) ? data_size_q : 3'b111;
assign miss_nc_o = (address_tag_q < (CachedAddrBeg>>DCACHE_INDEX_WIDTH)) ||
(address_tag_q >= (CachedAddrEnd>>DCACHE_INDEX_WIDTH)) ||
(!cache_en_i);
// noncacheable if request goes to I/O space, or if cache is disabled
assign miss_nc_o = (~cache_en_i) | (~ariane_pkg::is_inside_cacheable_regions(ArianeCfg, {address_tag_q, {DCACHE_INDEX_WIDTH{1'b0}}}));
assign miss_we_o = '0;
assign miss_wdata_o = '0;

View file

@ -52,8 +52,7 @@ import ariane_pkg::*;
import wt_cache_pkg::*;
module wt_dcache_wbuffer #(
parameter logic [63:0] CachedAddrBeg = 64'h00_8000_0000, // begin of cached region
parameter logic [63:0] CachedAddrEnd = 64'h80_0000_0000 // end of cached region
parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig // contains cacheable regions
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
@ -136,9 +135,8 @@ module wt_dcache_wbuffer #(
assign miss_nc_o = nc_pending_q;
assign addr_is_nc = (req_port_i.address_tag < (CachedAddrBeg>>DCACHE_INDEX_WIDTH)) ||
(req_port_i.address_tag >= (CachedAddrEnd>>DCACHE_INDEX_WIDTH)) ||
(!cache_en_i);
// noncacheable if request goes to I/O space, or if cache is disabled
assign addr_is_nc = (~cache_en_i) | (~ariane_pkg::is_inside_cacheable_regions(ArianeCfg, {req_port_i.address_tag, {DCACHE_INDEX_WIDTH{1'b0}}}));
assign miss_we_o = 1'b1;
assign miss_vld_bits_o = '0;

View file

@ -28,10 +28,8 @@ import ariane_pkg::*;
import wt_cache_pkg::*;
module wt_icache #(
parameter logic [CACHE_ID_WIDTH-1:0] RdTxId = 0, // ID to be used for read transactions
parameter bit Axi64BitCompliant = 1'b0, // set this to 1 when using in conjunction with 64bit AXI bus adapter
parameter logic [63:0] CachedAddrBeg = 64'h00_8000_0000, // begin of cached region
parameter logic [63:0] CachedAddrEnd = 64'h80_0000_0000 // end of cached region
parameter logic [CACHE_ID_WIDTH-1:0] RdTxId = 0, // ID to be used for read transactions
parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig // contains cacheable regions
) (
input logic clk_i,
input logic rst_ni,
@ -103,9 +101,7 @@ module wt_icache #(
assign cl_tag_d = (areq_i.fetch_valid) ? areq_i.fetch_paddr[ICACHE_TAG_WIDTH+ICACHE_INDEX_WIDTH-1:ICACHE_INDEX_WIDTH] : cl_tag_q;
// noncacheable if request goes to I/O space, or if cache is disabled
assign paddr_is_nc = (cl_tag_d < (CachedAddrBeg>>ICACHE_INDEX_WIDTH)) ||
(cl_tag_d >= (CachedAddrEnd>>ICACHE_INDEX_WIDTH)) ||
(!cache_en_q);
assign paddr_is_nc = (~cache_en_q) | (~ariane_pkg::is_inside_cacheable_regions(ArianeCfg, {cl_tag_d, {ICACHE_INDEX_WIDTH{1'b0}}}));
// pass exception through
assign dreq_o.ex = areq_i.fetch_exception;
@ -119,7 +115,7 @@ module wt_icache #(
assign cl_index = vaddr_d[ICACHE_INDEX_WIDTH-1:ICACHE_OFFSET_WIDTH];
if (Axi64BitCompliant) begin : gen_axi_offset
if (ArianeCfg.Axi64BitCompliant) begin : gen_axi_offset
// if we generate a noncacheable access, the word will be at offset 0 or 4 in the cl coming from memory
assign cl_offset_d = ( dreq_o.ready & dreq_i.req) ? {dreq_i.vaddr>>2, 2'b0} :
( paddr_is_nc & mem_data_req_o ) ? cl_offset_q[2]<<2 : // needed since we transfer 32bit over a 64bit AXI bus in this case

View file

@ -16,7 +16,7 @@
import ariane_pkg::*;
module ex_stage #(
parameter ariane_pkg::ariane_cfg_t Cfg = ariane_pkg::ArianeDefaultConfig
parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
@ -252,7 +252,7 @@ module ex_stage #(
assign lsu_data = lsu_valid_i ? fu_data_i : '0;
load_store_unit #(
.Cfg ( Cfg )
.ArianeCfg ( ArianeCfg )
) lsu_i (
.clk_i,
.rst_ni,

View file

@ -16,7 +16,7 @@ import ariane_pkg::*;
module load_store_unit #(
parameter int unsigned ASID_WIDTH = 1,
parameter ariane_pkg::ariane_cfg_t Cfg = ariane_pkg::ArianeDefaultConfig
parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig
)(
input logic clk_i,
input logic rst_ni,
@ -121,7 +121,7 @@ module load_store_unit #(
.INSTR_TLB_ENTRIES ( 16 ),
.DATA_TLB_ENTRIES ( 16 ),
.ASID_WIDTH ( ASID_WIDTH ),
.Cfg ( Cfg )
.ArianeCfg ( ArianeCfg )
) i_mmu (
// misaligned bypass
.misaligned_ex_i ( misaligned_exception ),

View file

@ -17,10 +17,10 @@
import ariane_pkg::*;
module mmu #(
parameter int unsigned INSTR_TLB_ENTRIES = 4,
parameter int unsigned DATA_TLB_ENTRIES = 4,
parameter int unsigned ASID_WIDTH = 1,
parameter ariane_pkg::ariane_cfg_t Cfg = ariane_pkg::ArianeDefaultConfig
parameter int unsigned INSTR_TLB_ENTRIES = 4,
parameter int unsigned DATA_TLB_ENTRIES = 4,
parameter int unsigned ASID_WIDTH = 1,
parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig
) (
input logic clk_i,
input logic rst_ni,
@ -243,15 +243,9 @@ module mmu #(
end
end
always_comb begin : execute_addr_check
// if we don't specify any region we assume everything is accessible
match_any_execute_region = (Cfg.NrExecuteRegionRules == 0);
// check for execute flag on memory
for (int i = 0; i < Cfg.NrExecuteRegionRules; i++) begin
match_any_execute_region |= (Cfg.ExecuteRegionAddrBase[i] & ariane_pkg::gen_mask(Cfg.ExecuteRegionLength[i]))
== (icache_areq_o.fetch_paddr & ariane_pkg::gen_mask(Cfg.ExecuteRegionLength[i]));
end
end
// check for execute flag on memory
assign match_any_execute_region = ariane_pkg::is_inside_execute_regions(ArianeCfg, icache_areq_o.fetch_paddr);
//-----------------------
// Data Interface
//-----------------------

View file

@ -1,212 +0,0 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 16.05.2017
// Description: Instruction Tracer Main Class
class instruction_tracer;
// interface to the core
virtual instruction_tracer_if tracer_if;
// keep the decoded instructions in a queue
logic [31:0] decode_queue [$];
// keep the issued instructions in a queue
logic [31:0] issue_queue [$];
// issue scoreboard entries
scoreboard_entry_t issue_sbe_queue [$];
scoreboard_entry_t issue_sbe;
// store resolved branches, get (mis-)predictions
branchpredict_t bp [$];
// shadow copy of the register files
logic [63:0] gp_reg_file [32];
logic [63:0] fp_reg_file [32];
// 64 bit clock tick count
longint unsigned clk_ticks;
int f, commit_log;
// address mapping
// contains mappings of the form vaddr <-> paddr
// should it print the instructions to the console
logic display_instructions;
logic [63:0] store_mapping[$], load_mapping[$], address_mapping;
// static uvm_cmdline_processor uvcl = uvm_cmdline_processor::get_inst();
function new(virtual instruction_tracer_if tracer_if, logic display_instructions);
this.tracer_if = tracer_if;
this.display_instructions = display_instructions;
endfunction : new
function void create_file(logic [63:0] hart_id);
string fn, fn_commit_log;
$sformat(fn, "trace_hart_%04.0f.log", hart_id);
$sformat(fn_commit_log, "trace_hart_%04.0f_commit.log", hart_id);
$display("[TRACER] Output filename is: %s", fn);
this.f = $fopen(fn,"w");
if (ENABLE_SPIKE_COMMIT_LOG) this.commit_log = $fopen(fn_commit_log, "w");
endfunction : create_file
task trace();
logic [31:0] decode_instruction, issue_instruction, issue_commit_instruction;
scoreboard_entry_t commit_instruction;
// initialize register 0
gp_reg_file = '{default:0};
fp_reg_file = '{default:0};
forever begin
automatic branchpredict_t bp_instruction = '0;
// new cycle, we are only interested if reset is de-asserted
@(tracer_if.pck iff tracer_if.pck.rstn);
// increment clock tick
clk_ticks++;
// -------------------
// Instruction Decode
// -------------------
// we are decoding an instruction
if (tracer_if.pck.fetch_valid && tracer_if.pck.fetch_ack) begin
decode_instruction = tracer_if.pck.instruction;
decode_queue.push_back(decode_instruction);
end
// -------------------
// Instruction Issue
// -------------------
// we got a new issue ack, so put the element from the decode queue to
// the issue queue
if (tracer_if.pck.issue_ack && !tracer_if.pck.flush_unissued) begin
issue_instruction = decode_queue.pop_front();
issue_queue.push_back(issue_instruction);
// also save the scoreboard entry to a separate issue queue
issue_sbe_queue.push_back(scoreboard_entry_t'(tracer_if.pck.issue_sbe));
end
// --------------------
// Address Translation
// --------------------
if (tracer_if.pck.st_valid) begin
store_mapping.push_back(tracer_if.pck.st_paddr);
end
if (tracer_if.pck.ld_valid && !tracer_if.pck.ld_kill) begin
load_mapping.push_back(tracer_if.pck.ld_paddr);
end
// ----------------------
// Store predictions
// ----------------------
if (tracer_if.pck.resolve_branch.valid) begin
bp.push_back(tracer_if.pck.resolve_branch);
end
// --------------
// Commit
// --------------
// we are committing an instruction
for (int i = 0; i < 2; i++) begin
if (tracer_if.pck.commit_ack[i]) begin
commit_instruction = scoreboard_entry_t'(tracer_if.pck.commit_instr[i]);
issue_commit_instruction = issue_queue.pop_front();
issue_sbe = issue_sbe_queue.pop_front();
// check if the instruction retiring is a load or store, get the physical address accordingly
if (tracer_if.pck.commit_instr[i].fu == LOAD)
address_mapping = load_mapping.pop_front();
else if (tracer_if.pck.commit_instr[i].fu == STORE)
address_mapping = store_mapping.pop_front();
if (tracer_if.pck.commit_instr[i].fu == CTRL_FLOW)
bp_instruction = bp.pop_front();
// the scoreboards issue entry still contains the immediate value as a result
// check if the write back is valid, if not we need to source the result from the register file
// as the most recent version of this register will be there.
if (tracer_if.pck.we_gpr[i] || tracer_if.pck.we_fpr[i]) begin
printInstr(issue_sbe, issue_commit_instruction, tracer_if.pck.wdata[i], address_mapping, tracer_if.pck.priv_lvl, tracer_if.pck.debug_mode, bp_instruction);
end else if (is_rd_fpr(commit_instruction.op)) begin
printInstr(issue_sbe, issue_commit_instruction, fp_reg_file[commit_instruction.rd], address_mapping, tracer_if.pck.priv_lvl, tracer_if.pck.debug_mode, bp_instruction);
end else begin
printInstr(issue_sbe, issue_commit_instruction, gp_reg_file[commit_instruction.rd], address_mapping, tracer_if.pck.priv_lvl, tracer_if.pck.debug_mode, bp_instruction);
end
end
end
// --------------
// Exceptions
// --------------
if (tracer_if.pck.exception.valid && !(tracer_if.pck.debug_mode && tracer_if.pck.exception.cause == riscv::BREAKPOINT)) begin
// print exception
printException(tracer_if.pck.commit_instr[0].pc, tracer_if.pck.exception.cause, tracer_if.pck.exception.tval);
end
// ----------------------
// Commit Registers
// ----------------------
// update shadow reg files here
for (int i = 0; i < 2; i++) begin
if (tracer_if.pck.we_gpr[i] && tracer_if.pck.waddr[i] != 5'b0) begin
gp_reg_file[tracer_if.pck.waddr[i]] = tracer_if.pck.wdata[i];
end else if (tracer_if.pck.we_fpr[i]) begin
fp_reg_file[tracer_if.pck.waddr[i]] = tracer_if.pck.wdata[i];
end
end
// --------------
// Flush Signals
// --------------
// flush un-issued instructions
if (tracer_if.pck.flush_unissued) begin
this.flushDecode();
end
// flush whole pipeline
if (tracer_if.pck.flush) begin
this.flush();
end
end
endtask
// flush all decoded instructions
function void flushDecode ();
decode_queue = {};
endfunction
// flush everything, we took an exception/interrupt
function void flush ();
this.flushDecode();
// clear all elements in the queue
issue_queue = {};
issue_sbe_queue = {};
// also clear mappings
store_mapping = {};
load_mapping = {};
bp = {};
endfunction
function void printInstr(scoreboard_entry_t sbe, logic [31:0] instr, logic [63:0] result, logic [63:0] paddr, riscv::priv_lvl_t priv_lvl, logic debug_mode, branchpredict_t bp);
instruction_trace_item iti = new ($time, clk_ticks, sbe, instr, this.gp_reg_file, this.fp_reg_file, result, paddr, priv_lvl, debug_mode, bp);
// print instruction to console
string print_instr = iti.printInstr();
if (ENABLE_SPIKE_COMMIT_LOG && !debug_mode) begin
$fwrite(this.commit_log, riscv::spikeCommitLog(sbe.pc, priv_lvl, instr, sbe.rd, result, is_rd_fpr(sbe.op)));
end
uvm_report_info( "Tracer", print_instr, UVM_HIGH);
$fwrite(this.f, {print_instr, "\n"});
endfunction
function void printException(logic [63:0] pc, logic [63:0] cause, logic [63:0] tval);
exception_trace_item eti = new (pc, cause, tval);
string print_ex = eti.printException();
uvm_report_info( "Tracer", print_ex, UVM_HIGH);
$fwrite(this.f, {print_ex, "\n"});
endfunction
function void close();
if (f) $fclose(this.f);
if (ENABLE_SPIKE_COMMIT_LOG && this.commit_log) $fclose(this.commit_log);
endfunction
endclass : instruction_tracer

View file

@ -1,27 +0,0 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 16.05.2017
// Description: Instruction Tracer Package
package instruction_tracer_pkg;
import ariane_pkg::*;
//pragma translate_off
import uvm_pkg::*;
`include "uvm_macros.svh"
`include "instruction_tracer_defines.svh"
`include "instruction_trace_item.svh"
`include "exception_trace_item.svh"
`include "instruction_tracer.svh"
//pragma translate_on
endpackage

View file

@ -11,58 +11,78 @@
// Author: Florian Zaruba, ETH Zurich
// Description: Contains SoC information as constants
package ariane_soc;
// M-Mode Hart, S-Mode Hart
localparam int unsigned NumTargets = 2;
// Uart, SPI, Ethernet, reserved
localparam int unsigned NumSources = 30;
localparam int unsigned MaxPriority = 7;
// M-Mode Hart, S-Mode Hart
localparam int unsigned NumTargets = 2;
// Uart, SPI, Ethernet, reserved
localparam int unsigned NumSources = 30;
localparam int unsigned MaxPriority = 7;
localparam NrSlaves = 2; // actually masters, but slaves on the crossbar
localparam NrSlaves = 2; // actually masters, but slaves on the crossbar
// 4 is recommended by AXI standard, so lets stick to it, do not change
localparam IdWidth = 4;
localparam IdWidthSlave = IdWidth + $clog2(NrSlaves);
// 4 is recommended by AXI standard, so lets stick to it, do not change
localparam IdWidth = 4;
localparam IdWidthSlave = IdWidth + $clog2(NrSlaves);
typedef enum int unsigned {
DRAM = 0,
GPIO = 1,
Ethernet = 2,
SPI = 3,
UART = 4,
PLIC = 5,
CLINT = 6,
ROM = 7,
Debug = 8
} axi_slaves_t;
typedef enum int unsigned {
DRAM = 0,
GPIO = 1,
Ethernet = 2,
SPI = 3,
UART = 4,
PLIC = 5,
CLINT = 6,
ROM = 7,
Debug = 8
} axi_slaves_t;
localparam NB_PERIPHERALS = Debug + 1;
localparam NB_PERIPHERALS = Debug + 1;
localparam logic[63:0] DebugLength = 64'h1000;
localparam logic[63:0] ROMLength = 64'h10000;
localparam logic[63:0] CLINTLength = 64'hC0000;
localparam logic[63:0] PLICLength = 64'h3FF_FFFF;
localparam logic[63:0] UARTLength = 64'h1000;
localparam logic[63:0] SPILength = 64'h800000;
localparam logic[63:0] EthernetLength = 64'h10000;
localparam logic[63:0] GPIOLength = 64'h1000;
localparam logic[63:0] DRAMLength = 64'h40000000; // 1GByte of DDR (split between two chips on Genesys2)
localparam logic[63:0] SRAMLength = 64'h1800000; // 24 MByte of SRAM
// Instantiate AXI protocol checkers
localparam bit GenProtocolChecker = 1'b0;
typedef enum logic [63:0] {
DebugBase = 64'h0000_0000,
ROMBase = 64'h0001_0000,
CLINTBase = 64'h0200_0000,
PLICBase = 64'h0C00_0000,
UARTBase = 64'h1000_0000,
SPIBase = 64'h2000_0000,
EthernetBase = 64'h3000_0000,
GPIOBase = 64'h4000_0000,
DRAMBase = 64'h8000_0000
} soc_bus_start_t;
localparam logic[63:0] DebugLength = 64'h1000;
localparam logic[63:0] ROMLength = 64'h10000;
localparam logic[63:0] CLINTLength = 64'hC0000;
localparam logic[63:0] PLICLength = 64'h3FF_FFFF;
localparam logic[63:0] UARTLength = 64'h1000;
localparam logic[63:0] SPILength = 64'h800000;
localparam logic[63:0] EthernetLength = 64'h10000;
localparam logic[63:0] GPIOLength = 64'h1000;
localparam logic[63:0] DRAMLength = 64'h40000000; // 1GByte of DDR (split between two chips on Genesys2)
localparam logic[63:0] SRAMLength = 64'h1800000; // 24 MByte of SRAM
// Instantiate AXI protocol checkers
localparam bit GenProtocolChecker = 1'b0;
localparam NrRegion = 1;
localparam logic [NrRegion-1:0][NB_PERIPHERALS-1:0] ValidRule = {{NrRegion * NB_PERIPHERALS}{1'b1}};
typedef enum logic [63:0] {
DebugBase = 64'h0000_0000,
ROMBase = 64'h0001_0000,
CLINTBase = 64'h0200_0000,
PLICBase = 64'h0C00_0000,
UARTBase = 64'h1000_0000,
SPIBase = 64'h2000_0000,
EthernetBase = 64'h3000_0000,
GPIOBase = 64'h4000_0000,
DRAMBase = 64'h8000_0000
} soc_bus_start_t;
localparam NrRegion = 1;
localparam logic [NrRegion-1:0][NB_PERIPHERALS-1:0] ValidRule = {{NrRegion * NB_PERIPHERALS}{1'b1}};
localparam ariane_pkg::ariane_cfg_t ArianeSocCfg = '{
// idempotent region
NrNonIdempotentRules: 0,
NonIdempotentAddrBase: {64'b0},
NonIdempotentLength: {64'b0},
NrExecuteRegionRules: 3,
ExecuteRegionAddrBase: {DRAMBase, ROMBase, DebugBase},
ExecuteRegionLength: {DRAMLength, ROMLength, DebugLength},
// cached region
NrCachedRegionRules: 1,
CachedRegionAddrBase: {DRAMBase},
CachedRegionLength: {DRAMLength},
// cache config
Axi64BitCompliant: 1'b1,
SwapEndianess: 1'b0,
// debug
DmBaseAddress: DebugBase
};
endpackage

View file

@ -659,11 +659,8 @@ module ariane_testharness #(
ariane_axi::resp_t axi_ariane_resp;
ariane #(
.AxiIdWidth ( ariane_soc::IdWidth ),
.SwapEndianess ( 0 ),
.CachedAddrBeg ( ariane_soc::DRAMBase ),
.CachedAddrEnd ( (ariane_soc::DRAMBase + ariane_soc::DRAMLength) ),
.DmBaseAddress ( ariane_soc::DebugBase )
.AxiIdWidth ( ariane_soc::IdWidth ),
.ArianeCfg ( ariane_soc::ArianeSocCfg )
) i_ariane (
.clk_i ( clk_i ),
.rst_ni ( ndmreset_n ),

View file

@ -40,6 +40,26 @@ module tb;
parameter logic [63:0] CachedAddrBeg = MemBytes>>3;//1/8th of the memory is NC
parameter logic [63:0] CachedAddrEnd = 64'hFFFF_FFFF_FFFF_FFFF;
localparam ariane_cfg_t ArianeDefaultConfig = '{
// idempotent region
NrNonIdempotentRules: 0,
NonIdempotentAddrBase: {64'b0},
NonIdempotentLength: {64'b0},
// executable region
NrExecuteRegionRules: 0,
ExecuteRegionAddrBase: {64'h0},
ExecuteRegionLength: {64'h0},
// cached region
NrCachedRegionRules: 1,
CachedRegionAddrBase: {CachedAddrBeg},//1/8th of the memory is NC
CachedRegionLength: {CachedAddrEnd-CachedAddrBeg+64'b1},
// cache config
Axi64BitCompliant: 1'b1,
SwapEndianess: 1'b0,
// debug
DmBaseAddress: 64'h0
};
// contention and invalidation rates (in %)
parameter MemRandHitRate = 75;
parameter MemRandInvRate = 10;
@ -204,9 +224,7 @@ module tb;
///////////////////////////////////////////////////////////////////////////////
wt_dcache #(
.CachedAddrBeg ( CachedAddrBeg ),
.CachedAddrEnd ( CachedAddrEnd ),
.Axi64BitCompliant ( 1'b1 )
.ArianeCfg ( ArianeDefaultConfig )
) i_dut (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),

View file

@ -39,6 +39,26 @@ module tb;
parameter logic [63:0] CachedAddrBeg = MemBytes/4;
parameter logic [63:0] CachedAddrEnd = 64'hFFFF_FFFF_FFFF_FFFF;
localparam ariane_cfg_t Cfg = '{
// idempotent region
NrNonIdempotentRules: 0,
NonIdempotentAddrBase: {64'b0},
NonIdempotentLength: {64'b0},
// executable region
NrExecuteRegionRules: 0,
ExecuteRegionAddrBase: {64'h0},
ExecuteRegionLength: {64'h0},
// cached region
NrCachedRegionRules: 1,
CachedRegionAddrBase: {CachedAddrBeg},
CachedRegionLength: {CachedAddrEnd-CachedAddrBeg+64'b1},
// cache config
Axi64BitCompliant: 1'b0,
SwapEndianess: 1'b0,
// debug
DmBaseAddress: 64'h0
};
// rates are in percent
parameter TlbRandHitRate = 50;
parameter MemRandHitRate = 50;
@ -240,8 +260,7 @@ module tb;
///////////////////////////////////////////////////////////////////////////////
wt_icache #(
.CachedAddrBeg(CachedAddrBeg),
.CachedAddrEnd(CachedAddrEnd)
.ArianeCfg(Cfg)
) dut (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),