Add DMA cycle accounting for H/V blank and sound DMA
This is just responsible for a few cycles every frame (could be around 1 and 2% depending on the game usage) but makes emulation a bit more accurate and potentially faster.
This commit is contained in:
parent
7b181cb6ff
commit
bc8c07272b
5 changed files with 32 additions and 17 deletions
10
gba_memory.c
10
gba_memory.c
|
@ -699,7 +699,7 @@ static cpu_alert_type trigger_dma(u32 dma_number, u32 value)
|
|||
|
||||
write_dmareg(REG_DMA0CNT_H, dma_number, value);
|
||||
if(start_type == DMA_START_IMMEDIATELY)
|
||||
return dma_transfer(dma_number);
|
||||
return dma_transfer(dma_number, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2804,7 +2804,7 @@ static cpu_alert_type dma_transfer_copy(
|
|||
return CPU_ALERT_NONE;
|
||||
}
|
||||
|
||||
cpu_alert_type dma_transfer(unsigned dma_chan)
|
||||
cpu_alert_type dma_transfer(unsigned dma_chan, int *usedcycles)
|
||||
{
|
||||
dma_transfer_type *dmach = &dma[dma_chan];
|
||||
u32 src_ptr = dmach->source_address & (
|
||||
|
@ -2862,6 +2862,12 @@ cpu_alert_type dma_transfer(unsigned dma_chan)
|
|||
ret = CPU_ALERT_IRQ;
|
||||
}
|
||||
|
||||
// This is an approximation for the most common case (no region cross)
|
||||
if (usedcycles)
|
||||
*usedcycles += dmach->length * (
|
||||
waitstate_cycles_sequential[src_ptr >> 24][tfsizes] +
|
||||
waitstate_cycles_sequential[dst_ptr >> 24][tfsizes]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -191,7 +191,7 @@ extern char gamepak_code[5];
|
|||
extern char gamepak_maker[3];
|
||||
extern char gamepak_filename[512];
|
||||
|
||||
cpu_alert_type dma_transfer(unsigned dma_chan);
|
||||
cpu_alert_type dma_transfer(unsigned dma_chan, int *cycles);
|
||||
u8 *memory_region(u32 address, u32 *memory_limit);
|
||||
u32 load_gamepak(const struct retro_game_info* info, const char *name);
|
||||
u32 load_backup(char *name);
|
||||
|
|
27
main.c
27
main.c
|
@ -39,9 +39,9 @@ char save_path[512];
|
|||
|
||||
void trigger_ext_event(void);
|
||||
|
||||
static void update_timers(irq_type *irq_raised)
|
||||
static unsigned update_timers(irq_type *irq_raised)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned i, ret = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if(timer[i].status == TIMER_INACTIVE)
|
||||
|
@ -70,14 +70,15 @@ static void update_timers(irq_type *irq_raised)
|
|||
if(i < 2)
|
||||
{
|
||||
if(timer[i].direct_sound_channels & 0x01)
|
||||
sound_timer(timer[i].frequency_step, 0);
|
||||
ret += sound_timer(timer[i].frequency_step, 0);
|
||||
|
||||
if(timer[i].direct_sound_channels & 0x02)
|
||||
sound_timer(timer[i].frequency_step, 1);
|
||||
ret += sound_timer(timer[i].frequency_step, 1);
|
||||
}
|
||||
|
||||
timer[i].count += (timer[i].reload << timer[i].prescale);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void init_main(void)
|
||||
|
@ -109,6 +110,7 @@ void init_main(void)
|
|||
u32 update_gba(void)
|
||||
{
|
||||
irq_type irq_raised = IRQ_NONE;
|
||||
int dma_cycles;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -125,7 +127,8 @@ u32 update_gba(void)
|
|||
gbc_sound_update = 0;
|
||||
}
|
||||
|
||||
update_timers(&irq_raised);
|
||||
// Timers can trigger DMA (usually sound) and consume cycles
|
||||
dma_cycles = update_timers(&irq_raised);
|
||||
|
||||
video_count -= execute_cycles;
|
||||
|
||||
|
@ -152,7 +155,7 @@ u32 update_gba(void)
|
|||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
if(dma[i].start_type == DMA_START_HBLANK)
|
||||
dma_transfer(i);
|
||||
dma_transfer(i, &dma_cycles);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,7 +186,7 @@ u32 update_gba(void)
|
|||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
if(dma[i].start_type == DMA_START_VBLANK)
|
||||
dma_transfer(i);
|
||||
dma_transfer(i, &dma_cycles);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -235,7 +238,7 @@ u32 update_gba(void)
|
|||
if(irq_raised)
|
||||
raise_interrupt(irq_raised);
|
||||
|
||||
execute_cycles = video_count;
|
||||
execute_cycles = MAX(0, video_count);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
|
@ -247,7 +250,11 @@ u32 update_gba(void)
|
|||
}
|
||||
} while(reg[CPU_HALT_STATE] != CPU_ACTIVE && !reg[COMPLETED_FRAME]);
|
||||
|
||||
return execute_cycles;
|
||||
// We voluntarily limit this. It is not accurate but it would be much harder.
|
||||
dma_cycles = MIN(64, dma_cycles);
|
||||
dma_cycles = MIN(execute_cycles, dma_cycles);
|
||||
|
||||
return execute_cycles - dma_cycles;
|
||||
}
|
||||
|
||||
void reset_gba(void)
|
||||
|
@ -288,7 +295,7 @@ bool main_read_savestate(const u8 *src)
|
|||
const u8 *p2 = bson_find_key(src, "timers");
|
||||
if (!p1 || !p2)
|
||||
return false;
|
||||
execute_cycles = 123;
|
||||
|
||||
if (!(bson_read_int32(p1, "cpu-ticks", &cpu_ticks) &&
|
||||
bson_read_int32(p1, "exec-cycles", &execute_cycles) &&
|
||||
bson_read_int32(p1, "video-count", (u32*)&video_count)))
|
||||
|
|
8
sound.c
8
sound.c
|
@ -74,8 +74,9 @@ void sound_timer_queue32(u32 channel, u32 value)
|
|||
}
|
||||
|
||||
|
||||
void sound_timer(fixed8_24 frequency_step, u32 channel)
|
||||
unsigned sound_timer(fixed8_24 frequency_step, u32 channel)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 sample_status = DIRECT_SOUND_INACTIVE;
|
||||
direct_sound_struct *ds = &direct_sound_channel[channel];
|
||||
|
||||
|
@ -160,11 +161,12 @@ void sound_timer(fixed8_24 frequency_step, u32 channel)
|
|||
if(((ds->fifo_top - ds->fifo_base) % 32) <= 16)
|
||||
{
|
||||
if(dma[1].direct_sound_channel == channel)
|
||||
dma_transfer(1);
|
||||
dma_transfer(1, &ret);
|
||||
|
||||
if(dma[2].direct_sound_channel == channel)
|
||||
dma_transfer(2);
|
||||
dma_transfer(2, &ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sound_reset_fifo(u32 channel)
|
||||
|
|
2
sound.h
2
sound.h
|
@ -101,7 +101,7 @@ extern u32 sound_on;
|
|||
void sound_timer_queue8(u32 channel, u8 value);
|
||||
void sound_timer_queue16(u32 channel, u16 value);
|
||||
void sound_timer_queue32(u32 channel, u32 value);
|
||||
void sound_timer(fixed8_24 frequency_step, u32 channel);
|
||||
unsigned sound_timer(fixed8_24 frequency_step, u32 channel);
|
||||
void sound_reset_fifo(u32 channel);
|
||||
void update_gbc_sound(u32 cpu_ticks);
|
||||
void init_sound(int need_reset);
|
||||
|
|
Loading…
Add table
Reference in a new issue