diff --git a/vendor/google_riscv-dv.lock.hjson b/vendor/google_riscv-dv.lock.hjson index 19fa11dd..3ceb7e7e 100644 --- a/vendor/google_riscv-dv.lock.hjson +++ b/vendor/google_riscv-dv.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/google/riscv-dv - rev: 17d79847e376a591cb3dcaae7601c98b0e70e8ac + rev: 2e5251846efb5fa42882a2b6b571ef8693e8cd60 } } diff --git a/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_cov_instr.py b/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_cov_instr.py index 347398db..1f4187d4 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_cov_instr.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_cov_instr.py @@ -63,7 +63,6 @@ class riscv_cov_instr: def __init__(self): # Program counter (PC) of the instruction self.pc = vsc.bit_t(rcs.XLEN) - rcs.XLEN) # Program counter (PC) of the instruction self.instr = None # self.gpr = None # destination operand of the instruction self.binary = vsc.bit_t(32) # Instruction binary diff --git a/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr.py b/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr.py index 7c69763c..41511415 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr.py @@ -172,16 +172,15 @@ class riscv_instr: # allowed_categories = [] for items in include_category: - allowed_instr.append(self.instr_category[items]) - + allowed_instr.extend(self.instr_category[items]) for items in exclude_category: if(items in self.instr_category): - disallowed_instr.append(self.instr_category[items]) + disallowed_instr.extend(self.instr_category[items]) for items in include_group: - allowed_instr.append(self.instr_group[items]) + allowed_instr.extend(self.instr_group[items]) for items in exclude_group: if(items in self.instr_group): - disallowed_instr.append(self.instr_group[items]) + disallowed_instr.extend(self.instr_group[items]) disallowed_instr.extend(exclude_instr) diff --git a/vendor/google_riscv-dv/pygen/pygen_src/riscv_asm_program_gen.py b/vendor/google_riscv-dv/pygen/pygen_src/riscv_asm_program_gen.py index 1bc65cd7..7c48f537 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/riscv_asm_program_gen.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_asm_program_gen.py @@ -15,11 +15,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import subprocess import logging import random +import copy +import sys from bitstring import BitArray from pygen_src.riscv_instr_sequence import riscv_instr_sequence from pygen_src.riscv_instr_pkg import pkg_ins, privileged_reg_t, privileged_mode_t, mtvec_mode_t -from pygen_src.riscv_instr_gen_config import cfg +from pygen_src.riscv_instr_gen_config import cfg, args, args_dict from pygen_src.target.rv32i import riscv_core_setting as rcs +from pygen_src.riscv_instr_stream import riscv_rand_instr_stream +from pygen_src.riscv_utils import factory ''' RISC-V assembly program generator @@ -33,7 +37,7 @@ class riscv_asm_program_gen: def __init__(self): self.instr_stream = [] - self.directed_instr_stream_ratio = [] + self.directed_instr_stream_ratio = {} self.hart = 0 self.page_table_list = [] self.main_program = [] @@ -77,12 +81,18 @@ class riscv_asm_program_gen: # Generate main program gt_lbl_str = pkg_ins.get_label("main", hart) + label_name = gt_lbl_str gt_lbl_str = riscv_instr_sequence() self.main_program.append(gt_lbl_str) self.main_program[hart].instr_cnt = cfg.main_program_instr_cnt self.main_program[hart].is_debug_program = 0 - self.main_program[hart].label_name = "main" - self.main_program[hart].gen_instr(is_main_program = 1, no_branch = cfg.no_branch_jump) + self.main_program[hart].label_name = label_name + self.generate_directed_instr_stream(hart=hart, + label=self.main_program[hart].label_name, + original_instr_cnt=self.main_program[hart].instr_cnt, + min_insert_cnt=1, + instr_stream=self.main_program[hart].directed_instr) + self.main_program[hart].gen_instr(is_main_program=1, no_branch=cfg.no_branch_jump) self.main_program[hart].post_process_instr() self.main_program[hart].generate_instr_stream() @@ -577,14 +587,60 @@ class riscv_asm_program_gen: pass def add_directed_instr_stream(self, name, ratio): - pass + self.directed_instr_stream_ratio[name] = ratio + logging.info("Adding directed instruction stream:%0s ratio:%0d/1000", name, ratio) def get_directed_instr_stream(self): - pass + opts = [] + for i in range(cfg.max_directed_instr_stream_seq): + arg = "directed_instr_{}".format(i) + stream_name_opts = "stream_name_{}".format(i) + stream_freq_opts = "stream_freq_{}".format(i) + if(arg in args): + val = args_dict[arg] + opts = val.split(",") + if(len(opts) != 2): + logging.critical( + "Incorrect directed instruction format : %0s, expect: name,ratio", val) + else: + self.add_directed_instr_stream(opts[0], int(opts[1])) + elif(stream_name_opts in args and stream_freq_opts in args): + stream_name = args_dict[stream_name_opts] + stream_freq = args_dict[stream_freq_opts] + self.add_directed_instr_stream(stream_name, stream_freq) - def generate_directed_instr_stream(self, hart = 0, label = "", original_instr_cnt = None, + def generate_directed_instr_stream(self, hart = 0, label = "", original_instr_cnt = 0, min_insert_cnt = 0, kernel_mode = 0, instr_stream = []): - pass + instr_insert_cnt = 0 + idx = 0 + if(cfg.no_directed_instr): + return + for instr_stream_name in self.directed_instr_stream_ratio: + instr_insert_cnt = int(original_instr_cnt * + self.directed_instr_stream_ratio[instr_stream_name] // 1000) + if(instr_insert_cnt <= min_insert_cnt): + instr_insert_cnt = min_insert_cnt + logging.info("Insert directed instr stream %0s %0d/%0d times", + instr_stream_name, instr_insert_cnt, original_instr_cnt) + for i in range(instr_insert_cnt): + name = "{}_{}".format(instr_stream_name, i) + object_h = factory(instr_stream_name) + object_h.name = name + if(object_h is None): + logging.critical("Cannot create instr stream %0s", name) + sys.exit(1) + new_instr_stream = copy.copy(object_h) + if(new_instr_stream): + new_instr_stream.hart = hart + new_instr_stream.label = "{}_{}".format(label, idx) + new_instr_stream.kernel_mode = kernel_mode + new_instr_stream.randomize() + instr_stream.append(new_instr_stream) + else: + logging.critical("Cannot Create instr stream %0s", name) + sys.exit(1) + idx += 1 + random.shuffle(instr_stream) def gen_debug_rom(self, hart): pass diff --git a/vendor/google_riscv-dv/pygen/pygen_src/riscv_defines.py b/vendor/google_riscv-dv/pygen/pygen_src/riscv_defines.py index bc1e5f5b..16278839 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/riscv_defines.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_defines.py @@ -34,3 +34,14 @@ def DEFINE_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp=imm_ "valid": riscv_instr.register(instr_n) }) g[class_name] = NewClass + + +''' +TODO +@vsc.constraint +def add_pseudo_instr(self, instr_n, instr_format, instr_category, instr_group): + with vsc.if_then(self.pseudo_instr_name == instr_n): + self.format == instr_format.name + self.category == instr_category.name + self.group == instr_group.name +''' diff --git a/vendor/google_riscv-dv/pygen/pygen_src/riscv_directed_instr_lib.py b/vendor/google_riscv-dv/pygen/pygen_src/riscv_directed_instr_lib.py new file mode 100644 index 00000000..318ae64d --- /dev/null +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_directed_instr_lib.py @@ -0,0 +1,98 @@ +""" +Copyright 2020 Google LLC +Copyright 2020 PerfectVIPs Inc. + +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. +""" + +import vsc +from enum import IntEnum, auto +from pygen_src.riscv_instr_stream import riscv_rand_instr_stream +from pygen_src.isa.riscv_instr import riscv_instr_ins +from pygen_src.riscv_instr_gen_config import cfg +from pygen_src.riscv_instr_pkg import riscv_reg_t, riscv_pseudo_instr_name_t +from pygen_src.target.rv32i import riscv_core_setting as rcs +from pygen_src.riscv_pseudo_instr import riscv_pseudo_instr + + +class riscv_directed_instr_stream(riscv_rand_instr_stream): + + def __init__(self): + super().__init__() + self.name = "" + self.label = "" + + def post_randomize(self): + for i in range(len(self.instr_list)): + self.instr_list[i].has_label = 0 + self.instr_list[i].atomic = 1 + self.instr_list[0].comment = "Start %0s" % (self.name) + self.instr_list[-1].comment = "End %0s" % (self.name) + if self.label != "": + self.instr_list[0].label = self.label + self.instr_list[0].has_label = 1 + + +class int_numeric_e(IntEnum): + NormalValue = auto() + Zero = auto() + AllOne = auto() + NegativeMax = auto() + + +@vsc.randobj +class riscv_int_numeric_corner_stream(riscv_directed_instr_stream): + def __init__(self): + super().__init__() + self.num_of_avail_regs = 10 + self.num_of_instr = vsc.rand_uint8_t() + self.init_val = vsc.rand_list_t(vsc.rand_bit_t(rcs.XLEN - 1), sz = 10) + self.init_val_type = vsc.rand_list_t(vsc.enum_t(int_numeric_e), sz =10) + self.init_instr = [] + + @vsc.constraint + def init_val_c(self): + # TO DO + # solve init_val_type before init_val; + self.init_val_type.size == self.num_of_avail_regs + self.init_val.size == self.num_of_avail_regs + self.num_of_instr in vsc.rangelist(vsc.rng(15, 30)) + + @vsc.constraint + def avail_regs_c(self): + self.avail_regs.size == self.num_of_avail_regs + vsc.unique(self.avail_regs) + with vsc.foreach(self.avail_regs, idx = True) as i: + self.avail_regs[i].not_inside(cfg.reserved_regs) + self.avail_regs[i] != riscv_reg_t.ZERO + + def pre_randomize(self): + pass + + def post_randomize(self): + self.init_instr = [None] * self.num_of_avail_regs + for i in range(len(self.init_val_type)): + if self.init_val_type[i] == int_numeric_e.Zero: + self.init_val[i] = 0 + elif self.init_val_type[i] == int_numeric_e.AllOne: + self.init_val[i] = 1 + elif self.init_val_type[i] == int_numeric_e.NegativeMax: + self.init_val[i] = 1 << (rcs.XLEN - 1) + self.init_instr[i] = riscv_pseudo_instr() + self.init_instr[i].rd = self.avail_regs[i] + self.init_instr[i].pseudo_instr_name = riscv_pseudo_instr_name_t.LI + self.init_instr[i].imm_str = "0x%0x" % (self.init_val[i]) + self.instr_list.append(self.init_instr[i]) + for i in range(self.num_of_instr): + instr = riscv_instr_ins.get_rand_instr( + include_category = ['ARITHMETIC'], + exclude_group = ['RV32C', 'RV64C', 'RV32F', 'RV64F', 'RV32D', 'RV64D']) + instr = self.randomize_gpr(instr) + self.instr_list.append(instr) + super().post_randomize() diff --git a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_cover_group.py b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_cover_group.py index 2ced738e..b2349c3e 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_cover_group.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_cover_group.py @@ -178,6 +178,7 @@ class riscv_instr_cover_group: '''TODO: covergroup inheritance is broken at the moment. The workaround will be switched back to the inheritance approach once it gets fixed''' + # @vsc.covergroup # class lb_cg(load_instr_cg): # def __init__(self, instr): @@ -1049,8 +1050,8 @@ class riscv_instr_cover_group: cp_t=vsc.enum_t(operand_sign_e)) self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit, bins={ + "Non-taken": vsc.bin(0), "Taken" : vsc.bin(1), - "Non-taken": vsc.bin(0) } ) self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, @@ -1334,17 +1335,73 @@ class riscv_instr_cover_group: self.cp_align = vsc.cross([self.cp_imm_align, self.cp_rs1_align]) self.cp_ras = vsc.cross([self.cp_rs1_link, self.cp_rd_link]) + '''CSR instructions''' + + @vsc.covergroup + class csrrw_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + + @vsc.covergroup + class opcode_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_opcode = vsc.coverpoint(lambda: instr.binary[7:2], + bins={ + "a": vsc.bin_array([], [0, 31]) + } + ) + + @vsc.covergroup + class rv32i_misc_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_misc = vsc.coverpoint(lambda: instr.instr, + cp_t=vsc.enum_t(rv32i_misc_instrs)) + + @vsc.covergroup + class mepc_alignment_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_align = vsc.coverpoint(lambda: instr.rd_value[2:0], + bins={ + "Zero": vsc.bin(0), + "Two" : vsc.bin(2) + } + ) + def sample(self, instr): self.instr_cnt += 1 if self.instr_cnt > 1: instr.check_hazard_condition(self.pre_instr) - # TODO: sampling based on the instruction binary + # TODO: sampling for hint, compressed, and illegal_compressed insts + if instr.binary[2:0] == 3: + opcode_cg = self.opcode_cg(instr) + opcode_cg.sample() try: cg = eval("self." + instr.instr.name.lower() + "_cg")(instr) cg.sample() except Exception: logging.info("Covergroup for instr {} is not supported yet".format( instr.instr.name)) + if instr.group.name == "RV32I": + rv32i_misc_cg = self.rv32i_misc_cg(instr) + rv32i_misc_cg.sample() + if instr.category.name == "CSR": + # MEPC + if instr.csr == 833: + mepc_alignment_cg = self.mepc_alignment_cg(instr) + mepc_alignment_cg.sample() self.pre_instr = instr def reset(self): diff --git a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_gen_config.py b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_gen_config.py index 7ba35b56..26f49aa2 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_gen_config.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_gen_config.py @@ -111,10 +111,22 @@ class riscv_instr_gen_config: self.num_of_harts = argv.num_of_harts self.fix_sp = argv.fix_sp self.use_push_data_section = argv.use_push_data_section - self.boot_mode_opts = "" + self.boot_mode_opts = argv.boot_mode_opts + + if(self.boot_mode_opts): + logging.info("Got boot mode option - %0s", self.boot_mode_opts) + if(self.boot_mode_opts == "m"): + self.init_privileged_mode = privileged_mode_t.MACHINE_MODE.name + elif(self.boot_mode_opts == "s"): + self.init_privileged_mode = privileged_mode_t.SUPERVISOR_MODE.name + elif(self.boot_mode_opts == "u"): + self.init_privileged_mode = privileged_mode_t.USER_MODE.name + else: + logging.error("Illegal boot mode option - %0s", self.boot_mode_opts) + self.enable_page_table_exception = argv.enable_page_table_exception self.no_directed_instr = argv.no_directed_instr - self.asm_test_suffix = "" + self.asm_test_suffix = argv.asm_test_suffix self.enable_interrupt = argv.enable_interrupt self.enable_nested_interrupt = argv.enable_nested_interrupt self.enable_timer_irq = argv.enable_timer_irq @@ -153,11 +165,16 @@ class riscv_instr_gen_config: self.enable_floating_point = argv.enable_floating_point self.enable_vector_extension = argv.enable_vector_extension self.enable_b_extension = argv.enable_b_extension - # Commenting out for now - # self.enable_bitmanip_groups = ['ZBB', 'ZBS', 'ZBP', 'ZBE', 'ZBF', - # 'ZBC', 'ZBR', 'ZBM', 'ZBT', 'ZB_TMP'] + self.enable_bitmanip_groups = argv.enable_bitmanip_groups self.dist_control_mode = 0 self.category_dist = {} + self.march_isa = argv.march_isa + + if(len(self.march_isa) != 0): + rcs.supported_isa = self.march_isa + + if(rcs.supported_isa != 'RV32C'): + self.disable_compressed_instr = 1 @vsc.constraint def gpr_c(self): @@ -386,35 +403,35 @@ def parse_args(): choices = [0, 1], type = int, default = 0) parse.add_argument('--enable_b_extension', help = 'enable_b_extension', choices = [0, 1], type = int, default = 0) - + parse.add_argument('--enable_bitmanip_groups', help = 'enable_bitmanip_groups', + default = ['ZBB', 'ZBS', 'ZBP', 'ZBE', 'ZBF', + 'ZBC', 'ZBR', 'ZBM', 'ZBT', 'ZB_TMP'], nargs = '*') + parse.add_argument('--boot_mode_opts', help = 'boot_mode_opts', default = "") + parse.add_argument('--asm_test_suffix', help = 'asm_test_suffix', default = "") + parse.add_argument('--march_isa', help = 'march_isa', default = [], + choices = [i.name for i in riscv_instr_group_t], nargs = '*') + parse.add_argument('--directed_instr_0', help = 'directed_instr_0', + default = "riscv_int_numeric_corner_stream,4") + parse.add_argument('--stream_name_opts', help = 'stream_name_0', + default = "riscv_load_store_rand_instr_stream") + parse.add_argument('--stream_freq_opts', help = 'stream_freq_0', default = 4) # TODO ''' - cmdline_enum_processor #(b_ext_group_t)::get_array_values("+enable_bitmanip_groups=", - enable_bitmanip_groups); - 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); - addr_translaction_rnd_order_c.constraint_mode(0); + if ($value$plusargs("tvec_alignment=%0d", tvec_alignment)) begin + tvec_alignment.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. - cmdline_enum_processor #(riscv_instr_group_t)::get_array_values("+march=", march_isa); - if (march_isa.size != 0) riscv_instr_pkg::supported_isa = march_isa; - ''' + vector_cfg = riscv_vector_cfg::type_id::create("vector_cfg"); + pmp_cfg = riscv_pmp_cfg::type_id::create("pmp_cfg"); + pmp_cfg.rand_mode(pmp_cfg.pmp_randomize); + pmp_cfg.initialize(require_signature_addr); + setup_instr_distribution(); + get_invalid_priv_lvl_csr(); + ''' args = parse.parse_args() return args args = parse_args() +args_dict = vars(args) cfg = riscv_instr_gen_config(args) diff --git a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_pkg.py b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_pkg.py index c5f2c930..541a9795 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_pkg.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_pkg.py @@ -24,7 +24,7 @@ class mem_region_t: xwr = auto() -class satp_mode_t(Enum): +class satp_mode_t(IntEnum): BARE = 0b0000 SV32 = 0b0001 SV39 = 0b1000 @@ -33,7 +33,7 @@ class satp_mode_t(Enum): SV64 = 0b1011 -class f_rounding_mode_t(Enum): +class f_rounding_mode_t(IntEnum): RNE = 0b000 RTZ = 0b001 RDN = 0b010 @@ -41,26 +41,26 @@ class f_rounding_mode_t(Enum): RMM = 0b100 -class mtvec_mode_t(Enum): +class mtvec_mode_t(IntEnum): DIRECT = 0b00 VECTORED = 0b01 -class imm_t(Enum): +class imm_t(IntEnum): IMM = 0 UIMM = auto() NZUIMM = auto() NZIMM = auto() -class privileged_mode_t(Enum): +class privileged_mode_t(IntEnum): USER_MODE = 0b00 SUPERVISOR_MODE = 0b01 RESERVED_MODE = 0b10 MACHINE_MODE = 0b11 -class riscv_instr_group_t(Enum): +class riscv_instr_group_t(IntEnum): RV32I = 0 RV64I = auto() RV32M = auto() @@ -85,7 +85,7 @@ class riscv_instr_group_t(Enum): RV64X = auto() -class riscv_instr_name_t(Enum): +class riscv_instr_name_t(IntEnum): LUI = 0 AUIPC = auto() JAL = auto() @@ -595,7 +595,7 @@ class riscv_reg_t(IntEnum): T6 = auto() -class riscv_fpr_t(Enum): +class riscv_fpr_t(IntEnum): FT0 = 0 FT1 = auto() FT2 = auto() @@ -630,7 +630,7 @@ class riscv_fpr_t(Enum): FT11 = auto() -class riscv_vreg_t(Enum): +class riscv_vreg_t(IntEnum): V0 = 0 V1 = auto() V2 = auto() @@ -665,7 +665,7 @@ class riscv_vreg_t(Enum): V31 = auto() -class riscv_instr_format_t(Enum): +class riscv_instr_format_t(IntEnum): J_FORMAT = 0 U_FORMAT = auto() I_FORMAT = auto() @@ -689,7 +689,7 @@ class riscv_instr_format_t(Enum): VS_FORMAT = auto() -class va_variant_t(Enum): +class va_variant_t(IntEnum): VV = 0 VI = auto() VX = auto() @@ -705,7 +705,7 @@ class va_variant_t(Enum): VM = auto() -class riscv_instr_category_t(Enum): +class riscv_instr_category_t(IntEnum): LOAD = 0 STORE = auto() SHIFT = auto() @@ -727,7 +727,7 @@ class riscv_instr_category_t(Enum): # typedef bit[11:0] riscv_csr_t; -class privileged_reg_t(Enum): +class privileged_reg_t(IntEnum): USTATUS = 0x000 UIE = 0x004 UTVEC = 0x005 @@ -958,7 +958,7 @@ class privileged_reg_t(Enum): VLENB = 0xC22 -class privileged_reg_fld_t(Enum): +class privileged_reg_fld_t(IntEnum): RSVD = 0 MXL = auto() EXTENSION = auto() @@ -967,30 +967,30 @@ class privileged_reg_fld_t(Enum): PPN = auto() -class privileged_level_t(Enum): +class privileged_level_t(IntEnum): M_LEVEL = 0b11 S_LEVEL = 0b01 U_LEVEL = 0b00 -class reg_field_access_t(Enum): +class reg_field_access_t(IntEnum): WPRI = 0 WLRL = auto() WARL = auto() -class riscv_pseudo_instr_name_t(Enum): +class riscv_pseudo_instr_name_t(IntEnum): LI = 0 LA = auto() -class data_pattern_t(Enum): +class data_pattern_t(IntEnum): RAND_DATA = 0 ALL_ZERO = auto() INCR_VAL = auto() -class pte_permission_t(Enum): +class pte_permission_t(IntEnum): NEXT_LEVEL_PAGE = 0b000 READ_ONLY_PAGE = 0b001 READ_WRITE_PAGE = 0b011 @@ -999,7 +999,7 @@ class pte_permission_t(Enum): R_W_EXECUTE_PAGE = 0b111 -class interrupt_cause_t(Enum): +class interrupt_cause_t(IntEnum): U_SOFTWARE_INTR = 0x0 S_SOFTWARE_INTR = 0x1 M_SOFTWARE_INTR = 0x3 @@ -1011,7 +1011,7 @@ class interrupt_cause_t(Enum): M_EXTERNAL_INTR = 0xB -class exception_cause_t(Enum): +class exception_cause_t(IntEnum): INSTRUCTION_ADDRESS_MISALIGNED = 0x0 INSTRUCTION_ACCESS_FAULT = 0x1 ILLEGAL_INSTRUCTION = 0x2 @@ -1028,7 +1028,7 @@ class exception_cause_t(Enum): STORE_AMO_PAGE_FAULT = 0xF -class misa_ext_t(Enum): +class misa_ext_t(IntEnum): MISA_EXT_A = 0 MISA_EXT_B = auto() MISA_EXT_C = auto() @@ -1071,6 +1071,15 @@ class branch_hazard_e(IntEnum): NO_HAZARD = 0 RAW_HAZARD = auto() + +# RV32I_MISC covergroup instructions +class rv32i_misc_instrs(IntEnum): + FENCE = 0 + FENCE_I = auto() + EBREAK = auto() + ECALL = auto() + MRET = auto() + # Ignore RAW_HAZARD for store lsu hazard class store_lsu_hazard_e(IntEnum): NO_HAZARD = 0 diff --git a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_sequence.py b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_sequence.py index a5bb12b0..fef67957 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_sequence.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_sequence.py @@ -16,7 +16,7 @@ import random from collections import defaultdict from pygen_src.riscv_instr_stream import riscv_rand_instr_stream from pygen_src.riscv_instr_gen_config import cfg -from pygen_src.riscv_instr_pkg import pkg_ins +from pygen_src.riscv_instr_pkg import pkg_ins, riscv_instr_category_t class riscv_instr_sequence: @@ -117,7 +117,7 @@ class riscv_instr_sequence: self.branch_idx[i] = random.randint(1, cfg.max_branch_step) while(j < len(self.instr_stream.instr_list)): - if((self.instr_stream.instr_list[j].category.name == "BRANCH") and + if((self.instr_stream.instr_list[j].category == riscv_instr_category_t.BRANCH) and (not self.instr_stream.instr_list[j].branch_assigned) and (not self.instr_stream.instr_list[j].is_illegal_instr)): ''' diff --git a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_stream.py b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_stream.py index ad4852a9..151066a3 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_stream.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_stream.py @@ -13,12 +13,14 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import random import logging import sys +import vsc from pygen_src.riscv_instr_pkg import riscv_instr_name_t,\ riscv_instr_category_t, riscv_reg_t from pygen_src.isa.riscv_instr import riscv_instr, riscv_instr_ins from pygen_src.riscv_instr_gen_config import cfg +@vsc.randobj class riscv_instr_stream: ''' Base class for RISC-V instruction stream @@ -30,9 +32,9 @@ class riscv_instr_stream: def __init__(self): self.instr_list = [] self.instr_cnt = 0 - self.label = " " + self.label = "" # User can specify a small group of available registers to generate various hazard condition - self.avail_regs = [] + self.avail_regs = vsc.randsz_list_t(vsc.enum_t(riscv_reg_t)) # Some additional reserved registers that should not be used as rd register # by this instruction stream self.reserved_rd = [] @@ -112,7 +114,7 @@ class riscv_instr_stream: if idx == 0: self.instr_list = new_instr + self.instr_list[idx:current_instr_cnt - 1] else: - self.instr_list = self.instr_list[0:idx - 1] + new_instr + \ + self.instr_list = self.instr_list[0:idx] + new_instr + \ self.instr_list[idx:current_instr_cnt - 1] def mix_instr_stream(self, new_instr, contained = 0): diff --git a/vendor/google_riscv-dv/pygen/pygen_src/riscv_pseudo_instr.py b/vendor/google_riscv-dv/pygen/pygen_src/riscv_pseudo_instr.py new file mode 100644 index 00000000..c573634f --- /dev/null +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_pseudo_instr.py @@ -0,0 +1,48 @@ +""" +Copyright 2020 Google LLC +Copyright 2020 PerfectVIPs Inc. + +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. + +""" + +import vsc +from pygen_src.isa.riscv_instr import riscv_instr +from pygen_src.riscv_instr_pkg import (riscv_pseudo_instr_name_t, riscv_instr_format_t, + riscv_instr_category_t, riscv_instr_group_t, pkg_ins) +# from pygen_src.riscv_defines import add_pseudo_instr + + +# Psuedo instructions are used to simplify assembly program writing +@vsc.randobj +class riscv_pseudo_instr(riscv_instr): + def __init__(self): + super().__init__() + self.process_load_store = 0 + self.format = riscv_instr_format_t.I_FORMAT + self.pseudo_instr_name = vsc.rand_enum_t(riscv_pseudo_instr_name_t) + + ''' + TODO + add_pseudo_instr(self, riscv_pseudo_instr_name_t.LI, riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.LOAD, riscv_instr_group_t.RV32I) + add_pseudo_instr(self, riscv_pseudo_instr_name_t.LA, riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.LOAD, riscv_instr_group_t.RV32I) + ''' + + def convert2asm(self, prefix = ""): + asm_str = pkg_ins.format_string(self.get_instr_name(), pkg_ins.MAX_INSTR_STR_LEN) + asm_str = "{}{}, {}".format(asm_str, self.rd.name, self.get_imm()) + + if(self.comment != ""): + asm_str = "{} #{}".format(asm_str, self.comment) + return asm_str.lower() + + def get_instr_name(self): + return self.pseudo_instr_name.name diff --git a/vendor/google_riscv-dv/pygen/pygen_src/riscv_utils.py b/vendor/google_riscv-dv/pygen/pygen_src/riscv_utils.py new file mode 100644 index 00000000..e1dc7108 --- /dev/null +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_utils.py @@ -0,0 +1,30 @@ +""" +Copyright 2020 Google LLC +Copyright 2020 PerfectVIPs Inc. + +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. + +""" +import sys +import logging +from pygen_src.riscv_directed_instr_lib import (riscv_directed_instr_stream, + riscv_int_numeric_corner_stream) + + +def factory(obj_of): + objs = { + "riscv_directed_instr_stream": riscv_directed_instr_stream, + "riscv_int_numeric_corner_stream": riscv_int_numeric_corner_stream + } + + try: + return objs[obj_of]() + except KeyError: + logging.critical("Cannot Create object of %s", obj_of) + sys.exit(1) diff --git a/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_base_test.py b/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_base_test.py index 7fa6b1e1..8058e8d7 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_base_test.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_base_test.py @@ -22,10 +22,12 @@ from pygen_src.riscv_asm_program_gen import riscv_asm_program_gen # NOQA class riscv_instr_base_test: def __init__(self): pass - asm = riscv_asm_program_gen() + for _ in range(cfg.num_of_tests): cfg.randomize() + asm = riscv_asm_program_gen() riscv_instr_ins.create_instr_list(cfg) - test_name = "riscv_asm_test_{}.S".format(_) + test_name = "riscv_arithmetic_basic_test_{}.S".format(_) + asm.get_directed_instr_stream() asm.gen_program() asm.gen_test_file(test_name) diff --git a/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_cov_test.py b/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_cov_test.py index 3b7303da..f54b9c22 100644 --- a/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_cov_test.py +++ b/vendor/google_riscv-dv/pygen/pygen_src/test/riscv_instr_cov_test.py @@ -116,6 +116,8 @@ class riscv_instr_cov_test: file.write(tabulate(table, headers, tablefmt="grid", numalign="center", stralign="center")) file.close() + # Write in xml format to be read by pyucis-viewer (visualization) + vsc.write_coverage_db("cov_db.xml") def post_process_trace(self): pass diff --git a/vendor/google_riscv-dv/scripts/gen_csr_test.py b/vendor/google_riscv-dv/scripts/gen_csr_test.py index 84c4fce9..c524e2b0 100644 --- a/vendor/google_riscv-dv/scripts/gen_csr_test.py +++ b/vendor/google_riscv-dv/scripts/gen_csr_test.py @@ -109,9 +109,9 @@ def get_rs1_val(iteration, xlen): 3) A randomly generated number """ if iteration == 0: - return bitarray(hex=f"0x{'a5'*int(xlen/8)}") + return bitarray(hex="0x{}".format('a5'*int(xlen/8))) elif iteration == 1: - return bitarray(hex=f"0x{'5a'*int(xlen/8)}") + return bitarray(hex="0x{}".format('5a'*int(xlen/8))) elif iteration == 2: val = bitarray(uint=0, length=xlen) # Must randomize all 32 bits, due to randomization library limitations @@ -193,7 +193,7 @@ def predict_csr_val(csr_op, rs1_val, csr_val, csr_write_mask, csr_read_mask): elif csr_op == 'csrrci': zero.append(rs1_val[-5:]) csr_write((~zero) & prediction, csr_val, csr_write_mask) - return f"0x{prediction.hex}" + return "0x{}".format(prediction.hex) def gen_setup(test_file): @@ -203,12 +203,12 @@ def gen_setup(test_file): Args: test_file: the file containing the generated assembly code. """ - test_file.write(f".macro init\n") - test_file.write(f".endm\n") - test_file.write(f".section .text.init\n") - test_file.write(f".globl _start\n") - test_file.write(f".option norvc\n") - test_file.write(f"_start:\n") + test_file.write(".macro init\n") + test_file.write(".endm\n") + test_file.write(".section .text.init\n") + test_file.write(".globl _start\n") + test_file.write(".option norvc\n") + test_file.write("_start:\n") def gen_csr_test_fail(test_file, end_addr): @@ -221,13 +221,13 @@ def gen_csr_test_fail(test_file, end_addr): test_file: the file containing the generated assembly test code. end_addr: address that should be written to at end of test """ - test_file.write(f"csr_fail:\n") - 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, 0x{end_addr}\n") - test_file.write(f"\tsw x1, 0(x2)\n") - test_file.write(f"\tj csr_fail\n") + test_file.write("csr_fail:\n") + test_file.write("\tli x1, {}\n".format(TEST_FAIL)) + test_file.write("\tslli x1, x1, 8\n") + test_file.write("\taddi x1, x1, {}\n".format(TEST_RESULT)) + test_file.write("\tli x2, 0x{}\n".format(end_addr)) + test_file.write("\tsw x1, 0(x2)\n") + test_file.write("\tj csr_fail\n") def gen_csr_test_pass(test_file, end_addr): @@ -240,13 +240,13 @@ def gen_csr_test_pass(test_file, end_addr): test_file: the file containing the generated assembly test code. end_addr: address that should be written to at end of test """ - test_file.write(f"csr_pass:\n") - 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, 0x{end_addr}\n") - test_file.write(f"\tsw x1, 0(x2)\n") - test_file.write(f"\tj csr_pass\n") + test_file.write("csr_pass:\n") + test_file.write("\tli x1, {}\n".format(TEST_PASS)) + test_file.write("\tslli x1, x1, 8\n") + test_file.write("\taddi x1, x1, {}\n".format(TEST_RESULT)) + test_file.write("\tli x2, 0x{}\n".format(end_addr)) + test_file.write("\tsw x1, 0(x2)\n") + test_file.write("\tj csr_pass\n") def gen_csr_instr(original_csr_map, csr_instructions, xlen, @@ -271,13 +271,13 @@ def gen_csr_instr(original_csr_map, csr_instructions, xlen, # pick two GPRs at random to act as source and destination registers # for CSR operations csr_map = copy.deepcopy(original_csr_map) - source_reg, dest_reg = [f"x{i}" for i in random.sample(range(1, 16), 2)] + source_reg, dest_reg = ["x{}".format(i) for i in random.sample(range(1, 16), 2)] csr_list = list(csr_map.keys()) - with open(f"{out}/riscv_csr_test_{i}.S", "w") as csr_test_file: + with open("{}/riscv_csr_test_{}.S".format(out, i), "w") as csr_test_file: gen_setup(csr_test_file) for csr in csr_list: csr_address, csr_val, csr_write_mask, csr_read_mask = csr_map.get(csr) - csr_test_file.write(f"\t# {csr}\n") + csr_test_file.write("\t# {}\n".format(csr)) for op in csr_instructions: for i in range(3): # hex string @@ -286,17 +286,17 @@ def gen_csr_instr(original_csr_map, csr_instructions, xlen, first_li = "" if op[-1] == "i": imm = rand_rs1_val[-5:] - csr_inst = f"\t{op} {dest_reg}, {csr_address}, 0b{imm.bin}\n" + csr_inst = "\t{} {}, {}, 0b{}\n".format(op, dest_reg, csr_address, imm.bin) imm_val = bitarray(uint=0, length=xlen-5) imm_val.append(imm) - predict_li = (f"\tli {source_reg}, " - f"{predict_csr_val(op, imm_val, csr_val, csr_write_mask, csr_read_mask)}\n") + predict_li = ("\tli {}, " + "{}\n".format(source_reg, predict_csr_val(op, imm_val, csr_val, csr_write_mask, csr_read_mask))) else: - first_li = f"\tli {source_reg}, 0x{rand_rs1_val.hex}\n" - csr_inst = f"\t{op} {dest_reg}, {csr_address}, {source_reg}\n" - predict_li = (f"\tli {source_reg}, " - f"{predict_csr_val(op, rand_rs1_val, csr_val, csr_write_mask, csr_read_mask)}\n") - branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n" + first_li = "\tli {}, 0x{}\n".format(source_reg, rand_rs1_val.hex) + csr_inst = "\t{} {}, {}, {}\n".format(op, dest_reg, csr_address, source_reg) + predict_li = ("\tli {}, " + "{}\n".format(source_reg, predict_csr_val(op, rand_rs1_val, csr_val, csr_write_mask, csr_read_mask))) + branch_check = "\tbne {}, {}, csr_fail\n".format(source_reg, dest_reg) csr_test_file.write(first_li) csr_test_file.write(csr_inst) csr_test_file.write(predict_li) @@ -306,11 +306,11 @@ def gen_csr_instr(original_csr_map, csr_instructions, xlen, been written to the CSR has not been tested. """ if csr == csr_list[-1] and op == csr_instructions[-1] and i == 2: - final_csr_read = f"\tcsrr {dest_reg}, {csr_address}\n" + final_csr_read = "\tcsrr {}, {}\n".format(dest_reg, csr_address) csrrs_read_mask = bitarray(uint=0, length=xlen) - final_li = (f"\tli {source_reg}, " - f"{predict_csr_val('csrrs', csrrs_read_mask, csr_val, csr_write_mask, csr_read_mask)}\n") - final_branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n" + final_li = ("\tli {}, " + "{}\n".format(source_reg, predict_csr_val('csrrs', csrrs_read_mask, csr_val, csr_write_mask, csr_read_mask))) + final_branch_check = "\tbne {}, {}, csr_fail\n".format(source_reg, dest_reg) csr_test_file.write(final_csr_read) csr_test_file.write(final_li) csr_test_file.write(final_branch_check) diff --git a/vendor/google_riscv-dv/src/isa/riscv_amo_instr.sv b/vendor/google_riscv-dv/src/isa/riscv_amo_instr.sv index 79be4801..f2d5f718 100644 --- a/vendor/google_riscv-dv/src/isa/riscv_amo_instr.sv +++ b/vendor/google_riscv-dv/src/isa/riscv_amo_instr.sv @@ -20,7 +20,7 @@ class riscv_amo_instr extends riscv_instr; rand bit rl; constraint aq_rl_c { - aq && rl == 0; + (aq && rl) == 0; } `uvm_object_utils(riscv_amo_instr)