Changing the timings of memory writes so they’re not effectively one T-cycle late. This screws up APU’s cycle accuracy for now.

This commit is contained in:
Lior Halphon 2018-03-05 21:17:37 +02:00
parent 88a11b891f
commit 544ca2be4c
4 changed files with 66 additions and 36 deletions

View File

@ -557,6 +557,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
GB_STATE(gb, display, 20);
GB_STATE(gb, display, 21);
GB_STATE(gb, display, 22);
GB_STATE(gb, display, 23);
}
if (!(gb->io_registers[GB_IO_LCDC] & 0x80)) {
@ -566,6 +567,8 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
}
return;
}
GB_SLEEP(gb, display, 23, 1);
/* Handle the very first line 0 */
gb->current_line = 0;

View File

@ -496,8 +496,8 @@ void GB_reset(GB_gameboy_t *gb)
}
gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = 0xFF;
}
/* The serial interrupt always occur on the 0xF8th cycle of every 0x100 cycle since boot. */
gb->serial_cycles = 0x100 - 0xF8;
/* The serial interrupt always occur on the 0xF7th cycle of every 0x100 cycle since boot. */
gb->serial_cycles = 0x100-0xF7;
gb->io_registers[GB_IO_SC] = 0x7E;
gb->magic = (uintptr_t)'SAME';
}

View File

@ -178,7 +178,15 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
gb->debugger_ticks += cycles;
cycles <<= !gb->cgb_double_speed;
if (!gb->cgb_double_speed) {
cycles <<= 1;
if ((cycles & 6) == 2) {
cycles--;
}
else if ((cycles & 6) == 6) {
cycles++;
}
}
// Not affected by speed boost
gb->hdma_cycles += cycles;

View File

@ -5,6 +5,24 @@
typedef void GB_opcode_t(GB_gameboy_t *gb, uint8_t opcode);
/*
About memroy timings:
Each M-cycle consists of 4 T-cycles. Every time the CPU accesses the memory it happens on the 1st T-cycle of an
M-cycle. During that cycle, other things may happen, such the PPU drawing to the screen. Since we can't really run
things in parallel, we run non-CPU "activities" serially using advnace_cycles(...). This is normally not a problem,
unless two entities (e.g. both the CPU and the PPU) read the same register at the same time (e.g. BGP). Since memory
accesses happen for an enitre T-cycle, if someone reads a value while someone else changes it during in the same
T-cycle, the read will return the new value. To correctly emulate this, a memory access T-cycle looks like this:
- Perform memory write (If needed)
- Run everything else
- Perform memory read (If needed)
This is equivalent to running the memory write 1 T-cycle before the memory read.
*/
static void ill(GB_gameboy_t *gb, uint8_t opcode)
{
GB_log(gb, "Illegal Opcode. Halting.\n");
@ -63,10 +81,10 @@ static void ld_rr_d16(GB_gameboy_t *gb, uint8_t opcode)
static void ld_drr_a(GB_gameboy_t *gb, uint8_t opcode)
{
uint8_t register_id;
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 3);
register_id = (opcode >> 4) + 1;
GB_write_memory(gb, gb->registers[register_id], gb->registers[GB_REGISTER_AF] >> 8);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
}
static void inc_rr(GB_gameboy_t *gb, uint8_t opcode)
@ -155,11 +173,11 @@ static void ld_da16_sp(GB_gameboy_t *gb, uint8_t opcode)
addr = GB_read_memory(gb, gb->pc++);
GB_advance_cycles(gb, 4);
addr |= GB_read_memory(gb, gb->pc++) << 8;
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 3);
GB_write_memory(gb, addr, gb->registers[GB_REGISTER_SP] & 0xFF);
GB_advance_cycles(gb, 4);
GB_write_memory(gb, addr+1, gb->registers[GB_REGISTER_SP] >> 8);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
}
static void add_hl_rr(GB_gameboy_t *gb, uint8_t opcode)
@ -392,16 +410,16 @@ static void ccf(GB_gameboy_t *gb, uint8_t opcode)
static void ld_dhli_a(GB_gameboy_t *gb, uint8_t opcode)
{
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 3);
GB_write_memory(gb, gb->registers[GB_REGISTER_HL]++, gb->registers[GB_REGISTER_AF] >> 8);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
}
static void ld_dhld_a(GB_gameboy_t *gb, uint8_t opcode)
{
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 3);
GB_write_memory(gb, gb->registers[GB_REGISTER_HL]--, gb->registers[GB_REGISTER_AF] >> 8);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
}
static void ld_a_dhli(GB_gameboy_t *gb, uint8_t opcode)
@ -425,9 +443,9 @@ static void inc_dhl(GB_gameboy_t *gb, uint8_t opcode)
uint8_t value;
GB_advance_cycles(gb, 4);
value = GB_read_memory(gb, gb->registers[GB_REGISTER_HL]) + 1;
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 3);
GB_write_memory(gb, gb->registers[GB_REGISTER_HL], value);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
gb->registers[GB_REGISTER_AF] &= ~(GB_SUBSTRACT_FLAG | GB_ZERO_FLAG | GB_HALF_CARRY_FLAG);
if ((value & 0x0F) == 0) {
@ -444,9 +462,9 @@ static void dec_dhl(GB_gameboy_t *gb, uint8_t opcode)
uint8_t value;
GB_advance_cycles(gb, 4);
value = GB_read_memory(gb, gb->registers[GB_REGISTER_HL]) - 1;
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 3);
GB_write_memory(gb, gb->registers[GB_REGISTER_HL], value);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
gb->registers[GB_REGISTER_AF] &= ~( GB_ZERO_FLAG | GB_HALF_CARRY_FLAG);
gb->registers[GB_REGISTER_AF] |= GB_SUBSTRACT_FLAG;
@ -463,9 +481,9 @@ static void ld_dhl_d8(GB_gameboy_t *gb, uint8_t opcode)
{
GB_advance_cycles(gb, 4);
uint8_t data = GB_read_memory(gb, gb->pc++);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 3);
GB_write_memory(gb, gb->registers[GB_REGISTER_HL], data);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
}
uint8_t get_src_value(GB_gameboy_t *gb, uint8_t opcode)
@ -501,8 +519,9 @@ static void set_src_value(GB_gameboy_t *gb, uint8_t opcode, uint8_t value)
gb->registers[GB_REGISTER_AF] |= value << 8;
}
else {
GB_advance_cycles(gb, 3);
GB_write_memory(gb, gb->registers[GB_REGISTER_HL], value);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 1);
}
}
else {
@ -540,9 +559,9 @@ GB_advance_cycles(gb, 4);\
#define LD_DHL_Y(y) \
static void ld_##dhl##_##y(GB_gameboy_t *gb, uint8_t opcode) \
{ \
GB_advance_cycles(gb, 4); \
GB_advance_cycles(gb, 3); \
GB_write_memory(gb, gb->registers[GB_REGISTER_HL], gb->y); \
GB_advance_cycles(gb, 4);\
GB_advance_cycles(gb, 5);\
}
LD_X_Y(b,c) LD_X_Y(b,d) LD_X_Y(b,e) LD_X_Y(b,h) LD_X_Y(b,l) LD_X_DHL(b) LD_X_Y(b,a)
@ -762,11 +781,11 @@ static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode)
uint16_t addr = GB_read_memory(gb, gb->pc++);
GB_advance_cycles(gb, 4);
addr |= (GB_read_memory(gb, gb->pc++) << 8);
GB_advance_cycles(gb, 8);
GB_advance_cycles(gb, 7);
GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc) >> 8);
GB_advance_cycles(gb, 4);
GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
gb->pc = addr;
GB_debugger_call_hook(gb, call_addr);
@ -780,13 +799,13 @@ static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode)
static void push_rr(GB_gameboy_t *gb, uint8_t opcode)
{
uint8_t register_id;
GB_advance_cycles(gb, 8);
GB_advance_cycles(gb, 7);
register_id = ((opcode >> 4) + 1) & 3;
gb->registers[GB_REGISTER_SP] -= 2;
GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->registers[register_id]) >> 8);
GB_advance_cycles(gb, 4);
GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->registers[register_id]) & 0xFF);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
}
static void add_a_d8(GB_gameboy_t *gb, uint8_t opcode)
@ -931,12 +950,12 @@ static void cp_a_d8(GB_gameboy_t *gb, uint8_t opcode)
static void rst(GB_gameboy_t *gb, uint8_t opcode)
{
uint16_t call_addr = gb->pc - 1;
GB_advance_cycles(gb, 8);
GB_advance_cycles(gb, 7);
gb->registers[GB_REGISTER_SP] -= 2;
GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc) >> 8);
GB_advance_cycles(gb, 4);
GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
gb->pc = opcode ^ 0xC7;
GB_debugger_call_hook(gb, call_addr);
}
@ -966,11 +985,11 @@ static void call_a16(GB_gameboy_t *gb, uint8_t opcode)
uint16_t addr = GB_read_memory(gb, gb->pc++);
GB_advance_cycles(gb, 4);
addr |= (GB_read_memory(gb, gb->pc++) << 8);
GB_advance_cycles(gb, 8);
GB_advance_cycles(gb, 7);
GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc) >> 8);
GB_advance_cycles(gb, 4);
GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
gb->pc = addr;
GB_debugger_call_hook(gb, call_addr);
}
@ -979,9 +998,9 @@ static void ld_da8_a(GB_gameboy_t *gb, uint8_t opcode)
{
GB_advance_cycles(gb, 4);
uint8_t temp = GB_read_memory(gb, gb->pc++);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 3);
GB_write_memory(gb, 0xFF00 + temp, gb->registers[GB_REGISTER_AF] >> 8);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
}
static void ld_a_da8(GB_gameboy_t *gb, uint8_t opcode)
@ -996,9 +1015,9 @@ static void ld_a_da8(GB_gameboy_t *gb, uint8_t opcode)
static void ld_dc_a(GB_gameboy_t *gb, uint8_t opcode)
{
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 3);
GB_write_memory(gb, 0xFF00 + (gb->registers[GB_REGISTER_BC] & 0xFF), gb->registers[GB_REGISTER_AF] >> 8);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
}
static void ld_a_dc(GB_gameboy_t *gb, uint8_t opcode)
@ -1043,9 +1062,9 @@ static void ld_da16_a(GB_gameboy_t *gb, uint8_t opcode)
addr = GB_read_memory(gb, gb->pc++);
GB_advance_cycles(gb, 4);
addr |= GB_read_memory(gb, gb->pc++) << 8;
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 3);
GB_write_memory(gb, addr, gb->registers[GB_REGISTER_AF] >> 8);
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
}
static void ld_a_da16(GB_gameboy_t *gb, uint8_t opcode)
@ -1372,7 +1391,7 @@ void GB_cpu_run(GB_gameboy_t *gb)
else if (effecitve_ime && interrupt_queue) {
gb->halted = false;
uint16_t call_addr = gb->pc - 1;
GB_advance_cycles(gb, 12);
GB_advance_cycles(gb, 11);
gb->registers[GB_REGISTER_SP] -= 2;
GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc) >> 8);
interrupt_queue = gb->interrupt_enable;
@ -1380,7 +1399,7 @@ void GB_cpu_run(GB_gameboy_t *gb)
GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc) & 0xFF);
interrupt_queue &= (gb->io_registers[GB_IO_IF]) & 0x1F;
GB_advance_cycles(gb, 4);
GB_advance_cycles(gb, 5);
if (interrupt_queue) {
uint8_t interrupt_bit = 0;
while (!(interrupt_queue & 1)) {