mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 13:07:46 -04:00
Update google_riscv-dv to google/riscv-dv@4583049 (#660)
Update code from upstream repository https://github.com/google/riscv- dv to revision 4583049cc2b3469ba9dea56b5e2d75809a89d8f3 * Allow running compile command in LSF (google/riscv-dv#506) (taoliug) * improve documentation of config options (Udi Jonnalagadda) * Update AMO region and data sections (google/riscv-dv#503) (taoliug) * Avoid jumping to a sub program of other harts (google/riscv-dv#502) (taoliug) * Use .section for data sections by default (google/riscv-dv#501) (taoliug) * create PMP accessible region for exception handlers and start/end sections (Udi Jonnalagadda) * minor change to signature_addr passed to generator (google/riscv- dv#497) (udinator) * Solve before cconstraints modified (google/riscv-dv#476) (Dariusz Stachańczyk) * Move instruction sections together for multi-harts (google/riscv- dv#495) (taoliug) * add seed capability to CSR test generation (Udi Jonnalagadda) * fix pmp/shifted_addr compile warning (google/riscv-dv#493) (udinator) * User long jump to switch between different harts (google/riscv- dv#491) (taoliug) * Fix s_region generation (google/riscv-dv#487) (taoliug) * update rv32imc/riscv_pmp_test testlist options (google/riscv-dv#486) (udinator) * Fix default value of num_of_harts (google/riscv-dv#485) (taoliug) * Add shared memory region for multi-harts AMO (google/riscv-dv#484) (taoliug) * Add a runtime option num_of_harts (google/riscv-dv#483) (taoliug) * Add multi-thread support (google/riscv-dv#482) (taoliug) Signed-off-by: Udi <udij@google.com>
This commit is contained in:
parent
f870accab6
commit
3d827e1db1
32 changed files with 784 additions and 342 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: 6bd323385d454858ea5e50dedd42a563b37931fe
|
||||
rev: 4583049cc2b3469ba9dea56b5e2d75809a89d8f3
|
||||
}
|
||||
}
|
||||
|
|
118
vendor/google_riscv-dv/docs/source/configuration.rst
vendored
118
vendor/google_riscv-dv/docs/source/configuration.rst
vendored
|
@ -145,57 +145,73 @@ You can also add directed assembly/C test in the testlist
|
|||
|
||||
Runtime options of the generator
|
||||
--------------------------------
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| Option | Description | Default |
|
||||
+=============================+===================================================+=========+
|
||||
| num_of_tests | Number of assembly tests to be generated | 1 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| num_of_sub_program | Number of sub-program in one test | 5 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| instr_cnt | Instruction count per test | 200 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| enable_page_table_exception | Enable page table exception | 0 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| enable_unaligned_load_store | Enable unaligned memory operations | 0 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| no_ebreak | Disable ebreak instruction | 1 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| no_wfi | Disable WFI instruction | 1 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| no_dret | Disable dret instruction | 1 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| no_branch_jump | Disable branch/jump instruction | 0 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| no_load_store | Disable load/store instruction | 0 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| no_csr_instr | Disable CSR instruction | 0 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| no_fence | Disable fence 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 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| signature_addr | Write to this addr to send data to testbench | 0 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| enable_interrupt | Enable MStatus.MIE, used in interrupt test | 0 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| gen_debug_section | Disables randomized debug_rom section | 0 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| num_debug_sub_program | Number of debug sub-programs in test | 0 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| enable_ebreak_in_debug_rom | Generate ebreak instructions inside debug ROM | 0 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| set_dcsr_ebreak | Randomly enable dcsr.ebreak(m/s/u) | 0 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
| randomize_csr | Fully randomize main CSRs (xSTATUS, xIE) | 0 |
|
||||
+-----------------------------+---------------------------------------------------+---------+
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| Option | Description | Default |
|
||||
+=================================+===================================================+=========+
|
||||
| num_of_tests | Number of assembly tests to be generated | 1 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| num_of_sub_program | Number of sub-program in one test | 5 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| instr_cnt | Instruction count per test | 200 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| enable_page_table_exception | Enable page table exception | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| enable_unaligned_load_store | Enable unaligned memory operations | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| no_ebreak | Disable ebreak instruction | 1 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| no_wfi | Disable WFI instruction | 1 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| set_mstatus_tw | Enable WFI to be treated as illegal instruction | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| no_dret | Disable dret instruction | 1 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| no_branch_jump | Disable branch/jump instruction | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| no_csr_instr | Disable CSR instruction | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| enable_illegal_csr_instruction | Enable illegal CSR instructions | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| enable_access_invalid_csr_level | Enable accesses to higher privileged CSRs | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| enable_dummy_csr_write | Enable some dummy CSR writes in setup routine | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| enable_misaligned_instr | Enable jumps to misaligned instruction addresses | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| no_fence | Disable fence instruction | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| no_data_page | Disable data page generation | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| disable_compressed_instr | Disable compressed instruction generation | 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 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| signature_addr | Write to this addr to send data to testbench | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| enable_interrupt | Enable MStatus.MIE, used in interrupt test | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| enable_timer_irq | Enable xIE.xTIE, used to enable timer interrupts | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| gen_debug_section | Enables randomized debug_rom section | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| num_debug_sub_program | Number of debug sub-programs in test | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| enable_ebreak_in_debug_rom | Generate ebreak instructions inside debug ROM | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| set_dcsr_ebreak | Randomly enable dcsr.ebreak(m/s/u) | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| enable_debug_single_step | Enable debug single stepping functionality | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
| randomize_csr | Fully randomize main CSRs (xSTATUS, xIE) | 0 |
|
||||
+---------------------------------+---------------------------------------------------+---------+
|
||||
|
||||
Setup Privileged CSR description (optional)
|
||||
-------------------------------------------
|
||||
|
|
17
vendor/google_riscv-dv/run.py
vendored
17
vendor/google_riscv-dv/run.py
vendored
|
@ -135,7 +135,7 @@ def get_iss_cmd(base_cmd, elf, log):
|
|||
|
||||
|
||||
def do_compile(compile_cmd, test_list, core_setting_dir, cwd, ext_dir,
|
||||
cmp_opts, output_dir, debug_cmd):
|
||||
cmp_opts, output_dir, debug_cmd, lsf_cmd):
|
||||
"""Compile the instruction generator
|
||||
|
||||
Args:
|
||||
|
@ -147,6 +147,7 @@ def do_compile(compile_cmd, test_list, core_setting_dir, cwd, ext_dir,
|
|||
cmd_opts : Compile options for the generator
|
||||
output_dir : Output directory of the ELF files
|
||||
debug_cmd : Produce the debug cmd log without running
|
||||
lsf_cmd : LSF command used to run the instruction generator
|
||||
"""
|
||||
if (not((len(test_list) == 1) and (test_list[0]['test'] == 'riscv_csr_test'))):
|
||||
logging.info("Building RISC-V instruction generator")
|
||||
|
@ -159,9 +160,12 @@ def do_compile(compile_cmd, test_list, core_setting_dir, cwd, ext_dir,
|
|||
cmd = re.sub("<user_extension>", ext_dir, cmd)
|
||||
cmd = re.sub("<cwd>", cwd, cmd)
|
||||
cmd = re.sub("<cmp_opts>", cmp_opts, cmd)
|
||||
|
||||
logging.debug("Compile command: %s" % cmd)
|
||||
run_cmd(cmd, debug_cmd = debug_cmd)
|
||||
if lsf_cmd:
|
||||
cmd = lsf_cmd + " " + cmd
|
||||
run_parallel_cmd([cmd], debug_cmd = debug_cmd)
|
||||
else:
|
||||
logging.debug("Compile command: %s" % cmd)
|
||||
run_cmd(cmd, debug_cmd = debug_cmd)
|
||||
|
||||
|
||||
def run_csr_test(cmd_list, cwd, csr_file, isa, iterations, lsf_cmd,
|
||||
|
@ -296,7 +300,7 @@ def gen(test_list, cfg, output_dir, cwd):
|
|||
# Compile the instruction generator
|
||||
if not argv.so:
|
||||
do_compile(compile_cmd, test_list, argv.core_setting_dir, cwd, argv.user_extension_dir,
|
||||
argv.cmp_opts, output_dir, argv.debug)
|
||||
argv.cmp_opts, output_dir, argv.debug, argv.lsf_cmd)
|
||||
# Run the instruction generator
|
||||
if not argv.co:
|
||||
do_simulate(sim_cmd, test_list, cwd, argv.sim_opts, argv.seed_yaml, argv.seed, argv.csr_yaml,
|
||||
|
@ -765,6 +769,9 @@ def load_config(args, cwd):
|
|||
if args.target == "rv32imc":
|
||||
args.mabi = "ilp32"
|
||||
args.isa = "rv32imc"
|
||||
elif args.target == "multi_harts":
|
||||
args.mabi = "ilp32"
|
||||
args.isa = "rv32gc"
|
||||
elif args.target == "rv32i":
|
||||
args.mabi = "ilp32"
|
||||
args.isa = "rv32i"
|
||||
|
|
64
vendor/google_riscv-dv/scripts/gen_csr_test.py
vendored
64
vendor/google_riscv-dv/scripts/gen_csr_test.py
vendored
|
@ -225,7 +225,7 @@ def gen_csr_test_fail(test_file, end_addr):
|
|||
test_file.write(f"\tli x1, {TEST_FAIL}\n")
|
||||
test_file.write(f"\tslli x1, x1, 8\n")
|
||||
test_file.write(f"\taddi x1, x1, {TEST_RESULT}\n")
|
||||
test_file.write(f"\tli x2, {end_addr}\n")
|
||||
test_file.write(f"\tli x2, 0x{end_addr}\n")
|
||||
test_file.write(f"\tsw x1, 0(x2)\n")
|
||||
test_file.write(f"\tj csr_fail\n")
|
||||
|
||||
|
@ -244,7 +244,7 @@ def gen_csr_test_pass(test_file, end_addr):
|
|||
test_file.write(f"\tli x1, {TEST_PASS}\n")
|
||||
test_file.write(f"\tslli x1, x1, 8\n")
|
||||
test_file.write(f"\taddi x1, x1, {TEST_RESULT}\n")
|
||||
test_file.write(f"\tli x2, {end_addr}\n")
|
||||
test_file.write(f"\tli x2, 0x{end_addr}\n")
|
||||
test_file.write(f"\tsw x1, 0(x2)\n")
|
||||
test_file.write(f"\tj csr_pass\n")
|
||||
|
||||
|
@ -318,28 +318,42 @@ def gen_csr_instr(original_csr_map, csr_instructions, xlen,
|
|||
gen_csr_test_fail(csr_test_file, end_signature_addr)
|
||||
|
||||
|
||||
"""
|
||||
Define command line arguments.
|
||||
"""
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--csr_file", type=str, default="yaml/csr_template.yaml",
|
||||
help="The YAML file contating descriptions of all processor supported CSRs")
|
||||
parser.add_argument("--xlen", type=int, default=32,
|
||||
help="Specify the ISA width, e.g. 32 or 64 or 128")
|
||||
parser.add_argument("--iterations", type=int, default=1,
|
||||
help="Specify how many tests to be generated")
|
||||
parser.add_argument("--out", type=str, default="./",
|
||||
help="Specify output directory")
|
||||
parser.add_argument("--end_signature_addr", type=str, default="0",
|
||||
help="Address that should be written to at end of this test")
|
||||
args = parser.parse_args()
|
||||
def main():
|
||||
"""Main entry point of CSR test generation script.
|
||||
Will set up a list of all supported CSR instructions,
|
||||
and seed the RNG."""
|
||||
|
||||
# define command line arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--csr_file", type=str, default="yaml/csr_template.yaml",
|
||||
help="The YAML file contating descriptions of all processor supported CSRs")
|
||||
parser.add_argument("--xlen", type=int, default=32,
|
||||
help="Specify the ISA width, e.g. 32 or 64 or 128")
|
||||
parser.add_argument("--iterations", type=int, default=1,
|
||||
help="Specify how many tests to be generated")
|
||||
parser.add_argument("--out", type=str, default="./",
|
||||
help="Specify output directory")
|
||||
parser.add_argument("--end_signature_addr", type=str, default="0",
|
||||
help="Address that should be written to at end of this test")
|
||||
parser.add_argument("--seed", type=int, default=None,
|
||||
help="""Value used to seed the random number generator. If no value is passed in,
|
||||
the RNG will be seeded from an internal source of randomness.""")
|
||||
args = parser.parse_args()
|
||||
|
||||
"""All supported CSR operations"""
|
||||
csr_ops = ['csrrw', 'csrrs', 'csrrc', 'csrrwi', 'csrrsi', 'csrrci']
|
||||
|
||||
"""
|
||||
Seed the RNG.
|
||||
If args.seed is None, seed will be drawn from some internal random source.
|
||||
If args.seed is defined, this will be used to seed the RNG for user reproducibility.
|
||||
"""
|
||||
random.seed(args.seed)
|
||||
|
||||
gen_csr_instr(get_csr_map(args.csr_file, args.xlen),
|
||||
csr_ops, args.xlen, args.iterations, args.out,
|
||||
args.end_signature_addr)
|
||||
|
||||
|
||||
"""
|
||||
A list containing all supported CSR instructions.
|
||||
"""
|
||||
csr_ops = ['csrrw', 'csrrs', 'csrrc', 'csrrwi', 'csrrsi', 'csrrci']
|
||||
|
||||
gen_csr_instr(get_csr_map(args.csr_file, args.xlen),
|
||||
csr_ops, args.xlen, args.iterations, args.out,
|
||||
args.end_signature_addr)
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -50,6 +50,21 @@ class riscv_amo_base_instr_stream extends riscv_mem_access_stream;
|
|||
super.new(name);
|
||||
endfunction
|
||||
|
||||
function void pre_randomize();
|
||||
data_page = cfg.amo_region;
|
||||
max_data_page_id = data_page.size();
|
||||
endfunction
|
||||
|
||||
// Use "la" instruction to initialize the base regiseter
|
||||
virtual function void add_rs1_init_la_instr(riscv_reg_t gpr, int id, int base = 0);
|
||||
riscv_pseudo_instr la_instr;
|
||||
la_instr = riscv_pseudo_instr::type_id::create("la_instr");
|
||||
la_instr.pseudo_instr_name = LA;
|
||||
la_instr.rd = gpr;
|
||||
la_instr.imm_str = $sformatf("%0s+%0d", cfg.amo_region[id].name, base);
|
||||
instr_list.push_front(la_instr);
|
||||
endfunction
|
||||
|
||||
function void post_randomize();
|
||||
gen_amo_instr();
|
||||
// rs1 cannot be modified by other instructions
|
||||
|
|
509
vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
vendored
509
vendor/google_riscv-dv/src/riscv_asm_program_gen.sv
vendored
|
@ -27,8 +27,8 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
riscv_instr_gen_config cfg;
|
||||
riscv_data_page_gen data_page_gen;
|
||||
// User mode programs
|
||||
riscv_instr_sequence main_program;
|
||||
riscv_instr_sequence sub_program[];
|
||||
riscv_instr_sequence main_program[NUM_HARTS];
|
||||
riscv_instr_sequence sub_program[NUM_HARTS][];
|
||||
riscv_asm_program_gen debug_rom;
|
||||
// Kernel programs
|
||||
// These programs are called in the interrupt/exception handling routine based on the privileged
|
||||
|
@ -47,6 +47,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// Directed instruction ratio, occurance per 1000 instructions
|
||||
int unsigned directed_instr_stream_ratio[string];
|
||||
riscv_page_table_list#(SATP_MODE) page_table_list;
|
||||
int hart;
|
||||
|
||||
`uvm_object_utils(riscv_asm_program_gen)
|
||||
|
||||
|
@ -60,120 +61,149 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
|
||||
// This is the main function to generate all sections of the program.
|
||||
virtual function void gen_program();
|
||||
string sub_program_name[$];
|
||||
instr_stream.delete();
|
||||
// Generate program header
|
||||
gen_program_header();
|
||||
// Initialize general purpose registers
|
||||
init_gpr();
|
||||
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();
|
||||
// Generate sub program
|
||||
gen_sub_program(sub_program, sub_program_name, cfg.num_of_sub_program);
|
||||
// Generate main program
|
||||
main_program = riscv_instr_sequence::type_id::create("main_program");
|
||||
main_program.instr_cnt = cfg.main_program_instr_cnt;
|
||||
main_program.is_debug_program = 0;
|
||||
main_program.label_name = "_main";
|
||||
generate_directed_instr_stream(.label("main"),
|
||||
.original_instr_cnt(main_program.instr_cnt),
|
||||
.min_insert_cnt(1),
|
||||
.instr_stream(main_program.directed_instr));
|
||||
main_program.cfg = cfg;
|
||||
`DV_CHECK_RANDOMIZE_FATAL(main_program)
|
||||
main_program.gen_instr(.is_main_program(1), .no_branch(cfg.no_branch_jump));
|
||||
// Setup jump instruction among main program and sub programs
|
||||
gen_callstack(main_program, sub_program, sub_program_name, cfg.num_of_sub_program);
|
||||
`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)
|
||||
`uvm_info(`gfn, "Main/sub program generation...done", UVM_LOW)
|
||||
// Program end
|
||||
gen_program_end();
|
||||
if (!cfg.bare_program_mode) begin
|
||||
// Privileged mode switch routine
|
||||
gen_privileged_mode_switch_routine();
|
||||
// Generate debug rom section
|
||||
if (riscv_instr_pkg::support_debug_mode) begin
|
||||
gen_debug_rom();
|
||||
for (int hart = 0; hart < cfg.num_of_harts; hart++) begin
|
||||
string sub_program_name[$];
|
||||
instr_stream.push_back($sformatf("h%0d_start:", hart));
|
||||
if (!cfg.bare_program_mode) begin
|
||||
setup_misa();
|
||||
// Create all page tables
|
||||
create_page_table(hart);
|
||||
// Setup privileged mode registers and enter target privileged mode
|
||||
pre_enter_privileged_mode(hart);
|
||||
end
|
||||
// Init section
|
||||
gen_init_section(hart);
|
||||
// If PMP is supported, we want to generate the associated trap handlers and the test_done
|
||||
// section at the start of the program so we can allow access through the pmpcfg0 CSR
|
||||
if (support_pmp) begin
|
||||
gen_trap_handlers(hart);
|
||||
// Ecall handler
|
||||
gen_ecall_handler(hart);
|
||||
// Instruction fault handler
|
||||
gen_instr_fault_handler(hart);
|
||||
// Load fault handler
|
||||
gen_load_fault_handler(hart);
|
||||
// Store fault handler
|
||||
gen_store_fault_handler(hart);
|
||||
gen_test_done();
|
||||
end
|
||||
// Generate sub program
|
||||
gen_sub_program(hart, sub_program[hart], sub_program_name, cfg.num_of_sub_program);
|
||||
// Generate main program
|
||||
main_program[hart] = riscv_instr_sequence::type_id::create(get_label("main", hart));
|
||||
main_program[hart].instr_cnt = cfg.main_program_instr_cnt;
|
||||
main_program[hart].is_debug_program = 0;
|
||||
main_program[hart].label_name = main_program[hart].get_name();
|
||||
generate_directed_instr_stream(.hart(hart),
|
||||
.label(main_program[hart].label_name),
|
||||
.original_instr_cnt(main_program[hart].instr_cnt),
|
||||
.min_insert_cnt(1),
|
||||
.instr_stream(main_program[hart].directed_instr));
|
||||
main_program[hart].cfg = cfg;
|
||||
`DV_CHECK_RANDOMIZE_FATAL(main_program[hart])
|
||||
main_program[hart].gen_instr(.is_main_program(1), .no_branch(cfg.no_branch_jump));
|
||||
// Setup jump instruction among main program and sub programs
|
||||
gen_callstack(main_program[hart], sub_program[hart], sub_program_name, cfg.num_of_sub_program);
|
||||
`uvm_info(`gfn, "Generating callstack...done", UVM_LOW)
|
||||
main_program[hart].post_process_instr();
|
||||
`uvm_info(`gfn, "Post-processing main program...done", UVM_LOW)
|
||||
main_program[hart].generate_instr_stream();
|
||||
`uvm_info(`gfn, "Generating main program instruction stream...done", UVM_LOW)
|
||||
instr_stream = {instr_stream, main_program[hart].instr_string_list};
|
||||
// If PMP is supported, need to jump from end of main program to test_done section at the end
|
||||
// of main_program, as the test_done will have moved to the beginning of the program
|
||||
instr_stream = {instr_stream, $sformatf("%sj test_done", indent)};
|
||||
// Test done section
|
||||
// If PMP isn't supported, generate this in the normal location
|
||||
if (hart == 0 & !support_pmp) begin
|
||||
gen_test_done();
|
||||
end
|
||||
// Shuffle the sub programs and insert to the instruction stream
|
||||
insert_sub_program(sub_program[hart], instr_stream);
|
||||
`uvm_info(`gfn, "Inserting sub-programs...done", UVM_LOW)
|
||||
`uvm_info(`gfn, "Main/sub program generation...done", UVM_LOW)
|
||||
// Program end
|
||||
gen_program_end(hart);
|
||||
if (!cfg.bare_program_mode) begin
|
||||
// Privileged mode switch routine
|
||||
gen_privileged_mode_switch_routine(hart);
|
||||
// Generate debug rom section
|
||||
if (riscv_instr_pkg::support_debug_mode) begin
|
||||
gen_debug_rom(hart);
|
||||
end
|
||||
end
|
||||
gen_section({hart_prefix(hart), "instr_end"}, {"nop"});
|
||||
end
|
||||
// Starting point of data section
|
||||
gen_data_page_begin();
|
||||
// Page table
|
||||
if (!cfg.bare_program_mode) begin
|
||||
gen_page_table_section();
|
||||
end
|
||||
if(!cfg.no_data_page) begin
|
||||
// Kernel data section
|
||||
gen_data_page();
|
||||
end
|
||||
gen_data_page_end();
|
||||
// Stack section
|
||||
gen_stack_section();
|
||||
if (!cfg.bare_program_mode) begin
|
||||
// Generate kernel program/data/stack section
|
||||
gen_kernel_sections();
|
||||
for (int hart = 0; hart < cfg.num_of_harts; hart++) begin
|
||||
// Starting point of data section
|
||||
gen_data_page_begin(hart);
|
||||
if(!cfg.no_data_page) begin
|
||||
// User data section
|
||||
gen_data_page(hart);
|
||||
// AMO memory region
|
||||
if ((hart == 0) && (RV32A inside {supported_isa})) begin
|
||||
gen_data_page(hart, .amo(1));
|
||||
end
|
||||
end
|
||||
// Stack section
|
||||
gen_stack_section(hart);
|
||||
if (!cfg.bare_program_mode) begin
|
||||
// Generate kernel program/data/stack section
|
||||
gen_kernel_sections(hart);
|
||||
end
|
||||
// Page table
|
||||
if (!cfg.bare_program_mode) begin
|
||||
gen_page_table_section(hart);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// Generate kernel program/data/stack sections
|
||||
//---------------------------------------------------------------------------------------
|
||||
virtual function void gen_kernel_sections();
|
||||
instr_stream.push_back("_kernel_instr_start: .align 12");
|
||||
virtual function void gen_kernel_sections(int hart);
|
||||
instr_stream.push_back(get_label("kernel_instr_start: .align 12", hart));
|
||||
instr_stream.push_back(".text");
|
||||
// Kernel programs
|
||||
if (cfg.virtual_addr_translation_on) begin
|
||||
umode_program = riscv_instr_sequence::type_id::create("umode_program");
|
||||
gen_kernel_program(umode_program);
|
||||
smode_program = riscv_instr_sequence::type_id::create("smode_program");
|
||||
gen_kernel_program(smode_program);
|
||||
smode_lsu_program = riscv_instr_sequence::type_id::create("smode_lsu_program");
|
||||
gen_kernel_program(smode_lsu_program);
|
||||
umode_program = riscv_instr_sequence::type_id::create(get_label("umode_program", hart));
|
||||
gen_kernel_program(hart, umode_program);
|
||||
smode_program = riscv_instr_sequence::type_id::create(get_label("smode_program", hart));
|
||||
gen_kernel_program(hart, smode_program);
|
||||
smode_lsu_program = riscv_instr_sequence::type_id::create(
|
||||
get_label("smode_lsu_program", hart));
|
||||
gen_kernel_program(hart, smode_lsu_program);
|
||||
end
|
||||
// All trap/interrupt handling is in the kernel region
|
||||
// Trap/interrupt delegation to user mode is not supported now
|
||||
// Trap handler
|
||||
gen_all_trap_handler();
|
||||
gen_all_trap_handler(hart);
|
||||
// Interrupt handling subroutine
|
||||
foreach(riscv_instr_pkg::supported_privileged_mode[i]) begin
|
||||
gen_interrupt_handler_section(riscv_instr_pkg::supported_privileged_mode[i]);
|
||||
gen_interrupt_handler_section(riscv_instr_pkg::supported_privileged_mode[i], hart);
|
||||
end
|
||||
instr_stream.push_back("_kernel_instr_end: nop");
|
||||
instr_stream.push_back(get_label("kernel_instr_end: nop", hart));
|
||||
// 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");
|
||||
instr_stream.push_back(get_label("kernel_data_start: .align 12", hart));
|
||||
if(!cfg.no_data_page) begin
|
||||
// Data section
|
||||
gen_data_page(1'b1);
|
||||
gen_data_page(hart, 1'b1);
|
||||
end
|
||||
gen_data_page_end();
|
||||
end
|
||||
// Kernel stack section
|
||||
gen_kernel_stack_section();
|
||||
gen_kernel_stack_section(hart);
|
||||
endfunction
|
||||
|
||||
virtual function void gen_kernel_program(riscv_instr_sequence seq);
|
||||
virtual function void gen_kernel_program(int hart, riscv_instr_sequence seq);
|
||||
seq.instr_cnt = cfg.kernel_program_instr_cnt;
|
||||
generate_directed_instr_stream(.label(seq.get_name()),
|
||||
generate_directed_instr_stream(.hart(hart),
|
||||
.label(seq.get_name()),
|
||||
.original_instr_cnt(seq.instr_cnt),
|
||||
.min_insert_cnt(0),
|
||||
.instr_stream(seq.directed_instr),
|
||||
|
@ -192,7 +222,8 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// Generate any subprograms and set up the callstack
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
||||
virtual function void gen_sub_program(ref riscv_instr_sequence sub_program[],
|
||||
virtual function void gen_sub_program(int hart,
|
||||
ref riscv_instr_sequence sub_program[],
|
||||
ref string sub_program_name[$],
|
||||
input int num_sub_program,
|
||||
bit is_debug = 1'b0,
|
||||
|
@ -200,15 +231,17 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
if(num_sub_program > 0) begin
|
||||
sub_program = new[num_sub_program];
|
||||
foreach(sub_program[i]) begin
|
||||
sub_program[i] = riscv_instr_sequence::type_id::create($sformatf("%s_%0d",prefix,i+1));
|
||||
`uvm_info(`gfn, $sformatf("sub program name: %s", prefix), UVM_LOW)
|
||||
sub_program[i] = riscv_instr_sequence::type_id::create(
|
||||
get_label($sformatf("%s_%0d", prefix, i + 1), hart));
|
||||
`uvm_info(`gfn, $sformatf("sub program name: %s", sub_program[i].get_name()), UVM_LOW)
|
||||
sub_program[i].is_debug_program = is_debug;
|
||||
if (is_debug) begin
|
||||
sub_program[i].instr_cnt = cfg.debug_sub_program_instr_cnt[i];
|
||||
end else begin
|
||||
sub_program[i].instr_cnt = cfg.sub_program_instr_cnt[i];
|
||||
end
|
||||
generate_directed_instr_stream(.label(sub_program[i].get_name()),
|
||||
generate_directed_instr_stream(.hart(hart),
|
||||
.label(sub_program[i].get_name()),
|
||||
.original_instr_cnt(sub_program[i].instr_cnt),
|
||||
.min_insert_cnt(0),
|
||||
.instr_stream(sub_program[i].directed_instr));
|
||||
|
@ -267,74 +300,96 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
//---------------------------------------------------------------------------------------
|
||||
|
||||
virtual function void gen_program_header();
|
||||
string str[$];
|
||||
instr_stream.push_back(".include \"user_define.h\"");
|
||||
instr_stream.push_back(".globl _start");
|
||||
instr_stream.push_back(".section .text");
|
||||
if (cfg.disable_compressed_instr) begin
|
||||
instr_stream.push_back(".option norvc;");
|
||||
end
|
||||
instr_stream.push_back("_start:");
|
||||
str = {"csrr x5, mhartid"};
|
||||
for (int hart = 0; hart < cfg.num_of_harts; hart++) begin
|
||||
str = {str, $sformatf("li x6, %0d", hart),
|
||||
$sformatf("beq x5, x6, %0df", hart)};
|
||||
end
|
||||
gen_section("_start", str);
|
||||
for (int hart = 0; hart < cfg.num_of_harts; hart++) begin
|
||||
instr_stream.push_back($sformatf("%0d: j h%0d_start", hart, hart));
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void gen_program_end();
|
||||
// Use write_tohost to terminate spike simulation
|
||||
gen_section("write_tohost", {"sw gp, tohost, t5"});
|
||||
gen_section("_exit", {"j write_tohost"});
|
||||
virtual function void gen_program_end(int hart);
|
||||
if (hart == 0) begin
|
||||
// Use write_tohost to terminate spike simulation
|
||||
gen_section("write_tohost", {"sw gp, tohost, t5"});
|
||||
gen_section("_exit", {"j write_tohost"});
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void gen_data_page_begin();
|
||||
instr_stream.push_back(".data");
|
||||
instr_stream.push_back(".pushsection .tohost,\"aw\",@progbits;");
|
||||
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;");
|
||||
virtual function void gen_data_page_begin(int hart);
|
||||
instr_stream.push_back(".section .data");
|
||||
if (hart == 0) begin
|
||||
instr_stream.push_back(".align 6; .global tohost; tohost: .dword 0;");
|
||||
instr_stream.push_back(".align 6; .global fromhost; fromhost: .dword 0;");
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void gen_data_page(bit is_kernel = 1'b0);
|
||||
virtual function void gen_data_page(int hart, bit is_kernel = 1'b0, bit amo = 0);
|
||||
string data_page;
|
||||
data_page_gen = riscv_data_page_gen::type_id::create("data_page_gen");
|
||||
data_page_gen.cfg = cfg;
|
||||
data_page_gen.gen_data_page(cfg.data_page_pattern, is_kernel);
|
||||
data_page_gen.gen_data_page(hart, cfg.data_page_pattern, is_kernel, amo);
|
||||
instr_stream = {instr_stream, data_page_gen.data_page_str};
|
||||
endfunction
|
||||
|
||||
virtual function void gen_data_page_end();
|
||||
instr_stream.push_back(".align 4;");
|
||||
endfunction
|
||||
|
||||
// Generate the user stack section
|
||||
virtual function void gen_stack_section();
|
||||
instr_stream.push_back(".pushsection .user_stack,\"aw\",@progbits;");
|
||||
virtual function void gen_stack_section(int hart);
|
||||
if (cfg.use_push_data_section) begin
|
||||
instr_stream.push_back($sformatf(".pushsection .%0suser_stack,\"aw\",@progbits;",
|
||||
hart_prefix(hart)));
|
||||
end
|
||||
instr_stream.push_back(".align 12");
|
||||
instr_stream.push_back("_user_stack_start:");
|
||||
instr_stream.push_back(get_label("user_stack_start:", hart));
|
||||
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(get_label("user_stack_end:", hart));
|
||||
instr_stream.push_back($sformatf(".%0dbyte 0x0", XLEN/8));
|
||||
instr_stream.push_back(".popsection;");
|
||||
if (cfg.use_push_data_section) begin
|
||||
instr_stream.push_back(".popsection;");
|
||||
end
|
||||
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;");
|
||||
virtual function void gen_kernel_stack_section(int hart);
|
||||
if (cfg.use_push_data_section) begin
|
||||
instr_stream.push_back($sformatf(".pushsection .%0skernel_stack,\"aw\",@progbits;",
|
||||
hart_prefix(hart)));
|
||||
end
|
||||
instr_stream.push_back(".align 12");
|
||||
instr_stream.push_back("_kernel_stack_start:");
|
||||
instr_stream.push_back(get_label("kernel_stack_start:", hart));
|
||||
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(get_label("kernel_stack_end:", hart));
|
||||
instr_stream.push_back($sformatf(".%0dbyte 0x0", XLEN/8));
|
||||
instr_stream.push_back(".popsection;");
|
||||
if (cfg.use_push_data_section) begin
|
||||
instr_stream.push_back(".popsection;");
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void gen_init_section();
|
||||
virtual function void gen_init_section(int hart);
|
||||
string str;
|
||||
str = format_string("_init:", LABEL_STR_LEN);
|
||||
str = format_string(get_label("init:", hart), LABEL_STR_LEN);
|
||||
instr_stream.push_back(str);
|
||||
init_gpr();
|
||||
// Init stack pointer to point to the end of the user stack
|
||||
str = {indent, $sformatf("la x%0d, _user_stack_end", cfg.sp)};
|
||||
str = {indent, $sformatf("la x%0d, %0suser_stack_end", cfg.sp, hart_prefix(hart))};
|
||||
instr_stream.push_back(str);
|
||||
if (support_pmp) begin
|
||||
str = {indent, "j main"};
|
||||
instr_stream.push_back(str);
|
||||
end
|
||||
if (cfg.enable_floating_point) begin
|
||||
init_floating_point_gpr();
|
||||
end
|
||||
|
@ -431,6 +486,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
bit [DATA_WIDTH-1:0] reg_val;
|
||||
// Init general purpose registers with random values
|
||||
for(int i = 0; i < 32; i++) begin
|
||||
if (i inside {cfg.sp, cfg.tp}) continue;
|
||||
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(reg_val,
|
||||
reg_val dist {
|
||||
'h0 :/ 1,
|
||||
|
@ -515,28 +571,29 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// Privileged mode entering routine
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
||||
virtual function void pre_enter_privileged_mode();
|
||||
virtual function void pre_enter_privileged_mode(int hart);
|
||||
string instr[];
|
||||
// Setup kerenal stack pointer
|
||||
gen_section("kernel_sp", {$sformatf("la x%0d, _kernel_stack_end", cfg.tp)});
|
||||
gen_section(get_label("kernel_sp", hart),
|
||||
{$sformatf("la x%0d, %0skernel_stack_end", cfg.tp, hart_prefix(hart))});
|
||||
// Setup interrupt and exception delegation
|
||||
if(!cfg.no_delegation && (cfg.init_privileged_mode != MACHINE_MODE)) begin
|
||||
gen_delegation();
|
||||
gen_delegation(hart);
|
||||
end
|
||||
// Setup trap vector register
|
||||
trap_vector_init();
|
||||
trap_vector_init(hart);
|
||||
// Setup PMP CSRs
|
||||
setup_pmp();
|
||||
setup_pmp(hart);
|
||||
// Initialize PTE (link page table based on their real physical address)
|
||||
if(cfg.virtual_addr_translation_on) begin
|
||||
page_table_list.process_page_table(instr);
|
||||
gen_section("process_pt", instr);
|
||||
gen_section(get_label("process_pt", hart), instr);
|
||||
end
|
||||
// Setup mepc register, jump to init entry
|
||||
setup_epc();
|
||||
setup_epc(hart);
|
||||
endfunction
|
||||
|
||||
virtual function void gen_privileged_mode_switch_routine();
|
||||
virtual function void gen_privileged_mode_switch_routine(int hart);
|
||||
privil_seq = riscv_privileged_common_seq::type_id::create("privil_seq");
|
||||
foreach(riscv_instr_pkg::supported_privileged_mode[i]) begin
|
||||
string instr[$];
|
||||
|
@ -547,6 +604,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
riscv_instr_pkg::supported_privileged_mode[i].name()), UVM_LOW)
|
||||
// Enter privileged mode
|
||||
privil_seq.cfg = cfg;
|
||||
privil_seq.hart = hart;
|
||||
`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
|
||||
|
@ -577,10 +635,10 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
endfunction
|
||||
|
||||
// Setup EPC before entering target privileged mode
|
||||
virtual function void setup_epc();
|
||||
virtual function void setup_epc(int hart);
|
||||
string instr[];
|
||||
string mode_name;
|
||||
instr = {$sformatf("la x%0d, _init", cfg.gpr[0])};
|
||||
instr = {$sformatf("la x%0d, %0sinit", cfg.gpr[0], hart_prefix(hart))};
|
||||
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
|
||||
|
@ -592,18 +650,18 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
mode_name = cfg.init_privileged_mode.name();
|
||||
instr = {instr,
|
||||
$sformatf("csrw mepc, x%0d", cfg.gpr[0]),
|
||||
$sformatf("j init_%0s", mode_name.tolower())
|
||||
$sformatf("j %0sinit_%0s", hart_prefix(hart), mode_name.tolower())
|
||||
};
|
||||
gen_section("mepc_setup", instr);
|
||||
gen_section(get_label("mepc_setup", hart), instr);
|
||||
endfunction
|
||||
|
||||
// Setup PMP CSR configuration
|
||||
virtual function void setup_pmp();
|
||||
virtual function void setup_pmp(int hart);
|
||||
string instr[$];
|
||||
if (riscv_instr_pkg::support_pmp) begin
|
||||
cfg.pmp_cfg.setup_pmp();
|
||||
cfg.pmp_cfg.gen_pmp_instr(instr, cfg.scratch_reg);
|
||||
gen_section("pmp_setup", instr);
|
||||
gen_section(get_label("pmp_setup", hart), instr);
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
@ -613,18 +671,19 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
|
||||
// Interrupt and exception delegation setting.
|
||||
// The lower level exception and interrupt can be delegated to higher level handler.
|
||||
virtual function void gen_delegation();
|
||||
gen_delegation_instr(MEDELEG, MIDELEG,
|
||||
virtual function void gen_delegation(int hart);
|
||||
gen_delegation_instr(hart, MEDELEG, MIDELEG,
|
||||
cfg.m_mode_exception_delegation,
|
||||
cfg.m_mode_interrupt_delegation);
|
||||
if(riscv_instr_pkg::support_umode_trap) begin
|
||||
gen_delegation_instr(SEDELEG, SIDELEG,
|
||||
gen_delegation_instr(hart, SEDELEG, SIDELEG,
|
||||
cfg.s_mode_exception_delegation,
|
||||
cfg.s_mode_interrupt_delegation);
|
||||
end
|
||||
endfunction
|
||||
|
||||
virtual function void gen_delegation_instr(privileged_reg_t edeleg,
|
||||
virtual function void gen_delegation_instr(int hart,
|
||||
privileged_reg_t edeleg,
|
||||
privileged_reg_t ideleg,
|
||||
bit edeleg_enable[exception_cause_t],
|
||||
bit ideleg_enable[interrupt_cause_t]);
|
||||
|
@ -651,11 +710,11 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
$sformatf("csrw 0x%0x, x%0d # %0s", ideleg, cfg.gpr[0], ideleg.name())};
|
||||
section_name = edeleg.name();
|
||||
section_name = section_name.tolower();
|
||||
gen_section($sformatf("%0s_setup", section_name), instr);
|
||||
gen_section(get_label($sformatf("%0s_setup", section_name), hart), instr);
|
||||
endfunction
|
||||
|
||||
// Setup trap vector - MTVEC, STVEC, UTVEC
|
||||
virtual function void trap_vector_init();
|
||||
virtual function void trap_vector_init(int hart);
|
||||
string instr[];
|
||||
privileged_reg_t trap_vec_reg;
|
||||
string tvec_name;
|
||||
|
@ -670,7 +729,8 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
!riscv_instr_pkg::support_umode_trap) continue;
|
||||
if (riscv_instr_pkg::supported_privileged_mode[i] < cfg.init_privileged_mode) continue;
|
||||
tvec_name = trap_vec_reg.name();
|
||||
instr = {instr, $sformatf("la x%0d, %0s_handler", cfg.gpr[0], tvec_name.tolower())};
|
||||
instr = {instr, $sformatf("la x%0d, %0s%0s_handler",
|
||||
cfg.gpr[0], hart_prefix(hart), tvec_name.tolower())};
|
||||
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
|
||||
|
@ -683,7 +743,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
instr = {instr, $sformatf("csrw 0x%0x, x%0d # %0s",
|
||||
trap_vec_reg, cfg.gpr[0], trap_vec_reg.name())};
|
||||
end
|
||||
gen_section("trap_vec_init", instr);
|
||||
gen_section(get_label("trap_vec_init", hart), instr);
|
||||
endfunction
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
@ -691,33 +751,24 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
//---------------------------------------------------------------------------------------
|
||||
|
||||
// Trap handling routine
|
||||
virtual function void gen_all_trap_handler();
|
||||
virtual function void gen_all_trap_handler(int hart);
|
||||
string instr[$];
|
||||
foreach(riscv_instr_pkg::supported_privileged_mode[i]) begin
|
||||
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, MIE, MIP);
|
||||
SUPERVISOR_MODE:
|
||||
gen_trap_handler_section("s", SCAUSE, STVEC, STVAL, SEPC, SSCRATCH, SSTATUS, SIE, SIP);
|
||||
USER_MODE:
|
||||
if(riscv_instr_pkg::support_umode_trap) begin
|
||||
gen_trap_handler_section("u", UCAUSE, UTVEC, UTVAL, UEPC, USCRATCH, USTATUS, UIE, UIP);
|
||||
end
|
||||
endcase
|
||||
// If PMP isn't supported, generate the relevant trap handler sections as per usual
|
||||
if (!support_pmp) begin
|
||||
gen_trap_handlers(hart);
|
||||
// Ecall handler
|
||||
gen_ecall_handler(hart);
|
||||
// Instruction fault handler
|
||||
gen_instr_fault_handler(hart);
|
||||
// Load fault handler
|
||||
gen_load_fault_handler(hart);
|
||||
// Store fault handler
|
||||
gen_store_fault_handler(hart);
|
||||
end
|
||||
// Ebreak handler
|
||||
gen_ebreak_handler();
|
||||
// Ecall handler
|
||||
gen_ecall_handler();
|
||||
gen_ebreak_handler(hart);
|
||||
// Illegal instruction handler
|
||||
gen_illegal_instr_handler();
|
||||
// Instruction fault handler
|
||||
gen_instr_fault_handler();
|
||||
// Load fault handler
|
||||
gen_load_fault_handler();
|
||||
// Store fault handler
|
||||
gen_store_fault_handler();
|
||||
gen_illegal_instr_handler(hart);
|
||||
// Generate page table fault handling routine
|
||||
// Page table fault is always handled in machine mode, as virtual address translation may be
|
||||
// broken when page fault happens.
|
||||
|
@ -727,22 +778,42 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
end else begin
|
||||
instr.push_back("nop");
|
||||
end
|
||||
gen_section("pt_fault_handler", instr);
|
||||
gen_section(get_label("pt_fault_handler", hart), instr);
|
||||
endfunction
|
||||
|
||||
virtual function void gen_trap_handlers(int hart);
|
||||
foreach(riscv_instr_pkg::supported_privileged_mode[i]) begin
|
||||
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(hart, "m", MCAUSE, MTVEC, MTVAL,
|
||||
MEPC, MSCRATCH, MSTATUS, MIE, MIP);
|
||||
SUPERVISOR_MODE:
|
||||
gen_trap_handler_section(hart, "s", SCAUSE, STVEC, STVAL,
|
||||
SEPC, SSCRATCH, SSTATUS, SIE, SIP);
|
||||
USER_MODE:
|
||||
if(riscv_instr_pkg::support_umode_trap) begin
|
||||
gen_trap_handler_section(hart, "u", UCAUSE, UTVEC, UTVAL,
|
||||
UEPC, USCRATCH, USTATUS, UIE, UIP);
|
||||
end
|
||||
endcase
|
||||
end
|
||||
endfunction
|
||||
|
||||
// Generate the interrupt and trap handler for different privileged mode.
|
||||
// The trap handler checks the xCAUSE to determine the type of the exception and jumps to
|
||||
// corresponding exeception handling routine.
|
||||
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 ie, privileged_reg_t ip);
|
||||
virtual function void gen_trap_handler_section(int hart,
|
||||
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 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, ie, ip, scratch, instr);
|
||||
gen_interrupt_vector_table(hart, 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
|
||||
|
@ -758,13 +829,14 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// handler Interrupt is indicated by xCause[XLEN-1]
|
||||
$sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], cause, cause.name()),
|
||||
$sformatf("srli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0], XLEN-1),
|
||||
$sformatf("bne x%0d, x0, %0smode_intr_handler", cfg.gpr[0], mode)};
|
||||
$sformatf("bne x%0d, x0, %0s%0smode_intr_handler",
|
||||
cfg.gpr[0], hart_prefix(hart), mode)};
|
||||
end
|
||||
// The trap handler will occupy one 4KB page, it will be allocated one entry in the page table
|
||||
// with a specific privileged mode.
|
||||
instr_stream.push_back(".align 12");
|
||||
tvec_name = tvec.name();
|
||||
gen_section($sformatf("%0s_handler", tvec_name.tolower()), instr);
|
||||
gen_section(get_label($sformatf("%0s_handler", tvec_name.tolower()), hart), instr);
|
||||
// Exception handler
|
||||
instr = {};
|
||||
if (cfg.mtvec_mode == VECTORED) begin
|
||||
|
@ -779,39 +851,51 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
$sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[0], cause, cause.name()),
|
||||
// Breakpoint
|
||||
$sformatf("li x%0d, 0x%0x # BREAKPOINT", cfg.gpr[1], BREAKPOINT),
|
||||
$sformatf("beq x%0d, x%0d, ebreak_handler", cfg.gpr[0], cfg.gpr[1]),
|
||||
$sformatf("beq x%0d, x%0d, %0sebreak_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
// Check if it's an ECALL exception. Jump to ECALL exception handler
|
||||
$sformatf("li x%0d, 0x%0x # ECALL_UMODE", cfg.gpr[1], ECALL_UMODE),
|
||||
$sformatf("beq x%0d, x%0d, ecall_handler", cfg.gpr[0], cfg.gpr[1]),
|
||||
$sformatf("beq x%0d, x%0d, %0secall_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
$sformatf("li x%0d, 0x%0x # ECALL_SMODE", cfg.gpr[1], ECALL_SMODE),
|
||||
$sformatf("beq x%0d, x%0d, ecall_handler", cfg.gpr[0], cfg.gpr[1]),
|
||||
$sformatf("beq x%0d, x%0d, %0secall_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
$sformatf("li x%0d, 0x%0x # ECALL_MMODE", cfg.gpr[1], ECALL_MMODE),
|
||||
$sformatf("beq x%0d, x%0d, ecall_handler", cfg.gpr[0], cfg.gpr[1]),
|
||||
$sformatf("beq x%0d, x%0d, %0secall_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
// Page table fault or access fault conditions
|
||||
$sformatf("li x%0d, 0x%0x", cfg.gpr[1], INSTRUCTION_ACCESS_FAULT),
|
||||
$sformatf("beq x%0d, x%0d, instr_fault_handler", cfg.gpr[0], cfg.gpr[1]),
|
||||
$sformatf("beq x%0d, x%0d, %0sinstr_fault_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
$sformatf("li x%0d, 0x%0x", cfg.gpr[1], LOAD_ACCESS_FAULT),
|
||||
$sformatf("beq x%0d, x%0d, load_fault_handler", cfg.gpr[0], cfg.gpr[1]),
|
||||
$sformatf("beq x%0d, x%0d, %0sload_fault_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
$sformatf("li x%0d, 0x%0x", cfg.gpr[1], STORE_AMO_ACCESS_FAULT),
|
||||
$sformatf("beq x%0d, x%0d, store_fault_handler", cfg.gpr[0], cfg.gpr[1]),
|
||||
$sformatf("beq x%0d, x%0d, %0sstore_fault_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
$sformatf("li x%0d, 0x%0x", cfg.gpr[1], INSTRUCTION_PAGE_FAULT),
|
||||
$sformatf("beq x%0d, x%0d, pt_fault_handler", cfg.gpr[0], cfg.gpr[1]),
|
||||
$sformatf("beq x%0d, x%0d, %0spt_fault_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
$sformatf("li x%0d, 0x%0x", cfg.gpr[1], LOAD_PAGE_FAULT),
|
||||
$sformatf("beq x%0d, x%0d, pt_fault_handler", cfg.gpr[0], cfg.gpr[1]),
|
||||
$sformatf("beq x%0d, x%0d, %0spt_fault_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
$sformatf("li x%0d, 0x%0x", cfg.gpr[1], STORE_AMO_PAGE_FAULT),
|
||||
$sformatf("beq x%0d, x%0d, pt_fault_handler", cfg.gpr[0], cfg.gpr[1]),
|
||||
$sformatf("beq x%0d, x%0d, %0spt_fault_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
// Illegal instruction exception
|
||||
$sformatf("li x%0d, 0x%0x # ILLEGAL_INSTRUCTION", cfg.gpr[1], ILLEGAL_INSTRUCTION),
|
||||
$sformatf("beq x%0d, x%0d, illegal_instr_handler", cfg.gpr[0], cfg.gpr[1]),
|
||||
$sformatf("beq x%0d, x%0d, %0sillegal_instr_handler",
|
||||
cfg.gpr[0], cfg.gpr[1], hart_prefix(hart)),
|
||||
// Skip checking tval for illegal instruction as it's implementation specific
|
||||
$sformatf("csrr x%0d, 0x%0x # %0s", cfg.gpr[1], tval, tval.name()),
|
||||
"1: jal x1, test_done "
|
||||
};
|
||||
gen_section($sformatf("%0smode_exception_handler", mode), instr);
|
||||
gen_section(get_label($sformatf("%0smode_exception_handler", mode), hart), instr);
|
||||
endfunction
|
||||
|
||||
// Generate for interrupt vector table
|
||||
virtual function void gen_interrupt_vector_table(string mode,
|
||||
virtual function void gen_interrupt_vector_table(int hart,
|
||||
string mode,
|
||||
privileged_reg_t status,
|
||||
privileged_reg_t cause,
|
||||
privileged_reg_t ie,
|
||||
|
@ -825,10 +909,10 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// ambiguity does not arise in practice, since user-mode software interrupts are either
|
||||
// disabled or delegated
|
||||
instr = {instr, ".option norvc;",
|
||||
$sformatf("j %0smode_exception_handler", mode)};
|
||||
$sformatf("j %0s%0smode_exception_handler", hart_prefix(hart), mode)};
|
||||
// Redirect the interrupt to the corresponding interrupt handler
|
||||
for (int i = 1; i < max_interrupt_vector_num; i++) begin
|
||||
instr.push_back($sformatf("j %0smode_intr_vector_%0d", mode, i));
|
||||
instr.push_back($sformatf("j %0s%0smode_intr_vector_%0d", hart_prefix(hart), mode, i));
|
||||
end
|
||||
if (!cfg.disable_compressed_instr) begin
|
||||
instr = {instr, ".option rvc;"};
|
||||
|
@ -849,18 +933,18 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
gen_signature_handshake(.instr(intr_handler), .signature_type(WRITE_CSR), .csr(ip));
|
||||
// Jump to commmon interrupt handling routine
|
||||
intr_handler = {intr_handler,
|
||||
$sformatf("j %0smode_intr_handler", mode),
|
||||
$sformatf("j %0s%0smode_intr_handler", hart_prefix(hart), mode),
|
||||
"1: j test_done"};
|
||||
gen_section($sformatf("%0smode_intr_vector_%0d", mode, i), intr_handler);
|
||||
gen_section(get_label($sformatf("%0smode_intr_vector_%0d", mode, i), hart), intr_handler);
|
||||
end
|
||||
endfunction
|
||||
|
||||
// ECALL trap handler
|
||||
// It does some clean up like dump GPRs before communicating with host to terminate the test.
|
||||
// User can extend this function if some custom clean up routine is needed.
|
||||
virtual function void gen_ecall_handler();
|
||||
virtual function void gen_ecall_handler(int hart);
|
||||
string str;
|
||||
str = format_string("ecall_handler:", LABEL_STR_LEN);
|
||||
str = format_string(get_label("ecall_handler:", hart), LABEL_STR_LEN);
|
||||
instr_stream.push_back(str);
|
||||
dump_perf_stats();
|
||||
gen_register_dump();
|
||||
|
@ -877,7 +961,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// 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();
|
||||
virtual function void gen_ebreak_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, EBREAK_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
|
@ -888,7 +972,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
instr.push_back("mret");
|
||||
gen_section("ebreak_handler", instr);
|
||||
gen_section(get_label("ebreak_handler", hart), instr);
|
||||
endfunction
|
||||
|
||||
// Illegal instruction handler
|
||||
|
@ -898,7 +982,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// 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();
|
||||
virtual function void gen_illegal_instr_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, ILLEGAL_INSTR_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
|
@ -909,37 +993,37 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
};
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
instr.push_back("mret");
|
||||
gen_section("illegal_instr_handler", instr);
|
||||
gen_section(get_label("illegal_instr_handler", hart), instr);
|
||||
endfunction
|
||||
|
||||
// TODO: handshake correct csr based on delegation
|
||||
virtual function void gen_instr_fault_handler();
|
||||
virtual function void gen_instr_fault_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, INSTR_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
instr.push_back("mret");
|
||||
gen_section("instr_fault_handler", instr);
|
||||
gen_section(get_label("instr_fault_handler", hart), instr);
|
||||
endfunction
|
||||
|
||||
// TODO: handshake correct csr based on delegation
|
||||
virtual function void gen_load_fault_handler();
|
||||
virtual function void gen_load_fault_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, LOAD_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
instr.push_back("mret");
|
||||
gen_section("load_fault_handler", instr);
|
||||
gen_section(get_label("load_fault_handler", hart), instr);
|
||||
endfunction
|
||||
|
||||
// TODO: handshake correct csr based on delegation
|
||||
virtual function void gen_store_fault_handler();
|
||||
virtual function void gen_store_fault_handler(int hart);
|
||||
string instr[$];
|
||||
gen_signature_handshake(instr, CORE_STATUS, STORE_FAULT_EXCEPTION);
|
||||
gen_signature_handshake(.instr(instr), .signature_type(WRITE_CSR), .csr(MCAUSE));
|
||||
pop_gpr_from_kernel_stack(MSTATUS, MSCRATCH, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr);
|
||||
instr.push_back("mret");
|
||||
gen_section("store_fault_handler", instr);
|
||||
gen_section(get_label("store_fault_handler", hart), instr);
|
||||
endfunction
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
@ -950,7 +1034,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// The page is created based on the address translation mode - SV32, SV39, SV48
|
||||
// Right now only the lowest level 4KB page table is configured as leaf page table entry (PTE),
|
||||
// all the other super pages are link PTE.
|
||||
virtual function void create_page_table();
|
||||
virtual function void create_page_table(int hart);
|
||||
string instr[];
|
||||
if(cfg.virtual_addr_translation_on) begin
|
||||
page_table_list = riscv_page_table_list#(SATP_MODE)::
|
||||
|
@ -969,15 +1053,20 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
|
||||
// Generate the page table section of the program
|
||||
// The page table is generated as a group of continuous 4KB data sections.
|
||||
virtual function void gen_page_table_section();
|
||||
virtual function void gen_page_table_section(int hart);
|
||||
string page_table_section[$];
|
||||
if(page_table_list != null) begin
|
||||
instr_stream.push_back(".pushsection .page_table,\"aw\",@progbits;");
|
||||
if (cfg.use_push_data_section) begin
|
||||
instr_stream.push_back($sformatf(".pushsection .%0spage_table,\"aw\",@progbits;",
|
||||
hart_prefix(hart)));
|
||||
end
|
||||
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;");
|
||||
if (cfg.use_push_data_section) begin
|
||||
instr_stream.push_back(".popsection;");
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
@ -992,7 +1081,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
endfunction
|
||||
|
||||
// Interrupt handler routine
|
||||
virtual function void gen_interrupt_handler_section(privileged_mode_t mode);
|
||||
virtual function void gen_interrupt_handler_section(privileged_mode_t mode, int hart);
|
||||
string mode_prefix;
|
||||
string ls_unit;
|
||||
privileged_reg_t status, ip, ie, scratch;
|
||||
|
@ -1063,7 +1152,8 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
};
|
||||
// The interrupt handler will use one 4KB page
|
||||
instr_stream.push_back(".align 12");
|
||||
gen_section($sformatf("%0smode_intr_handler", mode_prefix), interrupt_handler_instr);
|
||||
gen_section(get_label($sformatf("%0smode_intr_handler", mode_prefix), hart),
|
||||
interrupt_handler_instr);
|
||||
endfunction
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
@ -1227,7 +1317,8 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
endfunction
|
||||
|
||||
// Generate directed instruction stream based on the ratio setting
|
||||
virtual function void generate_directed_instr_stream(input string label,
|
||||
virtual function void generate_directed_instr_stream(input int hart,
|
||||
input string label,
|
||||
input int unsigned original_instr_cnt,
|
||||
input int unsigned min_insert_cnt = 0,
|
||||
input bit kernel_mode = 0,
|
||||
|
@ -1262,6 +1353,7 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
end
|
||||
if($cast(new_instr_stream, object_h)) begin
|
||||
new_instr_stream.cfg = cfg;
|
||||
new_instr_stream.hart = hart;
|
||||
new_instr_stream.label = $sformatf("%0s_%0d", label, idx);
|
||||
new_instr_stream.kernel_mode = kernel_mode;
|
||||
`DV_CHECK_RANDOMIZE_FATAL(new_instr_stream)
|
||||
|
@ -1279,10 +1371,11 @@ class riscv_asm_program_gen extends uvm_object;
|
|||
// Generate the debug ROM, and any related programs
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
||||
virtual function void gen_debug_rom();
|
||||
virtual function void gen_debug_rom(int hart);
|
||||
`uvm_info(`gfn, "Creating debug ROM", UVM_LOW)
|
||||
debug_rom = riscv_asm_program_gen::type_id::create("debug_rom", , {"uvm_test_top", ".", `gfn});
|
||||
debug_rom.cfg = cfg;
|
||||
debug_rom.hart = hart;
|
||||
debug_rom.gen_program();
|
||||
instr_stream = {instr_stream, debug_rom.instr_stream};
|
||||
endfunction
|
||||
|
|
|
@ -23,7 +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[$];
|
||||
mem_region_t mem_region_setting[$];
|
||||
|
||||
`uvm_object_utils(riscv_data_page_gen)
|
||||
|
||||
|
@ -50,7 +50,10 @@ class riscv_data_page_gen extends uvm_object;
|
|||
endfunction
|
||||
|
||||
// Generate data pages for all memory regions
|
||||
function void gen_data_page(data_pattern_t pattern, bit is_kernel = 1'b0);
|
||||
function void gen_data_page(int hart_id,
|
||||
data_pattern_t pattern,
|
||||
bit is_kernel = 1'b0,
|
||||
bit amo = 0);
|
||||
string tmp_str;
|
||||
bit [7:0] tmp_data[];
|
||||
int page_cnt;
|
||||
|
@ -58,23 +61,30 @@ class riscv_data_page_gen extends uvm_object;
|
|||
data_page_str = {};
|
||||
if (is_kernel) begin
|
||||
mem_region_setting = cfg.s_mem_region;
|
||||
end else if (amo) begin
|
||||
mem_region_setting = cfg.amo_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));
|
||||
if (amo) begin
|
||||
if (cfg.use_push_data_section) begin
|
||||
data_page_str.push_back($sformatf(".pushsection .%0s,\"aw\",@progbits;",
|
||||
mem_region_setting[i].name));
|
||||
end
|
||||
data_page_str.push_back($sformatf("%0s:", mem_region_setting[i].name));
|
||||
end else begin
|
||||
if (cfg.use_push_data_section) begin
|
||||
data_page_str.push_back($sformatf(".pushsection .%0s,\"aw\",@progbits;",
|
||||
{hart_prefix(hart_id), mem_region_setting[i].name}));
|
||||
end
|
||||
data_page_str.push_back($sformatf("%0s:",
|
||||
{hart_prefix(hart_id), mem_region_setting[i].name}));
|
||||
end
|
||||
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
|
||||
if (page_size-i >= 32) begin
|
||||
|
@ -85,13 +95,10 @@ class riscv_data_page_gen extends uvm_object;
|
|||
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
|
||||
if (cfg.use_push_data_section) begin
|
||||
data_page_str.push_back(".popsection;");
|
||||
end
|
||||
end
|
||||
if (is_kernel) begin
|
||||
data_page_str.push_back(".popsection;");
|
||||
end
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
|
|
@ -27,6 +27,7 @@ class riscv_debug_rom_gen extends riscv_asm_program_gen;
|
|||
string debug_end[$];
|
||||
string str[$];
|
||||
string dret;
|
||||
int hart;
|
||||
|
||||
`uvm_object_utils(riscv_debug_rom_gen)
|
||||
|
||||
|
@ -45,7 +46,7 @@ class riscv_debug_rom_gen extends riscv_asm_program_gen;
|
|||
// If the debug section should not be generated, we just populate it
|
||||
// with a dret instruction.
|
||||
debug_main = {dret};
|
||||
gen_section("debug_rom", debug_main);
|
||||
gen_section($sformatf("%0sdebug_rom", hart_prefix(hart)), debug_main);
|
||||
end else begin
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
gen_ebreak_header();
|
||||
|
@ -80,21 +81,21 @@ class riscv_debug_rom_gen extends riscv_asm_program_gen;
|
|||
gen_increment_ebreak_counter();
|
||||
end
|
||||
format_section(debug_main);
|
||||
gen_sub_program(sub_program, sub_program_name,
|
||||
gen_sub_program(hart, sub_program[hart], sub_program_name,
|
||||
cfg.num_debug_sub_program, 1'b1, "debug_sub");
|
||||
main_program = riscv_instr_sequence::type_id::create("main_program");
|
||||
main_program.instr_cnt = cfg.debug_program_instr_cnt;
|
||||
main_program.is_debug_program = 1;
|
||||
main_program.cfg = cfg;
|
||||
`DV_CHECK_RANDOMIZE_FATAL(main_program)
|
||||
main_program.gen_instr(.is_main_program(1'b1), .no_branch(cfg.no_branch_jump));
|
||||
gen_callstack(main_program, sub_program, sub_program_name,
|
||||
main_program[hart] = riscv_instr_sequence::type_id::create("debug_program");
|
||||
main_program[hart].instr_cnt = cfg.debug_program_instr_cnt;
|
||||
main_program[hart].is_debug_program = 1;
|
||||
main_program[hart].cfg = cfg;
|
||||
`DV_CHECK_RANDOMIZE_FATAL(main_program[hart])
|
||||
main_program[hart].gen_instr(.is_main_program(1'b1), .no_branch(cfg.no_branch_jump));
|
||||
gen_callstack(main_program[hart], sub_program[hart], sub_program_name,
|
||||
cfg.num_debug_sub_program);
|
||||
main_program.post_process_instr();
|
||||
main_program.generate_instr_stream(.no_label(1'b1));
|
||||
insert_sub_program(sub_program, debug_main);
|
||||
debug_main = {debug_main, main_program.instr_string_list};
|
||||
gen_section("debug_rom", debug_main);
|
||||
main_program[hart].post_process_instr();
|
||||
main_program[hart].generate_instr_stream(.no_label(1'b1));
|
||||
insert_sub_program(sub_program[hart], debug_main);
|
||||
debug_main = {debug_main, main_program[hart].instr_string_list};
|
||||
gen_section($sformatf("%0sdebug_rom", hart_prefix(hart)), debug_main);
|
||||
if (cfg.enable_ebreak_in_debug_rom) begin
|
||||
gen_ebreak_footer();
|
||||
end
|
||||
|
@ -105,7 +106,7 @@ class riscv_debug_rom_gen extends riscv_asm_program_gen;
|
|||
end
|
||||
//format_section(debug_end);
|
||||
debug_end = {debug_end, dret};
|
||||
gen_section("debug_end", debug_end);
|
||||
gen_section($sformatf("%0sdebug_end", hart_prefix(hart)), debug_end);
|
||||
end
|
||||
gen_debug_exception_handler();
|
||||
endfunction
|
||||
|
@ -114,7 +115,7 @@ class riscv_debug_rom_gen extends riscv_asm_program_gen;
|
|||
// TODO(udinator) - remains empty for now, only a DRET
|
||||
virtual function void gen_debug_exception_handler();
|
||||
str = {"dret"};
|
||||
gen_section("debug_exception", str);
|
||||
gen_section($sformatf("%0sdebug_exception", hart_prefix(hart)), str);
|
||||
endfunction
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
|
@ -130,7 +131,7 @@ class riscv_debug_rom_gen extends riscv_asm_program_gen;
|
|||
str = {$sformatf("csrw 0x%0x, x%0d", DSCRATCH1, cfg.scratch_reg),
|
||||
$sformatf("csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH0),
|
||||
$sformatf("beq x%0d, x0, 1f", cfg.scratch_reg),
|
||||
$sformatf("j debug_end"),
|
||||
$sformatf("j %0sdebug_end", hart_prefix(hart)),
|
||||
$sformatf("1: csrr x%0d, 0x%0x", cfg.scratch_reg, DSCRATCH1)};
|
||||
debug_main = {debug_main, str};
|
||||
endfunction
|
||||
|
|
|
@ -65,9 +65,11 @@ class riscv_mem_access_stream extends riscv_directed_instr_stream;
|
|||
la_instr.pseudo_instr_name = LA;
|
||||
la_instr.rd = gpr;
|
||||
if(kernel_mode) begin
|
||||
la_instr.imm_str = $sformatf("%s+%0d", cfg.s_mem_region[id].name, base);
|
||||
la_instr.imm_str = $sformatf("%0s%s+%0d",
|
||||
hart_prefix(hart), cfg.s_mem_region[id].name, base);
|
||||
end else begin
|
||||
la_instr.imm_str = $sformatf("%s+%0d", cfg.mem_region[id].name, base);
|
||||
la_instr.imm_str = $sformatf("%0s%s+%0d",
|
||||
hart_prefix(hart), cfg.mem_region[id].name, base);
|
||||
end
|
||||
instr_list.push_front(la_instr);
|
||||
endfunction
|
||||
|
@ -184,8 +186,10 @@ class riscv_jump_instr extends riscv_directed_instr_stream;
|
|||
instr_list[i].atomic = 1'b1;
|
||||
end
|
||||
jump.has_label = 1'b1;
|
||||
jump.label = $sformatf("j_%0s_%0s_%0d", label, target_program_label, idx);
|
||||
branch.imm_str = jump.label;
|
||||
jump.label = "1";
|
||||
jump.comment = $sformatf("%s jump %0s -> %0s",
|
||||
hart_prefix(hart), label, target_program_label);
|
||||
branch.imm_str = "1f";
|
||||
branch.comment = "branch to jump instr";
|
||||
branch.branch_assigned = 1'b1;
|
||||
endfunction
|
||||
|
|
|
@ -106,6 +106,11 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
'{name:"region_4", size_in_bytes: 4096, xwr: 3'b111}
|
||||
};
|
||||
|
||||
// Dedicated shared memory region for multi-harts atomic operations
|
||||
mem_region_t amo_region[$] = '{
|
||||
'{name:"amo_0", size_in_bytes: 64, xwr: 3'b111}
|
||||
};
|
||||
|
||||
// Stack section word length
|
||||
int stack_len = 5000;
|
||||
|
||||
|
@ -148,8 +153,12 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
bit enable_unaligned_load_store;
|
||||
int illegal_instr_ratio;
|
||||
int hint_instr_ratio;
|
||||
// Number of harts to be simulated, must be <= NUM_HARTS
|
||||
int num_of_harts = NUM_HARTS;
|
||||
// Use SP as stack pointer
|
||||
bit fix_sp;
|
||||
// Use push/pop section for data pages
|
||||
bit use_push_data_section = 0;
|
||||
// Directed boot privileged mode, u, m, s
|
||||
string boot_mode_opts;
|
||||
int enable_page_table_exception;
|
||||
|
@ -303,6 +312,11 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
// This is default disabled at setup phase. It can be enabled in the exception and interrupt
|
||||
// handling routine
|
||||
mstatus_mprv == 1'b0;
|
||||
if (SATP_MODE == BARE) {
|
||||
mstatus_mxr == 0;
|
||||
mstatus_sum == 0;
|
||||
mstatus_tvm == 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Exception delegation setting
|
||||
|
@ -379,8 +393,11 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
unique {gpr};
|
||||
}
|
||||
|
||||
constraint addr_translaction_c {
|
||||
constraint addr_translaction_rnd_order_c {
|
||||
solve init_privileged_mode before virtual_addr_translation_on;
|
||||
}
|
||||
|
||||
constraint addr_translaction_c {
|
||||
if ((init_privileged_mode != MACHINE_MODE) && (SATP_MODE != BARE)) {
|
||||
virtual_addr_translation_on == 1'b1;
|
||||
} else {
|
||||
|
@ -444,6 +461,7 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
`uvm_field_int(support_supervisor_mode, UVM_DEFAULT)
|
||||
`uvm_field_int(disable_compressed_instr, UVM_DEFAULT)
|
||||
`uvm_field_int(signature_addr, UVM_DEFAULT)
|
||||
`uvm_field_int(num_of_harts, UVM_DEFAULT)
|
||||
`uvm_field_int(require_signature_addr, UVM_DEFAULT)
|
||||
`uvm_field_int(gen_debug_section, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_ebreak_in_debug_rom, UVM_DEFAULT)
|
||||
|
@ -456,6 +474,7 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
`uvm_field_int(max_directed_instr_stream_seq, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_floating_point, UVM_DEFAULT)
|
||||
`uvm_field_int(enable_vector_extension, UVM_DEFAULT)
|
||||
`uvm_field_int(use_push_data_section, UVM_DEFAULT)
|
||||
`uvm_object_utils_end
|
||||
|
||||
function new (string name = "");
|
||||
|
@ -477,6 +496,7 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
get_bool_arg_value("+no_load_store=", no_load_store);
|
||||
get_bool_arg_value("+no_csr_instr=", no_csr_instr);
|
||||
get_bool_arg_value("+fix_sp=", fix_sp);
|
||||
get_bool_arg_value("+use_push_data_section=", use_push_data_section);
|
||||
get_bool_arg_value("+enable_illegal_csr_instruction=", enable_illegal_csr_instruction);
|
||||
get_bool_arg_value("+enable_access_invalid_csr_level=", enable_access_invalid_csr_level);
|
||||
get_bool_arg_value("+enable_misaligned_instr=", enable_misaligned_instr);
|
||||
|
@ -488,6 +508,7 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
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_int_arg_value("+num_of_harts=", num_of_harts);
|
||||
get_bool_arg_value("+enable_unaligned_load_store=", enable_unaligned_load_store);
|
||||
get_bool_arg_value("+force_m_delegation=", force_m_delegation);
|
||||
get_bool_arg_value("+force_s_delegation=", force_s_delegation);
|
||||
|
@ -517,6 +538,7 @@ class riscv_instr_gen_config extends uvm_object;
|
|||
$sformatf("Illegal boot mode option - %0s", boot_mode_opts))
|
||||
endcase
|
||||
init_privileged_mode.rand_mode(0);
|
||||
addr_translaction_rnd_order_c.constraint_mode(0);
|
||||
end
|
||||
`uvm_info(`gfn, $sformatf("riscv_instr_pkg::supported_privileged_mode = %0d",
|
||||
riscv_instr_pkg::supported_privileged_mode.size()), UVM_LOW)
|
||||
|
|
12
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
12
vendor/google_riscv-dv/src/riscv_instr_pkg.sv
vendored
|
@ -954,6 +954,18 @@ package riscv_instr_pkg;
|
|||
rand bit [XLEN - 1 : 0] addr;
|
||||
} pmp_cfg_reg_t;
|
||||
|
||||
function automatic string hart_prefix(int hart = 0);
|
||||
if (NUM_HARTS <= 1) begin
|
||||
return "";
|
||||
end else begin
|
||||
return $sformatf("h%0d_", hart);
|
||||
end
|
||||
endfunction : hart_prefix
|
||||
|
||||
function automatic string get_label(string label, int hart = 0);
|
||||
return {hart_prefix(hart), label};
|
||||
endfunction : get_label
|
||||
|
||||
typedef struct packed {
|
||||
bit ill;
|
||||
bit [XLEN-2:7] reserved;
|
||||
|
|
|
@ -28,6 +28,7 @@ class riscv_instr_stream extends uvm_object;
|
|||
// Some additional reserved registers that should not be used as rd register
|
||||
// by this instruction stream
|
||||
riscv_reg_t reserved_rd[];
|
||||
int hart;
|
||||
|
||||
`uvm_object_utils(riscv_instr_stream)
|
||||
`uvm_object_new
|
||||
|
|
|
@ -39,8 +39,11 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
|
|||
|
||||
`uvm_object_utils(riscv_load_store_base_instr_stream)
|
||||
|
||||
constraint sp_c {
|
||||
constraint sp_rnd_order_c {
|
||||
solve use_sp_as_rs1 before rs1_reg;
|
||||
}
|
||||
|
||||
constraint sp_c {
|
||||
use_sp_as_rs1 dist {1 := 1, 0 := 2};
|
||||
if (use_sp_as_rs1) {
|
||||
rs1_reg == SP;
|
||||
|
@ -97,6 +100,7 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream;
|
|||
if (SP inside {cfg.reserved_regs, reserved_rd}) begin
|
||||
use_sp_as_rs1 = 0;
|
||||
use_sp_as_rs1.rand_mode(0);
|
||||
sp_rnd_order_c.constraint_mode(0);
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
|
|
@ -354,7 +354,7 @@ 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_instr_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));
|
||||
|
@ -471,8 +471,8 @@ class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
|
|||
if (cfg.support_supervisor_mode) begin
|
||||
instr = {instr,
|
||||
// Process kernel instruction pages
|
||||
$sformatf("la x%0d, _kernel_instr_start", cfg.gpr[0]),
|
||||
$sformatf("la x%0d, _kernel_instr_end", cfg.gpr[1]),
|
||||
$sformatf("la x%0d, kernel_instr_start", cfg.gpr[0]),
|
||||
$sformatf("la x%0d, kernel_instr_end", cfg.gpr[1]),
|
||||
// Get the VPN of the physical address
|
||||
$sformatf("slli x%0d, x%0d, %0d",
|
||||
cfg.gpr[0], cfg.gpr[0], XLEN - MAX_USED_VADDR_BITS),
|
||||
|
@ -501,7 +501,7 @@ class riscv_page_table_list#(satp_mode_t MODE = SV39) extends uvm_object;
|
|||
// If not the end of the kernel space, process the next PTE
|
||||
$sformatf("ble x%0d, x%0d, 1b", cfg.gpr[0], cfg.gpr[1]),
|
||||
// Process kernel data pages
|
||||
$sformatf("la x%0d, _kernel_data_start", cfg.gpr[0]),
|
||||
$sformatf("la x%0d, kernel_data_start", cfg.gpr[0]),
|
||||
// Get the VPN of the physical address
|
||||
$sformatf("slli x%0d, x%0d, %0d", cfg.gpr[0], cfg.gpr[0],
|
||||
XLEN - MAX_USED_VADDR_BITS),
|
||||
|
|
7
vendor/google_riscv-dv/src/riscv_pmp_cfg.sv
vendored
7
vendor/google_riscv-dv/src/riscv_pmp_cfg.sv
vendored
|
@ -104,12 +104,13 @@ class riscv_pmp_cfg extends uvm_object;
|
|||
arg_name = $sformatf("+pmp_region_%0d=", i);
|
||||
if (inst.get_arg_value(arg_name, pmp_region)) begin
|
||||
parse_pmp_config(pmp_region, pmp_cfg[i]);
|
||||
`uvm_info(`gfn, $sformatf("Configured pmp_cfg[%0d] from command line: %p", i, pmp_cfg[i]), UVM_LOW)
|
||||
`uvm_info(`gfn, $sformatf("Configured pmp_cfg[%0d] from command line: %p",
|
||||
i, pmp_cfg[i]), UVM_LOW)
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
function void parse_pmp_config(string pmp_region, ref pmp_cfg_reg_t pmp_cfg_reg);
|
||||
function void parse_pmp_config(string pmp_region, output pmp_cfg_reg_t pmp_cfg_reg);
|
||||
string fields[$];
|
||||
string field_vals[$];
|
||||
string field_type;
|
||||
|
@ -160,7 +161,7 @@ class riscv_pmp_cfg extends uvm_object;
|
|||
// RV64 - pmpaddr is bits [55:2] of the whole 56 bit address, prepended by 10'b0
|
||||
// Return {10'b0, shifted_addr[53:0]}
|
||||
64: begin
|
||||
return {10'b0, shifted_addr[53:0]};
|
||||
return {10'b0, shifted_addr[XLEN - 11 : 0]};
|
||||
end
|
||||
endcase
|
||||
endfunction
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
class riscv_privileged_common_seq extends uvm_sequence;
|
||||
|
||||
riscv_instr_gen_config cfg;
|
||||
int hart;
|
||||
riscv_privil_reg mstatus;
|
||||
riscv_privil_reg mie;
|
||||
riscv_privil_reg sstatus;
|
||||
|
@ -33,7 +34,8 @@ class riscv_privileged_common_seq extends uvm_sequence;
|
|||
|
||||
virtual function void enter_privileged_mode(input privileged_mode_t mode,
|
||||
output string instrs[$]);
|
||||
string label = format_string({"init_", mode.name(), ":"}, LABEL_STR_LEN);
|
||||
string label = format_string({$sformatf("%0sinit_%0s:",
|
||||
hart_prefix(hart), mode.name())}, LABEL_STR_LEN);
|
||||
string ret_instr[] = {"mret"};
|
||||
riscv_privil_reg regs[$];
|
||||
label = label.tolower();
|
||||
|
@ -69,10 +71,16 @@ class riscv_privileged_common_seq extends uvm_sequence;
|
|||
mstatus.set_field("TW", cfg.set_mstatus_tw);
|
||||
mstatus.set_field("FS", cfg.mstatus_fs);
|
||||
mstatus.set_field("VS", cfg.mstatus_vs);
|
||||
if(XLEN==64) begin
|
||||
mstatus.set_field("UXL", 2'b10);
|
||||
if (!(SUPERVISOR_MODE inside {supported_privileged_mode}) && (XLEN != 32)) begin
|
||||
mstatus.set_field("SXL", 2'b00);
|
||||
end else if (XLEN == 64) begin
|
||||
mstatus.set_field("SXL", 2'b10);
|
||||
end
|
||||
if (!(USER_MODE inside {supported_privileged_mode}) && (XLEN != 32)) begin
|
||||
mstatus.set_field("UXL", 2'b00);
|
||||
end else if (XLEN == 64) begin
|
||||
mstatus.set_field("UXL", 2'b10);
|
||||
end
|
||||
mstatus.set_field("XS", 0);
|
||||
mstatus.set_field("SD", 0);
|
||||
mstatus.set_field("UIE", 0);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# riscOVPsim configuration file converted from YAML
|
||||
--variant RVB64I
|
||||
--variant RV64I
|
||||
--override riscvOVPsim/cpu/add_Extensions=MC
|
||||
--override riscvOVPsim/cpu/misa_MXL=2
|
||||
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
|
||||
|
|
|
@ -60,6 +60,8 @@ parameter int VLEN = 512;
|
|||
parameter int ELEN = 64;
|
||||
parameter int SLEN = 64;
|
||||
|
||||
// Number of harts
|
||||
parameter int NUM_HARTS = 1;
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
22
vendor/google_riscv-dv/target/multi_harts/riscvOVPsim.ic
vendored
Normal file
22
vendor/google_riscv-dv/target/multi_harts/riscvOVPsim.ic
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
# riscOVPsim configuration file converted from YAML
|
||||
--variant RV32I
|
||||
--override riscvOVPsim/cpu/add_Extensions=MCA
|
||||
--override riscvOVPsim/cpu/misa_MXL=1
|
||||
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/unaligned=T
|
||||
--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/user_version=2.3
|
||||
--override riscvOVPsim/cpu/priv_version=1.11
|
||||
--override riscvOVPsim/cpu/mvendorid=0
|
||||
--override riscvOVPsim/cpu/marchid=0
|
||||
--override riscvOVPsim/cpu/mimpid=0
|
||||
--override riscvOVPsim/cpu/mhartid=0
|
||||
--override riscvOVPsim/cpu/cycle_undefined=F
|
||||
--override riscvOVPsim/cpu/instret_undefined=F
|
||||
--override riscvOVPsim/cpu/time_undefined=T
|
||||
--override riscvOVPsim/cpu/reset_address=0x80000000
|
||||
--override riscvOVPsim/cpu/simulateexceptions=T
|
||||
--override riscvOVPsim/cpu/defaultsemihost=F
|
||||
--override riscvOVPsim/cpu/wfi_is_nop=T
|
||||
--exitonsymbol _exit
|
118
vendor/google_riscv-dv/target/multi_harts/riscv_core_setting.sv
vendored
Normal file
118
vendor/google_riscv-dv/target/multi_harts/riscv_core_setting.sv
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Processor feature configuration
|
||||
//-----------------------------------------------------------------------------
|
||||
// XLEN
|
||||
parameter int XLEN = 32;
|
||||
|
||||
// Parameter for SATP mode, set to BARE if address translation is not supported
|
||||
parameter satp_mode_t SATP_MODE = BARE;
|
||||
|
||||
// Supported Privileged mode
|
||||
privileged_mode_t supported_privileged_mode[] = {MACHINE_MODE};
|
||||
|
||||
// Unsupported instructions
|
||||
riscv_instr_name_t unsupported_instr[];
|
||||
|
||||
// ISA supported by the processor
|
||||
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV32C, RV32A};
|
||||
|
||||
// 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;
|
||||
|
||||
// Physical memory protection support
|
||||
bit support_pmp = 0;
|
||||
|
||||
// Debug mode support
|
||||
bit support_debug_mode = 0;
|
||||
|
||||
// Support delegate trap to user mode
|
||||
bit support_umode_trap = 0;
|
||||
|
||||
// Support sfence.vma instruction
|
||||
bit support_sfence = 0;
|
||||
|
||||
// Support unaligned load/store
|
||||
bit support_unaligned_load_store = 1'b1;
|
||||
|
||||
// Parameter for vector extension
|
||||
parameter int VECTOR_EXTENSION_ENABLE = 0;
|
||||
parameter int VLEN = 512;
|
||||
parameter int ELEN = 64;
|
||||
parameter int SLEN = 64;
|
||||
|
||||
// Number of harts
|
||||
parameter int NUM_HARTS = 2;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Implemented previlieged CSR list
|
||||
`ifdef DSIM
|
||||
privileged_reg_t implemented_csr[] = {
|
||||
`else
|
||||
parameter privileged_reg_t implemented_csr[] = {
|
||||
`endif
|
||||
// Machine mode mode CSR
|
||||
MVENDORID, // Vendor ID
|
||||
MARCHID, // Architecture ID
|
||||
MIMPID, // Implementation ID
|
||||
MHARTID, // Hardware thread ID
|
||||
MSTATUS, // Machine status
|
||||
MISA, // ISA and extensions
|
||||
MIE, // Machine interrupt-enable register
|
||||
MTVEC, // Machine trap-handler base address
|
||||
MCOUNTEREN, // Machine counter enable
|
||||
MSCRATCH, // Scratch register for machine trap handlers
|
||||
MEPC, // Machine exception program counter
|
||||
MCAUSE, // Machine trap cause
|
||||
MTVAL, // Machine bad address or instruction
|
||||
MIP // Machine interrupt pending
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Supported interrupt/exception setting, used for functional coverage
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
`ifdef DSIM
|
||||
interrupt_cause_t implemented_interrupt[] = {
|
||||
`else
|
||||
parameter interrupt_cause_t implemented_interrupt[] = {
|
||||
`endif
|
||||
M_SOFTWARE_INTR,
|
||||
M_TIMER_INTR,
|
||||
M_EXTERNAL_INTR
|
||||
};
|
||||
|
||||
`ifdef DSIM
|
||||
exception_cause_t implemented_exception[] = {
|
||||
`else
|
||||
parameter exception_cause_t implemented_exception[] = {
|
||||
`endif
|
||||
INSTRUCTION_ACCESS_FAULT,
|
||||
ILLEGAL_INSTRUCTION,
|
||||
BREAKPOINT,
|
||||
LOAD_ADDRESS_MISALIGNED,
|
||||
LOAD_ACCESS_FAULT,
|
||||
ECALL_MMODE
|
||||
};
|
79
vendor/google_riscv-dv/target/multi_harts/testlist.yaml
vendored
Normal file
79
vendor/google_riscv-dv/target/multi_harts/testlist.yaml
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
# Copyright Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# ================================================================================
|
||||
# Regression test list format
|
||||
# --------------------------------------------------------------------------------
|
||||
# test : Assembly test name
|
||||
# description : Description of this test
|
||||
# gen_opts : Instruction generator options
|
||||
# iterations : Number of iterations of this test
|
||||
# no_iss : Enable/disable ISS simulator (Optional)
|
||||
# gen_test : Test name used by the instruction generator
|
||||
# asm_tests : Path to directed, hand-coded assembly test file or directory
|
||||
# rtl_test : RTL simulation test name
|
||||
# cmp_opts : Compile options passed to the instruction generator
|
||||
# sim_opts : Simulation options passed to the instruction generator
|
||||
# no_post_compare : Enable/disable comparison of trace log and ISS log (Optional)
|
||||
# compare_opts : Options for the RTL & ISS trace comparison
|
||||
# gcc_opts : gcc compile options
|
||||
# --------------------------------------------------------------------------------
|
||||
|
||||
- import: <riscv_dv_root>/yaml/base_testlist.yaml
|
||||
|
||||
|
||||
- test: riscv_non_compressed_instr_test
|
||||
description: >
|
||||
Random instruction test without compressed instructions
|
||||
iterations: 1
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+disable_compressed_instr=1
|
||||
rtl_test: core_base_test
|
||||
|
||||
|
||||
- test: riscv_hint_instr_test
|
||||
description: >
|
||||
HINT instruction test, verify the processor can detect HINT instruction
|
||||
treat it as NOP. No illegal instruction exception is expected
|
||||
iterations: 2
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+hint_instr_ratio=5
|
||||
rtl_test: core_base_test
|
||||
|
||||
|
||||
- test: riscv_amo_test
|
||||
description: >
|
||||
RISC-V atomic instruction extension test
|
||||
iterations: 2
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+instr_cnt=5000
|
||||
+num_of_sub_program=5
|
||||
+directed_instr_0=riscv_lr_sc_instr_stream,10
|
||||
+directed_instr_1=riscv_amo_instr_stream,10
|
||||
rtl_test: core_base_test
|
||||
|
||||
|
||||
- test: riscv_single_hart_test
|
||||
description: >
|
||||
single hart random test
|
||||
iterations: 2
|
||||
gen_test: riscv_rand_instr_test
|
||||
gen_opts: >
|
||||
+instr_cnt=6000
|
||||
+num_of_harts=1
|
||||
rtl_test: core_base_test
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
# riscOVPsim configuration file converted from YAML
|
||||
--variant RVB32I
|
||||
--variant RV32I
|
||||
--override riscvOVPsim/cpu/misa_MXL=1
|
||||
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
|
||||
--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
|
||||
|
|
|
@ -60,6 +60,8 @@ parameter int VLEN = 512;
|
|||
parameter int ELEN = 64;
|
||||
parameter int SLEN = 64;
|
||||
|
||||
// Number of harts
|
||||
parameter int NUM_HARTS = 1;
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# riscOVPsim configuration file converted from YAML
|
||||
--variant RVB32I
|
||||
--variant RV32I
|
||||
--override riscvOVPsim/cpu/add_Extensions=MC
|
||||
--override riscvOVPsim/cpu/misa_MXL=1
|
||||
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
|
||||
|
|
|
@ -60,6 +60,9 @@ parameter int VLEN = 512;
|
|||
parameter int ELEN = 64;
|
||||
parameter int SLEN = 64;
|
||||
|
||||
// Number of harts
|
||||
parameter int NUM_HARTS = 1;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -62,5 +62,5 @@
|
|||
+pmp_randomize=0
|
||||
+pmp_num_regions=1
|
||||
+pmp_granularity=1
|
||||
+pmp_region_0=L:0,A:NAPOT,X=1,W=1,R=1,ADDR=0x090000000
|
||||
+pmp_region_0=L:0,A:TOR,X:1,W:1,R:1,ADDR:FFFFFFFF
|
||||
rtl_test: core_base_test
|
||||
|
|
|
@ -60,6 +60,9 @@ parameter int VLEN = 512;
|
|||
parameter int ELEN = 64;
|
||||
parameter int SLEN = 64;
|
||||
|
||||
// Number of harts
|
||||
parameter int NUM_HARTS = 1;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -60,6 +60,8 @@ parameter int VLEN = 512;
|
|||
parameter int ELEN = 64;
|
||||
parameter int SLEN = 64;
|
||||
|
||||
// Number of harts
|
||||
parameter int NUM_HARTS = 1;
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# riscOVPsim configuration file converted from YAML
|
||||
--variant RVB64I
|
||||
--variant RV64I
|
||||
--override riscvOVPsim/cpu/add_Extensions=MC
|
||||
--override riscvOVPsim/cpu/misa_MXL=2
|
||||
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
|
||||
|
|
|
@ -60,6 +60,9 @@ parameter int VLEN = 512;
|
|||
parameter int ELEN = 64;
|
||||
parameter int SLEN = 64;
|
||||
|
||||
// Number of harts
|
||||
parameter int NUM_HARTS = 1;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Previleged CSR implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -52,7 +52,9 @@ class riscv_ml_test extends riscv_instr_base_test;
|
|||
cfg.init_privileged_mode = MACHINE_MODE;
|
||||
cfg.init_privileged_mode.rand_mode(0);
|
||||
cfg.enable_unaligned_load_store = 1'b1;
|
||||
cfg.addr_translaction_rnd_order_c.constraint_mode(0);
|
||||
`DV_CHECK_RANDOMIZE_FATAL(cfg)
|
||||
cfg.addr_translaction_rnd_order_c.constraint_mode(1);
|
||||
`uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s",
|
||||
cfg.sprint()), UVM_LOW)
|
||||
endfunction
|
||||
|
|
1
vendor/google_riscv-dv/yaml/simulator.yaml
vendored
1
vendor/google_riscv-dv/yaml/simulator.yaml
vendored
|
@ -79,6 +79,7 @@
|
|||
+incdir+$UVM_HOME/src
|
||||
$UVM_HOME/src/uvm_pkg.sv
|
||||
+define+DSIM
|
||||
-suppress EnumMustBePositive
|
||||
+incdir+<setting>
|
||||
+incdir+<user_extension>
|
||||
-f <cwd>/files.f
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue