def test_all_candidate_instructions_are_offered_to_the_destinaton_unit( self): """Test candidate instructions aren't shortlisted. `self` is this test case. """ in_unit, out_unit = (UnitModel(ICaseString(name), width, ["ALU", "MEM"], LockInfo(rd_lock, wr_lock), mem_acl) for name, width, rd_lock, wr_lock, mem_acl in [( "input", 3, True, False, []), ("output", 2, False, True, ["MEM"])]) proc_desc = ProcessorDesc([in_unit], [FuncUnit(out_unit, [in_unit])], [], []) self.assertEqual( simulate([ HwInstruction([], *instr_params) for instr_params in [["R1", "MEM"], ["R2", "MEM"], ["R3", "ALU"]] ], HwSpec(proc_desc)), [ BagValDict(cp_util) for cp_util in [{ ICaseString("input"): map(InstrState, [0, 1, 2]) }, { ICaseString("output"): map(InstrState, [0, 2]), ICaseString("input"): [InstrState(1, StallState.STRUCTURAL)] }, { ICaseString("output"): [InstrState(1)] }] ])
def test_hazard(self): """Test structural hazards in a unified memory architecture. `self` is this test case. """ in_unit, out_unit = (UnitModel( ICaseString(name), 1, ["ALU", "MEM"], LockInfo(rd_lock, wr_lock), mem_acl) for name, rd_lock, wr_lock, mem_acl in [( "input", True, False, ["ALU", "MEM"]), ("output", False, True, ["MEM"])]) proc_desc = ProcessorDesc([in_unit], [FuncUnit(out_unit, [in_unit])], [], []) self.assertEqual( simulate([ HwInstruction([], out_reg, "ALU") for out_reg in ["R1", "R2"] ], HwSpec(proc_desc)), [ BagValDict(cp_util) for cp_util in [{ ICaseString("input"): [InstrState(0)] }, { ICaseString("output"): [InstrState(0)], ICaseString("input"): [InstrState(1)] }, { ICaseString("output"): [InstrState(1)] }] ])
class TestBasic: """Test case for basic simulation scenarios""" @mark.parametrize("prog, cpu, util_tbl", [ ([(["R11", "R15"], "R14", "alu")], read_proc_file("processors", "singleALUProcessor.yaml"), [{ICaseString("full system"): [InstrState(0)]}]), ([([], "R12", "MEM"), (["R11", "R15"], "R14", "ALU")], read_proc_file( "processors", "multiplexedInputSplitOutputProcessor.yaml"), [{ICaseString("input"): map(InstrState, [1, 0])}, {ICaseString("ALU output"): [InstrState(1)], ICaseString("MEM output"): [InstrState(0)]}])]) def test_sim(self, prog, cpu, util_tbl): """Test executing a program. `self` is this test case. `prog` is the program to run. `cpu` is the processor to run the program on. `util_tbl` is the expected utilization table. """ assert simulate([HwInstruction(*regs, ICaseString(categ)) for *regs, categ in prog], HwSpec(cpu)) == [ BagValDict(inst_util) for inst_util in util_tbl]
def test_write_registers_are_not_checked_in_units_without_write_lock(self): """Test opportune write register access check. `self` is this test case. """ in_unit, out_unit = (UnitModel( ICaseString(name), 1, ["ALU"], LockInfo(rd_lock, wr_lock), []) for name, rd_lock, wr_lock in [("input", False, False), ("output", True, True)]) proc_desc = ProcessorDesc([in_unit], [FuncUnit(out_unit, [in_unit])], [], []) self.assertEqual( simulate([ HwInstruction(*instr_regs, "ALU") for instr_regs in [[["R1"], "R2"], [[], "R1"]] ], HwSpec(proc_desc)), [ BagValDict(cp_util) for cp_util in [{ ICaseString("input"): [InstrState(0)] }, { ICaseString("input"): [InstrState(1)], ICaseString("output"): [InstrState(0)] }, { ICaseString("output"): [InstrState(1)] }] ])
def test_capability_with_nonstandard_case_is_detected( self, caplog, unit, acl_cap): """Test loading an ACL with a non-standard capability case. `self` is this test case. `caplog` is the log capture fixture. `unit` is the loaded unit name. `acl_cap` is the ACL capability to verify. """ caplog.set_level(WARNING) ref_cap = acl_cap.upper() assert load_proc_desc({ "units": [{ UNIT_NAME_KEY: unit, UNIT_WIDTH_KEY: 1, UNIT_CAPS_KEY: [ref_cap], **{attr: True for attr in [UNIT_RLOCK_KEY, UNIT_WLOCK_KEY]}, UNIT_MEM_KEY: [acl_cap] }], "dataPath": [] }) == ProcessorDesc([], [], [ UnitModel(ICaseString(unit), 1, [ICaseString(ref_cap)], LockInfo(True, True), [ICaseString(ref_cap)]) ], []) assert caplog.records warn_msg = caplog.records[0].getMessage() for token in [acl_cap, unit, ref_cap]: assert token in warn_msg
def test_capability_case_is_checked_across_all_units(self, caplog, unit): """Test ACL capability cases are checked across all units. `self` is this test case. `caplog` is the log capture fixture. """ caplog.set_level(WARNING) in_out_units = (UnitModel(ICaseString(name), 1, [ICaseString("ALU")], LockInfo(True, True), map(ICaseString, capabilities)) for name, capabilities in [(unit, []), ("core 2", ["ALU"])]) assert load_proc_desc({ "units": [{ UNIT_NAME_KEY: unit, UNIT_WIDTH_KEY: 1, UNIT_CAPS_KEY: ["ALU"], **{attr: True for attr in [UNIT_RLOCK_KEY, UNIT_WLOCK_KEY]} }, { UNIT_NAME_KEY: "core 2", UNIT_WIDTH_KEY: 1, UNIT_CAPS_KEY: ["ALU"], **{attr: True for attr in [UNIT_RLOCK_KEY, UNIT_WLOCK_KEY]}, UNIT_MEM_KEY: ["alu"] }], "dataPath": [] }) == ProcessorDesc([], [], in_out_units, []) assert caplog.records warn_msg = caplog.records[0].getMessage() for token in ["alu", "core 2", "ALU", unit]: assert token in warn_msg
def test_path_with_multiple_locks_raises_PathLockError( self, proc_desc, lock_data): """Test loading a processor with multiple locks in paths. `self` is this test case. `proc_desc` is the processor description. `lock_data` is the lock test data. """ ex_info = raises(PathLockError, load_proc_desc, { "units": [{UNIT_NAME_KEY: proc_desc.in_unit, UNIT_WIDTH_KEY: 1, UNIT_CAPS_KEY: [proc_desc.capability], **{lock_prop: True for lock_prop in [UNIT_RLOCK_KEY, lock_data.prop_name]}}, {UNIT_NAME_KEY: proc_desc.out_unit, UNIT_WIDTH_KEY: 1, UNIT_CAPS_KEY: [proc_desc.capability], **{lock_prop: True for lock_prop in [UNIT_WLOCK_KEY, lock_data.prop_name]}}], "dataPath": [[proc_desc.in_unit, proc_desc.out_unit]]}) assert ex_info.value.start == ICaseString(proc_desc.in_unit) assert ex_info.value.lock_type == lock_data.lock_type assert ex_info.value.capability == ICaseString(proc_desc.capability) ex_info = str(ex_info.value) for part in [ lock_data.lock_type, proc_desc.capability, proc_desc.in_unit]: assert part in ex_info
def test_mem_ACL_is_correctly_matched_against_instructions(self): """Test comparing memory ACL against instructions. `self` is this test case. """ res_util = (BagValDict( {ICaseString("full system"): [InstrState(instr)]}) for instr in [0, 1]) assert simulate( [ HwInstruction([], out_reg, ICaseString("ALU")) for out_reg in ["R1", "R2"] ], HwSpec( processor_utils.load_proc_desc({ "units": [{ units.UNIT_NAME_KEY: "full system", units.UNIT_WIDTH_KEY: 2, units.UNIT_CAPS_KEY: ["ALU"], **{ attr: True for attr in [ units.UNIT_RLOCK_KEY, units.UNIT_WLOCK_KEY ] }, units.UNIT_MEM_KEY: ["ALU"] }], "dataPath": [] }))) == list(res_util)
def test_isa_with_unsupported_capabilitiy_raises_UndefElemError(self): """Test loading an instruction set with an unknown capability. `self` is this test case. """ ex_chk = raises(errors.UndefElemError, read_isa_file, "singleInstructionISA.yaml", [ICaseString("MEM")]) chk_error([ValInStrCheck(ex_chk.value.element, ICaseString("ALU"))], ex_chk.value)
def _chk_one_unit(proc_dir, proc_file): """Verify a single unit processor. `proc_dir` is the directory containing the processor description file. `proc_file` is the processor description file. """ assert read_proc_file(proc_dir, proc_file) == ProcessorDesc([], [], [ UnitModel(ICaseString("full system"), 1, [ICaseString("ALU")], LockInfo(True, True), []) ], [])
def test_program(self, prog_file, inputs): """Test loading a program. `self` is this test case. `prog_file` is the program file. `inputs` are the instruction inputs. """ assert test_utils.compile_prog(prog_file, { "ADD": ICaseString("ALU")}) == [program_defs.HwInstruction(map( ICaseString, inputs), ICaseString("R14"), ICaseString("ALU"))]
def test_two_instructions_with_same_name_raise_DupElemError(self): """Test loading two instructions with the same name. `self` is this test case. """ ex_chk = raises( processor_utils.exception.DupElemError, read_isa_file, "twoInstructionsWithSameNameAndCase.yaml", [ICaseString("ALU")]) chk_error([ValInStrCheck(ex_chk.value.new_element, ICaseString("add")), ValInStrCheck(ex_chk.value.old_element, ICaseString("ADD"))], ex_chk.value)
def test_RLock_in_unit_before_WLock(self): """Test detecting RAW hazards with read locks in earlier units. `self` is this test case. """ in_unit, mid, out_unit = (UnitModel(ICaseString(name), 1, ["ALU"], LockInfo(rd_lock, wr_lock), []) for name, rd_lock, wr_lock in [( "input", False, False), ("middle", True, False), ("output", False, True)]) proc_desc = ProcessorDesc([in_unit], [FuncUnit(out_unit, [mid])], [], [FuncUnit(mid, [in_unit])]) self.assertEqual( simulate([ HwInstruction(*instr_regs, "ALU") for instr_regs in [[[], "R1"], [["R1"], "R2"]] ], HwSpec(proc_desc)), [ BagValDict(cp_util) for cp_util in [{ ICaseString("input"): [InstrState(0)] }, { ICaseString("input"): [InstrState(1)], ICaseString("middle"): [InstrState(0)] }, { ICaseString("middle"): [InstrState(1, StallState.DATA)], ICaseString("output"): [InstrState(0)] }, { ICaseString("middle"): [InstrState(1)] }, { ICaseString("output"): [InstrState(1)] }] ])
def test_mem_util_in_earlier_inputs_affects_later_ones(self): """Test propagation of memory utilization among inputs. `self` is this test case. """ full_sys_unit = UnitModel(ICaseString("full system"), 2, ["ALU"], LockInfo(True, True), ["ALU"]) res_util = (BagValDict( {ICaseString("full system"): [InstrState(instr)]}) for instr in [0, 1]) assert simulate( [HwInstruction([], out_reg, "ALU") for out_reg in ["R1", "R2"]], HwSpec(ProcessorDesc([], [], [full_sys_unit], []))) == list(res_util)
class TestIsa: """Test case for loading instruction sets""" # pylint: disable=invalid-name def test_isa_with_unsupported_capabilitiy_raises_UndefElemError(self): """Test loading an instruction set with an unknown capability. `self` is this test case. """ ex_chk = raises(errors.UndefElemError, read_isa_file, "singleInstructionISA.yaml", [ICaseString("MEM")]) chk_error([ValInStrCheck(ex_chk.value.element, ICaseString("ALU"))], ex_chk.value) # pylint: enable=invalid-name @pytest.mark.parametrize("in_file, supported_caps, exp_isa", [ ("emptyISA.yaml", ["ALU"], {}), ("singleInstructionISA.yaml", ["ALU"], {"ADD": ICaseString("ALU")}), ("singleInstructionISA.yaml", ["alu"], {"ADD": ICaseString("alu")}), ("dualInstructionISA.yaml", ["ALU"], {"ADD": ICaseString("ALU"), "SUB": ICaseString("ALU")})]) def test_load_isa(self, in_file, supported_caps, exp_isa): """Test loading an instruction set. `self` is this test case. `in_file` is the instruction set file. `supported_caps` are the supported hardware capabilities. `exp_isa` is the expected instruction set. """ assert read_isa_file( in_file, map(ICaseString, supported_caps)) == exp_isa # pylint: disable=invalid-name def test_two_instructions_with_same_name_raise_DupElemError(self): """Test loading two instructions with the same name. `self` is this test case. """ ex_chk = raises( processor_utils.exception.DupElemError, read_isa_file, "twoInstructionsWithSameNameAndCase.yaml", [ICaseString("ALU")]) chk_error([ValInStrCheck(ex_chk.value.new_element, ICaseString("add")), ValInStrCheck(ex_chk.value.old_element, ICaseString("ADD"))], ex_chk.value)
def test_hazard(self): """Test detecting RAR hazards. `self` is this test case. """ proc_desc = ProcessorDesc([], [], [ UnitModel(ICaseString(TEST_DIR), 2, ["ALU"], LockInfo(True, True), []) ], []) self.assertEqual( simulate([ HwInstruction(["R1"], out_reg, "ALU") for out_reg in ["R2", "R3"] ], HwSpec(proc_desc)), [BagValDict({ICaseString(TEST_DIR): map(InstrState, [0, 1])})])
def _get_reg_name(op_idx: object, op_name: str, line_num: object, instr: object, reg_registry: IndexedSet[_OperandInfo]) -> ICaseString: """Extract the registry name. `op_idx` is the one-based operand index. `op_name` is the operand name. `line_num` is the line number of the enclosing instruction. `instr` is the enclosing instruction. `reg_registry` is the register name registry. The function returns the register name. It raises a CodeError if the operand is invalid. """ if not op_name: raise CodeError( f"Operand {op_idx} empty for instruction ${CodeError.INSTR_KEY} at" f" line ${CodeError.LINE_NUM_KEY}", line_num, instr) std_reg = container_utils.get_from_set( reg_registry, _OperandInfo(ICaseString(op_name), line_num)) if std_reg.name.raw_str != op_name: logging.warning( "Register %s on line %d previously referred to as %s " "on line %d, using original reference...", op_name, line_num, std_reg.name, std_reg.line) return std_reg.name
def test_hw_load_calls_into_processor_and_isa_load_functions( self, capability, instr, hw_file): """Test loading a full hardware description file. `self` is this test case. `capability` is the hardware sole capability. `instr` is the sole supported instruction. `hw_file` is the hardware description file. The method tests appropriate calls are made to load the processor and ISA descriptions. """ full_sys_unit = ICaseString("full system") icase_cap = ICaseString(capability) lock_info = units.LockInfo(True, True) with open(os.path.join( test_utils.TEST_DATA_DIR, "fullHwDesc", hw_file)) as hw_src, patch( "processor_utils.load_proc_desc", return_value=processor_utils.ProcessorDesc([], [], [ units.UnitModel(full_sys_unit, 1, [icase_cap], lock_info, []) ], [])) as proc_mock, patch( "processor_utils.get_abilities", return_value=frozenset( [icase_cap])) as ability_mock, patch( "processor_utils.load_isa", return_value={instr: icase_cap}) as isa_mock: assert hw_loading.read_processor(hw_src) == hw_loading.HwDesc( proc_mock.return_value, isa_mock.return_value) isa_mock.assert_called() assert tuple(isa_mock.call_args.args[0]) == ((instr, capability), ) assert isa_mock.call_args.args[1] == ability_mock.return_value for mock_chk in [[ proc_mock, { "units": [{ units.UNIT_NAME_KEY: "full system", units.UNIT_WIDTH_KEY: 1, units.UNIT_CAPS_KEY: [capability], units.UNIT_RLOCK_KEY: True, units.UNIT_WLOCK_KEY: True }], "dataPath": [] } ], [ability_mock, proc_mock.return_value]]: unittest.mock.MagicMock.assert_called_with(*mock_chk)
def test_same_capability_with_different_cases_in_two_units_is_detected( self, caplog): """Test loading a capability with different cases in two units. `self` is this test case. `caplog` is the log capture fixture. """ caplog.set_level(WARNING) in_file = "twoCapabilitiesWithSameNameAndDifferentCaseInTwoUnits.yaml" processor = (UnitModel(ICaseString(unit_name), 1, [ICaseString("ALU")], LockInfo(True, True), []) for unit_name in ["core 1", "core 2"]) assert read_proc_file("capabilities", in_file) == ProcessorDesc([], [], processor, []) chk_warn(["ALU", "core 1", "alu", "core 2"], caplog.records) assert ICaseString.__name__ not in caplog.records[0].getMessage()
def chk_two_units(proc_dir, proc_file): """Verify a two-unit processor. `proc_dir` is the directory containing the processor description file. `proc_file` is the processor description file. The function asserts the order and descriptions of units and links among them. """ proc_desc = read_proc_file(proc_dir, proc_file) alu_cap = ICaseString("ALU") out_unit = ICaseString("output") assert proc_desc == processor_utils.ProcessorDesc( [UnitModel( ICaseString("input"), 1, [alu_cap], LockInfo(True, False), [])], [processor_utils.units.FuncUnit(UnitModel(out_unit, 1, [ alu_cap], LockInfo(False, True), []), proc_desc.in_ports)], [], [])
def test_instructions_are_loaded_to_lexicographically_inputs_first(self): """Test instructions are fed into sorted input units. `self` is this test case. """ in_unit, out_unit = (UnitModel(ICaseString(name), 1, ["ALU"], LockInfo( rd_lock, wr_lock), mem_acl) for name, rd_lock, wr_lock, mem_acl in [("input 1", True, False, []), ("output 1", False, True, ["ALU"])]) proc_desc = ProcessorDesc( [in_unit], [FuncUnit(out_unit, [in_unit])], [UnitModel(ICaseString( "input 2"), 1, ["ALU"], LockInfo(True, False), [])], []) self.assertEqual(simulate( [HwInstruction([], "R1", "ALU")], HwSpec(proc_desc)), [BagValDict( cp_util) for cp_util in [{ICaseString("input 1"): [InstrState( 0)]}, {ICaseString("output 1"): [InstrState(0)]}]])
def test_two_units_with_same_name_raise_DupElemError( self, in_file, dup_unit): """Test loading two units with the same name. `self` is this test case. `in_file` is the processor description file. `dup_unit` is the duplicate unit. """ ex_chk = raises(exception.DupElemError, read_proc_file, "units", in_file) chk_error([ ValInStrCheck(*chk_params) for chk_params in [(ex_chk.value.new_element, ICaseString(dup_unit)), (ex_chk.value.old_element, ICaseString("full system"))] ], ex_chk.value)
def test_hazard(self, instr_regs): """Test detecting data hazards. `self` is this test case. `instr_regs` are the registers accessed by each instruction. """ full_sys_unit = UnitModel(ICaseString(TEST_DIR), 2, ["ALU"], LockInfo(True, True), []) assert simulate( [HwInstruction(*regs, "ALU") for regs in instr_regs], HwSpec(ProcessorDesc([], [], [full_sys_unit], []))) == [ BagValDict(cp_util) for cp_util in [{ ICaseString(TEST_DIR): itertools.starmap(InstrState, [[0], [1, StallState.DATA]]) }, { ICaseString(TEST_DIR): [InstrState(1)] }] ]
def test_edge_with_unknown_unit_raises_UndefElemError(self): """Test loading an edge involving an unknown unit. `self` is this test case. """ ex_chk = raises(errors.UndefElemError, read_proc_file, "edges", "edgeWithUnknownUnit.yaml") chk_error([ValInStrCheck(ex_chk.value.element, ICaseString("input"))], ex_chk.value)
def test_processor_with_explicit_attributes(self): """Test loading a processor with explicitly defined attributes. `self` is this test case. """ assert load_proc_desc({ "units": [{ UNIT_NAME_KEY: "full system", UNIT_WIDTH_KEY: 1, UNIT_CAPS_KEY: ["ALU"], **{attr: True for attr in [UNIT_RLOCK_KEY, UNIT_WLOCK_KEY]}, UNIT_MEM_KEY: ["ALU"] }], "dataPath": [] }) == ProcessorDesc([], [], [ UnitModel(ICaseString("full system"), 1, [ICaseString("ALU")], LockInfo(True, True), [ICaseString("ALU")]) ], [])
def test_same_operand_with_different_case_in_same_instruction_is_detected( self, caplog, dup_reg): """Test loading operands in different cases(same instruction). `self` is this test case. `caplog` is the log capture fixture. `dup_reg` is the duplicate register. """ lower_reg = dup_reg.lower() upper_reg = dup_reg.upper() caplog.set_level(WARNING) assert read_program([f"ADD R1, {upper_reg}, {lower_reg}"]) == [ ProgInstruction( [ICaseString(dup_reg)], ICaseString("R1"), "ADD", 1)] assert caplog.records warn_msg = caplog.records[0].getMessage() for reg in [lower_reg, upper_reg]: assert reg in warn_msg
def test_sim(self, prog, cpu, util_tbl): """Test executing a program. `self` is this test case. `prog` is the program to run. `cpu` is the processor to run the program on. `util_tbl` is the expected utilization table. """ assert simulate([HwInstruction(*regs, ICaseString(categ)) for *regs, categ in prog], HwSpec(cpu)) == [ BagValDict(inst_util) for inst_util in util_tbl]
def test_partial_mem_access(self): """Test loading a processor with partial memory access. `self` is this test case. """ assert load_proc_desc({ "units": [{ UNIT_NAME_KEY: "full system", UNIT_WIDTH_KEY: 1, UNIT_CAPS_KEY: ["ALU", "MEM"], **{attr: True for attr in [UNIT_RLOCK_KEY, UNIT_WLOCK_KEY]}, UNIT_MEM_KEY: ["MEM"] }], "dataPath": [] }) == ProcessorDesc([], [], [ UnitModel(ICaseString("full system"), 1, map(ICaseString, ["ALU", "MEM"]), LockInfo(True, True), [ICaseString("MEM")]) ], [])
def test_processor_with_incapable_ports_raises_EmptyProcError( self, in_file): """Test a processor with no capable ports. `self` is this test case. `in_file` is the processor description file. """ assert "input" in ICaseString( str( raises(exception.EmptyProcError, read_proc_file, "capabilities", in_file).value))
def test_only_mem_access_instructions_are_checked(self): """Test always allowing instructions without memory access. `self` is this test case. """ in_unit, out_unit = (UnitModel(ICaseString(name), 2, ["ALU", "MEM"], LockInfo(rd_lock, wr_lock), mem_acl) for name, rd_lock, wr_lock, mem_acl in [( "input", True, False, []), ("output", False, True, ["MEM"])]) proc_desc = ProcessorDesc([in_unit], [FuncUnit(out_unit, [in_unit])], [], []) self.assertEqual( simulate([ HwInstruction([], *instr_params) for instr_params in [["R1", "MEM"], ["R2", "ALU"]] ], HwSpec(proc_desc)), [ BagValDict({ICaseString(unit): map(InstrState, [0, 1])}) for unit in ["input", "output"] ])