Skip to content

Commit 0210c85

Browse files
committed
Fix further inaccuracies in the timer code to pass a couple more Mooneye tests
1 parent ad7c39e commit 0210c85

3 files changed

Lines changed: 20 additions & 12 deletions

File tree

src/core/cpu.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -127,17 +127,18 @@ bool CPU::get_timer_enable_bit(uint16_t counter, uint8_t tac) {
127127
void CPU::tick_timers(uint8_t cycles) {
128128
for (int i = 0; i < cycles; i++) {
129129
// Handle pending reloads
130+
bool in_reload = false;
131+
130132
if (tima_reload_delay > 0) {
133+
in_reload = true;
131134
tima_reload_delay--;
132135

133136
// If delay hits 0, then reload TIMA from TMA
134137
if (tima_reload_delay == 0) {
135138
uint8_t tma = mmu->read_byte(0xFF06);
136139
mmu->write_byte(0xFF05, tma);
137-
138-
// Request timer interrupt (bit 2)
139-
uint8_t if_reg = mmu->read_byte(0xFF0F);
140-
mmu->write_byte(0xFF0F, if_reg | 0x04);
140+
141+
in_reload = false;
141142
}
142143
}
143144

@@ -150,16 +151,19 @@ void CPU::tick_timers(uint8_t cycles) {
150151
bool new_signal = get_timer_enable_bit(internal_counter, tac);
151152

152153
// Increment TIMA on falling edge
153-
if (old_signal && !new_signal) {
154+
if (old_signal && !new_signal && !in_reload) {
154155
uint8_t tima = mmu->read_byte(0xFF05);
155156

156157
// Increment TIMA
157158
tima++;
158159

159160
// If timer overflowed to 0, then reload after 4 cycle delay
160161
if (tima == 0x00) {
161-
tima_reload_delay = 4;
162162
mmu->write_byte(0xFF05, 0x00);
163+
tima_reload_delay = 4;
164+
165+
uint8_t if_reg = mmu->read_byte(0xFF0F);
166+
mmu->write_byte(0xFF0F, if_reg | 0x04);
163167
} else {
164168
mmu->write_byte(0xFF05, tima);
165169
}
@@ -181,7 +185,8 @@ void CPU::sync_timer_on_div_write() {
181185
tima++;
182186
if (tima == 0x00) {
183187
tima_reload_delay = 4;
184-
mmu->write_byte(0xFF05, 0x00);
188+
uint8_t if_reg = mmu->read_byte(0xFF0F);
189+
mmu->write_byte(0xFF0F, if_reg | 0x04);
185190
} else {
186191
mmu->write_byte(0xFF05, tima);
187192
}
@@ -199,26 +204,27 @@ void CPU::sync_timer_on_tac_write(uint8_t new_tac) {
199204
tima++;
200205
if (tima == 0x00) {
201206
tima_reload_delay = 4;
202-
mmu->write_byte(0xFF05, 0x00);
207+
uint8_t if_reg = mmu->read_byte(0xFF0F);
208+
mmu->write_byte(0xFF0F, if_reg | 0x04);
203209
} else {
204210
mmu->write_byte(0xFF05, tima);
205211
}
206212
}
207213
}
208214

215+
void CPU::sync_timer_on_tma_write(uint8_t value) {
216+
// Placeholder for any future behavior needed when TMA is written to
217+
}
218+
209219
void CPU::sync_timer_on_tima_write(uint8_t value) {
210220
// Edge case - write ignored when delay == 1 (TIMA will be reloaded to TMA next cycle)
211221
if (tima_reload_delay == 1) {
212-
mmu->write_byte(0xFF05, 0x00);
213222
return;
214223
}
215224

216225
// Normal case - If reload is pending (> 1 cycle left), writing cancels the reload.
217226
if (tima_reload_delay > 1) {
218227
tima_reload_delay = 0;
219-
220-
uint8_t if_reg = mmu->read_byte(0xFF0F);
221-
mmu->write_byte(0xFF0F, if_reg | 0x04);
222228
}
223229
}
224230

src/core/cpu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ class CPU {
118118
// Timer sync helpers, called by MMU on writes to timer registers
119119
void sync_timer_on_div_write();
120120
void sync_timer_on_tac_write(uint8_t new_tac);
121+
void sync_timer_on_tma_write(uint8_t value);
121122
void sync_timer_on_tima_write(uint8_t value);
122123

123124
// Interrupt handlers

src/core/mmu.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ void MMU::write_byte(uint16_t address, uint8_t value) {
171171
// TMA (0xFF06)
172172
if (address == 0xFF06) {
173173
io[address - 0xFF00] = value;
174+
if (cpu) cpu->sync_timer_on_tma_write(value);
174175
return;
175176
}
176177

0 commit comments

Comments
 (0)