From 3c6c631945516d980d5f0c7e35ca743c4753dc7d Mon Sep 17 00:00:00 2001 From: Mike Naberezny Date: Thu, 23 Jan 2014 17:27:41 -0800 Subject: [PATCH] Remove page wrap bug from indexed indirect (X) on 65C02 --- py65/devices/mpu65c02.py | 7 +- py65/tests/devices/test_mpu6502.py | 184 ++++++++++++++++++++++------ py65/tests/devices/test_mpu65c02.py | 140 +++++++++++++++++++++ 3 files changed, 293 insertions(+), 38 deletions(-) diff --git a/py65/devices/mpu65c02.py b/py65/devices/mpu65c02.py index ad07605..e57fc92 100644 --- a/py65/devices/mpu65c02.py +++ b/py65/devices/mpu65c02.py @@ -26,11 +26,14 @@ class MPU(mpu6502.MPU): # addressing modes + def IndirectXAddr(self): + return self.WordAt(self.ByteAt(self.pc) + self.x) + def ZeroPageIndirectAddr(self): - return self.WordAt(255 & (self.ByteAt(self.pc))) + return self.WordAt(self.ByteAt(self.pc)) def IndirectAbsXAddr(self): - return (self.WordAt(self.pc) + self.x) & self.addrMask + return self.addrMask & (self.WordAt(self.pc) + self.x) def AccumulatorAddr(self): return self.a diff --git a/py65/tests/devices/test_mpu6502.py b/py65/tests/devices/test_mpu6502.py index 50270d6..7f43e6d 100644 --- a/py65/tests/devices/test_mpu6502.py +++ b/py65/tests/devices/test_mpu6502.py @@ -5636,17 +5636,38 @@ class MPUTests(unittest.TestCase, Common6502Tests): mpu = self._make_mpu() self.assertTrue("6502" in repr(mpu)) - # LDA Zero Page, X-Indexed + # ADC Indirect, Indexed (X) - def test_lda_zp_x_indexed_page_wraps(self): + def test_adc_ind_indexed_has_page_wrap_bug(self): mpu = self._make_mpu() - mpu.a = 0x00 + mpu.a = 0x01 mpu.x = 0xFF - # $0000 LDA $80,X - self._write(mpu.memory, 0x0000, (0xB5, 0x80)) - mpu.memory[0x007F] = 0x42 + # $0000 ADC ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0x61, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0x01 + mpu.memory[0xBBBB] = 0x02 + mpu.step() + self.assertEqual(0x03, mpu.a) + + # AND Indirect, Indexed (X) + + def test_and_ind_indexed_x_has_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.a = 0x42 + mpu.x = 0xFF + # $0000 AND ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0x21, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0 + mpu.memory[0xBBBB] = 0xFF mpu.step() - self.assertEqual(0x0002, mpu.pc) self.assertEqual(0x42, mpu.a) # BRK @@ -5671,9 +5692,75 @@ class MPUTests(unittest.TestCase, Common6502Tests): self.assertEqual(mpu.BREAK, mpu.p & mpu.BREAK) self.assertEqual(0, mpu.p & mpu.DECIMAL) + # CMP Indirect, Indexed (X) + + def test_cmp_ind_x_has_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.p = 0 + mpu.a = 0x42 + mpu.x = 0xFF + # $0000 CMP ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0xC1, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0x00 + mpu.memory[0xBBBB] = 0x42 + mpu.step() + self.assertEqual(mpu.ZERO, mpu.p & mpu.ZERO) + + # EOR Indirect, Indexed (X) + + def test_eor_ind_x_has_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.p = 0 + mpu.a = 0xAA + mpu.x = 0xFF + # $0000 EOR ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0x41, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0x00 + mpu.memory[0xBBBB] = 0xFF + mpu.step() + self.assertEqual(0x55, mpu.a) + + # LDA Indirect, Indexed (X) + + def test_lda_ind_indexed_x_has_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.a = 0x00 + mpu.x = 0xff + # $0000 LDA ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0xA1, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0x42 + mpu.memory[0xBBBB] = 0xEF + mpu.step() + self.assertEqual(0xEF, mpu.a) + + # LDA Zero Page, X-Indexed + + def test_lda_zp_x_has_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.a = 0x00 + mpu.x = 0xFF + # $0000 LDA $80,X + self._write(mpu.memory, 0x0000, (0xB5, 0x80)) + mpu.memory[0x007F] = 0x42 + mpu.step() + self.assertEqual(0x0002, mpu.pc) + self.assertEqual(0x42, mpu.a) + # JMP Indirect - def test_jmp_jumps_to_address_with_page_wrap_bug(self): + def test_jmp_indirect_has_page_wrap_bug(self): mpu = self._make_mpu() mpu.memory[0x00ff] = 0 # $0000 JMP ($00) @@ -5682,6 +5769,59 @@ class MPUTests(unittest.TestCase, Common6502Tests): self.assertEqual(0x6c00, mpu.pc) self.assertEqual(5, mpu.processorCycles) + # ORA Indirect, Indexed (X) + + def test_ora_ind_indexed_x_has_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.a = 0 + mpu.x = 0xFF + # $0000 ORA ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0x01, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0 + mpu.memory[0xBBBB] = 0x42 + mpu.step() + self.assertEqual(0x42, mpu.a) + + # SBC Indirect, Indexed (X) + + def test_sbc_ind_x_has_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.p = mpu.CARRY + mpu.a = 0x03 + mpu.x = 0xFF + # $0000 SBC ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0xE1, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0x01 + mpu.memory[0xBBBB] = 0x02 + mpu.step() + self.assertEqual(0x01, mpu.a) + + # STA Indirect, Indexed (X) + + def test_sta_ind_indexed_x_has_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.a = 0x42 + mpu.x = 0xFF + # $0000 STA ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0x81, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0 + mpu.memory[0xBBBB] = 0 + mpu.step() + self.assertEqual(0x00, mpu.memory[0xABCD]) + self.assertEqual(0x42, mpu.memory[0xBBBB]) + # Test page wrapping def test_zeropage_indexed_ind_wrap(self): @@ -5694,34 +5834,6 @@ class MPUTests(unittest.TestCase, Common6502Tests): mpu.step() self.assertEqual(0x31, mpu.a) - def test_zeropage_indexed_wrap(self): - mpu = self._make_mpu() - mpu.x = 1 - # $0000 LDA $FF,X - self._write(mpu.memory, 0, (0xb5, 0xff)) - mpu.step() - self.assertEqual(0xb5, mpu.a) - - def test_zeropage_ind_indexed_wrap(self): - mpu = self._make_mpu() - mpu.x = 0 - mpu.memory[0xa100] = 0x31 - mpu.memory[0xff] = 0 - # $0000 LDA ($FF,X) - self._write(mpu.memory, 0, (0xa1, 0xff)) - mpu.step() - self.assertEqual(0x31, mpu.a) - - def test_zeropage_ind_indexed_index_wrap(self): - mpu = self._make_mpu() - mpu.x = 0xff - mpu.memory[0xa100] = 0x31 - mpu.memory[0x00ff] = 0 - # $0000 LDA ($00,X) - self._write(mpu.memory, 0, (0xa1, 0)) - mpu.step() - self.assertEqual(0x31, mpu.a) - def _get_target_class(self): return py65.devices.mpu6502.MPU diff --git a/py65/tests/devices/test_mpu65c02.py b/py65/tests/devices/test_mpu65c02.py index bd088fe..000e285 100644 --- a/py65/tests/devices/test_mpu65c02.py +++ b/py65/tests/devices/test_mpu65c02.py @@ -11,6 +11,23 @@ class MPUTests(unittest.TestCase, Common6502Tests): mpu = self._make_mpu() self.assertTrue('65C02' in repr(mpu)) + # ADC Indirect, Indexed (X) + + def test_adc_ind_indexed_has_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.a = 0x01 + mpu.x = 0xFF + # $0000 ADC ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0x61, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0x01 + mpu.memory[0xBBBB] = 0x02 + mpu.step() + self.assertEqual(0x02, mpu.a) + # ADC Zero Page, Indirect def test_adc_bcd_off_zp_ind_carry_clear_in_accumulator_zeroes(self): @@ -149,6 +166,23 @@ class MPUTests(unittest.TestCase, Common6502Tests): self.assertEqual(mpu.OVERFLOW, mpu.p & mpu.OVERFLOW) self.assertEqual(0, mpu.p & mpu.ZERO) + # AND Indirect, Indexed (X) + + def test_and_ind_indexed_x_does_not_have_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.a = 0x42 + mpu.x = 0xFF + # $0000 AND ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0x21, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0xFF + mpu.memory[0xBBBB] = 0 + mpu.step() + self.assertEqual(0x42, mpu.a) + # AND Zero Page, Indirect def test_and_zp_ind_all_zeros_setting_zero_flag(self): @@ -442,6 +476,42 @@ class MPUTests(unittest.TestCase, Common6502Tests): self.assertEqual(mpu.BREAK, mpu.p & mpu.BREAK) self.assertEqual(0, mpu.p & mpu.DECIMAL) + # CMP Indirect, Indexed (X) + + def test_cmp_ind_x_has_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.p = 0 + mpu.a = 0x42 + mpu.x = 0xFF + # $0000 CMP ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0xC1, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0x42 + mpu.memory[0xBBBB] = 0x00 + mpu.step() + self.assertEqual(mpu.ZERO, mpu.p & mpu.ZERO) + + # EOR Indirect, Indexed (X) + + def test_eor_ind_x_does_not_have_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.p = 0 + mpu.a = 0xAA + mpu.x = 0xFF + # $0000 EOR ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0x41, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0xFF + mpu.memory[0xBBBB] = 0x00 + mpu.step() + self.assertEqual(0x55, mpu.a) + # EOR Zero Page, Indirect def test_eor_zp_ind_flips_bits_over_setting_z_flag(self): @@ -499,6 +569,23 @@ class MPUTests(unittest.TestCase, Common6502Tests): self.assertEqual(0x1234, mpu.pc) self.assertEqual(6, mpu.processorCycles) + # LDA Indirect, Indexed (X) + + def test_lda_ind_indexed_x_does_not_have_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.a = 0x00 + mpu.x = 0xff + # $0000 LDA ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0xA1, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0x42 + mpu.memory[0xBBBB] = 0xFF + mpu.step() + self.assertEqual(0x42, mpu.a) + # LDA Zero Page, Indirect def test_lda_zp_ind_loads_a_sets_n_flag(self): @@ -531,6 +618,23 @@ class MPUTests(unittest.TestCase, Common6502Tests): self.assertEqual(mpu.ZERO, mpu.p & mpu.ZERO) self.assertEqual(0, mpu.p & mpu.NEGATIVE) + # ORA Indirect, Indexed (X) + + def test_ora_ind_indexed_x_does_not_have_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.a = 0 + mpu.x = 0xFF + # $0000 ORA ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0x01, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0x42 + mpu.memory[0xBBBB] = 0 + mpu.step() + self.assertEqual(0x42, mpu.a) + # ORA Zero Page, Indirect def test_ora_zp_ind_zeroes_or_zeros_sets_z_flag(self): @@ -806,6 +910,42 @@ class MPUTests(unittest.TestCase, Common6502Tests): mpu.step() self.assertEqual(expected, mpu.p) + # SBC Indirect, Indexed (X) + + def test_sbc_ind_x_has_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.p = mpu.CARRY + mpu.a = 0x03 + mpu.x = 0xFF + # $0000 SBC ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0xE1, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0x01 + mpu.memory[0xBBBB] = 0x02 + mpu.step() + self.assertEqual(0x02, mpu.a) + + # STA Indirect, Indexed (X) + + def test_sta_ind_indexed_x_does_not_have_page_wrap_bug(self): + mpu = self._make_mpu() + mpu.a = 0x42 + mpu.x = 0xFF + # $0000 STA ($80,X) + # $007f Vector to $BBBB (read if page wrapped) + # $017f Vector to $ABCD (read if no page wrap) + self._write(mpu.memory, 0x0000, (0x81, 0x80)) + self._write(mpu.memory, 0x007f, (0xBB, 0xBB)) + self._write(mpu.memory, 0x017f, (0xCD, 0xAB)) + mpu.memory[0xABCD] = 0 + mpu.memory[0xBBBB] = 0 + mpu.step() + self.assertEqual(0x42, mpu.memory[0xABCD]) + self.assertEqual(0x00, mpu.memory[0xBBBB]) + # STA Zero Page, Indirect def test_sta_zp_ind_stores_a_leaves_a_and_n_flag_unchanged(self):