Skip to content

Commit

Permalink
Merge pull request chipsalliance#479 from udinator/pmp
Browse files Browse the repository at this point in the history
Improve pmp config object - enable cmdline args
  • Loading branch information
udinator authored Feb 18, 2020
2 parents 4682ff2 + f80dce7 commit a216407
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 32 deletions.
43 changes: 23 additions & 20 deletions src/riscv_instr_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,6 @@ package riscv_instr_pkg;
bit [2:0] xwr; // Excutable,Writable,Readale
} mem_region_t;

// PMP address matching mode
typedef enum bit [1:0] {
OFF = 2'b00,
TOR = 2'b01,
NA4 = 2'b10,
NAPOT = 2'b11
} pmp_addr_mode_t;

// PMP configuration register layout
// This configuration struct includes the pmp address for simplicity
typedef struct{
rand bit l;
bit [1:0] zero;
rand pmp_addr_mode_t a;
rand bit x;
rand bit w;
rand bit r;
rand bit [33:0] addr;
} pmp_cfg_reg_t;

typedef enum bit [3:0] {
BARE = 4'b0000,
SV32 = 4'b0001,
Expand Down Expand Up @@ -951,6 +931,29 @@ package riscv_instr_pkg;

`include "riscv_core_setting.sv"

// PMP address matching mode
typedef enum bit [1:0] {
OFF = 2'b00,
TOR = 2'b01,
NA4 = 2'b10,
NAPOT = 2'b11
} pmp_addr_mode_t;

// PMP configuration register layout
// This configuration struct includes the pmp address for simplicity
// TODO (udinator) allow a full 34 bit address for rv32?
typedef struct{
rand bit l;
bit [1:0] zero;
rand pmp_addr_mode_t a;
rand bit x;
rand bit w;
rand bit r;
// RV32: addr is the top 32 bits of a 34 bit PMP address
// RV64: addr is the top 54 bits of a 56 bit PMP address
rand bit [XLEN - 1 : 0] addr;
} pmp_cfg_reg_t;

typedef struct packed {
bit ill;
bit [XLEN-2:7] reserved;
Expand Down
109 changes: 98 additions & 11 deletions src/riscv_pmp_cfg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@ class riscv_pmp_cfg extends uvm_object;
// default to a single PMP region
rand int pmp_num_regions = 1;
// default to granularity of 0 (4 bytes grain)
rand int pmp_granularity = 0;
int pmp_granularity = 0;
// enable bit for pmp randomization
bit pmp_randomize = 0;
// pmp CSR configurations
rand pmp_cfg_reg_t pmp_cfg[];
// PMP maximum address - used to set defaults
// TODO(udinator) - make this address configurable?
bit [XLEN - 1 : 0] pmp_max_address = {XLEN{1'b1}};

// used to parse addr_mode configuration from cmdline
typedef uvm_enum_wrapper#(pmp_addr_mode_t) addr_mode_wrapper;
Expand All @@ -40,7 +43,8 @@ class riscv_pmp_cfg extends uvm_object;
pmp_granularity inside {[0 : XLEN + 3]};
}

// TODO(udinator) move these constraints to post_randomize() to save performance
// TODO(udinator) more address constraints?
// TODO(udinator) move to posts_randomize() if lower performance
constraint xwr_c {
foreach (pmp_cfg[i]) {
!(pmp_cfg[i].w && !pmp_cfg[i].r);
Expand All @@ -56,31 +60,114 @@ class riscv_pmp_cfg extends uvm_object;
function new(string name = "");
string s;
super.new(name);
inst = uvm_cmdline_processor::get_inst();
get_bool_arg_value("+pmp_randomize=", pmp_randomize);
get_int_arg_value("+pmp_granularity=", pmp_granularity);
get_int_arg_value("+pmp_num_regions=", pmp_num_regions);
pmp_cfg = new[pmp_num_regions];
// As per privileged spec, the top 10 bits of a rv64 PMP address are all 0.
if (XLEN == 64) begin
pmp_max_address[XLEN - 1 : XLEN - 11] = 10'b0;
end
if (!pmp_randomize) begin
set_defaults();
setup_pmp();
end
endfunction

// TODO(udinator) partition address space to map to all active pmp_addr CSRs
// TODO(udinator) set pmp address defaults
// This will only get called if pmp_randomize is set, in which case we apply command line
// arguments after randomization
function void post_randomize();
setup_pmp();
endfunction

function void set_defaults();
foreach(pmp_cfg[i]) begin
pmp_cfg[i].l = 1'b0;
pmp_cfg[i].a = TOR;
pmp_cfg[i].x = 1'b1;
pmp_cfg[i].w = 1'b1;
pmp_cfg[i].r = 1'b1;
pmp_cfg[i].addr = 34'h3FFFFFFFF;
pmp_cfg[i].addr = assign_default_addr(pmp_num_regions, i + 1);
end
endfunction

// Helper function to break down
function bit [XLEN - 1 : 0] assign_default_addr(int num_regions, int index);
return pmp_max_address / num_regions * index;
endfunction

function void setup_pmp();
string arg_name;
string pmp_region;
get_int_arg_value("+pmp_num_regions=", pmp_num_regions);
get_int_arg_value("+pmp_granularity=", pmp_granularity);
// TODO(udinator) - parse the pmp configuration values
foreach (pmp_cfg[i]) begin
arg_name = $sformatf("+pmp_region_%0d=", i);
if (inst.get_arg_value(arg_name, pmp_region)) begin
parse_pmp_config(pmp_region, pmp_cfg[i]);
`uvm_info(`gfn, $sformatf("Configured pmp_cfg[%0d] from command line: %p", i, pmp_cfg[i]), UVM_LOW)
end
end
endfunction

function void parse_pmp_config(string pmp_region, ref pmp_cfg_reg_t pmp_cfg_reg);
string fields[$];
string field_vals[$];
string field_type;
string field_val;
uvm_split_string(pmp_region, ",", fields);
foreach (fields[i]) begin
uvm_split_string(fields[i], ":", field_vals);
field_type = field_vals.pop_front();
field_val = field_vals.pop_front();
case (field_type)
"L": begin
pmp_cfg_reg.l = field_val.atobin();
end
"A": begin
`DV_CHECK(addr_mode_wrapper::from_name(field_val, addr_mode))
pmp_cfg_reg.a = addr_mode;
end
"X": begin
pmp_cfg_reg.x = field_val.atobin();
end
"W": begin
pmp_cfg_reg.w = field_val.atobin();
end
"R": begin
pmp_cfg_reg.r = field_val.atobin();
end
"ADDR": begin
// Don't have to convert address to "PMP format" here,
// since it must be masked off in hardware
pmp_cfg_reg.addr = format_addr(field_val.atohex());
end
default: begin
`uvm_fatal(`gfn, $sformatf("%s, Invalid PMP configuration field name!", field_val))
end
endcase
end
endfunction

function bit [XLEN - 1 : 0] format_addr(bit [XLEN - 1 : 0] addr);
// For all ISAs, pmpaddr CSRs do not include the bottom two bits of the input address
bit [XLEN - 1 : 0] shifted_addr;
shifted_addr = addr >> 2; case (XLEN)
// RV32 - pmpaddr is bits [33:2] of the whole 34 bit address
// Return the input address right-shifted by 2 bits
32: begin
return shifted_addr;
end
// RV64 - pmpaddr is bits [55:2] of the whole 56 bit address, prepended by 10'b0
// Return {10'b0, shifted_addr[53:0]}
64: begin
return {10'b0, shifted_addr[53:0]};
end
endcase
endfunction

// TODO(udinator) - implement function to return hardware masked pmpaddr "representation"
function bit [XLEN - 1 : 0] convert_addr2pmp(bit [XLEN - 1 : 0] addr);
`uvm_info(`gfn, "Placeholder function, need to implement", UVM_LOW)
endfunction

// This function parses the pmp_cfg[] array to generate the actual instructions to set up
Expand All @@ -97,7 +184,7 @@ class riscv_pmp_cfg extends uvm_object;
riscv_instr_pkg::privileged_reg_t base_pmpcfg_addr = PMPCFG0;
int pmp_id;
foreach (pmp_cfg[i]) begin
// TODO(udijnator) condense this calculations if possible
// TODO(udinator) condense this calculations if possible
pmp_id = i / cfg_per_csr;
cfg_byte = {pmp_cfg[i].l, pmp_cfg[i].zero, pmp_cfg[i].a,
pmp_cfg[i].x, pmp_cfg[i].w, pmp_cfg[i].r};
Expand All @@ -107,8 +194,8 @@ class riscv_pmp_cfg extends uvm_object;
pmp_word = pmp_word | cfg_bitmask;
`uvm_info(`gfn, $sformatf("pmp_word: 0x%0x", pmp_word), UVM_DEBUG)
cfg_bitmask = 0;
//TODO (udinator) - add rv64 support for pmpaddr writes
instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg, pmp_cfg[i].addr[XLEN + 1 : 2]));
`uvm_info(`gfn, $sformatf("pmp_addr: 0x%0x", pmp_cfg[i].addr), UVM_DEBUG)
instr.push_back($sformatf("li x%0d, 0x%0x", scratch_reg, pmp_cfg[i].addr));
instr.push_back($sformatf("csrw 0x%0x, x%0d", base_pmp_addr + i, scratch_reg));
// short circuit if end of list
if (i == pmp_cfg.size() - 1) begin
Expand Down
11 changes: 11 additions & 0 deletions target/rv32imc/testlist.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,14 @@
+hint_instr_ratio=5
rtl_test: core_base_test

- test: riscv_pmp_test
description: >
Provide some PMP configuration parameters, and setup PMP CSRs appropriately
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+pmp_randomize=0
+pmp_num_regions=1
+pmp_granularity=1
+pmp_region_0=L:0,A:NAPOT,X=1,W=1,R=1,ADDR=0x090000000
rtl_test: core_base_test
1 change: 0 additions & 1 deletion yaml/iss.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
<path_var>/riscvOVPsim.exe
--controlfile <cfg_path>/riscvOVPsim.ic
--objfilenoentry <elf>
--override riscvOVPsim/cpu/PMP_registers=0
--override riscvOVPsim/cpu/simulateexceptions=T
--trace --tracechange --traceshowicount --tracemode --traceregs
--finishafter 1000000
Expand Down

0 comments on commit a216407

Please sign in to comment.