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:
taoliug 2020-03-05 17:21:36 -08:00 committed by GitHub
parent f870accab6
commit 3d827e1db1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 784 additions and 342 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
rev: 6bd323385d454858ea5e50dedd42a563b37931fe
rev: 4583049cc2b3469ba9dea56b5e2d75809a89d8f3
}
}

View file

@ -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)
-------------------------------------------

View file

@ -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"

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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),

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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
// ----------------------------------------------------------------------------

View 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

View 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
};

View 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

View file

@ -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

View file

@ -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
// ----------------------------------------------------------------------------

View file

@ -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

View file

@ -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
// ----------------------------------------------------------------------------

View file

@ -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

View file

@ -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
// ----------------------------------------------------------------------------

View file

@ -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
// ----------------------------------------------------------------------------

View file

@ -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

View file

@ -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
// ----------------------------------------------------------------------------

View file

@ -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

View file

@ -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