Coverage for MC6809/components/mc6809_ops_logic.py: 96%
110 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.cpu_utils.instruction_caller import opcode
25from MC6809.utils.bits import get_bit
28class OpsLogicalMixin:
29 # ---- Logical Operations ----
31 @opcode( # AND memory with accumulator
32 0x84, 0x94, 0xa4, 0xb4, # ANDA (immediate, direct, indexed, extended)
33 0xc4, 0xd4, 0xe4, 0xf4, # ANDB (immediate, direct, indexed, extended)
34 )
35 def instruction_AND(self, opcode, m, register):
36 """
37 Performs the logical AND operation between the contents of an
38 accumulator and the contents of memory location M and the result is
39 stored in the accumulator.
41 source code forms: ANDA P; ANDB P
43 CC bits "HNZVC": -aa0-
44 """
45 a = register.value
46 r = a & m
47 register.set(r)
48 self.clear_NZV()
49 self.update_NZ_8(r)
50# log.debug("\tAND %s: %i & %i = %i",
51# register.name, a, m, r
52# )
54 @opcode( # Exclusive OR memory with accumulator
55 0x88, 0x98, 0xa8, 0xb8, # EORA (immediate, direct, indexed, extended)
56 0xc8, 0xd8, 0xe8, 0xf8, # EORB (immediate, direct, indexed, extended)
57 )
58 def instruction_EOR(self, opcode, m, register):
59 """
60 The contents of memory location M is exclusive ORed into an 8-bit
61 register.
63 source code forms: EORA P; EORB P
65 CC bits "HNZVC": -aa0-
66 """
67 a = register.value
68 r = a ^ m
69 register.set(r)
70 self.clear_NZV()
71 self.update_NZ_8(r)
72# log.debug("\tEOR %s: %i ^ %i = %i",
73# register.name, a, m, r
74# )
76 @opcode( # OR memory with accumulator
77 0x8a, 0x9a, 0xaa, 0xba, # ORA (immediate, direct, indexed, extended)
78 0xca, 0xda, 0xea, 0xfa, # ORB (immediate, direct, indexed, extended)
79 )
80 def instruction_OR(self, opcode, m, register):
81 """
82 Performs an inclusive OR operation between the contents of accumulator A
83 or B and the contents of memory location M and the result is stored in
84 accumulator A or B.
86 source code forms: ORA P; ORB P
88 CC bits "HNZVC": -aa0-
89 """
90 a = register.value
91 r = a | m
92 register.set(r)
93 self.clear_NZV()
94 self.update_NZ_8(r)
95# log.debug("$%04x OR %s: %02x | %02x = %02x",
96# self.program_counter, register.name, a, m, r
97# )
99 # ---- CC manipulation ----
101 @opcode( # AND condition code register
102 0x1c, # ANDCC (immediate)
103 )
104 def instruction_ANDCC(self, opcode, m, register):
105 """
106 Performs a logical AND between the condition code register and the
107 immediate byte specified in the instruction and places the result in the
108 condition code register.
110 source code forms: ANDCC #xx
112 CC bits "HNZVC": ddddd
113 """
114 assert register == self.cc_register
116 old_cc = self.get_cc_value()
117 new_cc = old_cc & m
118 self.set_cc(new_cc)
119# log.debug("\tANDCC: $%x AND $%x = $%x | set CC to %s",
120# old_cc, m, new_cc, self.get_cc_info()
121# )
123 @opcode( # OR condition code register
124 0x1a, # ORCC (immediate)
125 )
126 def instruction_ORCC(self, opcode, m, register):
127 """
128 Performs an inclusive OR operation between the contents of the condition
129 code registers and the immediate value, and the result is placed in the
130 condition code register. This instruction may be used to set interrupt
131 masks (disable interrupts) or any other bit(s).
133 source code forms: ORCC #XX
135 CC bits "HNZVC": ddddd
136 """
137 assert register == self.cc_register
139 old_cc = self.get_cc_value()
140 new_cc = old_cc | m
141 self.set_cc(new_cc)
142# log.debug("\tORCC: $%x OR $%x = $%x | set CC to %s",
143# old_cc, m, new_cc, self.get_cc_info()
144# )
146 # ---- Logical shift: LSL, LSR ----
148 def LSL(self, a):
149 """
150 Shifts all bits of accumulator A or B or memory location M one place to
151 the left. Bit zero is loaded with a zero. Bit seven of accumulator A or
152 B or memory location M is shifted into the C (carry) bit.
154 This is a duplicate assembly-language mnemonic for the single machine
155 instruction ASL.
157 source code forms: LSL Q; LSLA; LSLB
159 CC bits "HNZVC": naaas
160 """
161 r = a << 1
162 self.clear_NZVC()
163 self.update_NZVC_8(a, a, r)
164 return r
166 @opcode(0x8, 0x68, 0x78) # LSL/ASL (direct, indexed, extended)
167 def instruction_LSL_memory(self, opcode, ea, m):
168 """
169 Logical shift left memory location / Arithmetic shift of memory left
170 """
171 r = self.LSL(m)
172# log.debug("$%x LSL memory value $%x << 1 = $%x and write it to $%x \t| %s" % (
173# self.program_counter,
174# m, r, ea,
175# self.cfg.mem_info.get_shortest(ea)
176# ))
177 return ea, r & 0xff
179 @opcode(0x48, 0x58) # LSLA/ASLA / LSLB/ASLB (inherent)
180 def instruction_LSL_register(self, opcode, register):
181 """
182 Logical shift left accumulator / Arithmetic shift of accumulator
183 """
184 a = register.value
185 r = self.LSL(a)
186# log.debug("$%x LSL %s value $%x << 1 = $%x" % (
187# self.program_counter,
188# register.name, a, r
189# ))
190 register.set(r)
192 def LSR(self, a):
193 """
194 Performs a logical shift right on the register. Shifts a zero into bit
195 seven and bit zero into the C (carry) bit.
197 source code forms: LSR Q; LSRA; LSRB
199 CC bits "HNZVC": -0a-s
200 """
201 r = a >> 1
202 self.clear_NZC()
203 self.C = get_bit(a, bit=0) # same as: self.C |= (a & 1)
204 self.set_Z8(r)
205 return r
207 @opcode(0x4, 0x64, 0x74) # LSR (direct, indexed, extended)
208 def instruction_LSR_memory(self, opcode, ea, m):
209 """ Logical shift right memory location """
210 r = self.LSR(m)
211# log.debug("$%x LSR memory value $%x >> 1 = $%x and write it to $%x \t| %s" % (
212# self.program_counter,
213# m, r, ea,
214# self.cfg.mem_info.get_shortest(ea)
215# ))
216 return ea, r & 0xff
218 @opcode(0x44, 0x54) # LSRA / LSRB (inherent)
219 def instruction_LSR_register(self, opcode, register):
220 """ Logical shift right accumulator """
221 a = register.value
222 r = self.LSR(a)
223# log.debug("$%x LSR %s value $%x >> 1 = $%x" % (
224# self.program_counter,
225# register.name, a, r
226# ))
227 register.set(r)
229 def ASR(self, a):
230 """
231 ASR (Arithmetic Shift Right) alias LSR (Logical Shift Right)
233 Shifts all bits of the register one place to the right. Bit seven is held
234 constant. Bit zero is shifted into the C (carry) bit.
236 source code forms: ASR Q; ASRA; ASRB
238 CC bits "HNZVC": uaa-s
239 """
240 r = (a >> 1) | (a & 0x80)
241 self.clear_NZC()
242 self.C = get_bit(a, bit=0) # same as: self.C |= (a & 1)
243 self.update_NZ_8(r)
244 return r
246 @opcode(0x7, 0x67, 0x77) # ASR (direct, indexed, extended)
247 def instruction_ASR_memory(self, opcode, ea, m):
248 """ Arithmetic shift memory right """
249 r = self.ASR(m)
250# log.debug("$%x ASR memory value $%x >> 1 | Carry = $%x and write it to $%x \t| %s" % (
251# self.program_counter,
252# m, r, ea,
253# self.cfg.mem_info.get_shortest(ea)
254# ))
255 return ea, r & 0xff
257 @opcode(0x47, 0x57) # ASRA/ASRB (inherent)
258 def instruction_ASR_register(self, opcode, register):
259 """ Arithmetic shift accumulator right """
260 a = register.value
261 r = self.ASR(a)
262# log.debug("$%x ASR %s value $%x >> 1 | Carry = $%x" % (
263# self.program_counter,
264# register.name, a, r
265# ))
266 register.set(r)
268 # ---- Rotate: ROL, ROR ----
270 def ROL(self, a):
271 """
272 Rotates all bits of the register one place left through the C (carry)
273 bit. This is a 9-bit rotation.
275 source code forms: ROL Q; ROLA; ROLB
277 CC bits "HNZVC": -aaas
278 """
279 r = (a << 1) | self.C
280 self.clear_NZVC()
281 self.update_NZVC_8(a, a, r)
282 return r
284 @opcode(0x9, 0x69, 0x79) # ROL (direct, indexed, extended)
285 def instruction_ROL_memory(self, opcode, ea, m):
286 """ Rotate memory left """
287 r = self.ROL(m)
288# log.debug("$%x ROL memory value $%x << 1 | Carry = $%x and write it to $%x \t| %s" % (
289# self.program_counter,
290# m, r, ea,
291# self.cfg.mem_info.get_shortest(ea)
292# ))
293 return ea, r & 0xff
295 @opcode(0x49, 0x59) # ROLA / ROLB (inherent)
296 def instruction_ROL_register(self, opcode, register):
297 """ Rotate accumulator left """
298 a = register.value
299 r = self.ROL(a)
300# log.debug("$%x ROL %s value $%x << 1 | Carry = $%x" % (
301# self.program_counter,
302# register.name, a, r
303# ))
304 register.set(r)
306 def ROR(self, a):
307 """
308 Rotates all bits of the register one place right through the C (carry)
309 bit. This is a 9-bit rotation.
311 moved the carry flag into bit 8
312 moved bit 7 into carry flag
314 source code forms: ROR Q; RORA; RORB
316 CC bits "HNZVC": -aa-s
317 """
318 r = (a >> 1) | (self.C << 7)
319 self.clear_NZ()
320 self.update_NZ_8(r)
321 self.C = get_bit(a, bit=0) # same as: self.C = (a & 1)
322 return r
324 @opcode(0x6, 0x66, 0x76) # ROR (direct, indexed, extended)
325 def instruction_ROR_memory(self, opcode, ea, m):
326 """ Rotate memory right """
327 r = self.ROR(m)
328# log.debug("$%x ROR memory value $%x >> 1 | Carry = $%x and write it to $%x \t| %s" % (
329# self.program_counter,
330# m, r, ea,
331# self.cfg.mem_info.get_shortest(ea)
332# ))
333 return ea, r & 0xff
335 @opcode(0x46, 0x56) # RORA/RORB (inherent)
336 def instruction_ROR_register(self, opcode, register):
337 """ Rotate accumulator right """
338 a = register.value
339 r = self.ROR(a)
340# log.debug("$%x ROR %s value $%x >> 1 | Carry = $%x" % (
341# self.program_counter,
342# register.name, a, r
343# ))
344 register.set(r)