From: Jacob Lifshay Date: Sat, 24 Sep 2022 00:12:47 +0000 (-0700) Subject: pcdec. works! X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a3d71d6e00a14a6cadff2f65662758a123600daf;p=openpower-isa.git pcdec. works! --- diff --git a/openpower/isa/prefix_codes.mdwn b/openpower/isa/prefix_codes.mdwn index 4292a614..ab6c2c6b 100644 --- a/openpower/isa/prefix_codes.mdwn +++ b/openpower/isa/prefix_codes.mdwn @@ -4,7 +4,7 @@ VA2-Form -* pcdec. RT,RA,RB,RC,once (Rc=1) +* pcdec. RT,RA,RB,RC,once Pseudo-code: diff --git a/src/openpower/test/prefix_codes/prefix_codes_cases.py b/src/openpower/test/prefix_codes/prefix_codes_cases.py index 797d8ffa..0f8a72aa 100644 --- a/src/openpower/test/prefix_codes/prefix_codes_cases.py +++ b/src/openpower/test/prefix_codes/prefix_codes_cases.py @@ -2,49 +2,131 @@ from openpower.test.common import TestAccumulatorBase from openpower.sv.trans.svp64 import SVP64Asm from openpower.test.state import ExpectedState from openpower.simulator.program import Program -from copy import deepcopy + def tree_code(code): # type: (str) -> int retval = 1 - for bit in reversed(code): + for bit in code: assert bit in "01" retval = retval * 2 + int(bit) + assert retval < 64, "code too long" return retval def make_tree(*codes): # type: (*str) -> int retval = 0 - for code in codes: + for code in sorted(codes, key=len): + for i in range(len(code)): + assert retval & (1 << tree_code(code[:i])) == 0, \ + f"conflicting code: {code} conflicts with {code[:i]}" retval |= 1 << tree_code(code) return retval -def code_seq(*codes, prefix1=False): - # type: (*str, bool) -> int - prefix = "0b1" if prefix1 else "0b" - return int(prefix + "".join(reversed(codes)), base=0) +def reference_pcdec(supported_codes, input_bits, max_count): + # type: (set[str], str, int) -> tuple[list[str], bool] + assert input_bits.lstrip("01") == "", "input_bits must be binary bits" + retval = [] + current_code = "" + overflow = False + for bit in input_bits: + current_code += bit + if len(current_code) > 6: + overflow = True + break + if current_code in supported_codes: + retval.append(current_code) + current_code = "" + if len(retval) >= max_count: + break + return retval, overflow + + +CODE_2 = "0" +CODE_7 = "11" +CODE_19 = "1001" +CODE_35 = "10101" +CODE_37 = "10111" +CODES = {CODE_2, CODE_7, CODE_19, CODE_35, CODE_37} class PrefixCodesCases(TestAccumulatorBase): - def case_pcdec_simple(self): - lst = list(SVP64Asm(["pcdec. 4,6,7,5,0"])) + def check_pcdec(self, supported_codes, input_bits, src_loc_at=0): + # type: (set[str], str, int) -> None + original_input_bits = input_bits + input_bits = input_bits.replace("_", "") + assert input_bits.lstrip("01") == "", "input_bits must be binary bits" + assert len(input_bits) < 128, "input_bits too long" + decoded, expected_SO = reference_pcdec( + supported_codes, input_bits, max_count=8) + expected_EQ = len(decoded) == 0 + expected_RT = int.from_bytes( + [int("1" + code, 2) for code in decoded], 'little') + decoded_bits_len = len("".join(decoded)) + expected_rb_used = False + RA_val = make_tree(*supported_codes) + rev_input_bits = input_bits[::-1] + RB_val = 0 + RB = 0 + expected_RS = None + if len(input_bits) >= 64: + RB_val = int(rev_input_bits[:64], 2) + RB = 7 + rev_input_bits = rev_input_bits[64:] + expected_rb_used = decoded_bits_len > len(rev_input_bits) + if expected_rb_used: + expected_RS = (RB_val + 2 ** 64) >> decoded_bits_len + RC_val = int("1" + rev_input_bits, 2) + if expected_RS is None: + expected_RS = RC_val >> decoded_bits_len + lst = list(SVP64Asm([f"pcdec. 4,6,{RB},5,0"])) gprs = [0] * 32 - gpr5_codes = ["0", "11", "1001", "101010"] - gpr7_codes = ["1001"] * 8 + ["101010", "11"] * 4 - gprs[5] = code_seq(*gpr5_codes, prefix1=True) - # XXX hack out bits 65 and above from make_tree() with mask - gprs[6] = make_tree("0", "11", "1001", "101010") & 0xffff_ffff_ffff_ffff - gprs[7] = code_seq(*gpr7_codes) - # take a deep copy of the gprs above so that overwrites do not mess up - expected_regs = deepcopy(gprs) - expected_regs[4] = int.from_bytes( - map(tree_code, (gpr5_codes + gpr7_codes)[:8]), 'little') - expected_regs[5] = code_seq(*(gpr5_codes + gpr7_codes)[8:], - prefix1=True) - expected_regs[4] = 0x2190702 # XXX to get a "pass" - expected_regs[5] = 0x35 # XXX to get a "pass" - e = ExpectedState(pc=4, int_regs=expected_regs) - e.crregs[0] = 0b1000 - self.add_case(Program(lst, False), gprs, expected=e) + gprs[6] = RA_val + if RB: + gprs[RB] = RB_val + gprs[5] = RC_val + e = ExpectedState(pc=4, int_regs=gprs) + e.intregs[4] = expected_RT + e.intregs[5] = expected_RS + e.crregs[0] = expected_rb_used * 8 + expected_EQ * 2 + expected_SO + with self.subTest(supported_codes=supported_codes, + input_bits=original_input_bits): + self.add_case(Program(lst, False), gprs, expected=e, + src_loc_at=src_loc_at + 1) + + def case_pcdec_empty(self): + self.check_pcdec({CODE_2}, "") + + def case_pcdec_only_one_code(self): + self.check_pcdec({CODE_37}, CODE_37) + + def case_pcdec_short_seq(self): + self.check_pcdec(CODES, "_".join([CODE_2, CODE_19, CODE_35])) + + def case_pcdec_medium_seq(self): + self.check_pcdec(CODES, "0_11_1001_10101_10111_10111_10101_1001_11_0") + + def case_pcdec_long_seq(self): + self.check_pcdec(CODES, + "0_11_1001_10101_10111_10111_10101_1001_11_0" + + CODE_37 * 6) + + def case_pcdec_invalid_code_at_start(self): + self.check_pcdec(CODES, "_".join(["1000", CODE_35])) + + def case_pcdec_invalid_code_after_3(self): + self.check_pcdec(CODES, "_".join( + [CODE_2, CODE_19, CODE_35, "1000", CODE_35])) + + def case_pcdec_invalid_code_after_8(self): + self.check_pcdec(CODES, "_".join( + [CODE_2, CODE_19, *([CODE_35] * 6), "1000", CODE_35])) + + def case_pcdec_invalid_code_in_rb(self): + self.check_pcdec(CODES, "_".join( + [CODE_2, CODE_19, "1000", *([CODE_19] * 15)])) + + def case_pcdec_overlong_code(self): + self.check_pcdec(CODES, "_".join([CODE_2, CODE_19, "10000000"]))