diff --git a/CHANGES.txt b/CHANGES.txt index 31f7f5a..64eda3a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -11,7 +11,9 @@ - Fixed a bug where the MPU status display would wrap unexpectedly on some terminals. - - Added support for 65C02 opcode 0x89 (BIT immediate). + - Added support for 65C02 opcode 0x89: BIT #. + + - Added support for 65C02 opcode 0x7C: JMP (abs,x). 0.13 (2012-11-15) diff --git a/py65/assembler.py b/py65/assembler.py index eca5279..58771c6 100644 --- a/py65/assembler.py +++ b/py65/assembler.py @@ -19,6 +19,8 @@ class Assembler: re.compile(r'^\$00([0-9A-F]{2})$')], ['inx', # "($0012,X) re.compile(r'^\(\$00([0-9A-F]{2}),X\)$')], + ['iax', # "($1234,X) + re.compile(r'^\(\$([0-9A-F]{2})([0-9A-F]{2}),X\)$')], ['iny', # "($0012),Y" re.compile(r'^\(\$00([0-9A-F]{2})\),Y$')], ['ind', # "($1234)" diff --git a/py65/devices/mpu65c02.py b/py65/devices/mpu65c02.py index b4bd99f..a77aaa7 100644 --- a/py65/devices/mpu65c02.py +++ b/py65/devices/mpu65c02.py @@ -29,6 +29,9 @@ class MPU(mpu6502.MPU): def ZeroPageIndirectAddr(self): return self.WordAt(255 & (self.ByteAt(self.pc))) + def IndirectAbsXAddr(self): + return (self.WordAt(self.pc) + self.x) & self.addrMask + def AccumulatorAddr(self): return self.a @@ -261,6 +264,10 @@ class MPU(mpu6502.MPU): def inst_0x3a(self): self.opDECR(None) + @instruction(name="JMP", mode="iax", cycles=6) + def inst_0x7c(self): + self.pc = self.WordAt(self.IndirectAbsXAddr()) + @instruction(name="BRA", mode="rel", cycles=1, extracycles=1) def inst_0x80(self): self.BranchRelAddr() diff --git a/py65/disassembler.py b/py65/disassembler.py index 6a9cc19..902c816 100644 --- a/py65/disassembler.py +++ b/py65/disassembler.py @@ -78,6 +78,13 @@ class Disassembler: disasm += ' (%s,X)' % address_or_label length = 2 + elif addressing == 'iax': + address = self._mpu.WordAt(pc + 1) + address_or_label = self._address_parser.label_for( + address, '$' + self.addrFmt % address) + disasm += ' (%s,X)' % address_or_label + length = 3 + elif addressing == 'rel': opv = self._mpu.ByteAt(pc + 1) targ = pc + 2 diff --git a/py65/tests/devices/test_mpu65c02.py b/py65/tests/devices/test_mpu65c02.py index 22cd621..8da97f6 100644 --- a/py65/tests/devices/test_mpu65c02.py +++ b/py65/tests/devices/test_mpu65c02.py @@ -463,6 +463,19 @@ class MPUTests(unittest.TestCase, Common6502Tests): self.assertEqual(mpu.NEGATIVE, mpu.p & mpu.NEGATIVE) self.assertEqual(0, mpu.p & mpu.ZERO) + # JMP Indirect Absolute X-Indexed + + def test_jmp_iax_jumps_to_address(self): + mpu = self._make_mpu() + mpu.x = 2 + # $0000 JMP ($ABCD,X) + # $ABCF Vector to $1234 + self._write(mpu.memory, 0x0000, (0x7C, 0xCD, 0xAB)) + self._write(mpu.memory, 0xABCF, (0x34, 0x12)) + mpu.step() + self.assertEqual(0x1234, mpu.pc) + self.assertEqual(6, mpu.processorCycles) + # LDA Zero Page, Indirect def test_lda_zp_ind_loads_a_sets_n_flag(self): diff --git a/py65/tests/test_assembler.py b/py65/tests/test_assembler.py index 75d113a..a5bfa70 100644 --- a/py65/tests/test_assembler.py +++ b/py65/tests/test_assembler.py @@ -470,8 +470,19 @@ class AssemblerTests(unittest.TestCase): def dont_test_assembles_7b(self): pass - def dont_test_assembles_7c(self): - pass + def test_assembles_7c_6502(self): + self.assertRaises(SyntaxError, + self.assemble, "JMP ($1234,X)") + + def test_assembles_7c_65c02(self): + mpu = MPU65C02() + self.assertEqual([0x7c, 0x34, 0x12], + self.assemble('JMP ($1234,X)', 0x0000, mpu)) + + def test_assembles_07_65c02(self): + mpu = MPU65C02() + self.assertEqual([0x07, 0x42], + self.assemble('RMB0 $42', 0x0000, mpu)) def test_assembles_7d(self): self.assertEqual([0x7d, 0x00, 0x44], diff --git a/py65/tests/test_disassembler.py b/py65/tests/test_disassembler.py index 18bfe65..1841592 100644 --- a/py65/tests/test_disassembler.py +++ b/py65/tests/test_disassembler.py @@ -633,11 +633,17 @@ class DisassemblerTests(unittest.TestCase): self.assertEqual(1, length) self.assertEqual('???', disasm) - def test_disassembles_7c(self): + def test_disassembles_7c_6502(self): length, disasm = self.disassemble([0x7c]) self.assertEqual(1, length) self.assertEqual('???', disasm) + def test_disassembles_7c_65c02(self): + mpu = MPU65C02() + length, disasm = self.disassemble([0x7c, 0x34, 0x12], 0x0000, mpu) + self.assertEqual(3, length) + self.assertEqual('JMP ($1234,X)', disasm) + def test_disassembles_7d(self): length, disasm = self.disassemble([0x7d, 0x00, 0x44]) self.assertEqual(3, length)