From efed7dae2307c65e004a2cec465b45b5a94b5a7e Mon Sep 17 00:00:00 2001 From: Adrian Conlon Date: Thu, 12 Nov 2020 18:21:51 +0000 Subject: [PATCH] LR35902 Simplify timing mechanism (corrects some timing issues as well!) Signed-off-by: Adrian Conlon --- LR35902/inc/LR35902.h | 43 ++++++++++++++-------- LR35902/src/LR35902.cpp | 81 ++++++----------------------------------- inc/IntelProcessor.h | 7 +++- src/IntelProcessor.cpp | 5 --- 4 files changed, 43 insertions(+), 93 deletions(-) diff --git a/LR35902/inc/LR35902.h b/LR35902/inc/LR35902.h index 578ed66..caa2c89 100644 --- a/LR35902/inc/LR35902.h +++ b/LR35902/inc/LR35902.h @@ -48,38 +48,49 @@ namespace EightBit { void handleRESET() final; void handleINT() final; - void jr(int8_t offset) final { - IntelProcessor::jr(offset); - tick(5); + void memoryWrite() final { + tick(); + IntelProcessor::memoryWrite(); } - int callConditional(const int condition) final { - if (IntelProcessor::callConditional(condition)) - tick(3); - tick(3); - return condition; + uint8_t memoryRead() final { + tick(); + return IntelProcessor::memoryRead(); + } + + void pushWord(register16_t value) final { + tick(); + IntelProcessor::pushWord(value); + } + + void jr(int8_t offset) final { + IntelProcessor::jr(offset); + tick(); } int jumpConditional(const int condition) final { - IntelProcessor::jumpConditional(condition); - tick(3); + if (IntelProcessor::jumpConditional(condition)) + tick(); return condition; } int returnConditional(const int condition) final { - if (IntelProcessor::returnConditional(condition)) - tick(3); - tick(2); + IntelProcessor::returnConditional(condition); + tick(); return condition; } int jrConditional(const int condition) final { - if (IntelProcessor::jrConditional(condition)) + if (!IntelProcessor::jrConditional(condition)) tick(); - tick(2); return condition; } + void ret() final { + IntelProcessor::ret(); + tick(); + } + private: Bus& m_bus; @@ -222,7 +233,7 @@ namespace EightBit { [[nodiscard]] static uint8_t add(uint8_t& f, uint8_t operand, uint8_t value, int carry = 0); [[nodiscard]] static uint8_t adc(uint8_t& f, uint8_t operand, uint8_t value); [[nodiscard]] static uint8_t sbc(uint8_t& f, uint8_t operand, uint8_t value); - [[nodiscard]] static uint8_t andr(uint8_t& f, uint8_t operand, uint8_t value); + static uint8_t andr(uint8_t& f, uint8_t operand, uint8_t value); [[nodiscard]] static uint8_t xorr(uint8_t& f, uint8_t operand, uint8_t value); [[nodiscard]] static uint8_t orr(uint8_t& f, uint8_t operand, uint8_t value); [[nodiscard]] static void compare(uint8_t& f, uint8_t operand, uint8_t value); diff --git a/LR35902/src/LR35902.cpp b/LR35902/src/LR35902.cpp index 779febc..69206bf 100644 --- a/LR35902/src/LR35902.cpp +++ b/LR35902/src/LR35902.cpp @@ -38,7 +38,6 @@ void EightBit::GameBoy::LR35902::handleINT() { raiseHALT(); di(); restart(BUS().DATA()); - tick(4); } void EightBit::GameBoy::LR35902::di() { @@ -83,11 +82,7 @@ bool EightBit::GameBoy::LR35902::convertCondition(const uint8_t f, int flag) { } void EightBit::GameBoy::LR35902::returnConditionalFlag(const uint8_t f, const int flag) { - if (convertCondition(f, flag)) { - tick(3); - ret(); - } - tick(2); + returnConditional(convertCondition(f, flag)); } void EightBit::GameBoy::LR35902::jrConditionalFlag(const uint8_t f, const int flag) { @@ -109,6 +104,8 @@ void EightBit::GameBoy::LR35902::reti() { EightBit::register16_t EightBit::GameBoy::LR35902::add(uint8_t& f, const register16_t operand, const register16_t value) { + tick(); + const int addition = operand.word + value.word; const register16_t result = addition; @@ -238,8 +235,7 @@ void EightBit::GameBoy::LR35902::bit(uint8_t& f, const int n, const uint8_t oper ASSUME(n >= 0); ASSUME(n <= 7); const auto carry = f & CF; - uint8_t discarded = operand; - andr(f, discarded, Chip::bit(n)); + andr(f, operand, Chip::bit(n)); f = setBit(f, CF, carry); } @@ -331,6 +327,7 @@ int EightBit::GameBoy::LR35902::step() { } else if (UNLIKELY(lowered(INT()))) { handleINT(); } else if (UNLIKELY(lowered(HALT()))) { + IntelProcessor::memoryRead(PC()); Processor::execute(0); // NOP } else { Processor::execute(fetchByte()); @@ -397,29 +394,17 @@ void EightBit::GameBoy::LR35902::executeCB(const int x, const int y, const int z default: UNREACHABLE; } - tick(2); R(z, operand); F() = adjustZero(F(), operand); - if (UNLIKELY(z == 6)) - tick(2); break; } case 1: // BIT y, r[z] bit(F(), y, R(z)); - tick(2); - if (UNLIKELY(z == 6)) - tick(2); break; case 2: // RES y, r[z] R(z, res(y, R(z))); - tick(2); - if (UNLIKELY(z == 6)) - tick(2); break; case 3: // SET y, r[z] R(z, set(y, R(z))); - tick(2); - if (UNLIKELY(z == 6)) - tick(2); break; default: UNREACHABLE; @@ -433,20 +418,16 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in case 0: // Relative jumps and assorted ops switch (y) { case 0: // NOP - tick(); break; case 1: // GB: LD (nn),SP BUS().ADDRESS() = fetchWord(); setWord(SP()); - tick(5); break; case 2: // GB: STOP stop(); - tick(); break; case 3: // JR d jr(fetchByte()); - tick(4); break; case 4: // JR cc,d case 5: @@ -462,11 +443,9 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in switch (q) { case 0: // LD rp,nn RP(p) = fetchWord(); - tick(3); break; case 1: // ADD HL,rp HL() = add(F(), HL(), RP(p)); - tick(2); break; default: UNREACHABLE; @@ -478,19 +457,15 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in switch (p) { case 0: // LD (BC),A IntelProcessor::memoryWrite(BC(), A()); - tick(2); break; case 1: // LD (DE),A IntelProcessor::memoryWrite(DE(), A()); - tick(2); break; case 2: // GB: LDI (HL),A IntelProcessor::memoryWrite(HL()++, A()); - tick(2); break; case 3: // GB: LDD (HL),A IntelProcessor::memoryWrite(HL()--, A()); - tick(2); break; default: UNREACHABLE; @@ -500,19 +475,15 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in switch (p) { case 0: // LD A,(BC) A() = IntelProcessor::memoryRead(BC()); - tick(2); break; case 1: // LD A,(DE) A() = IntelProcessor::memoryRead(DE()); - tick(2); break; case 2: // GB: LDI A,(HL) A() = IntelProcessor::memoryRead(HL()++); - tick(2); break; case 3: // GB: LDD A,(HL) A() = IntelProcessor::memoryRead(HL()--); - tick(2); break; default: UNREACHABLE; @@ -533,25 +504,18 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in default: UNREACHABLE; } - tick(2); + tick(); break; case 4: { // 8-bit INC auto operand = R(y); R(y, increment(F(), operand)); - tick(); - if (UNLIKELY(y == 6)) - tick(2); break; } case 5: { // 8-bit DEC auto operand = R(y); R(y, decrement(F(), operand)); - tick(); - if (UNLIKELY(y == 6)) - tick(2); break; } case 6: // 8-bit load immediate R(y, fetchByte()); // LD r,n - tick(2); break; case 7: // Assorted operations on accumulator/flags switch (y) { @@ -582,7 +546,6 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in default: UNREACHABLE; } - tick(); break; default: UNREACHABLE; @@ -593,10 +556,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in lowerHALT(); } else { R(y, R(z)); - if (UNLIKELY((y == 6) || (z == 6))) // M operations - tick(); } - tick(); break; case 2: // Operate on accumulator and register/memory location switch (y) { @@ -627,9 +587,6 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in default: UNREACHABLE; } - tick(); - if (UNLIKELY(z == 6)) - tick(); break; case 3: switch (z) { @@ -643,11 +600,11 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in break; case 4: // GB: LD (FF00 + n),A IntelProcessor::memoryWrite(IoRegisters::BASE + fetchByte(), A()); - tick(3); break; case 5: { // GB: ADD SP,dd const auto before = SP().word; const int8_t value = fetchByte(); + tick(2); const auto result = before + value; SP() = result; const auto carried = before ^ value ^ (result & Mask16); @@ -655,15 +612,14 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in F() = setBit(F(), CF, carried & Bit8); F() = setBit(F(), HC, carried & Bit4); } - tick(4); break; case 6: // GB: LD A,(FF00 + n) A() = IntelProcessor::memoryRead(IoRegisters::BASE + fetchByte()); - tick(3); break; case 7: { // GB: LD HL,SP + dd const auto before = SP().word; const int8_t value = fetchByte(); + tick(); const auto result = before + value; HL() = result; const auto carried = before ^ value ^ (result & Mask16); @@ -671,7 +627,6 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in F() = setBit(F(), CF, carried & Bit8); F() = setBit(F(), HC, carried & Bit4); } - tick(3); break; default: UNREACHABLE; @@ -681,25 +636,21 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in switch (q) { case 0: // POP rp2[p] RP2(p) = popWord(); - tick(3); break; case 1: switch (p) { case 0: // RET ret(); - tick(4); break; case 1: // GB: RETI reti(); - tick(4); break; case 2: // JP HL jump(HL()); - tick(); break; case 3: // LD SP,HL SP() = HL(); - tick(2); + tick(); break; default: UNREACHABLE; @@ -719,21 +670,17 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in break; case 4: // GB: LD (FF00 + C),A IntelProcessor::memoryWrite(IoRegisters::BASE + C(), A()); - tick(2); break; case 5: // GB: LD (nn),A BUS().ADDRESS() = MEMPTR() = fetchWord(); IntelProcessor::memoryWrite(A()); - tick(4); break; case 6: // GB: LD A,(FF00 + C) A() = IntelProcessor::memoryRead(IoRegisters::BASE + C()); - tick(2); break; case 7: // GB: LD A,(nn) BUS().ADDRESS() = MEMPTR() = fetchWord(); - A() = busRead(); - tick(4); + A() = memoryRead(); break; default: UNREACHABLE; @@ -743,7 +690,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in switch (y) { case 0: // JP nn jump(MEMPTR() = fetchWord()); - tick(4); + tick(); break; case 1: // CB prefix m_prefixCB = true; @@ -751,11 +698,9 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in break; case 6: // DI di(); - tick(); break; case 7: // EI ei(); - tick(); break; } break; @@ -766,13 +711,11 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in switch (q) { case 0: // PUSH rp2[p] pushWord(RP2(p)); - tick(4); break; case 1: switch (p) { case 0: // CALL nn call(MEMPTR() = fetchWord()); - tick(6); break; } break; @@ -809,11 +752,9 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in default: UNREACHABLE; } - tick(2); break; case 7: // Restart: RST y * 8 restart(y << 3); - tick(4); break; default: UNREACHABLE; diff --git a/inc/IntelProcessor.h b/inc/IntelProcessor.h index 7b8de0b..253683d 100644 --- a/inc/IntelProcessor.h +++ b/inc/IntelProcessor.h @@ -132,7 +132,7 @@ namespace EightBit { // - void restart(const uint8_t address) { + virtual void restart(const uint8_t address) { call(MEMPTR() = { address, 0 }); } @@ -169,7 +169,10 @@ namespace EightBit { return condition; } - void ret() final; + void ret() override { + Processor::ret(); + MEMPTR() = PC(); + } private: std::array m_decodedOpcodes; diff --git a/src/IntelProcessor.cpp b/src/IntelProcessor.cpp index 4b4669a..6154c4e 100644 --- a/src/IntelProcessor.cpp +++ b/src/IntelProcessor.cpp @@ -40,8 +40,3 @@ void EightBit::IntelProcessor::setWord(const register16_t value) { LittleEndianProcessor::setWord(value); MEMPTR() = BUS().ADDRESS(); } - -void EightBit::IntelProcessor::ret() { - Processor::ret(); - MEMPTR() = PC(); -}