diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index 7159174..a478d35 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -393,6 +393,8 @@ namespace ComSquare::CPU int CMP(uint24_t, AddressingMode); //! @brief Increment int INC(uint24_t, AddressingMode); + //! @brief Decrement + int DEC(uint24_t, AddressingMode); //! @brief All the instructions of the CPU. //! @info Instructions are indexed by their opcode @@ -455,7 +457,7 @@ namespace ComSquare::CPU {&CPU::AND, 6, "and", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 37 {&CPU::SEC, 2, "sec", AddressingMode::Implied, 1}, // 38 {&CPU::AND, 4, "and", AddressingMode::AbsoluteIndexedByY, 3}, // 39 - {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // 3A + {&CPU::DEC, 2, "dec", AddressingMode::Implied, 1}, // 3A {&CPU::BRK, 7, "tsc #-#", AddressingMode::Implied, 2}, // 3B {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 3C {&CPU::AND, 4, "and", AddressingMode::AbsoluteIndexedByX, 3}, // 3D @@ -595,7 +597,7 @@ namespace ComSquare::CPU {&CPU::CMP, 4, "cmp", AddressingMode::StackRelative, 2}, // C3 {&CPU::CPY, 3, "cpy", AddressingMode::DirectPage, 2}, // C4 {&CPU::CMP, 3, "cmp", AddressingMode::DirectPage, 2}, // C5 - {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // C6 + {&CPU::DEC, 5, "dec", AddressingMode::DirectPage, 2}, // C6 {&CPU::CMP, 6, "cmp", AddressingMode::DirectPageIndirectLong, 2}, // C7 {&CPU::INY, 2, "iny", AddressingMode::Implied, 1}, // C8 {&CPU::CMP, 2, "cmp", AddressingMode::ImmediateForA, 2}, // C9 @@ -603,7 +605,7 @@ namespace ComSquare::CPU {&CPU::BRK, 7, "wai #-#", AddressingMode::Implied, 2}, // CB {&CPU::CPY, 4, "cpy", AddressingMode::Absolute, 3}, // CC {&CPU::CMP, 4, "cmp", AddressingMode::Absolute, 3}, // CD - {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // CE + {&CPU::DEC, 6, "dec", AddressingMode::Absolute, 3}, // CE {&CPU::CMP, 6, "cmp", AddressingMode::AbsoluteLong, 4}, // CF {&CPU::BNE, 2, "bne", AddressingMode::Implied, 2}, // D0 {&CPU::CMP, 5, "cmp", AddressingMode::DirectPageIndirectIndexedByY, 2}, // D1 @@ -611,7 +613,7 @@ namespace ComSquare::CPU {&CPU::CMP, 7, "cmp", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // D3 {&CPU::BRK, 7, "pei #-#", AddressingMode::Implied, 2}, // D4 {&CPU::CMP, 4, "cmp", AddressingMode::DirectPageIndexedByX, 2}, // D5 - {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // D6 + {&CPU::DEC, 6, "dec", AddressingMode::DirectPageIndexedByX, 2}, // D6 {&CPU::CMP, 6, "cmp", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // D7 {&CPU::CLD, 2, "cld", AddressingMode::Implied, 2}, // D8 {&CPU::CMP, 4, "cmp", AddressingMode::AbsoluteIndexedByY, 3}, // D9 @@ -619,7 +621,7 @@ namespace ComSquare::CPU {&CPU::BRK, 7, "stp #-#", AddressingMode::Implied, 2}, // DB {&CPU::JML, 7, "jml", AddressingMode::AbsoluteIndirectLong, 2}, // DC {&CPU::CMP, 4, "cmp", AddressingMode::AbsoluteIndexedByX, 3}, // DD - {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // DE + {&CPU::DEC, 7, "dec", AddressingMode::AbsoluteIndexedByX, 3}, // DE {&CPU::CMP, 5, "cmp", AddressingMode::AbsoluteIndexedByXLong, 4}, // DF {&CPU::CPX, 2, "cpx", AddressingMode::ImmediateForX, 2}, // E0 {&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // E1 diff --git a/sources/CPU/Instructions/MathematicalOperations.cpp b/sources/CPU/Instructions/MathematicalOperations.cpp index df64f01..ff2d63e 100644 --- a/sources/CPU/Instructions/MathematicalOperations.cpp +++ b/sources/CPU/Instructions/MathematicalOperations.cpp @@ -325,4 +325,44 @@ namespace ComSquare::CPU return 0; } } + + int CPU::DEC(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 48364f2..1f293aa 100644 --- a/tests/CPU/Math/testOthersMath.cpp +++ b/tests/CPU/Math/testOthersMath.cpp @@ -218,4 +218,70 @@ Test(INC, negativeNativeAccumulator) 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."); +} + +Test(DEC, simple) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.wram->_data[0] = 0x58; + snes.cpu->DEC(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(DEC, negative) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.wram->_data[0] = 0x81; + snes.cpu->DEC(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(DEC, accumulator) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x58; + snes.cpu->DEC(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(DEC, negativeAccumulator) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x81; + snes.cpu->DEC(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(DEC, nativeAccumulator) +{ + Init() + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0x5602; + snes.cpu->DEC(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(DEC, negativeNativeAccumulator) +{ + Init() + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0x9001; + snes.cpu->DEC(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