Coverage for MC6809/components/mc6809_addressing.py: 90%

131 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.MC6809data.MC6809_op_data import REG_S, REG_U, REG_X, REG_Y 

25from MC6809.utils.bits import is_bit_set 

26from MC6809.utils.byte_word_values import signed5, signed8, signed16 

27 

28 

29class AddressingMixin: 

30 

31 def get_m_immediate(self): 

32 ea, m = self.read_pc_byte() 

33# log.debug("\tget_m_immediate(): $%x from $%x", m, ea) 

34 return m 

35 

36 def get_m_immediate_word(self): 

37 ea, m = self.read_pc_word() 

38# log.debug("\tget_m_immediate_word(): $%x from $%x", m, ea) 

39 return m 

40 

41 def get_ea_direct(self): 

42 op_addr, m = self.read_pc_byte() 

43 dp = self.direct_page.value 

44 ea = dp << 8 | m 

45# log.debug("\tget_ea_direct(): ea = dp << 8 | m => $%x=$%x<<8|$%x", ea, dp, m) 

46 return ea 

47 

48 def get_ea_m_direct(self): 

49 ea = self.get_ea_direct() 

50 m = self.memory.read_byte(ea) 

51# log.debug("\tget_ea_m_direct(): ea=$%x m=$%x", ea, m) 

52 return ea, m 

53 

54 def get_m_direct(self): 

55 ea = self.get_ea_direct() 

56 m = self.memory.read_byte(ea) 

57# log.debug("\tget_m_direct(): $%x from $%x", m, ea) 

58 return m 

59 

60 def get_m_direct_word(self): 

61 ea = self.get_ea_direct() 

62 m = self.memory.read_word(ea) 

63# log.debug("\tget_m_direct(): $%x from $%x", m, ea) 

64 return m 

65 

66 INDEX_POSTBYTE2STR = { 

67 0x00: REG_X, # 16 bit index register 

68 0x01: REG_Y, # 16 bit index register 

69 0x02: REG_U, # 16 bit user-stack pointer 

70 0x03: REG_S, # 16 bit system-stack pointer 

71 } 

72 

73 def get_ea_indexed(self): 

74 """ 

75 Calculate the address for all indexed addressing modes 

76 """ 

77 addr, postbyte = self.read_pc_byte() 

78# log.debug("\tget_ea_indexed(): postbyte: $%02x (%s) from $%04x", 

79# postbyte, byte2bit_string(postbyte), addr 

80# ) 

81 

82 rr = (postbyte >> 5) & 3 

83 try: 

84 register_str = self.INDEX_POSTBYTE2STR[rr] 

85 except KeyError: 

86 raise RuntimeError(f"Register ${rr:x} doesn't exists! (postbyte: ${postbyte:x})") 

87 

88 register_obj = self.register_str2object[register_str] 

89 register_value = register_obj.value 

90# log.debug("\t%02x == register %s: value $%x", 

91# rr, register_obj.name, register_value 

92# ) 

93 

94 if not is_bit_set(postbyte, bit=7): # bit 7 == 0 

95 # EA = n, R - use 5-bit offset from post-byte 

96 offset = signed5(postbyte & 0x1f) 

97 ea = register_value + offset 

98# log.debug( 

99# "\tget_ea_indexed(): bit 7 == 0: reg.value: $%04x -> ea=$%04x + $%02x = $%04x", 

100# register_value, register_value, offset, ea 

101# ) 

102 return ea 

103 

104 addr_mode = postbyte & 0x0f 

105 self.cycles += 1 

106 offset = None 

107 # TODO: Optimized this, maybe use a dict mapping... 

108 if addr_mode == 0x0: 

109 # log.debug("\t0000 0x0 | ,R+ | increment by 1") 

110 ea = register_value 

111 register_obj.increment(1) 

112 elif addr_mode == 0x1: 

113 # log.debug("\t0001 0x1 | ,R++ | increment by 2") 

114 ea = register_value 

115 register_obj.increment(2) 

116 self.cycles += 1 

117 elif addr_mode == 0x2: 

118 # log.debug("\t0010 0x2 | ,R- | decrement by 1") 

119 register_obj.decrement(1) 

120 ea = register_obj.value 

121 elif addr_mode == 0x3: 

122 # log.debug("\t0011 0x3 | ,R-- | decrement by 2") 

123 register_obj.decrement(2) 

124 ea = register_obj.value 

125 self.cycles += 1 

126 elif addr_mode == 0x4: 

127 # log.debug("\t0100 0x4 | ,R | No offset") 

128 ea = register_value 

129 elif addr_mode == 0x5: 

130 # log.debug("\t0101 0x5 | B, R | B register offset") 

131 offset = signed8(self.accu_b.value) 

132 elif addr_mode == 0x6: 

133 # log.debug("\t0110 0x6 | A, R | A register offset") 

134 offset = signed8(self.accu_a.value) 

135 elif addr_mode == 0x8: 

136 # log.debug("\t1000 0x8 | n, R | 8 bit offset") 

137 offset = signed8(self.read_pc_byte()[1]) 

138 elif addr_mode == 0x9: 

139 # log.debug("\t1001 0x9 | n, R | 16 bit offset") 

140 offset = signed16(self.read_pc_word()[1]) 

141 self.cycles += 1 

142 elif addr_mode == 0xa: 142 ↛ 144line 142 didn't jump to line 144, because the condition on line 142 was never true

143 # log.debug("\t1010 0xa | illegal, set ea=0") 

144 ea = 0 

145 elif addr_mode == 0xb: 

146 # log.debug("\t1011 0xb | D, R | D register offset") 

147 # D - 16 bit concatenated reg. (A + B) 

148 offset = signed16(self.accu_d.value) # FIXME: signed16() ok? 

149 self.cycles += 1 

150 elif addr_mode == 0xc: 

151 # log.debug("\t1100 0xc | n, PCR | 8 bit offset from program counter") 

152 __, value = self.read_pc_byte() 

153 value_signed = signed8(value) 

154 ea = self.program_counter.value + value_signed 

155# log.debug("\tea = pc($%x) + $%x = $%x (dez.: %i + %i = %i)", 

156# self.program_counter, value_signed, ea, 

157# self.program_counter, value_signed, ea, 

158# ) 

159 elif addr_mode == 0xd: 159 ↛ 169line 159 didn't jump to line 169, because the condition on line 159 was never false

160 # log.debug("\t1101 0xd | n, PCR | 16 bit offset from program counter") 

161 __, value = self.read_pc_word() 

162 value_signed = signed16(value) 

163 ea = self.program_counter.value + value_signed 

164 self.cycles += 1 

165# log.debug("\tea = pc($%x) + $%x = $%x (dez.: %i + %i = %i)", 

166# self.program_counter, value_signed, ea, 

167# self.program_counter, value_signed, ea, 

168# ) 

169 elif addr_mode == 0xe: 

170 # log.error("\tget_ea_indexed(): illegal address mode, use 0xffff") 

171 ea = 0xffff # illegal 

172 elif addr_mode == 0xf: 

173 # log.debug("\t1111 0xf | [n] | 16 bit address - extended indirect") 

174 __, ea = self.read_pc_word() 

175 else: 

176 raise RuntimeError(f"Illegal indexed addressing mode: ${addr_mode:x}") 

177 

178 if offset is not None: 

179 ea = register_value + offset 

180# log.debug("\t$%x + $%x = $%x (dez: %i + %i = %i)", 

181# register_value, offset, ea, 

182# register_value, offset, ea 

183# ) 

184 

185 ea = ea & 0xffff 

186 

187 if is_bit_set(postbyte, bit=4): # bit 4 is 1 -> Indirect 

188 # log.debug("\tIndirect addressing: get new ea from $%x", ea) 

189 ea = self.memory.read_word(ea) 

190# log.debug("\tIndirect addressing: new ea is $%x", ea) 

191 

192# log.debug("\tget_ea_indexed(): return ea=$%x", ea) 

193 return ea 

194 

195 def get_m_indexed(self): 

196 ea = self.get_ea_indexed() 

197 m = self.memory.read_byte(ea) 

198# log.debug("\tget_m_indexed(): $%x from $%x", m, ea) 

199 return m 

200 

201 def get_ea_m_indexed(self): 

202 ea = self.get_ea_indexed() 

203 m = self.memory.read_byte(ea) 

204# log.debug("\tget_ea_m_indexed(): ea = $%x m = $%x", ea, m) 

205 return ea, m 

206 

207 def get_m_indexed_word(self): 

208 ea = self.get_ea_indexed() 

209 m = self.memory.read_word(ea) 

210# log.debug("\tget_m_indexed_word(): $%x from $%x", m, ea) 

211 return m 

212 

213 def get_ea_extended(self): 

214 """ 

215 extended indirect addressing mode takes a 2-byte value from post-bytes 

216 """ 

217 attr, ea = self.read_pc_word() 

218# log.debug("\tget_ea_extended() ea=$%x from $%x", ea, attr) 

219 return ea 

220 

221 def get_m_extended(self): 

222 ea = self.get_ea_extended() 

223 m = self.memory.read_byte(ea) 

224# log.debug("\tget_m_extended(): $%x from $%x", m, ea) 

225 return m 

226 

227 def get_ea_m_extended(self): 

228 ea = self.get_ea_extended() 

229 m = self.memory.read_byte(ea) 

230# log.debug("\tget_m_extended(): ea = $%x m = $%x", ea, m) 

231 return ea, m 

232 

233 def get_m_extended_word(self): 

234 ea = self.get_ea_extended() 

235 m = self.memory.read_word(ea) 

236# log.debug("\tget_m_extended_word(): $%x from $%x", m, ea) 

237 return m 

238 

239 def get_ea_relative(self): 

240 addr, x = self.read_pc_byte() 

241 x = signed8(x) 

242 ea = self.program_counter.value + x 

243# log.debug("\tget_ea_relative(): ea = $%x + %i = $%x \t| %s", 

244# self.program_counter, x, ea, 

245# self.cfg.mem_info.get_shortest(ea) 

246# ) 

247 return ea 

248 

249 def get_ea_relative_word(self): 

250 addr, x = self.read_pc_word() 

251 ea = self.program_counter.value + x 

252# log.debug("\tget_ea_relative_word(): ea = $%x + %i = $%x \t| %s", 

253# self.program_counter, x, ea, 

254# self.cfg.mem_info.get_shortest(ea) 

255# ) 

256 return ea