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

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 

25 

26 

27class OpsBranchesMixin: 

28 

29 # ---- Programm Flow Instructions ---- 

30 

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. 

37 

38 source code forms: JMP EA 

39 

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) 

47 

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. 

55 

56 source code forms: RTS 

57 

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) 

67 

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. 

79 

80 A return from subroutine (RTS) instruction is used to reverse this 

81 process and must be the last instruction executed in a subroutine. 

82 

83 source code forms: BSR dd; LBSR DDDD; JSR EA 

84 

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) 

93 

94 # ---- Branch Instructions ---- 

95 

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. 

106 

107 source code forms: BEQ dd; LBEQ DDDD 

108 

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# )) 

120 

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. 

133 

134 source code forms: BGE dd; LBGE DDDD 

135 

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# )) 

151 

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. 

164 

165 source code forms: BGT dd; LBGT DDDD 

166 

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# )) 

183 

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. 

194 

195 Generally not useful after INC/DEC, LD/TST, and TST/CLR/COM 

196 instructions. 

197 

198 source code forms: BHI dd; LBHI DDDD 

199 

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# )) 

211 

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. 

224 

225 source code forms: BLE dd; LBLE DDDD 

226 

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# )) 

238 

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. 

249 

250 Generally not useful after INC/DEC, LD/ST, and TST/CLR/COM instructions. 

251 

252 source code forms: BLS dd; LBLS DDDD 

253 

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# )) 

266 

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. 

278 

279 source code forms: BLT dd; LBLT DDDD 

280 

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# )) 

292 

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. 

301 

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. 

305 

306 source code forms: BMI dd; LBMI DDDD 

307 

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# )) 

319 

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. 

330 

331 source code forms: BNE dd; LBNE DDDD 

332 

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# )) 

344 

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. 

354 

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. 

358 

359 source code forms: BPL dd; LBPL DDDD 

360 

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# )) 

372 

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. 

380 

381 source code forms: BRA dd; LBRA DDDD 

382 

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) 

389 

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. 

398 

399 source code forms: BRN dd; LBRN DDDD 

400 

401 CC bits "HNZVC": ----- 

402 """ 

403 pass 

404 

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. 

415 

416 source code forms: BVC dd; LBVC DDDD 

417 

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# )) 

429 

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. 

440 

441 source code forms: BVS dd; LBVS DDDD 

442 

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# )) 

454 

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# )) 

473 

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# ))