prog8/sim65/test/Test65C02.kt
2019-09-04 22:23:31 +02:00

1548 lines
44 KiB
Kotlin

import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import kotlin.test.*
/*
Unit test suite adapted from Py65 https://github.com/mnaberez/py65
Copyright (c) 2008-2018, Mike Naberezny and contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@TestInstance(TestInstance.Lifecycle.PER_METHOD)
@Disabled("there is no 65C02 cpu implementation at this time") // TODO create a 65c02 cpu!
class Test65C02 : TestCommon6502() {
// CMOS 65C02 Tests
// Reset
@Test
fun test_reset_clears_decimal_flag() {
// W65C02S Datasheet, Apr 14 2009, Table 7-1 Operational Enhancements
// NMOS 6502 decimal flag = indetermine after reset, CMOS 65C02 = 0
mpu.Status.D = true
mpu.reset()
assertFalse(mpu.Status.D)
}
// ADC Zero Page, Indirect
@Test
fun test_adc_bcd_off_zp_ind_carry_clear_in_accumulator_zeroes() {
mpu.A = 0x00
// $0000 ADC ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x72, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x00, mpu.A)
assertFalse(mpu.Status.C)
assertFalse(mpu.Status.N)
assertTrue(mpu.Status.Z)
}
@Test
fun test_adc_bcd_off_zp_ind_carry_set_in_accumulator_zero() {
mpu.A = 0
mpu.Status.C = true
// $0000 ADC ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x72, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x01, mpu.A)
assertFalse(mpu.Status.N)
assertFalse(mpu.Status.Z)
assertFalse(mpu.Status.C)
}
@Test
fun test_adc_bcd_off_zp_ind_carry_clear_in_no_carry_clear_out() {
mpu.A = 0x01
// $0000 ADC ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x72, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0xFE
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0xFF, mpu.A)
assertTrue(mpu.Status.N)
assertFalse(mpu.Status.C)
assertFalse(mpu.Status.Z)
}
@Test
fun test_adc_bcd_off_zp_ind_carry_clear_in_carry_set_out() {
mpu.A = 0x02
// $0000 ADC ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x72, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x01, mpu.A)
assertTrue(mpu.Status.C)
assertFalse(mpu.Status.N)
assertFalse(mpu.Status.Z)
}
@Test
fun test_adc_bcd_off_zp_ind_overflow_cleared_no_carry_01_plus_01() {
mpu.Status.C = false
mpu.A = 0x01
// $0000 ADC ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x72, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x01
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(0x02, mpu.A)
assertFalse(mpu.Status.V)
}
@Test
fun test_adc_bcd_off_zp_ind_overflow_cleared_no_carry_01_plus_ff() {
mpu.Status.C = false
mpu.A = 0x01
// $0000 ADC ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x72, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(0x00, mpu.A)
assertFalse(mpu.Status.V)
}
@Test
fun test_adc_bcd_off_zp_ind_overflow_set_no_carry_7f_plus_01() {
mpu.Status.C = false
mpu.A = 0x7f
// $0000 ADC ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x72, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x01
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(0x80, mpu.A)
assertTrue(mpu.Status.V)
}
@Test
fun test_adc_bcd_off_zp_ind_overflow_set_no_carry_80_plus_ff() {
mpu.Status.C = false
mpu.A = 0x80
// $0000 ADC ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x72, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(0x7f, mpu.A)
assertTrue(mpu.Status.V)
}
@Test
fun test_adc_bcd_off_zp_ind_overflow_set_on_40_plus_40() {
mpu.A = 0x40
// $0000 ADC ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x72, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x40
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(0x80, mpu.A)
assertTrue(mpu.Status.N)
assertTrue(mpu.Status.V)
assertFalse(mpu.Status.Z)
}
// AND Zero Page, Indirect
@Test
fun test_and_zp_ind_all_zeros_setting_zero_flag() {
mpu.A = 0xFF
// $0000 AND ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x32, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x00, mpu.A)
assertTrue(mpu.Status.Z)
assertFalse(mpu.Status.N)
}
@Test
fun test_and_zp_ind_zeros_and_ones_setting_negative_flag() {
mpu.A = 0xFF
// $0000 AND ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x32, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0xAA
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0xAA, mpu.A)
assertTrue(mpu.Status.N)
assertFalse(mpu.Status.Z)
}
// BIT (Absolute, X-Indexed)
@Test
fun test_bit_abs_x_copies_bit_7_of_memory_to_n_flag_when_0() {
mpu.Status.N = false
mpu.X = 0x02
// $0000 BIT $FEEB,X
writeMem(memory, 0x0000, listOf(0x3C, 0xEB, 0xFE))
memory[0xFEED] = 0xFF
mpu.A = 0xFF
mpu.step()
assertTrue(mpu.Status.N)
assertEquals(4, mpu.totalCycles)
assertEquals(0x0003, mpu.PC)
}
@Test
fun test_bit_abs_x_copies_bit_7_of_memory_to_n_flag_when_1() {
mpu.Status.N = true
mpu.X = 0x02
// $0000 BIT $FEEB,X
writeMem(memory, 0x0000, listOf(0x3C, 0xEB, 0xFE))
memory[0xFEED] = 0x00
mpu.A = 0xFF
mpu.step()
assertFalse(mpu.Status.N)
assertEquals(4, mpu.totalCycles)
assertEquals(0x0003, mpu.PC)
}
@Test
fun test_bit_abs_x_copies_bit_6_of_memory_to_v_flag_when_0() {
mpu.Status.V = false
mpu.X = 0x02
// $0000 BIT $FEEB,X
writeMem(memory, 0x0000, listOf(0x3C, 0xEB, 0xFE))
memory[0xFEED] = 0xFF
mpu.A = 0xFF
mpu.step()
assertTrue(mpu.Status.V)
assertEquals(4, mpu.totalCycles)
assertEquals(0x0003, mpu.PC)
}
@Test
fun test_bit_abs_x_copies_bit_6_of_memory_to_v_flag_when_1() {
mpu.Status.V = true
mpu.X = 0x02
// $0000 BIT $FEEB,X
writeMem(memory, 0x0000, listOf(0x3C, 0xEB, 0xFE))
memory[0xFEED] = 0x00
mpu.A = 0xFF
mpu.step()
assertFalse(mpu.Status.V)
assertEquals(4, mpu.totalCycles)
assertEquals(0x0003, mpu.PC)
}
@Test
fun test_bit_abs_x_stores_result_of_and_in_z_preserves_a_when_1() {
mpu.Status.Z = false
mpu.X = 0x02
// $0000 BIT $FEEB,X
writeMem(memory, 0x0000, listOf(0x3C, 0xEB, 0xFE))
memory[0xFEED] = 0x00
mpu.A = 0x01
mpu.step()
assertTrue(mpu.Status.Z)
assertEquals(0x01, mpu.A)
assertEquals(0x00, memory[0xFEED])
assertEquals(4, mpu.totalCycles)
assertEquals(0x0003, mpu.PC)
}
@Test
fun test_bit_abs_x_stores_result_of_and_nonzero_in_z_preserves_a() {
mpu.Status.Z = true
mpu.X = 0x02
// $0000 BIT $FEEB,X
writeMem(memory, 0x0000, listOf(0x3C, 0xEB, 0xFE))
memory[0xFEED] = 0x01
mpu.A = 0x01
mpu.step()
assertFalse(mpu.Status.Z) // result of AND is non-zero
assertEquals(0x01, mpu.A)
assertEquals(0x01, memory[0xFEED])
assertEquals(4, mpu.totalCycles)
assertEquals(0x0003, mpu.PC)
}
@Test
fun test_bit_abs_x_stores_result_of_and_when_zero_in_z_preserves_a() {
mpu.Status.Z = false
mpu.X = 0x02
// $0000 BIT $FEEB,X
writeMem(memory, 0x0000, listOf(0x3C, 0xEB, 0xFE))
memory[0xFEED] = 0x00
mpu.A = 0x01
mpu.step()
assertTrue(mpu.Status.Z) // result of AND is zero
assertEquals(0x01, mpu.A)
assertEquals(0x00, memory[0xFEED])
assertEquals(4, mpu.totalCycles)
assertEquals(0x0003, mpu.PC)
}
// BIT (Immediate)
@Test
fun test_bit_imm_does_not_affect_n_and_z_flags() {
mpu.Status.N = true
mpu.Status.V = true
// $0000 BIT #$FF
writeMem(memory, 0x0000, listOf(0x89, 0xff))
mpu.A = 0x00
mpu.step()
assertTrue(mpu.Status.N)
assertTrue(mpu.Status.V)
assertEquals(0x00, mpu.A)
assertEquals(2, mpu.totalCycles)
assertEquals(0x02, mpu.PC)
}
@Test
fun test_bit_imm_stores_result_of_and_in_z_preserves_a_when_1() {
mpu.Status.Z = false
// $0000 BIT #$00
writeMem(memory, 0x0000, listOf(0x89, 0x00))
mpu.A = 0x01
mpu.step()
assertTrue(mpu.Status.Z)
assertEquals(0x01, mpu.A)
assertEquals(2, mpu.totalCycles)
assertEquals(0x02, mpu.PC)
}
@Test
fun test_bit_imm_stores_result_of_and_when_nonzero_in_z_preserves_a() {
mpu.Status.Z = true
// $0000 BIT #$01
writeMem(memory, 0x0000, listOf(0x89, 0x01))
mpu.A = 0x01
mpu.step()
assertFalse(mpu.Status.Z) // result of AND is non-zero
assertEquals(0x01, mpu.A)
assertEquals(2, mpu.totalCycles)
assertEquals(0x02, mpu.PC)
}
@Test
fun test_bit_imm_stores_result_of_and_when_zero_in_z_preserves_a() {
mpu.Status.Z = false
// $0000 BIT #$00
writeMem(memory, 0x0000, listOf(0x89, 0x00))
mpu.A = 0x01
mpu.step()
assertTrue(mpu.Status.Z) // result of AND is zero
assertEquals(0x01, mpu.A)
assertEquals(2, mpu.totalCycles)
assertEquals(0x02, mpu.PC)
}
// BIT (Zero Page, X-Indexed)
@Test
fun test_bit_zp_x_copies_bit_7_of_memory_to_n_flag_when_0() {
mpu.Status.N = false
// $0000 BIT $0010,X
writeMem(memory, 0x0000, listOf(0x34, 0x10))
memory[0x0013] = 0xFF
mpu.X = 0x03
mpu.A = 0xFF
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(4, mpu.totalCycles)
assertTrue(mpu.Status.N)
}
@Test
fun test_bit_zp_x_copies_bit_7_of_memory_to_n_flag_when_1() {
mpu.Status.N = true
// $0000 BIT $0010,X
writeMem(memory, 0x0000, listOf(0x34, 0x10))
memory[0x0013] = 0x00
mpu.X = 0x03
mpu.A = 0xFF
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(4, mpu.totalCycles)
assertFalse(mpu.Status.N)
}
@Test
fun test_bit_zp_x_copies_bit_6_of_memory_to_v_flag_when_0() {
mpu.Status.V = false
// $0000 BIT $0010,X
writeMem(memory, 0x0000, listOf(0x34, 0x10))
memory[0x0013] = 0xFF
mpu.X = 0x03
mpu.A = 0xFF
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(4, mpu.totalCycles)
assertTrue(mpu.Status.V)
}
@Test
fun test_bit_zp_x_copies_bit_6_of_memory_to_v_flag_when_1() {
mpu.Status.V = true
// $0000 BIT $0010,X
writeMem(memory, 0x0000, listOf(0x34, 0x10))
memory[0x0013] = 0x00
mpu.X = 0x03
mpu.A = 0xFF
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(4, mpu.totalCycles)
assertFalse(mpu.Status.V)
}
@Test
fun test_bit_zp_x_stores_result_of_and_in_z_preserves_a_when_1() {
mpu.Status.Z = false
// $0000 BIT $0010,X
writeMem(memory, 0x0000, listOf(0x34, 0x10))
memory[0x0013] = 0x00
mpu.X = 0x03
mpu.A = 0x01
mpu.step()
assertTrue(mpu.Status.Z)
assertEquals(0x0002, mpu.PC)
assertEquals(4, mpu.totalCycles)
assertEquals(0x01, mpu.A)
assertEquals(0x00, memory[0x0010 + mpu.X])
}
@Test
fun test_bit_zp_x_stores_result_of_and_when_nonzero_in_z_preserves_a() {
mpu.Status.Z = true
// $0000 BIT $0010,X
writeMem(memory, 0x0000, listOf(0x34, 0x10))
memory[0x0013] = 0x01
mpu.X = 0x03
mpu.A = 0x01
mpu.step()
assertFalse(mpu.Status.Z) // result of AND is non-zero
assertEquals(0x0002, mpu.PC)
assertEquals(4, mpu.totalCycles)
assertEquals(0x01, mpu.A)
assertEquals(0x01, memory[0x0010 + mpu.X])
}
@Test
fun test_bit_zp_x_stores_result_of_and_when_zero_in_z_preserves_a() {
mpu.Status.Z = false
// $0000 BIT $0010,X
writeMem(memory, 0x0000, listOf(0x34, 0x10))
memory[0x0013] = 0x00
mpu.X = 0x03
mpu.A = 0x01
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(4, mpu.totalCycles)
assertTrue(mpu.Status.Z) // result of AND is zero
assertEquals(0x01, mpu.A)
assertEquals(0x00, memory[0x0010 + mpu.X])
}
// BRK
@Test
fun test_brk_clears_decimal_flag() {
mpu.Status.D = true
// $C000 BRK
memory[0xC000] = 0x00
mpu.PC = 0xC000
mpu.step()
assertTrue(mpu.Status.B)
assertFalse(mpu.Status.D)
}
// CMP Zero Page, Indirect
@Test
fun test_cmp_zpi_sets_z_flag_if_equal() {
mpu.A = 0x42
// $0000 AND ($10)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0xd2, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x42
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x42, mpu.A)
assertTrue(mpu.Status.Z)
assertFalse(mpu.Status.N)
}
@Test
fun test_cmp_zpi_resets_z_flag_if_unequal() {
mpu.A = 0x43
// $0000 AND ($10)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0xd2, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x42
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x43, mpu.A)
assertFalse(mpu.Status.Z)
assertFalse(mpu.Status.N)
}
// EOR Zero Page, Indirect
@Test
fun test_eor_zp_ind_flips_bits_over_setting_z_flag() {
mpu.A = 0xFF
// $0000 EOR ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x52, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x00, mpu.A)
assertEquals(0xFF, memory[0xABCD])
assertTrue(mpu.Status.Z)
}
@Test
fun test_eor_zp_ind_flips_bits_over_setting_n_flag() {
mpu.A = 0x00
// $0000 EOR ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x52, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0xFF, mpu.A)
assertEquals(0xFF, memory[0xABCD])
assertTrue(mpu.Status.N)
assertFalse(mpu.Status.Z)
}
// INC Accumulator
@Test
fun test_inc_acc_increments_accum() {
memory[0x0000] = 0x1A
mpu.A = 0x42
mpu.step()
assertEquals(0x0001, mpu.PC)
assertEquals(0x43, mpu.A)
assertFalse(mpu.Status.Z)
assertFalse(mpu.Status.N)
}
@Test
fun test_inc_acc_increments_accum_rolls_over_and_sets_zero_flag() {
memory[0x0000] = 0x1A
mpu.A = 0xFF
mpu.step()
assertEquals(0x0001, mpu.PC)
assertEquals(0x00, mpu.A)
assertTrue(mpu.Status.Z)
assertFalse(mpu.Status.N)
}
@Test
fun test_inc_acc_sets_negative_flag_when_incrementing_above_7F() {
memory[0x0000] = 0x1A
mpu.A = 0x7F
mpu.step()
assertEquals(0x0001, mpu.PC)
assertEquals(0x80, mpu.A)
assertFalse(mpu.Status.Z)
assertTrue(mpu.Status.N)
}
// JMP Indirect
@Test
fun test_jmp_ind_does_not_have_page_wrap_bug() {
writeMem(memory, 0x10FF, listOf(0xCD, 0xAB))
// $0000 JMP ($10FF)
writeMem(memory, 0, listOf(0x6c, 0xFF, 0x10))
mpu.step()
assertEquals(0xABCD, mpu.PC)
assertEquals(6, mpu.totalCycles)
}
// JMP Indirect Absolute X-Indexed
@Test
fun test_jmp_iax_jumps_to_address() {
mpu.X = 2
// $0000 JMP ($ABCD,X)
// $ABCF Vector to $1234
writeMem(memory, 0x0000, listOf(0x7C, 0xCD, 0xAB))
writeMem(memory, 0xABCF, listOf(0x34, 0x12))
mpu.step()
assertEquals(0x1234, mpu.PC)
assertEquals(6, mpu.totalCycles)
}
// LDA Zero Page, Indirect
@Test
fun test_lda_zp_ind_loads_a_sets_n_flag() {
mpu.A = 0x00
// $0000 LDA ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0xB2, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x80
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x80, mpu.A)
assertTrue(mpu.Status.N)
assertFalse(mpu.Status.Z)
}
@Test
fun test_lda_zp_ind_loads_a_sets_z_flag() {
mpu.A = 0x00
// $0000 LDA ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0xB2, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x00, mpu.A)
assertTrue(mpu.Status.Z)
assertFalse(mpu.Status.N)
}
// ORA Zero Page, Indirect
@Test
fun test_ora_zp_ind_zeroes_or_zeros_sets_z_flag() {
mpu.Status.Z = false
mpu.A = 0x00
mpu.Y = 0x12 // These should not affect the ORA
mpu.X = 0x34
// $0000 ORA ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x12, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x00, mpu.A)
assertTrue(mpu.Status.Z)
}
@Test
fun test_ora_zp_ind_turns_bits_on_sets_n_flag() {
mpu.Status.N = false
mpu.A = 0x03
// $0000 ORA ($0010)
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x12, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x82
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x83, mpu.A)
assertTrue(mpu.Status.N)
assertFalse(mpu.Status.Z)
}
// PHX
@Test
fun test_phx_pushes_x_and_updates_sp() {
mpu.X = 0xAB
// $0000 PHX
memory[0x0000] = 0xDA
mpu.step()
assertEquals(0x0001, mpu.PC)
assertEquals(0xAB, mpu.X)
assertEquals(0xAB, memory[0x01FF])
assertEquals(0xFE, mpu.SP)
assertEquals(3, mpu.totalCycles)
}
// PHY
@Test
fun test_phy_pushes_y_and_updates_sp() {
mpu.Y = 0xAB
// $0000 PHY
memory[0x0000] = 0x5A
mpu.step()
assertEquals(0x0001, mpu.PC)
assertEquals(0xAB, mpu.Y)
assertEquals(0xAB, memory[0x01FF])
assertEquals(0xFE, mpu.SP)
assertEquals(3, mpu.totalCycles)
}
// PLX
@Test
fun test_plx_pulls_top_byte_from_stack_into_x_and_updates_sp() {
// $0000 PLX
memory[0x0000] = 0xFA
memory[0x01FF] = 0xAB
mpu.SP = 0xFE
mpu.step()
assertEquals(0x0001, mpu.PC)
assertEquals(0xAB, mpu.X)
assertEquals(0xFF, mpu.SP)
assertEquals(4, mpu.totalCycles)
}
// PLY
@Test
fun test_ply_pulls_top_byte_from_stack_into_y_and_updates_sp() {
// $0000 PLY
memory[0x0000] = 0x7A
memory[0x01FF] = 0xAB
mpu.SP = 0xFE
mpu.step()
assertEquals(0x0001, mpu.PC)
assertEquals(0xAB, mpu.Y)
assertEquals(0xFF, mpu.SP)
assertEquals(4, mpu.totalCycles)
}
// RMB0
@Test
fun test_rmb0_clears_bit_0_without_affecting_other_bits() {
memory[0x0043] = 0b11111111
// $0000 RMB0 $43
writeMem(memory, 0x0000, listOf(0x07, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b11111110
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_rmb0_does_not_affect_status_register() {
memory[0x0043] = 0b11111111
// $0000 RMB0 $43
writeMem(memory, 0x0000, listOf(0x07, 0x43))
val expected = 0b01010101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// RMB1
@Test
fun test_rmb1_clears_bit_1_without_affecting_other_bits() {
memory[0x0043] = 0b11111111
// $0000 RMB1 $43
writeMem(memory, 0x0000, listOf(0x17, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b11111101
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_rmb1_does_not_affect_status_register() {
memory[0x0043] = 0b11111111
// $0000 RMB1 $43
writeMem(memory, 0x0000, listOf(0x17, 0x43))
val expected = 0b01010101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// RMB2
@Test
fun test_rmb2_clears_bit_2_without_affecting_other_bits() {
memory[0x0043] = 0b11111111
// $0000 RMB2 $43
writeMem(memory, 0x0000, listOf(0x27, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b11111011
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_rmb2_does_not_affect_status_register() {
memory[0x0043] = 0b11111111
// $0000 RMB2 $43
writeMem(memory, 0x0000, listOf(0x27, 0x43))
val expected = 0b01010101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// RMB3
@Test
fun test_rmb3_clears_bit_3_without_affecting_other_bits() {
memory[0x0043] = 0b11111111
// $0000 RMB3 $43
writeMem(memory, 0x0000, listOf(0x37, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b11110111
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_rmb3_does_not_affect_status_register() {
memory[0x0043] = 0b11111111
// $0000 RMB3 $43
writeMem(memory, 0x0000, listOf(0x37, 0x43))
val expected = 0b01010101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// RMB4
@Test
fun test_rmb4_clears_bit_4_without_affecting_other_bits() {
memory[0x0043] = 0b11111111
// $0000 RMB4 $43
writeMem(memory, 0x0000, listOf(0x47, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b11101111
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_rmb4_does_not_affect_status_register() {
memory[0x0043] = 0b11111111
// $0000 RMB4 $43
writeMem(memory, 0x0000, listOf(0x47, 0x43))
val expected = 0b01010101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// RMB5
@Test
fun test_rmb5_clears_bit_5_without_affecting_other_bits() {
memory[0x0043] = 0b11111111
// $0000 RMB5 $43
writeMem(memory, 0x0000, listOf(0x57, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b11011111
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_rmb5_does_not_affect_status_register() {
memory[0x0043] = 0b11111111
// $0000 RMB5 $43
writeMem(memory, 0x0000, listOf(0x57, 0x43))
val expected = 0b01010101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// RMB6
@Test
fun test_rmb6_clears_bit_6_without_affecting_other_bits() {
memory[0x0043] = 0b11111111
// $0000 RMB6 $43
writeMem(memory, 0x0000, listOf(0x67, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b10111111
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_rmb6_does_not_affect_status_register() {
memory[0x0043] = 0b11111111
// $0000 RMB6 $43
writeMem(memory, 0x0000, listOf(0x67, 0x43))
val expected = 0b01010101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// RMB7
@Test
fun test_rmb7_clears_bit_7_without_affecting_other_bits() {
memory[0x0043] = 0b11111111
// $0000 RMB7 $43
writeMem(memory, 0x0000, listOf(0x77, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b01111111
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_rmb7_does_not_affect_status_register() {
memory[0x0043] = 0b11111111
// $0000 RMB7 $43
writeMem(memory, 0x0000, listOf(0x77, 0x43))
val expected = 0b01010101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// STA Zero Page, Indirect
@Test
fun test_sta_zp_ind_stores_a_leaves_a_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.Status.fromByte(flags)
mpu.A = 0xFF
// $0000 STA ($0010)
// $0010 Vector to $FEED
writeMem(memory, 0x0000, listOf(0x92, 0x10))
writeMem(memory, 0x0010, listOf(0xED, 0xFE))
memory[0xFEED] = 0x00
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0xFF, memory[0xFEED])
assertEquals(0xFF, mpu.A)
assertEquals(flags, mpu.Status.asByte().toInt())
}
@Test
fun test_sta_zp_ind_stores_a_leaves_a_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.Status.fromByte(flags)
mpu.A = 0x00
// $0000 STA ($0010)
// $0010 Vector to $FEED
writeMem(memory, 0x0000, listOf(0x92, 0x10))
writeMem(memory, 0x0010, listOf(0xED, 0xFE))
memory[0xFEED] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x00, memory[0xFEED])
assertEquals(0x00, mpu.A)
assertEquals(flags, mpu.Status.asByte().toInt())
}
// SMB0
@Test
fun test_smb0_sets_bit_0_without_affecting_other_bits() {
memory[0x0043] = 0b00000000
// $0000 SMB0 $43
writeMem(memory, 0x0000, listOf(0x87, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b00000001
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_smb0_does_not_affect_status_register() {
memory[0x0043] = 0b00000000
// $0000 SMB0 $43
writeMem(memory, 0x0000, listOf(0x87, 0x43))
val expected = 0b11001100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// SMB1
@Test
fun test_smb1_sets_bit_1_without_affecting_other_bits() {
memory[0x0043] = 0b00000000
// $0000 SMB1 $43
writeMem(memory, 0x0000, listOf(0x97, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b00000010
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_smb1_does_not_affect_status_register() {
memory[0x0043] = 0b00000000
// $0000 SMB1 $43
writeMem(memory, 0x0000, listOf(0x97, 0x43))
val expected = 0b11001100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// SMB2
@Test
fun test_smb2_sets_bit_2_without_affecting_other_bits() {
memory[0x0043] = 0b00000000
// $0000 SMB2 $43
writeMem(memory, 0x0000, listOf(0xA7, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b00000100
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_smb2_does_not_affect_status_register() {
memory[0x0043] = 0b00000000
// $0000 SMB2 $43
writeMem(memory, 0x0000, listOf(0xA7, 0x43))
val expected = 0b11001100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// SMB3
@Test
fun test_smb3_sets_bit_3_without_affecting_other_bits() {
memory[0x0043] = 0b00000000
// $0000 SMB3 $43
writeMem(memory, 0x0000, listOf(0xB7, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b00001000
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_smb3_does_not_affect_status_register() {
memory[0x0043] = 0b00000000
// $0000 SMB3 $43
writeMem(memory, 0x0000, listOf(0xB7, 0x43))
val expected = 0b11001100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// SMB4
@Test
fun test_smb4_sets_bit_4_without_affecting_other_bits() {
memory[0x0043] = 0b00000000
// $0000 SMB4 $43
writeMem(memory, 0x0000, listOf(0xC7, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b00010000
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_smb4_does_not_affect_status_register() {
memory[0x0043] = 0b00000000
// $0000 SMB4 $43
writeMem(memory, 0x0000, listOf(0xC7, 0x43))
val expected = 0b11001100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// SMB5
@Test
fun test_smb5_sets_bit_5_without_affecting_other_bits() {
memory[0x0043] = 0b00000000
// $0000 SMB5 $43
writeMem(memory, 0x0000, listOf(0xD7, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b00100000
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_smb5_does_not_affect_status_register() {
memory[0x0043] = 0b00000000
// $0000 SMB5 $43
writeMem(memory, 0x0000, listOf(0xD7, 0x43))
val expected = 0b11001100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// SMB6
@Test
fun test_smb6_sets_bit_6_without_affecting_other_bits() {
memory[0x0043] = 0b00000000
// $0000 SMB6 $43
writeMem(memory, 0x0000, listOf(0xE7, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b01000000
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_smb6_does_not_affect_status_register() {
memory[0x0043] = 0b00000000
// $0000 SMB6 $43
writeMem(memory, 0x0000, listOf(0xE7, 0x43))
val expected = 0b11001100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// SMB7
@Test
fun test_smb7_sets_bit_7_without_affecting_other_bits() {
memory[0x0043] = 0b00000000
// $0000 SMB7 $43
writeMem(memory, 0x0000, listOf(0xF7, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
val expected = 0b10000000
assertEquals(expected, memory[0x0043].toInt())
}
@Test
fun test_smb7_does_not_affect_status_register() {
memory[0x0043] = 0b00000000
// $0000 SMB7 $43
writeMem(memory, 0x0000, listOf(0xF7, 0x43))
val expected = 0b11001100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
}
// SBC Zero Page, Indirect
@Test
fun test_sbc_zp_ind_all_zeros_and_no_borrow_is_zero() {
mpu.Status.D = false
mpu.Status.C = true // borrow = 0
mpu.A = 0x00
// $0000 SBC ($10)
// $0010 Vector to $FEED
writeMem(memory, 0x0000, listOf(0xF2, 0x10))
writeMem(memory, 0x0010, listOf(0xED, 0xFE))
memory[0xFEED] = 0x00
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x00, mpu.A)
assertFalse(mpu.Status.N)
assertTrue(mpu.Status.C)
assertTrue(mpu.Status.Z)
}
@Test
fun test_sbc_zp_ind_downto_zero_no_borrow_sets_z_clears_n() {
mpu.Status.D = false
mpu.Status.C = true // borrow = 0
mpu.A = 0x01
// $0000 SBC ($10)
// $0010 Vector to $FEED
writeMem(memory, 0x0000, listOf(0xF2, 0x10))
writeMem(memory, 0x0010, listOf(0xED, 0xFE))
memory[0xFEED] = 0x01
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x00, mpu.A)
assertFalse(mpu.Status.N)
assertTrue(mpu.Status.C)
assertTrue(mpu.Status.Z)
}
@Test
fun test_sbc_zp_ind_downto_zero_with_borrow_sets_z_clears_n() {
mpu.Status.D = false
mpu.Status.C = false // borrow = 1
mpu.A = 0x01
// $0000 SBC ($10)
// $0010 Vector to $FEED
writeMem(memory, 0x0000, listOf(0xF2, 0x10))
writeMem(memory, 0x0010, listOf(0xED, 0xFE))
memory[0xFEED] = 0x00
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x00, mpu.A)
assertFalse(mpu.Status.N)
assertTrue(mpu.Status.C)
assertTrue(mpu.Status.Z)
}
@Test
fun test_sbc_zp_ind_downto_four_with_borrow_clears_z_n() {
mpu.Status.D = false
mpu.Status.C = false // borrow = 1
mpu.A = 0x07
// $0000 SBC ($10)
// $0010 Vector to $FEED
writeMem(memory, 0x0000, listOf(0xF2, 0x10))
writeMem(memory, 0x0010, listOf(0xED, 0xFE))
memory[0xFEED] = 0x02
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
assertEquals(0x04, mpu.A)
assertFalse(mpu.Status.N)
assertFalse(mpu.Status.Z)
assertTrue(mpu.Status.C)
}
// STZ Zero Page
@Test
fun test_stz_zp_stores_zero() {
memory[0x0032] = 0x88
// #0000 STZ $32
memory[0x0000] = 0x64
memory[0x0001] = 0x32
assertEquals(0x88, memory[0x0032])
mpu.step()
assertEquals(0x00, memory[0x0032])
assertEquals(0x0002, mpu.PC)
assertEquals(3, mpu.totalCycles)
}
// STZ Zero Page, X-Indexed
@Test
fun test_stz_zp_x_stores_zero() {
memory[0x0032] = 0x88
// $0000 STZ $32,X
memory[0x0000] = 0x74
memory[0x0001] = 0x32
assertEquals(0x88, memory[0x0032])
mpu.step()
assertEquals(0x00, memory[0x0032])
assertEquals(0x0002, mpu.PC)
assertEquals(4, mpu.totalCycles)
}
// STZ Absolute
@Test
fun test_stz_abs_stores_zero() {
memory[0xFEED] = 0x88
// $0000 STZ $FEED
writeMem(memory, 0x0000, listOf(0x9C, 0xED, 0xFE))
assertEquals(0x88, memory[0xFEED])
mpu.step()
assertEquals(0x00, memory[0xFEED])
assertEquals(0x0003, mpu.PC)
assertEquals(4, mpu.totalCycles)
}
// STZ Absolute, X-Indexed
@Test
fun test_stz_abs_x_stores_zero() {
memory[0xFEED] = 0x88
mpu.X = 0x0D
// $0000 STZ $FEE0,X
writeMem(memory, 0x0000, listOf(0x9E, 0xE0, 0xFE))
assertEquals(0x88, memory[0xFEED])
assertEquals(0x0D, mpu.X)
mpu.step()
assertEquals(0x00, memory[0xFEED])
assertEquals(0x0003, mpu.PC)
assertEquals(5, mpu.totalCycles)
}
// TSB Zero Page
@Test
fun test_tsb_zp_ones() {
memory[0x00BB] = 0xE0
// $0000 TSB $BD
writeMem(memory, 0x0000, listOf(0x04, 0xBB))
mpu.A = 0x70
assertEquals(0xE0, memory[0x00BB])
mpu.step()
assertEquals(0xF0, memory[0x00BB])
assertFalse(mpu.Status.Z)
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
}
@Test
fun test_tsb_zp_zeros() {
memory[0x00BB] = 0x80
// $0000 TSB $BD
writeMem(memory, 0x0000, listOf(0x04, 0xBB))
mpu.A = 0x60
assertEquals(0x80, memory[0x00BB])
mpu.step()
assertEquals(0xE0, memory[0x00BB])
assertTrue(mpu.Status.Z)
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
}
// TSB Absolute
@Test
fun test_tsb_abs_ones() {
memory[0xFEED] = 0xE0
// $0000 TSB $FEED
writeMem(memory, 0x0000, listOf(0x0C, 0xED, 0xFE))
mpu.A = 0x70
assertEquals(0xE0, memory[0xFEED])
mpu.step()
assertEquals(0xF0, memory[0xFEED])
assertFalse(mpu.Status.Z)
assertEquals(0x0003, mpu.PC)
assertEquals(6, mpu.totalCycles)
}
@Test
fun test_tsb_abs_zeros() {
memory[0xFEED] = 0x80
// $0000 TSB $FEED
writeMem(memory, 0x0000, listOf(0x0C, 0xED, 0xFE))
mpu.A = 0x60
assertEquals(0x80, memory[0xFEED])
mpu.step()
assertEquals(0xE0, memory[0xFEED])
assertTrue(mpu.Status.Z)
assertEquals(0x0003, mpu.PC)
assertEquals(6, mpu.totalCycles)
}
// TRB Zero Page
@Test
fun test_trb_zp_ones() {
memory[0x00BB] = 0xE0
// $0000 TRB $BD
writeMem(memory, 0x0000, listOf(0x14, 0xBB))
mpu.A = 0x70
assertEquals(0xE0, memory[0x00BB])
mpu.step()
assertEquals(0x80, memory[0x00BB])
assertFalse(mpu.Status.Z)
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
}
@Test
fun test_trb_zp_zeros() {
memory[0x00BB] = 0x80
// $0000 TRB $BD
writeMem(memory, 0x0000, listOf(0x14, 0xBB))
mpu.A = 0x60
assertEquals(0x80, memory[0x00BB])
mpu.step()
assertEquals(0x80, memory[0x00BB])
assertTrue(mpu.Status.Z)
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles)
}
// TRB Absolute
@Test
fun test_trb_abs_ones() {
memory[0xFEED] = 0xE0
// $0000 TRB $FEED
writeMem(memory, 0x0000, listOf(0x1C, 0xED, 0xFE))
mpu.A = 0x70
assertEquals(0xE0, memory[0xFEED])
mpu.step()
assertEquals(0x80, memory[0xFEED])
assertFalse(mpu.Status.Z)
assertEquals(0x0003, mpu.PC)
assertEquals(6, mpu.totalCycles)
}
@Test
fun test_trb_abs_zeros() {
memory[0xFEED] = 0x80
// $0000 TRB $FEED
writeMem(memory, 0x0000, listOf(0x1C, 0xED, 0xFE))
mpu.A = 0x60
assertEquals(0x80, memory[0xFEED])
mpu.step()
assertEquals(0x80, memory[0xFEED])
assertTrue(mpu.Status.Z)
assertEquals(0x0003, mpu.PC)
assertEquals(6, mpu.totalCycles)
}
@Test
fun test_dec_a_decreases_a() {
// $0000 DEC A
memory[0x0000] = 0x3a
mpu.A = 0x48
mpu.step()
assertFalse(mpu.Status.Z)
assertFalse(mpu.Status.N)
assertEquals(0x47, mpu.A)
}
@Test
fun test_dec_a_sets_zero_flag() {
// $0000 DEC A
memory[0x0000] = 0x3a
mpu.A = 0x01
mpu.step()
assertTrue(mpu.Status.Z)
assertFalse(mpu.Status.N)
assertEquals(0x00, mpu.A)
}
@Test
fun test_dec_a_wraps_at_zero() {
// $0000 DEC A
memory[0x0000] = 0x3a
mpu.A = 0x00
mpu.step()
assertFalse(mpu.Status.Z)
assertTrue(mpu.Status.N)
assertEquals(0xFF, mpu.A)
}
@Test
fun test_bra_forward() {
// $0000 BRA $10
writeMem(memory, 0x0000, listOf(0x80, 0x10))
mpu.step()
assertEquals(0x12, mpu.PC)
assertEquals(2, mpu.totalCycles)
}
@Test
fun test_bra_backward() {
// $0240 BRA $F0
writeMem(memory, 0x0000, listOf(0x80, 0xF0))
mpu.PC = 0x0204
mpu.step()
assertEquals(0x1F6, mpu.PC)
assertEquals(3, mpu.totalCycles) // Crossed boundry
}
// WAI
@Test
fun test_wai_sets_waiting() {
assertFalse(mpu.waiting)
// $0240 WAI
memory[0x0204] = 0xcb
mpu.PC = 0x0204
mpu.step()
assertTrue(mpu.waiting)
assertEquals(0x0205, mpu.PC)
assertEquals(3, mpu.totalCycles)
}
}