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
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-06 19:50 +0100
1#!/usr/bin/env python
3"""
4 MC6809 - 6809 CPU emulator in Python
5 =======================================
7 6809 is Big-Endian
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/
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.
17 Based on:
18 * ApplyPy by James Tauber (MIT license)
19 * XRoar emulator by Ciaran Anscomb (GPL license)
20 more info, see README
21"""
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
29class AddressingMixin:
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
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
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
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
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
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
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 }
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# )
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})")
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# )
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
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}")
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# )
185 ea = ea & 0xffff
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)
192# log.debug("\tget_ea_indexed(): return ea=$%x", ea)
193 return ea
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
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
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
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
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
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
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
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
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