Coverage for MC6809/components/mc6809_stack.py: 74%

75 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 6809 is Big-Endian 

8 

9 Links: 

10 http://dragondata.worldofdragon.org/Publications/inside-dragon.htm 

11 http://www.burgins.com/m6809.html 

12 http://koti.mbnet.fi/~atjs/mc6809/ 

13 

14 :copyleft: 2013-2015 by the MC6809 team, see AUTHORS for more details. 

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

16 

17 Based on: 

18 * ApplyPy by James Tauber (MIT license) 

19 * XRoar emulator by Ciaran Anscomb (GPL license) 

20 more info, see README 

21""" 

22 

23 

24from MC6809.components.cpu_utils.instruction_caller import opcode 

25from MC6809.components.MC6809data.MC6809_op_data import REG_A, REG_B, REG_CC, REG_DP, REG_PC, REG_U, REG_X, REG_Y 

26 

27 

28class StackMixin: 

29 

30 def push_byte(self, stack_pointer, byte): 

31 """ pushed a byte onto stack """ 

32 # FIXME: self.system_stack_pointer -= 1 

33 stack_pointer.decrement(1) 

34 addr = stack_pointer.value 

35 

36# log.info( 

37# log.error( 

38# "%x|\tpush $%x to %s stack at $%x\t|%s", 

39# self.last_op_address, byte, stack_pointer.name, addr, 

40# self.cfg.mem_info.get_shortest(self.last_op_address) 

41# ) 

42 self.memory.write_byte(addr, byte) 

43 

44 def pull_byte(self, stack_pointer): 

45 """ pulled a byte from stack """ 

46 addr = stack_pointer.value 

47 byte = self.memory.read_byte(addr) 

48# log.info( 

49# log.error( 

50# "%x|\tpull $%x from %s stack at $%x\t|%s", 

51# self.last_op_address, byte, stack_pointer.name, addr, 

52# self.cfg.mem_info.get_shortest(self.last_op_address) 

53# ) 

54 

55 # FIXME: self.system_stack_pointer += 1 

56 stack_pointer.increment(1) 

57 

58 return byte 

59 

60 def push_word(self, stack_pointer, word): 

61 # FIXME: self.system_stack_pointer -= 2 

62 stack_pointer.decrement(2) 

63 

64 addr = stack_pointer.value 

65# log.info( 

66# log.error( 

67# "%x|\tpush word $%x to %s stack at $%x\t|%s", 

68# self.last_op_address, word, stack_pointer.name, addr, 

69# self.cfg.mem_info.get_shortest(self.last_op_address) 

70# ) 

71 

72 self.memory.write_word(addr, word) 

73 

74# hi, lo = divmod(word, 0x100) 

75# self.push_byte(hi) 

76# self.push_byte(lo) 

77 

78 def pull_word(self, stack_pointer): 

79 addr = stack_pointer.value 

80 word = self.memory.read_word(addr) 

81# log.info( 

82# log.error( 

83# "%x|\tpull word $%x from %s stack at $%x\t|%s", 

84# self.last_op_address, word, stack_pointer.name, addr, 

85# self.cfg.mem_info.get_shortest(self.last_op_address) 

86# ) 

87 # FIXME: self.system_stack_pointer += 2 

88 stack_pointer.increment(2) 

89 return word 

90 

91 #### 

92 

93 @opcode( # Push A, B, CC, DP, D, X, Y, U, or PC onto stack 

94 0x36, # PSHU (immediate) 

95 0x34, # PSHS (immediate) 

96 ) 

97 def instruction_PSH(self, opcode, m, register): 

98 """ 

99 All, some, or none of the processor registers are pushed onto stack 

100 (with the exception of stack pointer itself). 

101 

102 A single register may be placed on the stack with the condition codes 

103 set by doing an autodecrement store onto the stack (example: STX ,--S). 

104 

105 source code forms: b7 b6 b5 b4 b3 b2 b1 b0 PC U Y X DP B A CC push order 

106 -> 

107 

108 CC bits "HNZVC": ----- 

109 """ 

110 assert register in (self.system_stack_pointer, self.user_stack_pointer) 

111 

112 def push(register_str, stack_pointer): 

113 register_obj = self.register_str2object[register_str] 

114 data = register_obj.value 

115 

116# log.debug("\tpush %s with data $%x", register_obj.name, data) 

117 

118 if register_obj.WIDTH == 8: 

119 self.push_byte(register, data) 

120 else: 

121 assert register_obj.WIDTH == 16 

122 self.push_word(register, data) 

123 

124# log.debug("$%x PSH%s post byte: $%x", self.program_counter, register.name, m) 

125 

126 # m = postbyte 

127 if m & 0x80: 127 ↛ 128line 127 didn't jump to line 128, because the condition on line 127 was never true

128 push(REG_PC, register) # 16 bit program counter register 

129 if m & 0x40: 129 ↛ 130line 129 didn't jump to line 130, because the condition on line 129 was never true

130 push(REG_U, register) # 16 bit user-stack pointer 

131 if m & 0x20: 131 ↛ 132line 131 didn't jump to line 132, because the condition on line 131 was never true

132 push(REG_Y, register) # 16 bit index register 

133 if m & 0x10: 

134 push(REG_X, register) # 16 bit index register 

135 if m & 0x08: 135 ↛ 136line 135 didn't jump to line 136, because the condition on line 135 was never true

136 push(REG_DP, register) # 8 bit direct page register 

137 if m & 0x04: 

138 push(REG_B, register) # 8 bit accumulator 

139 if m & 0x02: 

140 push(REG_A, register) # 8 bit accumulator 

141 if m & 0x01: 141 ↛ 142line 141 didn't jump to line 142, because the condition on line 141 was never true

142 push(REG_CC, register) # 8 bit condition code register 

143 

144 @opcode( # Pull A, B, CC, DP, D, X, Y, U, or PC from stack 

145 0x37, # PULU (immediate) 

146 0x35, # PULS (immediate) 

147 ) 

148 def instruction_PUL(self, opcode, m, register): 

149 """ 

150 All, some, or none of the processor registers are pulled from stack 

151 (with the exception of stack pointer itself). 

152 

153 A single register may be pulled from the stack with condition codes set 

154 by doing an autoincrement load from the stack (example: LDX ,S++). 

155 

156 source code forms: b7 b6 b5 b4 b3 b2 b1 b0 PC U Y X DP B A CC = pull 

157 order 

158 

159 CC bits "HNZVC": ccccc 

160 """ 

161 assert register in (self.system_stack_pointer, self.user_stack_pointer) 

162 

163 def pull(register_str, stack_pointer): 

164 reg_obj = self.register_str2object[register_str] 

165 

166 reg_width = reg_obj.WIDTH # 8 / 16 

167 if reg_width == 8: 167 ↛ 170line 167 didn't jump to line 170, because the condition on line 167 was never false

168 data = self.pull_byte(stack_pointer) 

169 else: 

170 assert reg_width == 16 

171 data = self.pull_word(stack_pointer) 

172 

173 reg_obj.set(data) 

174 

175# log.debug("$%x PUL%s:", self.program_counter, register.name) 

176 

177 # m = postbyte 

178 if m & 0x01: 178 ↛ 179line 178 didn't jump to line 179, because the condition on line 178 was never true

179 pull(REG_CC, register) # 8 bit condition code register 

180 if m & 0x02: 

181 pull(REG_A, register) # 8 bit accumulator 

182 if m & 0x04: 

183 pull(REG_B, register) # 8 bit accumulator 

184 if m & 0x08: 184 ↛ 185line 184 didn't jump to line 185, because the condition on line 184 was never true

185 pull(REG_DP, register) # 8 bit direct page register 

186 if m & 0x10: 186 ↛ 187line 186 didn't jump to line 187, because the condition on line 186 was never true

187 pull(REG_X, register) # 16 bit index register 

188 if m & 0x20: 188 ↛ 189line 188 didn't jump to line 189, because the condition on line 188 was never true

189 pull(REG_Y, register) # 16 bit index register 

190 if m & 0x40: 190 ↛ 191line 190 didn't jump to line 191, because the condition on line 190 was never true

191 pull(REG_U, register) # 16 bit user-stack pointer 

192 if m & 0x80: 192 ↛ 193line 192 didn't jump to line 193, because the condition on line 192 was never true

193 pull(REG_PC, register) # 16 bit program counter register