| /* |
| * Copyright 2018 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. |
| */ |
| |
| //----------------------------------------------------------------------------- |
| // RISC-V assembly program generator configuration class |
| //----------------------------------------------------------------------------- |
| |
| class riscv_instr_gen_config extends uvm_object; |
| |
| //----------------------------------------------------------------------------- |
| // Random instruction generation settings |
| //----------------------------------------------------------------------------- |
| |
| // Instruction count of the main program |
| rand int main_program_instr_cnt; |
| |
| // Instruction count of each sub-program |
| rand int sub_program_instr_cnt[]; |
| |
| // Instruction count of the debug rom |
| rand int debug_program_instr_cnt; |
| |
| // Instruction count of debug sub-programs |
| rand int debug_sub_program_instr_cnt[]; |
| |
| // Pattern of data section: RAND_DATA, ALL_ZERO, INCR_VAL |
| rand data_pattern_t data_page_pattern; |
| |
| // Associate array for delegation configuration for each exception and interrupt |
| // When the bit is 1, the corresponding delegation is enabled. |
| rand bit m_mode_exception_delegation[exception_cause_t]; |
| rand bit s_mode_exception_delegation[exception_cause_t]; |
| rand bit m_mode_interrupt_delegation[interrupt_cause_t]; |
| rand bit s_mode_interrupt_delegation[interrupt_cause_t]; |
| |
| // Priviledged mode after boot |
| rand privileged_mode_t init_privileged_mode; |
| |
| rand bit[XLEN-1:0] mstatus, mie, |
| sstatus, sie, |
| ustatus, uie; |
| |
| // Key fields in xSTATUS |
| // Memory protection bits |
| rand bit mstatus_mprv; |
| rand bit mstatus_mxr; |
| rand bit mstatus_sum; |
| rand bit mstatus_tvm; |
| rand bit [1:0] mstatus_fs; |
| rand mtvec_mode_t mtvec_mode; |
| |
| // Floating point rounding mode |
| rand f_rounding_mode_t fcsr_rm; |
| |
| // Enable sfence.vma instruction |
| rand bit enable_sfence; |
| |
| // Reserved register |
| // Reserved for various hardcoded routines |
| rand riscv_reg_t gpr[4]; |
| // Used by any DCSR operations inside of the debug rom |
| rand riscv_reg_t scratch_reg; |
| // Use a random register for stack pointer/thread pointer |
| rand riscv_reg_t sp; |
| rand riscv_reg_t tp; |
| rand riscv_reg_t ra; |
| |
| // Options for privileged mode CSR checking |
| // Below checking can be made optional as the ISS implementation could be different with the |
| // processor. |
| bit check_misa_init_val = 1'b0; |
| bit check_xstatus = 1'b1; |
| |
| // Virtual address translation is on for this test |
| rand bit virtual_addr_translation_on; |
| |
| //----------------------------------------------------------------------------- |
| // User space memory region and stack setting |
| //----------------------------------------------------------------------------- |
| |
| mem_region_t mem_region[$] = '{ |
| '{name:"region_0", size_in_bytes: 4096, xwr: 3'b111}, |
| '{name:"region_1", size_in_bytes: 4096 * 4, xwr: 3'b111}, |
| '{name:"region_2", size_in_bytes: 4096 * 2, xwr: 3'b111}, |
| '{name:"region_3", size_in_bytes: 512, xwr: 3'b111}, |
| '{name:"region_4", size_in_bytes: 4096, xwr: 3'b111} |
| }; |
| |
| // Stack section word length |
| int stack_len = 5000; |
| |
| //----------------------------------------------------------------------------- |
| // Kernel section setting, used by supervisor mode programs |
| //----------------------------------------------------------------------------- |
| |
| mem_region_t s_mem_region[$] = '{ |
| '{name:"s_region_0", size_in_bytes: 4096, xwr: 3'b111}, |
| '{name:"s_region_1", size_in_bytes: 4096, xwr: 3'b111}}; |
| |
| // Kernel Stack section word length |
| int kernel_stack_len = 4000; |
| |
| // Number of instructions for each kernel program |
| int kernel_program_instr_cnt = 400; |
| |
| //----------------------------------------------------------------------------- |
| // Instruction list based on the config, generate by build_instruction_template |
| //----------------------------------------------------------------------------- |
| riscv_instr_base instr_template[riscv_instr_name_t]; |
| riscv_instr_name_t basic_instr[$]; |
| riscv_instr_name_t instr_group[riscv_instr_group_t][$]; |
| riscv_instr_name_t instr_category[riscv_instr_category_t][$]; |
| |
| //----------------------------------------------------------------------------- |
| // Command line options or control knobs |
| //----------------------------------------------------------------------------- |
| // Main options for RISC-V assembly program generation |
| // Number of sub-programs per test |
| int num_of_sub_program = 5; |
| int instr_cnt = 200; |
| int num_of_tests = 1; |
| // For tests doesn't involve load/store, the data section generation could be skipped |
| bit no_data_page; |
| // Options to turn off some specific types of instructions |
| bit no_branch_jump; // No branch/jump instruction |
| bit no_load_store; // No load/store instruction |
| bit no_csr_instr; // No csr instruction |
| bit no_ebreak = 1; // No ebreak instruction |
| bit no_dret = 1; // No dret instruction |
| bit no_fence; // No fence instruction |
| bit no_wfi = 1; // No WFI instruction |
| bit enable_unaligned_load_store; |
| int illegal_instr_ratio; |
| int hint_instr_ratio; |
| // Directed boot privileged mode, u, m, s |
| string boot_mode_opts; |
| int enable_page_table_exception; |
| bit no_directed_instr; |
| // A name suffix for the generated assembly program |
| string asm_test_suffix; |
| // Enable interrupt bit in MSTATUS (MIE, SIE, UIE) |
| bit enable_interrupt; |
| // We need a separate control knob for enabling timer interrupts, as Spike |
| // throws an exception if xIE.xTIE is enabled |
| bit enable_timer_irq; |
| // Generate a bare program without any init/exit/error handling/page table routines |
| // The generated program can be integrated with a larger program. |
| // Note that the bare mode program is not expected to run in standalone mode |
| bit bare_program_mode; |
| // Enable accessing illegal CSR instruction |
| // - Accessing non-existence CSR |
| // - Accessing CSR with wrong privileged mode |
| bit enable_illegal_csr_instruction; |
| bit randomize_csr = 0; |
| // sfence support |
| bit allow_sfence_exception = 0; |
| // Interrupt/Exception Delegation |
| bit no_delegation = 1; |
| bit force_m_delegation = 0; |
| bit force_s_delegation = 0; |
| bit support_supervisor_mode; |
| bit disable_compressed_instr; |
| // "Memory mapped" address that when written to will indicate some event to |
| // the testbench - testbench will take action based on the value written |
| int signature_addr = 32'hdead_beef; |
| bit require_signature_addr = 1'b0; |
| // Enable a full or empty debug_rom section. |
| // Full debug_rom will contain random instruction streams. |
| // Empty debug_rom will contain just dret instruction and will return immediately. |
| // Will be empty by default. |
| bit gen_debug_section = 1'b0; |
| // Enable generation of a directed sequence of instructions containing |
| // ebreak inside the debug_rom. |
| // Disabled by default. |
| bit enable_ebreak_in_debug_rom = 1'b0; |
| // Enable setting dcsr.ebreak(m/s/u) |
| bit set_dcsr_ebreak = 1'b0; |
| // Number of sub programs in the debug rom |
| int num_debug_sub_program = 0; |
| // Enable debug single stepping |
| bit enable_debug_single_step = 0; |
| // Number of single stepping iterations |
| rand int single_step_iterations; |
| // Stack space allocated to each program, need to be enough to store necessary context |
| // Example: RA, SP, T0 |
| int min_stack_len_per_program = 10 * (XLEN/8); |
| int max_stack_len_per_program = 16 * (XLEN/8); |
| // Maximum branch distance, avoid skipping large portion of the code |
| int max_branch_step = 20; |
| // Maximum directed instruction stream sequence count |
| int max_directed_instr_stream_seq = 20; |
| // Reserved registers |
| riscv_reg_t reserved_regs[]; |
| // Floating point support |
| bit enable_floating_point; |
| |
| //----------------------------------------------------------------------------- |
| // Command line options for instruction distribution control |
| //----------------------------------------------------------------------------- |
| int dist_control_mode; |
| int unsigned category_dist[riscv_instr_category_t]; |
| |
| uvm_cmdline_processor inst; |
| |
| constraint default_c { |
| sub_program_instr_cnt.size() == num_of_sub_program; |
| debug_sub_program_instr_cnt.size() == num_debug_sub_program; |
| main_program_instr_cnt inside {[10 : instr_cnt]}; |
| foreach(sub_program_instr_cnt[i]) { |
| sub_program_instr_cnt[i] inside {[10 : instr_cnt]}; |
| } |
| // Disable sfence if the program is not boot to supervisor mode |
| // If sfence exception is allowed, we can enable sfence instruction in any priviledged mode. |
| // When MSTATUS.TVM is set, executing sfence.vma will be treate as illegal instruction |
| if(allow_sfence_exception) { |
| enable_sfence == 1'b1; |
| (init_privileged_mode != SUPERVISOR_MODE) || (mstatus_tvm == 1'b1); |
| } else { |
| (init_privileged_mode != SUPERVISOR_MODE || !riscv_instr_pkg::support_sfence || mstatus_tvm || no_fence) |
| -> (enable_sfence == 1'b0); |
| } |
| } |
| |
| constraint debug_mode_c { |
| if (riscv_instr_pkg::support_debug_mode) { |
| debug_program_instr_cnt inside {[100 : 300]}; |
| foreach(debug_sub_program_instr_cnt[i]) { |
| debug_sub_program_instr_cnt[i] inside {[100 : 300]}; |
| } |
| } |
| `ifndef DSIM |
| main_program_instr_cnt + sub_program_instr_cnt.sum() == instr_cnt; |
| `else |
| // dsim has some issue supporting sum(), use some approximate constraint to generate |
| // instruction cnt |
| if (num_of_sub_program > 0) { |
| main_program_instr_cnt inside {[10:instr_cnt/2]}; |
| foreach (sub_program_instr_cnt[i]) { |
| sub_program_instr_cnt[i] inside {[10:instr_cnt/num_of_sub_program]}; |
| } |
| } else { |
| main_program_instr_cnt == instr_cnt; |
| } |
| `endif |
| } |
| |
| // Keep the number of single step iterations relatively small |
| constraint debug_single_step_c { |
| if (enable_debug_single_step) { |
| single_step_iterations inside {[10 : 50]}; |
| } |
| } |
| |
| // Boot privileged mode distribution |
| constraint boot_privileged_mode_dist_c { |
| // Boot to higher privileged mode more often |
| if(riscv_instr_pkg::supported_privileged_mode.size() == 2) { |
| init_privileged_mode dist {riscv_instr_pkg::supported_privileged_mode[0] := 9, |
| riscv_instr_pkg::supported_privileged_mode[1] := 1}; |
| } else if (riscv_instr_pkg::supported_privileged_mode.size() == 3) { |
| init_privileged_mode dist {riscv_instr_pkg::supported_privileged_mode[0] := 6, |
| riscv_instr_pkg::supported_privileged_mode[1] := 3, |
| riscv_instr_pkg::supported_privileged_mode[2] := 1}; |
| } else { |
| init_privileged_mode == riscv_instr_pkg::supported_privileged_mode[0]; |
| } |
| } |
| |
| constraint mtvec_c { |
| mtvec_mode inside {supported_interrupt_mode}; |
| } |
| |
| constraint mstatus_c { |
| // This is default disabled at setup phase. It can be enabled in the exception and interrupt |
| // handling routine |
| mstatus_mprv == 1'b0; |
| } |
| |
| // Exception delegation setting |
| constraint exception_delegation_c { |
| // Do not delegate instructino page fault to supervisor/user mode because this may introduce |
| // dead loop. All the subsequent instruction fetches may fail and program cannot recover. |
| m_mode_exception_delegation[INSTRUCTION_PAGE_FAULT] == 1'b0; |
| if(force_m_delegation) { |
| foreach(m_mode_exception_delegation[i]) { |
| soft m_mode_exception_delegation[i] == 1'b1; |
| } |
| foreach(m_mode_interrupt_delegation[i]) { |
| soft m_mode_interrupt_delegation[i] == 1'b1; |
| } |
| } |
| if(force_s_delegation) { |
| foreach(s_mode_exception_delegation[i]) { |
| soft s_mode_exception_delegation[i] == 1'b1; |
| } |
| foreach(s_mode_interrupt_delegation[i]) { |
| soft s_mode_interrupt_delegation[i] == 1'b1; |
| } |
| } |
| } |
| |
| // Spike only supports a subset of exception and interrupt delegation |
| // You can modify this constraint if your ISS support different set of delegations |
| constraint delegation_c { |
| foreach(m_mode_exception_delegation[i]) { |
| if(!support_supervisor_mode || no_delegation) { |
| m_mode_exception_delegation[i] == 0; |
| } |
| if(!(i inside {INSTRUCTION_ADDRESS_MISALIGNED, BREAKPOINT, ECALL_UMODE, |
| INSTRUCTION_PAGE_FAULT, LOAD_PAGE_FAULT, STORE_AMO_PAGE_FAULT})) { |
| m_mode_exception_delegation[i] == 0; |
| } |
| } |
| foreach(m_mode_interrupt_delegation[i]) { |
| if(!support_supervisor_mode || no_delegation) { |
| m_mode_interrupt_delegation[i] == 0; |
| } |
| if(!(i inside {S_SOFTWARE_INTR, S_TIMER_INTR, S_EXTERNAL_INTR})) { |
| m_mode_interrupt_delegation[i] == 0; |
| } |
| } |
| } |
| |
| constraint ra_c { |
| ra dist {RA := 5, T1 := 2, [SP:T0] :/ 1, [T2:T6] :/ 2}; |
| ra != sp; |
| ra != tp; |
| ra != ZERO; |
| } |
| |
| constraint sp_tp_c { |
| sp != tp; |
| sp dist {SP := 6, RA := 1, [GP:T6] :/ 3}; |
| !(sp inside {GP, RA, ZERO}); |
| !(tp inside {GP, RA, ZERO}); |
| } |
| |
| constraint reserve_scratch_reg_c { |
| scratch_reg != ZERO; |
| scratch_reg != sp; |
| scratch_reg != tp; |
| } |
| |
| constraint gpr_c { |
| foreach (gpr[i]) { |
| !(gpr[i] inside {sp, tp, scratch_reg, ZERO, RA, GP}); |
| } |
| unique {gpr}; |
| } |
| |
| constraint addr_translaction_c { |
| solve init_privileged_mode before virtual_addr_translation_on; |
| if ((init_privileged_mode != MACHINE_MODE) && (SATP_MODE != BARE)) { |
| virtual_addr_translation_on == 1'b1; |
| } else { |
| virtual_addr_translation_on == 1'b0; |
| } |
| } |
| |
| constraint floating_point_c { |
| if (enable_floating_point) { |
| mstatus_fs == 2'b01; |
| } else { |
| mstatus_fs == 2'b00; |
| } |
| } |
| |
| `uvm_object_utils_begin(riscv_instr_gen_config) |
| `uvm_field_int(main_program_instr_cnt, UVM_DEFAULT) |
| `uvm_field_sarray_int(sub_program_instr_cnt, UVM_DEFAULT) |
| `uvm_object_utils_end |
| |
| function new (string name = ""); |
| string s; |
| super.new(name); |
| init_delegation(); |
| inst = uvm_cmdline_processor::get_inst(); |
| get_int_arg_value("+num_of_tests=", num_of_tests); |
| get_int_arg_value("+enable_page_table_exception=", enable_page_table_exception); |
| get_bool_arg_value("+enable_interrupt=", enable_interrupt); |
| get_bool_arg_value("+enable_timer_irq=", enable_timer_irq); |
| get_int_arg_value("+num_of_sub_program=", num_of_sub_program); |
| get_int_arg_value("+instr_cnt=", instr_cnt); |
| get_bool_arg_value("+no_ebreak=", no_ebreak); |
| get_bool_arg_value("+no_dret=", no_dret); |
| get_bool_arg_value("+no_wfi=", no_wfi); |
| get_bool_arg_value("+no_branch_jump=", no_branch_jump); |
| get_bool_arg_value("+no_load_store=", no_load_store); |
| get_bool_arg_value("+no_csr_instr=", no_csr_instr); |
| get_bool_arg_value("+enable_illegal_csr_instruction=", enable_illegal_csr_instruction); |
| get_bool_arg_value("+allow_sfence_exception=", allow_sfence_exception); |
| get_bool_arg_value("+no_data_page=", no_data_page); |
| get_bool_arg_value("+no_directed_instr=", no_directed_instr); |
| get_bool_arg_value("+no_fence=", no_fence); |
| get_bool_arg_value("+no_delegation=", no_delegation); |
| get_int_arg_value("+illegal_instr_ratio=", illegal_instr_ratio); |
| get_int_arg_value("+hint_instr_ratio=", hint_instr_ratio); |
| get_bool_arg_value("+enable_unaligned_load_store=", enable_unaligned_load_store); |
| get_bool_arg_value("+force_m_delegation=", force_m_delegation); |
| get_bool_arg_value("+force_s_delegation=", force_s_delegation); |
| get_bool_arg_value("+require_signature_addr=", require_signature_addr); |
| get_bool_arg_value("+disable_compressed_instr=", disable_compressed_instr); |
| get_bool_arg_value("+randomize_csr=", randomize_csr); |
| if (this.require_signature_addr) begin |
| get_hex_arg_value("+signature_addr=", signature_addr); |
| end |
| get_bool_arg_value("+gen_debug_section=", gen_debug_section); |
| get_bool_arg_value("+bare_program_mode=", bare_program_mode); |
| get_int_arg_value("+num_debug_sub_program=", num_debug_sub_program); |
| get_bool_arg_value("+enable_ebreak_in_debug_rom=", enable_ebreak_in_debug_rom); |
| get_bool_arg_value("+set_dcsr_ebreak=", set_dcsr_ebreak); |
| get_bool_arg_value("+enable_debug_single_step=", enable_debug_single_step); |
| get_bool_arg_value("+enable_floating_point=", enable_floating_point); |
| if(inst.get_arg_value("+boot_mode=", boot_mode_opts)) begin |
| `uvm_info(get_full_name(), $sformatf( |
| "Got boot mode option - %0s", boot_mode_opts), UVM_LOW) |
| case(boot_mode_opts) |
| "m" : init_privileged_mode = MACHINE_MODE; |
| "s" : init_privileged_mode = SUPERVISOR_MODE; |
| "u" : init_privileged_mode = USER_MODE; |
| default: `uvm_fatal(get_full_name(), |
| $sformatf("Illegal boot mode option - %0s", boot_mode_opts)) |
| endcase |
| init_privileged_mode.rand_mode(0); |
| end |
| `uvm_info(`gfn, $sformatf("riscv_instr_pkg::supported_privileged_mode = %0d", |
| riscv_instr_pkg::supported_privileged_mode.size()), UVM_LOW) |
| void'(inst.get_arg_value("+asm_test_suffix=", asm_test_suffix)); |
| // Directed march list from the runtime options, ex. RV32I, RV32M etc. |
| void'(inst.get_arg_value("+march=", s)); |
| if(s != "") begin |
| string cmdline_march_list[$]; |
| riscv_instr_group_t march; |
| uvm_split_string(s, ",", cmdline_march_list); |
| riscv_instr_pkg::supported_isa.delete(); |
| foreach(cmdline_march_list[i]) begin |
| if(uvm_enum_wrapper#(riscv_instr_group_t)::from_name( |
| cmdline_march_list[i].toupper(), march)) begin |
| riscv_instr_pkg::supported_isa.push_back(march); |
| end else begin |
| `uvm_fatal(get_full_name(), $sformatf( |
| "Invalid march %0s specified in command line", cmdline_march_list[i])) |
| end |
| end |
| end |
| if (!(RV32C inside {supported_isa})) begin |
| disable_compressed_instr = 1; |
| end |
| setup_instr_distribution(); |
| endfunction |
| |
| function void setup_instr_distribution(); |
| string opts; |
| int val; |
| get_int_arg_value("+dist_control_mode=", dist_control_mode); |
| if (dist_control_mode == 1) begin |
| riscv_instr_category_t category; |
| category = category.first; |
| do begin |
| opts = {$sformatf("dist_%0s=", category.name()), "%d"}; |
| opts = opts.tolower(); |
| if ($value$plusargs(opts, val)) begin |
| category_dist[category] = val; |
| end else begin |
| category_dist[category] = 10; // Default ratio |
| end |
| `uvm_info(`gfn, $sformatf("Set dist[%0s] = %0d", |
| category.name(), category_dist[category]), UVM_LOW) |
| category = category.next; |
| end |
| while(category != category.first); |
| end |
| endfunction |
| |
| // Initialize the exception/interrupt delegation associate array, set all delegation default to 0 |
| virtual function void init_delegation(); |
| exception_cause_t cause; |
| interrupt_cause_t intr_cause; |
| cause = cause.first; |
| // Init exception delegation array |
| do begin |
| m_mode_exception_delegation[cause] = 1'b0; |
| s_mode_exception_delegation[cause] = 1'b0; |
| cause = cause.next; |
| end |
| while(cause != cause.first); |
| // Init interrupt delegation array |
| intr_cause = intr_cause.first; |
| do begin |
| m_mode_interrupt_delegation[intr_cause] = 1'b0; |
| s_mode_interrupt_delegation[intr_cause] = 1'b0; |
| intr_cause = intr_cause.next; |
| end |
| while(intr_cause != intr_cause.first); |
| endfunction |
| |
| function void pre_randomize(); |
| foreach (riscv_instr_pkg::supported_privileged_mode[i]) begin |
| if(riscv_instr_pkg::supported_privileged_mode[i] == SUPERVISOR_MODE) |
| support_supervisor_mode = 1; |
| end |
| endfunction |
| |
| function void get_non_reserved_gpr(); |
| endfunction |
| |
| function void post_randomize(); |
| // Setup the list all reserved registers |
| reserved_regs = {tp, sp, scratch_reg}; |
| // Need to save all loop registers, and RA/T0 |
| min_stack_len_per_program = 2 * (XLEN/8); |
| // Check if the setting is legal |
| check_setting(); |
| endfunction |
| |
| function void check_setting(); |
| bit support_64b; |
| bit support_128b; |
| foreach (riscv_instr_pkg::supported_isa[i]) begin |
| if (riscv_instr_pkg::supported_isa[i] inside {RV64I, RV64M, RV64A, RV64F, RV64D, RV64C}) begin |
| support_64b = 1'b1; |
| end else if (riscv_instr_pkg::supported_isa[i] inside {RV128I, RV128C}) begin |
| support_128b = 1'b1; |
| end |
| end |
| if (support_128b && XLEN != 128) begin |
| `uvm_fatal(`gfn, "XLEN should be set to 128 based on riscv_instr_pkg::supported_isa setting") |
| end |
| if (!support_128b && support_64b && XLEN != 64) begin |
| `uvm_fatal(`gfn, "XLEN should be set to 64 based on riscv_instr_pkg::supported_isa setting") |
| end |
| if (!(support_128b || support_64b) && XLEN != 32) begin |
| `uvm_fatal(`gfn, "XLEN should be set to 32 based on riscv_instr_pkg::supported_isa setting") |
| end |
| if (!(support_128b || support_64b) && !(SATP_MODE inside {SV32, BARE})) begin |
| `uvm_fatal(`gfn, $sformatf("SATP mode %0s is not supported for RV32G ISA", SATP_MODE.name())) |
| end |
| endfunction |
| |
| // Get an integer argument from comand line |
| function void get_int_arg_value(string cmdline_str, ref int val); |
| string s; |
| if(inst.get_arg_value(cmdline_str, s)) begin |
| val = s.atoi(); |
| end |
| endfunction |
| |
| // Get a bool argument from comand line |
| function void get_bool_arg_value(string cmdline_str, ref bit val); |
| string s; |
| if(inst.get_arg_value(cmdline_str, s)) begin |
| val = s.atobin(); |
| end |
| endfunction |
| |
| // Get a hex argument from command line |
| function void get_hex_arg_value(string cmdline_str, ref int val); |
| string s; |
| if(inst.get_arg_value(cmdline_str, s)) begin |
| val = s.atohex(); |
| end |
| endfunction |
| |
| // Build instruction template |
| virtual function void build_instruction_template(bit skip_instr_exclusion = 0); |
| riscv_instr_name_t instr_name; |
| riscv_instr_name_t excluded_instr[$]; |
| excluded_instr = {INVALID_INSTR}; |
| if (!skip_instr_exclusion) begin |
| get_excluded_instr(excluded_instr); |
| end |
| instr_name = instr_name.first; |
| do begin |
| riscv_instr_base instr; |
| if (!(instr_name inside {unsupported_instr, excluded_instr})) begin |
| instr = riscv_instr_base::type_id::create("instr"); |
| `DV_CHECK_RANDOMIZE_WITH_FATAL(instr, instr_name == local::instr_name;) |
| if ((instr.group inside {supported_isa}) && |
| !(disable_compressed_instr && instr.is_compressed) && |
| !(!enable_floating_point && (instr.group inside {RV32F, RV64F, RV32D, RV64D}))) begin |
| `uvm_info(`gfn, $sformatf("Adding [%s] %s to the list", |
| instr.group.name(), instr.instr_name.name()), UVM_HIGH) |
| instr_group[instr.group].push_back(instr_name); |
| instr_category[instr.category].push_back(instr_name); |
| instr_template[instr_name] = instr; |
| end |
| end |
| instr_name = instr_name.next; |
| end |
| while (instr_name != instr_name.first); |
| endfunction |
| |
| virtual function void build_instruction_list(); |
| basic_instr = {instr_category[SHIFT], instr_category[ARITHMETIC], |
| instr_category[LOGICAL], instr_category[COMPARE]}; |
| basic_instr = {basic_instr, EBREAK}; |
| foreach(riscv_instr_pkg::supported_isa[i]) begin |
| if (riscv_instr_pkg::supported_isa[i] inside {RV32C, RV64C, RV128C, RV32DC, RV32FC}) begin |
| basic_instr = {basic_instr, C_EBREAK}; |
| break; |
| end |
| end |
| if (no_dret == 0) begin |
| basic_instr = {basic_instr, DRET}; |
| end |
| if (no_fence == 0) begin |
| basic_instr = {basic_instr, instr_category[SYNCH]}; |
| end |
| // TODO: Support CSR instruction in other mode |
| if ((no_csr_instr == 0) && (init_privileged_mode == MACHINE_MODE)) begin |
| `uvm_info(`gfn, $sformatf("Adding CSR instr, mode: %0s", init_privileged_mode.name()), UVM_LOW) |
| basic_instr = {basic_instr, instr_category[CSR]}; |
| end |
| if (no_wfi == 0) begin |
| basic_instr = {basic_instr, WFI}; |
| end |
| endfunction |
| |
| virtual function void get_excluded_instr(ref riscv_instr_name_t excluded[$]); |
| // Below instrutions will modify stack pointer, not allowed in normal instruction stream. |
| // It can be used in stack operation instruction stream. |
| excluded = {excluded, C_SWSP, C_SDSP, C_ADDI16SP}; |
| if (!enable_sfence) begin |
| excluded = {excluded, SFENCE_VMA}; |
| end |
| if (no_fence) begin |
| excluded = {excluded, FENCE, FENCE_I, SFENCE_VMA}; |
| end |
| // TODO: Support C_ADDI4SPN |
| excluded = {excluded, C_ADDI4SPN}; |
| endfunction |
| |
| endclass |