LR35902: Fix lots of timing issues by attaching to the "tick" event.

Signed-off-by: Adrian Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon
2020-11-13 10:14:06 +00:00
parent efed7dae23
commit fa7e1480d3
4 changed files with 37 additions and 39 deletions
+3 -3
View File
@@ -117,7 +117,7 @@ namespace EightBit {
poke(IF, peek(IF) | cause);
}
void checkTimers(int cycles);
void incrementTimers();
int timerClockTicks();
@@ -125,7 +125,7 @@ namespace EightBit {
bool timerEnabled();
bool timerDisabled();
void incrementDIV(int cycles);
void incrementDIV();
void incrementTIMA();
void incrementLY();
@@ -185,7 +185,7 @@ namespace EightBit {
bool m_p11 = true; // left/b
bool m_p10 = true; // right/a
void checkTimer(int cycles);
void incrementTimer();
void mask(const uint16_t address, const uint8_t masking) {
poke(address, peek(address) | ~masking);
+8 -12
View File
@@ -26,10 +26,6 @@ namespace EightBit {
Signal<LR35902> ExecutingInstruction;
Signal<LR35902> ExecutedInstruction;
[[nodiscard]] auto clockCycles() const noexcept {
return cycles() * 4;
}
[[nodiscard]] register16_t& AF() final;
[[nodiscard]] register16_t& BC() final;
[[nodiscard]] register16_t& DE() final;
@@ -49,46 +45,46 @@ namespace EightBit {
void handleINT() final;
void memoryWrite() final {
tick();
tick(4);
IntelProcessor::memoryWrite();
}
uint8_t memoryRead() final {
tick();
tick(4);
return IntelProcessor::memoryRead();
}
void pushWord(register16_t value) final {
tick();
tick(4);
IntelProcessor::pushWord(value);
}
void jr(int8_t offset) final {
IntelProcessor::jr(offset);
tick();
tick(4);
}
int jumpConditional(const int condition) final {
if (IntelProcessor::jumpConditional(condition))
tick();
tick(4);
return condition;
}
int returnConditional(const int condition) final {
IntelProcessor::returnConditional(condition);
tick();
tick(4);
return condition;
}
int jrConditional(const int condition) final {
if (!IntelProcessor::jrConditional(condition))
tick();
tick(4);
return condition;
}
void ret() final {
IntelProcessor::ret();
tick();
tick(4);
}
private:
+11 -12
View File
@@ -146,15 +146,14 @@ void EightBit::GameBoy::IoRegisters::Bus_WrittenByte(EightBit::EventArgs) {
}
}
void EightBit::GameBoy::IoRegisters::checkTimers(int cycles) {
incrementDIV(cycles);
checkTimer(cycles);
void EightBit::GameBoy::IoRegisters::incrementTimers() {
incrementDIV();
incrementTimer();
}
void EightBit::GameBoy::IoRegisters::checkTimer(int cycles) {
void EightBit::GameBoy::IoRegisters::incrementTimer() {
if (timerEnabled()) {
m_timerCounter -= cycles;
if (m_timerCounter <= 0) {
if (--m_timerCounter == 0) {
m_timerCounter += m_timerRate;
incrementTIMA();
}
@@ -164,13 +163,13 @@ void EightBit::GameBoy::IoRegisters::checkTimer(int cycles) {
int EightBit::GameBoy::IoRegisters::timerClockTicks() {
switch (timerClock()) {
case 0b00:
return 1024; // 4.096 Khz
return 256; // 4.096 Khz
case 0b01:
return 16; // 262.144 Khz
return 4; // 262.144 Khz
case 0b10:
return 64; // 65.536 Khz
return 16; // 65.536 Khz
case 0b11:
return 256; // 16.384 Khz
return 64; // 16.384 Khz
default:
UNREACHABLE;
}
@@ -189,8 +188,8 @@ bool EightBit::GameBoy::IoRegisters::timerDisabled() {
return (peek(TAC) & Chip::Bit2) == 0;
}
void EightBit::GameBoy::IoRegisters::incrementDIV(int cycles) {
m_divCounter += cycles;
void EightBit::GameBoy::IoRegisters::incrementDIV() {
++m_divCounter;
poke(DIV, m_divCounter.high);
}
+15 -12
View File
@@ -7,6 +7,12 @@
EightBit::GameBoy::LR35902::LR35902(Bus& memory)
: IntelProcessor(memory),
m_bus(memory) {
Ticked.connect([this](EventArgs) {
if ((cycles() % 4) == 0) {
m_bus.IO().incrementTimers();
m_bus.IO().transferDma();
}
});
}
EightBit::register16_t& EightBit::GameBoy::LR35902::AF() {
@@ -30,7 +36,7 @@ void EightBit::GameBoy::LR35902::handleRESET() {
IntelProcessor::handleRESET();
di();
SP() = Mask16 - 1;
tick(4);
tick(4 * 4);
}
void EightBit::GameBoy::LR35902::handleINT() {
@@ -104,7 +110,7 @@ void EightBit::GameBoy::LR35902::reti() {
EightBit::register16_t EightBit::GameBoy::LR35902::add(uint8_t& f, const register16_t operand, const register16_t value) {
tick();
tick(4);
const int addition = operand.word + value.word;
const register16_t result = addition;
@@ -332,12 +338,9 @@ int EightBit::GameBoy::LR35902::step() {
} else {
Processor::execute(fetchByte());
}
m_bus.IO().checkTimers(clockCycles());
m_bus.IO().transferDma();
}
ExecutedInstruction.fire(*this);
return clockCycles();
return cycles();
}
int EightBit::GameBoy::LR35902::execute() {
@@ -359,7 +362,7 @@ int EightBit::GameBoy::LR35902::execute() {
if (UNLIKELY(cycles() == 0))
throw std::logic_error("Unhandled opcode");
return clockCycles();
return cycles();
}
void EightBit::GameBoy::LR35902::executeCB(const int x, const int y, const int z, int, int) {
@@ -504,7 +507,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in
default:
UNREACHABLE;
}
tick();
tick(4);
break;
case 4: { // 8-bit INC
auto operand = R(y);
@@ -604,7 +607,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in
case 5: { // GB: ADD SP,dd
const auto before = SP().word;
const int8_t value = fetchByte();
tick(2);
tick(2 * 4);
const auto result = before + value;
SP() = result;
const auto carried = before ^ value ^ (result & Mask16);
@@ -619,7 +622,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in
case 7: { // GB: LD HL,SP + dd
const auto before = SP().word;
const int8_t value = fetchByte();
tick();
tick(4);
const auto result = before + value;
HL() = result;
const auto carried = before ^ value ^ (result & Mask16);
@@ -650,7 +653,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in
break;
case 3: // LD SP,HL
SP() = HL();
tick();
tick(4);
break;
default:
UNREACHABLE;
@@ -690,7 +693,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in
switch (y) {
case 0: // JP nn
jump(MEMPTR() = fetchWord());
tick();
tick(4);
break;
case 1: // CB prefix
m_prefixCB = true;