Coverage for MC6809/components/cpu_utils/instruction_caller.py: 92%

44 statements  

« prev     ^ index     » next       coverage.py v7.2.1, created at 2023-03-06 19:50 +0100

1#!/usr/bin/env python 

2 

3""" 

4 MC6809 - 6809 CPU emulator in Python 

5 ======================================= 

6 

7 :copyleft: 2013-2014 by the MC6809 team, see AUTHORS for more details. 

8 :license: GNU GPL v3 or above, see LICENSE for more details. 

9""" 

10 

11 

12import inspect 

13 

14from MC6809.components.cpu6809_trace import InstructionTrace 

15from MC6809.components.cpu_utils.instruction_call import PrepagedInstructions 

16from MC6809.components.cpu_utils.Instruction_generator import func_name_from_op_code 

17from MC6809.components.MC6809data.MC6809_data_utils import MC6809OP_DATA_DICT 

18 

19 

20def opcode(*opcodes): 

21 """A decorator for opcodes""" 

22 def decorator(func): 

23 setattr(func, "_is_opcode", True) 

24 setattr(func, "_opcodes", opcodes) 

25 return func 

26 return decorator 

27 

28 

29class OpCollection: 

30 def __init__(self, cpu): 

31 self.cpu = cpu 

32 self.opcode_dict = {} 

33 self.collect_ops() 

34 

35 def get_opcode_dict(self): 

36 return self.opcode_dict 

37 

38 def collect_ops(self): 

39 # Get the members not from class instance, so that's possible to 

40 # exclude properties without "activate" them. 

41 cls = type(self.cpu) 

42 for name, cls_method in inspect.getmembers(cls): 

43 if name.startswith("_") or isinstance(cls_method, property): 

44 continue 

45 

46 try: 

47 opcodes = getattr(cls_method, "_opcodes") 

48 except AttributeError: 

49 continue 

50 

51 instr_func = getattr(self.cpu, name) 

52 self._add_ops(opcodes, instr_func) 

53 

54 def _add_ops(self, opcodes, instr_func): 

55 # log.debug("%20s: %s" % ( 

56 # instr_func.__name__, ",".join(["$%x" % c for c in opcodes]) 

57 # )) 

58 for op_code in opcodes: 

59 assert op_code not in self.opcode_dict, \ 

60 f"Opcode ${op_code:x} ({instr_func.__name__}) defined more then one time!" 

61 

62 op_code_data = MC6809OP_DATA_DICT[op_code] 

63 

64 func_name = func_name_from_op_code(op_code) 

65 

66 if self.cpu.cfg.trace: 66 ↛ 67line 66 didn't jump to line 67, because the condition on line 66 was never true

67 InstructionClass = InstructionTrace 

68 else: 

69 InstructionClass = PrepagedInstructions 

70 

71 instrution_class = InstructionClass(self.cpu, instr_func) 

72 try: 

73 func = getattr(instrution_class, func_name) 

74 except AttributeError as err: 

75 raise AttributeError(f"{err} (op code: ${op_code:02x})") 

76 

77 self.opcode_dict[op_code] = (op_code_data["cycles"], func) 

78 

79 

80if __name__ == "__main__": 

81 from dragonpy.Dragon32.config import Dragon32Cfg 

82 

83 from MC6809.components.cpu6809 import CPU 

84 from MC6809.components.memory import Memory 

85 from MC6809.tests.test_base import BaseCPUTestCase 

86 

87 cmd_args = BaseCPUTestCase.UNITTEST_CFG_DICT 

88 cfg = Dragon32Cfg(cmd_args) 

89 memory = Memory(cfg) 

90 cpu = CPU(memory, cfg) 

91 

92 for op_code, data in sorted(cpu.opcode_dict.items()): 

93 cycles, func = data 

94 if op_code > 0xff: 

95 op_code = f"${op_code:04x}" 

96 else: 

97 op_code = f" ${op_code:02x}" 

98 

99 print(f"Op {op_code} - cycles: {cycles:2d} - func: {func.__name__}") 

100 

101 print(" --- END --- ")