Merge pull request #331 from retro-wertz/gba_timings

Reduce input delay by 1 frame and audio timing fix
This commit is contained in:
Zach Bacon 2018-12-12 13:43:04 -05:00 committed by GitHub
commit 0d1b23c5e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 46 deletions

View File

@ -480,8 +480,8 @@ inline int CPUUpdateTicks()
{ {
int cpuLoopTicks = lcdTicks; int cpuLoopTicks = lcdTicks;
if (soundTicks < cpuLoopTicks) //if (soundTicks < cpuLoopTicks)
cpuLoopTicks = soundTicks; //cpuLoopTicks = soundTicks;
if (timer0On && (timer0Ticks < cpuLoopTicks)) { if (timer0On && (timer0Ticks < cpuLoopTicks)) {
cpuLoopTicks = timer0Ticks; cpuLoopTicks = timer0Ticks;
@ -3669,6 +3669,40 @@ void CPUInterrupt()
biosProtected[3] = 0xe5; biosProtected[3] = 0xe5;
} }
static uint32_t joy;
static bool has_frames;
static void gbaUpdateJoypads(void)
{
// update joystick information
if (systemReadJoypads())
// read default joystick
joy = systemReadJoypad(-1);
P1 = 0x03FF ^ (joy & 0x3FF);
systemUpdateMotionSensor();
UPDATE_REG(0x130, P1);
uint16_t P1CNT = READ16LE(((uint16_t*)&ioMem[0x132]));
// this seems wrong, but there are cases where the game
// can enter the stop state without requesting an IRQ from
// the joypad.
if ((P1CNT & 0x4000) || stopState) {
uint16_t p1 = (0x3FF ^ P1) & 0x3FF;
if (P1CNT & 0x8000) {
if (p1 == (P1CNT & 0x3FF)) {
IF |= 0x1000;
UPDATE_REG(0x202, IF);
}
} else {
if (p1 & P1CNT) {
IF |= 0x1000;
UPDATE_REG(0x202, IF);
}
}
}
}
void CPULoop(int ticks) void CPULoop(int ticks)
{ {
int clockTicks; int clockTicks;
@ -3733,6 +3767,8 @@ void CPULoop(int ticks)
lcdTicks -= clockTicks; lcdTicks -= clockTicks;
soundTicks += clockTicks;
if (lcdTicks <= 0) { if (lcdTicks <= 0) {
if (DISPSTAT & 1) { // V-BLANK if (DISPSTAT & 1) { // V-BLANK
// if in V-Blank mode, keep computing... // if in V-Blank mode, keep computing...
@ -3789,32 +3825,6 @@ void CPULoop(int ticks)
lastTime = time; lastTime = time;
count = 0; count = 0;
} }
uint32_t joy = 0;
// update joystick information
if (systemReadJoypads())
// read default joystick
joy = systemReadJoypad(-1);
P1 = 0x03FF ^ (joy & 0x3FF);
systemUpdateMotionSensor();
UPDATE_REG(0x130, P1);
uint16_t P1CNT = READ16LE(((uint16_t*)&ioMem[0x132]));
// this seems wrong, but there are cases where the game
// can enter the stop state without requesting an IRQ from
// the joypad.
if ((P1CNT & 0x4000) || stopState) {
uint16_t p1 = (0x3FF ^ P1) & 0x3FF;
if (P1CNT & 0x8000) {
if (p1 == (P1CNT & 0x3FF)) {
IF |= 0x1000;
UPDATE_REG(0x202, IF);
}
} else {
if (p1 & P1CNT) {
IF |= 0x1000;
UPDATE_REG(0x202, IF);
}
}
}
uint32_t ext = (joy >> 10); uint32_t ext = (joy >> 10);
// If no (m) code is enabled, apply the cheats at each LCDline // If no (m) code is enabled, apply the cheats at each LCDline
@ -3837,6 +3847,9 @@ void CPULoop(int ticks)
UPDATE_REG(0x202, IF); UPDATE_REG(0x202, IF);
} }
CPUCheckDMA(1, 0x0f); CPUCheckDMA(1, 0x0f);
psoundTickfn();
if (frameCount >= framesToSkip) { if (frameCount >= framesToSkip) {
systemDrawScreen(); systemDrawScreen();
frameCount = 0; frameCount = 0;
@ -3844,6 +3857,8 @@ void CPULoop(int ticks)
frameCount++; frameCount++;
if (systemPauseOnFrame()) if (systemPauseOnFrame())
ticks = 0; ticks = 0;
has_frames = true;
} }
UPDATE_REG(0x04, DISPSTAT); UPDATE_REG(0x04, DISPSTAT);
@ -3971,11 +3986,12 @@ void CPULoop(int ticks)
// we shouldn't be doing sound in stop state, but we loose synchronization // we shouldn't be doing sound in stop state, but we loose synchronization
// if sound is disabled, so in stop state, soundTick will just produce // if sound is disabled, so in stop state, soundTick will just produce
// mute sound // mute sound
soundTicks -= clockTicks;
if (soundTicks <= 0) { //soundTicks -= clockTicks;
psoundTickfn(); //if (soundTicks <= 0) {
soundTicks += SOUND_CLOCK_TICKS; //psoundTickfn();
} //soundTicks += SOUND_CLOCK_TICKS;
//}
if (!stopState) { if (!stopState) {
if (timer0On) { if (timer0On) {
@ -4180,7 +4196,8 @@ void CPULoop(int ticks)
if (cpuNextEvent > ticks) if (cpuNextEvent > ticks)
cpuNextEvent = ticks; cpuNextEvent = ticks;
if (ticks <= 0 || cpuBreakLoop) // end loop when a frame is done
if (ticks <= 0 || cpuBreakLoop || has_frames)
break; break;
} }
} }
@ -4190,9 +4207,25 @@ void CPULoop(int ticks)
#endif #endif
} }
void gbaEmulate(int ticks)
{
has_frames = false;
// Read and process inputs
gbaUpdateJoypads();
// Runs nth number of ticks till vblank, outputs audio
// then the video frames.
// sanity check:
// wrapped in loop in case frames has not been written yet
do {
CPULoop(ticks);
} while (!has_frames);
}
struct EmulatedSystem GBASystem = { struct EmulatedSystem GBASystem = {
// emuMain // emuMain
CPULoop, gbaEmulate,
// emuReset // emuReset
CPUReset, CPUReset,
// emuCleanUp // emuCleanUp
@ -4223,7 +4256,7 @@ struct EmulatedSystem GBASystem = {
true, true,
// emuCount // emuCount
#ifdef FINAL_VERSION #ifdef FINAL_VERSION
250000 300000
#else #else
5000 5000
#endif #endif

View File

@ -96,9 +96,9 @@ static Stereo_Buffer* stereo_buffer;
static Blip_Synth<blip_best_quality, 1> pcm_synth[3]; // 32 kHz, 16 kHz, 8 kHz static Blip_Synth<blip_best_quality, 1> pcm_synth[3]; // 32 kHz, 16 kHz, 8 kHz
static inline blip_time_t blip_time() static inline blip_time_t blip_time(void)
{ {
return SOUND_CLOCK_TICKS - soundTicks; return soundTicks;
} }
void Gba_Pcm::init() void Gba_Pcm::init()
@ -390,7 +390,7 @@ void psoundTickfn()
{ {
if (gb_apu && stereo_buffer) { if (gb_apu && stereo_buffer) {
// Run sound hardware to present // Run sound hardware to present
end_frame(SOUND_CLOCK_TICKS); end_frame(soundTicks);
flush_samples(stereo_buffer); flush_samples(stereo_buffer);
@ -400,6 +400,8 @@ void psoundTickfn()
if (soundVolume_ != soundVolume) if (soundVolume_ != soundVolume)
apply_volume(); apply_volume();
} }
soundTicks = 0;
} }
static void apply_muting() static void apply_muting()
@ -429,7 +431,7 @@ static void reset_apu()
if (stereo_buffer) if (stereo_buffer)
stereo_buffer->clear(); stereo_buffer->clear();
soundTicks = SOUND_CLOCK_TICKS; soundTicks = 0;
} }
static void remake_stereo_buffer() static void remake_stereo_buffer()
@ -524,8 +526,7 @@ void soundReset()
reset_apu(); reset_apu();
soundPaused = true; soundPaused = true;
SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_; soundTicks = 0;
soundTicks = SOUND_CLOCK_TICKS_;
soundEvent(NR52, (uint8_t)0x80); soundEvent(NR52, (uint8_t)0x80);
} }

View File

@ -70,7 +70,9 @@ void interp_rate();
// Notifies emulator that SOUND_CLOCK_TICKS clocks have passed // Notifies emulator that SOUND_CLOCK_TICKS clocks have passed
void psoundTickfn(); void psoundTickfn();
extern int SOUND_CLOCK_TICKS; // Number of 16.8 MHz clocks between calls to soundTick() extern int SOUND_CLOCK_TICKS; // Number of 16.8 MHz clocks between calls to soundTick()
extern int soundTicks; // Number of 16.8 MHz clocks until soundTick() will be called
// 2018-12-10 - counts up from 0 since last psoundTickfn() was called
extern int soundTicks;
// Saves/loads emulator state // Saves/loads emulator state
#ifdef __LIBRETRO__ #ifdef __LIBRETRO__