def get_rs1_val(iteration, xlen): """ Calculates and returns the 3 test RS1 values that will be used to exercise the CSR. Args: iteration: Integer between 0 and 2 inclusive, indicates which test value to return. xlen: The currnet RISC-V ISA bit length. Returns: A bitarray encoding the value that will be written to the CSR to test it. Will be one of 3 values: 1) 0xa5a5... 2) 0x5a5a... 3) A randomly generated number """ if iteration == 0: return bitarray(hex=f"0x{'a5'*int(xlen/8)}") elif iteration == 1: return bitarray(hex=f"0x{'5a'*int(xlen/8)}") elif iteration == 2: val = bitarray(uint=0, length=xlen) # Must randomize all 32 bits, due to randomization library limitations for i in range(32): bit = random.randint(0, 1) val.set(bit, i) return val
def predict_csr_val(csr_op, rs1_val, csr_val, csr_address, csr_write_mask, csr_read_mask): """ Predicts the CSR reference value, based on the current CSR operation. Args: csr_op: A string of the CSR operation being performed. rs1_val: A bitarray containing the value to be written to the CSR. csr_val: A bitarray containing the current value of the CSR. csr_write_mask: A bitarray containing the CSR's write mask. csr_read_mask: A bitarray containing the CSR's read mask Returns: A hexadecimal string of the predicted CSR value. """ prediction = None max_event = bitarray(uint=50, length=32) # create a zero bitarray to zero extend immediates zero = bitarray(uint=0, length=csr_val.len - 5) prediction = csr_read(csr_val, csr_read_mask) if csr_op == 'csrrw': if (csr_address == 803 or csr_address == 804 or csr_address == 805 or csr_address == 806): if(max_event.uint<rs1_val.uint): csr_val.overwrite(bitarray(uint=50, length=32), 0) else: csr_write(rs1_val, csr_val, csr_write_mask) else: csr_write(rs1_val, csr_val, csr_write_mask) elif csr_op == 'csrrs': if (csr_address == 803 or csr_address == 804 or csr_address == 805 or csr_address == 806): if((max_event.uint<rs1_val.uint) or (max_event.uint<=csr_val.uint)): csr_val.overwrite(bitarray(uint=50, length=32), 0) else: csr_write(rs1_val, csr_val, csr_write_mask) else: csr_write(rs1_val | prediction, csr_val, csr_write_mask) elif csr_op == 'csrrc': """if (csr_address == 803 or csr_address == 804 or csr_address == 805 or csr_address == 806): if(max_event.uint<rs1_val.uint): csr_val.overwrite(bitarray(uint=0, length=32), 0) else: csr_write((~rs1_val) & prediction, csr_val, csr_write_mask) else:""" csr_write((~rs1_val) & prediction, csr_val, csr_write_mask) elif csr_op == 'csrrwi': zero.append(rs1_val[-5:]) csr_write(zero, csr_val, csr_write_mask) elif csr_op == 'csrrsi': zero.append(rs1_val[-5:]) csr_write(zero | prediction, csr_val, csr_write_mask) elif csr_op == 'csrrci': zero.append(rs1_val[-5:]) csr_write((~zero) & prediction, csr_val, csr_write_mask) return "0x{}".format(prediction.hex)
def get_csr_map(csr_file, xlen): """ Parses the YAML file containing CSR descriptions. Args: csr_file: The CSR YAML file. xlen: The current RISC-V ISA bit length. Returns: A dictionary contining mappings for each CSR, of the form: { csr_name : [csr_address, csr_val_bitarray, csr_write_mask_bitarray, csr_read_mask_bitarray] } """ rv_string = "rv{}".format(str(xlen)) csrs = {} with open(csr_file, "r") as c: csr_description = yaml.safe_load(c) for csr_dict in csr_description: csr_name = csr_dict.get("csr") csr_address = csr_dict.get("address") assert ( rv_string in csr_dict), "The {} CSR must be configured for rv{}".format( csr_name, str(rv)) csr_value = bitarray(uintbe=0, length=xlen) csr_write_mask = [] csr_read_mask = bitarray(uintbe=0, length=xlen) csr_field_list = csr_dict.get(rv_string) for csr_field_detail_dict in csr_field_list: field_type = csr_field_detail_dict.get("type") field_val = csr_field_detail_dict.get("reset_val") field_msb = csr_field_detail_dict.get("msb") field_lsb = csr_field_detail_dict.get("lsb") field_size = field_msb - field_lsb + 1 if field_type != "WPRI": val_bitarray = bitarray(uint=field_val, length=field_size) mask_bitarray = bitarray(uint=1, length=1) * field_size start_pos = xlen - 1 - field_msb end_pos = xlen - 1 - field_lsb csr_read_mask.overwrite(mask_bitarray, xlen - 1 - field_msb) csr_value.overwrite(val_bitarray, xlen - 1 - field_msb) access = True if field_type == "R" else False csr_write_mask.append( [mask_bitarray, (start_pos, end_pos), access]) csrs.update({ csr_name: [csr_address, csr_value, csr_write_mask, csr_read_mask] }) return csrs
def predict_csr_val(csr_op, rs1_val, csr_val, csr_write_mask, csr_read_mask): """ Predicts the CSR reference value, based on the current CSR operation. Args: csr_op: A string of the CSR operation being performed. rs1_val: A bitarray containing the value to be written to the CSR. csr_val: A bitarray containing the current value of the CSR. csr_write_mask: A bitarray containing the CSR's write mask. csr_read_mask: A bitarray containing the CSR's read mask Returns: A hexadecimal string of the predicted CSR value. """ prediction = None # create a zero bitarray to zero extend immediates zero = bitarray(uint=0, length=csr_val.len - 5) prediction = csr_read(csr_val, csr_read_mask) if csr_op == 'csrrw': csr_write(rs1_val, csr_val, csr_write_mask) elif csr_op == 'csrrs': csr_write(rs1_val | prediction, csr_val, csr_write_mask) elif csr_op == 'csrrc': csr_write((~rs1_val) & prediction, csr_val, csr_write_mask) elif csr_op == 'csrrwi': zero.append(rs1_val[-5:]) csr_write(zero, csr_val, csr_write_mask) elif csr_op == 'csrrsi': zero.append(rs1_val[-5:]) csr_write(zero | prediction, csr_val, csr_write_mask) elif csr_op == 'csrrci': zero.append(rs1_val[-5:]) csr_write((~zero) & prediction, csr_val, csr_write_mask) return f"0x{prediction.hex}"
def gen_csr_instr(csr_map, csr_instructions, xlen, iterations, out): """ Uses the information in the map produced by get_csr_map() to generate test CSR instructions operating on the generated random values. Args: csr_map: The dictionary containing CSR mappings generated by get_csr_map() csr_instructions: A list of all supported CSR instructions in string form. xlen: The RISC-V ISA bit length. iterations: Indicates how many randomized test files will be generated. out: A string containing the directory path that the tests will be generated in. Returns: No explicit return value, but will write the randomized assembly test code to the specified number of files. """ for i in range(iterations): # pick two GPRs at random to act as source and destination registers # for CSR operations source_reg, dest_reg = [f"x{i}" for i in random.sample(range(5, 15), 2)] csr_list = list(csr_map.keys()) with open(f"{out}/riscv_csr_test.{i}.S", "w") as csr_test_file: csr_test_file.write(f"csr_test:\n") for csr in csr_list: last_csr = csr csr_val, csr_mask = csr_map.get(csr) for op in csr_instructions: for i in range(3): # hex string rand_rs1_val = get_rs1_val(i, xlen) # I type CSR instruction first_li = "" if op[-1] == "i": imm = rand_rs1_val[-5:] csr_inst = f"\t{op} {dest_reg}, {csr}, 0b{imm.bin}\n" else: first_li = f"\tli {source_reg}, 0x{rand_rs1_val.hex}\n" csr_inst = f"\t{op} {dest_reg}, {csr}, {source_reg}\n" predict_li = f"\tli {source_reg}, {predict_csr_val(op, rand_rs1_val, csr_val, csr_mask)}\n" branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n" csr_test_file.write(first_li) csr_test_file.write(csr_inst) csr_test_file.write(predict_li) csr_test_file.write(branch_check) """ We must hardcode in one final CSR check, as the value that has last been written to the CSR has not been tested. """ if csr == csr_list[-1] and op == csr_instructions[-1] and i == 2: final_csr_read = f"\tcsrr {dest_reg}, {csr_list[-1]}\n" csrrs_read_mask = bitarray(uint=0, length=xlen) final_li = f"\tli {source_reg}, {predict_csr_val('csrrs', csrrs_read_mask, csr_val, csr_mask)}\n" final_branch_check = f"\tbne {source_reg}, {dest_reg}, csr_fail\n" csr_test_file.write(final_csr_read) csr_test_file.write(final_li) csr_test_file.write(final_branch_check) gen_csr_test_pass(csr_test_file) gen_csr_test_fail(csr_test_file)
def gen_csr_instr(original_csr_map, csr_instructions, xlen, iterations, out, end_signature_addr): """ Uses the information in the map produced by get_csr_map() to generate test CSR instructions operating on the generated random values. Args: original_csr_map: The dictionary containing CSR mappings generated by get_csr_map() csr_instructions: A list of all supported CSR instructions in string form. xlen: The RISC-V ISA bit length. iterations: Indicates how many randomized test files will be generated. out: A string containing the directory path that the tests will be generated in. end_signature_addr: The address the test should write to upon terminating Returns: No explicit return value, but will write the randomized assembly test code to the specified number of files. """ for i in range(iterations): # pick two GPRs at random to act as source and destination registers # for CSR operations csr_map = copy.deepcopy(original_csr_map) source_reg, dest_reg = [ "x{}".format(i) for i in random.sample(range(1, 16), 2) ] csr_list = list(csr_map.keys()) with open("{}/riscv_csr_test_{}.S".format(out, i), "w") as csr_test_file: gen_setup(csr_test_file) for csr in csr_list: csr_address, csr_val, csr_write_mask, csr_read_mask = csr_map.get( csr) csr_test_file.write("\t# {}\n".format(csr)) for op in csr_instructions: for i in range(3): # hex string rand_rs1_val = get_rs1_val(i, xlen) # I type CSR instruction first_li = "" if op[-1] == "i": imm = rand_rs1_val[-5:] csr_inst = "\t{} {}, {}, 0b{}\n".format( op, dest_reg, csr_address, imm.bin) imm_val = bitarray(uint=0, length=xlen - 5) imm_val.append(imm) predict_li = ("\tli {}, " "{}\n".format( source_reg, predict_csr_val( op, imm_val, csr_val, csr_write_mask, csr_read_mask))) else: first_li = "\tli {}, 0x{}\n".format( source_reg, rand_rs1_val.hex) csr_inst = "\t{} {}, {}, {}\n".format( op, dest_reg, csr_address, source_reg) predict_li = ("\tli {}, " "{}\n".format( source_reg, predict_csr_val( op, rand_rs1_val, csr_val, csr_write_mask, csr_read_mask))) branch_check = "\tbne {}, {}, csr_fail\n".format( source_reg, dest_reg) csr_test_file.write(first_li) csr_test_file.write(csr_inst) csr_test_file.write(predict_li) csr_test_file.write(branch_check) """ We must hardcode in one final CSR check, as the value that has last been written to the CSR has not been tested. """ if csr == csr_list[-1] and op == csr_instructions[ -1] and i == 2: final_csr_read = "\tcsrr {}, {}\n".format( dest_reg, csr_address) csrrs_read_mask = bitarray(uint=0, length=xlen) final_li = ("\tli {}, " "{}\n".format( source_reg, predict_csr_val( 'csrrs', csrrs_read_mask, csr_val, csr_write_mask, csr_read_mask))) final_branch_check = "\tbne {}, {}, csr_fail\n".format( source_reg, dest_reg) csr_test_file.write(final_csr_read) csr_test_file.write(final_li) csr_test_file.write(final_branch_check) gen_csr_test_pass(csr_test_file, end_signature_addr) gen_csr_test_fail(csr_test_file, end_signature_addr)