diff --git a/vendor/google_riscv-dv.lock.hjson b/vendor/google_riscv-dv.lock.hjson index 446124a8..19fa11dd 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: 61755c001bec0433fb69458f74d95476d2101cf3 + rev: 17d79847e376a591cb3dcaae7601c98b0e70e8ac } } 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 new file mode 100644 index 00000000..347398db --- /dev/null +++ b/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_cov_instr.py @@ -0,0 +1,517 @@ +"""Copyright 2020 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. +""" + +import os +import sys +import vsc +import logging +from enum import Enum, IntEnum, auto +from bitstring import BitArray +from pygen.pygen_src.target.rv32i import riscv_core_setting as rcs +from pygen.pygen_src.riscv_instr_pkg import * + + +class operand_sign_e(IntEnum): + POSITIVE = 0 + NEGATIVE = auto() + + +class div_result_e(IntEnum): + DIV_NORMAL = 0 + DIV_BY_ZERO = auto() + DIV_OVERFLOW = auto() + + +class compare_result_e(IntEnum): + EQUAL = 0 + LARGER = auto() + SMALLER = auto() + + +class logical_similarity_e(IntEnum): + IDENTICAL = 0 + OPPOSITE = auto() + SIMILAR = auto() + DIFFERENT = auto() + + +class special_val_e(IntEnum): + NORMAL_VAL = 0 + MIN_VAL = auto() + MAX_VAL = auto() + ZERO_VAL = auto() + + +class riscv_cov_instr: + """ Class for a riscv instruction in functional coverage phase; + data parsed from the CSV file fill different fields of an instruction """ + # class attr. to keep track of reg_name:reg_value throughout the program + gpr_state = {} + + 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 + # self.mode = None # Instruction mode + self.trace = "None" # String representation of the instruction + # self.operands = "None" # Instruction operands (srcss/dests) + # self.pad = None # Not used + + self.rs1_value = vsc.int_t(rcs.XLEN) + self.rs2_value = vsc.int_t(rcs.XLEN) + self.rs3_value = vsc.int_t(rcs.XLEN) + self.rd_value = vsc.int_t(rcs.XLEN) + self.fs1_value = vsc.int_t(rcs.XLEN) + self.fs2_value = vsc.int_t(rcs.XLEN) + self.fs3_value = vsc.int_t(rcs.XLEN) + self.fd_value = vsc.int_t(rcs.XLEN) + + self.mem_addr = vsc.int_t(rcs.XLEN) + self.unaligned_pc = 0 + self.unaligned_mem_access = 0 + self.compressed = 0 + self.branch_hit = 0 + self.div_result = None + self.rs1_sign = 0 + self.rs2_sign = 0 + self.rs3_sign = 0 + self.fs1_sign = 0 + self.fs2_sign = 0 + self.fs3_sign = 0 + self.imm_sign = 0 + self.rd_sign = 0 + self.fd_sign = 0 + self.gpr_hazard = hazard_e.NO_HAZARD + self.lsu_hazard = hazard_e.NO_HAZARD + self.rs1_special_value = 0 + self.rs2_special_value = 0 + self.rs3_special_value = 0 + self.rd_special_value = 0 + self.imm_special_value = 0 + self.compare_result = 0 + self.logical_similarity = 0 + + self.group = None + self.format = None + self.category = None + self.imm_type = None + + self.csr = vsc.bit_t(12) + ''' TODO: rs2, rs1, rd, group, format, category, imm_type will be + changed to vsc.enum_t once the issue with set/get_val is fixed ''' + self.rs2 = 0 + self.rs1 = 0 + self.rd = 0 + self.imm = vsc.int_t(32) + self.has_rs1 = 1 + self.has_rs2 = 1 + self.has_rd = 1 + self.has_imm = 1 + self.imm_len = 0 + + def assign_attributes(self): + attr_list = get_attr_list(self.instr) + self.format = attr_list[0] + self.category = attr_list[1] + self.group = attr_list[2] + self.imm_type = imm_t.IMM + if len(attr_list) > 3: + self.imm_type = attr_list[3] + self.set_imm_len() + self.set_mode() + + def set_imm_len(self): + if self.format.name in ["U_FORMAT", "J_FORMAT"]: + self.imm_len = 20 + elif self.format.name in ["I_FORMAT", "S_FORMAT", "B_FORMAT"]: + if self.imm_type.name == "UIMM": + self.imm_len = 5 + else: + self.imm_len = 11 + + def set_mode(self): + # mode setting for Instruction Format + if self.format.name == "R_FORMAT": + self.has_imm = 0 + if self.format.name == "I_FORMAT": + self.has_rs2 = 0 + if self.format.name in ["S_FORMAT", "B_FORMAT"]: + self.has_rd = 0 + if self.format.name in ["U_FORMAT", "J_FORMAT"]: + self.has_rs1 = 0 + self.has_rs2 = 0 + + # mode setting for Instruction Category + if self.category.name == "CSR": + self.has_rs2 = 0 + if self.format.name == "I_FORMAT": + self.has_rs1 = 0 + + def pre_sample(self): + unaligned_pc = self.pc.get_val() % 4 != 0 + self.rs1_sign = self.get_operand_sign(self.rs1_value) + self.rs2_sign = self.get_operand_sign(self.rs2_value) + self.rs3_sign = self.get_operand_sign(self.rs3_value) + self.rd_sign = self.get_operand_sign(self.rd_value) + self.fs1_sign = self.get_operand_sign(self.fs1_value) + self.fs2_sign = self.get_operand_sign(self.fs2_value) + self.fs3_sign = self.get_operand_sign(self.fs3_value) + self.fd_sign = self.get_operand_sign(self.fd_value) + self.imm_sign = self.get_imm_sign(self.imm) + self.rs1_special_value = self.get_operand_special_value(self.rs1_value) + self.rd_special_value = self.get_operand_special_value(self.rd_value) + self.rs2_special_value = self.get_operand_special_value(self.rs2_value) + self.rs3_special_value = self.get_operand_special_value(self.rs3_value) + if self.format.name not in ["R_FORMAT", "CR_FORMAT"]: + self.imm_special_value = self.get_imm_special_val(self.imm) + if self.category.name in ["COMPARE", "BRANCH"]: + self.compare_result = self.get_compare_result() + if self.category.name in ["LOAD", "STORE"]: + self.mem_addr.set_val(self.rs1_value.get_val() + + self.imm.get_val()) + self.unaligned_mem_access = self.is_unaligned_mem_access() + if self.unaligned_mem_access: + logging.info("Unaligned: {}, mem_addr: {}".format( + self.instr.name, self.mem_addr.get_val())) + if self.category.name == "LOGICAL": + self.logical_similarity = self.get_logical_similarity() + if self.category.name == "BRANCH": + self.branch_hit = self.is_branch_hit() + if self.instr.name in ["DIV", "DIVU", "REM", "REMU", "DIVW", "DIVUW", + "REMW", "REMUW"]: + self.div_result = self.get_div_result() + + @staticmethod + def get_operand_sign(operand): + # TODO: Currently handled using string formatting as part select + # isn't yet supported for global vsc variables + operand_bin = format(operand.get_val(), '#0{}b'.format(rcs.XLEN + 2)) + # "0b" is the prefix, so operand_bin[2] is the sign bit + if operand_bin[2] == "0": + return operand_sign_e["POSITIVE"] + else: + return operand_sign_e["NEGATIVE"] + + def is_unaligned_mem_access(self): + if (self.instr.name in ["LWU", "LD", "SD", "C_LD", "C_SD"] and + self.mem_addr.get_val() % 8 != 0): + return 1 + elif (self.instr.name in ["LW", "SW", "C_LW", "C_SW"] and + self.mem_addr.get_val() % 4 != 0): + return 1 + elif (self.instr.name in ["LH", "LHU", "SH"] and + self.mem_addr.get_val() % 2 != 0): + return 1 + return 0 + + @staticmethod + def get_imm_sign(imm): + # TODO: Currently handled using string formatting as part select + # isn't yet supported for global vsc variables + imm_bin = format(imm.get_val(), '#0{}b'.format(rcs.XLEN + 2)) + # "0b" is the prefix, so imm_bin[2] is the sign bit + if imm_bin[2] == "0": + return operand_sign_e["POSITIVE"] + else: + return operand_sign_e["NEGATIVE"] + + def get_div_result(self): + if self.rs2_value.get_val() == 0: + return div_result_e["DIV_BY_ZERO"] + elif (self.rs2_value.get_val() == 1 + and self.rs1_value.get_val() == (1 << (rcs.XLEN - 1))): + return div_result_e["DIV_OVERFLOW"] + else: + return div_result_e["DIV_NORMAL"] + + @staticmethod + def get_operand_special_value(operand): + if operand.get_val() == 0: + return special_val_e["ZERO_VAL"] + elif operand.get_val() == 1 << (rcs.XLEN - 1): + return special_val_e["MIN_VAL"] + elif operand.get_val() == 1 >> 1: + return special_val_e["MAX_VAL"] + else: + return special_val_e["NORMAL_VAL"] + + def get_imm_special_val(self, imm): + if imm.get_val() == 0: + return special_val_e["ZERO_VAL"] + elif self.format == riscv_instr_format_t.U_FORMAT: + # unsigned immediate value + max_val = vsc.int_t(32, (1 << self.imm_len) - 1) + if imm.get_val() == 0: + return special_val_e["MIN_VAL"] + if imm.get_val() == max_val.get_val(): + return special_val_e["MAX_VAL"] + else: + # signed immediate value + max_val = vsc.int_t(32, (2 ** (self.imm_len - 1)) - 1) + min_val = vsc.int_t(32, -2 ** (self.imm_len - 1)) + if min_val.get_val() == imm.get_val(): + return special_val_e["MIN_VAL"] + if max_val.get_val() == imm.get_val(): + return special_val_e["MAX_VAL"] + return special_val_e["NORMAL_VAL"] + + def get_compare_result(self): + val1 = vsc.int_t(rcs.XLEN, self.rs1_value.get_val()) + val2 = vsc.int_t(rcs.XLEN, self.imm.get_val() if ( + self.format == riscv_instr_format_t.I_FORMAT) else + self.rs2_value.val) + if val1.get_val() == val2.get_val(): + return compare_result_e["EQUAL"] + elif val1.get_val() < val2.get_val(): + return compare_result_e["SMALLER"] + else: + return compare_result_e["LARGER"] + + def is_branch_hit(self): + if self.instr.name == "BEQ": + return int(self.rs1_value.get_val() == self.rs2_value.get_val()) + elif self.instr.name == "C_BEQZ": + return int(self.rs1_value.get_val() == 0) + elif self.instr.name == "BNE": + return int(self.rs1_value.get_val() != self.rs2_value.get_val()) + elif self.instr.name == "C_BNEZ": + return int(self.rs1_value.get_val() != 0) + elif self.instr.name == "BLT" or self.instr.name == "BLTU": + return int(self.rs1_value.get_val() < self.rs2_value.get_val()) + elif self.instr.name == "BGE" or self.instr.name == "BGEU": + return int(self.rs1_value.get_val() >= self.rs2_value.get_val()) + else: + logging.error("Unexpected instruction {}".format(self.instr.name)) + + def get_logical_similarity(self): + val1 = vsc.int_t(rcs.XLEN, self.rs1_value.get_val()) + val2 = vsc.int_t(rcs.XLEN, (self.imm.get_val() if + self.format == riscv_instr_format_t.I_FORMAT + else self.rs2_value.val)) + temp = bin(val1.get_val() ^ val2.get_val()) + bit_difference = len([[ones for ones in temp[2:] if ones == '1']]) + if val1.get_val() == val2.get_val(): + return logical_similarity_e["IDENTICAL"] + elif bit_difference == 32: + return logical_similarity_e["OPPOSITE"] + elif bit_difference < 5: + return logical_similarity_e["SIMILAR"] + else: + return logical_similarity_e["DIFFERENT"] + + def check_hazard_condition(self, pre_instr): + '''TODO: There are cases where instruction actually has destination but + ovpsim doesn't log it because of no change in its value. Hence, + the result of the check_hazard_condition won't be accurate. Need to + explicitly extract the destination register from the operands ''' + if pre_instr.has_rd: + if ((self.has_rs1 and self.rs1 == pre_instr.rd) or + (self.has_rs2 and self.rs1 == pre_instr.rd)): + self.gpr_hazard = hazard_e["RAW_HAZARD"] + elif self.has_rd and self.rd == pre_instr.rd: + self.gpr_hazard = hazard_e["WAW_HAZARD"] + elif (self.has_rd and + ((pre_instr.has_rs1 and (pre_instr.rs1 == self.rd)) or + (pre_instr.has_rs2 and (pre_instr.rs2 == self.rd)))): + self.gpr_hazard = hazard_e["WAR_HAZARD"] + else: + self.gpr_hazard = hazard_e["NO_HAZARD"] + if self.category == riscv_instr_category_t.LOAD: + if (pre_instr.category == riscv_instr_category_t.STORE and + pre_instr.mem_addr.get_val() == self.mem_addr.get_val()): + self.lsu_hazard = hazard_e["RAW_HAZARD"] + else: + self.lsu_hazard = hazard_e["NO_HAZARD"] + if self.category == riscv_instr_category_t.STORE: + if (pre_instr.category == riscv_instr_category_t.STORE and + pre_instr.mem_addr.get_val() == self.mem_addr.get_val()): + self.lsu_hazard = hazard_e["WAW_HAZARD"] + elif (pre_instr.category == riscv_instr_category_t.LOAD and + pre_instr.mem_addr.get_val() == self.mem_addr.get_val()): + self.lsu_hazard = hazard_e["WAR_HAZARD"] + else: + self.lsu_hazard = hazard_e["NO_HAZARD"] + logging.debug("Pre PC/name: {}/{}, Cur PC/name: {}/{}, " + "Hazard: {}/{}".format(pre_instr.pc.get_val(), + pre_instr.instr.name, + self.pc.get_val(), + self.instr.name, + self.gpr_hazard.name, + self.lsu_hazard.name)) + + def get_instr_name(self): + get_instr_name = self.instr.name + for i in get_instr_name: + if i == "_": + get_instr_name = get_instr_name.replace(i, ".") + return get_instr_name + + def update_src_regs(self, operands): + if self.format.name in ["J_FORMAT", "U_FORMAT"]: + # instr rd,imm + assert len(operands) == 2 + self.imm.set_val(get_val(operands[1])) + elif self.format.name == "I_FORMAT": + assert len(operands) == 3 + if self.category.name == "LOAD": + # load rd, imm(rs1) + self.rs1 = self.get_gpr(operands[2]) + self.rs1_value.set_val(self.get_gpr_state(operands[2])) + self.imm.set_val(get_val(operands[1])) + elif self.category.name == "CSR": + # csrrwi rd, csr, imm + self.imm.set_val(get_val(operands[2])) + if operands[1].upper() in privileged_reg_t.__members__: + self.csr.set_val( + privileged_reg_t[operands[1].upper()].value) + else: + self.csr.set_val(get_val(operands[1])) + else: + # addi rd, rs1, imm + self.rs1 = self.get_gpr(operands[1]) + self.rs1_value.set_val(self.get_gpr_state(operands[1])) + self.imm.set_val(get_val(operands[2])) + elif self.format.name in ["S_FORMAT", "B_FORMAT"]: + assert len(operands) == 3 + if self.category.name == "STORE": + self.rs2 = self.get_gpr(operands[0]) + self.rs2_value.set_val(self.get_gpr_state(operands[0])) + self.rs1 = self.get_gpr(operands[2]) + self.rs1_value.set_val(self.get_gpr_state(operands[2])) + self.imm.set_val(get_val(operands[1])) + else: + # bne rs1, rs2, imm + self.rs1 = self.get_gpr(operands[0]) + self.rs1_value.set_val(self.get_gpr_state(operands[0])) + self.rs2 = self.get_gpr(operands[1]) + self.rs2_value.set_val(self.get_gpr_state(operands[1])) + self.imm.set_val(get_val(operands[2])) + elif self.format.name == "R_FORMAT": + if self.has_rs2 or self.category.name == "CSR": + assert len(operands) == 3 + else: + assert len(operands) == 2 + if self.category.name == "CSR": + # csrrw rd, csr, rs1 + if operands[1].upper() in privileged_reg_t.__members__: + self.csr.set_val( + privileged_reg_t[operands[1].upper()].value) + else: + self.csr.set_val(get_val(operands[1])) + self.rs1 = self.get_gpr(operands[2]) + self.rs1_value.set_val(self.get_gpr_state(operands[2])) + else: + # add rd, rs1, rs2 + self.rs1 = self.get_gpr(operands[1]) + self.rs1_value.set_val(self.get_gpr_state(operands[1])) + if self.has_rs2: + self.rs2 = self.get_gpr(operands[2]) + self.rs2_value.set_val(self.get_gpr_state(operands[2])) + elif self.format.name == "R4_FORMAT": + assert len(operands) == 4 + self.rs1 = self.get_gpr(operands[1]) + self.rs1_value.set_val(self.get_gpr_state(operands[1])) + self.rs2 = self.get_gpr(operands[2]) + self.rs2_value.set_val(self.get_gpr_state(operands[2])) + self.rs2 = self.get_gpr(operands[3]) + self.rs2_value.set_val(self.get_gpr_state(operands[3])) + elif self.format.name in ["CI_FORMAT", "CIW_FORMAT"]: + if self.instr.name == "C_ADDI16SP": + self.imm.set_val(get_val(operands[1])) + self.rs1 = riscv_reg_t.SP + self.rs1_value.set_val(self.get_gpr_state("sp")) + elif self.instr.name == "C_ADDI4SPN": + self.rs1 = riscv_reg_t.SP + self.rs1_value.set_val(self.get_gpr_state("sp")) + elif self.instr.name in ["C_LDSP", "C_LWSP", "C_LQSP"]: + # c.ldsp rd, imm + self.imm.set_val(get_val(operands[1])) + self.rs1 = riscv_reg_t.SP + self.rs1_value.set_val(self.get_gpr_state("sp")) + else: + # c.lui rd, imm + self.imm.set_val(get_val(operands[1])) + elif self.format.name == "CL_FORMAT": + # c.lw rd, imm(rs1) + self.imm.set_val(get_val(operands[1])) + self.rs1 = self.get_gpr(operands[2]) + self.rs1_value.set_val(self.get_gpr_state(operands[2])) + elif self.format.name == "CS_FORMAT": + # c.sw rs2,imm(rs1) + self.rs2 = self.get_gpr(operands[0]) + self.rs2_value.set_val(self.get_gpr_state(operands[0])) + self.rs1 = self.get_gpr(operands[2]) + self.rs1_value.set_val(self.get_gpr_state(operands[2])) + self.imm.set_val(get_val(operands[1])) + elif self.format.name == "CA_FORMAT": + # c.and rd, rs2 (rs1 == rd) + self.rs2 = self.get_gpr(operands[1]) + self.rs2_value.set_val(self.get_gpr_state(operands[1])) + self.rs1 = self.get_gpr(operands[0]) + self.rs1_value.set_val(self.get_gpr_state(operands[0])) + elif self.format.name == "CB_FORMAT": + # c.beqz rs1, imm + self.rs1 = self.get_gpr(operands[0]) + self.rs1_value.set_val(self.get_gpr_state(operands[0])) + self.imm.set_val(get_val(operands[1])) + elif self.format.name == "CSS_FORMAT": + # c.swsp rs2, imm + self.rs2 = self.get_gpr(operands[0]) + self.rs2_value.set_val(self.get_gpr_state(operands[0])) + self.rs1 = riscv_reg_t.SP + self.rs1_value.set_val(self.get_gpr_state("sp")) + self.imm.set_val(get_val(operands[1])) + elif self.format.name == "CR_FORMAT": + if self.instr.name in ["C_JR", "C_JALR"]: + # c.jalr rs1 + self.rs1 = self.get_gpr(operands[0]) + self.rs1_value.set_val(self.get_gpr_state(operands[0])) + else: + # c.add rd, rs2 + self.rs2 = self.get_gpr(operands[1]) + self.rs2_value.set_val(self.get_gpr_state(operands[1])) + elif self.format.name == "CJ_FORMAT": + # c.j imm + self.imm.set_val(get_val(operands[0])) + else: + logging.error("Unsupported format {}".format(self.format.name)) + + def update_dst_regs(self, reg_name, val_str): + riscv_cov_instr.gpr_state[reg_name] = get_val(val_str, hexa=1) + self.rd = self.get_gpr(reg_name) + self.rd_value.set_val(self.get_gpr_state(reg_name)) + + @staticmethod + def get_gpr(reg_name): + reg_name = reg_name.upper() + if reg_name not in riscv_reg_t.__members__: + logging.error("Cannot convert {} to GPR".format(reg_name)) + return riscv_reg_t[reg_name] + + @staticmethod + def get_gpr_state(name): + if name in ["zero", "x0"]: + return 0 + elif name in riscv_cov_instr.gpr_state: + return riscv_cov_instr.gpr_state[name] + else: + logging.warning( + "Cannot find GPR state: {}; initialize to 0".format(name)) + if name.upper() in riscv_reg_t.__members__: + riscv_cov_instr.gpr_state[name] = 0 + return 0 diff --git a/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr_cov.py b/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr_cov.py deleted file mode 100644 index 2bbe2349..00000000 --- a/vendor/google_riscv-dv/pygen/pygen_src/isa/riscv_instr_cov.py +++ /dev/null @@ -1,46 +0,0 @@ -import sys -import vsc -import logging -from enum import Enum, auto -from pygen_src.riscv_instr_pkg import riscv_reg_t - -class operand_sign_e(Enum): - POSITIVE = 0 - NEGATIVE = auto() - -class div_result_e(Enum): - DIV_NORMAL = 0 - DIV_BY_ZERO = auto() - DIV_OVERFLOW = auto() - -class compare_result_e(Enum): - EQUAL = 0 - LARGER = auto() - SMALLER = auto() - -class logical_similarity_e(Enum): - IDENTICAL = 0 - OPPOSITE = auto() - SIMILAR = auto() - DIFFERENT = auto() - -class special_val_e(Enum): - NORMAL_VAL = 0 - MIN_VAL = auto() - MAX_VAL = auto() - ZERO_VAL = auto() - - -def get_gpr(reg_name): - reg_name = reg_name.upper() - if not reg_name in riscv_reg_t: - logging.fatal("Cannot convert {} to GPR".format(reg_name)) - return riscv_reg_t[reg_name] - -def get_gpr_state(reg_name): - if reg_name in ["zero", "x0"]: - return 0 - elif reg_name in gpr_state: - return gpr_state[reg_name] - else: - logging.warning("Cannot find GPR state: {}".format(reg_name)) 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 054bdc29..1bc65cd7 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 @@ -84,6 +84,7 @@ class riscv_asm_program_gen: 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].post_process_instr() self.main_program[hart].generate_instr_stream() logging.info("Generating main program instruction stream...done") self.instr_stream.extend(self.main_program[hart].instr_string_list) @@ -292,7 +293,20 @@ class riscv_asm_program_gen: self.instr_stream.append(pkg_ins.indent + "ecall") def gen_register_dump(self): - pass + string = "" + # load base address + string = "{}la x{}, _start".format(pkg_ins.indent, cfg.gpr[0].value) + self.instr_stream.append(string) + + # Generate sw/sd instructions + for i in range(32): + if (rcs.XLEN == 64): + string = "{}sd x{}, {}(x{})".format( + pkg_ins.indent, i, i * (rcs.XLEN / 8), cfg.gpr[0].value) + else: + string = "{}sw x{}, {}(x{})".format( + pkg_ins.indent, i, int(i * (rcs.XLEN / 8)), cfg.gpr[0].value) + self.instr_stream.append(string) def pre_enter_privileged_mode(self, hart): instr = [] @@ -430,7 +444,15 @@ class riscv_asm_program_gen: pass def gen_ecall_handler(self, hart): - pass + string = "" + string = pkg_ins.format_string(pkg_ins.get_label( + "ecall_handler:", hart), pkg_ins.LABEL_STR_LEN) + self.instr_stream.append(string) + self.dump_perf_stats() + self.gen_register_dump() + string = pkg_ins.format_string(" ", pkg_ins.LABEL_STR_LEN) + string = string + "j write_tohost" + self.instr_stream.append(string) def gen_ebreak_handler(self, hart): pass 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 new file mode 100644 index 00000000..2ced738e --- /dev/null +++ b/vendor/google_riscv-dv/pygen/pygen_src/riscv_instr_cover_group.py @@ -0,0 +1,1353 @@ +"""Copyright 2020 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. +""" + +from pygen.pygen_src.isa.riscv_cov_instr import * + + +class riscv_instr_cover_group: + def __init__(self): + self.pre_instr = riscv_cov_instr() + self.cfg = None + self.instr_list = [] + self.instr_cnt = 0 + self.branch_instr_cnt = 0 + self.branch_hit_history = vsc.bit_t(5) # The last 5 branch result + self.ignored_exceptions = [] + self.exception_list = [] + ''' + Mode of the coverage model: + In compliance mode, all the micro-architecture related covergroups + are removed. Only the ones related to RISC-V specification compliance + is sampled. + ''' + self.compliance_mode = vsc.bit_t(1) + self.select_isa = vsc.bit_t(1) # Select an ISA extension to cover + self.cov_isa = None + + '''Format specific covergroups''' + + @vsc.covergroup + class r_instr_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + + @vsc.covergroup + class i_instr_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + + @vsc.covergroup + class u_instr_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_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + + @vsc.covergroup + class cmp_instr_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_result = vsc.coverpoint(lambda: instr.rd_value[0], + bins={ + "Unset": vsc.bin(0), + "Set" : vsc.bin(1) + } + ) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + + @vsc.covergroup + class sb_instr_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit, + bins={ + "Taken" : vsc.bin(1), + "Non-taken": vsc.bin(0) + } + ) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + + @vsc.covergroup + class j_instr_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + '''The RISC-V hardware allows any of the 32 integer registers + to be given as rd. If register 0 (ZERO) is given as rd then the + return address is discarded and we effectively have a + goto rather than a function call''' + # if instr.rd: + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd_align = vsc.coverpoint(lambda: instr.rd_value[1], + bins={ + "Aligned" : vsc.bin(1), + "Not-aligned": vsc.bin(0) + } + ) + + '''Category specific covergroups''' + '''Load instructions''' + + @vsc.covergroup + class load_instr_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_ex_zero_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + + '''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): + # super().__init__(instr) + @vsc.covergroup + class lb_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_ex_zero_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + + # @vsc.covergroup + # class lh_cg(load_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_align = vsc.coverpoint(lambda: instr.unaligned_mem_access, + # bins={ + # "aligned" : vsc.bin(0), + # "unaligned": vsc.bin(1) + # }) + @vsc.covergroup + class lh_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_ex_zero_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + self.cp_align = vsc.coverpoint(lambda: instr.unaligned_mem_access, + bins={ + "aligned" : vsc.bin(0), + "unaligned": vsc.bin(1) + }) + + # @vsc.covergroup + # class lw_cg(load_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_align = vsc.coverpoint(lambda: instr.unaligned_mem_access, + # bins={ + # "aligned" : vsc.bin(0), + # "unaligned": vsc.bin(1) + # }) + @vsc.covergroup + class lw_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_ex_zero_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + + self.cp_align = vsc.coverpoint(lambda: instr.unaligned_mem_access, + bins={ + "aligned" : vsc.bin(0), + "unaligned": vsc.bin(1) + }) + + # @vsc.covergroup + # class lbu_cg(load_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + @vsc.covergroup + class lbu_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_ex_zero_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + + # @vsc.covergroup + # class lhu_cg(load_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_align = vsc.coverpoint(lambda: instr.unaligned_mem_access, + # bins={ + # "aligned" : vsc.bin(0), + # "unaligned": vsc.bin(1) + # }) + @vsc.covergroup + class lhu_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_ex_zero_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + self.cp_align = vsc.coverpoint(lambda: instr.unaligned_mem_access, + bins={ + "aligned" : vsc.bin(0), + "unaligned": vsc.bin(1) + }) + + '''Store instructions''' + + @vsc.covergroup + class store_instr_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_ex_zero_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.lsu_hazard, + cp_t=vsc.enum_t( + store_lsu_hazard_e)) + + # @vsc.covergroup + # class sb_cg(store_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + @vsc.covergroup + class sb_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_ex_zero_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.lsu_hazard, + cp_t=vsc.enum_t( + store_lsu_hazard_e)) + + # @vsc.covergroup + # class sh_cg(store_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_misalign = vsc.coverpoint( + # lambda: instr.unaligned_mem_access, + # bins={ + # "aligned" : vsc.bin(0), + # "unaligned": vsc.bin(1) + # }) + @vsc.covergroup + class sh_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_ex_zero_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.lsu_hazard, + cp_t=vsc.enum_t( + store_lsu_hazard_e)) + self.cp_misalign = vsc.coverpoint( + lambda: instr.unaligned_mem_access, + bins={ + "aligned" : vsc.bin(0), + "unaligned": vsc.bin(1) + }) + + # @vsc.covergroup + # class sw_cg(store_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_misalign = vsc.coverpoint( + # lambda: instr.unaligned_mem_access, + # bins={ + # "aligned" : vsc.bin(0), + # "unaligned": vsc.bin(1) + # }) + @vsc.covergroup + class sw_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_ex_zero_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + self.cp_lsu_hazard = vsc.coverpoint(lambda: instr.lsu_hazard, + cp_t=vsc.enum_t( + store_lsu_hazard_e)) + self.cp_misalign = vsc.coverpoint( + lambda: instr.unaligned_mem_access, + bins={ + "aligned" : vsc.bin(0), + "unaligned": vsc.bin(1) + }) + + '''Shift instructions''' + + # @vsc.covergroup + # class sll_cg(r_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + # self.cp_rs2_sign]) + @vsc.covergroup + class sll_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + + @vsc.covergroup + class slli_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + + # @vsc.covergroup + # class srl_cg(r_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + # self.cp_rs2_sign]) + @vsc.covergroup + class srl_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + + @vsc.covergroup + class srli_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + + # @vsc.covergroup + # class sra_cg(r_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + # self.cp_rs2_sign]) + @vsc.covergroup + class sra_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + + @vsc.covergroup + class srai_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + + '''Arithmetic instructions''' + + # @vsc.covergroup + # class add_cg(r_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign, + # self.cp_rd_sign]) + @vsc.covergroup + class add_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign, + self.cp_rd_sign]) + + @vsc.covergroup + class addi_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_ex_zero_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_imm_sign, + self.cp_rd_sign]) + + # @vsc.covergroup + # class sub_cg(r_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign, + # self.cp_rd_sign]) + @vsc.covergroup + class sub_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign, + self.cp_rd_sign]) + + # @vsc.covergroup + # class lui_cg(u_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + @vsc.covergroup + class lui_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_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + + # @vsc.covergroup + # class auipc_cg(u_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + @vsc.covergroup + class auipc_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_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + + '''Logical instructions''' + + # @vsc.covergroup + # class xor_cg(r_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity, + # cp_t=vsc.enum_t( + # logical_similarity_e)) + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + # self.cp_rs2_sign]) + @vsc.covergroup + class xor_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity, + cp_t=vsc.enum_t( + logical_similarity_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + + # @vsc.covergroup + # class xori_cg(i_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity, + # cp_t=vsc.enum_t( + # logical_similarity_e)) + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + # self.cp_imm_sign]) + @vsc.covergroup + class xori_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity, + cp_t=vsc.enum_t( + logical_similarity_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_imm_sign]) + + # @vsc.covergroup + # class or_cg(r_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity, + # cp_t=vsc.enum_t( + # logical_similarity_e)) + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + # self.cp_rs2_sign]) + @vsc.covergroup + class or_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity, + cp_t=vsc.enum_t( + logical_similarity_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + + # @vsc.covergroup + # class ori_cg(i_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity, + # cp_t=vsc.enum_t( + # logical_similarity_e)) + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + # self.cp_imm_sign]) + @vsc.covergroup + class ori_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity, + cp_t=vsc.enum_t( + logical_similarity_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_imm_sign]) + + # @vsc.covergroup + # class and_cg(r_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity, + # cp_t=vsc.enum_t( + # logical_similarity_e)) + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + # self.cp_rs2_sign]) + @vsc.covergroup + class and_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity, + cp_t=vsc.enum_t( + logical_similarity_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + + # @vsc.covergroup + # class andi_cg(i_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity, + # cp_t=vsc.enum_t( + # logical_similarity_e)) + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + # self.cp_imm_sign]) + @vsc.covergroup + class andi_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rd_sign = vsc.coverpoint(lambda: instr.rd_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_logical = vsc.coverpoint(lambda: instr.logical_similarity, + cp_t=vsc.enum_t( + logical_similarity_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_imm_sign]) + + '''Compare instructions''' + + # @vsc.covergroup + # class slt_cg(cmp_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + # cp_t=vsc.enum_t(riscv_reg_t)) + # self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + # cp_t=vsc.enum_t(operand_sign_e)) + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + # self.cp_rs2_sign]) + @vsc.covergroup + class slt_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_result = vsc.coverpoint(lambda: instr.rd_value[0], + bins={ + "Unset": vsc.bin(0), + "Set" : vsc.bin(1) + } + ) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + + # @vsc.covergroup + # class slti_cg(cmp_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + # cp_t=vsc.enum_t(operand_sign_e)) + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + # self.cp_imm_sign]) + @vsc.covergroup + class slti_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_result = vsc.coverpoint(lambda: instr.rd_value[0], + bins={ + "Unset": vsc.bin(0), + "Set" : vsc.bin(1) + } + ) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_imm_sign]) + + # @vsc.covergroup + # class sltu_cg(cmp_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + # cp_t=vsc.enum_t(riscv_reg_t)) + # self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + # cp_t=vsc.enum_t(operand_sign_e)) + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + # self.cp_rs2_sign]) + @vsc.covergroup + class sltu_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_result = vsc.coverpoint(lambda: instr.rd_value[0], + bins={ + "Unset": vsc.bin(0), + "Set" : vsc.bin(1) + } + ) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + + # @vsc.covergroup + # class sltiu_cg(cmp_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + # cp_t=vsc.enum_t(operand_sign_e)) + # self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + # self.cp_imm_sign]) + @vsc.covergroup + class sltiu_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_result = vsc.coverpoint(lambda: instr.rd_value[0], + bins={ + "Unset": vsc.bin(0), + "Set" : vsc.bin(1) + } + ) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t(hazard_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_imm_sign]) + + '''Branch instructions''' + + # @vsc.covergroup + # class beq_cg(sb_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + @vsc.covergroup + class beq_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit, + bins={ + "Taken" : vsc.bin(1), + "Non-taken": vsc.bin(0) + } + ) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + + # @vsc.covergroup + # class bne_cg(sb_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + @vsc.covergroup + class bne_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit, + bins={ + "Taken" : vsc.bin(1), + "Non-taken": vsc.bin(0) + } + ) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + + # @vsc.covergroup + # class blt_cg(sb_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + @vsc.covergroup + class blt_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit, + bins={ + "Taken" : vsc.bin(1), + "Non-taken": vsc.bin(0) + } + ) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + + # @vsc.covergroup + # class bge_cg(sb_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + @vsc.covergroup + class bge_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit, + bins={ + "Taken" : vsc.bin(1), + "Non-taken": vsc.bin(0) + } + ) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + + # @vsc.covergroup + # class bltu_cg(sb_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + @vsc.covergroup + class bltu_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit, + bins={ + "Taken" : vsc.bin(1), + "Non-taken": vsc.bin(0) + } + ) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + + # @vsc.covergroup + # class bgeu_cg(sb_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + @vsc.covergroup + class bgeu_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_rs1 = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs2 = vsc.coverpoint(lambda: instr.rs2, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rs1_sign = vsc.coverpoint(lambda: instr.rs1_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_rs2_sign = vsc.coverpoint(lambda: instr.rs2_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + self.cp_branch_hit = vsc.coverpoint(lambda: instr.branch_hit, + bins={ + "Taken" : vsc.bin(1), + "Non-taken": vsc.bin(0) + } + ) + self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, + self.cp_rs2_sign]) + self.cp_gpr_hazard = vsc.coverpoint(lambda: instr.gpr_hazard, + cp_t=vsc.enum_t( + branch_hazard_e)) + + '''Jump instructions''' + + # @vsc.covergroup + # class jal_cg(j_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # self.cp_imm_align = vsc.coverpoint(lambda: instr.imm[1], + # bins={ + # "Aligned" : vsc.bin(1), + # "Not-aligned": vsc.bin(0) + # } + # ) + @vsc.covergroup + class jal_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + '''The RISC-V hardware allows any of the 32 integer registers + to be given as rd. If register 0 (ZERO) is given as rd then the + return address is discarded and we effectively have a + goto rather than a function call''' + # if instr.rd: + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd_align = vsc.coverpoint(lambda: instr.rd_value[1], + bins={ + "Aligned" : vsc.bin(1), + "Not-aligned": vsc.bin(0) + } + ) + self.cp_imm_align = vsc.coverpoint(lambda: instr.imm[1], + bins={ + "Aligned" : vsc.bin(1), + "Not-aligned": vsc.bin(0) + } + ) + + # @vsc.covergroup + # class jalr_cg(j_instr_cg): + # def __init__(self, instr): + # super().__init__(instr) + # + # '''default bins are not supported in pyvsc. We ignore it here + # as coverage values hit in default bin are not taken account while + # reporting coverage''' + # self.cp_rs1_link = vsc.coverpoint(lambda: instr.rs1, + # cp_t=vsc.enum_t( + # jalr_riscv_reg_t)) + # self.cp_rd_link = vsc.coverpoint(lambda: instr.rd, + # cp_t=vsc.enum_t(jalr_riscv_reg_t)) + # # left index is excluded in pyvsc bit_t type + # self.cp_imm_align = vsc.coverpoint(lambda: instr.imm[2:0], + # bins={ + # "Zero" : vsc.bin(0), + # "One" : vsc.bin(1), + # "Two" : vsc.bin(2), + # "Three": vsc.bin(3) + # } + # ) + # self.cp_rs1_align = vsc.coverpoint(lambda: instr.rs1_value[2:0], + # bins={ + # "Zero" : vsc.bin(0), + # "One" : vsc.bin(1), + # "Two" : vsc.bin(2), + # "Three": vsc.bin(3) + # } + # ) + # 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]) + @vsc.covergroup + class jalr_cg(object): + def __init__(self, instr): + super().__init__() + + self.cp_imm_sign = vsc.coverpoint(lambda: instr.imm_sign, + cp_t=vsc.enum_t(operand_sign_e)) + '''The RISC-V hardware allows any of the 32 integer registers + to be given as rd. If register 0 (ZERO) is given as rd then the + return address is discarded and we effectively have a + goto rather than a function call''' + # TODO: if instr.rd: + self.cp_rd = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(riscv_reg_t)) + self.cp_rd_align = vsc.coverpoint(lambda: instr.rd_value[1], + bins={ + "Aligned" : vsc.bin(1), + "Not-aligned": vsc.bin(0) + } + ) + '''default bins are not supported in pyvsc. We ignore it here + as coverage values hit in default bin are not taken account while + reporting coverage''' + self.cp_rs1_link = vsc.coverpoint(lambda: instr.rs1, + cp_t=vsc.enum_t( + jalr_riscv_reg_t)) + self.cp_rd_link = vsc.coverpoint(lambda: instr.rd, + cp_t=vsc.enum_t(jalr_riscv_reg_t)) + # left index is excluded in pyvsc bit_t type + self.cp_imm_align = vsc.coverpoint(lambda: instr.imm[2:0], + bins={ + "Zero" : vsc.bin(0), + "One" : vsc.bin(1), + "Two" : vsc.bin(2), + "Three": vsc.bin(3) + } + ) + self.cp_rs1_align = vsc.coverpoint(lambda: instr.rs1_value[2:0], + bins={ + "Zero" : vsc.bin(0), + "One" : vsc.bin(1), + "Two" : vsc.bin(2), + "Three": vsc.bin(3) + } + ) + 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]) + + 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 + 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)) + self.pre_instr = instr + + def reset(self): + self.instr_cnt = 0 + self.branch_instr_cnt = 0 + self.branch_hit_history.set_val(0) 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 0f56094a..7ba35b56 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 @@ -317,9 +317,8 @@ def parse_args(): parse.add_argument('--no_dret', help = 'no_dret', choices = [0, 1], type = int, default = 1) parse.add_argument('--no_wfi', help = 'no_wfi', choices = [0, 1], type = int, default = 1) - # TODO : Enabling no_branch_jump default to 1 for now. parse.add_argument('--no_branch_jump', help = 'no_branch_jump', - choices = [0, 1], type = int, default = 1) + choices = [0, 1], type = int, default = 0) parse.add_argument('--no_load_store', help = 'no_load_store', choices = [0, 1], type = int, default = 0) parse.add_argument('--no_csr_instr', help = 'no_csr_instr', 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 fd4e134d..c5f2c930 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 @@ -13,9 +13,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ import logging -from enum import Enum, auto +from enum import Enum, IntEnum, auto from bitstring import BitArray -from pygen_src.target.rv32i import riscv_core_setting as rcs +from pygen.pygen_src.target.rv32i import riscv_core_setting as rcs class mem_region_t: @@ -560,7 +560,7 @@ class riscv_instr_name_t(Enum): INVALID_INSTR = auto() -class riscv_reg_t(Enum): +class riscv_reg_t(IntEnum): ZERO = 0 RA = auto() SP = auto() @@ -722,6 +722,8 @@ class riscv_instr_category_t(Enum): TRAP = auto() INTERRUPT = auto() AMO = auto() + + # typedef bit[11:0] riscv_csr_t; @@ -1055,13 +1057,68 @@ class misa_ext_t(Enum): MISA_EXT_Z = auto() -class hazard_e(Enum): +class hazard_e(IntEnum): NO_HAZARD = 0 RAW_HAZARD = auto() WAR_HAZARD = auto() WAW_HAZARD = auto() +# TODO: ignore bins is not yet supported in pyvsc; extra enums will be removed +# once support is added +# Ignore WAR/WAW_HAZARD for branch instructions +class branch_hazard_e(IntEnum): + NO_HAZARD = 0 + RAW_HAZARD = auto() + +# Ignore RAW_HAZARD for store lsu hazard +class store_lsu_hazard_e(IntEnum): + NO_HAZARD = 0 + WAR_HAZARD = auto() + WAW_HAZARD = auto() + + +# RA/T1 for rs1/rd_link in jalr instruction +class jalr_riscv_reg_t(IntEnum): + RA = 0 + T1 = auto() + + +# Ignore ZERO as src1 of load instructions +class riscv_reg_ex_zero_t(IntEnum): + RA = 0 + SP = auto() + GP = auto() + TP = auto() + T0 = auto() + T1 = auto() + T2 = auto() + S0 = auto() + S1 = auto() + A0 = auto() + A1 = auto() + A2 = auto() + A3 = auto() + A4 = auto() + A5 = auto() + A6 = auto() + A7 = auto() + S2 = auto() + S3 = auto() + S4 = auto() + S5 = auto() + S6 = auto() + S7 = auto() + S8 = auto() + S9 = auto() + S10 = auto() + S11 = auto() + T3 = auto() + T4 = auto() + T5 = auto() + T6 = auto() + + class pmp_addr_mode_t(Enum): OFF = 0b00 TOR = 0b01 @@ -1161,29 +1218,215 @@ class all_categories(Enum): INTERRUPT = auto() AMO = auto() + def get_val(in_string, hexa=0): if len(in_string) > 2: if "0x" in in_string: - out_val = hex(int(in_string, base=16)) + out_val = int(in_string, base=16) return out_val - if hexa: - out_val = hex(int(in_string, base=16)) - else: - out_val = int(in_string) - logging.info("riscv_instr_pkg: imm: {} -> {}".format(in_string, out_val)) - return out_val + if hexa: + out_val = int(in_string, base=16) + else: + out_val = int(in_string) + logging.info("imm: {} -> {}".format(in_string, out_val)) + return out_val + + +def get_attr_list(instr_name): + switcher = { + # LOAD instructions + riscv_instr_name_t.LB: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.LOAD, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.LH: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.LOAD, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.LW: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.LOAD, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.LBU: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.LOAD, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.LHU: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.LOAD, + riscv_instr_group_t.RV32I], + # STORE instructions + riscv_instr_name_t.SB: [riscv_instr_format_t.S_FORMAT, + riscv_instr_category_t.STORE, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.SH: [riscv_instr_format_t.S_FORMAT, + riscv_instr_category_t.STORE, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.SW: [riscv_instr_format_t.S_FORMAT, + riscv_instr_category_t.STORE, + riscv_instr_group_t.RV32I], + # SHIFT intructions + riscv_instr_name_t.SLL: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.SHIFT, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.SLLI: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.SHIFT, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.SRL: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.SHIFT, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.SRLI: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.SHIFT, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.SRA: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.SHIFT, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.SRAI: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.SHIFT, + riscv_instr_group_t.RV32I], + # ARITHMETIC intructions + riscv_instr_name_t.ADD: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.ARITHMETIC, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.ADDI: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.ARITHMETIC, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.NOP: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.ARITHMETIC, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.SUB: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.ARITHMETIC, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.LUI: [riscv_instr_format_t.U_FORMAT, + riscv_instr_category_t.ARITHMETIC, + riscv_instr_group_t.RV32I, imm_t.UIMM], + riscv_instr_name_t.AUIPC: [riscv_instr_format_t.U_FORMAT, + riscv_instr_category_t.ARITHMETIC, + riscv_instr_group_t.RV32I, imm_t.UIMM], + # LOGICAL instructions + riscv_instr_name_t.XOR: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.LOGICAL, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.XORI: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.LOGICAL, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.OR: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.LOGICAL, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.ORI: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.LOGICAL, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.AND: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.LOGICAL, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.ANDI: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.LOGICAL, + riscv_instr_group_t.RV32I], + # COMPARE instructions + riscv_instr_name_t.SLT: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.COMPARE, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.SLTI: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.COMPARE, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.SLTU: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.COMPARE, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.SLTIU: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.COMPARE, + riscv_instr_group_t.RV32I], + # BRANCH instructions + riscv_instr_name_t.BEQ: [riscv_instr_format_t.B_FORMAT, + riscv_instr_category_t.BRANCH, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.BNE: [riscv_instr_format_t.B_FORMAT, + riscv_instr_category_t.BRANCH, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.BLT: [riscv_instr_format_t.B_FORMAT, + riscv_instr_category_t.BRANCH, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.BGE: [riscv_instr_format_t.B_FORMAT, + riscv_instr_category_t.BRANCH, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.BLTU: [riscv_instr_format_t.B_FORMAT, + riscv_instr_category_t.BRANCH, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.BGEU: [riscv_instr_format_t.B_FORMAT, + riscv_instr_category_t.BRANCH, + riscv_instr_group_t.RV32I], + # JUMP instructions + riscv_instr_name_t.JAL: [riscv_instr_format_t.J_FORMAT, + riscv_instr_category_t.JUMP, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.JALR: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.JUMP, + riscv_instr_group_t.RV32I], + # SYNCH instructions + riscv_instr_name_t.FENCE: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.SYNCH, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.FENCE_I: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.SYNCH, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.SFENCE_VMA: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.SYNCH, + riscv_instr_group_t.RV32I], + # SYSTEM instructions + riscv_instr_name_t.ECALL: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.SYSTEM, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.EBREAK: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.SYSTEM, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.URET: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.SYSTEM, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.SRET: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.SYSTEM, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.MRET: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.SYSTEM, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.DRET: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.SYSTEM, + riscv_instr_group_t.RV32I], + riscv_instr_name_t.WFI: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.INTERRUPT, + riscv_instr_group_t.RV32I], + # CSR instructions + riscv_instr_name_t.CSRRW: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.CSR, + riscv_instr_group_t.RV32I, imm_t.UIMM], + riscv_instr_name_t.CSRRS: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.CSR, + riscv_instr_group_t.RV32I, imm_t.UIMM], + riscv_instr_name_t.CSRRC: [riscv_instr_format_t.R_FORMAT, + riscv_instr_category_t.CSR, + riscv_instr_group_t.RV32I, imm_t.UIMM], + riscv_instr_name_t.CSRRWI: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.CSR, + riscv_instr_group_t.RV32I, imm_t.UIMM], + riscv_instr_name_t.CSRRSI: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.CSR, + riscv_instr_group_t.RV32I, imm_t.UIMM], + riscv_instr_name_t.CSRRCI: [riscv_instr_format_t.I_FORMAT, + riscv_instr_category_t.CSR, + riscv_instr_group_t.RV32I, imm_t.UIMM], + } + # if instruction is not present in the dictionary,second argument well + # be assigned as default value of passed argument + attr_list = switcher.get(instr_name, "Cannot find instruction") + return attr_list + + +def add_functions_as_methods(function): + def decorator(Class): + setattr(Class, function.__name__, function) + return Class + + return decorator -class hazard_e(Enum): - NO_HAZARD = 0 - RAW_HAZARD = auto() - WAR_HAZARD = auto() - WAW_HAZARD = auto() class riscv_instr_pkg: def __init__(self): - self.MPRV_BIT_MASK = BitArray(uint= 0x1 << 0x17, length = rcs.XLEN) - self.SUM_BIT_MASK = BitArray(uint = 0x1 << 0x18, length = rcs.XLEN) - self.MPP_BIT_MASK = BitArray(uint = 0x3 << 0x11, length = rcs.XLEN) + self.MPRV_BIT_MASK = BitArray(uint=0x1 << 0x17, length=rcs.XLEN) + self.SUM_BIT_MASK = BitArray(uint=0x1 << 0x18, length=rcs.XLEN) + self.MPP_BIT_MASK = BitArray(uint=0x3 << 0x11, length=rcs.XLEN) self.MAX_USED_VADDR_BITS = 30 self.IMM25_WIDTH = 25 self.IMM12_WIDTH = 12 @@ -1196,8 +1439,8 @@ class riscv_instr_pkg: self.MAX_CALL_PER_FUNC = 5 self.indent = self.LABEL_STR_LEN * " " - def hart_prefix(self, hart = 0): - if(rcs.NUM_HARTS <= 1): + def hart_prefix(self, hart=0): + if (rcs.NUM_HARTS <= 1): return "" else: return f"h{hart}_" @@ -1205,17 +1448,18 @@ class riscv_instr_pkg: def get_label(self, label, hart=0): return (self.hart_prefix(hart) + label) - def format_string(self, string, length = 10): + def format_string(self, string, length=10): formatted_str = length * " " if (int(length) < len(string)): return string formatted_str = string + formatted_str[0: (int(length) - len(string))] return formatted_str - def format_data(self, data, byte_per_group = 4): + def format_data(self, data, byte_per_group=4): string = "0x" for i in range(len(data)): - if ((i % byte_per_group == 0) and (i != len(data) - 1) and (i != 0)): + if ((i % byte_per_group == 0) and (i != len(data) - 1) and ( + i != 0)): string = string + ", 0x" string = string + f"{hex(data[i])}" return string 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 d0ca1c49..a5bb12b0 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 @@ -1,89 +1,188 @@ -""" -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 logging -from pygen_src.riscv_instr_stream import riscv_rand_instr_stream -from pygen_src.riscv_instr_pkg import pkg_ins - - -class riscv_instr_sequence: - - def __init__(self): - self.instr_cnt = 0 - self.instr_stream = riscv_rand_instr_stream() - self.is_main_program = 0 - self.is_debug_program = 0 - self.label_name = "" - self.instr_string_list = [] # Save the instruction list - self.program_stack_len = 0 # Stack space allocated for this program - self.directed_instr = [] # List of all directed instruction stream - self.illegal_instr_pct = 0 # Percentage of illegal instructions - self.hint_instr_pct = 0 # Percentage of hint instructions - - def gen_instr(self, is_main_program, no_branch = 1): - self.is_main_program = is_main_program - self.instr_stream.initialize_instr_list(self.instr_cnt) - logging.info("Start generating %d instruction" % len(self.instr_stream.instr_list)) - self.instr_stream.gen_instr(no_branch = no_branch, no_load_store = 1, - is_debug_program = self.is_debug_program) - - if not is_main_program: - self.gen_stack_enter_instr() - self.gen_stack_exit_instr() - - # TODO - def gen_stack_enter_instr(self): - pass - - # TODO - def gen_stack_exit_instr(self): - pass - - # TODO - def post_process_instr(self): - pass - - # TODO - def insert_jump_instr(self): - pass - - def generate_instr_stream(self, no_label = 0): - prefix = '' - string = '' - self.instr_string_list.clear() - - for i in range(len(self.instr_stream.instr_list)): - if i == 0: - if no_label: - prefix = pkg_ins.format_string(string = ' ', length = pkg_ins.LABEL_STR_LEN) - else: - prefix = pkg_ins.format_string(string = '{}:'.format( - self.label_name), length = pkg_ins.LABEL_STR_LEN) - - self.instr_stream.instr_list[i].has_label = 1 - else: - if(self.instr_stream.instr_list[i].has_label): - prefix = pkg_ins.format_string(string = '{}'.format( - self.instr_stream.instr_list[i].label), length = pkg_ins.LABEL_STR_LEN) - else: - prefix = pkg_ins.format_string(string = " ", length = pkg_ins.LABEL_STR_LEN) - string = prefix + self.instr_stream.instr_list[i].convert2asm() - self.instr_string_list.append(string) - - # TODO - def generate_return_routine(self): - pass - - # TODO - def insert_illegal_hint_instr(self): - pass +""" +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 logging +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 + + +class riscv_instr_sequence: + + def __init__(self): + self.instr_cnt = 0 + self.instr_stream = riscv_rand_instr_stream() + self.is_main_program = 0 + self.is_debug_program = 0 + self.label_name = "" + self.instr_string_list = [] # Save the instruction list + self.program_stack_len = 0 # Stack space allocated for this program + self.directed_instr = [] # List of all directed instruction stream + self.illegal_instr_pct = 0 # Percentage of illegal instructions + self.hint_instr_pct = 0 # Percentage of hint instructions + self.branch_idx = [None] * 30 + + def gen_instr(self, is_main_program, no_branch = 1): + self.is_main_program = is_main_program + self.instr_stream.initialize_instr_list(self.instr_cnt) + logging.info("Start generating %d instruction" % len(self.instr_stream.instr_list)) + self.instr_stream.gen_instr(no_branch = no_branch, no_load_store = 1, + is_debug_program = self.is_debug_program) + + if not is_main_program: + self.gen_stack_enter_instr() + self.gen_stack_exit_instr() + + # TODO + def gen_stack_enter_instr(self): + pass + + # TODO + def gen_stack_exit_instr(self): + pass + + ''' + ---------------------------------------------------------------------------------------------- + Instruction post-process + + Post-process is required for branch instructions: + + Need to assign a valid branch target. This is done by picking a random instruction label in + this sequence and assigning to the branch instruction. All the non-atomic instructions + will have a unique numeric label as the local branch target identifier. + The atomic instruction streams don't have labels except for the first instruction. This is + to avoid branching into an atomic instruction stream which breaks its atomicy. The + definition of an atomic instruction stream here is a sequence of instructions which must be + executed in-order. + In this sequence, only forward branch is handled. The backward branch target is implemented + in a dedicated loop instruction sequence. Randomly choosing a backward branch target could + lead to dead loops in the absence of proper loop exiting conditions. + ---------------------------------------------------------------------------------------------- + ''' + + def post_process_instr(self): + label_idx = 0 + branch_cnt = 0 + j = 0 + branch_target = defaultdict(lambda: None) + + for instr in self.directed_instr: + self.instr_stream.insert_instr_stream(instr.instr_list) + ''' + Assign an index for all instructions, these indexes wont change + even a new instruction is injected in the post process. + ''' + for i in range(len(self.instr_stream.instr_list)): + self.instr_stream.instr_list[i].idx = label_idx + if(self.instr_stream.instr_list[i].has_label and + not(self.instr_stream.instr_list[i].atomic)): + if((self.illegal_instr_pct > 0) and + (self.instr_stream.instr_list[i].insert_illegal_instr == 0)): + ''' + The illegal instruction generator always increase PC by 4 when resume execution, + need to make sure PC + 4 is at the correct instruction boundary. + ''' + if(self.instr_stream.instr_list[i].is_compressed): + if(i < (len(self.instr_stream.instr_list) - 1)): + if(self.instr_stream.instr_list[i + 1].is_compressed): + self.instr_stream.instr_list[i].is_illegal_instr = random.randrange( + 0, min(100, self.illegal_instr_pct)) + else: + self.instr_stream.instr_list[i].is_illegal_instr = random.randrange( + 0, min(100, self.illegal_instr_pct)) + if(self.hint_instr_pct > 0 and + (self.instr_stream.instr_list[i].is_illegal_instr == 0)): + if(self.instr_stream.instr_list[i].is_compressed): + self.instr_stream.instr_list[i].is_hint_instr = random.randrange( + 0, min(100, self.hint_instr_pct)) + + self.instr_stream.instr_list[i].label = "{}".format(label_idx) + self.instr_stream.instr_list[i].is_local_numeric_label = 1 + label_idx += 1 + + # Generate branch target + for i in range(len(self.branch_idx)): + 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 + (not self.instr_stream.instr_list[j].branch_assigned) and + (not self.instr_stream.instr_list[j].is_illegal_instr)): + ''' + Post process the branch instructions to give a valid local label + Here we only allow forward branch to avoid unexpected infinite loop + The loop structure will be inserted with a separate routine using + reserved loop registers + ''' + branch_target_label = 0 + branch_byte_offset = 0 + branch_target_label = self.instr_stream.instr_list[j].idx + \ + self.branch_idx[branch_cnt] + if(branch_target_label >= label_idx): + branch_target_label = label_idx - 1 + branch_cnt += 1 + if(branch_cnt == len(self.branch_idx)): + branch_cnt = 0 + random.shuffle(self.branch_idx) + logging.info("Processing branch instruction[%0d]:%0s # %0d -> %0d", j, + self.instr_stream.instr_list[j].convert2asm(), + self.instr_stream.instr_list[j].idx, branch_target_label) + self.instr_stream.instr_list[j].imm_str = "{}f".format(branch_target_label) + self.instr_stream.instr_list[j].branch_assigned = 1 + branch_target[branch_target_label] = 1 + + # Remove the local label which is not used as branch target + if(self.instr_stream.instr_list[j].has_label and + self.instr_stream.instr_list[j].is_local_numeric_label): + idx = int(self.instr_stream.instr_list[j].label) + if(not branch_target[idx]): + self.instr_stream.instr_list[j].has_label = 0 + j += 1 + logging.info("Finished post-processing instructions") + + def insert_jump_instr(self): + pass # TODO + + def generate_instr_stream(self, no_label = 0): + prefix = '' + string = '' + self.instr_string_list.clear() + + for i in range(len(self.instr_stream.instr_list)): + if i == 0: + if no_label: + prefix = pkg_ins.format_string(string = ' ', length = pkg_ins.LABEL_STR_LEN) + else: + prefix = pkg_ins.format_string(string = '{}:'.format( + self.label_name), length = pkg_ins.LABEL_STR_LEN) + + self.instr_stream.instr_list[i].has_label = 1 + else: + if(self.instr_stream.instr_list[i].has_label): + prefix = pkg_ins.format_string(string = '{}:'.format( + self.instr_stream.instr_list[i].label), length = pkg_ins.LABEL_STR_LEN) + else: + prefix = pkg_ins.format_string(string = " ", length = pkg_ins.LABEL_STR_LEN) + string = prefix + self.instr_stream.instr_list[i].convert2asm() + self.instr_string_list.append(string) + prefix = pkg_ins.format_string(str(i), pkg_ins.LABEL_STR_LEN) + + # TODO + def generate_return_routine(self): + pass + + # TODO + def insert_illegal_hint_instr(self): + pass 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 8cc37c5b..3b7303da 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 @@ -1,270 +1,36 @@ -# Lint as: python3 -"""Tests for riscv_instr_cov.""" +"""Copyright 2020 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. +""" + import sys -import os -import logging -import argparse -import vsc # PyVSC library -import csv # Python library to read/write from/to CSV files -from bitstring import BitArray -from pygen.pygen_src.isa.riscv_instr_cov import * +import vsc +import csv +from tabulate import * +from pygen.pygen_src.isa.riscv_cov_instr import riscv_cov_instr +from pygen.pygen_src.riscv_instr_cover_group import * from pygen.pygen_src.riscv_instr_pkg import * -from pygen.pygen_src.target.rv32i import riscv_core_setting as rcs + +logging.basicConfig(filename='logging_two_files_new.log', filemode='w', + format="%(filename)s %(lineno)s %(levelname)s %(message)s", + level=logging.ERROR) - -logging.basicConfig(filename='logging.log',level=logging.DEBUG) - -class riscv_instr(): - """ Class for a riscv instruction; data parsed from the CSV file will fill - different fields of an instruction """ - # class attr. to keep track of reg_name:reg_value throughout the program - gpr_state = {} - def __init__(self, instr_name): - self.pc = 0 # Program counter (PC) of the instruction - self.instr = instr_name - self.gpr = None # destination operand of the instruction - self.csr = None - self.binary = 0 # Instruction binary - self.mode = None # Instruction mode - self.trace = "None" # String representation of the instruction - self.operands = "None" # Instruction operands (srcss/dests) - self.pad = None # Not used - - self.rs1_value = None - self.rs2_value = None - self.rs3_value = None - self.rd_value = None - self.fs1_value = None - self.fs2_value = None - self.fs3_value = None - self.fd_value = None - - self.mem_addr = None - self.unaligned_pc = 0 - self.unaligned_mem_access = 0 - self.compressed = 0 - self.branch_hit = 0 - self.div_result = None - self.rs1_sign = None - self.rs2_sign = None - self.rs3_sign = None - self.fs1_sign = None - self.fs2_sign = None - self.fs3_sign = None - self.imm_sign = None - self.rd_sign = None - self.gpr_hazard = None - self.lsu_hazard = None - self.rs1_special_value = None - self.rs2_special_value = None - self.rs3_special_value = None - self.rd_special_value = None - self.imm_special_value = None - self.compare_result = None - self.logical_similarity = None - - # TODO: add & map... - #self.imm - #self.format - #self.category - - def pre_sample(self): - unaligned_pc = self.pc[-2:] != "00" - self.rs1_sign = self.get_operand_sign(self.rs1_value) - self.rs2_sign = self.get_operand_sign(self.rs2_value) - self.rs3_sign = self.get_operand_sign(self.rs3_value) - self.rd_sign = self.get_operand_sign(self.rd_value) - self.fs1_sign = self.get_operand_sign(self.fs1_value) - self.fs2_sign = self.get_operand_sign(self.fs2_value) - self.fs3_sign = self.get_operand_sign(self.fs3_value) - self.fd_sign = self.get_operand_sign(self.fd_value) - self.imm_sign = self.get_imm_sign(self.imm) - self.rs1_special_value = self.get_operand_special_value(self.rs1_value) - self.rd_special_value = self.get_operand_special_value(self.rd_value) - self.rs2_special_value = self.get_operand_special_value(self.rs2_value) - self.rs3_special_value = self.get_operand_special_value(self.rs3_value) - if (self.format != riscv_instr_format_t.R_FORMAT and - self.format != riscv_instr_format_t.CR_FORMAT): - self.imm_special_value = self.get_imm_special_val(self.imm) - if self.category in [riscv_instr_category_t.COMPARE, - riscv_instr_category_t.BRANCH]: - self.compare_result = self.get_compare_result() - if self.category in [riscv_instr_category_t.LOAD, - riscv_instr_category_t.STORE]: - self.mem_addr = self.rs1_value + self.imm - self.unaligned_mem_access = self.is_unaligned_mem_access() - if self.unaligned_mem_access: - logging.info("Unaligned: {}, mem_addr: {}".format( - self.instr, self.mem_addr)) - if self.category == riscv_instr_category_t.LOGICAL: - self.logical_similarity = self.get_logical_similarity() - if self.category == riscv_instr_category_t.BRANCH: - self.branch_hit = self.is_branch_hit() - #TODO: string > enumeration - if self.instr in ["DIV", "DIVU", "REM", "REMU", "DIVW", "DIVUW", - "REMW", "REMUW"]: - self.div_result = self.get_div_result() - - def get_operand_sign(self, operand): - #TODO: change operand to vsc.bit_t - out = BitArray(int=operand.val, length=rcs.XLEN) - if out[0]: - return operand_sign_e["NEGATIVE"] - else: - return operand_sign_e["POSITIVE"] - - def is_unaligned_mem_access(self): - #TODO: string > enumeration - if (self.instr in ["LWU", "LD", "SD", "C_LD", "C_SD"] and - self.mem_addr % 8 != 0): - return True - elif (self.instr in ["LW", "SW", "C_LW", "C_SW"] and - self.mem_addr % 4 != 0): - return True - elif (self.instr in ["LH", "LHU", "SH"] and - self.mem_addr % 2 != 0): - return True - return False - - def get_imm_sign(self, imm): - #TODO: change imm to vsc.int_t(32) - out = BitArray(int=imm.val, length=rcs.XLEN) - if out[0]: - return operand_sign_e["NEGATIVE"] - else: - return operand_sign_e["POSITIVE"] - - def get_div_result(self): - #TODO: change rs2_value to vsc.int_t(32) - if self.rs2_value.val == 0: - return div_result_e["DIV_BY_ZERO"] - elif self.rs2_value.val == 1 and self.rs1_value.val == (1 << (rcs.XLEN-1)): - return div_result_e["DIV_OVERFLOW"] - else: - return div_result_e["DIV_NORMAL"] - - def get_operand_special_value(self, operand): - if operand.val == 0: - return special_val_e["ZERO_VAL"] - elif operand.val == 1 << (rcs.XLEN-1): - return special_val_e["MIN_VAL"] - elif operand.val == 1 >> 1: - return special_val_e["MAX_VAL"] - else: - return special_val_e["NORMAL_VAL"] - - def get_imm_special_val(self, imm): - if imm.val == 0: - return special_val_e["ZERO_VAL"] - elif self.format == riscv_instr_format_t.U_FORMAT: - # unsigned immediate value - # TODO: self.imm_len - max = vsc.int_t(32, (1 << self.imm_len)-1) - if imm.val == 0: - return special_val_e["MIN_VAL"] - if imm.val == max.val: - return special_val_e["MAX_VAL"] - else: - # signed immediate value - max = vsc.int_t(32, (2 ** (self.imm_len - 1)) - 1) - min = vsc.int_t(32, -2 ** (self.imm_len - 1)) - if min.val == imm.val: - return special_val_e["MIN_VAL"] - if max.val == imm.val: - return special_val_e["MAX_VAL"] - return special_val_e["NORMAL_VAL"] - - def get_compare_result(self): - val1 = vsc.int_t(rcs.XLEN) - val2 = vsc.int_t(rcs.XLEN) - val1.val = self.rs1_value.val - val2.val = self.imm.val if ( - self.format == riscv_instr_format_t.I_FORMAT) \ - else self.rs2_value.val - if val1.val == val2.val: - return compare_result_e["EQUAL"] - elif val1.val < val2.val: - return compare_result_e["SMALLER"] - else: - return compare_result_e["LARGER"] - - def is_branch_hit(self): - # TODO: string/enumeration - if self.instr == "BEQ": - return self.rs1_value.val == self.rs2_value.val - elif self.instr == "C_BEQZ": - return self.rs1_value.val == 0 - elif self.instr == "BNE": - return self.rs1_value.val != self.rs2_value.val - elif self.instr == "C_BNEZ": - return self.rs1_value.val != 0 - elif self.instr == "BLT" or self.instr == "BLTU": - return self.rs1_value.val < self.rs2_value.val - elif self.instr == "BGE" or self.instr == "BGEU": - return self.rs1_value.val >= self.rs2_value.val - else: - logging.error("Unexpected instruction {}".format(self.instr)) - - def get_logical_similarity(self): - val1 = vsc.int_t(rcs.XLEN, self.rs1_value.val) - val2 = vsc.int_t(rcs.XLEN) - val2.val = (self.imm.val if self.format == riscv_instr_format_t.I_FORMAT - else self.rs2_value.val) - temp = bin(val1.val ^ val2.val) - bit_difference = len([[ones for ones in temp[2:] if ones=='1']]) - if val1.val == val2.val: - return logical_similarity_e["IDENTICAL"] - elif bit_difference == 32: - return logical_similarity_e["OPPOSITE"] - elif bit_difference < 5: - return logical_similarity_e["SIMILAR"] - else: - return logical_similarity_e["DIFFERENT"] - - def check_hazard_condition(self, pre_instr): - # TODO: has_rd(), has_rs1, has_rs2, rd, category, convert2asm (from IG) - if pre_instr.has_rd(): - if ((self.has_rs1 and self.rs1 == pre_instr.rd) or - (self.has_rs2 and self.rs1 == pre_instr.rd)): - self.gpr_hazard = hazard_e["RAW_HAZARD"] - elif self.has_rd and self.rd == pre_instr.rd: - self.gpr_hazard = hazard_e["WAW_HAZARD"] - elif (self.has_rd and - ((pre_instr.has_rs1 and (pre_instr.rs1 == self.rd)) or - (pre_instr.has_rs2 and (pre_instr.rs2 == self.rd)))): - self.gpr_hazard = hazard_e["WAR_HAZARD"] - else: - self.gpr_hazard = hazard_e["NO_HAZARD"] - if self.category == riscv_instr_category_t.LOAD: - # TODO: change mem_addr to vsc type - if (pre_instr.category == riscv_instr_category_t.STORE and - pre_instr.mem_addr == self.mem_addr): - self.lsu_hazard = hazard_e["RAW_HAZARD"] - else: - self.lsu_hazard = hazard_e["NO_HAZARD"] - if self.category == riscv_instr_category_t.STORE: - if (pre_instr.category == riscv_instr_category_t.STORE and - pre_instr.mem_addr == self.mem_addr): - self.lsu_hazard = hazard_e["WAW_HAZARD"] - elif (pre_instr.category == riscv_instr_category_t.LOAD and - pre_instr.mem_addr == self.mem_addr): - self.lsu_hazard = hazard_e["WAR_HAZARD"] - else: - self.lsu_hazard = hazard_e["NO_HAZARD"] - logging.info("Pre: {}, Cur: {}, Hazard: {}/{}".format( - pre_instr.convert2asm(), self.convert2asm(), - self.gpr_hazard.name, self.lsu_hazard.name)) - - def update_src_regs(self, operands): - pass - - def update_dst_regs(self, reg_name, val_str): - pass - -class riscv_instr_cov_test(): +class riscv_instr_cov_test: """ Main class for applying the functional coverage test """ + def __init__(self, argv): + self.instr_cg = riscv_instr_cover_group() self.trace = {} self.csv_trace = argv self.entry_cnt, self.total_entry_cnt, self.skipped_cnt, \ @@ -281,7 +47,7 @@ class riscv_instr_cov_test(): with open("{}".format(csv_file)) as trace_file: self.entry_cnt = 0 header = [] - entry = [] + self.instr_cg.reset() csv_reader = csv.reader(trace_file, delimiter=',') line_count = 0 # Get the header line @@ -297,27 +63,30 @@ class riscv_instr_cov_test(): self.skipped_cnt += 1 else: self.trace["csv_entry"] = row + logging.info("-----------------------------" + "-----------------------------") for idx in range(len(header)): if "illegal" in entry[idx]: expect_illegal_instr = True self.trace[header[idx]] = entry[idx] if header[idx] != "pad": logging.info("{} = {}".format(header[idx], - entry[idx])) + entry[idx])) self.post_process_trace() if self.trace["instr"] in ["li", "ret", "la"]: - pass - if "amo" in self.trace["instr"] or \ - "lr" in self.trace["instr"] or \ - "sc" in self.trace["instr"]: + continue + if ("amo" in self.trace["instr"] or + "lr" in self.trace["instr"] or + "sc" in self.trace["instr"]): # TODO: Enable functional coverage for AMO test - pass + continue if not self.sample(): if not expect_illegal_instr: logging.error("Found unexpected illegal " "instr: {} " "[{}]".format(self.trace[ - "instr"],entry)) + "instr"], + entry)) self.unexpected_illegal_instr_cnt += 1 self.entry_cnt += 1 line_count += 1 @@ -326,53 +95,82 @@ class riscv_instr_cov_test(): self.total_entry_cnt += self.entry_cnt logging.info("Finished processing {} trace CSV, {} " "instructions".format(len(self.csv_trace), - self.total_entry_cnt)) + self.total_entry_cnt)) if self.skipped_cnt > 0 or self.unexpected_illegal_instr_cnt > 0: logging.error("{} instruction skipped, {} illegal " - "instructions".format(self.skipped_cnt), - self.unexpected_illegal_instr_cnt) + "instructions".format(self.skipped_cnt, + self.unexpected_illegal_instr_cnt)) + self.get_coverage_report() + + @staticmethod + def get_coverage_report(): + model = vsc.get_coverage_report_model() + file = open('CoverageReport.txt', 'w') + file.write("Groups Coverage Summary\n") + file.write("Total groups in report: {}\n".format( + len(model.covergroups))) + headers = ["SCORE", "WEIGHT", "NAME"] + table = [] + for cg in model.covergroups: + table.append([cg.coverage, cg.weight, cg.name]) + file.write(tabulate(table, headers, tablefmt="grid", + numalign="center", stralign="center")) + file.close() def post_process_trace(self): pass def sample(self): - instr_name, binary = "", "" - binary = get_val(self.trace["binary"], hexa=1) - if binary[-2:] != "11": #TODO: and RV32C in supported_isa - #TODO: sample compressed instruction + binary = vsc.int_t(rcs.XLEN) + binary.set_val(get_val(self.trace["binary"], hexa=1)) + # TODO: Currently handled using string formatting as part select + # isn't yet supported for global vsc variables + # width is rcs.XLEN+2 because of 0b in the beginning of binary_bin + binary_bin = format(binary.get_val(), '#0{}b'.format(rcs.XLEN + 2)) + if binary_bin[-2:] != "11": # TODO: and RV32C in supported_isa + # TODO: sample compressed instruction pass - if binary[-2:] == "11": - #TODO: sampling + if binary_bin[-2:] == "11": + # TODO: sampling pass - #TODO: buch of if statements to check if the instruction name is valid - # and is a member of registered ones - instr_name = self.process_instr_name(self.trace["instr"]) - instruction = riscv_instr(instr_name) - #TODO: check the instruction group... - self.assign_trace_info_to_instr(instruction) - #TODO: instruction.pre_sample() and sample(instruction) - return True + processed_instr_name = self.process_instr_name(self.trace["instr"]) + if processed_instr_name in riscv_instr_name_t.__members__: + instr_name = riscv_instr_name_t[processed_instr_name] + instruction = riscv_cov_instr() + instruction.instr = instr_name + # cov_instr is created, time to manually assign attributes + # TODO: This will get fixed later when we get an inst from template + instruction.assign_attributes() + if instruction.group.name in ["RV32I", "RV32M", "RV32C", "RV64I", + "RV64M", "RV64C", "RV32F", "RV64F", + "RV32D", "RV64D", "RV32B", "RV64B"]: + self.assign_trace_info_to_instr(instruction) + instruction.pre_sample() + self.instr_cg.sample(instruction) + return True + logging.info("Cannot find opcode: {}".format(processed_instr_name)) + return False def assign_trace_info_to_instr(self, instruction): - operands, gpr_update, pair = [], [], [] - instruction.pc = get_val(self.trace["pc"], hexa=1) - instruction.binary = get_val(self.trace["binary"], hexa=1) - instruction.gpr = self.trace["gpr"] - instruction.csr = self.trace["csr"] - instruction.mode = self.trace["mode"] + instruction.pc.set_val(get_val(self.trace["pc"], hexa=1)) + instruction.binary.set_val(get_val(self.trace["binary"], hexa=1)) instruction.trace = self.trace["instr_str"] - instruction.operands = self.trace["operand"] + if instruction.instr.name in ["NOP", "WFI", "FENCE", "FENCE_I", + "EBREAK", "C_EBREAK", "SFENCE_VMA", + "ECALL", "C_NOP", "MRET", "SRET", + "URET"]: + return operands = self.trace["operand"].split(",") instruction.update_src_regs(operands) + gpr_update = self.trace["gpr"].split(";") - if len(gpr_update) == 1 and gpr_update[0] == "": + if len(gpr_update) == 1 and gpr_update[0] == "": gpr_update = [] for dest in gpr_update: pair = dest.split(":") if len(pair) != 2: logging.error("Illegal gpr update format: {}".format(dest)) instruction.update_dst_regs(pair[0], pair[1]) - instruction.pad = self.trace["pad"] def process_instr_name(self, instruction): instruction = instruction.upper() @@ -380,18 +178,19 @@ class riscv_instr_cov_test(): instruction = self.update_instr_name(instruction) return instruction - def update_instr_name(self, instruction): + @staticmethod + def update_instr_name(instruction): switcher = { # Rename to new name as ovpsim still uses old name "FMV_S_X": "FMV_W_X", "FMV_X_S": "FMV_X_W", # Convert pseudoinstructions - "FMV_S": "FSGNJ_S", - "FABS_S": "FSGNJX_S", - "FNEG_S": "FSGNJN_S", - "FMV_D": "FSGNJ_D", - "FABS_D": "FSGNJX_D", - "FNEG_D": "FSGNJN_D", + "FMV_S" : "FSGNJ_S", + "FABS_S" : "FSGNJX_S", + "FNEG_S" : "FSGNJN_S", + "FMV_D" : "FSGNJ_D", + "FABS_D" : "FSGNJX_D", + "FNEG_D" : "FSGNJN_D", } # if instruction is not present in the dictionary,second argument well # be assigned as default value of passed argument @@ -399,9 +198,10 @@ class riscv_instr_cov_test(): return instruction -def main(argv): +def main(argv): cov_test = riscv_instr_cov_test(argv) cov_test.run_phase() + if __name__ == "__main__": main(sys.argv) diff --git a/vendor/google_riscv-dv/requirements.txt b/vendor/google_riscv-dv/requirements.txt index 3483387a..26b37214 100644 --- a/vendor/google_riscv-dv/requirements.txt +++ b/vendor/google_riscv-dv/requirements.txt @@ -8,3 +8,4 @@ sphinx_rtd_theme rst2pdf flake8 pyvsc +tabulate diff --git a/vendor/google_riscv-dv/src/isa/riscv_instr_cov.svh b/vendor/google_riscv-dv/src/isa/riscv_instr_cov.svh index 18b79252..569f6392 100644 --- a/vendor/google_riscv-dv/src/isa/riscv_instr_cov.svh +++ b/vendor/google_riscv-dv/src/isa/riscv_instr_cov.svh @@ -160,9 +160,6 @@ // unsigend immediate value bit [31:0] max_val; max_val = (1 << imm_len)-1; - if (value == '0) begin - return MIN_VAL; - end if (value == max_val) begin return MAX_VAL; end diff --git a/vendor/google_riscv-dv/src/riscv_pmp_cfg.sv b/vendor/google_riscv-dv/src/riscv_pmp_cfg.sv index 7c2155b3..ffb949a6 100644 --- a/vendor/google_riscv-dv/src/riscv_pmp_cfg.sv +++ b/vendor/google_riscv-dv/src/riscv_pmp_cfg.sv @@ -97,7 +97,7 @@ class riscv_pmp_cfg extends uvm_object; // Offset of pmp_cfg[0] does not matter, since it will be set to
, // so we do not constrain it here, as it will be overridden during generation if (i != 0) { - pmp_cfg[i].offset inside {[1 : pmp_max_offset + 1]}; + pmp_cfg[i].offset inside {[1 : pmp_max_offset]}; } else { pmp_cfg[i].offset == 0; } @@ -622,7 +622,7 @@ class riscv_pmp_cfg extends uvm_object; for (int i = 0; i < pmp_num_regions; i++) begin pmp_addr = base_pmp_addr + i; pmpcfg_addr = base_pmpcfg_addr + (i / cfg_per_csr); - // We randomize the upper 31 bits of pmp_val and then add this to the + // We randomize the lower 31 bits of pmp_val and then add this to the // address of
, guaranteeing that the random value written to // pmpaddr[i] doesn't interfere with the safe region. `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(pmp_val, pmp_val[31] == 1'b0;) @@ -642,12 +642,15 @@ class riscv_pmp_cfg extends uvm_object; // // TODO: support rv64. `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(pmp_val, - // Need to constrain pmp_val[7], pmp_val[15], ... to 1'b0 - // to ensure that the random config regions aren't locked foreach (pmp_val[i]) { + // constrain each Lock bit to 0 if ((i+1) % 8 == 0) { pmp_val[i] == 1'b0; } + // prevent W=1/R=0 combination + if (i % 8 == 0) { // this is an R bit + !((pmp_val[i] == 0) && (pmp_val[i+1] == 1'b1)); + } } ) // If we're writing to the pmpcfg CSR that contains region0 config information,