public void TestStepNonMaskableInterrupt(bool initialIFF1, bool initialIFF2) { var initialState = new CPUConfig() { InterruptsEnabled = initialIFF1, InterruptsEnabledPreviousValue = initialIFF2, Registers = new CPURegisters() { PC = 0x1234, SP = 0x3FFF, }, }; var cpu = new CPU(initialState); var cycles = cpu.StepNonMaskableInterrupt(); Assert.Equal(17, cycles); // We should've jumped to 0x0066. Assert.Equal(0x0066, cpu.Registers.PC); // Interrupts should be disabled (IFF1). Assert.False(cpu.InterruptsEnabled); // The previous value of IFF1 should have been preserved in IFF2. Assert.Equal(initialIFF1, cpu.InterruptsEnabledPreviousValue); // Ensure the previous program counter value was pushed onto the stack. Assert.Equal(0x3FFD, cpu.Registers.SP); Assert.Equal(0x12, cpu.Memory.Read(0x3FFE)); Assert.Equal(0x34, cpu.Memory.Read(0x3FFD)); }
public void Test_LD_MRR_N_ToMemory() { var rom = AssembleSource($@" org 00h LD (HL), 42h HALT "); var registers = new CPURegisters(); registers[Register.H] = 0x22; registers[Register.L] = 0x33; var initialState = new CPUConfig() { Registers = registers, }; var state = Execute(rom, initialState); Assert.Equal(0x42, state.Memory[0x2233]); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 10, state.Cycles); Assert.Equal(0x02, state.Registers.PC); }
public void Test_IN_A_MN_DoesNotThrowExceptionIfNoHandlersPresent() { var rom = AssembleSource($@" org 00h IN A, (2) HALT "); var initialState = new CPUConfig(); initialState.Registers = new CPURegisters() { A = 0x11, }; var cpu = new CPU(initialState); var state = Execute(rom, cpu); Assert.Equal(0x00, state.Registers.A); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 10, state.Cycles); Assert.Equal(0x02, state.Registers.PC); }
public void Test_INC_MIY_NoFlags(int offset) { var rom = AssembleSource($@" org 00h INC (IY {(offset < 0 ? '-' : '+')} {Math.Abs(offset)}) HALT "); var registers = new CPURegisters() { IY = 0x2477, }; var memory = new byte[16384]; memory[0x2477 + offset] = 0x42; var initialState = new CPUConfig() { Registers = registers, Flags = new ConditionFlags() { Subtract = true, }, }; var state = Execute(rom, memory, initialState); Assert.Equal(0x43, state.Memory[0x2477 + offset]); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 23, state.Cycles); Assert.Equal(0x03, state.Registers.PC); }
public void Test_ADD_A_N_OverflowFlag() { var rom = AssembleSource($@" org 00h ADD A, 2 HALT "); var initialState = new CPUConfig() { Registers = new CPURegisters() { A = 127, }, }; var state = Execute(rom, initialState); Assert.Equal(129, state.Registers.A); Assert.True(state.Flags.Sign); Assert.False(state.Flags.Zero); Assert.True(state.Flags.HalfCarry); Assert.True(state.Flags.ParityOverflow); Assert.False(state.Flags.Subtract); Assert.False(state.Flags.Carry); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 7, state.Cycles); Assert.Equal(0x02, state.Registers.PC); }
public void Test_IN_R_MC_DoesNotThrowExceptionIfNoHandlersPresent() { var rom = AssembleSource($@" org 00h IN B, (C) HALT "); var initialState = new CPUConfig(); initialState.Registers = new CPURegisters(); initialState.Registers.C = 123; initialState.Registers.B = 44; var cpu = new CPU(initialState); var state = Execute(rom, cpu); Assert.Equal(0, state.Registers.B); Assert.False(state.Flags.Sign); Assert.True(state.Flags.Zero); Assert.True(state.Flags.ParityOverflow); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 12, state.Cycles); Assert.Equal(0x02, state.Registers.PC); }
public void Test_DJNZ() { var rom = AssembleSource($@" org 00h NOP ; $0000 NOP ; $0001 DJNZ $+5 ; $0002 NOP ; $0004 HALT ; $0005 HALT ; $0006 NOP ; $0007 JP $0002 ; $0008 HALT ; $0009 HALT ; $000A "); var initialState = new CPUConfig() { Registers = new CPURegisters() { B = 4, }, }; var state = Execute(rom, initialState); Assert.Equal(0x0000, state.Registers.SP); AssertFlagsFalse(state); Assert.Equal(14, state.Iterations); Assert.Equal(4 + (4 * 6) + (13 * 3) + (10 * 3) + 8, state.Cycles); Assert.Equal(0x0005, state.Registers.PC); }
public void Test_JP_NC_Jumps() { var rom = AssembleSource($@" org 00h NOP ; $0000 NOP ; $0001 JP NC, 000Ah; $0002 HALT ; $0005 NOP ; $0006 NOP ; $0007 NOP ; $0008 NOP ; $0009 HALT ; $000A "); var initialState = new CPUConfig() { Flags = new ConditionFlags() { Carry = false, }, }; var state = Execute(rom, initialState); Assert.Equal(0x0000, state.Registers.SP); AssertFlagsSame(initialState, state); Assert.Equal(4, state.Iterations); Assert.Equal(4 + (4 * 2) + 10, state.Cycles); Assert.Equal(0x000A, state.Registers.PC); }
public void Test_LD_SP_HL() { var rom = AssembleSource($@" org 00h LD SP, HL HALT "); var initialState = new CPUConfig() { Registers = new CPURegisters() { HL = 0x2477, }, }; var state = Execute(rom, initialState); AssertFlagsFalse(state); Assert.Equal(0x2477, state.Registers.SP); Assert.Equal(0x2477, state.Registers.HL); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 6, state.Cycles); Assert.Equal(0x0001, state.Registers.PC); }
public void Test_PUSH_IY() { var rom = AssembleSource($@" org 00h PUSH IY HALT "); var initialState = new CPUConfig() { Registers = new CPURegisters() { SP = 0x3000, IY = 0x2477, }, }; var state = Execute(rom, initialState); Assert.Equal(0x2477, state.Registers.IY); Assert.Equal(0x00, state.Memory[0x3000]); Assert.Equal(0x24, state.Memory[0x2FFF]); Assert.Equal(0x77, state.Memory[0x2FFE]); Assert.Equal(0x2FFE, state.Registers.SP); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 15, state.Cycles); Assert.Equal(0x02, state.Registers.PC); }
public void TestXCHG() { var rom = AssembleSource($@" org 00h EX DE, HL HALT "); var initialState = new CPUConfig() { Registers = new CPURegisters() { H = 0x42, D = 0x99, L = 0x77, E = 0x88, }, }; var state = Execute(rom, initialState); Assert.Equal(0x99, state.Registers.H); Assert.Equal(0x42, state.Registers.D); Assert.Equal(0x88, state.Registers.L); Assert.Equal(0x77, state.Registers.E); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 4, state.Cycles); Assert.Equal(0x01, state.Registers.PC); }
public void Test_LD_HL_MNN() { var rom = AssembleSource($@" org 00h LD HL, (2477h) HALT "); var memory = new byte[16384]; memory[0x2477] = 0x77; memory[0x2478] = 0x66; var initialState = new CPUConfig() { }; var state = Execute(rom, memory, initialState); Assert.Equal(0x66, state.Registers.H); Assert.Equal(0x77, state.Registers.L); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 16, state.Cycles); Assert.Equal(0x03, state.Registers.PC); }
public void TestArithmeticAdditionSetsFlags(string valueA, string valueB, int expectedRegValue, int expectedRegSignedValue, ConditionFlags expected) { var rom = AssembleSource($@" org 00h LD A, {valueA} LD B, {valueB} ADD B HALT "); var initialState = new CPUConfig() { Flags = new ConditionFlags() { Sign = !expected.Sign, Zero = !expected.Zero, HalfCarry = !expected.HalfCarry, ParityOverflow = !expected.ParityOverflow, Subtract = !expected.Subtract, Carry = !expected.Carry, }, }; var state = Execute(rom, initialState); Assert.Equal(expectedRegValue, state.Registers.A); Assert.Equal(expectedRegSignedValue, (sbyte)state.Registers.A); Assert.Equal(expected.Sign, state.Flags.Sign); Assert.Equal(expected.Zero, state.Flags.Zero); Assert.Equal(expected.HalfCarry, state.Flags.HalfCarry); Assert.Equal(expected.ParityOverflow, state.Flags.ParityOverflow); Assert.Equal(expected.Subtract, state.Flags.Subtract); Assert.Equal(expected.Carry, state.Flags.Carry); }
public void TestStepMaskableInterrupt_Mode1() { var initialState = new CPUConfig() { InterruptsEnabled = true, InterruptMode = InterruptMode.One, Registers = new CPURegisters() { PC = 0x1234, SP = 0x3FFF, }, }; var cpu = new CPU(initialState); var cycles = cpu.StepMaskableInterrupt(0x00); Assert.Equal(11, cycles); // Interrupts should still be enabled (IFF1). Assert.True(cpu.InterruptsEnabled); // We should've jumped here. Assert.Equal(0x0038, cpu.Registers.PC); // Ensure the previous program counter value was pushed onto the stack. Assert.Equal(0x3FFD, cpu.Registers.SP); Assert.Equal(0x12, cpu.Memory.Read(0x3FFE)); Assert.Equal(0x34, cpu.Memory.Read(0x3FFD)); }
public void Test_LD_MNN_HL() { // We have to assemble by hand here since LD (**), HL is a duplicate instruction // and the assembler will use the standard instruction instead of the undocumented // extended instruction. var rom = new byte[] { 0xED, 0x63, // LD (NN), HL 0x77, 0x24, // (2477h) 0x76 // HALT }; var memory = new byte[20490]; var initialState = new CPUConfig() { Registers = new CPURegisters() { HL = 0x6677, }, }; var state = Execute(rom, memory, initialState); Assert.Equal(0x77, state.Memory[0x2477]); Assert.Equal(0x66, state.Memory[0x2478]); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 20, state.Cycles); Assert.Equal(0x04, state.Registers.PC); }
public void Test_ADC_A_N_NoFlags() { var rom = AssembleSource($@" org 00h ADC A, 18h HALT "); var initialState = new CPUConfig() { Registers = new CPURegisters() { A = 0x42, }, Flags = new ConditionFlags() { Carry = true, // Ensure this is flipped to zero because this was an addition. Subtract = true, }, }; var state = Execute(rom, initialState); Assert.Equal(0x5B, state.Registers.A); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 7, state.Cycles); Assert.Equal(0x02, state.Registers.PC); }
public void Test_LD_MNN_RR(RegisterPair registerPair) { var rom = AssembleSource($@" org 00h LD (2477h), {registerPair} HALT "); var memory = new byte[20490]; var initialState = new CPUConfig(); initialState.Registers[registerPair] = 0x6677; var state = Execute(rom, memory, initialState); Assert.Equal(0x77, state.Memory[0x2477]); Assert.Equal(0x66, state.Memory[0x2478]); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 20, state.Cycles); Assert.Equal(0x04, state.Registers.PC); }
public void Test_DI() { var rom = AssembleSource($@" org 00h DI HALT "); var initialState = new CPUConfig() { InterruptsEnabled = true, InterruptsEnabledPreviousValue = true, }; var state = Execute(rom, initialState); Assert.False(state.InterruptsEnabled); Assert.False(state.InterruptsEnabledPreviousValue); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 4, state.Cycles); Assert.Equal(0x01, state.Registers.PC); }
public void Test_IN_R_MC_SetsFlags() { var rom = AssembleSource($@" org 00h IN (C) HALT "); var initialState = new CPUConfig(); initialState.Registers = new CPURegisters(); initialState.Registers.C = 77; var cpu = new CPU(initialState); var actualDeviceId = -1; cpu.OnDeviceRead += (int deviceID) => { actualDeviceId = deviceID; return(213); }; var state = Execute(rom, cpu); Assert.Equal(77, state.Registers.C); Assert.Equal(77, actualDeviceId); Assert.True(state.Flags.Sign); Assert.False(state.Flags.Zero); Assert.False(state.Flags.ParityOverflow); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 12, state.Cycles); Assert.Equal(0x02, state.Registers.PC); }
public void Test_OR_A_NoFlags() { var rom = AssembleSource($@" org 00h OR A HALT "); var registers = new CPURegisters(); registers.A = 0b01100100; var initialState = new CPUConfig() { Registers = registers, }; var state = Execute(rom, initialState); Assert.Equal(0b01100100, state.Registers.A); Assert.False(state.Flags.Sign); Assert.False(state.Flags.Zero); Assert.False(state.Flags.HalfCarry); Assert.False(state.Flags.ParityOverflow); Assert.False(state.Flags.Subtract); Assert.False(state.Flags.Carry); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 4, state.Cycles); Assert.Equal(0x01, state.Registers.PC); }
public void Test_JP_HL() { var rom = AssembleSource($@" org 00h JP (HL) ; $0000 NOP ; $0001 NOP ; $0002 HALT ; $0003 "); var initialState = new CPUConfig() { Registers = new CPURegisters() { HL = 0x003, }, }; var state = Execute(rom, initialState); AssertFlagsSame(initialState, state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 4, state.Cycles); Assert.Equal(0x0003, state.Registers.PC); }
public void Test_ADD_A_MIY_ExampleFromManual() { var rom = AssembleSource($@" org 00h ADD A, (IY + 5h) HALT "); var memory = new byte[16 * 1024]; memory[0x1005] = 0x22; var initialState = new CPUConfig() { Registers = new CPURegisters() { A = 0x11, IY = 0x1000, }, }; var state = Execute(rom, memory, initialState); Assert.Equal(0x33, state.Registers.A); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 19, state.Cycles); Assert.Equal(0x03, state.Registers.PC); }
public void Test_EX_MSP_IY() { var rom = AssembleSource($@" org 00h EX (SP), IY HALT "); var memory = new byte[16384]; memory[0x2222] = 0x99; memory[0x2223] = 0x88; var initialState = new CPUConfig() { Registers = new CPURegisters() { IY = 0x4277, SP = 0x2222, }, }; var state = Execute(rom, memory, initialState); Assert.Equal(0x8899, state.Registers.IY); Assert.Equal(0x77, state.Memory[0x2222]); Assert.Equal(0x42, state.Memory[0x2223]); Assert.Equal(0x2222, state.Registers.SP); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 23, state.Cycles); Assert.Equal(0x02, state.Registers.PC); }
public void Test_IM(int modeNumber, InterruptMode mode) { var rom = AssembleSource($@" org 00h IM {modeNumber} HALT "); var initialState = new CPUConfig() { InterruptsEnabled = false, InterruptsEnabledPreviousValue = false, }; var cpu = new CPU(initialState); var state = Execute(rom, cpu); // Ensure the mode was set. Assert.Equal(mode, cpu.InterruptMode); // Setting mode does not enable interrupts. Assert.False(cpu.InterruptsEnabled); Assert.False(cpu.InterruptsEnabledPreviousValue); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 8, state.Cycles); Assert.Equal(0x02, state.Registers.PC); }
public void Test_SUB_N_SignFlag() { var rom = AssembleSource($@" org 00h SUB 16h HALT "); var initialState = new CPUConfig() { Registers = new CPURegisters() { A = 0xFF, }, Flags = new ConditionFlags() { Subtract = false, }, }; var state = Execute(rom, initialState); Assert.Equal(0xE9, state.Registers.A); Assert.True(state.Flags.Sign); Assert.False(state.Flags.Zero); Assert.False(state.Flags.HalfCarry); Assert.False(state.Flags.ParityOverflow); Assert.True(state.Flags.Subtract); Assert.False(state.Flags.Carry); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 7, state.Cycles); Assert.Equal(0x02, state.Registers.PC); }
// [InlineData(Register.R, Register.A)] // TODO: Make specific tests for R register since it's special // [InlineData(Register.A, Register.R)] public void Test_LD(Register destReg, Register sourceReg) { var rom = AssembleSource($@" org 00h LD {destReg}, {sourceReg} HALT "); var initialState = new CPUConfig() { Registers = new CPURegisters() { [sourceReg] = 0x42, [destReg] = 0x77, }, }; var state = Execute(rom, initialState); Assert.Equal(0x42, state.Registers[sourceReg]); Assert.Equal(0x42, state.Registers[destReg]); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 9, state.Cycles); Assert.Equal(0x02, state.Registers.PC); }
public void Test_SCF_SetsFalseToTrue() { var rom = AssembleSource($@" org 00h SCF HALT "); var initialState = new CPUConfig() { Flags = new ConditionFlags() { Carry = false, Subtract = true, HalfCarry = true, }, }; var state = Execute(rom, initialState); Assert.False(state.Flags.Sign); Assert.False(state.Flags.Zero); Assert.False(state.Flags.HalfCarry); Assert.False(state.Flags.ParityOverflow); Assert.False(state.Flags.Subtract); Assert.True(state.Flags.Carry); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 4, state.Cycles); Assert.Equal(0x01, state.Registers.PC); }
public void Test_LD_MNN_A() { var rom = AssembleSource($@" org 00h LD (2477h), A HALT "); var registers = new CPURegisters(); registers.A = 0x42; var initialState = new CPUConfig() { Registers = registers, }; var state = Execute(rom, initialState); Assert.Equal(0x42, state.Memory[0x2477]); Assert.Equal(0x42, state.Registers.A); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 13, state.Cycles); Assert.Equal(0x03, state.Registers.PC); }
public void Test_AND_ParityFlag(Register sourceReg) { var rom = AssembleSource($@" org 00h AND {sourceReg} HALT "); var registers = new CPURegisters(); registers.A = 0b11100101; registers[sourceReg] = 0b00101110; var initialState = new CPUConfig() { Registers = registers, }; var state = Execute(rom, initialState); Assert.Equal(0b00100100, state.Registers.A); Assert.Equal(0b00101110, state.Registers[sourceReg]); Assert.False(state.Flags.Sign); Assert.False(state.Flags.Zero); Assert.True(state.Flags.HalfCarry); Assert.True(state.Flags.ParityOverflow); Assert.False(state.Flags.Subtract); Assert.False(state.Flags.Carry); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 4, state.Cycles); Assert.Equal(0x01, state.Registers.PC); }
public void Test_LD_A_MRR(RegisterPair registerPair) { var rom = AssembleSource($@" org 00h LD A, ({registerPair}) HALT "); var registers = new CPURegisters(); registers[registerPair] = 0x2477; var memory = new byte[16384]; memory[0x2477] = 0x42; var initialState = new CPUConfig() { Registers = registers, }; var state = Execute(rom, memory, initialState); Assert.Equal(0x42, state.Memory[0x2477]); Assert.Equal(0x42, state.Registers.A); Assert.Equal(0x2477, state.Registers[registerPair]); AssertFlagsFalse(state); Assert.Equal(2, state.Iterations); Assert.Equal(4 + 7, state.Cycles); Assert.Equal(0x01, state.Registers.PC); }