diff --git a/MC6809/inc/mc6809.h b/MC6809/inc/mc6809.h index 999bb98..4ea7949 100644 --- a/MC6809/inc/mc6809.h +++ b/MC6809/inc/mc6809.h @@ -112,7 +112,7 @@ namespace EightBit { // Default push/pop handlers void push(uint8_t value) noexcept final; - [[nodiscard]] uint8_t pop() noexcept final; + void pop() noexcept final; // Interrupt (etc.) handlers @@ -121,8 +121,13 @@ namespace EightBit { // Bus reader/writers - void busWrite() noexcept final; - uint8_t busRead() noexcept final; + using Processor::memoryRead; + using Processor::memoryWrite; + void memoryRead() noexcept override; + void memoryWrite() noexcept override; + + void busWrite() noexcept; + uint8_t busRead() noexcept; void call(register16_t destination) noexcept final; void ret() noexcept final; @@ -236,7 +241,7 @@ namespace EightBit { // Flag adjustment template constexpr void adjustZero(const T datum) { CC() = clearBit(CC(), ZF, datum); } - constexpr void adjustZero(const register16_t datum) { CC() = clearBit(CC(), ZF, datum.word); } + constexpr void adjustZero(const register16_t datum) { CC() = clearBit(CC(), ZF, datum.joined); } constexpr void adjustNegative(const uint8_t datum) { CC() = setBit(CC(), NF, datum & Bit7); } constexpr void adjustNegative(const register16_t datum) { adjustNegative(datum.high); } constexpr void adjustNegative(const uint16_t datum) { adjustNegative(register16_t(datum)); } @@ -248,11 +253,11 @@ namespace EightBit { constexpr void adjustCarry(const uint16_t datum) { CC() = setBit(CC(), CF, datum & Bit8); } // 8-bit addition constexpr void adjustCarry(const uint32_t datum) { CC() = setBit(CC(), CF, datum & Bit16); } // 16-bit addition - constexpr void adjustCarry(const register16_t datum) { adjustCarry(datum.word); } + constexpr void adjustCarry(const register16_t datum) { adjustCarry(datum.joined); } constexpr void adjustBorrow(const uint16_t datum) { CC() = clearBit(CC(), CF, datum & Bit8); } // 8-bit subtraction constexpr void adjustBorrow(const uint32_t datum) { CC() = clearBit(CC(), CF, datum & Bit16); } // 16-bit subtraction - constexpr void adjustBorrow(const register16_t datum) { adjustBorrow(datum.word); } + constexpr void adjustBorrow(const register16_t datum) { adjustBorrow(datum.joined); } constexpr void adjustOverflow(const uint8_t before, const uint8_t data, const register16_t after) { const uint8_t lowAfter = after.low; @@ -267,7 +272,7 @@ namespace EightBit { } constexpr void adjustOverflow(const register16_t before, const register16_t data, const register16_t after) { - adjustOverflow(before.word, data.word, after.word); + adjustOverflow(before.joined, data.joined, after.joined); } constexpr void adjustHalfCarry(const uint8_t before, const uint8_t data, const uint8_t after) { @@ -290,7 +295,7 @@ namespace EightBit { } constexpr void adjustAddition(const register16_t before, const register16_t data, const uint32_t after) { - adjustAddition(before.word, data.word, after); + adjustAddition(before.joined, data.joined, after); } constexpr void adjustSubtraction(const uint8_t before, const uint8_t data, const register16_t after) { @@ -308,7 +313,7 @@ namespace EightBit { } constexpr void adjustSubtraction(const register16_t before, const register16_t data, const uint32_t after) { - adjustSubtraction(before.word, data.word, after); + adjustSubtraction(before.joined, data.joined, after); } diff --git a/MC6809/src/Disassembly.cpp b/MC6809/src/Disassembly.cpp index ffe76ef..0e35418 100644 --- a/MC6809/src/Disassembly.cpp +++ b/MC6809/src/Disassembly.cpp @@ -43,7 +43,7 @@ std::string EightBit::Disassembly::dump_RelativeValue(int8_t value) { } std::string EightBit::Disassembly::dump_WordValue(register16_t value) { - return dump_WordValue(value.word); + return dump_WordValue(value.joined); } std::string EightBit::Disassembly::dump_WordValue(uint16_t value) { @@ -53,7 +53,7 @@ std::string EightBit::Disassembly::dump_WordValue(uint16_t value) { } std::string EightBit::Disassembly::dump_RelativeValue(register16_t value) { - return dump_RelativeValue((int16_t)value.word); + return dump_RelativeValue((int16_t)value.joined); } std::string EightBit::Disassembly::dump_RelativeValue(int16_t value) { @@ -69,7 +69,7 @@ std::string EightBit::Disassembly::trace() { } std::string EightBit::Disassembly::trace(register16_t current) { - return trace(current.word); + return trace(current.joined); } std::string EightBit::Disassembly::trace(uint16_t current) { @@ -99,7 +99,7 @@ std::string EightBit::Disassembly::disassemble() { } std::string EightBit::Disassembly::disassemble(register16_t current) { - return disassemble(current.word); + return disassemble(current.joined); } bool EightBit::Disassembly::ignore() { @@ -883,7 +883,7 @@ uint8_t EightBit::Disassembly::getByte(uint16_t address) { } uint16_t EightBit::Disassembly::getShort(uint16_t address) { - return CPU().peekShort(address).word; + return CPU().peekShort(address).joined; } // diff --git a/MC6809/src/mc6809.cpp b/MC6809/src/mc6809.cpp index 38c5ec8..325e83e 100644 --- a/MC6809/src/mc6809.cpp +++ b/MC6809/src/mc6809.cpp @@ -36,7 +36,7 @@ void EightBit::mc6809::poweredStep() noexcept { else if (UNLIKELY(lowered(INT()) && !interruptMasked())) handleINT(); else - BigEndianProcessor::execute(fetchByte()); + BigEndianProcessor::execute(fetchInstruction()); //} //ExecutedInstruction.fire(*this); //assert(cycles() > 0); @@ -62,7 +62,7 @@ void EightBit::mc6809::handleRESET() noexcept { memoryRead(); memoryRead(); memoryRead(); - jump(getShort()); + getPagedInto(PC()); eat(); } @@ -77,7 +77,7 @@ void EightBit::mc6809::handleNMI() noexcept { eat(); CC() = setBit(CC(), IF); // Disable IRQ CC() = setBit(CC(), FF); // Disable FIRQ - jump(Processor::getWordPaged(0xff, NMIvector)); + Processor::getPagedInto(0xff, NMIvector, PC()); eat(); } @@ -91,7 +91,7 @@ void EightBit::mc6809::handleINT() noexcept { saveEntireRegisterState(); eat(); CC() = setBit(CC(), IF); // Disable IRQ - jump(Processor::getWordPaged(0xff, IRQvector)); + Processor::getPagedInto(0xff, IRQvector, PC()); eat(); } @@ -106,12 +106,20 @@ void EightBit::mc6809::handleFIRQ() noexcept { eat(); CC() = setBit(CC(), IF); // Disable IRQ CC() = setBit(CC(), FF); // Disable FIRQ - jump(Processor::getWordPaged(0xff, FIRQvector)); + Processor::getPagedInto(0xff, FIRQvector, PC()); eat(); } // +void EightBit::mc6809::memoryRead() noexcept { + busRead(); +} + +void EightBit::mc6809::memoryWrite() noexcept { + busWrite(); +} + void EightBit::mc6809::busWrite() noexcept { tick(); lowerRW(); @@ -121,7 +129,8 @@ void EightBit::mc6809::busWrite() noexcept { uint8_t EightBit::mc6809::busRead() noexcept { tick(); raiseRW(); - return BigEndianProcessor::busRead(); + BigEndianProcessor::busRead(); + return BUS().DATA(); } // @@ -129,7 +138,7 @@ uint8_t EightBit::mc6809::busRead() noexcept { void EightBit::mc6809::call(register16_t destination) noexcept { memoryRead(destination); eat(); - BigEndianProcessor::pushWord(PC()); + pushShort(PC()); jump(destination); } @@ -162,8 +171,8 @@ void EightBit::mc6809::executeUnprefixed() { switch (opcode()) { - case 0x10: m_prefix10 = true; Processor::execute(fetchByte()); break; - case 0x11: m_prefix11 = true; Processor::execute(fetchByte()); break; + case 0x10: m_prefix10 = true; Processor::execute(fetchInstruction()); break; + case 0x11: m_prefix11 = true; Processor::execute(fetchInstruction()); break; // ABX case 0x3a: memoryRead(); X() += B(); eat(); break; // ABX (inherent) @@ -447,19 +456,19 @@ void EightBit::mc6809::executeUnprefixed() { case 0xf7: memoryWrite(Address_extended(), through(B())); break; // ST (STB extended) // STD - case 0xdd: Processor::setWord(Address_direct(), through(D())); break; // ST (STD direct) - case 0xed: Processor::setWord(Address_indexed(), through(D())); break; // ST (STD indexed) - case 0xfd: Processor::setWord(Address_extended(), through(D())); break; // ST (STD extended) + case 0xdd: Processor::setShort(Address_direct(), through(D())); break; // ST (STD direct) + case 0xed: Processor::setShort(Address_indexed(), through(D())); break; // ST (STD indexed) + case 0xfd: Processor::setShort(Address_extended(), through(D())); break; // ST (STD extended) // STU - case 0xdf: Processor::setWord(Address_direct(), through(U())); break; // ST (STU direct) - case 0xef: Processor::setWord(Address_indexed(), through(U())); break; // ST (STU indexed) - case 0xff: Processor::setWord(Address_extended(), through(U())); break; // ST (STU extended) + case 0xdf: Processor::setShort(Address_direct(), through(U())); break; // ST (STU direct) + case 0xef: Processor::setShort(Address_indexed(), through(U())); break; // ST (STU indexed) + case 0xff: Processor::setShort(Address_extended(), through(U())); break; // ST (STU extended) // STX - case 0x9f: Processor::setWord(Address_direct(), through(X())); break; // ST (STX direct) - case 0xaf: Processor::setWord(Address_indexed(), through(X())); break; // ST (STX indexed) - case 0xbf: Processor::setWord(Address_extended(), through(X())); break; // ST (STX extended) + case 0x9f: Processor::setShort(Address_direct(), through(X())); break; // ST (STX direct) + case 0xaf: Processor::setShort(Address_indexed(), through(X())); break; // ST (STX indexed) + case 0xbf: Processor::setShort(Address_extended(), through(X())); break; // ST (STX extended) // SUB @@ -579,14 +588,14 @@ void EightBit::mc6809::execute10() { case 0x2f: branchLong(LE()); break; // BLE (LBLE relative) // STS - case 0xdf: Processor::setWord(Address_direct(), through(S())); break; // ST (STS direct) - case 0xef: Processor::setWord(Address_indexed(), through(S())); break; // ST (STS indexed) - case 0xff: Processor::setWord(Address_extended(), through(S())); break; // ST (STS extended) + case 0xdf: Processor::setShort(Address_direct(), through(S())); break; // ST (STS direct) + case 0xef: Processor::setShort(Address_indexed(), through(S())); break; // ST (STS indexed) + case 0xff: Processor::setShort(Address_extended(), through(S())); break; // ST (STS extended) // STY - case 0x9f: Processor::setWord(Address_direct(), through(Y())); break; // ST (STY direct) - case 0xaf: Processor::setWord(Address_indexed(), through(Y())); break; // ST (STY indexed) - case 0xbf: Processor::setWord(Address_extended(), through(Y())); break; // ST (STY extended) + case 0x9f: Processor::setShort(Address_direct(), through(Y())); break; // ST (STY direct) + case 0xaf: Processor::setShort(Address_indexed(), through(Y())); break; // ST (STY indexed) + case 0xbf: Processor::setShort(Address_extended(), through(Y())); break; // ST (STY extended) // SWI case 0x3f: memoryRead(); swi2(); break; // SWI (SWI2 inherent) @@ -631,8 +640,8 @@ void EightBit::mc6809::push(const uint8_t value) noexcept { pushS(value); } -uint8_t EightBit::mc6809::pop() noexcept { - return popS(); +void EightBit::mc6809::pop() noexcept { + (void)popS(); } void EightBit::mc6809::push(register16_t& stack, const uint8_t value) noexcept { @@ -640,7 +649,8 @@ void EightBit::mc6809::push(register16_t& stack, const uint8_t value) noexcept { } uint8_t EightBit::mc6809::pop(register16_t& stack) noexcept { - return memoryRead(stack++); + memoryRead(stack++); + return BUS().DATA(); } // @@ -663,23 +673,27 @@ EightBit::register16_t& EightBit::mc6809::RR(const int which) { } EightBit::register16_t EightBit::mc6809::Address_relative_byte() { - const auto address = PC() + (int8_t)fetchByte(); + fetchByte(); + const auto address = PC() + (int8_t)BUS().DATA(); eat(); return address; } EightBit::register16_t EightBit::mc6809::Address_relative_word() { - return PC() + (int16_t)fetchWord().word; + fetchShort(); + return PC() + (int16_t)intermediate().joined; } EightBit::register16_t EightBit::mc6809::Address_direct() { - const auto offset = fetchByte(); + fetchByte(); + const auto offset = BUS().DATA(); eat(); return register16_t(offset, DP()); } EightBit::register16_t EightBit::mc6809::Address_indexed() { - const auto type = fetchByte(); + fetchByte(); + const auto type = BUS().DATA(); auto& r = RR((type & (Bit6 | Bit5)) >> 5); register16_t address = Mask16; @@ -725,11 +739,13 @@ EightBit::register16_t EightBit::mc6809::Address_indexed() { eat(); break; case 0b1000: // n,R (eight-bit) - address = r + (int8_t)fetchByte(); + fetchByte(); + address = r + (int8_t)BUS().DATA(); eat(); break; case 0b1001: // n,R (sixteen-bit) - address = r + (int16_t)fetchWord().word; + fetchShort(); + address = r + (int16_t)intermediate().joined; memoryRead(PC()); eat(2); break; @@ -757,7 +773,8 @@ EightBit::register16_t EightBit::mc6809::Address_indexed() { UNREACHABLE; } if (indirect) { - address = Processor::getShort(address); + getShort(address); + address = intermediate(); eat(); } } else { @@ -770,45 +787,53 @@ EightBit::register16_t EightBit::mc6809::Address_indexed() { } EightBit::register16_t EightBit::mc6809::Address_extended() { - const auto ea = fetchWord(); + fetchShort(); eat(); - return ea; + return intermediate(); } // uint8_t EightBit::mc6809::AM_immediate_byte() { - return fetchByte(); + fetchByte(); + return BUS().DATA(); } uint8_t EightBit::mc6809::AM_direct_byte() { - return memoryRead(Address_direct()); + memoryRead(Address_direct()); + return BUS().DATA(); } uint8_t EightBit::mc6809::AM_indexed_byte() { - return memoryRead(Address_indexed()); + memoryRead(Address_indexed()); + return BUS().DATA(); } uint8_t EightBit::mc6809::AM_extended_byte() { - return memoryRead(Address_extended()); + memoryRead(Address_extended()); + return BUS().DATA(); } // EightBit::register16_t EightBit::mc6809::AM_immediate_word() { - return fetchWord(); + fetchShort(); + return intermediate(); } EightBit::register16_t EightBit::mc6809::AM_direct_word() { - return Processor::getShort(Address_direct()); + getShort(Address_direct()); + return intermediate(); } EightBit::register16_t EightBit::mc6809::AM_indexed_word() { - return Processor::getShort(Address_indexed()); + getShort(Address_indexed()); + return intermediate(); } EightBit::register16_t EightBit::mc6809::AM_extended_word() { - return Processor::getShort(Address_extended()); + getShort(Address_extended()); + return intermediate(); } // @@ -844,7 +869,7 @@ uint8_t EightBit::mc6809::add(const uint8_t operand, const uint8_t data, const u } EightBit::register16_t EightBit::mc6809::add(const register16_t operand, const register16_t data) { - const uint32_t addition = operand.word + data.word; + const uint32_t addition = operand.joined + data.joined; adjustAddition(operand, data, addition); eat(); return addition & Mask16; @@ -1087,21 +1112,21 @@ void EightBit::mc6809::swi() { saveEntireRegisterState(); CC() = setBit(CC(), IF); // Disable IRQ CC() = setBit(CC(), FF); // Disable FIRQ - jump(Processor::getWordPaged(0xff, SWIvector)); + Processor::getPagedInto(0xff, SWIvector, PC()); eat(); } void EightBit::mc6809::swi2() { eat(); saveEntireRegisterState(); - jump(Processor::getWordPaged(0xff, SWI2vector)); + Processor::getPagedInto(0xff, SWI2vector, PC()); eat(); } void EightBit::mc6809::swi3() { eat(); saveEntireRegisterState(); - jump(Processor::getWordPaged(0xff, SWI3vector)); + Processor::getPagedInto(0xff, SWI3vector, PC()); eat(); } @@ -1137,7 +1162,7 @@ uint8_t EightBit::mc6809::sub(const uint8_t operand, const uint8_t data, const u } EightBit::register16_t EightBit::mc6809::sub(const register16_t operand, const register16_t data) { - const uint32_t subtraction = operand.word - data.word; + const uint32_t subtraction = operand.joined - data.joined; adjustSubtraction(operand, data, subtraction); eat(); return subtraction & Mask16; diff --git a/MC6809/test/Board.cpp b/MC6809/test/Board.cpp index 6d2157e..30354e3 100644 --- a/MC6809/test/Board.cpp +++ b/MC6809/test/Board.cpp @@ -4,7 +4,7 @@ Board::Board(const Configuration& configuration) : m_configuration(configuration) {} -void Board::raisePOWER() { +void Board::raisePOWER() noexcept { EightBit::Bus::raisePOWER(); @@ -26,7 +26,7 @@ void Board::raisePOWER() { accessAcia(); } -void Board::lowerPOWER() { +void Board::lowerPOWER() noexcept { if (m_configuration.isProfileMode()) { m_profiler.EmitLine.connect([this](EightBit::ProfileLineEventArgs line) { @@ -40,7 +40,7 @@ void Board::lowerPOWER() { EightBit::Bus::lowerPOWER(); } -void Board::initialise() { +void Board::initialise() noexcept { // Load our BASIC interpreter const auto directory = m_configuration.getRomDirectory() + "\\"; @@ -53,14 +53,14 @@ void Board::initialise() { }); // Marshal data from memory -> ACIA - WrittenByte.connect([this] (EightBit::EventArgs&) { + CPU().WrittenMemory.connect([this] (EightBit::EventArgs&) { updateAciaPins(); if (ACIA().selected()) accessAcia(); }); // Marshal data from ACIA -> memory - ReadingByte.connect([this] (EightBit::EventArgs&) { + CPU().ReadingMemory.connect([this] (EightBit::EventArgs&) { updateAciaPins(); if (accessAcia()) poke(ACIA().DATA()); @@ -84,7 +84,7 @@ void Board::initialise() { m_profiler.addInstruction(peek(cpu.PC())); }); m_cpu.ExecutedInstruction.connect([this](EightBit::mc6809& cpu) { - m_profiler.addAddress(cpu.PC().word, cpu.cycles()); + m_profiler.addAddress(cpu.PC().joined, cpu.cycles()); }); } @@ -111,27 +111,31 @@ void Board::initialise() { } } -EightBit::MemoryMapping Board::mapping(uint16_t address) { +const EightBit::MemoryMapping& Board::mapping(uint16_t address) noexcept { if (address < 0x8000) - return { m_ram, 0x0000, EightBit::Chip::Mask16, EightBit::MemoryMapping::AccessLevel::ReadWrite }; + return m_ramMapping; + //return { m_ram, 0x0000, EightBit::Chip::Mask16, EightBit::MemoryMapping::AccessLevel::ReadWrite }; if (address < 0xa000) - return { m_unused2000, 0x8000, EightBit::Chip::Mask16, EightBit::MemoryMapping::AccessLevel::ReadOnly }; + return m_unused2000Mapping; + //return { m_unused2000, 0x8000, EightBit::Chip::Mask16, EightBit::MemoryMapping::AccessLevel::ReadOnly }; if (address < 0xc000) - return { m_io, 0xa000, EightBit::Chip::Mask16, EightBit::MemoryMapping::AccessLevel::ReadWrite }; + return m_ioMapping; + //return { m_io, 0xa000, EightBit::Chip::Mask16, EightBit::MemoryMapping::AccessLevel::ReadWrite }; - return { m_rom, 0xc000, EightBit::Chip::Mask16, EightBit::MemoryMapping::AccessLevel::ReadOnly }; + return m_romMapping; + //return { m_rom, 0xc000, EightBit::Chip::Mask16, EightBit::MemoryMapping::AccessLevel::ReadOnly }; } void Board::updateAciaPins() { ACIA().DATA() = DATA(); EightBit::Device::match(ACIA().RW(), CPU().RW()); - EightBit::Device::match(ACIA().RS(), ADDRESS().word & EightBit::Chip::Bit0); - EightBit::Device::match(ACIA().CS0(), ADDRESS().word & EightBit::Chip::Bit15); - EightBit::Device::match(ACIA().CS1(), ADDRESS().word & EightBit::Chip::Bit13); - EightBit::Device::match(ACIA().CS2(), ADDRESS().word & EightBit::Chip::Bit14); + EightBit::Device::match(ACIA().RS(), ADDRESS().joined & EightBit::Chip::Bit0); + EightBit::Device::match(ACIA().CS0(), ADDRESS().joined & EightBit::Chip::Bit15); + EightBit::Device::match(ACIA().CS1(), ADDRESS().joined & EightBit::Chip::Bit13); + EightBit::Device::match(ACIA().CS2(), ADDRESS().joined & EightBit::Chip::Bit14); } bool Board::accessAcia() { diff --git a/MC6809/test/Board.h b/MC6809/test/Board.h index e29a238..e4c47ad 100644 --- a/MC6809/test/Board.h +++ b/MC6809/test/Board.h @@ -20,13 +20,13 @@ public: auto& CPU() { return m_cpu; } auto& ACIA() { return m_acia; } - void raisePOWER() final; - void lowerPOWER() final; + void raisePOWER() noexcept final; + void lowerPOWER() noexcept final; - virtual void initialise() final; + virtual void initialise() noexcept final; protected: - EightBit::MemoryMapping mapping(uint16_t address) final; + const EightBit::MemoryMapping& mapping(uint16_t address) noexcept final; private: const Configuration& m_configuration; @@ -35,6 +35,11 @@ private: EightBit::Ram m_io = 0x2000; // A000 - BFFF, 8K serial interface, minimally decoded EightBit::Rom m_rom = 0x4000; // C000 - FFFF, 16K ROM + EightBit::MemoryMapping m_ramMapping = { m_ram, 0x0000, EightBit::Chip::Mask16, EightBit::MemoryMapping::AccessLevel::ReadWrite }; + EightBit::MemoryMapping m_unused2000Mapping = { m_unused2000, 0x8000, EightBit::Chip::Mask16, EightBit::MemoryMapping::AccessLevel::ReadOnly }; + EightBit::MemoryMapping m_ioMapping = { m_io, 0xa000, EightBit::Chip::Mask16, EightBit::MemoryMapping::AccessLevel::ReadWrite }; + EightBit::MemoryMapping m_romMapping = { m_rom, 0xc000, EightBit::Chip::Mask16, EightBit::MemoryMapping::AccessLevel::ReadOnly }; + EightBit::mc6850 m_acia; EightBit::mc6809 m_cpu = *this; diff --git a/MC6809/unittest/Board.cpp b/MC6809/unittest/Board.cpp index 70fa5b7..e248424 100644 --- a/MC6809/unittest/Board.cpp +++ b/MC6809/unittest/Board.cpp @@ -3,7 +3,7 @@ Board::Board() {} -void Board::raisePOWER() { +void Board::raisePOWER() noexcept { EightBit::Bus::raisePOWER(); CPU().raisePOWER(); @@ -16,12 +16,12 @@ void Board::raisePOWER() { CPU().raiseHALT(); } -void Board::lowerPOWER() { +void Board::lowerPOWER() noexcept { CPU().lowerPOWER(); EightBit::Bus::lowerPOWER(); } -void Board::initialise() { +void Board::initialise() noexcept { CPU().ExecutingInstruction.connect([this](EightBit::mc6809& cpu) { m_disassembleAt = CPU().PC(); m_ignoreDisassembly = m_disassembler.ignore(); @@ -33,6 +33,6 @@ void Board::initialise() { }); } -EightBit::MemoryMapping Board::mapping(uint16_t) { - return { m_ram, 0x0000, 0xffff, EightBit::MemoryMapping::AccessLevel::ReadWrite }; +const EightBit::MemoryMapping& Board::mapping(uint16_t) noexcept { + return m_mapping; } diff --git a/MC6809/unittest/Board.h b/MC6809/unittest/Board.h index d01c7f2..055448b 100644 --- a/MC6809/unittest/Board.h +++ b/MC6809/unittest/Board.h @@ -11,16 +11,17 @@ public: constexpr EightBit::mc6809& CPU() { return m_cpu; } - void raisePOWER() final; - void lowerPOWER() final; + void raisePOWER() noexcept final; + void lowerPOWER() noexcept final; protected: - void initialise() final; + void initialise() noexcept final; - EightBit::MemoryMapping mapping(uint16_t address) final; + const EightBit::MemoryMapping& mapping(uint16_t address) noexcept final; private: EightBit::Ram m_ram = 0x10000; // 0000 - FFFF, 64K RAM + EightBit::MemoryMapping m_mapping = { m_ram, 0x0000, 0xffff, EightBit::MemoryMapping::AccessLevel::ReadWrite }; EightBit::mc6809 m_cpu = { *this }; EightBit::Disassembly m_disassembler = { *this, m_cpu }; diff --git a/MC6809/unittest/mc6809_tests.cpp b/MC6809/unittest/mc6809_tests.cpp index c916727..a57943d 100644 --- a/MC6809/unittest/mc6809_tests.cpp +++ b/MC6809/unittest/mc6809_tests.cpp @@ -4,1055 +4,1287 @@ // Some tests from: // 6809 Assembly Language Programming, by Lance A. Leventhal // https://github.com/sorenroug/osnine-java/blob/master/core/cputests/ -// void setRegs(a, b, x, y, u) -TEST_CASE("Add Accumulator B to Index Register X Unsigned", "[ABX]") { +BOOST_AUTO_TEST_SUITE(ABX) +BOOST_AUTO_TEST_CASE(Inherent) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - - SECTION("Inherent") { - board.poke(0, 0x3a); - cpu.B() = 0x84; - cpu.X() = 0x1097; - cycles = cpu.step(); - REQUIRE(cpu.X() == 0x111b); - REQUIRE(cycles == 3); - } - - SECTION("Inherent test (ABX1)") { - cpu.A() = 0; - cpu.B() = 0xce; - cpu.X() = 0x8006; - cpu.Y() = 0; - cpu.U() = 0; - cpu.CC() = 0; - board.poke(0, 0x3a); - cycles = cpu.step(); - REQUIRE(cpu.A() == 0); - REQUIRE(cpu.B() == 0xce); - REQUIRE(cpu.X() == 0x80d4); - REQUIRE(cpu.Y() == 0); - REQUIRE(cpu.U() == 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.halfCarry() == 0); - REQUIRE(cycles == 3); - } - - SECTION("Inherent test (ABX2)") { - cpu.A() = 0; - cpu.B() = 0xd6; - cpu.X() = 0x7ffe; - cpu.Y() = 0; - cpu.U() = 0; - cpu.CC() = EightBit::mc6809::CF | EightBit::mc6809::VF | EightBit::mc6809::ZF; - board.poke(0, 0x3a); - cycles = cpu.step(); - REQUIRE(cpu.A() == 0); - REQUIRE(cpu.B() == 0xd6); - REQUIRE(cpu.X() == 0x80d4); - REQUIRE(cpu.Y() == 0); - REQUIRE(cpu.U() == 0); - REQUIRE(cpu.carry() != 0); - REQUIRE(cpu.overflow() != 0); - REQUIRE(cpu.zero() != 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.halfCarry() == 0); - REQUIRE(cycles == 3); - } + board.poke(0, 0x3a); + cpu.B() = 0x84; + cpu.X() = 0x1097; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.X(), 0x111b); + BOOST_CHECK_EQUAL(cycles, 3); } -TEST_CASE("Add Memory Plus Carry to Accumulator", "[ADC][ADCA]") { - +BOOST_AUTO_TEST_CASE(ABX1) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - - SECTION("Immediate (byte)") { - board.poke(0, 0x89); - board.poke(1, 0x7c); - cpu.CC() = EightBit::Chip::setBit(cpu.CC(), EightBit::mc6809::CF); - cpu.A() = 0x3a; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0xb7); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.halfCarry() != 0); - REQUIRE(cpu.overflow() != 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cycles == 2); - } - - SECTION("Immediate (byte) ADCANoC1") { - cpu.A() = 0x5; - cpu.CC() = 0; - board.poke(0, 0x89); - board.poke(1, 0x02); - cycles = cpu.step(); - REQUIRE(cpu.A() == 7); - REQUIRE(cpu.carry() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.halfCarry() == 0); - REQUIRE(cycles == 2); - } - - /* Test half-carry $E + $2 = $10 */ - SECTION("Immediate (byte) ADCANoC2") { - cpu.A() = 0xe; - cpu.CC() = 0; - board.poke(0, 0x89); - board.poke(1, 0x02); - cycles = cpu.step(); - REQUIRE(cpu.A() == 0x10); - REQUIRE(cpu.carry() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.halfCarry() != 0); - REQUIRE(cycles == 2); - } - - /* Add $22 and carry to register A ($14) */ - SECTION("Immediate (byte) ADCAWiC") { - cpu.A() = 0x14; - cpu.CC() = EightBit::mc6809::CF | EightBit::mc6809::HF; - board.poke(0, 0x89); - board.poke(1, 0x22); - cycles = cpu.step(); - REQUIRE(cpu.A() == 0x37); - REQUIRE(cpu.carry() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.halfCarry() == 0); - REQUIRE(cycles == 2); - } - - /* Test that half-carry is set when adding with a carry */ - SECTION("Immediate (byte) ADCAWiHC") { - cpu.A() = 0x14; - cpu.CC() = EightBit::mc6809::CF; - board.poke(0, 0x89); - board.poke(1, 0x2B); - cycles = cpu.step(); - REQUIRE(cpu.A() == 0x40); - REQUIRE(cpu.carry() == 0); - REQUIRE(cpu.halfCarry() != 0); - REQUIRE(cycles == 2); - } + cpu.A() = 0; + cpu.B() = 0xce; + cpu.X() = 0x8006; + cpu.Y() = 0; + cpu.U() = 0; + cpu.CC() = 0; + board.poke(0, 0x3a); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0); + BOOST_CHECK_EQUAL(cpu.B(), 0xce); + BOOST_CHECK_EQUAL(cpu.X(), 0x80d4); + BOOST_CHECK_EQUAL(cpu.Y(), 0); + BOOST_CHECK_EQUAL(cpu.U(), 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cpu.halfCarry(), 0); + BOOST_CHECK_EQUAL(cycles, 3); } -TEST_CASE("Add Memory to Accumulator", "[ADD][ADDA][ADDB][ADDD]") { - +BOOST_AUTO_TEST_CASE(ABX2) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - - SECTION("Immediate (byte)") { - board.poke(0, 0x8b); - board.poke(1, 0x8b); - cpu.A() = 0x24; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0xaf); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.halfCarry() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cycles == 2); - } - - // Add 0x02 to A=0x04. - SECTION("Immediate (byte) (ADDANoC)") { - board.poke(0, 0x8b); - board.poke(1, 0x02); - cpu.CC() = 0; - cpu.A() = 4; - cpu.B() = 5; - cycles = cpu.step(); - REQUIRE(cpu.A() == 6); - REQUIRE(cpu.B() == 5); - REQUIRE(cpu.halfCarry() == 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cycles == 2); - } - - // The overflow (V) bit indicates signed two’s complement overflow, which occurs when the - // sign bit differs from the carry bit after an arithmetic operation. - // A=0x03 + 0xFF becomes 0x02 - SECTION("Immediate (byte) (ADDAWiC)") { - board.poke(0, 0x8b); - board.poke(1, 0xff); - cpu.CC() = 0; - cpu.A() = 3; - cycles = cpu.step(); - REQUIRE(cpu.A() == 2); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.carry() != 0); - REQUIRE(cycles == 2); - } - - // positive + positive with overflow. - // B=0x40 + 0x41 becomes 0x81 or -127 - SECTION("Immediate (byte) ADDB1") { - board.poke(0, 0xcb); - board.poke(1, 0x41); - cpu.B() = 0x40; - cpu.CC() = 0; - cycles = cpu.step(); - REQUIRE(cpu.B() == 0x81); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.halfCarry() == 0); - REQUIRE(cpu.overflow() != 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cycles == 2); - } - - // negative + negative. - // B=0xFF + 0xFF becomes 0xFE or -2 - SECTION("Immediate (byte) ADDB2") { - board.poke(0, 0xcb); - board.poke(1, 0xff); - cpu.B() = 0xff; - cpu.CC() = 0; - cycles = cpu.step(); - REQUIRE(cpu.B() == 0xfe); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.carry() != 0); - REQUIRE(cycles == 2); - } - - // negative + negative with overflow. - // B=0xC0 + 0xBF becomes 0x7F or 127 - SECTION("Immediate (byte) ADDB3") { - board.poke(0, 0xcb); - board.poke(1, 0xbf); - cpu.B() = 0xc0; - cpu.CC() = 0; - cycles = cpu.step(); - REQUIRE(cpu.B() == 0x7f); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() != 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.carry() != 0); - REQUIRE(cycles == 2); - } - - // positive + negative with negative result. - // B=0x02 + 0xFC becomes 0xFE or -2 - SECTION("Immediate (byte) ADDB4") { - board.poke(0, 0xcb); - board.poke(1, 0xfc); - cpu.B() = 0x02; - cpu.CC() = 0; - cycles = cpu.step(); - REQUIRE(cpu.B() == 0xfe); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cycles == 2); - } - - // Add 0x02B0 to D=0x0405 becomes 0x6B5. - // positive + positive = positive - SECTION("Immediate (word) (ADDDNoC)") { - board.poke(0, 0xc3); - board.poke(1, 0x02); - board.poke(2, 0xb0); - cpu.CC() = 0; - cpu.A() = 4; - cpu.B() = 5; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0x06); - REQUIRE(cpu.B() == 0xb5); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cycles == 4); - } - - // Add 0xE2B0 to D=0x8405 becomes 0x66B5. - // negative + negative = positive + overflow - SECTION("Immediate (word) (ADDD1)") { - board.poke(0, 0xc3); - board.poke(1, 0xe2); - board.poke(2, 0xb0); - cpu.CC() = 0; - cpu.A() = 0x84; - cpu.B() = 5; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0x66); - REQUIRE(cpu.B() == 0xb5); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() != 0); - REQUIRE(cpu.carry() != 0); - REQUIRE(cycles == 4); - } - - // negative + negative = negative. - // Add 0xE000 to D=0xD000 becomes 0xB000 - SECTION("Immediate (word) (ADDD2)") { - board.poke(0, 0xc3); - board.poke(1, 0xe0); - board.poke(2, 0); - cpu.CC() = 0; - cpu.A() = 0xd0; - cpu.B() = 0; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0xb0); - REQUIRE(cpu.B() == 0x00); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.carry() != 0); - REQUIRE(cpu.cycles() == 4); - } - - // positive + positive = negative + overflow. - // Add 0x7000 to D=0x7000 becomes 0xE000 - SECTION("Immediate (word) (ADDD3)") { - board.poke(0, 0xc3); - board.poke(1, 0x70); - board.poke(2, 0); - cpu.CC() = 0; - cpu.A() = 0x70; - cpu.B() = 0; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0xe0); - REQUIRE(cpu.B() == 0x00); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() != 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cpu.cycles() == 4); - } + cpu.A() = 0; + cpu.B() = 0xd6; + cpu.X() = 0x7ffe; + cpu.Y() = 0; + cpu.U() = 0; + cpu.CC() = EightBit::mc6809::CF | EightBit::mc6809::VF | EightBit::mc6809::ZF; + board.poke(0, 0x3a); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0); + BOOST_CHECK_EQUAL(cpu.B(), 0xd6); + BOOST_CHECK_EQUAL(cpu.X(), 0x80d4); + BOOST_CHECK_EQUAL(cpu.Y(), 0); + BOOST_CHECK_EQUAL(cpu.U(), 0); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK(cpu.overflow() != 0); + BOOST_CHECK(cpu.zero() != 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cpu.halfCarry(), 0); + BOOST_CHECK_EQUAL(cycles, 3); } -TEST_CASE("Logical AND Accumulator", "[AND][ANDA]") { +BOOST_AUTO_TEST_SUITE_END() +// + +BOOST_AUTO_TEST_SUITE(ADC) + +BOOST_AUTO_TEST_CASE(Immediate_byte) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - - SECTION("Immediate (byte)") { - board.poke(0, 0x84); - board.poke(1, 0x13); - cpu.A() = 0xfc; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0x10); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cycles == 2); - } + board.poke(0, 0x89); + board.poke(1, 0x7c); + cpu.CC() = EightBit::Chip::setBit(cpu.CC(), EightBit::mc6809::CF); + cpu.A() = 0x3a; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0xb7); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK(cpu.halfCarry() != 0); + BOOST_CHECK(cpu.overflow() != 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cycles, 2); } -TEST_CASE("Shift Accumulator or Memory Byte Left", "[ASL][ASLA]") { - +BOOST_AUTO_TEST_CASE(ADCANoC1) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - - SECTION("Inherent") { - board.poke(0, 0x48); - cpu.A() = 0x7a; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0xf4); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() != 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cycles == 2); - } + cpu.A() = 0x5; + cpu.CC() = 0; + board.poke(0, 0x89); + board.poke(1, 0x02); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 7); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cpu.halfCarry(), 0); + BOOST_CHECK_EQUAL(cycles, 2); } -TEST_CASE("Shift Accumulator or Memory Byte Right", "[ASR][ASRA]") { - +// Test half-carry $E + $2 = $10 +BOOST_AUTO_TEST_CASE(ADCANoC2) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - - SECTION("Inherent") { - board.poke(0, 0x47); - cpu.A() = 0xcb; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0xe5); - REQUIRE(cpu.carry() != 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cycles == 2); - } + cpu.A() = 0xe; + cpu.CC() = 0; + board.poke(0, 0x89); + board.poke(1, 0x02); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0x10); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK(cpu.halfCarry() != 0); + BOOST_CHECK_EQUAL(cycles, 2); } -TEST_CASE("Bit Test", "[BIT][BITA]") { - +// Add $22 and carry to register A ($14) +BOOST_AUTO_TEST_CASE(ADCAWiC) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - - SECTION("Immediate (byte)") { - board.poke(0, 0x85); - board.poke(1, 0xe0); - cpu.A() = 0xa6; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0xa6); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cycles == 2); - } + cpu.A() = 0x14; + cpu.CC() = EightBit::mc6809::CF | EightBit::mc6809::HF; + board.poke(0, 0x89); + board.poke(1, 0x22); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0x37); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cpu.halfCarry(), 0); + BOOST_CHECK_EQUAL(cycles, 2); } -TEST_CASE("Clear Accumulator or Memory", "[CLR][CLRA]") { - +// Test that half-carry is set when adding with a carry +BOOST_AUTO_TEST_CASE(ADCAWiHC) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - - SECTION("Implied") { - board.poke(0, 0x4f); - cpu.A() = 0x43; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0x00); - REQUIRE(cpu.carry() == 0); - REQUIRE(cpu.zero() != 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cycles == 2); - } + cpu.A() = 0x14; + cpu.CC() = EightBit::mc6809::CF; + board.poke(0, 0x89); + board.poke(1, 0x2B); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0x40); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK(cpu.halfCarry() != 0); + BOOST_CHECK_EQUAL(cycles, 2); } -TEST_CASE("Compare Memory with a Register", "[CMP][CMPA][CMPB][CMPX]") { +BOOST_AUTO_TEST_SUITE_END() +// + +BOOST_AUTO_TEST_SUITE(ADD) + +BOOST_AUTO_TEST_CASE(Immediate_byte) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - - SECTION("Immediate (byte)") { - board.poke(0, 0x81); - board.poke(1, 0x18); - cpu.A() = 0xf6; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0xf6); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cycles == 2); - } - - SECTION("Indirect mode: CMPA ,Y+ (CMP1)") { - board.poke(0, 0xa1); - board.poke(1, 0xa0); - board.poke(0x205, 0xff); - cpu.CC() = 0; - cpu.A() = 0xff; - cpu.B() = 0; - cpu.X() = 0; - cpu.Y() = 0x205; - cpu.U() = 0; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0xff); - REQUIRE(cpu.B() == 0x00); - REQUIRE(cpu.X() == 0x00); - REQUIRE(cpu.Y() == 0x206); - REQUIRE(cpu.U() == 0); - REQUIRE(cpu.zero() != 0); - REQUIRE(cycles == 6); - } - - // B = 0xA0, CMPB with 0xA0 - SECTION("Immediate (CMP2)") { - board.poke(0, 0xc1); - board.poke(1, 0xa0); - cpu.CC() = EightBit::mc6809::NF; - cpu.B() = 0xa0; - cycles = cpu.step(); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.zero() != 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cycles == 2); - } - - // B = 0x70, CMPB with 0xA0 - SECTION("Immediate (CMP3)") { - board.poke(0, 0xc1); - board.poke(1, 0xa0); - cpu.CC() = EightBit::mc6809::NF; - cpu.B() = 0x70; - cycles = cpu.step(); - REQUIRE(cpu.carry() != 0); - REQUIRE(cpu.overflow() != 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cycles == 2); - } - - // Compare 0x5410 with 0x5410 - SECTION("Immediate (word) (CMP16)") { - board.poke(0, 0xc1); - board.poke(1, 0xa0); - cpu.CC() = EightBit::mc6809::NF; - cpu.B() = 0x70; - cycles = cpu.step(); - REQUIRE(cpu.carry() != 0); - REQUIRE(cpu.overflow() != 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cycles == 2); - } - - SECTION("Immediate (word)") { - board.poke(0, 0x8c); - board.poke(1, 0x1b); - board.poke(2, 0xb0); - cpu.X() = 0x1ab0; - cycles = cpu.step(); - REQUIRE(cpu.X() == 0x1ab0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.carry() != 0); - REQUIRE(cycles == 4); - } + board.poke(0, 0x8b); + board.poke(1, 0x8b); + cpu.A() = 0x24; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0xaf); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.halfCarry(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cycles, 2); } -TEST_CASE("Decrement Accumulator or Memory", "[DEC][DECA]") { - +// Add 0x02 to A=0x04. +BOOST_AUTO_TEST_CASE(ADDANoC) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - - SECTION("Inherent (DECA0x32)") { - board.poke(0, 0x4a); - cpu.CC() = 0; - cpu.A() = 0x32; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0x31); - REQUIRE(cpu.carry() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cycles == 2); - } - - // Test 0x80 - special case - SECTION("Inherent (DECA0x80)") { - board.poke(0, 0x4a); - cpu.CC() = 0; - cpu.A() = 0x80; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0x7f); - REQUIRE(cpu.carry() == 0); - REQUIRE(cpu.overflow() != 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cycles == 2); - } - - // Test 0x00 - special case - SECTION("Inherent (DECA0x00)") { - board.poke(0, 0x4a); - cpu.CC() = 0; - cpu.A() = 0x00; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0xff); - REQUIRE(cpu.carry() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cycles == 2); - } + board.poke(0, 0x8b); + board.poke(1, 0x02); + cpu.CC() = 0; + cpu.A() = 4; + cpu.B() = 5; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 6); + BOOST_CHECK_EQUAL(cpu.B(), 5); + BOOST_CHECK_EQUAL(cpu.halfCarry(), 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cycles, 2); } -TEST_CASE("Increment Accumulator or Memory Location by 1", "[INC][INCA]") { - +// A=0x03 + 0xFF becomes 0x02 +BOOST_AUTO_TEST_CASE(ADDAWiC) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - - SECTION("Inherent (INCA1)") { - board.poke(0, 0x4c); - cpu.CC() = 0; - cpu.A() = 0x32; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0x33); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cycles == 2); - } - - SECTION("Inherent (INCA2)") { - board.poke(0, 0x4c); - cpu.CC() = 0; - cpu.A() = 0x7f; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0x80); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() != 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cycles == 2); - } - - SECTION("Inherent (INCA3)") { - board.poke(0, 0x4c); - cpu.CC() = 0; - cpu.A() = 0xff; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.zero() != 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cycles == 2); - } + board.poke(0, 0x8b); + board.poke(1, 0xff); + cpu.CC() = 0; + cpu.A() = 3; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 2); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cycles, 2); } -TEST_CASE("Subtract Memory from Accumulator with Borrow (8-bit)", "[SBC][SBCA][SBCB]") { - +// positive + positive with overflow: B=0x40 + 0x41 becomes 0x81 +BOOST_AUTO_TEST_CASE(ADDB1) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - - SECTION("Immediate (byte)") { - board.poke(0, 0x82); - board.poke(1, 0x34); - cpu.A() = 0x14; - cpu.CC() = cpu.setBit(cpu.CC(), EightBit::mc6809::CF); - cycles = cpu.step(); - REQUIRE(cpu.A() == 0xdf); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.carry() != 0); - REQUIRE(cycles == 2); - } - - // Test the subtraction with carry instruction. - // B=0x35 - addr(0x503)=0x3 - C=1 becomes 0x31 - // SBCB dp+03 - SECTION("Direct (SBCB)") { - board.poke(0, 0xd2); - board.poke(1, 0x03); - board.poke(0x503, 0x03); - cpu.DP() = 5; - cpu.B() = 0x35; - cpu.CC() = EightBit::mc6809::CF; - cycles = cpu.step(); - REQUIRE(cpu.B() == 0x31); - REQUIRE(cpu.carry() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cycles == 4); - } - - // Test the SBCA instruction. - // A=0xFF - 0xFE - C=1 becomes 0x00 - SECTION("Immediate (SBCA) (SBCA1)") { - board.poke(0, 0x82); - board.poke(1, 0xfe); - board.poke(0x503, 0x03); - cpu.CC() = EightBit::mc6809::CF | EightBit::mc6809::NF; - cpu.A() = 0xff; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0); - REQUIRE(cpu.carry() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.zero() != 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cycles == 2); - } - - // Test the SBCA instruction. - // A=0x00 - 0xFF - C=0 becomes 0x01 - SECTION("Immediate (SBCA) (SBCA2)") { - board.poke(0, 0x82); - board.poke(1, 0xff); - cpu.CC() = EightBit::mc6809::NF | EightBit::mc6809::VF; - cpu.A() = 0; - cycles = cpu.step(); - REQUIRE(cpu.A() == 1); - REQUIRE(cpu.carry() != 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cycles == 2); - } - - // Test the SBCA instruction. - // A=0x00 - 0x01 - C=0 becomes 0xFF - SECTION("Immediate (SBCA) (SBCA3)") { - board.poke(0, 0x82); - board.poke(1, 0x01); - cpu.CC() = EightBit::mc6809::NF | EightBit::mc6809::VF; - cpu.A() = 0; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0xff); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() != 0); - REQUIRE(cycles == 2); - } + board.poke(0, 0xcb); + board.poke(1, 0x41); + cpu.B() = 0x40; + cpu.CC() = 0; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.B(), 0x81); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.halfCarry(), 0); + BOOST_CHECK(cpu.overflow() != 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cycles, 2); } -TEST_CASE("Subtract Memory from Register", "[SUB][SUBA]") { - +// negative + negative: B=0xFF + 0xFF becomes 0xFE +BOOST_AUTO_TEST_CASE(ADDB2) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - - // Test the SUBA instruction. - // The overflow (V) bit indicates signed two’s complement overflow, which - // occurs when the sign bit differs from the carry bit after an arithmetic - // operation. - // A=0x00 - 0xFF becomes 0x01 - // positive - negative = positive - SECTION("Immediate (SUBA) (SUBA1)") { - board.poke(0, 0x80); - board.poke(1, 0xff); - cpu.CC() = EightBit::mc6809::CF | EightBit::mc6809::NF | EightBit::mc6809::VF; - cpu.A() = 0; - cycles = cpu.step(); - REQUIRE(cpu.A() == 1); - REQUIRE(cpu.carry() != 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.negative() == 0); - REQUIRE(cycles == 2); - } - - // A=0x00 - 0x01 becomes 0xFF - // positive - positive = negative - SECTION("Immediate (SUBA) (SUBA2)") { - board.poke(0, 0x80); - board.poke(1, 1); - cpu.CC() = EightBit::mc6809::CF | EightBit::mc6809::NF | EightBit::mc6809::VF; - cpu.A() = 0; - cycles = cpu.step(); - REQUIRE(cpu.A() == 0xff); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.carry() != 0); - REQUIRE(cycles == 2); - } - - // Test the subtraction instruction. - // IMMEDIATE mode: B=0x02 - 0xB3 becomes 0x4F - // positive - negative = positive - SECTION("Immediate (SUBB) (SUBB1)") { - board.poke(0, 0xc0); - board.poke(1, 0xb3); - cpu.CC() = 0; - cpu.B() = 2; - cycles = cpu.step(); - REQUIRE(cpu.B() == 0x4f); - REQUIRE(cpu.negative() == 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.carry() != 0); - REQUIRE(cycles == 2); - } - - // Test the subtraction instruction. - // IMMEDIATE mode: B=0x02 - 0x81 becomes 0x81 - // positive - negative = negative + overflow - SECTION("Immediate (SUBB) (SUBB2)") { - board.poke(0, 0xc0); - board.poke(1, 0x81); - cpu.CC() = 0; - cpu.B() = 2; - cycles = cpu.step(); - REQUIRE(cpu.B() == 0x81); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() != 0); - REQUIRE(cpu.carry() != 0); - REQUIRE(cycles == 2); - } - - // Example from Programming the 6809. - // 0x03 - 0x21 = 0xE2 - // positive - positive = negative - SECTION("Immediate (SUBB) (SUBBY)") { - board.poke(0, 0xe0); - board.poke(1, 0xa4); - board.poke(0x21, 0x21); - cpu.CC() = EightBit::mc6809::ZF; - cpu.B() = 3; - cpu.Y() = 0x21; - cycles = cpu.step(); - REQUIRE(cpu.B() == 0xe2); - REQUIRE(cpu.negative() != 0); - REQUIRE(cpu.zero() == 0); - REQUIRE(cpu.overflow() == 0); - REQUIRE(cpu.carry() != 0); - REQUIRE(cycles == 4); - } + board.poke(0, 0xcb); + board.poke(1, 0xff); + cpu.B() = 0xff; + cpu.CC() = 0; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.B(), 0xfe); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cycles, 2); } -TEST_CASE(" Branch if Greater Than Zero", "[BGT]") { - +// negative + negative with overflow: B=0xC0 + 0xBF becomes 0x7F +BOOST_AUTO_TEST_CASE(ADDB3) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xcb); + board.poke(1, 0xbf); + cpu.B() = 0xc0; + cpu.CC() = 0; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.B(), 0x7f); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK(cpu.overflow() != 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cycles, 2); +} +// positive + negative with negative result: B=0x02 + 0xFC becomes 0xFE +BOOST_AUTO_TEST_CASE(ADDB4) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xcb); + board.poke(1, 0xfc); + cpu.B() = 0x02; + cpu.CC() = 0; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.B(), 0xfe); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +// Add 0x02B0 to D=0x0405 becomes 0x6B5 +BOOST_AUTO_TEST_CASE(ADDDNoC) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xc3); + board.poke(1, 0x02); + board.poke(2, 0xb0); + cpu.CC() = 0; + cpu.A() = 4; + cpu.B() = 5; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0x06); + BOOST_CHECK_EQUAL(cpu.B(), 0xb5); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cycles, 4); +} + +// Add 0xE2B0 to D=0x8405 becomes 0x66B5 +BOOST_AUTO_TEST_CASE(ADDD1) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xc3); + board.poke(1, 0xe2); + board.poke(2, 0xb0); + cpu.CC() = 0; + cpu.A() = 0x84; + cpu.B() = 5; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0x66); + BOOST_CHECK_EQUAL(cpu.B(), 0xb5); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK(cpu.overflow() != 0); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cycles, 4); +} + +// Add 0xE000 to D=0xD000 becomes 0xB000 +BOOST_AUTO_TEST_CASE(ADDD2) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xc3); + board.poke(1, 0xe0); + board.poke(2, 0); + cpu.CC() = 0; + cpu.A() = 0xd0; + cpu.B() = 0; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0xb0); + BOOST_CHECK_EQUAL(cpu.B(), 0x00); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cpu.cycles(), 4); +} + +// Add 0x7000 to D=0x7000 becomes 0xE000 +BOOST_AUTO_TEST_CASE(ADDD3) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xc3); + board.poke(1, 0x70); + board.poke(2, 0); + cpu.CC() = 0; + cpu.A() = 0x70; + cpu.B() = 0; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0xe0); + BOOST_CHECK_EQUAL(cpu.B(), 0x00); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK(cpu.overflow() != 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cpu.cycles(), 4); +} + +BOOST_AUTO_TEST_SUITE_END() + +// + +BOOST_AUTO_TEST_SUITE(AND_Accumulator) + +BOOST_AUTO_TEST_CASE(Immediate_byte) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x84); + board.poke(1, 0x13); + cpu.A() = 0xfc; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0x10); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +BOOST_AUTO_TEST_SUITE_END() + +// + +BOOST_AUTO_TEST_SUITE(ASL) + +BOOST_AUTO_TEST_CASE(Inherent) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x48); + cpu.A() = 0x7a; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0xf4); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK(cpu.overflow() != 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +BOOST_AUTO_TEST_SUITE_END() + +// + +BOOST_AUTO_TEST_SUITE(ASR) + +BOOST_AUTO_TEST_CASE(Inherent) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x47); + cpu.A() = 0xcb; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0xe5); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +BOOST_AUTO_TEST_SUITE_END() + +// + +BOOST_AUTO_TEST_SUITE(BIT_Test) + +BOOST_AUTO_TEST_CASE(Immediate_byte) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x85); + board.poke(1, 0xe0); + cpu.A() = 0xa6; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0xa6); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +BOOST_AUTO_TEST_SUITE_END() + +// + +BOOST_AUTO_TEST_SUITE(CLR) + +BOOST_AUTO_TEST_CASE(Implied) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x4f); + cpu.A() = 0x43; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0x00); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK(cpu.zero() != 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +BOOST_AUTO_TEST_SUITE_END() + +// + +BOOST_AUTO_TEST_SUITE(CMP) + +BOOST_AUTO_TEST_CASE(Immediate_byte) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x81); + board.poke(1, 0x18); + cpu.A() = 0xf6; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0xf6); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +BOOST_AUTO_TEST_CASE(CMP1_indexed) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xa1); + board.poke(1, 0xa0); + board.poke(0x205, 0xff); + cpu.CC() = 0; + cpu.A() = 0xff; + cpu.B() = 0; + cpu.X() = 0; + cpu.Y() = 0x205; + cpu.U() = 0; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0xff); + BOOST_CHECK_EQUAL(cpu.B(), 0x00); + BOOST_CHECK_EQUAL(cpu.X(), 0x00); + BOOST_CHECK_EQUAL(cpu.Y(), 0x206); + BOOST_CHECK_EQUAL(cpu.U(), 0); + BOOST_CHECK(cpu.zero() != 0); + BOOST_CHECK_EQUAL(cycles, 6); +} + +// B = 0xA0, CMPB with 0xA0 +BOOST_AUTO_TEST_CASE(CMP2) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xc1); + board.poke(1, 0xa0); + cpu.CC() = EightBit::mc6809::NF; + cpu.B() = 0xa0; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK(cpu.zero() != 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +// B = 0x70, CMPB with 0xA0 +BOOST_AUTO_TEST_CASE(CMP3) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xc1); + board.poke(1, 0xa0); + cpu.CC() = EightBit::mc6809::NF; + cpu.B() = 0x70; + cycles = cpu.step(); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK(cpu.overflow() != 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +// Compare 0x5410 with 0x5410 +BOOST_AUTO_TEST_CASE(CMP16) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xc1); + board.poke(1, 0xa0); + cpu.CC() = EightBit::mc6809::NF; + cpu.B() = 0x70; + cycles = cpu.step(); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK(cpu.overflow() != 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +BOOST_AUTO_TEST_CASE(Immediate_word) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x8c); + board.poke(1, 0x1b); + board.poke(2, 0xb0); + cpu.X() = 0x1ab0; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.X(), 0x1ab0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cycles, 4); +} + +BOOST_AUTO_TEST_SUITE_END() + +// + +BOOST_AUTO_TEST_SUITE(DEC) + +BOOST_AUTO_TEST_CASE(DECA0x32) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x4a); + cpu.CC() = 0; + cpu.A() = 0x32; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0x31); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +// Test 0x80 - special case +BOOST_AUTO_TEST_CASE(DECA0x80) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x4a); + cpu.CC() = 0; + cpu.A() = 0x80; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0x7f); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK(cpu.overflow() != 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +// Test 0x00 - special case +BOOST_AUTO_TEST_CASE(DECA0x00) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x4a); + cpu.CC() = 0; + cpu.A() = 0x00; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0xff); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +BOOST_AUTO_TEST_SUITE_END() + +// + +BOOST_AUTO_TEST_SUITE(INC) + +BOOST_AUTO_TEST_CASE(INCA1) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x4c); + cpu.CC() = 0; + cpu.A() = 0x32; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0x33); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +BOOST_AUTO_TEST_CASE(INCA2) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x4c); + cpu.CC() = 0; + cpu.A() = 0x7f; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0x80); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK(cpu.overflow() != 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +BOOST_AUTO_TEST_CASE(INCA3) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x4c); + cpu.CC() = 0; + cpu.A() = 0xff; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK(cpu.zero() != 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +BOOST_AUTO_TEST_SUITE_END() + +// + +BOOST_AUTO_TEST_SUITE(SBC) + +BOOST_AUTO_TEST_CASE(Immediate_byte) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x82); + board.poke(1, 0x34); + cpu.A() = 0x14; + cpu.CC() = cpu.setBit(cpu.CC(), EightBit::mc6809::CF); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0xdf); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +// B=0x35 - addr(0x503)=0x3 - C=1 becomes 0x31 +BOOST_AUTO_TEST_CASE(SBCB_direct) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xd2); + board.poke(1, 0x03); + board.poke(0x503, 0x03); + cpu.DP() = 5; + cpu.B() = 0x35; + cpu.CC() = EightBit::mc6809::CF; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.B(), 0x31); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cycles, 4); +} + +// A=0xFF - 0xFE - C=1 becomes 0x00 +BOOST_AUTO_TEST_CASE(SBCA1) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x82); + board.poke(1, 0xfe); + board.poke(0x503, 0x03); + cpu.CC() = EightBit::mc6809::CF | EightBit::mc6809::NF; + cpu.A() = 0xff; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0); + BOOST_CHECK_EQUAL(cpu.carry(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK(cpu.zero() != 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +// A=0x00 - 0xFF - C=0 becomes 0x01 +BOOST_AUTO_TEST_CASE(SBCA2) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x82); + board.poke(1, 0xff); + cpu.CC() = EightBit::mc6809::NF | EightBit::mc6809::VF; + cpu.A() = 0; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 1); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +// A=0x00 - 0x01 - C=0 becomes 0xFF +BOOST_AUTO_TEST_CASE(SBCA3) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x82); + board.poke(1, 0x01); + cpu.CC() = EightBit::mc6809::NF | EightBit::mc6809::VF; + cpu.A() = 0; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0xff); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +BOOST_AUTO_TEST_SUITE_END() + +// + +BOOST_AUTO_TEST_SUITE(SUB) + +// A=0x00 - 0xFF becomes 0x01 +BOOST_AUTO_TEST_CASE(SUBA1) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x80); + board.poke(1, 0xff); + cpu.CC() = EightBit::mc6809::CF | EightBit::mc6809::NF | EightBit::mc6809::VF; + cpu.A() = 0; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 1); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +// A=0x00 - 0x01 becomes 0xFF +BOOST_AUTO_TEST_CASE(SUBA2) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x80); + board.poke(1, 1); + cpu.CC() = EightBit::mc6809::CF | EightBit::mc6809::NF | EightBit::mc6809::VF; + cpu.A() = 0; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 0xff); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +// B=0x02 - 0xB3 becomes 0x4F +BOOST_AUTO_TEST_CASE(SUBB1) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xc0); + board.poke(1, 0xb3); + cpu.CC() = 0; + cpu.B() = 2; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.B(), 0x4f); + BOOST_CHECK_EQUAL(cpu.negative(), 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +// B=0x02 - 0x81 becomes 0x81 +BOOST_AUTO_TEST_CASE(SUBB2) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xc0); + board.poke(1, 0x81); + cpu.CC() = 0; + cpu.B() = 2; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.B(), 0x81); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK(cpu.overflow() != 0); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cycles, 2); +} + +// 0x03 - 0x21 = 0xE2 (indexed: SUBB ,Y) +BOOST_AUTO_TEST_CASE(SUBBY) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0xe0); + board.poke(1, 0xa4); + board.poke(0x21, 0x21); + cpu.CC() = EightBit::mc6809::ZF; + cpu.B() = 3; + cpu.Y() = 0x21; + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.B(), 0xe2); + BOOST_CHECK(cpu.negative() != 0); + BOOST_CHECK_EQUAL(cpu.zero(), 0); + BOOST_CHECK_EQUAL(cpu.overflow(), 0); + BOOST_CHECK(cpu.carry() != 0); + BOOST_CHECK_EQUAL(cycles, 4); +} + +BOOST_AUTO_TEST_SUITE_END() + +// + +BOOST_AUTO_TEST_SUITE(BGT) + +BOOST_AUTO_TEST_CASE(BGT1) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset board.poke(0, 0x2e); // BGT board.poke(1, 0x03); - board.poke(2, 0x86); // LDA #1 + board.poke(2, 0x86); // LDA #1 board.poke(3, 0x01); board.poke(4, 0x12); // NOP - board.poke(5, 0x86); // LDA #2 + board.poke(5, 0x86); // LDA #2 board.poke(6, 0x02); board.poke(7, 0x12); // NOP - - SECTION("BGT1") { - cpu.A() = 0; - cpu.CC() = EightBit::mc6809::ZF; - cycles = cpu.step(); - cycles = cpu.step(); - REQUIRE(cpu.A() == 1); - } - - cpu.lowerRESET(); + cpu.A() = 0; + cpu.CC() = EightBit::mc6809::ZF; cycles = cpu.step(); - - SECTION("BGT2") { - REQUIRE(cpu.PC() == 0); - cpu.CC() = 0; - cycles = cpu.step(); - cycles = cpu.step(); - REQUIRE(cpu.A() == 2); - } - - cpu.lowerRESET(); cycles = cpu.step(); - - SECTION("BGT3") { - REQUIRE(cpu.PC() == 0); - cpu.CC() = EightBit::mc6809::NF; - cycles = cpu.step(); - cycles = cpu.step(); - REQUIRE(cpu.A() == 1); - } - - cpu.lowerRESET(); - cycles = cpu.step(); - - SECTION("BGT4") { - REQUIRE(cpu.PC() == 0); - cpu.CC() = EightBit::mc6809::NF | EightBit::mc6809::VF; - cycles = cpu.step(); - cycles = cpu.step(); - REQUIRE(cpu.A() == 2); - } - - cpu.lowerRESET(); - cycles = cpu.step(); - - SECTION("BGT5") { - REQUIRE(cpu.PC() == 0); - cpu.CC() = EightBit::mc6809::ZF | EightBit::mc6809::NF; - cycles = cpu.step(); - cycles = cpu.step(); - REQUIRE(cpu.A() == 1); - } + BOOST_CHECK_EQUAL(cpu.A(), 1); } -TEST_CASE(" Branch if Higher", "[BHI]") { - +BOOST_AUTO_TEST_CASE(BGT2) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x2e); // BGT + board.poke(1, 0x03); + board.poke(2, 0x86); // LDA #1 + board.poke(3, 0x01); + board.poke(4, 0x12); // NOP + board.poke(5, 0x86); // LDA #2 + board.poke(6, 0x02); + board.poke(7, 0x12); // NOP + cpu.lowerRESET(); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.PC(), 0); + cpu.CC() = 0; + cycles = cpu.step(); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 2); +} +BOOST_AUTO_TEST_CASE(BGT3) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x2e); // BGT + board.poke(1, 0x03); + board.poke(2, 0x86); // LDA #1 + board.poke(3, 0x01); + board.poke(4, 0x12); // NOP + board.poke(5, 0x86); // LDA #2 + board.poke(6, 0x02); + board.poke(7, 0x12); // NOP + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.lowerRESET(); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.PC(), 0); + cpu.CC() = EightBit::mc6809::NF; + cycles = cpu.step(); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 1); +} + +BOOST_AUTO_TEST_CASE(BGT4) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x2e); // BGT + board.poke(1, 0x03); + board.poke(2, 0x86); // LDA #1 + board.poke(3, 0x01); + board.poke(4, 0x12); // NOP + board.poke(5, 0x86); // LDA #2 + board.poke(6, 0x02); + board.poke(7, 0x12); // NOP + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.lowerRESET(); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.PC(), 0); + cpu.CC() = EightBit::mc6809::NF | EightBit::mc6809::VF; + cycles = cpu.step(); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 2); +} + +BOOST_AUTO_TEST_CASE(BGT5) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x2e); // BGT + board.poke(1, 0x03); + board.poke(2, 0x86); // LDA #1 + board.poke(3, 0x01); + board.poke(4, 0x12); // NOP + board.poke(5, 0x86); // LDA #2 + board.poke(6, 0x02); + board.poke(7, 0x12); // NOP + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.lowerRESET(); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.PC(), 0); + cpu.CC() = EightBit::mc6809::ZF | EightBit::mc6809::NF; + cycles = cpu.step(); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 1); +} + +BOOST_AUTO_TEST_SUITE_END() + +// + +BOOST_AUTO_TEST_SUITE(BHI) + +BOOST_AUTO_TEST_CASE(BHI1) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset board.poke(0, 0x22); // BHI board.poke(1, 0x03); - board.poke(2, 0x86); // LDA #1 + board.poke(2, 0x86); // LDA #1 board.poke(3, 0x01); board.poke(4, 0x12); // NOP - board.poke(5, 0x86); // LDA #2 + board.poke(5, 0x86); // LDA #2 board.poke(6, 0x02); board.poke(7, 0x12); // NOP - - SECTION("BHI1") { - cpu.A() = 0; - cpu.CC() = EightBit::mc6809::ZF; - cycles = cpu.step(); - cycles = cpu.step(); - REQUIRE(cpu.A() == 1); - } + cpu.A() = 0; + cpu.CC() = EightBit::mc6809::ZF; + cycles = cpu.step(); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 1); } -TEST_CASE("Branch on Less than or Equal to Zero", "[BLE]") { +BOOST_AUTO_TEST_SUITE_END() +// + +BOOST_AUTO_TEST_SUITE(BLE) + +BOOST_AUTO_TEST_CASE(BLE1) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - board.poke(0, 0x2f); // BLE board.poke(1, 0x03); - board.poke(2, 0x86); // LDA #1 + board.poke(2, 0x86); // LDA #1 board.poke(3, 0x01); board.poke(4, 0x12); // NOP - board.poke(5, 0x86); // LDA #2 + board.poke(5, 0x86); // LDA #2 board.poke(6, 0x02); board.poke(7, 0x12); // NOP - - SECTION("BLE1") { - cpu.A() = 0; - cpu.CC() = EightBit::mc6809::ZF; - cycles = cpu.step(); - cycles = cpu.step(); - REQUIRE(cpu.A() == 2); - } - - cpu.lowerRESET(); + cpu.A() = 0; + cpu.CC() = EightBit::mc6809::ZF; cycles = cpu.step(); - - SECTION("BLE2") { - cpu.A() = 0; - cpu.CC() = 0; - cycles = cpu.step(); - cycles = cpu.step(); - REQUIRE(cpu.A() == 1); - } - - cpu.lowerRESET(); cycles = cpu.step(); - - SECTION("BLE3") { - cpu.A() = 0; - cpu.CC() = EightBit::mc6809::NF; - cycles = cpu.step(); - cycles = cpu.step(); - REQUIRE(cpu.A() == 2); - } - - cpu.lowerRESET(); - cycles = cpu.step(); - - SECTION("BLE4") { - cpu.A() = 0; - cpu.CC() = EightBit::mc6809::NF | EightBit::mc6809::VF; - cycles = cpu.step(); - cycles = cpu.step(); - REQUIRE(cpu.A() == 1); - } - - cpu.lowerRESET(); - cycles = cpu.step(); - - SECTION("BLE5") { - cpu.A() = 0; - cpu.CC() = EightBit::mc6809::ZF | EightBit::mc6809::NF; - cycles = cpu.step(); - cycles = cpu.step(); - REQUIRE(cpu.A() == 2); - } + BOOST_CHECK_EQUAL(cpu.A(), 2); } -TEST_CASE("Subroutines", "[JSR][RTS]") { +BOOST_AUTO_TEST_CASE(BLE2) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x2f); // BLE + board.poke(1, 0x03); + board.poke(2, 0x86); // LDA #1 + board.poke(3, 0x01); + board.poke(4, 0x12); // NOP + board.poke(5, 0x86); // LDA #2 + board.poke(6, 0x02); + board.poke(7, 0x12); // NOP + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.A() = 0; + cpu.CC() = 0; + cycles = cpu.step(); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 1); +} +BOOST_AUTO_TEST_CASE(BLE3) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x2f); // BLE + board.poke(1, 0x03); + board.poke(2, 0x86); // LDA #1 + board.poke(3, 0x01); + board.poke(4, 0x12); // NOP + board.poke(5, 0x86); // LDA #2 + board.poke(6, 0x02); + board.poke(7, 0x12); // NOP + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.A() = 0; + cpu.CC() = EightBit::mc6809::NF; + cycles = cpu.step(); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 2); +} + +BOOST_AUTO_TEST_CASE(BLE4) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x2f); // BLE + board.poke(1, 0x03); + board.poke(2, 0x86); // LDA #1 + board.poke(3, 0x01); + board.poke(4, 0x12); // NOP + board.poke(5, 0x86); // LDA #2 + board.poke(6, 0x02); + board.poke(7, 0x12); // NOP + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.A() = 0; + cpu.CC() = EightBit::mc6809::NF | EightBit::mc6809::VF; + cycles = cpu.step(); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 1); +} + +BOOST_AUTO_TEST_CASE(BLE5) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset + board.poke(0, 0x2f); // BLE + board.poke(1, 0x03); + board.poke(2, 0x86); // LDA #1 + board.poke(3, 0x01); + board.poke(4, 0x12); // NOP + board.poke(5, 0x86); // LDA #2 + board.poke(6, 0x02); + board.poke(7, 0x12); // NOP + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.lowerRESET(); + cycles = cpu.step(); + cpu.A() = 0; + cpu.CC() = EightBit::mc6809::ZF | EightBit::mc6809::NF; + cycles = cpu.step(); + cycles = cpu.step(); + BOOST_CHECK_EQUAL(cpu.A(), 2); +} + +BOOST_AUTO_TEST_SUITE_END() + +// + +BOOST_AUTO_TEST_SUITE(Subroutines) + +// JSR D,Y (indexed) +BOOST_AUTO_TEST_CASE(JSR) { Board board; board.raisePOWER(); auto& cpu = board.CPU(); auto cycles = cpu.step(); // Step over the reset - // Test the JSR - Jump to Subroutine - instruction. - // INDEXED mode: JSR D,Y - SECTION("JSR") { + cpu.pokeShort(0x205, 0x03ff); + cpu.D() = 0x105; + cpu.Y() = 0x200; + cpu.S() = 0x915; + board.poke(0xB00, 0xAD); + board.poke(0xB01, 0xAB); + board.poke(0xB02, 0x11); // Junk + board.poke(0xB03, 0x22); // Junk + cpu.PC() = 0xB00; + cpu.CC() = 0; + cycles = cpu.step(); - // Set up a word to test at address 0x205 - cpu.pokeShort(0x205, 0x03ff); + BOOST_CHECK_EQUAL(cpu.CC(), 0); + BOOST_CHECK_EQUAL(cpu.A(), 1); + BOOST_CHECK_EQUAL(cpu.B(), 5); + BOOST_CHECK_EQUAL(cpu.DP(), 0); + BOOST_CHECK_EQUAL(cpu.X(), 0); + BOOST_CHECK_EQUAL(cpu.Y(), 0x200); + BOOST_CHECK_EQUAL(cpu.D(), 0x105); + BOOST_CHECK_EQUAL(cpu.S(), 0x913); + BOOST_CHECK_EQUAL(cpu.U(), 0); + BOOST_CHECK_EQUAL(cpu.PC(), 0x305); + BOOST_CHECK_EQUAL(board.peek(0x914), 2); + BOOST_CHECK_EQUAL(board.peek(0x913), 0xb); + BOOST_CHECK_EQUAL(cycles, 11); +} - // Set register D - cpu.D() = 0x105; - - // Set register Y to point to that location minus 5 - cpu.Y() = 0x200; - - // Set register S to point to 0x915 - cpu.S() = 0x915; - - // Two bytes of instruction - board.poke(0xB00, 0xAD); - board.poke(0xB01, 0xAB); - board.poke(0xB02, 0x11); // Junk - board.poke(0xB03, 0x22); // Junk - - cpu.PC() = 0xB00; - cpu.CC() = 0; - - cycles = cpu.step(); - - REQUIRE(cpu.CC() == 0); - REQUIRE(cpu.A() == 1); - REQUIRE(cpu.B() == 5); - REQUIRE(cpu.DP() == 0); - REQUIRE(cpu.X() == 0); - REQUIRE(cpu.Y() == 0x200); - REQUIRE(cpu.D() == 0x105); - REQUIRE(cpu.S() == 0x913); - REQUIRE(cpu.U() == 0); - REQUIRE(cpu.PC() == 0x305); - - REQUIRE(board.peek(0x914) == 2); - REQUIRE(board.peek(0x913) == 0xb); - - REQUIRE(cycles == 11); - } +BOOST_AUTO_TEST_CASE(RTS) { + Board board; + board.raisePOWER(); + auto& cpu = board.CPU(); + auto cycles = cpu.step(); // Step over the reset cpu.lowerRESET(); cycles = cpu.step(); - SECTION("RTS") { + cpu.S() = 0x300; + cpu.pokeShort(0x300, 0x102C); // Write return address + board.poke(0xB00, 0x39); // RTS + cpu.PC() = 0xB00; + cycles = cpu.step(); - cpu.S().word = 0x300; - - cpu.pokeShort(0x300, 0x102C); // Write return address - board.poke(0xB00, 0x39); // RTS - - cpu.PC().word = 0xB00; - - cycles = cpu.step(); - - REQUIRE(cpu.PC().word == 0x102C); - REQUIRE(cpu.S().word == 0x302); - REQUIRE(cycles == 5); - } + BOOST_CHECK_EQUAL(cpu.PC(), 0x102C); + BOOST_CHECK_EQUAL(cpu.S(), 0x302); + BOOST_CHECK_EQUAL(cycles, 5); } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/MC6809/unittest/pch.h b/MC6809/unittest/pch.h index d36b3a5..43f7416 100644 Binary files a/MC6809/unittest/pch.h and b/MC6809/unittest/pch.h differ diff --git a/MC6809/unittest/unittest_MC6809.cpp b/MC6809/unittest/unittest_MC6809.cpp index d2bef69..da8f85f 100644 Binary files a/MC6809/unittest/unittest_MC6809.cpp and b/MC6809/unittest/unittest_MC6809.cpp differ diff --git a/MC6809/unittest/unittest_MC6809.vcxproj b/MC6809/unittest/unittest_MC6809.vcxproj index 8f37b71..2067976 100644 --- a/MC6809/unittest/unittest_MC6809.vcxproj +++ b/MC6809/unittest/unittest_MC6809.vcxproj @@ -66,19 +66,19 @@ false - ..\inc;..\..\inc;..\..\MC6850\inc;$(SolutionDir)modules\catch2\single_include\catch2;$(IncludePath) + ..\inc;..\..\inc;..\..\MC6850\inc;C:\Libraries\boost_1_88_0;$(IncludePath) true - ..\inc;..\..\inc;..\..\MC6850\inc;$(SolutionDir)modules\catch2\single_include\catch2;$(IncludePath) + ..\inc;..\..\inc;..\..\MC6850\inc;C:\Libraries\boost_1_88_0;$(IncludePath) true - ..\inc;..\..\inc;..\..\MC6850\inc;$(SolutionDir)modules\catch2\single_include\catch2;$(IncludePath) + ..\inc;..\..\inc;..\..\MC6850\inc;C:\Libraries\boost_1_88_0;$(IncludePath) false - ..\inc;..\..\inc;..\..\MC6850\inc;$(SolutionDir)modules\catch2\single_include\catch2;$(IncludePath) + ..\inc;..\..\inc;..\..\MC6850\inc;C:\Libraries\boost_1_88_0;$(IncludePath)