Coverage for MC6809/components/mc6809_ops_branches.py: 83%
76 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
27class OpsBranchesMixin:
29 # ---- Programm Flow Instructions ----
31 @opcode( # Jump
32 0xe, 0x6e, 0x7e, # JMP (direct, indexed, extended)
33 )
34 def instruction_JMP(self, opcode, ea):
35 """
36 Program control is transferred to the effective address.
38 source code forms: JMP EA
40 CC bits "HNZVC": -----
41 """
42# log.info("%x|\tJMP to $%x \t| %s" % (
43# self.last_op_address,
44# ea, self.cfg.mem_info.get_shortest(ea)
45# ))
46 self.program_counter.set(ea)
48 @opcode( # Return from subroutine
49 0x39, # RTS (inherent)
50 )
51 def instruction_RTS(self, opcode):
52 """
53 Program control is returned from the subroutine to the calling program.
54 The return address is pulled from the stack.
56 source code forms: RTS
58 CC bits "HNZVC": -----
59 """
60 ea = self.pull_word(self.system_stack_pointer)
61# log.info("%x|\tRTS to $%x \t| %s" % (
62# self.last_op_address,
63# ea,
64# self.cfg.mem_info.get_shortest(ea)
65# ))
66 self.program_counter.set(ea)
68 @opcode(
69 # Branch to subroutine:
70 0x8d, # BSR (relative)
71 0x17, # LBSR (relative)
72 # Jump to subroutine:
73 0x9d, 0xad, 0xbd, # JSR (direct, indexed, extended)
74 )
75 def instruction_BSR_JSR(self, opcode, ea):
76 """
77 Program control is transferred to the effective address after storing
78 the return address on the hardware stack.
80 A return from subroutine (RTS) instruction is used to reverse this
81 process and must be the last instruction executed in a subroutine.
83 source code forms: BSR dd; LBSR DDDD; JSR EA
85 CC bits "HNZVC": -----
86 """
87# log.info("%x|\tJSR/BSR to $%x \t| %s" % (
88# self.last_op_address,
89# ea, self.cfg.mem_info.get_shortest(ea)
90# ))
91 self.push_word(self.system_stack_pointer, self.program_counter.value)
92 self.program_counter.set(ea)
94 # ---- Branch Instructions ----
96 @opcode( # Branch if equal
97 0x27, # BEQ (relative)
98 0x1027, # LBEQ (relative)
99 )
100 def instruction_BEQ(self, opcode, ea):
101 """
102 Tests the state of the Z (zero) bit and causes a branch if it is set.
103 When used after a subtract or compare operation, this instruction will
104 branch if the compared values, signed or unsigned, were exactly the
105 same.
107 source code forms: BEQ dd; LBEQ DDDD
109 CC bits "HNZVC": -----
110 """
111 if self.Z == 1:
112 # log.info("$%x BEQ branch to $%x, because Z==1 \t| %s" % (
113 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
114 # ))
115 self.program_counter.set(ea)
116# else:
117# log.debug("$%x BEQ: don't branch to $%x, because Z==0 \t| %s" % (
118# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
119# ))
121 @opcode( # Branch if greater than or equal (signed)
122 0x2c, # BGE (relative)
123 0x102c, # LBGE (relative)
124 )
125 def instruction_BGE(self, opcode, ea):
126 """
127 Causes a branch if the N (negative) bit and the V (overflow) bit are
128 either both set or both clear. That is, branch if the sign of a valid
129 twos complement result is, or would be, positive. When used after a
130 subtract or compare operation on twos complement values, this
131 instruction will branch if the register was greater than or equal to the
132 memory register.
134 source code forms: BGE dd; LBGE DDDD
136 CC bits "HNZVC": -----
137 """
138 # Note these variantes are the same:
139 # self.N == self.V
140 # (self.N ^ self.V) == 0
141 # not operator.xor(self.N, self.V)
142 if self.N == self.V:
143 # log.info("$%x BGE branch to $%x, because N XOR V == 0 \t| %s" % (
144 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
145 # ))
146 self.program_counter.set(ea)
147# else:
148# log.debug("$%x BGE: don't branch to $%x, because N XOR V != 0 \t| %s" % (
149# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
150# ))
152 @opcode( # Branch if greater (signed)
153 0x2e, # BGT (relative)
154 0x102e, # LBGT (relative)
155 )
156 def instruction_BGT(self, opcode, ea):
157 """
158 Causes a branch if the N (negative) bit and V (overflow) bit are either
159 both set or both clear and the Z (zero) bit is clear. In other words,
160 branch if the sign of a valid twos complement result is, or would be,
161 positive and not zero. When used after a subtract or compare operation
162 on twos complement values, this instruction will branch if the register
163 was greater than the memory register.
165 source code forms: BGT dd; LBGT DDDD
167 CC bits "HNZVC": -----
168 """
169 # Note these variantes are the same:
170 # not ((self.N ^ self.V) == 1 or self.Z == 1)
171 # not ((self.N ^ self.V) | self.Z)
172 # self.N == self.V and self.Z == 0
173 # ;)
174 if not self.Z and self.N == self.V:
175 # log.info("$%x BGT branch to $%x, because (N==V and Z==0) \t| %s" % (
176 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
177 # ))
178 self.program_counter.set(ea)
179# else:
180# log.debug("$%x BGT: don't branch to $%x, because (N==V and Z==0) is False \t| %s" % (
181# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
182# ))
184 @opcode( # Branch if higher (unsigned)
185 0x22, # BHI (relative)
186 0x1022, # LBHI (relative)
187 )
188 def instruction_BHI(self, opcode, ea):
189 """
190 Causes a branch if the previous operation caused neither a carry nor a
191 zero result. When used after a subtract or compare operation on unsigned
192 binary values, this instruction will branch if the register was higher
193 than the memory register.
195 Generally not useful after INC/DEC, LD/TST, and TST/CLR/COM
196 instructions.
198 source code forms: BHI dd; LBHI DDDD
200 CC bits "HNZVC": -----
201 """
202 if self.C == 0 and self.Z == 0:
203 # log.info("$%x BHI branch to $%x, because C==0 and Z==0 \t| %s" % (
204 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
205 # ))
206 self.program_counter.set(ea)
207# else:
208# log.debug("$%x BHI: don't branch to $%x, because C and Z not 0 \t| %s" % (
209# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
210# ))
212 @opcode( # Branch if less than or equal (signed)
213 0x2f, # BLE (relative)
214 0x102f, # LBLE (relative)
215 )
216 def instruction_BLE(self, opcode, ea):
217 """
218 Causes a branch if the exclusive OR of the N (negative) and V (overflow)
219 bits is 1 or if the Z (zero) bit is set. That is, branch if the sign of
220 a valid twos complement result is, or would be, negative. When used
221 after a subtract or compare operation on twos complement values, this
222 instruction will branch if the register was less than or equal to the
223 memory register.
225 source code forms: BLE dd; LBLE DDDD
227 CC bits "HNZVC": -----
228 """
229 if (self.N ^ self.V) == 1 or self.Z == 1:
230 # log.info("$%x BLE branch to $%x, because N^V==1 or Z==1 \t| %s" % (
231 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
232 # ))
233 self.program_counter.set(ea)
234# else:
235# log.debug("$%x BLE: don't branch to $%x, because N^V!=1 and Z!=1 \t| %s" % (
236# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
237# ))
239 @opcode( # Branch if lower or same (unsigned)
240 0x23, # BLS (relative)
241 0x1023, # LBLS (relative)
242 )
243 def instruction_BLS(self, opcode, ea):
244 """
245 Causes a branch if the previous operation caused either a carry or a
246 zero result. When used after a subtract or compare operation on unsigned
247 binary values, this instruction will branch if the register was lower
248 than or the same as the memory register.
250 Generally not useful after INC/DEC, LD/ST, and TST/CLR/COM instructions.
252 source code forms: BLS dd; LBLS DDDD
254 CC bits "HNZVC": -----
255 """
256# if (self.C|self.Z) == 0:
257 if self.C == 1 or self.Z == 1:
258 # log.info("$%x BLS branch to $%x, because C|Z==1 \t| %s" % (
259 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
260 # ))
261 self.program_counter.set(ea)
262# else:
263# log.debug("$%x BLS: don't branch to $%x, because C|Z!=1 \t| %s" % (
264# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
265# ))
267 @opcode( # Branch if less than (signed)
268 0x2d, # BLT (relative)
269 0x102d, # LBLT (relative)
270 )
271 def instruction_BLT(self, opcode, ea):
272 """
273 Causes a branch if either, but not both, of the N (negative) or V
274 (overflow) bits is set. That is, branch if the sign of a valid twos
275 complement result is, or would be, negative. When used after a subtract
276 or compare operation on twos complement binary values, this instruction
277 will branch if the register was less than the memory register.
279 source code forms: BLT dd; LBLT DDDD
281 CC bits "HNZVC": -----
282 """
283 if (self.N ^ self.V) == 1: # N xor V
284 # log.info("$%x BLT branch to $%x, because N XOR V == 1 \t| %s" % (
285 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
286 # ))
287 self.program_counter.set(ea)
288# else:
289# log.debug("$%x BLT: don't branch to $%x, because N XOR V != 1 \t| %s" % (
290# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
291# ))
293 @opcode( # Branch if minus
294 0x2b, # BMI (relative)
295 0x102b, # LBMI (relative)
296 )
297 def instruction_BMI(self, opcode, ea):
298 """
299 Tests the state of the N (negative) bit and causes a branch if set. That
300 is, branch if the sign of the twos complement result is negative.
302 When used after an operation on signed binary values, this instruction
303 will branch if the result is minus. It is generally preferred to use the
304 LBLT instruction after signed operations.
306 source code forms: BMI dd; LBMI DDDD
308 CC bits "HNZVC": -----
309 """
310 if self.N == 1:
311 # log.info("$%x BMI branch to $%x, because N==1 \t| %s" % (
312 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
313 # ))
314 self.program_counter.set(ea)
315# else:
316# log.debug("$%x BMI: don't branch to $%x, because N==0 \t| %s" % (
317# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
318# ))
320 @opcode( # Branch if not equal
321 0x26, # BNE (relative)
322 0x1026, # LBNE (relative)
323 )
324 def instruction_BNE(self, opcode, ea):
325 """
326 Tests the state of the Z (zero) bit and causes a branch if it is clear.
327 When used after a subtract or compare operation on any binary values,
328 this instruction will branch if the register is, or would be, not equal
329 to the memory register.
331 source code forms: BNE dd; LBNE DDDD
333 CC bits "HNZVC": -----
334 """
335 if self.Z == 0:
336 # log.info("$%x BNE branch to $%x, because Z==0 \t| %s" % (
337 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
338 # ))
339 self.program_counter.set(ea)
340# else:
341# log.debug("$%x BNE: don't branch to $%x, because Z==1 \t| %s" % (
342# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
343# ))
345 @opcode( # Branch if plus
346 0x2a, # BPL (relative)
347 0x102a, # LBPL (relative)
348 )
349 def instruction_BPL(self, opcode, ea):
350 """
351 Tests the state of the N (negative) bit and causes a branch if it is
352 clear. That is, branch if the sign of the twos complement result is
353 positive.
355 When used after an operation on signed binary values, this instruction
356 will branch if the result (possibly invalid) is positive. It is
357 generally preferred to use the BGE instruction after signed operations.
359 source code forms: BPL dd; LBPL DDDD
361 CC bits "HNZVC": -----
362 """
363 if self.N == 0:
364 # log.info("$%x BPL branch to $%x, because N==0 \t| %s" % (
365 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
366 # ))
367 self.program_counter.set(ea)
368# else:
369# log.debug("$%x BPL: don't branch to $%x, because N==1 \t| %s" % (
370# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
371# ))
373 @opcode( # Branch always
374 0x20, # BRA (relative)
375 0x16, # LBRA (relative)
376 )
377 def instruction_BRA(self, opcode, ea):
378 """
379 Causes an unconditional branch.
381 source code forms: BRA dd; LBRA DDDD
383 CC bits "HNZVC": -----
384 """
385# log.info("$%x BRA branch to $%x \t| %s" % (
386# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
387# ))
388 self.program_counter.set(ea)
390 @opcode( # Branch never
391 0x21, # BRN (relative)
392 0x1021, # LBRN (relative)
393 )
394 def instruction_BRN(self, opcode, ea):
395 """
396 Does not cause a branch. This instruction is essentially a no operation,
397 but has a bit pattern logically related to branch always.
399 source code forms: BRN dd; LBRN DDDD
401 CC bits "HNZVC": -----
402 """
403 pass
405 @opcode( # Branch if valid twos complement result
406 0x28, # BVC (relative)
407 0x1028, # LBVC (relative)
408 )
409 def instruction_BVC(self, opcode, ea):
410 """
411 Tests the state of the V (overflow) bit and causes a branch if it is
412 clear. That is, branch if the twos complement result was valid. When
413 used after an operation on twos complement binary values, this
414 instruction will branch if there was no overflow.
416 source code forms: BVC dd; LBVC DDDD
418 CC bits "HNZVC": -----
419 """
420 if self.V == 0:
421 # log.info("$%x BVC branch to $%x, because V==0 \t| %s" % (
422 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
423 # ))
424 self.program_counter.set(ea)
425# else:
426# log.debug("$%x BVC: don't branch to $%x, because V==1 \t| %s" % (
427# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
428# ))
430 @opcode( # Branch if invalid twos complement result
431 0x29, # BVS (relative)
432 0x1029, # LBVS (relative)
433 )
434 def instruction_BVS(self, opcode, ea):
435 """
436 Tests the state of the V (overflow) bit and causes a branch if it is
437 set. That is, branch if the twos complement result was invalid. When
438 used after an operation on twos complement binary values, this
439 instruction will branch if there was an overflow.
441 source code forms: BVS dd; LBVS DDDD
443 CC bits "HNZVC": -----
444 """
445 if self.V == 1:
446 # log.info("$%x BVS branch to $%x, because V==1 \t| %s" % (
447 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
448 # ))
449 self.program_counter.set(ea)
450# else:
451# log.debug("$%x BVS: don't branch to $%x, because V==0 \t| %s" % (
452# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
453# ))
455 @opcode( # Branch if lower (unsigned)
456 0x25, # BLO/BCS (relative)
457 0x1025, # LBLO/LBCS (relative)
458 )
459 def instruction_BLO(self, opcode, ea):
460 """
461 CC bits "HNZVC": -----
462 case 0x5: cond = REG_CC & CC_C; break; // BCS, BLO, LBCS, LBLO
463 """
464 if self.C == 1:
465 # log.info("$%x BLO/BCS/LBLO/LBCS branch to $%x, because C==1 \t| %s" % (
466 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
467 # ))
468 self.program_counter.set(ea)
469# else:
470# log.debug("$%x BLO/BCS/LBLO/LBCS: don't branch to $%x, because C==0 \t| %s" % (
471# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
472# ))
474 @opcode( # Branch if lower (unsigned)
475 0x24, # BHS/BCC (relative)
476 0x1024, # LBHS/LBCC (relative)
477 )
478 def instruction_BHS(self, opcode, ea):
479 """
480 CC bits "HNZVC": -----
481 case 0x4: cond = !(REG_CC & CC_C); break; // BCC, BHS, LBCC, LBHS
482 """
483 if self.C == 0:
484 # log.info("$%x BHS/BCC/LBHS/LBCC branch to $%x, because C==0 \t| %s" % (
485 # self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
486 # ))
487 self.program_counter.set(ea)
488# else:
489# log.debug("$%x BHS/BCC/LBHS/LBCC: don't branch to $%x, because C==1 \t| %s" % (
490# self.program_counter, ea, self.cfg.mem_info.get_shortest(ea)
491# ))