diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index 1f6dd1c..7159174 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -391,6 +391,8 @@ namespace ComSquare::CPU int RTL(uint24_t, AddressingMode); //! @brief Compare Accumulator with Memory. int CMP(uint24_t, AddressingMode); + //! @brief Increment + int INC(uint24_t, AddressingMode); //! @brief All the instructions of the CPU. //! @info Instructions are indexed by their opcode @@ -421,7 +423,7 @@ namespace ComSquare::CPU {&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 17 {&CPU::CLC, 2, "clc", AddressingMode::Implied, 1}, // 18 {&CPU::ORA, 4, "ora", AddressingMode::AbsoluteIndexedByY, 3}, // 19 - {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // 1A + {&CPU::INC, 2, "inc", AddressingMode::Implied, 1}, // 1A {&CPU::BRK, 7, "tcs #-#", AddressingMode::Implied, 2}, // 1B {&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 1C {&CPU::ORA, 4, "ora", AddressingMode::AbsoluteIndexedByX, 3}, // 1D @@ -625,7 +627,7 @@ namespace ComSquare::CPU {&CPU::SBC, 4, "sbc", AddressingMode::StackRelative, 2}, // E3 {&CPU::CPX, 3, "cpx", AddressingMode::DirectPage, 2}, // E4 {&CPU::SBC, 3, "sbc", AddressingMode::DirectPage, 2}, // E5 - {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // E6 + {&CPU::INC, 5, "inc", AddressingMode::DirectPage, 2}, // E6 {&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectLong, 2}, // E7 {&CPU::INX, 2, "inx", AddressingMode::Implied, 1}, // E8 {&CPU::SBC, 2, "sbc", AddressingMode::ImmediateForA, 2}, // E9 @@ -633,7 +635,7 @@ namespace ComSquare::CPU {&CPU::BRK, 7, "xba #-#", AddressingMode::Implied, 2}, // EB {&CPU::CPX, 4, "cpx", AddressingMode::Absolute, 3}, // EC {&CPU::SBC, 4, "sbc", AddressingMode::Absolute, 3}, // ED - {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // EE + {&CPU::INC, 6, "inc", AddressingMode::Absolute, 3}, // EE {&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteLong, 4}, // EF {&CPU::BEQ, 2, "beq", AddressingMode::Implied, 2}, // F0 {&CPU::SBC, 5, "sbc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // F1 @@ -641,7 +643,7 @@ namespace ComSquare::CPU {&CPU::SBC, 7, "sbc", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // F3 {&CPU::BRK, 7, "pea #-#", AddressingMode::Implied, 2}, // F4 {&CPU::SBC, 4, "sbc", AddressingMode::DirectPageIndexedByX, 2}, // F5 - {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // F6 + {&CPU::INC, 6, "inc", AddressingMode::DirectPageIndexedByX, 2}, // F6 {&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // F7 {&CPU::SED, 2, "sed", AddressingMode::Implied, 1}, // F8 {&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByY, 3}, // F9 @@ -649,7 +651,7 @@ namespace ComSquare::CPU {&CPU::XCE, 2, "xce", AddressingMode::Implied, 1}, // FB {&CPU::JSR, 8, "jsr", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // FC {&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByX, 3}, // FD - {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // FE + {&CPU::INC, 7, "inc", AddressingMode::AbsoluteIndexedByX, 3}, // FE {&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteIndexedByXLong, 4}, // FF }; public: diff --git a/sources/CPU/Instructions/MathematicalOperations.cpp b/sources/CPU/Instructions/MathematicalOperations.cpp index 35af999..df64f01 100644 --- a/sources/CPU/Instructions/MathematicalOperations.cpp +++ b/sources/CPU/Instructions/MathematicalOperations.cpp @@ -254,7 +254,7 @@ namespace ComSquare::CPU int CPU::AND(uint24_t valueAddr, AddressingMode mode) { - unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u; + unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; unsigned value = this->_bus->read(valueAddr); if (!this->_registers.p.m) value += this->_bus->read(valueAddr + 1) << 8u; @@ -285,4 +285,44 @@ namespace ComSquare::CPU } return cycles; } + + int CPU::INC(uint24_t valueAddr, AddressingMode mode) + { + unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; + + unsigned result; + if (mode == Implied) { + this->_registers.a++; + if (this->_registers.p.m) + this->_registers.ah = 0; + result = this->_registers.a; + } else if (!this->_registers.p.m) { + result = this->_bus->read(valueAddr); + result += this->_bus->read(valueAddr + 1) << 8u; + result = (uint16_t)(result + 1); + this->_bus->write(valueAddr, result); + this->_bus->write(valueAddr + 1, result << 8u); + } else { + result = this->_bus->read(valueAddr); + result = (uint8_t)(result + 1); + this->_bus->write(valueAddr, result); + } + + this->_registers.p.z = result == 0; + this->_registers.p.n = result & negativeMask; + + switch (mode) { + case Implied: + return 0; + case Absolute: + return this->_registers.p.m == 0 ? 2 : 0; + case DirectPage: + case DirectPageIndexedByX: + return (this->_registers.p.m == 0 ? 2 : 0) + this->_registers.dl != 0 ; + case AbsoluteIndexedByX: + return (this->_registers.p.m == 0 ? 2 : 0) + this->_hasIndexCrossedPageBoundary; + default: + return 0; + } + } } \ No newline at end of file diff --git a/tests/CPU/Math/testOthersMath.cpp b/tests/CPU/Math/testOthersMath.cpp index 3a65f92..48364f2 100644 --- a/tests/CPU/Math/testOthersMath.cpp +++ b/tests/CPU/Math/testOthersMath.cpp @@ -152,4 +152,70 @@ Test(ORA, zero) cr_assert_eq(snes.cpu->_registers.a, 0x00, "The accumulator's value should be 0x00 but it was 0x%x.", snes.cpu->_registers.a); cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set."); +} + +Test(INC, simple) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.wram->_data[0] = 0x56; + snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Absolute); + cr_assert_eq(snes.wram->_data[0], 0x57, "The incremented value should be 0x57 but it was 0x%x.", snes.wram->_data[0]); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(INC, negative) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.wram->_data[0] = 0x7F; + snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Absolute); + cr_assert_eq(snes.wram->_data[0], 0x80, "The incremented value should be 0x80 but it was 0x%x.", snes.wram->_data[0]); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(INC, accumulator) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x56; + snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x57, "The incremented value should be 0x57 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(INC, negativeAccumulator) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x7F; + snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x80, "The incremented value should be 0x80 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(INC, nativeAccumulator) +{ + Init() + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0x5600; + snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x5601, "The incremented value should be 0x5601 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(INC, negativeNativeAccumulator) +{ + Init() + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0x8FFF; + snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x9000, "The incremented value should be 0x9000 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); } \ No newline at end of file