mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
Update google_riscv-dv to google/riscv-dv@c98d89c (#312)
Update code from upstream repository https://github.com/google/riscv- dv to revision c98d89cdff7b56d9911904e05e6b46e005233280 * Interrupt test integration (Udi) * Update README for illegal/hint instruction (google/riscv-dv#155) (taoliug) * Refactor illegal/hint instruction generation (google/riscv-dv#154) (taoliug) * Skip x0 in GPR save/restore (google/riscv-dv#153) (taoliug) * Move user_define.h to the beginning of the program (google/riscv- dv#151) (taoliug) * Add user_define.h (google/riscv-dv#149) (taoliug) * Move instr_bin to a separate section (google/riscv-dv#148) (taoliug) * Remove temp files (google/riscv-dv#145) (taoliug) * Move dv_defines.svh outside the package (google/riscv-dv#144) (taoliug) * Fix typo (google/riscv-dv#141) (taoliug) * Refactored loop instruction stream, reduce global reserved registers (google/riscv-dv#139) (taoliug) * Remove obsolete sample program (google/riscv-dv#138) (taoliug) * Update readme (google/riscv-dv#137) (taoliug) * Skip kernel instruction/data pages when not needed (google/riscv- dv#136) (taoliug) * Re-organize data page generation (google/riscv-dv#135) (taoliug) * Re-organize text and data section (google/riscv-dv#134) (taoliug) * Refine the bare program mode (google/riscv-dv#133) (taoliug) * Add a bare program mode (google/riscv-dv#130) (taoliug) * Allow running riscv-dv from other directories (google/riscv-dv#128) (taoliug) * Fix trace compare issue (google/riscv-dv#123) (taoliug) * Optimize for constraint solving performance (google/riscv-dv#122) (taoliug) * Avoid ISS simulation timeout (google/riscv-dv#121) (taoliug) * Optimize irun randomization performance (google/riscv-dv#120) (taoliug) * fix ius compile/simulation warnings (Tao Liu) * Fix ius compilation failure (Tao Liu) * Fix google/riscv-dv#109 ius constraint solver failure (Tao Liu) * Add ebreak sequence generation and cmdline options (Udi) * Added dret instruction to random generation (Udi) * Tighten up regex in spike log tracer. (Dave Estes) * Fix generation of debug handshake (Udi) * Fix wfi generation, add indent to core_initialization handshake (Udi)
This commit is contained in:
parent
f025236a22
commit
3fcf5a634d
35 changed files with 861 additions and 19694 deletions
2
vendor/google_riscv-dv.lock.hjson
vendored
2
vendor/google_riscv-dv.lock.hjson
vendored
|
@ -9,6 +9,6 @@
|
|||
upstream:
|
||||
{
|
||||
url: https://github.com/google/riscv-dv
|
||||
rev: 102791dbb7eb992d3bc22336d2e4e5f0d688e761
|
||||
rev: c98d89cdff7b56d9911904e05e6b46e005233280
|
||||
}
|
||||
}
|
||||
|
|
55
vendor/google_riscv-dv/README.md
vendored
55
vendor/google_riscv-dv/README.md
vendored
|
@ -184,6 +184,37 @@ riscv_instr_group_t supported_isa[] = {RV32I, RV32M, RV64I, RV64M};
|
|||
...
|
||||
```
|
||||
|
||||
### Setup the memory map
|
||||
|
||||
Here's a few cases that you might want to allocate the instruction and data
|
||||
sections to match the actual memory map
|
||||
- The processor has internal memories, and you want to test load/store from
|
||||
various internal/externel memory regions
|
||||
- The processor implments the PMP feature, and you want to configure the memory
|
||||
map to match PMP setting.
|
||||
- Virtual address translation is implmented and you want to test load/store from
|
||||
sparse memory locations to verify data TLB replacement logic.
|
||||
|
||||
You can configure the memory map in [riscv_instr_gen_config.sv](https://github.com/google/riscv-dv/blob/master/src/riscv_instr_gen_config.sv)
|
||||
|
||||
```
|
||||
mem_region_t mem_region[$] = '{
|
||||
'{name:"region_0", size_in_bytes: 4096, xwr: 3'b111},
|
||||
'{name:"region_1", size_in_bytes: 4096 * 4, xwr: 3'b111},
|
||||
'{name:"region_2", size_in_bytes: 4096 * 2, xwr: 3'b111},
|
||||
'{name:"region_3", size_in_bytes: 512, xwr: 3'b111},
|
||||
'{name:"region_4", size_in_bytes: 4096, xwr: 3'b111}
|
||||
};
|
||||
```
|
||||
|
||||
Each memory region belongs to a separate section in the generated assembly
|
||||
program. You can modify the link script to link each section to the target
|
||||
memory location. Please avoid setting a large memory range as it could takes a
|
||||
long time to randomly initializing the memory. You can break down a large memory
|
||||
region to a few representative small regions which covers all the boundary
|
||||
conditions for the load/store testing.
|
||||
|
||||
|
||||
### Runtime options of the generator
|
||||
|
||||
| Option | Description | Default |
|
||||
|
@ -198,8 +229,8 @@ riscv_instr_group_t supported_isa[] = {RV32I, RV32M, RV64I, RV64M};
|
|||
| no_load_store | Disable load/store instruction | 0 |
|
||||
| no_csr_instr | Disable CSR instruction | 0 |
|
||||
| no_fence | Disable fence instruction | 0 |
|
||||
| enable_illegal_instruction | Enable illegal instructions | 0 |
|
||||
| enable_hint_instruction | Enable HINT instruction | 0 |
|
||||
| illegal_instr_ratio | Number of illegal instructions every 1000 instr | 0 |
|
||||
| hint_instr_ratio | Number of HINT instructions every 1000 instr | 0 |
|
||||
| boot_mode | m:Machine mode, s:Supervisor mode, u:User mode | m |
|
||||
| no_directed_instr | Disable directed instruction stream | 0 |
|
||||
| require_signature_addr | Set to 1 if test needs to talk to testbench | 0 |
|
||||
|
@ -343,9 +374,23 @@ python3 run.py --test riscv_page_table_exception_test --iss new_iss_name
|
|||
|
||||
We have collaborated with LowRISC to apply this flow for [IBEX RISC-V core
|
||||
verification](https://github.com/lowRISC/ibex/blob/master/doc/verification.rst). You can use
|
||||
it as a reference to setup end-to-end co-simulation flow. It's also a good
|
||||
reference for [customizing the generator](https://github.com/lowRISC/ibex/tree/master/dv/uvm/riscv_dv_extension) without getting impacted by upstream
|
||||
changes.
|
||||
it as a reference to setup end-to-end co-simulation flow.
|
||||
This repo is still under active development, here's recommended approach to
|
||||
customize the instruction generator while keeping the minimum effort of merging
|
||||
upstream changes.
|
||||
- Do not modify the upstream classes directly. When possible, extending from
|
||||
the upstream classses and implment your own functionalities.
|
||||
- Use command line type override to use your extended classes.
|
||||
--sim_opts="+uvm_set_type_override=<upstream_class>,<extended_class>"
|
||||
- Create a new file list for your local modifications. Pass to the instruction
|
||||
generator like below:
|
||||
--cmp_opts "+define+RISCV_DV_EXT_FILE_LIST=<local_file_list>"
|
||||
- Create a new file for the core settings, and pass to the instruction generator:
|
||||
--cmp_opts "+define+RISCV_CORE_SETTING=<your_core_setting.sv>"
|
||||
|
||||
You can refer to [riscv-dv extension for ibex](https://github.com/lowRISC/ibex/blob/master/dv/uvm/Makefile#L68) for a working example.
|
||||
|
||||
|
||||
We have plan to open-source the end-to-end environment of other advanced RISC-V
|
||||
processors. Stay tuned!
|
||||
|
||||
|
|
12
vendor/google_riscv-dv/files.f
vendored
12
vendor/google_riscv-dv/files.f
vendored
|
@ -13,11 +13,11 @@
|
|||
// limitations under the License.
|
||||
|
||||
// HEADERS
|
||||
+incdir+./src
|
||||
+incdir+./test
|
||||
+incdir+${RISCV_DV_ROOT}/src
|
||||
+incdir+${RISCV_DV_ROOT}/test
|
||||
|
||||
// SOURCES
|
||||
./src/riscv_signature_pkg.sv
|
||||
./src/riscv_instr_pkg.sv
|
||||
./test/riscv_instr_test_pkg.sv
|
||||
./test/riscv_instr_gen_tb_top.sv
|
||||
${RISCV_DV_ROOT}/src/riscv_signature_pkg.sv
|
||||
${RISCV_DV_ROOT}/src/riscv_instr_pkg.sv
|
||||
${RISCV_DV_ROOT}/test/riscv_instr_test_pkg.sv
|
||||
${RISCV_DV_ROOT}/test/riscv_instr_gen_tb_top.sv
|
||||
|
|
17
vendor/google_riscv-dv/run.py
vendored
17
vendor/google_riscv-dv/run.py
vendored
|
@ -193,7 +193,7 @@ def gcc_compile(test_list, output_dir, isa, mabi, opts):
|
|||
"""
|
||||
for test in test_list:
|
||||
for i in range(0, test['iterations']):
|
||||
prefix = ("%s/asm_tests/%s.%d" % (output_dir, test['test'], i))
|
||||
prefix = ("%s/asm_tests/%s_%d" % (output_dir, test['test'], i))
|
||||
asm = prefix + ".S"
|
||||
elf = prefix + ".o"
|
||||
binary = prefix + ".bin"
|
||||
|
@ -201,8 +201,10 @@ def gcc_compile(test_list, output_dir, isa, mabi, opts):
|
|||
cmd = ("%s -static -mcmodel=medany \
|
||||
-fvisibility=hidden -nostdlib \
|
||||
-nostartfiles %s \
|
||||
-Tscripts/link.ld %s -o %s " % \
|
||||
(get_env_var("RISCV_GCC"), asm, opts, elf))
|
||||
-I%s/user_extension \
|
||||
-T%s/scripts/link.ld %s -o %s " % \
|
||||
(get_env_var("RISCV_GCC"), asm, get_env_var("RISCV_DV_ROOT"),
|
||||
get_env_var("RISCV_DV_ROOT"), opts, elf))
|
||||
if 'gcc_opts' in test:
|
||||
cmd += test['gcc_opts']
|
||||
# If march/mabi is not defined in the test gcc_opts, use the default
|
||||
|
@ -243,7 +245,7 @@ def iss_sim(test_list, output_dir, iss_list, iss_yaml, isa, timeout_s):
|
|||
continue
|
||||
else:
|
||||
for i in range(0, test['iterations']):
|
||||
prefix = ("%s/asm_tests/%s.%d" % (output_dir, test['test'], i))
|
||||
prefix = ("%s/asm_tests/%s_%d" % (output_dir, test['test'], i))
|
||||
elf = prefix + ".o"
|
||||
log = ("%s/%s.%d.log" % (log_dir, test['test'], i))
|
||||
cmd = get_iss_cmd(base_cmd, elf, log)
|
||||
|
@ -268,7 +270,7 @@ def iss_cmp(test_list, iss, output_dir, isa):
|
|||
run_cmd("rm -rf %s" % report)
|
||||
for test in test_list:
|
||||
for i in range(0, test['iterations']):
|
||||
elf = ("%s/asm_tests/%s.%d.o" % (output_dir, test['test'], i))
|
||||
elf = ("%s/asm_tests/%s_%d.o" % (output_dir, test['test'], i))
|
||||
logging.info("Comparing ISS sim result %s/%s : %s" %
|
||||
(iss_list[0], iss_list[1], elf))
|
||||
csv_list = []
|
||||
|
@ -342,7 +344,7 @@ def setup_parser():
|
|||
help="Generator timeout limit in seconds")
|
||||
parser.add_argument("--end_signature_addr", type=str, default="0",
|
||||
help="Address that privileged CSR test writes to at EOT")
|
||||
parser.add_argument("--iss_timeout", type=int, default=50,
|
||||
parser.add_argument("--iss_timeout", type=int, default=25,
|
||||
help="ISS sim timeout limit in seconds")
|
||||
parser.add_argument("--iss_yaml", type=str, default="",
|
||||
help="ISS setting YAML")
|
||||
|
@ -376,7 +378,7 @@ def setup_logging(verbose):
|
|||
|
||||
def main():
|
||||
"""This is the main entry point."""
|
||||
|
||||
check_riscv_dv_setting()
|
||||
parser = setup_parser()
|
||||
args = parser.parse_args()
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
|
@ -399,6 +401,7 @@ def main():
|
|||
output_dir = "out_" + str(date.today())
|
||||
else:
|
||||
output_dir = args.o
|
||||
|
||||
subprocess.run(["mkdir", "-p", output_dir])
|
||||
subprocess.run(["mkdir", "-p", ("%s/asm_tests" % output_dir)])
|
||||
|
||||
|
|
19195
vendor/google_riscv-dv/sample/sample.S
vendored
19195
vendor/google_riscv-dv/sample/sample.S
vendored
File diff suppressed because it is too large
Load diff
|
@ -279,7 +279,7 @@ def gen_csr_instr(original_csr_map, csr_instructions, xlen,
|
|||
csr_map = copy.deepcopy(original_csr_map)
|
||||
source_reg, dest_reg = [f"x{i}" for i in random.sample(range(1, 16), 2)]
|
||||
csr_list = list(csr_map.keys())
|
||||
with open(f"{out}/riscv_csr_test.{i}.S", "w") as csr_test_file:
|
||||
with open(f"{out}/riscv_csr_test_{i}.S", "w") as csr_test_file:
|
||||
gen_setup(csr_test_file)
|
||||
for csr in csr_list:
|
||||
csr_address, csr_val, csr_write_mask, csr_read_mask = csr_map.get(csr)
|
||||
|
|
|
@ -201,6 +201,8 @@ def parse_gpr_update_from_trace(trace_csv, gpr_trace):
|
|||
|
||||
def check_update_gpr(rd, rd_val, gpr):
|
||||
gpr_state_change = 0
|
||||
if rd == '':
|
||||
return gpr_state_change
|
||||
if rd in gpr:
|
||||
if rd_val != gpr[rd]:
|
||||
gpr_state_change = 1
|
||||
|
|
9
vendor/google_riscv-dv/scripts/lib.py
vendored
9
vendor/google_riscv-dv/scripts/lib.py
vendored
|
@ -59,6 +59,15 @@ def get_env_var(var):
|
|||
return val
|
||||
|
||||
|
||||
def check_riscv_dv_setting():
|
||||
"""Check the RISCV-DV directory setting, default "."
|
||||
"""
|
||||
try:
|
||||
val = os.environ["RISCV_DV_ROOT"]
|
||||
except KeyError:
|
||||
os.environ["RISCV_DV_ROOT"] = "."
|
||||
|
||||
|
||||
def get_seed(seed):
|
||||
"""Get the seed to run the generator
|
||||
|
||||
|
|
8
vendor/google_riscv-dv/scripts/link.ld
vendored
8
vendor/google_riscv-dv/scripts/link.ld
vendored
|
@ -19,13 +19,15 @@ ENTRY(_start)
|
|||
SECTIONS
|
||||
{
|
||||
. = 0x80000000;
|
||||
.text.init : { *(.text.init) }
|
||||
.text : { *(.text) }
|
||||
. = ALIGN(0x1000);
|
||||
.tohost : { *(.tohost) }
|
||||
. = ALIGN(0x1000);
|
||||
.text : { *(.text) }
|
||||
. = ALIGN(0x1000);
|
||||
.page_table : { *(.page_table) }
|
||||
.data : { *(.data) }
|
||||
.user_stack : { *(.user_stack) }
|
||||
.kernel_data : { *(.kernel_data) }
|
||||
.kernel_stack : { *(.kernel_stack) }
|
||||
.bss : { *(.bss) }
|
||||
_end = .;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ def process_spike_sim_log(spike_log, csv):
|
|||
spike_instr = ""
|
||||
|
||||
RD_RE = re.compile(r"(?P<pri>\d) 0x(?P<addr>[a-f0-9]+?) " \
|
||||
"\((?P<bin>.*?)\) x\s*(?P<reg>\d*?) 0x(?P<val>.*)")
|
||||
"\((?P<bin>.*?)\) x\s*(?P<reg>\d*?) 0x(?P<val>[a-f0-9]+)")
|
||||
CORE_RE = re.compile(r"core.*0x(?P<addr>[a-f0-9]+?) \(0x(?P<bin>.*?)\) (?P<instr>.*?)$")
|
||||
INSTR_RE = re.compile(r"(?P<instr>[a-z\.]+?)(\s+?)(?P<operand>.*)")
|
||||
GPR_RE = re.compile(r"^[a-z][0-9a-z]$")
|
||||
|
|
|
@ -35,6 +35,10 @@ riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV64I, RV64M, RV32C, RV64C
|
|||
// Interrupt mode support
|
||||
mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED};
|
||||
|
||||
// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is
|
||||
// supported
|
||||
int max_interrupt_vector_num = 16;
|
||||
|
||||
// Debug mode support
|
||||
bit support_debug_mode = 0;
|
||||
|
||||
|
@ -44,48 +48,6 @@ bit support_umode_trap = 0;
|
|||
// Support sfence.vma instruction
|
||||
bit support_sfence = 1;
|
||||
|
||||
// Cache line size (in bytes)
|
||||
// If processor does not support caches, set to XLEN/8
|
||||
int dcache_line_size_in_bytes = 128;
|
||||
|
||||
// Number of data section
|
||||
// For processor that doesn't have data TLB, this can be set to 1
|
||||
// For processor that supports data TLB, this should be set to be larger than the number
|
||||
// of entries of dTLB to cover dTLB hit/miss scenario
|
||||
int num_of_data_pages = 40;
|
||||
|
||||
// Data section byte size
|
||||
// For processor with no dTLB and data cache, keep the value below 10K
|
||||
// For processor with dTLB support, set it to the physical memory size that covers one entry
|
||||
// of the dTLB
|
||||
int data_page_size = 4096;
|
||||
int data_page_alignment = $clog2(data_page_size);
|
||||
|
||||
// The maximum data section byte size actually used by load/store instruction
|
||||
// Set to this value to be smaller than data_page_size. If there's data cache in the system,
|
||||
// this value should be set large enough to be able to hit cache hit/miss scenario within a data
|
||||
// section. Don't set this to too big as it will introduce a very large binary.
|
||||
int max_used_data_page_size = 512;
|
||||
|
||||
// Stack section word length
|
||||
int stack_len = 5000;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Kernel section setting, used by supervisor mode programs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Number of kernel data pages
|
||||
int num_of_kernel_data_pages = 5;
|
||||
|
||||
// Byte size of kernel data pages
|
||||
int kernel_data_page_size = 4096;
|
||||
|
||||
// Kernel Stack section word length
|
||||
int kernel_stack_len = 5000;
|
||||
|
||||
// Number of instructions for each kernel program
|
||||
int kernel_program_instr_cnt = 400;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
// Base class for AMO instruction stream
|
||||
class riscv_amo_base_instr_stream extends riscv_directed_instr_stream;
|
||||
class riscv_amo_base_instr_stream extends riscv_mem_access_stream;
|
||||
|
||||
rand int unsigned num_amo;
|
||||
rand int unsigned num_mixed_instr;
|
||||
|
@ -23,6 +23,7 @@ class riscv_amo_base_instr_stream extends riscv_directed_instr_stream;
|
|||
rand riscv_reg_t rs1_reg;
|
||||
riscv_reg_t reserved_rd[$];
|
||||
rand int unsigned data_page_id;
|
||||
rand int max_load_store_offset;
|
||||
|
||||
// User can specify a small group of available registers to generate various hazard condition
|
||||
rand riscv_reg_t avail_regs[];
|
||||
|
@ -70,10 +71,10 @@ class riscv_amo_base_instr_stream extends riscv_directed_instr_stream;
|
|||
pseudo_instr_name == LA;
|
||||
rd == rs1_reg;,
|
||||
"Cannot randomize la_instr")
|
||||
if(access_u_mode_mem) begin
|
||||
la_instr.imm_str = $sformatf("data_page_%0d+%0d", data_page_id, base);
|
||||
if(kernel_mode) begin
|
||||
la_instr.imm_str = cfg.s_mem_region[data_page_id].name;
|
||||
end else begin
|
||||
la_instr.imm_str = $sformatf("kernel_data_page_%0d+%0d", data_page_id, base);
|
||||
la_instr.imm_str = cfg.mem_region[data_page_id].name;
|
||||
end
|
||||
instr_list.push_front(la_instr);
|
||||
endfunction
|
||||
|
|
450
vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
vendored
450
vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
vendored
|
@ -29,8 +29,6 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// User mode programs
|
||||
riscv_instr_sequence main_program;
|
||||
riscv_instr_sequence sub_program[];
|
||||
// Program in binary format, stored in the data section, used to inject illegal/HINT instruction
|
||||
riscv_instr_sequence bin_program;
|
||||
riscv_instr_sequence debug_program;
|
||||
riscv_instr_sequence debug_sub_program[];
|
||||
string instr_binary[$];
|
||||
|
@ -70,30 +68,12 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
gen_program_header();
|
||||
// Initialize general purpose registers
|
||||
init_gpr();
|
||||
setup_misa();
|
||||
// Create all page tables
|
||||
create_page_table();
|
||||
// Setup privileged mode registers and enter target privileged mode
|
||||
pre_enter_privileged_mode();
|
||||
// Generate sub program in binary format
|
||||
// Illegal instruction and hint instruction cannot pass compilation, need to directly generate
|
||||
// the instruction in binary format and store in data section to skip compilation.
|
||||
if(cfg.enable_illegal_instruction || cfg.enable_hint_instruction) begin
|
||||
bin_program = riscv_instr_sequence::type_id::create("bin_program");
|
||||
bin_program.instr_cnt = cfg.bin_program_instr_cnt;
|
||||
bin_program.is_debug_program = 0;
|
||||
bin_program.label_name = bin_program.get_name();
|
||||
bin_program.cfg = cfg;
|
||||
if (cfg.enable_illegal_instruction) begin
|
||||
bin_program.illegal_instr_pct = $urandom_range(5, 20);
|
||||
end
|
||||
if (cfg.enable_hint_instruction) begin
|
||||
bin_program.hint_instr_pct = $urandom_range(5, 20);
|
||||
end
|
||||
`DV_CHECK_RANDOMIZE_FATAL(bin_program)
|
||||
bin_program.gen_instr(.is_main_program(0));
|
||||
bin_program.post_process_instr();
|
||||
bin_program.generate_binary_stream(instr_binary);
|
||||
if (!cfg.bare_program_mode) begin
|
||||
setup_misa();
|
||||
// Create all page tables
|
||||
create_page_table();
|
||||
// Setup privileged mode registers and enter target privileged mode
|
||||
pre_enter_privileged_mode();
|
||||
end
|
||||
// Init section
|
||||
gen_init_section();
|
||||
|
@ -113,16 +93,17 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
main_program.gen_instr(1);
|
||||
// Setup jump instruction among main program and sub programs
|
||||
gen_callstack(main_program, sub_program, sub_program_name, cfg.num_of_sub_program);
|
||||
if (bin_program != null) begin
|
||||
main_program.insert_jump_instr("sub_bin", 0);
|
||||
end
|
||||
`uvm_info(`gfn, "Generating callstack...done", UVM_LOW)
|
||||
main_program.post_process_instr();
|
||||
`uvm_info(`gfn, "Post-processing main program...done", UVM_LOW)
|
||||
main_program.generate_instr_stream();
|
||||
`uvm_info(`gfn, "Generating main program instruction stream...done", UVM_LOW)
|
||||
instr_stream = {instr_stream, main_program.instr_string_list};
|
||||
// Test done section
|
||||
gen_test_done();
|
||||
// Shuffle the sub programs and insert to the instruction stream
|
||||
insert_sub_program(sub_program, instr_stream);
|
||||
`uvm_info(`gfn, "Inserting sub-programs...done", UVM_LOW)
|
||||
// Reserve some space to copy instruction from data section
|
||||
if (instr_binary.size() > 0) begin
|
||||
instr_stream.push_back(".align 2");
|
||||
|
@ -132,45 +113,49 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
instr_stream.push_back({indent, ".endr"});
|
||||
instr_stream.push_back({indent, "ret"});
|
||||
end
|
||||
// Privileged mode switch routine
|
||||
gen_privileged_mode_switch_routine();
|
||||
`uvm_info(`gfn, "Main/sub program generation...done", UVM_LOW)
|
||||
// Program end
|
||||
gen_program_end();
|
||||
// Generate debug rom section
|
||||
gen_debug_rom();
|
||||
// Generate debug mode exception handler
|
||||
gen_debug_exception_handler();
|
||||
if (!cfg.bare_program_mode) begin
|
||||
// Privileged mode switch routine
|
||||
gen_privileged_mode_switch_routine();
|
||||
// Generate debug rom section
|
||||
gen_debug_rom();
|
||||
// Generate debug mode exception handler
|
||||
gen_debug_exception_handler();
|
||||
end
|
||||
// Starting point of data section
|
||||
gen_data_page_begin();
|
||||
// Generate the sub program in binary format
|
||||
gen_bin_program();
|
||||
// Page table
|
||||
gen_page_table_section();
|
||||
if (!cfg.bare_program_mode) begin
|
||||
gen_page_table_section();
|
||||
end
|
||||
if(!cfg.no_data_page) begin
|
||||
// Data section
|
||||
// Kernel data section
|
||||
gen_data_page();
|
||||
end
|
||||
gen_data_page_end();
|
||||
// Stack section
|
||||
gen_stack_section();
|
||||
// Generate kernel program/data/stack section
|
||||
gen_kernel_sections();
|
||||
if (!cfg.bare_program_mode) begin
|
||||
// Generate kernel program/data/stack section
|
||||
gen_kernel_sections();
|
||||
end
|
||||
endfunction
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// Generate kernel program/data/stack sections
|
||||
//---------------------------------------------------------------------------------------
|
||||
virtual function void gen_kernel_sections();
|
||||
instr_stream.push_back("_kernel_start: .align 12");
|
||||
instr_stream.push_back("_kernel_instr_start: .align 12");
|
||||
instr_stream.push_back(".text");
|
||||
// Kernel programs
|
||||
if (cfg.init_privileged_mode != MACHINE_MODE) begin
|
||||
if (cfg.virtual_addr_translation_on) begin
|
||||
smode_accessible_umode_program = riscv_instr_sequence::type_id::
|
||||
create("smode_accessible_umode_program");
|
||||
gen_kernel_program(smode_accessible_umode_program);
|
||||
end
|
||||
smode_program = riscv_instr_sequence::type_id::create("smode_program");
|
||||
gen_kernel_program(smode_program);
|
||||
if (cfg.init_privileged_mode != MACHINE_MODE) begin
|
||||
smode_program = riscv_instr_sequence::type_id::create("smode_program");
|
||||
gen_kernel_program(smode_program);
|
||||
smode_ls_umem_program = riscv_instr_sequence::type_id::create("smode_ls_umem_program");
|
||||
gen_kernel_program(smode_ls_umem_program);
|
||||
end
|
||||
|
@ -182,25 +167,29 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
foreach(riscv_instr_pkg::supported_privileged_mode[i]) begin
|
||||
gen_interrupt_handler_section(riscv_instr_pkg::supported_privileged_mode[i]);
|
||||
end
|
||||
// Kernel data pages
|
||||
gen_kernel_data_page_begin();
|
||||
if(!cfg.no_data_page) begin
|
||||
// Data section
|
||||
gen_data_page(.is_kernel(1'b1));
|
||||
instr_stream.push_back("_kernel_instr_end: nop");
|
||||
// User stack and data pages may not be accessible when executing trap handling programs in
|
||||
// machine/supervisor mode. Generate separate kernel data/stack sections to solve it.
|
||||
if (cfg.virtual_addr_translation_on) begin
|
||||
// Kernel data pages
|
||||
instr_stream.push_back("_kernel_data_start: .align 12");
|
||||
if(!cfg.no_data_page) begin
|
||||
// Data section
|
||||
gen_data_page(1'b1);
|
||||
end
|
||||
gen_data_page_end();
|
||||
end
|
||||
gen_data_page_end();
|
||||
// Kernel stack section
|
||||
gen_kernel_stack_section();
|
||||
instr_stream.push_back("_kernel_end: nop");
|
||||
endfunction
|
||||
|
||||
virtual function void gen_kernel_program(riscv_instr_sequence seq);
|
||||
seq.instr_cnt = riscv_instr_pkg::kernel_program_instr_cnt;
|
||||
seq.instr_cnt = cfg.kernel_program_instr_cnt;
|
||||
generate_directed_instr_stream(.label(seq.get_name()),
|
||||
.original_instr_cnt(seq.instr_cnt),
|
||||
.min_insert_cnt(0),
|
||||
.instr_stream(seq.directed_instr),
|
||||
.access_u_mode_mem(1'b0));
|
||||
.kernel_mode(1'b1));
|
||||
seq.label_name = seq.get_name();
|
||||
seq.is_debug_program = 0;
|
||||
seq.cfg = cfg;
|
||||
|
@ -290,10 +279,9 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
//---------------------------------------------------------------------------------------
|
||||
|
||||
virtual function void gen_program_header();
|
||||
instr_stream.push_back(".macro init");
|
||||
instr_stream.push_back(".endm");
|
||||
instr_stream.push_back(".section .text.init");
|
||||
instr_stream.push_back(".include \"user_define.h\"");
|
||||
instr_stream.push_back(".globl _start");
|
||||
instr_stream.push_back(".section .text");
|
||||
instr_stream.push_back("_start:");
|
||||
endfunction
|
||||
|
||||
|
@ -309,12 +297,6 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
instr_stream.push_back(".align 6; .global tohost; tohost: .dword 0;");
|
||||
instr_stream.push_back(".align 6; .global fromhost; fromhost: .dword 0;");
|
||||
instr_stream.push_back(".popsection;");
|
||||
instr_stream.push_back(".align 4;");
|
||||
endfunction
|
||||
|
||||
virtual function void gen_kernel_data_page_begin();
|
||||
instr_stream.push_back(".data");
|
||||
instr_stream.push_back(".align 4;");
|
||||
endfunction
|
||||
|
||||
virtual function void gen_data_page(bit is_kernel = 1'b0);
|
||||
|
@ -331,24 +313,28 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
|
||||
// Generate the user stack section
|
||||
virtual function void gen_stack_section();
|
||||
instr_stream.push_back(".pushsection .user_stack,\"aw\",@progbits;");
|
||||
instr_stream.push_back($sformatf(".align %0d", $clog2(XLEN)));
|
||||
instr_stream.push_back("_user_stack_start:");
|
||||
instr_stream.push_back($sformatf(".rept %0d", riscv_instr_pkg::stack_len - 1));
|
||||
instr_stream.push_back($sformatf(".rept %0d", cfg.stack_len - 1));
|
||||
instr_stream.push_back($sformatf(".%0dbyte 0x0", XLEN/8));
|
||||
instr_stream.push_back(".endr");
|
||||
instr_stream.push_back("_user_stack_end:");
|
||||
instr_stream.push_back($sformatf(".%0dbyte 0x0", XLEN/8));
|
||||
instr_stream.push_back(".popsection;");
|
||||
endfunction
|
||||
|
||||
// The kernal stack is used to save user program context before executing exception handling
|
||||
virtual function void gen_kernel_stack_section();
|
||||
instr_stream.push_back(".pushsection .kernel_stack,\"aw\",@progbits;");
|
||||
instr_stream.push_back($sformatf(".align %0d", $clog2(XLEN)));
|
||||
instr_stream.push_back("_kernel_stack_start:");
|
||||
instr_stream.push_back($sformatf(".rept %0d", riscv_instr_pkg::kernel_stack_len - 1));
|
||||
instr_stream.push_back($sformatf(".rept %0d", cfg.kernel_stack_len - 1));
|
||||
instr_stream.push_back($sformatf(".%0dbyte 0x0", XLEN/8));
|
||||
instr_stream.push_back(".endr");
|
||||
instr_stream.push_back("_kernel_stack_end:");
|
||||
instr_stream.push_back($sformatf(".%0dbyte 0x0", XLEN/8));
|
||||
instr_stream.push_back(".popsection;");
|
||||
endfunction
|
||||
|
||||
virtual function void gen_init_section();
|
||||
|
@ -399,10 +385,12 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// Write to the signature_addr with values to indicate to the core testbench
|
||||
// that is safe to start sending interrupt and debug stimulus
|
||||
virtual function void core_is_initialized();
|
||||
string instr[$];
|
||||
if (cfg.require_signature_addr) begin
|
||||
if (cfg.signature_addr != 32'hdead_beef) begin
|
||||
string str;
|
||||
gen_signature_handshake(instr_stream, CORE_STATUS, INITIALIZED);
|
||||
gen_signature_handshake(instr, CORE_STATUS, INITIALIZED);
|
||||
format_section(instr);
|
||||
instr_stream = {instr_stream, instr};
|
||||
end else begin
|
||||
`uvm_fatal(`gfn, "The signature_addr is not properly configured!")
|
||||
end
|
||||
|
@ -434,7 +422,11 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
string str = format_string("test_done:", LABEL_STR_LEN);
|
||||
instr_stream.push_back(str);
|
||||
instr_stream.push_back({indent, "li gp, 1"});
|
||||
instr_stream.push_back({indent, "ecall"});
|
||||
if (cfg.bare_program_mode) begin
|
||||
instr_stream.push_back({indent, "j write_tohost"});
|
||||
end else begin
|
||||
instr_stream.push_back({indent, "ecall"});
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Dump all GPR to the starting point of the program
|
||||
|
@ -474,7 +466,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// Setup trap vector register
|
||||
trap_vector_init();
|
||||
// Initialize PTE (link page table based on their real physical address)
|
||||
if((SATP_MODE != BARE) && (cfg.init_privileged_mode != MACHINE_MODE)) begin
|
||||
if(cfg.virtual_addr_translation_on) begin
|
||||
page_table_list.process_page_table(instr);
|
||||
gen_section("process_pt", instr);
|
||||
end
|
||||
|
@ -486,6 +478,8 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
privil_seq = riscv_privileged_common_seq::type_id::create("privil_seq");
|
||||
foreach(riscv_instr_pkg::supported_privileged_mode[i]) begin
|
||||
string instr[$];
|
||||
string csr_handshake[$];
|
||||
string ret_instr;
|
||||
if(riscv_instr_pkg::supported_privileged_mode[i] < cfg.init_privileged_mode) continue;
|
||||
`uvm_info(`gfn, $sformatf("Generating privileged mode routing for %0s",
|
||||
riscv_instr_pkg::supported_privileged_mode[i].name()), UVM_LOW)
|
||||
|
@ -493,6 +487,27 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
privil_seq.cfg = cfg;
|
||||
`DV_CHECK_RANDOMIZE_FATAL(privil_seq)
|
||||
privil_seq.enter_privileged_mode(riscv_instr_pkg::supported_privileged_mode[i], instr);
|
||||
if (cfg.require_signature_addr) begin
|
||||
ret_instr = instr.pop_back();
|
||||
// Want to write the main system CSRs to the testbench before indicating that initialization
|
||||
// is complete, for any initial state analysis
|
||||
case(riscv_instr_pkg::supported_privileged_mode[i])
|
||||
MACHINE_MODE: begin
|
||||
gen_signature_handshake(.instr(csr_handshake), .signature_type(WRITE_CSR), .csr(MSTATUS));
|
||||
gen_signature_handshake(.instr(csr_handshake), .signature_type(WRITE_CSR), .csr(MIE));
|
||||
end
|
||||
SUPERVISOR_MODE: begin
|
||||
gen_signature_handshake(.instr(csr_handshake), .signature_type(WRITE_CSR), .csr(SSTATUS));
|
||||
gen_signature_handshake(.instr(csr_handshake), .signature_type(WRITE_CSR), .csr(SIE));
|
||||
end
|
||||
USER_MODE: begin
|
||||
gen_signature_handshake(.instr(csr_handshake), .signature_type(WRITE_CSR), .csr(USTATUS));
|
||||
gen_signature_handshake(.instr(csr_handshake), .signature_type(WRITE_CSR), .csr(UIE));
|
||||
end
|
||||
endcase
|
||||
format_section(csr_handshake);
|
||||
instr = {instr, csr_handshake, ret_instr};
|
||||
end
|
||||
instr_stream = {instr_stream, instr};
|
||||
end
|
||||
endfunction
|
||||
|
@ -502,7 +517,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
string instr[];
|
||||
string mode_name;
|
||||
instr = {"la x10, _init"};
|
||||
if(SATP_MODE != BARE && cfg.init_privileged_mode != MACHINE_MODE) begin
|
||||
if(cfg.virtual_addr_translation_on) begin
|
||||
// For supervisor and user mode, use virtual address instead of physical address.
|
||||
// Virtual address starts from address 0x0, here only the lower 12 bits are kept
|
||||
// as virtual address offset.
|
||||
|
@ -582,7 +597,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
if (riscv_instr_pkg::supported_privileged_mode[i] < cfg.init_privileged_mode) continue;
|
||||
tvec_name = trap_vec_reg.name();
|
||||
instr = {instr, $sformatf("la a0, %0s_handler", tvec_name.tolower())};
|
||||
if(SATP_MODE != BARE && riscv_instr_pkg::supported_privileged_mode[i] != MACHINE_MODE) begin
|
||||
if (SATP_MODE != BARE && riscv_instr_pkg::supported_privileged_mode[i] != MACHINE_MODE) begin
|
||||
// For supervisor and user mode, use virtual address instead of physical address.
|
||||
// Virtual address starts from address 0x0, here only the lower 20 bits are kept
|
||||
// as virtual address offset.
|
||||
|
@ -607,12 +622,12 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
if(riscv_instr_pkg::supported_privileged_mode[i] < cfg.init_privileged_mode) continue;
|
||||
case(riscv_instr_pkg::supported_privileged_mode[i])
|
||||
MACHINE_MODE:
|
||||
gen_trap_handler_section("m", MCAUSE, MTVEC, MTVAL, MEPC, MSCRATCH, MSTATUS);
|
||||
gen_trap_handler_section("m", MCAUSE, MTVEC, MTVAL, MEPC, MSCRATCH, MSTATUS, MIE, MIP);
|
||||
SUPERVISOR_MODE:
|
||||
gen_trap_handler_section("s", SCAUSE, STVEC, STVAL, SEPC, SSCRATCH, SSTATUS);
|
||||
gen_trap_handler_section("s", SCAUSE, STVEC, STVAL, SEPC, SSCRATCH, SSTATUS, SIE, SIP);
|
||||
USER_MODE:
|
||||
if(riscv_instr_pkg::support_umode_trap)
|
||||
gen_trap_handler_section("u", UCAUSE, UTVEC, UTVAL, UEPC, USCRATCH, USTATUS);
|
||||
gen_trap_handler_section("u", UCAUSE, UTVEC, UTVAL, UEPC, USCRATCH, USTATUS, UIE, UIP);
|
||||
endcase
|
||||
end
|
||||
// Ebreak handler
|
||||
|
@ -639,12 +654,13 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
virtual function void gen_trap_handler_section(string mode,
|
||||
privileged_reg_t cause, privileged_reg_t tvec,
|
||||
privileged_reg_t tval, privileged_reg_t epc,
|
||||
privileged_reg_t scratch, privileged_reg_t status);
|
||||
privileged_reg_t scratch, privileged_reg_t status,
|
||||
privileged_reg_t ie, privileged_reg_t ip);
|
||||
bit is_interrupt = 'b1;
|
||||
string tvec_name;
|
||||
string instr[$];
|
||||
if (cfg.mtvec_mode == VECTORED) begin
|
||||
gen_interrupt_vector_table(mode, status, cause, scratch, instr);
|
||||
gen_interrupt_vector_table(mode, status, cause, ie, ip, scratch, instr);
|
||||
end else begin
|
||||
// Push user mode GPR to kernel stack before executing exception handling, this is to avoid
|
||||
// exception handling routine modify user program state unexpectedly
|
||||
|
@ -716,6 +732,8 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
virtual function void gen_interrupt_vector_table(string mode,
|
||||
privileged_reg_t status,
|
||||
privileged_reg_t cause,
|
||||
privileged_reg_t ie,
|
||||
privileged_reg_t ip,
|
||||
privileged_reg_t scratch,
|
||||
ref string instr[$]);
|
||||
|
||||
|
@ -727,22 +745,27 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
instr = {instr, ".option norvc;",
|
||||
$sformatf("j %0smode_exception_handler", mode)};
|
||||
// Redirect the interrupt to the corresponding interrupt handler
|
||||
for (int i = 1; i < 16; i++) begin
|
||||
for (int i = 1; i < max_interrupt_vector_num; i++) begin
|
||||
instr.push_back($sformatf("j %0smode_intr_vector_%0d", mode, i));
|
||||
end
|
||||
instr = {instr, ".option rvc;"};
|
||||
for (int i = 1; i < 16; i++) begin
|
||||
for (int i = 1; i < max_interrupt_vector_num; i++) begin
|
||||
string intr_handler[$];
|
||||
push_gpr_to_kernel_stack(status, scratch, cfg.mstatus_mprv, intr_handler);
|
||||
gen_signature_handshake(intr_handler, CORE_STATUS, HANDLING_IRQ);
|
||||
gen_signature_handshake(.instr(intr_handler), .signature_type(CORE_STATUS), .core_status(HANDLING_IRQ));
|
||||
intr_handler = {intr_handler,
|
||||
$sformatf("csrr a1, 0x%0x # %0s", cause, cause.name()),
|
||||
// Terminate the test if xCause[31] != 0 (indicating exception)
|
||||
$sformatf("bltz a1, 1f"),
|
||||
// TODO(taliu) write xCause to the signature address
|
||||
$sformatf("csrr a1, 0x%0x # %0s", cause, cause.name()),
|
||||
// Terminate the test if xCause[31] != 0 (indicating exception)
|
||||
$sformatf("srli a1, a1, 0x1f"),
|
||||
$sformatf("beqz a1, 1f")};
|
||||
gen_signature_handshake(.instr(intr_handler), .signature_type(WRITE_CSR), .csr(status));
|
||||
gen_signature_handshake(.instr(intr_handler), .signature_type(WRITE_CSR), .csr(cause));
|
||||
gen_signature_handshake(.instr(intr_handler), .signature_type(WRITE_CSR), .csr(ie));
|
||||
gen_signature_handshake(.instr(intr_handler), .signature_type(WRITE_CSR), .csr(ip));
|
||||
// Jump to commmon interrupt handling routine
|
||||
$sformatf("j %0smode_intr_handler", mode),
|
||||
"1: j test_done"};
|
||||
intr_handler = {intr_handler,
|
||||
$sformatf("j %0smode_intr_handler", mode),
|
||||
"1: j test_done"};
|
||||
gen_section($sformatf("%0smode_intr_vector_%0d", mode, i), intr_handler);
|
||||
end
|
||||
endfunction
|
||||
|
@ -768,9 +791,11 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// guarantees that epc + 4 is a valid instruction boundary
|
||||
// TODO: Support random operations in debug mode
|
||||
// TODO: Support ebreak exception delegation
|
||||
// TODO: handshake the correct Xcause CSR based on delegation privil. mode
|
||||
virtual function void gen_ebreak_handler();
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, HANDLING_EXCEPTION);
|
||||
gen_signature_handshake(instr, CORE_STATUS, EBREAK_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
instr = {instr,
|
||||
"csrr x31, mepc",
|
||||
"addi x31, x31, 4",
|
||||
|
@ -787,9 +812,11 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// know the illegal instruction is compressed or not. This hanlder just simply adds the PC by
|
||||
// 4 and resumes execution. The way that the illegal instruction is injected guarantees that
|
||||
// PC + 4 is a valid instruction boundary.
|
||||
// TODO: handshake the corret Xcause CSR based on delegation setup
|
||||
virtual function void gen_illegal_instr_handler();
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, HANDLING_EXCEPTION);
|
||||
gen_signature_handshake(instr, CORE_STATUS, ILLEGAL_INSTR_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
instr = {instr,
|
||||
"csrr x31, mepc",
|
||||
"addi x31, x31, 4",
|
||||
|
@ -810,7 +837,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// all the other super pages are link PTE.
|
||||
virtual function void create_page_table();
|
||||
string instr[];
|
||||
if((SATP_MODE != BARE) && (cfg.init_privileged_mode != MACHINE_MODE)) begin
|
||||
if(cfg.virtual_addr_translation_on) begin
|
||||
page_table_list = riscv_page_table_list#(SATP_MODE)::
|
||||
type_id::create("page_table_list");
|
||||
page_table_list.cfg = cfg;
|
||||
|
@ -830,10 +857,12 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
virtual function void gen_page_table_section();
|
||||
string page_table_section[$];
|
||||
if(page_table_list != null) begin
|
||||
instr_stream.push_back(".pushsection .page_table,\"aw\",@progbits;");
|
||||
foreach(page_table_list.page_table[i]) begin
|
||||
page_table_list.page_table[i].gen_page_table_section(page_table_section);
|
||||
instr_stream = {instr_stream, page_table_section};
|
||||
end
|
||||
instr_stream.push_back(".popsection;");
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
@ -841,6 +870,10 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// In this case, the core will write to a specific location as the response to the interrupt, and
|
||||
// external PLIC unit can detect this response and process the interrupt clean up accordingly.
|
||||
virtual function void gen_plic_section(ref string interrupt_handler_instr[$]);
|
||||
// Utilize the memory mapped handshake scheme to signal the testbench that the interrupt
|
||||
// handling has been completed and we are about to xRET out of the handler
|
||||
gen_signature_handshake(.instr(interrupt_handler_instr), .signature_type(CORE_STATUS),
|
||||
.core_status(FINISHED_IRQ));
|
||||
endfunction
|
||||
|
||||
// Interrupt handler routine
|
||||
|
@ -943,39 +976,34 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
input signature_type_t signature_type,
|
||||
core_status_t core_status = INITIALIZED,
|
||||
test_result_t test_result = TEST_FAIL,
|
||||
privileged_reg_t csr = MSCRATCH);
|
||||
privileged_reg_t csr = MSCRATCH,
|
||||
string addr_label = "");
|
||||
if (cfg.require_signature_addr) begin
|
||||
string str;
|
||||
str = $sformatf("li x%0d, 0x%0h", cfg.signature_addr_reg, cfg.signature_addr);
|
||||
instr.push_back(str);
|
||||
string str[$];
|
||||
str = {$sformatf("li x%0d, 0x%0h", cfg.signature_addr_reg, cfg.signature_addr)};
|
||||
instr = {instr, str};
|
||||
case (signature_type)
|
||||
// A single data word is written to the signature address.
|
||||
// Bits [7:0] contain the signature_type of CORE_STATUS, and the upper
|
||||
// XLEN-8 bits contain the core_status_t data.
|
||||
CORE_STATUS: begin
|
||||
str = $sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, core_status);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("slli x%0d, x%0d, 8", cfg.signature_data_reg, cfg.signature_data_reg);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("addi x%0d, x%0d, 0x%0h", cfg.signature_data_reg,
|
||||
cfg.signature_data_reg, signature_type);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
|
||||
instr.push_back(str);
|
||||
str = {$sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, core_status),
|
||||
$sformatf("slli x%0d, x%0d, 8", cfg.signature_data_reg, cfg.signature_data_reg),
|
||||
$sformatf("addi x%0d, x%0d, 0x%0h", cfg.signature_data_reg,
|
||||
cfg.signature_data_reg, signature_type),
|
||||
$sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg)};
|
||||
instr = {instr, str};
|
||||
end
|
||||
// A single data word is written to the signature address.
|
||||
// Bits [7:0] contain the signature_type of TEST_RESULT, and the upper
|
||||
// XLEN-8 bits contain the test_result_t data.
|
||||
TEST_RESULT: begin
|
||||
str = $sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, test_result);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("slli x%0d, x%0d, 8", cfg.signature_data_reg, cfg.signature_data_reg);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("addi x%0d, x%0d, 0x%0h", cfg.signature_data_reg,
|
||||
cfg.signature_data_reg, signature_type);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
|
||||
instr.push_back(str);
|
||||
str = {$sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, test_result),
|
||||
$sformatf("slli x%0d, x%0d, 8", cfg.signature_data_reg, cfg.signature_data_reg),
|
||||
$sformatf("addi x%0d, x%0d, 0x%0h", cfg.signature_data_reg,
|
||||
cfg.signature_data_reg, signature_type),
|
||||
$sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg)};
|
||||
instr = {instr, str};
|
||||
end
|
||||
// The first write to the signature address contains just the
|
||||
// signature_type of WRITE_GPR.
|
||||
|
@ -983,13 +1011,12 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// each writing the data contained in one GPR, starting from x0 as the
|
||||
// first write, and ending with x31 as the 32nd write.
|
||||
WRITE_GPR: begin
|
||||
str = $sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, signature_type);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
|
||||
instr.push_back(str);
|
||||
str = {$sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, signature_type),
|
||||
$sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg)};
|
||||
instr = {instr, str};
|
||||
for(int i = 0; i < 32; i++) begin
|
||||
str = $sformatf("sw x%0x, 0(x%0d)", i, cfg.signature_addr_reg);
|
||||
instr.push_back(str);
|
||||
str = {$sformatf("sw x%0x, 0(x%0d)", i, cfg.signature_addr_reg)};
|
||||
instr = {instr, str};
|
||||
end
|
||||
end
|
||||
// The first write to the signature address contains the
|
||||
|
@ -998,19 +1025,14 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// It is followed by a second write to the signature address,
|
||||
// containing the data stored in the specified CSR.
|
||||
WRITE_CSR: begin
|
||||
str = $sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, csr);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("slli x%0d, x%0d, 8", cfg.signature_data_reg, cfg.signature_data_reg);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("addi x%0d, x%0d, 0x%0h", cfg.signature_data_reg,
|
||||
cfg.signature_data_reg, signature_type);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("csrr x%0d, 0x%0h", cfg.signature_data_reg, csr);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg);
|
||||
instr.push_back(str);
|
||||
str = {$sformatf("li x%0d, 0x%0h", cfg.signature_data_reg, csr),
|
||||
$sformatf("slli x%0d, x%0d, 8", cfg.signature_data_reg, cfg.signature_data_reg),
|
||||
$sformatf("addi x%0d, x%0d, 0x%0h", cfg.signature_data_reg,
|
||||
cfg.signature_data_reg, signature_type),
|
||||
$sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg),
|
||||
$sformatf("csrr x%0d, 0x%0h", cfg.signature_data_reg, csr),
|
||||
$sformatf("sw x%0d, 0(x%0d)", cfg.signature_data_reg, cfg.signature_addr_reg)};
|
||||
instr = {instr, str};
|
||||
end
|
||||
default: begin
|
||||
`uvm_fatal(`gfn, "signature_type is not defined")
|
||||
|
@ -1048,7 +1070,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
virtual function void generate_directed_instr_stream(input string label,
|
||||
input int unsigned original_instr_cnt,
|
||||
input int unsigned min_insert_cnt = 0,
|
||||
input bit access_u_mode_mem = 1,
|
||||
input bit kernel_mode = 0,
|
||||
output riscv_instr_stream instr_stream[]);
|
||||
uvm_object object_h;
|
||||
riscv_rand_instr_stream new_instr_stream;
|
||||
|
@ -1073,7 +1095,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
if($cast(new_instr_stream, object_h)) begin
|
||||
new_instr_stream.cfg = cfg;
|
||||
new_instr_stream.label = $sformatf("%0s_instr_%0d", label, idx);
|
||||
new_instr_stream.access_u_mode_mem = access_u_mode_mem;
|
||||
new_instr_stream.kernel_mode = kernel_mode;
|
||||
`DV_CHECK_RANDOMIZE_FATAL(new_instr_stream)
|
||||
instr_stream = {instr_stream, new_instr_stream};
|
||||
end else begin
|
||||
|
@ -1085,45 +1107,84 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
instr_stream.shuffle();
|
||||
endfunction
|
||||
|
||||
// Generate sub-program in binary format, this is needed for illegal and HINT instruction
|
||||
function void gen_bin_program();
|
||||
if (bin_program != null) begin
|
||||
string str;
|
||||
instr_stream.push_back("instr_bin:");
|
||||
instr_stream.push_back(".align 12");
|
||||
foreach (instr_binary[i]) begin
|
||||
if (((i+1) % 8 == 0) || (i == instr_binary.size() - 1)) begin
|
||||
if (str != "")
|
||||
instr_stream.push_back($sformatf(".word %0s, %0s", str, instr_binary[i]));
|
||||
else
|
||||
instr_stream.push_back($sformatf(".word %0s", instr_binary[i]));
|
||||
str = "";
|
||||
end else begin
|
||||
if (str != "") begin
|
||||
str = {str, ", ", instr_binary[i]};
|
||||
end else begin
|
||||
str = instr_binary[i];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
//---------------------------------------------------------------------------------------
|
||||
// Generate the debug rom, and any related programs
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
||||
// Generate the program in the debug ROM
|
||||
// Processor will fetch instruction from here upon receiving debug request from debug module
|
||||
virtual function void gen_debug_rom();
|
||||
string push_gpr[$];
|
||||
string pop_gpr[$];
|
||||
string instr[$];
|
||||
string debug_end[$];
|
||||
string dret;
|
||||
string debug_sub_program_name[$] = {};
|
||||
string str[$];
|
||||
if (riscv_instr_pkg::support_debug_mode) begin
|
||||
// Signal that the core entered the debug rom regardless of whether the
|
||||
// main debug rom program has been generated
|
||||
gen_signature_handshake(instr, CORE_STATUS, IN_DEBUG_MODE);
|
||||
format_section(instr);
|
||||
dret = {format_string(" ", LABEL_STR_LEN), "dret"};
|
||||
// The main debug rom
|
||||
if (cfg.gen_debug_section) begin
|
||||
if (!cfg.gen_debug_section) begin
|
||||
// If the debug section should not be generated, we just populate it
|
||||
// with a dret instruction.
|
||||
instr = {dret};
|
||||
gen_section("debug_rom", instr);
|
||||
end else begin
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
// As execution of ebreak in D mode causes core to
|
||||
// re-enter D mode, this directed sequence will be a loop that ensures the
|
||||
// ebreak instruction will only be executed once to prevent infinitely
|
||||
// looping back to the beginning of the debug rom.
|
||||
// Write dscratch to random GPR and branch to debug_end if greater
|
||||
// than 0, for ebreak loops.
|
||||
// Use dscratch1 to store original GPR value.
|
||||
str = {$sformatf("csrw 0x%0x, x%0d", DSCRATCH1, cfg.scratch_reg),
|
||||
$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH0)};
|
||||
instr = {instr, str};
|
||||
// send dpc and dcsr to testbench, as this handshake will be
|
||||
// executed twice due to the ebreak loop, there should be no change
|
||||
// in their values as by the Debug Mode Spec Ch. 4.1.8
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(DCSR));
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(DPC));
|
||||
str = {$sformatf("beq x%0d, x0, 1f", cfg.scratch_reg),
|
||||
$sformatf("j debug_end"),
|
||||
$sformatf("1: csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH1)};
|
||||
instr = {instr, str};
|
||||
end
|
||||
// Need to save off GPRs to avoid modifying program flow
|
||||
push_gpr_to_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, instr);
|
||||
// Signal that the core entered debug rom only if the rom is actually
|
||||
// being filled with random instructions to prevent stress tests from
|
||||
// having to execute unnecessary push/pop of GPRs on the stack ever
|
||||
// time a debug request is sent
|
||||
gen_signature_handshake(instr, CORE_STATUS, IN_DEBUG_MODE);
|
||||
if (cfg.set_dcsr_ebreak) begin
|
||||
// We want to set dcsr.ebreak(m/s/u) to 1'b1, depending on what modes
|
||||
// are available.
|
||||
// TODO(udinator) - randomize the dcsr.ebreak setup
|
||||
gen_dcsr_ebreak(instr);
|
||||
end
|
||||
// Check dcsr.cause, and update dpc by 0x4 if the cause is ebreak, as
|
||||
// ebreak will set set dpc to its own address, which will cause an
|
||||
// infinite loop.
|
||||
str = {$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DCSR),
|
||||
$sformatf("slli x%0d, x%0d, 0x17", cfg.scratch_reg, cfg.scratch_reg),
|
||||
$sformatf("srli x%0d, x%0d, 0x1d", cfg.scratch_reg, cfg.scratch_reg),
|
||||
$sformatf("li x%0d, 0x1", cfg.signature_data_reg),
|
||||
$sformatf("bne x%0d, x%0d, 2f", cfg.scratch_reg, cfg.signature_data_reg)};
|
||||
instr = {instr, str};
|
||||
increment_csr(DPC, 4, instr);
|
||||
str = {"2: nop"};
|
||||
instr = {instr, str};
|
||||
// write DCSR to the testbench for any analysis
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(DCSR));
|
||||
// Increment dscratch0 by 1 to update the loop counter for all ebreak
|
||||
// tests
|
||||
if (cfg.enable_ebreak_in_debug_rom || cfg.set_dcsr_ebreak) begin
|
||||
// Add 1 to dscratch0
|
||||
increment_csr(DSCRATCH0, 1, instr);
|
||||
str = {$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH1)};
|
||||
instr = {instr, str};
|
||||
end
|
||||
format_section(instr);
|
||||
gen_sub_program(debug_sub_program, debug_sub_program_name,
|
||||
cfg.num_debug_sub_program, 1'b1, "debug_sub");
|
||||
debug_program = riscv_instr_sequence::type_id::create("debug_program");
|
||||
|
@ -1136,17 +1197,28 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
cfg.num_debug_sub_program);
|
||||
debug_program.post_process_instr();
|
||||
debug_program.generate_instr_stream(.no_label(1'b1));
|
||||
// Need to save off GPRs to avoid modifying program flow
|
||||
push_gpr_to_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, push_gpr);
|
||||
format_section(push_gpr);
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, pop_gpr);
|
||||
format_section(pop_gpr);
|
||||
instr = {push_gpr, instr, debug_program.instr_string_list, pop_gpr};
|
||||
insert_sub_program(debug_sub_program, instr_stream);
|
||||
instr = {instr, debug_program.instr_string_list};
|
||||
gen_section("debug_rom", instr);
|
||||
// Set dscratch0 back to 0x0 to prepare for the next entry into debug
|
||||
// mode, and write dscratch0 and dcsr to the testbench for any
|
||||
// analysis
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
str = {$sformatf("csrwi 0x%0x, 0x0", DSCRATCH0)};
|
||||
debug_end = {debug_end, str};
|
||||
end
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, debug_end);
|
||||
// We have been using dscratch1 to store the
|
||||
// value of our given scratch register for use in ebreak loop, so we
|
||||
// need to restore its value before returning from D mode
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
str = {$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH1)};
|
||||
debug_end = {debug_end, str};
|
||||
end
|
||||
format_section(debug_end);
|
||||
debug_end = {debug_end, dret};
|
||||
gen_section("debug_end", debug_end);
|
||||
end
|
||||
dret = {format_string(" ", LABEL_STR_LEN), "dret"};
|
||||
instr = {instr, dret};
|
||||
gen_section("debug_rom", instr);
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
@ -1159,4 +1231,38 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
end
|
||||
endfunction
|
||||
|
||||
// Set dcsr.ebreak(m/s/u)
|
||||
// TODO(udinator) - randomize the setup for these fields
|
||||
virtual function void gen_dcsr_ebreak(ref string instr[$]);
|
||||
string str;
|
||||
if (MACHINE_MODE inside {riscv_instr_pkg::supported_privileged_mode}) begin
|
||||
str = $sformatf("li x%0d, 0x8000", cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("csrs dcsr, x%0d", cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
end
|
||||
if (SUPERVISOR_MODE inside {riscv_instr_pkg::supported_privileged_mode}) begin
|
||||
str = $sformatf("li x%0d, 0x2000", cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("csrs dcsr, x%0d", cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
end
|
||||
if (USER_MODE inside {riscv_instr_pkg::supported_privileged_mode}) begin
|
||||
str = $sformatf("li x%0d, 0x1000", cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("csrs dcsr, x%0d", cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void increment_csr(privileged_reg_t csr, int val, ref string instr[$]);
|
||||
string str;
|
||||
str = $sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, csr);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("addi x%0d, x%0d, 0x%0x", cfg.scratch_reg, cfg.scratch_reg, val);
|
||||
instr.push_back(str);
|
||||
str = $sformatf("csrw 0x%0x, x%0d", csr, cfg.scratch_reg);
|
||||
instr.push_back(str);
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
|
|
@ -23,6 +23,7 @@ class riscv_data_page_gen extends uvm_object;
|
|||
|
||||
riscv_instr_gen_config cfg;
|
||||
string data_page_str[$];
|
||||
mem_region_t mem_region_setting[$];
|
||||
|
||||
`uvm_object_utils(riscv_data_page_gen)
|
||||
|
||||
|
@ -48,29 +49,48 @@ class riscv_data_page_gen extends uvm_object;
|
|||
end
|
||||
endfunction
|
||||
|
||||
// Generate the assembly code for the data section
|
||||
// Generate data pages for all memory regions
|
||||
function void gen_data_page(data_pattern_t pattern, bit is_kernel = 1'b0);
|
||||
string tmp_str;
|
||||
bit [7:0] tmp_data[];
|
||||
int page_cnt;
|
||||
int page_size;
|
||||
data_page_str = {};
|
||||
page_cnt = is_kernel ? riscv_instr_pkg::num_of_kernel_data_pages :
|
||||
riscv_instr_pkg::num_of_data_pages;
|
||||
page_size = is_kernel ? riscv_instr_pkg::kernel_data_page_size :
|
||||
riscv_instr_pkg::data_page_size;
|
||||
for(int section_idx = 0; section_idx < page_cnt; section_idx++) begin
|
||||
if(is_kernel) begin
|
||||
data_page_str.push_back($sformatf("kernel_data_page_%0d:", section_idx));
|
||||
end else begin
|
||||
data_page_str.push_back($sformatf("data_page_%0d:", section_idx));
|
||||
if (is_kernel) begin
|
||||
mem_region_setting = cfg.s_mem_region;
|
||||
end else begin
|
||||
mem_region_setting = cfg.mem_region;
|
||||
end
|
||||
if (is_kernel) begin
|
||||
// All kernel data pages in the same section
|
||||
data_page_str.push_back(".pushsection .kernel_data,\"aw\",@progbits;");
|
||||
end
|
||||
foreach (mem_region_setting[i]) begin
|
||||
`uvm_info(`gfn, $sformatf("Generate data section: %0s size:0x%0x xwr:0x%0x]",
|
||||
mem_region_setting[i].name,
|
||||
mem_region_setting[i].size_in_bytes,
|
||||
mem_region_setting[i].xwr), UVM_LOW)
|
||||
if (!is_kernel) begin
|
||||
data_page_str.push_back($sformatf(".pushsection .%0s,\"aw\",@progbits;",
|
||||
mem_region_setting[i].name));
|
||||
end
|
||||
data_page_str.push_back($sformatf(".align %0d", riscv_instr_pkg::data_page_alignment));
|
||||
data_page_str.push_back($sformatf("%0s:", mem_region_setting[i].name));
|
||||
page_size = mem_region_setting[i].size_in_bytes;
|
||||
for(int i = 0; i < page_size; i+= 32) begin
|
||||
gen_data(.idx(i), .pattern(pattern), .num_of_bytes(32), .data(tmp_data));
|
||||
if (page_size-i >= 32) begin
|
||||
gen_data(.idx(i), .pattern(pattern), .num_of_bytes(32), .data(tmp_data));
|
||||
end else begin
|
||||
gen_data(.idx(i), .pattern(pattern), .num_of_bytes(page_size-i), .data(tmp_data));
|
||||
end
|
||||
tmp_str = format_string($sformatf(".word %0s", format_data(tmp_data)), LABEL_STR_LEN);
|
||||
data_page_str.push_back(tmp_str);
|
||||
end
|
||||
if (!is_kernel) begin
|
||||
data_page_str.push_back(".popsection;");
|
||||
end
|
||||
end
|
||||
if (is_kernel) begin
|
||||
data_page_str.push_back(".popsection;");
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
|
|
@ -40,6 +40,27 @@ class riscv_directed_instr_stream extends riscv_rand_instr_stream;
|
|||
|
||||
endclass
|
||||
|
||||
// Base class for memory access stream
|
||||
class riscv_mem_access_stream extends riscv_directed_instr_stream;
|
||||
|
||||
int max_data_page_id;
|
||||
mem_region_t data_page[$];
|
||||
string label;
|
||||
|
||||
`uvm_object_utils(riscv_mem_access_stream)
|
||||
`uvm_object_new
|
||||
|
||||
function void pre_randomize();
|
||||
if(kernel_mode) begin
|
||||
data_page = cfg.s_mem_region;
|
||||
end else begin
|
||||
data_page = cfg.mem_region;
|
||||
end
|
||||
max_data_page_id = data_page.size();
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Create a infinte zero instruction loop, test if we can interrupt or
|
||||
// enter debug mode while core is executing this loop
|
||||
class riscv_infinte_loop_instr extends riscv_directed_instr_stream;
|
||||
|
@ -109,10 +130,7 @@ class riscv_jump_instr extends riscv_rand_instr_stream;
|
|||
!(addi.rs1 inside {cfg.reserved_regs, ZERO});
|
||||
addi.rs1 == la.rd;
|
||||
addi.rd == la.rd;
|
||||
// Avoid using negative offset -1024
|
||||
addi.imm != 'hFFFF_FC00;
|
||||
addi.imm != 1024;
|
||||
jump.imm == ~addi.imm + 1;
|
||||
imm inside {[-1023:1023]};
|
||||
jump.rs1 == addi.rd;
|
||||
addi.instr_name == ADDI;
|
||||
branch.category == BRANCH;
|
||||
|
@ -142,6 +160,8 @@ class riscv_jump_instr extends riscv_rand_instr_stream;
|
|||
initialize_instr_list(mixed_instr_cnt);
|
||||
gen_instr(1'b1);
|
||||
la.imm_str = target_program_label;
|
||||
addi.imm_str = $sformatf("%0d", imm);
|
||||
jump.imm_str = $sformatf("%0d", -imm);
|
||||
// The branch instruction is always inserted right before the jump instruction to avoid
|
||||
// skipping other required instructions like restore stack, load jump base etc.
|
||||
// The purse of adding the branch instruction here is to cover branch -> jump scenario.
|
||||
|
@ -188,8 +208,9 @@ class riscv_push_stack_instr extends riscv_rand_instr_stream;
|
|||
endfunction
|
||||
|
||||
function void init();
|
||||
// Save RA, T0 and all reserved loop regs
|
||||
saved_regs = {RA, T0, cfg.loop_regs};
|
||||
// Save RA, T0
|
||||
reserved_rd = {RA, T0};
|
||||
saved_regs = {RA, T0};
|
||||
num_of_reg_to_save = saved_regs.size();
|
||||
if(num_of_reg_to_save * (XLEN/8) > stack_len) begin
|
||||
`uvm_fatal(get_full_name(), $sformatf("stack len [%0d] is not enough to store %d regs",
|
||||
|
@ -266,6 +287,7 @@ class riscv_pop_stack_instr extends riscv_rand_instr_stream;
|
|||
endfunction
|
||||
|
||||
function void init();
|
||||
reserved_rd = {RA, T0};
|
||||
num_of_reg_to_save = saved_regs.size();
|
||||
if(num_of_reg_to_save * 4 > stack_len) begin
|
||||
`uvm_fatal(get_full_name(), $sformatf("stack len [%0d] is not enough to store %d regs",
|
||||
|
@ -337,7 +359,8 @@ class riscv_long_branch_instr extends riscv_rand_instr_stream;
|
|||
backward_branch_instr_stream.initialize_instr_list(branch_instr_stream_len);
|
||||
endfunction
|
||||
|
||||
virtual function void gen_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1);
|
||||
virtual function void gen_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1,
|
||||
bit is_debug_program = 1'b0);
|
||||
int branch_offset;
|
||||
super.gen_instr(1'b1);
|
||||
forward_branch_instr_stream.gen_instr();
|
||||
|
|
|
@ -39,9 +39,10 @@ class riscv_illegal_instr extends uvm_object;
|
|||
7'b0100011,
|
||||
7'b0110111,
|
||||
7'b1100011,
|
||||
7'b0110011,
|
||||
7'b1100111,
|
||||
7'b1101111,
|
||||
7'b1110011};
|
||||
7'b1110011,
|
||||
7'b1101111};
|
||||
|
||||
rand illegal_instr_type_e exception;
|
||||
rand bit [31:0] instr_bin;
|
||||
|
@ -213,9 +214,6 @@ class riscv_illegal_instr extends uvm_object;
|
|||
if (riscv_instr_pkg::RV32A inside {riscv_instr_pkg::supported_isa}) begin
|
||||
legal_opcode = {legal_opcode, 7'b0101111};
|
||||
end
|
||||
if (riscv_instr_pkg::RV32M inside {riscv_instr_pkg::supported_isa}) begin
|
||||
legal_opcode = {legal_opcode, 7'b0110011};
|
||||
end
|
||||
if ((riscv_instr_pkg::RV64I inside {riscv_instr_pkg::supported_isa}) ||
|
||||
riscv_instr_pkg::RV64M inside {riscv_instr_pkg::supported_isa}) begin
|
||||
legal_opcode = {legal_opcode, 7'b0111011};
|
||||
|
|
52
vendor/google_riscv-dv/src/riscv_instr_base.sv
vendored
52
vendor/google_riscv-dv/src/riscv_instr_base.sv
vendored
|
@ -182,6 +182,9 @@ class riscv_instr_base extends uvm_object;
|
|||
rs2 inside {[S0:A5]};
|
||||
rd inside {[S0:A5]};
|
||||
}
|
||||
if(format inside {CI_FORMAT, CR_FORMAT}) {
|
||||
rs1 == rd;
|
||||
}
|
||||
// C_ADDI16SP is only valid when rd == SP
|
||||
if(instr_name == C_ADDI16SP) {
|
||||
rd == SP;
|
||||
|
@ -244,6 +247,7 @@ class riscv_instr_base extends uvm_object;
|
|||
`add_instr(URET, I_FORMAT, SYSTEM, RV32I)
|
||||
`add_instr(SRET, I_FORMAT, SYSTEM, RV32I)
|
||||
`add_instr(MRET, I_FORMAT, SYSTEM, RV32I)
|
||||
`add_instr(DRET, I_FORMAT, SYSTEM, RV32I)
|
||||
`add_instr(WFI, I_FORMAT, INTERRUPT, RV32I)
|
||||
// CSR instructions
|
||||
`add_instr(CSRRW, R_FORMAT, CSR, RV32I, UIMM)
|
||||
|
@ -469,16 +473,35 @@ class riscv_instr_base extends uvm_object;
|
|||
function riscv_reg_t gen_rand_gpr(riscv_reg_t included_reg[] = {},
|
||||
riscv_reg_t excluded_reg[] = {});
|
||||
riscv_reg_t gpr;
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(gpr,
|
||||
if (is_compressed) {
|
||||
gpr inside {[S0:A5]};
|
||||
}
|
||||
if (excluded_reg.size() != 0) {
|
||||
!(gpr inside {excluded_reg});
|
||||
}
|
||||
if (included_reg.size() != 0) {
|
||||
gpr inside {included_reg};
|
||||
})
|
||||
int unsigned i;
|
||||
riscv_reg_t legal_gpr[$];
|
||||
if (included_reg.size() > 0) begin
|
||||
legal_gpr = included_reg;
|
||||
while (is_compressed && (i < legal_gpr.size())) begin
|
||||
if (legal_gpr[i] < S0 || legal_gpr[i] > A5) begin
|
||||
legal_gpr.delete(i);
|
||||
end else begin
|
||||
i++;
|
||||
end
|
||||
end
|
||||
end else if (is_compressed) begin
|
||||
legal_gpr = riscv_instr_pkg::compressed_gpr;
|
||||
end else begin
|
||||
legal_gpr = riscv_instr_pkg::all_gpr;
|
||||
end
|
||||
if (excluded_reg.size() > 0) begin
|
||||
i = 0;
|
||||
while (i < legal_gpr.size()) begin
|
||||
if (legal_gpr[i] inside {excluded_reg}) begin
|
||||
legal_gpr.delete(i);
|
||||
end else begin
|
||||
i++;
|
||||
end
|
||||
end
|
||||
end
|
||||
`DV_CHECK_FATAL(legal_gpr.size() > 0)
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(i, i < legal_gpr.size();)
|
||||
gpr = legal_gpr[i];
|
||||
return gpr;
|
||||
endfunction
|
||||
|
||||
|
@ -521,6 +544,8 @@ class riscv_instr_base extends uvm_object;
|
|||
I_FORMAT: // instr rd,rs1,imm
|
||||
if(instr_name == NOP)
|
||||
asm_str = "nop";
|
||||
else if(instr_name == WFI)
|
||||
asm_str = "wfi";
|
||||
else if(instr_name == FENCE)
|
||||
asm_str = $sformatf("fence"); // TODO: Support all fence combinations
|
||||
else if(instr_name == FENCEI)
|
||||
|
@ -602,7 +627,7 @@ class riscv_instr_base extends uvm_object;
|
|||
FENCE, FENCEI : get_opcode = 7'b0001111;
|
||||
ECALL, EBREAK, CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI : get_opcode = 7'b1110011;
|
||||
ADDW, SUBW, SLLW, SRLW, SRAW, MULW, DIVW, DIVUW, REMW, REMUW : get_opcode = 7'b0111011;
|
||||
ECALL, EBREAK, URET, SRET, MRET, WFI, SFENCE_VMA : get_opcode = 7'b1110011;
|
||||
ECALL, EBREAK, URET, SRET, MRET, DRET, WFI, SFENCE_VMA : get_opcode = 7'b1110011;
|
||||
default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
|
||||
endcase
|
||||
endfunction
|
||||
|
@ -744,7 +769,7 @@ class riscv_instr_base extends uvm_object;
|
|||
C_SWSP : get_func3 = 3'b110;
|
||||
C_FSWSP : get_func3 = 3'b111;
|
||||
C_SDSP : get_func3 = 3'b111;
|
||||
ECALL, EBREAK, URET, SRET, MRET, WFI, SFENCE_VMA : get_func3 = 3'b000;
|
||||
ECALL, EBREAK, URET, SRET, MRET, DRET, WFI, SFENCE_VMA : get_func3 = 3'b000;
|
||||
default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
|
||||
endcase
|
||||
endfunction
|
||||
|
@ -794,6 +819,7 @@ class riscv_instr_base extends uvm_object;
|
|||
URET : get_func7 = 7'b0000000;
|
||||
SRET : get_func7 = 7'b0001000;
|
||||
MRET : get_func7 = 7'b0011000;
|
||||
DRET : get_func7 = 7'b0111101;
|
||||
WFI : get_func7 = 7'b0001000;
|
||||
SFENCE_VMA: get_func7 = 7'b0001001;
|
||||
default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
|
||||
|
@ -820,6 +846,8 @@ class riscv_instr_base extends uvm_object;
|
|||
binary = $sformatf("%8h", {get_func7(), 18'b0, get_opcode()});
|
||||
else if(instr_name inside {URET, SRET, MRET})
|
||||
binary = $sformatf("%8h", {get_func7(), 5'b10, 13'b0, get_opcode()});
|
||||
else if(instr_name inside {DRET})
|
||||
binary = $sformatf("%8h", {get_func7(), 5'b10010, 13'b0, get_opcode()});
|
||||
else if(instr_name == EBREAK)
|
||||
binary = $sformatf("%8h", {get_func7(), 5'b01, 13'b0, get_opcode()});
|
||||
else if(instr_name == WFI)
|
||||
|
|
139
vendor/google_riscv-dv/src/riscv_instr_gen_config.sv
vendored
139
vendor/google_riscv-dv/src/riscv_instr_gen_config.sv
vendored
|
@ -39,9 +39,6 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
// Pattern of data section: RAND_DATA, ALL_ZERO, INCR_VAL
|
||||
rand data_pattern_t data_page_pattern;
|
||||
|
||||
// Max depth for the nested loops
|
||||
rand bit [1:0] max_nested_loop;
|
||||
|
||||
// Associate array for delegation configuration for each exception and interrupt
|
||||
// When the bit is 1, the corresponding delegation is enabled.
|
||||
rand bit m_mode_exception_delegation[exception_cause_t];
|
||||
|
@ -52,6 +49,10 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
// Priviledged mode after boot
|
||||
rand privileged_mode_t init_privileged_mode;
|
||||
|
||||
rand bit[XLEN-1:0] mstatus, mie,
|
||||
sstatus, sie,
|
||||
ustatus, uie;
|
||||
|
||||
// Key fields in xSTATUS
|
||||
// Memory protection bits
|
||||
rand bit mstatus_mprv;
|
||||
|
@ -69,12 +70,44 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
bit check_misa_init_val = 1'b0;
|
||||
bit check_xstatus = 1'b1;
|
||||
|
||||
// Virtual address translation is on for this test
|
||||
bit virtual_addr_translation_on;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// User space memory region and stack setting
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
mem_region_t mem_region[$] = '{
|
||||
'{name:"region_0", size_in_bytes: 4096, xwr: 3'b111},
|
||||
'{name:"region_1", size_in_bytes: 4096 * 4, xwr: 3'b111},
|
||||
'{name:"region_2", size_in_bytes: 4096 * 2, xwr: 3'b111},
|
||||
'{name:"region_3", size_in_bytes: 512, xwr: 3'b111},
|
||||
'{name:"region_4", size_in_bytes: 4096, xwr: 3'b111}
|
||||
};
|
||||
|
||||
// Stack section word length
|
||||
int stack_len = 5000;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Kernel section setting, used by supervisor mode programs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
mem_region_t s_mem_region[$] = '{
|
||||
'{name:"s_region_0", size_in_bytes: 4096, xwr: 3'b111},
|
||||
'{name:"s_region_1", size_in_bytes: 4096, xwr: 3'b111}};
|
||||
|
||||
// Kernel Stack section word length
|
||||
int kernel_stack_len = 4000;
|
||||
|
||||
// Number of instructions for each kernel program
|
||||
int kernel_program_instr_cnt = 400;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Instruction list based on the config, generate by build_instruction_template
|
||||
//-----------------------------------------------------------------------------
|
||||
riscv_instr_base instr_template[riscv_instr_name_t];
|
||||
riscv_instr_name_t basic_instr[$];
|
||||
riscv_instr_name_t instr_group[riscv_instr_cateogry_t][$];
|
||||
riscv_instr_name_t instr_group[riscv_instr_group_t][$];
|
||||
riscv_instr_name_t instr_category[riscv_instr_cateogry_t][$];
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -88,16 +121,16 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
// For tests doesn't involve load/store, the data section generation could be skipped
|
||||
bit no_data_page;
|
||||
// Options to turn off some specific types of instructions
|
||||
bit no_branch_jump; // No branch/jump instruction
|
||||
bit no_load_store; // No load/store instruction
|
||||
bit no_csr_instr; // No csr instruction
|
||||
bit no_ebreak = 1; // No ebreak instruction
|
||||
bit no_fence; // No fence instruction
|
||||
bit no_wfi = 1; // No WFI instruction
|
||||
bit no_branch_jump; // No branch/jump instruction
|
||||
bit no_load_store; // No load/store instruction
|
||||
bit no_csr_instr; // No csr instruction
|
||||
bit no_ebreak = 1; // No ebreak instruction
|
||||
bit no_dret = 1; // No dret instruction
|
||||
bit no_fence; // No fence instruction
|
||||
bit no_wfi = 1; // No WFI instruction
|
||||
bit enable_unaligned_load_store;
|
||||
bit enable_illegal_instruction;
|
||||
bit enable_hint_instruction;
|
||||
int bin_program_instr_cnt = 200;
|
||||
int illegal_instr_ratio;
|
||||
int hint_instr_ratio;
|
||||
// Directed boot privileged mode, u, m, s
|
||||
string boot_mode_opts;
|
||||
int enable_page_table_exception;
|
||||
|
@ -106,6 +139,10 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
string asm_test_suffix;
|
||||
// Enable interrupt bit in MSTATUS (MIE, SIE, UIE)
|
||||
int enable_interrupt;
|
||||
// Generate a bare program without any init/exit/error handling/page table routines
|
||||
// The generated program can be integrated with a larger program.
|
||||
// Note that the bare mode program is not expected to run in standalone mode
|
||||
bit bare_program_mode;
|
||||
// Enable accessing illegal CSR instruction
|
||||
// - Accessing non-existence CSR
|
||||
// - Accessing CSR with wrong privileged mode
|
||||
|
@ -123,16 +160,24 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
bit require_signature_addr = 1'b0;
|
||||
rand riscv_reg_t signature_addr_reg;
|
||||
rand riscv_reg_t signature_data_reg;
|
||||
bit gen_debug_section = 1'b0;
|
||||
// Register that will be used to handle any DCSR operations inside of the
|
||||
// debug rom
|
||||
rand riscv_reg_t scratch_reg;
|
||||
// Enable a full or empty debug_rom section.
|
||||
// Full debug_rom will contain random instruction streams.
|
||||
// Empty debug_rom will contain just dret instruction and will return immediately.
|
||||
// Will be empty by default.
|
||||
bit empty_debug_section = 1'b0;
|
||||
bit gen_debug_section = 1'b0;
|
||||
// Enable generation of a directed sequence of instructions containing
|
||||
// ebreak inside the debug_rom.
|
||||
// Disabled by default.
|
||||
bit enable_ebreak_in_debug_rom = 1'b0;
|
||||
// Enable setting dcsr.ebreak(m/s/u)
|
||||
bit set_dcsr_ebreak = 1'b0;
|
||||
// Number of sub programs in the debug rom
|
||||
int num_debug_sub_program = 0;
|
||||
// Stack space allocated to each program, need to be enough to store necessary context
|
||||
// Example: RA, SP, T0, loop registers
|
||||
// Example: RA, SP, T0
|
||||
int min_stack_len_per_program = 10 * (XLEN/8);
|
||||
int max_stack_len_per_program = 16 * (XLEN/8);
|
||||
// Maximum branch distance, avoid skipping large portion of the code
|
||||
|
@ -142,9 +187,6 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
// Reserved registers
|
||||
// Default reserved registers, only used by special instructions
|
||||
riscv_reg_t default_reserved_regs[];
|
||||
// Reserve some registers for loop counter, make sure the loop can execute
|
||||
// in a determinstic way and not affected by other random instructions
|
||||
rand riscv_reg_t loop_regs[];
|
||||
// All reserved regs
|
||||
riscv_reg_t reserved_regs[];
|
||||
|
||||
|
@ -250,23 +292,24 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
}
|
||||
}
|
||||
|
||||
constraint reserved_reg_c {
|
||||
unique {loop_regs};
|
||||
foreach(loop_regs[i]) {
|
||||
!(loop_regs[i] inside {default_reserved_regs});
|
||||
constraint reserve_scratch_reg_c {
|
||||
scratch_reg != ZERO;
|
||||
foreach (default_reserved_regs[i]) {
|
||||
signature_data_reg != default_reserved_regs[i];
|
||||
signature_addr_reg != default_reserved_regs[i];
|
||||
}
|
||||
!(signature_addr_reg inside {ZERO, default_reserved_regs, loop_regs});
|
||||
!(signature_data_reg inside {ZERO, default_reserved_regs, loop_regs});
|
||||
signature_addr_reg != signature_data_reg;
|
||||
}
|
||||
|
||||
constraint legal_loop_regs_c {
|
||||
soft max_nested_loop != 0;
|
||||
// One register for loop counter, one for loop limit
|
||||
loop_regs.size() == max_nested_loop*2;
|
||||
unique {loop_regs};
|
||||
foreach(loop_regs[i]) {
|
||||
loop_regs[i] != ZERO;
|
||||
constraint signature_addr_c {
|
||||
if (require_signature_addr) {
|
||||
foreach (default_reserved_regs[i]) {
|
||||
signature_addr_reg != default_reserved_regs[i];
|
||||
signature_data_reg != default_reserved_regs[i];
|
||||
}
|
||||
signature_data_reg != scratch_reg;
|
||||
signature_addr_reg != scratch_reg;
|
||||
signature_data_reg != ZERO;
|
||||
signature_addr_reg != ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,6 +330,7 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
get_int_arg_value("+num_of_sub_program=", num_of_sub_program);
|
||||
get_int_arg_value("+instr_cnt=", instr_cnt);
|
||||
get_bool_arg_value("+no_ebreak=", no_ebreak);
|
||||
get_bool_arg_value("+no_dret=", no_dret);
|
||||
get_bool_arg_value("+no_wfi=", no_wfi);
|
||||
get_bool_arg_value("+no_branch_jump=", no_branch_jump);
|
||||
get_bool_arg_value("+no_load_store=", no_load_store);
|
||||
|
@ -297,9 +341,9 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
get_bool_arg_value("+no_directed_instr=", no_directed_instr);
|
||||
get_bool_arg_value("+no_fence=", no_fence);
|
||||
get_bool_arg_value("+no_delegation=", no_delegation);
|
||||
get_int_arg_value("+illegal_instr_ratio=", illegal_instr_ratio);
|
||||
get_int_arg_value("+hint_instr_ratio=", hint_instr_ratio);
|
||||
get_bool_arg_value("+enable_unaligned_load_store=", enable_unaligned_load_store);
|
||||
get_bool_arg_value("+enable_illegal_instruction=", enable_illegal_instruction);
|
||||
get_bool_arg_value("+enable_hint_instruction=", enable_hint_instruction);
|
||||
get_bool_arg_value("+force_m_delegation=", force_m_delegation);
|
||||
get_bool_arg_value("+force_s_delegation=", force_s_delegation);
|
||||
get_bool_arg_value("+require_signature_addr=", require_signature_addr);
|
||||
|
@ -307,7 +351,10 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
get_hex_arg_value("+signature_addr=", signature_addr);
|
||||
end
|
||||
get_bool_arg_value("+gen_debug_section=", gen_debug_section);
|
||||
get_bool_arg_value("+bare_program_mode=", bare_program_mode);
|
||||
get_int_arg_value("+num_debug_sub_program=", num_debug_sub_program);
|
||||
get_bool_arg_value("+enable_ebreak_in_debug_rom=", enable_ebreak_in_debug_rom);
|
||||
get_bool_arg_value("+set_dcsr_ebreak=", set_dcsr_ebreak);
|
||||
if(inst.get_arg_value("+boot_mode=", boot_mode_opts)) begin
|
||||
`uvm_info(get_full_name(), $sformatf(
|
||||
"Got boot mode option - %0s", boot_mode_opts), UVM_LOW)
|
||||
|
@ -367,10 +414,8 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
// Reserve below registers for special purpose instruction
|
||||
// The other normal instruction cannot use them as destination register
|
||||
virtual function void setup_default_reserved_regs();
|
||||
default_reserved_regs = {RA, // x1, return address
|
||||
SP, // x2, stack pointer (user stack)
|
||||
TP, // x4, thread pointer, used as kernel stack pointer
|
||||
T0 // x5, alternative link pointer
|
||||
default_reserved_regs = {SP, // x2, stack pointer (user stack)
|
||||
TP // x4, thread pointer, used as kernel stack pointer
|
||||
};
|
||||
endfunction
|
||||
|
||||
|
@ -383,11 +428,14 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
|
||||
function void post_randomize();
|
||||
// Setup the list all reserved registers
|
||||
reserved_regs = {default_reserved_regs, loop_regs};
|
||||
reserved_regs = {default_reserved_regs, scratch_reg};
|
||||
// Need to save all loop registers, and RA/T0
|
||||
min_stack_len_per_program = (max_nested_loop * 2 + 2) * (XLEN/8);
|
||||
min_stack_len_per_program = 2 * (XLEN/8);
|
||||
// Check if the setting is legal
|
||||
check_setting();
|
||||
if ((init_privileged_mode != MACHINE_MODE) && (SATP_MODE != BARE)) begin
|
||||
virtual_addr_translation_on = 1'b1;
|
||||
end
|
||||
endfunction
|
||||
|
||||
function void check_setting();
|
||||
|
@ -465,6 +513,15 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
while (instr_name != instr_name.first);
|
||||
if (no_ebreak == 0) begin
|
||||
basic_instr = {basic_instr, EBREAK};
|
||||
foreach(riscv_instr_pkg::supported_isa[i]) begin
|
||||
if (riscv_instr_pkg::supported_isa[i] inside {RV32C, RV64C, RV128C, RV32DC, RV32FC}) begin
|
||||
basic_instr = {basic_instr, C_EBREAK};
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
if (no_dret == 0) begin
|
||||
basic_instr = {basic_instr, DRET};
|
||||
end
|
||||
if (no_fence == 0) begin
|
||||
basic_instr = {basic_instr, instr_category[SYNCH]};
|
||||
|
|
32
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
32
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
|
@ -14,17 +14,24 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
`include "dv_defines.svh"
|
||||
|
||||
package riscv_instr_pkg;
|
||||
|
||||
import uvm_pkg::*;
|
||||
import riscv_signature_pkg::*;
|
||||
|
||||
`include "uvm_macros.svh"
|
||||
`include "dv_defines.svh"
|
||||
`include "riscv_defines.svh"
|
||||
|
||||
`define include_file(f) `include `"f`"
|
||||
|
||||
// Data section setting
|
||||
typedef struct {
|
||||
string name;
|
||||
int unsigned size_in_bytes;
|
||||
bit [2:0] xwr; // Excutable,Writable,Readale
|
||||
} mem_region_t;
|
||||
|
||||
typedef enum bit [3:0] {
|
||||
BARE = 4'b0000,
|
||||
SV32 = 4'b0001,
|
||||
|
@ -261,6 +268,7 @@ package riscv_instr_pkg;
|
|||
AMOMINU_D,
|
||||
AMOMAXU_D,
|
||||
// Supervisor instruction
|
||||
DRET,
|
||||
MRET,
|
||||
URET,
|
||||
SRET,
|
||||
|
@ -570,7 +578,8 @@ package riscv_instr_pkg;
|
|||
TDATA3 = 'h7A3, // Third Debug/Trace trigger data register
|
||||
DCSR = 'h7B0, // Debug control and status register
|
||||
DPC = 'h7B1, // Debug PC
|
||||
DSCRATCH = 'h7B2 // Debug scratch register
|
||||
DSCRATCH0 = 'h7B2, // Debug scratch register
|
||||
DSCRATCH1 = 'h7B3 // Debug scratch register
|
||||
} privileged_reg_t;
|
||||
|
||||
typedef enum bit [5:0] {
|
||||
|
@ -589,7 +598,6 @@ package riscv_instr_pkg;
|
|||
} privileged_level_t;
|
||||
|
||||
typedef enum bit [1:0] {
|
||||
WIRI, // Reserved Writes Ignored, Reads Ignore Value
|
||||
WPRI, // Reserved Writes Preserve Values, Reads Ignore Value
|
||||
WLRL, // Write/Read Only Legal Values
|
||||
WARL // Write Any Values, Reads Legal Values
|
||||
|
@ -772,10 +780,10 @@ package riscv_instr_pkg;
|
|||
instr.push_back($sformatf("srli sp, sp, %0d", XLEN - MAX_USED_VADDR_BITS));
|
||||
end
|
||||
end
|
||||
// Reserve space from kernel stack to save all 32 GPR
|
||||
instr.push_back($sformatf("1: addi sp, sp, -%0d", 32 * (XLEN/8)));
|
||||
// Reserve space from kernel stack to save all 32 GPR except for x0
|
||||
instr.push_back($sformatf("1: addi sp, sp, -%0d", 31 * (XLEN/8)));
|
||||
// Push all GPRs to kernel stack
|
||||
for(int i = 0; i < 32; i++) begin
|
||||
for(int i = 1; i < 32; i++) begin
|
||||
instr.push_back($sformatf("%0s x%0d, %0d(sp)", store_instr, i, i * (XLEN/8)));
|
||||
end
|
||||
endfunction
|
||||
|
@ -787,11 +795,11 @@ package riscv_instr_pkg;
|
|||
ref string instr[$]);
|
||||
string load_instr = (XLEN == 32) ? "lw" : "ld";
|
||||
// Pop user mode GPRs from kernel stack
|
||||
for(int i = 0; i < 32; i++) begin
|
||||
for(int i = 1; i < 32; i++) begin
|
||||
instr.push_back($sformatf("%0s x%0d, %0d(sp)", load_instr, i, i * (XLEN/8)));
|
||||
end
|
||||
// Restore kernel stack pointer
|
||||
instr.push_back($sformatf("addi sp, sp, %0d", 32 * (XLEN/8)));
|
||||
instr.push_back($sformatf("addi sp, sp, %0d", 31 * (XLEN/8)));
|
||||
if (scratch inside {implemented_csr}) begin
|
||||
// Move SP to TP
|
||||
instr.push_back("add tp, sp, zero");
|
||||
|
@ -800,6 +808,12 @@ package riscv_instr_pkg;
|
|||
end
|
||||
endfunction
|
||||
|
||||
riscv_reg_t all_gpr[] = {ZERO, RA, SP, GP, TP, T0, T1, T2, S0, S1, A0,
|
||||
A1, A2, A3, A4, A5, A6, A7, S2, S3, S4, S5, S6,
|
||||
S7, S8, S9, S10, S11, T3, T4, T5, T6};
|
||||
|
||||
riscv_reg_t compressed_gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5};
|
||||
|
||||
`include "riscv_instr_base.sv"
|
||||
`include "riscv_instr_gen_config.sv"
|
||||
`include "riscv_illegal_instr.sv"
|
||||
|
|
|
@ -78,7 +78,8 @@ class riscv_instr_sequence extends uvm_sequence;
|
|||
instr_stream.instr_list.size()), UVM_LOW)
|
||||
// Do not generate load/store instruction here
|
||||
// The load/store instruction will be inserted as directed instruction stream
|
||||
instr_stream.gen_instr(.no_branch(no_branch), .no_load_store(1'b1));
|
||||
instr_stream.gen_instr(.no_branch(no_branch), .no_load_store(1'b1),
|
||||
.is_debug_program(is_debug_program));
|
||||
if(!is_main_program) begin
|
||||
gen_stack_enter_instr();
|
||||
gen_stack_exit_instr();
|
||||
|
@ -132,6 +133,8 @@ class riscv_instr_sequence extends uvm_sequence;
|
|||
virtual function void post_process_instr();
|
||||
int i;
|
||||
int label_idx;
|
||||
int branch_cnt;
|
||||
int unsigned branch_idx[];
|
||||
int branch_target[string] = '{default: 0};
|
||||
// Insert directed instructions, it's randomly mixed with the random instruction stream.
|
||||
foreach (directed_instr[i]) begin
|
||||
|
@ -169,6 +172,11 @@ class riscv_instr_sequence extends uvm_sequence;
|
|||
end
|
||||
end
|
||||
// Generate branch target
|
||||
branch_idx = new[30];
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(branch_idx,
|
||||
foreach(branch_idx[i]) {
|
||||
branch_idx[i] inside {[1:cfg.max_branch_step]};
|
||||
})
|
||||
while(i < instr_stream.instr_list.size()) begin
|
||||
if((instr_stream.instr_list[i].category == BRANCH) &&
|
||||
(!instr_stream.instr_list[i].branch_assigned) &&
|
||||
|
@ -179,11 +187,15 @@ class riscv_instr_sequence extends uvm_sequence;
|
|||
// reserved loop registers
|
||||
int branch_target_label;
|
||||
int branch_byte_offset;
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(branch_target_label,
|
||||
branch_target_label >= instr_stream.instr_list[i].idx+1;
|
||||
branch_target_label <= label_idx-1;
|
||||
branch_target_label <= instr_stream.instr_list[i].idx+cfg.max_branch_step;,
|
||||
"Cannot randomize branch_target_label")
|
||||
branch_target_label = instr_stream.instr_list[i].idx + branch_idx[branch_cnt];
|
||||
if (branch_target_label >= label_idx) begin
|
||||
branch_target_label = label_idx-1;
|
||||
end
|
||||
branch_cnt++;
|
||||
if (branch_cnt == branch_idx.size()) begin
|
||||
branch_cnt = 0;
|
||||
branch_idx.shuffle();
|
||||
end
|
||||
`uvm_info(get_full_name(),
|
||||
$sformatf("Processing branch instruction[%0d]:%0s # %0d -> %0d",
|
||||
i, instr_stream.instr_list[i].convert2asm(),
|
||||
|
@ -266,6 +278,7 @@ class riscv_instr_sequence extends uvm_sequence;
|
|||
str = {prefix, instr_stream.instr_list[i].convert2asm()};
|
||||
instr_string_list.push_back(str);
|
||||
end
|
||||
insert_illegal_hint_instr();
|
||||
prefix = format_string($sformatf("%0d:", i), LABEL_STR_LEN);
|
||||
if(!is_main_program) begin
|
||||
str = {prefix, "ret"};
|
||||
|
@ -273,53 +286,36 @@ class riscv_instr_sequence extends uvm_sequence;
|
|||
end
|
||||
endfunction
|
||||
|
||||
// Convert the instruction stream to binary format
|
||||
function void generate_binary_stream(ref string binary[$]);
|
||||
string instr_bin;
|
||||
string remaining_bin;
|
||||
function void insert_illegal_hint_instr();
|
||||
int bin_instr_cnt;
|
||||
int idx;
|
||||
string str;
|
||||
illegal_instr.cfg = cfg;
|
||||
foreach (instr_stream.instr_list[i]) begin
|
||||
if (instr_stream.instr_list[i].is_illegal_instr) begin
|
||||
// Replace the original instruction with illegal instruction binary
|
||||
illegal_instr.init(cfg);
|
||||
bin_instr_cnt = instr_cnt * cfg.illegal_instr_ratio / 1000;
|
||||
if (bin_instr_cnt >= 0) begin
|
||||
`uvm_info(`gfn, $sformatf("Injecting %0d illegal instructions, ratio %0d/100",
|
||||
bin_instr_cnt, cfg.illegal_instr_ratio), UVM_LOW)
|
||||
repeat (bin_instr_cnt) begin
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(illegal_instr,
|
||||
exception != kHintInstr;
|
||||
compressed == instr_stream.instr_list[i].is_compressed;)
|
||||
str = illegal_instr.get_bin_str();
|
||||
`uvm_info(`gfn, $sformatf("Inject %0s [%0d] %0s replaced with %0s",
|
||||
illegal_instr.exception.name(), i,
|
||||
instr_stream.instr_list[i].convert2bin() ,str), UVM_HIGH)
|
||||
end else if (instr_stream.instr_list[i].is_hint_instr) begin
|
||||
// Replace the original instruction with HINT instruction binary
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(illegal_instr,
|
||||
exception == kHintInstr;
|
||||
compressed == instr_stream.instr_list[i].is_compressed;)
|
||||
str = illegal_instr.get_bin_str();
|
||||
`uvm_info(`gfn, $sformatf("Inject %0s [%0d] %0s replaced with %0s",
|
||||
illegal_instr.exception.name(), i,
|
||||
instr_stream.instr_list[i].convert2bin() ,str), UVM_HIGH)
|
||||
end else begin
|
||||
str = instr_stream.instr_list[i].convert2bin();
|
||||
exception != kHintInstr;)
|
||||
str = {indent, $sformatf(".4byte 0x%s # %0s",
|
||||
illegal_instr.get_bin_str(), illegal_instr.exception.name())};
|
||||
idx = $urandom_range(0, instr_string_list.size());
|
||||
instr_string_list.insert(idx, str);
|
||||
end
|
||||
instr_bin = {str, remaining_bin};
|
||||
// Handle various instruction alignment
|
||||
if (instr_bin.len() == 8) begin
|
||||
binary.push_back({"0x", instr_bin});
|
||||
remaining_bin = "";
|
||||
end else if (instr_bin.len() == 12) begin
|
||||
binary.push_back({"0x", instr_bin.substr(4, 11)});
|
||||
remaining_bin = instr_bin.substr(0, 3);
|
||||
end else if (instr_bin.len() == 4) begin
|
||||
remaining_bin = instr_bin;
|
||||
end else begin
|
||||
`uvm_fatal(`gfn, $sformatf("Unexpected binary length :%0d", instr_bin.len()))
|
||||
end
|
||||
`uvm_info("BIN", $sformatf("%0s : %0s", instr_stream.instr_list[i].convert2bin(),
|
||||
instr_stream.instr_list[i].convert2asm()), UVM_HIGH)
|
||||
end
|
||||
// Attach a C_NOP(0x0001) to make the last entry 32b
|
||||
if (remaining_bin != "") begin
|
||||
binary.push_back({"0x0001", remaining_bin});
|
||||
bin_instr_cnt = instr_cnt * cfg.hint_instr_ratio / 1000;
|
||||
if (bin_instr_cnt >= 0) begin
|
||||
`uvm_info(`gfn, $sformatf("Injecting %0d HINT instructions, ratio %0d/100",
|
||||
bin_instr_cnt, cfg.illegal_instr_ratio), UVM_LOW)
|
||||
repeat (bin_instr_cnt) begin
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(illegal_instr,
|
||||
exception == kHintInstr;)
|
||||
str = {indent, $sformatf(".2byte 0x%s # %0s",
|
||||
illegal_instr.get_bin_str(), illegal_instr.exception.name())};
|
||||
idx = $urandom_range(0, instr_string_list.size());
|
||||
instr_string_list.insert(idx, str);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
|
57
vendor/google_riscv-dv/src/riscv_instr_stream.sv
vendored
57
vendor/google_riscv-dv/src/riscv_instr_stream.sv
vendored
|
@ -25,6 +25,9 @@ class riscv_instr_stream extends uvm_object;
|
|||
string label = "";
|
||||
// User can specify a small group of available registers to generate various hazard condition
|
||||
rand riscv_reg_t avail_regs[];
|
||||
// Some additional reserved registers that should not be used as rd register
|
||||
// by this instruction stream
|
||||
riscv_reg_t reserved_rd[];
|
||||
|
||||
`uvm_object_utils(riscv_instr_stream)
|
||||
`uvm_object_new
|
||||
|
@ -95,9 +98,17 @@ class riscv_instr_stream extends uvm_object;
|
|||
if(replace) begin
|
||||
new_instr[0].label = instr_list[idx].label;
|
||||
new_instr[0].has_label = instr_list[idx].has_label;
|
||||
instr_list = {instr_list[0:idx-1], new_instr, instr_list[idx+1:current_instr_cnt-1]};
|
||||
if (idx == 0) begin
|
||||
instr_list = {new_instr, instr_list[idx+1:current_instr_cnt-1]};
|
||||
end else begin
|
||||
instr_list = {instr_list[0:idx-1], new_instr, instr_list[idx+1:current_instr_cnt-1]};
|
||||
end
|
||||
end else begin
|
||||
instr_list = {instr_list[0:idx-1], new_instr, instr_list[idx:current_instr_cnt-1]};
|
||||
if (idx == 0) begin
|
||||
instr_list = {new_instr, instr_list[idx:current_instr_cnt-1]};
|
||||
end else begin
|
||||
instr_list = {instr_list[0:idx-1], new_instr, instr_list[idx:current_instr_cnt-1]};
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
@ -112,10 +123,10 @@ class riscv_instr_stream extends uvm_object;
|
|||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(insert_instr_position,
|
||||
foreach(insert_instr_position[i]) {
|
||||
insert_instr_position[i] inside {[0:current_instr_cnt-1]};
|
||||
if(i > 0) {
|
||||
insert_instr_position[i] >= insert_instr_position[i-1];
|
||||
}
|
||||
})
|
||||
if (insert_instr_position.size() > 0) begin
|
||||
insert_instr_position.sort();
|
||||
end
|
||||
if(contained) begin
|
||||
insert_instr_position[0] = 0;
|
||||
if(new_instr_cnt > 1)
|
||||
|
@ -144,15 +155,9 @@ endclass
|
|||
class riscv_rand_instr_stream extends riscv_instr_stream;
|
||||
|
||||
riscv_instr_gen_config cfg;
|
||||
bit access_u_mode_mem = 1'b1;
|
||||
int max_load_store_offset;
|
||||
int max_data_page_id;
|
||||
bit kernel_mode;
|
||||
riscv_instr_name_t allowed_instr[$];
|
||||
|
||||
// Some additional reserved registers that should not be used as rd register
|
||||
// by this instruction stream
|
||||
riscv_reg_t reserved_rd[];
|
||||
|
||||
constraint avoid_reserved_rd_c {
|
||||
if(reserved_rd.size() > 0) {
|
||||
foreach(instr_list[i]) {
|
||||
|
@ -172,17 +177,7 @@ class riscv_rand_instr_stream extends riscv_instr_stream;
|
|||
end
|
||||
endfunction
|
||||
|
||||
function void pre_randomize();
|
||||
if(access_u_mode_mem) begin
|
||||
max_load_store_offset = riscv_instr_pkg::data_page_size;
|
||||
max_data_page_id = riscv_instr_pkg::num_of_data_pages;
|
||||
end else begin
|
||||
max_load_store_offset = riscv_instr_pkg::kernel_data_page_size;
|
||||
max_data_page_id = riscv_instr_pkg::num_of_kernel_data_pages;
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function setup_allowed_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1);
|
||||
virtual function void setup_allowed_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1);
|
||||
allowed_instr = cfg.basic_instr;
|
||||
if (no_branch == 0) begin
|
||||
allowed_instr = {allowed_instr, cfg.instr_category[BRANCH]};
|
||||
|
@ -192,10 +187,11 @@ class riscv_rand_instr_stream extends riscv_instr_stream;
|
|||
end
|
||||
endfunction
|
||||
|
||||
virtual function void gen_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1);
|
||||
virtual function void gen_instr(bit no_branch = 1'b0, bit no_load_store = 1'b1,
|
||||
bit is_debug_program = 1'b0);
|
||||
setup_allowed_instr(no_branch, no_load_store);
|
||||
foreach(instr_list[i]) begin
|
||||
randomize_instr(instr_list[i]);
|
||||
randomize_instr(instr_list[i], is_debug_program);
|
||||
end
|
||||
// Do not allow branch instruction as the last instruction because there's no
|
||||
// forward branch target
|
||||
|
@ -206,14 +202,23 @@ class riscv_rand_instr_stream extends riscv_instr_stream;
|
|||
endfunction
|
||||
|
||||
function void randomize_instr(riscv_instr_base instr,
|
||||
bit is_in_debug = 1'b0,
|
||||
bit skip_rs1 = 1'b0,
|
||||
bit skip_rs2 = 1'b0,
|
||||
bit skip_rd = 1'b0,
|
||||
bit skip_imm = 1'b0,
|
||||
bit skip_csr = 1'b0);
|
||||
riscv_instr_name_t instr_name;
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(instr_name,
|
||||
// if set_dcsr_ebreak is set, we do not want to generate any ebreak
|
||||
// instructions inside the debug_rom
|
||||
if (!cfg.enable_ebreak_in_debug_rom && is_in_debug) begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(instr_name,
|
||||
instr_name inside {allowed_instr};
|
||||
!(instr_name inside {EBREAK, C_EBREAK});)
|
||||
end else begin
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(instr_name,
|
||||
instr_name inside {allowed_instr};)
|
||||
end
|
||||
instr.copy_base_instr(cfg.instr_template[instr_name]);
|
||||
`uvm_info(`gfn, $sformatf("%s: rs1:%0d, rs2:%0d, rd:%0d, imm:%0d",
|
||||
instr.instr_name.name(),
|
||||
|
|
|
@ -16,7 +16,14 @@
|
|||
|
||||
// Base class for all load/store instruction stream
|
||||
|
||||
class riscv_load_store_base_instr_stream extends riscv_directed_instr_stream;
|
||||
class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
|
||||
|
||||
typedef enum bit [1:0] {
|
||||
NARROW,
|
||||
HIGH,
|
||||
MEDIUM,
|
||||
SPARSE
|
||||
} locality_e;
|
||||
|
||||
rand int unsigned num_load_store;
|
||||
rand int unsigned num_mixed_instr;
|
||||
|
@ -25,6 +32,8 @@ class riscv_load_store_base_instr_stream extends riscv_directed_instr_stream;
|
|||
rand int addr[];
|
||||
rand int unsigned data_page_id;
|
||||
rand riscv_reg_t rs1_reg;
|
||||
rand locality_e locality;
|
||||
rand int max_load_store_offset;
|
||||
|
||||
`uvm_object_utils(riscv_load_store_base_instr_stream)
|
||||
|
||||
|
@ -38,13 +47,35 @@ class riscv_load_store_base_instr_stream extends riscv_directed_instr_stream;
|
|||
}
|
||||
|
||||
constraint addr_c {
|
||||
solve data_page_id before max_load_store_offset;
|
||||
solve max_load_store_offset before base;
|
||||
solve max_load_store_offset before addr;
|
||||
solve max_load_store_offset before offset;
|
||||
data_page_id < max_data_page_id;
|
||||
foreach (data_page[i]) {
|
||||
if (i == data_page_id) {
|
||||
max_load_store_offset == data_page[i].size_in_bytes;
|
||||
}
|
||||
}
|
||||
base inside {[0 : max_load_store_offset-1]};
|
||||
foreach(offset[i]) {
|
||||
addr[i] == base + offset[i];
|
||||
// Make sure address is still valid
|
||||
addr[i] inside {[0 : max_load_store_offset - 1]};
|
||||
offset[i] inside {[-2048:2047]};
|
||||
}
|
||||
}
|
||||
|
||||
constraint offset_locality_c {
|
||||
solve locality before offset;
|
||||
foreach(offset[i]) {
|
||||
if (locality == NARROW) {
|
||||
soft offset[i] inside {[-16:16]};
|
||||
} else if (locality == HIGH) {
|
||||
soft offset[i] inside {[-64:64]};
|
||||
} else if (locality == MEDIUM) {
|
||||
soft offset[i] inside {[-256:256]};
|
||||
} else if (locality == SPARSE) {
|
||||
soft offset[i] inside {[-2048:2047]};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,10 +103,10 @@ class riscv_load_store_base_instr_stream extends riscv_directed_instr_stream;
|
|||
pseudo_instr_name == LA;
|
||||
rd == rs1_reg;,
|
||||
"Cannot randomize la_instr")
|
||||
if(access_u_mode_mem) begin
|
||||
la_instr.imm_str = $sformatf("data_page_%0d+%0d", data_page_id, base);
|
||||
if(kernel_mode) begin
|
||||
la_instr.imm_str = $sformatf("%s+%0d", cfg.s_mem_region[data_page_id].name, base);
|
||||
end else begin
|
||||
la_instr.imm_str = $sformatf("kernel_data_page_%0d+%0d", data_page_id, base);
|
||||
la_instr.imm_str = $sformatf("%s+%0d", cfg.mem_region[data_page_id].name, base);
|
||||
end
|
||||
instr_list.push_front(la_instr);
|
||||
endfunction
|
||||
|
@ -253,27 +284,11 @@ class riscv_load_store_hazard_instr_stream extends riscv_load_store_base_instr_s
|
|||
addr[i] = temp_addr;
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Back-to-back access to the same cache line
|
||||
class riscv_cache_line_stress_instr_stream extends riscv_load_store_stress_instr_stream;
|
||||
|
||||
constraint same_cache_line_c {
|
||||
base % riscv_instr_pkg::dcache_line_size_in_bytes == 0;
|
||||
foreach(offset[i]) {
|
||||
offset[i] inside {[0 : riscv_instr_pkg::dcache_line_size_in_bytes-1]};
|
||||
}
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_cache_line_stress_instr_stream)
|
||||
`uvm_object_new
|
||||
|
||||
endclass
|
||||
|
||||
// Back to back access to multiple data pages
|
||||
// This is useful to test data TLB switch and replacement
|
||||
class riscv_multi_page_load_store_instr_stream extends riscv_directed_instr_stream;
|
||||
class riscv_multi_page_load_store_instr_stream extends riscv_mem_access_stream;
|
||||
|
||||
riscv_load_store_stress_instr_stream load_store_instr_stream[];
|
||||
rand int unsigned num_of_instr_stream;
|
||||
|
@ -287,13 +302,17 @@ class riscv_multi_page_load_store_instr_stream extends riscv_directed_instr_stre
|
|||
data_page_id.size() == num_of_instr_stream;
|
||||
rs1_reg.size() == num_of_instr_stream;
|
||||
unique {rs1_reg};
|
||||
unique {data_page_id};
|
||||
num_of_instr_stream inside {[1 : max_data_page_id]};
|
||||
foreach(rs1_reg[i]) {
|
||||
!(rs1_reg[i] inside {cfg.reserved_regs, ZERO});
|
||||
}
|
||||
}
|
||||
|
||||
constraint page_c {
|
||||
solve num_of_instr_stream before data_page_id;
|
||||
num_of_instr_stream inside {[1 : max_data_page_id]};
|
||||
unique {data_page_id};
|
||||
}
|
||||
|
||||
// Avoid accessing a large number of pages because we may run out of registers for rs1
|
||||
// Each page access needs a reserved register as the base address of load/store instruction
|
||||
constraint reasonable_c {
|
||||
|
@ -334,3 +353,20 @@ class riscv_multi_page_load_store_instr_stream extends riscv_directed_instr_stre
|
|||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// Access the different locations of the same memory regions
|
||||
class riscv_mem_region_stress_test extends riscv_multi_page_load_store_instr_stream;
|
||||
|
||||
`uvm_object_utils(riscv_mem_region_stress_test)
|
||||
`uvm_object_new
|
||||
|
||||
constraint page_c {
|
||||
num_of_instr_stream inside {[2:5]};
|
||||
foreach (data_page_id[i]) {
|
||||
if (i > 0) {
|
||||
data_page_id[i] == data_page_id[i-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endclass
|
||||
|
|
31
vendor/google_riscv-dv/src/riscv_loop_instr.sv
vendored
31
vendor/google_riscv-dv/src/riscv_loop_instr.sv
vendored
|
@ -25,8 +25,8 @@ class riscv_loop_instr extends riscv_rand_instr_stream;
|
|||
rand int loop_step_val[];
|
||||
rand int loop_limit_val[];
|
||||
rand bit [2:0] num_of_nested_loop;
|
||||
rand riscv_instr_name_t branch_type[];
|
||||
rand int num_of_instr_in_loop;
|
||||
rand riscv_instr_name_t branch_type[];
|
||||
riscv_instr_base loop_init_instr[];
|
||||
riscv_instr_base loop_update_instr[];
|
||||
riscv_instr_base loop_branch_instr[];
|
||||
|
@ -34,23 +34,37 @@ class riscv_loop_instr extends riscv_rand_instr_stream;
|
|||
// Aggregated loop instruction stream
|
||||
riscv_instr_base loop_instr[];
|
||||
|
||||
constraint loop_c {
|
||||
constraint legal_loop_regs_c {
|
||||
solve num_of_nested_loop before loop_cnt_reg;
|
||||
solve num_of_nested_loop before loop_limit_reg;
|
||||
foreach (loop_cnt_reg[i]) {
|
||||
loop_cnt_reg[i] != ZERO;
|
||||
foreach (cfg.default_reserved_regs[j]) {
|
||||
loop_cnt_reg[i] != cfg.default_reserved_regs[j];
|
||||
}
|
||||
}
|
||||
foreach (loop_limit_reg[i]) {
|
||||
loop_limit_reg[i] != ZERO;
|
||||
foreach (cfg.default_reserved_regs[j]) {
|
||||
loop_limit_reg[i] != cfg.default_reserved_regs[j];
|
||||
}
|
||||
}
|
||||
unique {loop_cnt_reg, loop_limit_reg};
|
||||
loop_cnt_reg.size() == num_of_nested_loop;
|
||||
loop_limit_reg.size() == num_of_nested_loop;
|
||||
}
|
||||
|
||||
constraint loop_c {
|
||||
solve num_of_nested_loop before loop_init_val;
|
||||
solve num_of_nested_loop before loop_step_val;
|
||||
solve num_of_nested_loop before loop_limit_val;
|
||||
num_of_instr_in_loop inside {[1:200]};
|
||||
num_of_nested_loop inside {[1:cfg.max_nested_loop]};
|
||||
loop_cnt_reg.size() == num_of_nested_loop;
|
||||
loop_limit_reg.size() == num_of_nested_loop;
|
||||
num_of_nested_loop inside {[1:2]};
|
||||
loop_init_val.size() == num_of_nested_loop;
|
||||
loop_step_val.size() == num_of_nested_loop;
|
||||
loop_limit_val.size() == num_of_nested_loop;
|
||||
branch_type.size() == num_of_nested_loop;
|
||||
foreach(loop_init_val[i]) {
|
||||
loop_cnt_reg[i] inside {cfg.loop_regs};
|
||||
loop_limit_reg[i] inside {cfg.loop_regs};
|
||||
loop_init_val[i] inside {[-10:10]};
|
||||
loop_limit_val[i] inside {[-20:20]};
|
||||
loop_step_val[i] inside {[-10:10]};
|
||||
|
@ -74,13 +88,13 @@ class riscv_loop_instr extends riscv_rand_instr_stream;
|
|||
branch_type[i] inside {BGEU, BNE, BGE, BEQ};
|
||||
}
|
||||
}
|
||||
unique {loop_cnt_reg, loop_limit_reg};
|
||||
}
|
||||
|
||||
`uvm_object_utils(riscv_loop_instr)
|
||||
`uvm_object_new
|
||||
|
||||
function void post_randomize();
|
||||
reserved_rd = {loop_cnt_reg, loop_limit_reg};
|
||||
// Generate instructions that mixed with the loop instructions
|
||||
initialize_instr_list(num_of_instr_in_loop);
|
||||
gen_instr(1'b1);
|
||||
|
@ -113,6 +127,7 @@ class riscv_loop_instr extends riscv_rand_instr_stream;
|
|||
// Branch target instruction, can be anything
|
||||
loop_branch_target_instr[i] = riscv_rand_instr::type_id::create("loop_branch_target_instr");
|
||||
loop_branch_target_instr[i].cfg = cfg;
|
||||
loop_branch_target_instr[i].reserved_rd = reserved_rd;
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(loop_branch_target_instr[i],
|
||||
!(category inside {LOAD, STORE, BRANCH, JUMP});,
|
||||
"Cannot randomize branch target instruction")
|
||||
|
|
|
@ -49,10 +49,9 @@ class riscv_page_table#(satp_mode_t MODE = SV39) extends uvm_object;
|
|||
string str;
|
||||
this.gen_page_table_binary();
|
||||
// Align the page table to 4K boundary
|
||||
str = ".align 12";
|
||||
instr.push_back(str);
|
||||
str = $sformatf("%0s:", get_name());
|
||||
instr.push_back(str);
|
||||
instr = {instr,
|
||||
".align 12",
|
||||
$sformatf("%0s:", get_name())};
|
||||
foreach(pte_binary[i]) begin
|
||||
if (i % 8 == 0) begin
|
||||
if (XLEN == 64) begin
|
||||
|
|
|
@ -353,7 +353,8 @@ class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
|
|||
// Fix kernel leaf PTE
|
||||
instr.push_back("fix_kernel_leaf_pte:");
|
||||
// - Load the starting virtual address of the kernel space
|
||||
instr.push_back($sformatf("la x%0d, _kernel_start", tmp_reg));
|
||||
instr.push_back($sformatf("la x%0d, _kernel_instr_start", tmp_reg));
|
||||
// TODO: Fix kernel instruction/data pages separatedly
|
||||
instr.push_back($sformatf("slli x%0d, x%0d, %0d", tmp_reg, tmp_reg,
|
||||
XLEN - MAX_USED_VADDR_BITS));
|
||||
instr.push_back($sformatf("srli x%0d, x%0d, %0d", tmp_reg, tmp_reg,
|
||||
|
@ -460,14 +461,14 @@ class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
|
|||
end
|
||||
end
|
||||
end
|
||||
// ---------------------------------------
|
||||
// Set the kernel page u bit to 0
|
||||
// ---------------------------------------
|
||||
// Load the start and end address of the kernel space
|
||||
// ---------------------------------------------------------------------------
|
||||
// Set the kernel page u bit to 0 for supervisor mode instruction/data pages
|
||||
// ---------------------------------------------------------------------------
|
||||
if (cfg.support_supervisor_mode) begin
|
||||
instr = {instr,
|
||||
"la x20, _kernel_start",
|
||||
"la x21, _kernel_end",
|
||||
// Process kernel instruction pages
|
||||
"la x20, _kernel_instr_start",
|
||||
"la x21, _kernel_instr_end",
|
||||
// Get the VPN of the physical address
|
||||
$sformatf("slli x20, x20, %0d", XLEN - MAX_USED_VADDR_BITS),
|
||||
$sformatf("srli x20, x20, %0d", XLEN - MAX_USED_VADDR_BITS + 12),
|
||||
|
@ -480,7 +481,7 @@ class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
|
|||
"add x20, x22, x20",
|
||||
"add x21, x22, x21",
|
||||
$sformatf("li x22, 0x%0x", ubit_mask),
|
||||
"process_kernel_pte:",
|
||||
"1:",
|
||||
// Load the PTE from the memory
|
||||
$sformatf("l%0s x23, 0(x20)", load_store_unit),
|
||||
// Unset U bit
|
||||
|
@ -490,7 +491,30 @@ class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
|
|||
// Move to the next PTE
|
||||
$sformatf("addi x20, x20, %0d", XLEN/8),
|
||||
// If not the end of the kernel space, process the next PTE
|
||||
"ble x20, x21, process_kernel_pte"};
|
||||
"ble x20, x21, 1b",
|
||||
// Process kernel data pages
|
||||
"la x20, _kernel_data_start",
|
||||
// Get the VPN of the physical address
|
||||
$sformatf("slli x20, x20, %0d", XLEN - MAX_USED_VADDR_BITS),
|
||||
$sformatf("srli x20, x20, %0d", XLEN - MAX_USED_VADDR_BITS + 12),
|
||||
$sformatf("slli x20, x20, %0d", $clog2(XLEN)),
|
||||
// Starting from the first 4KB leaf page table
|
||||
$sformatf("la x22, page_table_%0d", get_1st_4k_table_id()),
|
||||
"add x20, x22, x20",
|
||||
$sformatf("li x22, 0x%0x", ubit_mask),
|
||||
// Assume 20 PTEs for kernel data pages
|
||||
$sformatf("addi x20, x20, %0d", 20 * XLEN/8),
|
||||
"2:",
|
||||
// Load the PTE from the memory
|
||||
$sformatf("l%0s x23, 0(x20)", load_store_unit),
|
||||
// Unset U bit
|
||||
"and x23, x23, x22",
|
||||
// Save PTE back to memory
|
||||
$sformatf("l%0s x23, 0(x20)", load_store_unit),
|
||||
// Move to the next PTE
|
||||
$sformatf("addi x20, x20, %0d", XLEN/8),
|
||||
// If not the end of the kernel space, process the next PTE
|
||||
"ble x20, x21, 2b"};
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
|
42
vendor/google_riscv-dv/src/riscv_privil_reg.sv
vendored
42
vendor/google_riscv-dv/src/riscv_privil_reg.sv
vendored
|
@ -31,29 +31,29 @@ class riscv_privil_reg extends riscv_reg#(privileged_reg_t);
|
|||
MISA: begin
|
||||
privil_level = M_LEVEL;
|
||||
add_field("WARL0", 26, WARL);
|
||||
add_field("WIRI", XLEN-28, WIRI);
|
||||
add_field("WLRL", XLEN-28, WLRL);
|
||||
add_field("MXL", 2, WARL);
|
||||
end
|
||||
// Machine Vendor ID Register
|
||||
MVENDORID: begin
|
||||
privil_level = M_LEVEL;
|
||||
add_field("OFFSET", 7, WIRI);
|
||||
add_field("BANK", XLEN-7, WIRI);
|
||||
add_field("OFFSET", 7, WPRI);
|
||||
add_field("BANK", XLEN-7, WPRI);
|
||||
end
|
||||
// Machine Architecture ID Register
|
||||
MARCHID: begin
|
||||
privil_level = M_LEVEL;
|
||||
add_field("ARCHITECTURE_ID", XLEN, WIRI);
|
||||
add_field("ARCHITECTURE_ID", XLEN, WPRI);
|
||||
end
|
||||
// Machine Implementation ID Register
|
||||
MIMPID: begin
|
||||
privil_level = M_LEVEL;
|
||||
add_field("IMPLEMENTATION", XLEN, WIRI);
|
||||
add_field("IMPLEMENTATION", XLEN, WPRI);
|
||||
end
|
||||
// Hart ID Register
|
||||
MHARTID: begin
|
||||
privil_level = M_LEVEL;
|
||||
add_field("HART_ID", XLEN, WIRI);
|
||||
add_field("HART_ID", XLEN, WPRI);
|
||||
end
|
||||
// Machine Status Register
|
||||
MSTATUS: begin
|
||||
|
@ -136,7 +136,7 @@ class riscv_privil_reg extends riscv_reg#(privileged_reg_t);
|
|||
privil_level = M_LEVEL;
|
||||
add_field("USIP", 1, WARL);
|
||||
add_field("SSIP", 1, WARL);
|
||||
add_field("WIRI0", 1, WIRI);
|
||||
add_field("WPRI0", 1, WPRI);
|
||||
add_field("MSIP", 1, WARL);
|
||||
add_field("UTIP", 1, WARL);
|
||||
add_field("STIP", 1, WARL);
|
||||
|
@ -144,9 +144,9 @@ class riscv_privil_reg extends riscv_reg#(privileged_reg_t);
|
|||
add_field("MTIP", 1, WARL);
|
||||
add_field("UEIP", 1, WARL);
|
||||
add_field("SEIP", 1, WARL);
|
||||
add_field("WIRI2", 1, WIRI);
|
||||
add_field("WPRI2", 1, WPRI);
|
||||
add_field("MEIP", 1, WARL);
|
||||
add_field("WIRI3", XLEN - 12, WIRI);
|
||||
add_field("WPRI3", XLEN - 12, WPRI);
|
||||
end
|
||||
// Machine interrupt-enable register
|
||||
MIE: begin
|
||||
|
@ -168,27 +168,27 @@ class riscv_privil_reg extends riscv_reg#(privileged_reg_t);
|
|||
// Cycle Count Register
|
||||
MCYCLE: begin
|
||||
privil_level = M_LEVEL;
|
||||
add_field("MCYCLE", 64, WIRI);
|
||||
add_field("MCYCLE", 64, WPRI);
|
||||
end
|
||||
// Instruction Count Register
|
||||
MINSTRET: begin
|
||||
privil_level = M_LEVEL;
|
||||
add_field("MINSTRET", 64, WIRI);
|
||||
add_field("MINSTRET", 64, WPRI);
|
||||
end
|
||||
// Cycle Count Register - RV32I only
|
||||
MCYCLEH: begin
|
||||
privil_level = M_LEVEL;
|
||||
add_field("MCYCLEH", 32, WIRI);
|
||||
add_field("MCYCLEH", 32, WPRI);
|
||||
end
|
||||
// Instruction Count Register - RV32I only
|
||||
MINSTRETH: begin
|
||||
privil_level = M_LEVEL;
|
||||
add_field("MINSTRETH", 32, WIRI);
|
||||
add_field("MINSTRETH", 32, WPRI);
|
||||
end
|
||||
// Hardware Performance Monitor Counters
|
||||
[MHPMCOUNTER3:MHPMCOUNTER31]: begin
|
||||
privil_level = M_LEVEL;
|
||||
add_field($sformatf("%s", reg_name.name()), XLEN, WIRI);
|
||||
add_field($sformatf("%s", reg_name.name()), XLEN, WARL);
|
||||
end
|
||||
// Hardware Performance Monitor Events
|
||||
[MHPMEVENT3:MHPMEVENT31]: begin
|
||||
|
@ -201,7 +201,7 @@ class riscv_privil_reg extends riscv_reg#(privileged_reg_t);
|
|||
`uvm_fatal(get_full_name(), $sformatf("Register %s is only in RV32I", reg_name.name()))
|
||||
end
|
||||
privil_level = M_LEVEL;
|
||||
add_field($sformatf("%s", reg_name.name()), 32, WIRI);
|
||||
add_field($sformatf("%s", reg_name.name()), 32, WARL);
|
||||
end
|
||||
// Machine Counter Enable Register
|
||||
MCOUNTEREN: begin
|
||||
|
@ -324,7 +324,7 @@ class riscv_privil_reg extends riscv_reg#(privileged_reg_t);
|
|||
privil_level = M_LEVEL;
|
||||
if(XLEN==64) begin
|
||||
add_field("ADDRESS", 54, WARL);
|
||||
add_field("WIRI", 10, WIRI);
|
||||
add_field("WARL", 10, WARL);
|
||||
end else begin
|
||||
add_field("ADDRESS", 32, WARL);
|
||||
end
|
||||
|
@ -560,16 +560,6 @@ class riscv_privil_reg extends riscv_reg#(privileged_reg_t);
|
|||
default:
|
||||
`uvm_fatal(get_full_name(), $sformatf("reg %0s is not supported yet", reg_name.name()))
|
||||
endcase
|
||||
set_wiri_wpri_fields();
|
||||
endfunction
|
||||
|
||||
// Hardwire all WIRI and WPRI fields to '0
|
||||
virtual function void set_wiri_wpri_fields();
|
||||
foreach(fld[i]) begin
|
||||
if(fld[i].access_type inside {WIRI, WPRI}) begin
|
||||
set_field(fld[i].get_name(), '0, 1'b1);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
|
|
@ -55,6 +55,9 @@ class riscv_privileged_common_seq extends uvm_sequence;
|
|||
virtual function void setup_mmode_reg(privileged_mode_t mode, ref riscv_privil_reg regs[$]);
|
||||
mstatus = riscv_privil_reg::type_id::create("mstatus");
|
||||
mstatus.init_reg(MSTATUS);
|
||||
`uvm_info(`gfn, $sformatf("mstatus_val: 0x%0x", cfg.mstatus), UVM_LOW)
|
||||
mstatus.set_val({cfg.mstatus[XLEN-1:XLEN-21], cfg.mstatus_tvm, cfg.mstatus_mxr,
|
||||
cfg.mstatus_sum, cfg.mstatus_mprv, cfg.mstatus[16:0]});
|
||||
`DV_CHECK_RANDOMIZE_FATAL(mstatus, "cannot randomize mstatus");
|
||||
if(XLEN==64) begin
|
||||
mstatus.set_field("UXL", 2'b10);
|
||||
|
@ -64,10 +67,6 @@ class riscv_privileged_common_seq extends uvm_sequence;
|
|||
mstatus.set_field("FS", 0);
|
||||
mstatus.set_field("SD", 0);
|
||||
mstatus.set_field("UIE", 0);
|
||||
mstatus.set_field("MPRV", cfg.mstatus_mprv);
|
||||
mstatus.set_field("MXR", cfg.mstatus_mxr);
|
||||
mstatus.set_field("SUM", cfg.mstatus_sum);
|
||||
mstatus.set_field("TVM", cfg.mstatus_tvm);
|
||||
// Set the previous privileged mode as the target mode
|
||||
mstatus.set_field("MPP", mode);
|
||||
if(mode == USER_MODE)
|
||||
|
@ -86,12 +85,19 @@ class riscv_privileged_common_seq extends uvm_sequence;
|
|||
if (MIE inside {implemented_csr}) begin
|
||||
mie = riscv_privil_reg::type_id::create("mie");
|
||||
mie.init_reg(MIE);
|
||||
mie.set_val(cfg.mie);
|
||||
mie.set_field("UEIE", cfg.enable_interrupt);
|
||||
mie.set_field("SEIE", cfg.enable_interrupt);
|
||||
mie.set_field("MEIE", cfg.enable_interrupt);
|
||||
mie.set_field("USIE", cfg.enable_interrupt);
|
||||
mie.set_field("SSIE", cfg.enable_interrupt);
|
||||
mie.set_field("MSIE", cfg.enable_interrupt);
|
||||
// TODO(udinator) - since full CSRs are being randomized, it's necessary to hardwire the xTIE
|
||||
// fields to 1'b0, as it causes some timer interrupts to be triggered in Spike after a certain
|
||||
// amount of simulation time.
|
||||
mie.set_field("MTIE", 1'b0);
|
||||
mie.set_field("STIE", 1'b0);
|
||||
mie.set_field("UTIE", 1'b0);
|
||||
regs.push_back(mie);
|
||||
end
|
||||
endfunction
|
||||
|
@ -100,6 +106,7 @@ class riscv_privileged_common_seq extends uvm_sequence;
|
|||
sstatus = riscv_privil_reg::type_id::create("sstatus");
|
||||
sstatus.init_reg(SSTATUS);
|
||||
`DV_CHECK_RANDOMIZE_FATAL(sstatus, "cannot randomize sstatus")
|
||||
sstatus.set_val(cfg.sstatus);
|
||||
sstatus.set_field("SPIE", cfg.enable_interrupt);
|
||||
sstatus.set_field("SIE", cfg.enable_interrupt);
|
||||
sstatus.set_field("UPIE", cfg.enable_interrupt);
|
||||
|
@ -120,10 +127,13 @@ class riscv_privileged_common_seq extends uvm_sequence;
|
|||
if (SIE inside {implemented_csr}) begin
|
||||
sie = riscv_privil_reg::type_id::create("sie");
|
||||
sie.init_reg(SIE);
|
||||
sie.set_val(cfg.sie);
|
||||
sie.set_field("UEIE", cfg.enable_interrupt);
|
||||
sie.set_field("SEIE", cfg.enable_interrupt);
|
||||
sie.set_field("USIE", cfg.enable_interrupt);
|
||||
sie.set_field("SSIE", cfg.enable_interrupt);
|
||||
sie.set_field("STIE", 1'b0);
|
||||
sie.set_field("UTIE", 1'b0);
|
||||
regs.push_back(sie);
|
||||
end
|
||||
endfunction
|
||||
|
@ -132,14 +142,17 @@ class riscv_privileged_common_seq extends uvm_sequence;
|
|||
ustatus = riscv_privil_reg::type_id::create("ustatus");
|
||||
ustatus.init_reg(USTATUS);
|
||||
`DV_CHECK_RANDOMIZE_FATAL(ustatus, "cannot randomize ustatus")
|
||||
ustatus.set_val(cfg.ustatus);
|
||||
ustatus.set_field("UIE", cfg.enable_interrupt);
|
||||
ustatus.set_field("UPIE", cfg.enable_interrupt);
|
||||
regs.push_back(ustatus);
|
||||
if (UIE inside {implemented_csr}) begin
|
||||
uie = riscv_privil_reg::type_id::create("uie");
|
||||
uie.init_reg(UIE);
|
||||
uie.set_val(cfg.uie);
|
||||
uie.set_field("UEIE", cfg.enable_interrupt);
|
||||
uie.set_field("USIE", cfg.enable_interrupt);
|
||||
uie.set_field("UTIE", 1'b0);
|
||||
regs.push_back(uie);
|
||||
end
|
||||
endfunction
|
||||
|
|
|
@ -76,6 +76,9 @@ class riscv_rand_instr extends riscv_instr_base;
|
|||
if(cfg.no_wfi) {
|
||||
instr_name != WFI;
|
||||
}
|
||||
if(cfg.no_dret) {
|
||||
instr_name != DRET;
|
||||
}
|
||||
// Below previleged instruction is not generated by default
|
||||
!(instr_name inside {ECALL, URET, SRET, MRET});
|
||||
if(cfg.no_load_store) {
|
||||
|
|
3
vendor/google_riscv-dv/src/riscv_reg.sv
vendored
3
vendor/google_riscv-dv/src/riscv_reg.sv
vendored
|
@ -153,7 +153,4 @@ class riscv_reg#(type REG_T = privileged_reg_t) extends uvm_object;
|
|||
end
|
||||
endfunction
|
||||
|
||||
virtual function void set_wiri_wpri_fields();
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
|
|
@ -42,7 +42,10 @@ package riscv_signature_pkg;
|
|||
IN_SUPERVISOR_MODE,
|
||||
IN_USER_MODE,
|
||||
HANDLING_IRQ,
|
||||
HANDLING_EXCEPTION
|
||||
FINISHED_IRQ,
|
||||
HANDLING_EXCEPTION,
|
||||
ILLEGAL_INSTR_EXCEPTION,
|
||||
EBREAK_EXCEPTION
|
||||
} core_status_t;
|
||||
|
||||
typedef enum bit {
|
||||
|
@ -50,5 +53,4 @@ package riscv_signature_pkg;
|
|||
TEST_FAIL
|
||||
} test_result_t;
|
||||
|
||||
|
||||
endpackage
|
||||
|
|
|
@ -96,7 +96,7 @@ class riscv_instr_base_test extends uvm_test;
|
|||
asm_gen = riscv_asm_program_gen::type_id::create("asm_gen");
|
||||
get_directed_instr_stream_opts();
|
||||
asm_gen.cfg = cfg;
|
||||
test_name = $sformatf("%0s.%0d.S", asm_file_name, i);
|
||||
test_name = $sformatf("%0s_%0d.S", asm_file_name, i);
|
||||
apply_directed_instr();
|
||||
`uvm_info(`gfn, "All directed instruction is applied", UVM_LOW)
|
||||
cfg.build_instruction_template();
|
||||
|
|
|
@ -23,8 +23,7 @@ class riscv_rand_instr_test extends riscv_instr_base_test;
|
|||
virtual function void randomize_cfg();
|
||||
cfg.instr_cnt = 10000;
|
||||
cfg.num_of_sub_program = 5;
|
||||
`DV_CHECK_RANDOMIZE_WITH_FATAL(cfg,
|
||||
max_nested_loop == 2;)
|
||||
`DV_CHECK_RANDOMIZE_FATAL(cfg)
|
||||
`uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
|
||||
cfg.sprint()), UVM_LOW)
|
||||
endfunction
|
||||
|
@ -35,8 +34,8 @@ class riscv_rand_instr_test extends riscv_instr_base_test;
|
|||
asm_gen.add_directed_instr_stream("riscv_loop_instr", 4);
|
||||
asm_gen.add_directed_instr_stream("riscv_hazard_instr_stream", 4);
|
||||
asm_gen.add_directed_instr_stream("riscv_load_store_hazard_instr_stream", 4);
|
||||
asm_gen.add_directed_instr_stream("riscv_cache_line_stress_instr_stream", 4);
|
||||
asm_gen.add_directed_instr_stream("riscv_multi_page_load_store_instr_stream", 4);
|
||||
asm_gen.add_directed_instr_stream("riscv_mem_region_stress_test", 4);
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
|
1
vendor/google_riscv-dv/user_extension/user_define.h
vendored
Normal file
1
vendor/google_riscv-dv/user_extension/user_define.h
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
# Add user macros, routines in this file
|
2
vendor/google_riscv-dv/yaml/iss.yaml
vendored
2
vendor/google_riscv-dv/yaml/iss.yaml
vendored
|
@ -25,7 +25,7 @@
|
|||
--override riscvOVPsim/cpu/PMP_registers=0
|
||||
--override riscvOVPsim/cpu/simulateexceptions=T
|
||||
--trace --tracechange --traceshowicount --program <elf>
|
||||
--finishafter 500000
|
||||
--finishafter 1000000
|
||||
|
||||
- iss: sail
|
||||
path_var: SAIL_RISCV
|
||||
|
|
32
vendor/google_riscv-dv/yaml/testlist.yaml
vendored
32
vendor/google_riscv-dv/yaml/testlist.yaml
vendored
|
@ -76,8 +76,19 @@
|
|||
+directed_instr_1=riscv_loop_instr,4
|
||||
+directed_instr_2=riscv_hazard_instr_stream,4
|
||||
+directed_instr_3=riscv_load_store_hazard_instr_stream,4
|
||||
+directed_instr_4=riscv_cache_line_stress_instr_stream,4
|
||||
+directed_instr_5=riscv_multi_page_load_store_instr_stream,4
|
||||
+directed_instr_4=riscv_multi_page_load_store_instr_stream,4
|
||||
+directed_instr_5=riscv_mem_region_stress_test,4
|
||||
rtl_test: core_base_test
|
||||
|
||||
- test: riscv_loop_test
|
||||
description: >
|
||||
Random instruction stress test
|
||||
iterations: 2
|
||||
gen_test: riscv_instr_base_test
|
||||
gen_opts: >
|
||||
+instr_cnt=10000
|
||||
+num_of_sub_program=5
|
||||
+directed_instr_1=riscv_loop_instr,20
|
||||
rtl_test: core_base_test
|
||||
|
||||
# TODO: Temporarily disable this as compiler seems to generate compressed instruction with rv64im
|
||||
|
@ -98,7 +109,7 @@
|
|||
iterations: 2
|
||||
gen_test: riscv_instr_base_test
|
||||
gen_opts: >
|
||||
+instr_cnt=15000
|
||||
+instr_cnt=10000
|
||||
+num_of_sub_program=20
|
||||
+directed_instr_0=riscv_load_store_rand_instr_stream,8
|
||||
rtl_test: core_base_test
|
||||
|
@ -114,15 +125,16 @@
|
|||
+num_of_sub_program=5
|
||||
+directed_instr_0=riscv_load_store_rand_instr_stream,40
|
||||
+directed_instr_1=riscv_load_store_hazard_instr_stream,40
|
||||
+directed_instr_2=riscv_cache_line_stress_instr_stream,40
|
||||
+directed_instr_3=riscv_multi_page_load_store_instr_stream,40
|
||||
+directed_instr_2=riscv_multi_page_load_store_instr_stream,10
|
||||
+directed_instr_3=riscv_mem_region_stress_test,10
|
||||
rtl_test: core_base_test
|
||||
|
||||
# TODO: Re-enable this test after all the data/instruction page organization changes are done
|
||||
- test: riscv_page_table_exception_test
|
||||
description: >
|
||||
Test random page table exception handling. An exception handling routine is
|
||||
designed to fix the page table error and resume execution.
|
||||
iterations: 2
|
||||
iterations: 0
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+enable_page_table_exception=1
|
||||
|
@ -156,7 +168,7 @@
|
|||
iterations: 2
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+enable_illegal_instruction=1
|
||||
+illegal_instr_ratio=5
|
||||
rtl_test: core_base_test
|
||||
|
||||
- test: riscv_hint_instr_test
|
||||
|
@ -166,7 +178,7 @@
|
|||
iterations: 2
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+enable_hint_instruction=1
|
||||
+hint_instr_ratio=5
|
||||
rtl_test: core_base_test
|
||||
|
||||
- test: riscv_ebreak_test
|
||||
|
@ -228,8 +240,8 @@
|
|||
+num_of_sub_program=5
|
||||
+directed_instr_0=riscv_load_store_rand_instr_stream,20
|
||||
+directed_instr_1=riscv_load_store_hazard_instr_stream,20
|
||||
+directed_instr_2=riscv_cache_line_stress_instr_stream,20
|
||||
+directed_instr_3=riscv_multi_page_load_store_instr_stream,20
|
||||
+directed_instr_2=riscv_multi_page_load_store_instr_stream,5
|
||||
+directed_instr_3=riscv_mem_region_stress_test,5
|
||||
+enable_unaligned_load_store=1
|
||||
rtl_test: core_ibex_base_test
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue