Skip to content

Commit

Permalink
Emulator: Switch to fixes size tick periods to improve device synchro…
Browse files Browse the repository at this point in the history
…nisation
  • Loading branch information
visrealm committed Sep 19, 2023
1 parent 63f565e commit 1d787bd
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 53 deletions.
90 changes: 55 additions & 35 deletions emulator/src/devices/6502_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ struct CPU6502Device
double secsPerTick;
double runTimeSeconds;
IsBreakpointFn isBreakFn;

HBC56Device *syncedDevice;
DeviceTickFn syncedDeviceTickFn;

};
typedef struct CPU6502Device CPU6502Device;

Expand Down Expand Up @@ -76,6 +80,8 @@ HBC56Device create6502CpuDevice(IsBreakpointFn brkCb, int clockFreqHz)
cpuDevice->ticks = cpuDevice->ticksWai = 0L;
cpuDevice->extraTicks = 0;
cpuDevice->isBreakFn = brkCb;
cpuDevice->syncedDevice = NULL;
cpuDevice->syncedDeviceTickFn = NULL;
device.data = cpuDevice;

device.resetFn = &reset6502CpuDevice;
Expand Down Expand Up @@ -153,13 +159,12 @@ static void tick6502CpuDevice(HBC56Device* device, uint32_t deltaTicks, float de
/* introduce a limit to the amount of time we can process in a single step
to prevent a runaway condition for slow processors */
int realDeltaTicks = deltaTicks;
realDeltaTicks += cpuDevice->extraTicks;
if (deltaTime > CPU_6502_MAX_TIMESTEP_SEC)
{
realDeltaTicks = CPU_6502_MAX_TIMESTEP_STEPS;
}

realDeltaTicks += cpuDevice->extraTicks;

uint16_t intVec = (hbc56MemRead(0xfffe, true) | (hbc56MemRead(0xffff, true) << 8));
uint16_t nmiVec = (hbc56MemRead(0xfffa, true) | (hbc56MemRead(0xfffb, true) << 8));
uint32_t cycleTicks = 0;
Expand All @@ -185,43 +190,45 @@ static void tick6502CpuDevice(HBC56Device* device, uint32_t deltaTicks, float de
{
cycleTicks = vrEmu6502InstCycle(cpuDevice->cpu6502);

if (vrEmu6502GetOpcodeCycle(cpuDevice->cpu6502) == 0) /* end of the instruction */
if (cpuDevice->currentState == CPU_BREAK_ON_INTERRUPT)
{
if (cpuDevice->currentState == CPU_BREAK_ON_INTERRUPT)
{
if (vrEmu6502GetCurrentOpcodeAddr(cpuDevice->cpu6502) == intVec ||
vrEmu6502GetCurrentOpcodeAddr(cpuDevice->cpu6502) == nmiVec)
{
cpuDevice->currentState = CPU_BREAK;
}
}

if (cpuDevice->isBreakFn(vrEmu6502GetPC(cpuDevice->cpu6502)))
if (vrEmu6502GetCurrentOpcodeAddr(cpuDevice->cpu6502) == intVec ||
vrEmu6502GetCurrentOpcodeAddr(cpuDevice->cpu6502) == nmiVec)
{
cpuDevice->currentState = CPU_BREAK;
}
}

uint8_t nextOpcode = vrEmu6502GetNextOpcode(cpuDevice->cpu6502);
int isJsr = (nextOpcode == CPU_6502_JSR);
int isRts = (nextOpcode == CPU_6502_RTS);
int isBrk = (nextOpcode == CPU_6502_BRK);
if (cpuDevice->isBreakFn(vrEmu6502GetPC(cpuDevice->cpu6502)))
{
cpuDevice->currentState = CPU_BREAK;
}

if (isRts && cpuDevice->callStackPtr)
{
--cpuDevice->callStackPtr;
}
uint8_t nextOpcode = vrEmu6502GetNextOpcode(cpuDevice->cpu6502);
int isJsr = (nextOpcode == CPU_6502_JSR);
int isRts = (nextOpcode == CPU_6502_RTS);
int isBrk = (nextOpcode == CPU_6502_BRK);

if (isJsr)
{
cpuDevice->callStack[cpuDevice->callStackPtr++] = vrEmu6502GetPC(cpuDevice->cpu6502) + 3;
cpuDevice->callStackPtr &= (CPU_6502_MAX_CALL_STACK - 1);
}
if (isRts && cpuDevice->callStackPtr)
{
--cpuDevice->callStackPtr;
}

if (isJsr)
{
cpuDevice->callStack[cpuDevice->callStackPtr++] = vrEmu6502GetPC(cpuDevice->cpu6502) + 3;
cpuDevice->callStackPtr &= (CPU_6502_MAX_CALL_STACK - 1);
}

if (isBrk)
{
cpuDevice->currentState = CPU_BREAK;
}

if (isBrk)
{
cpuDevice->currentState = CPU_BREAK;
}

if (cpuDevice->syncedDevice)
{
cpuDevice->syncedDeviceTickFn(cpuDevice->syncedDevice, cycleTicks, 0.0f);
}
}
else
Expand All @@ -233,15 +240,16 @@ static void tick6502CpuDevice(HBC56Device* device, uint32_t deltaTicks, float de

// note: we do this now rather than at the end, because some devices require accurate timing
cpuDevice->runTimeSeconds += cycleTicks * cpuDevice->secsPerTick;


realDeltaTicks -= cycleTicks;

if (vrEmu6502GetCurrentOpcode(cpuDevice->cpu6502) == CPU_6502_WAI)
{
cpuDevice->ticksWai += cycleTicks;
}

realDeltaTicks -= cycleTicks;
}
cpuDevice->extraTicks = realDeltaTicks;

cpuDevice->extraTicks = (cpuDevice->currentState == CPU_RUNNING) ? realDeltaTicks : 0;
}
}

Expand Down Expand Up @@ -318,6 +326,18 @@ void debug6502State(HBC56Device* device, HBC56CpuState state)
}
}

void sync6502CpuDevice(HBC56Device* device, HBC56Device* otherDevice)
{
CPU6502Device* cpuDevice = get6502CpuDevice(device);
if (cpuDevice)
{
cpuDevice->syncedDevice = otherDevice;
cpuDevice->syncedDeviceTickFn = otherDevice->tickFn;
otherDevice->tickFn = NULL;
}
}


HBC56CpuState getDebug6502State(HBC56Device* device)
{
CPU6502Device* cpuDevice = get6502CpuDevice(device);
Expand Down Expand Up @@ -364,4 +384,4 @@ double getCpuRuntimeSeconds(HBC56Device* device)



#endif
#endif
3 changes: 3 additions & 0 deletions emulator/src/devices/6502_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ HBC56Device create6502CpuDevice(IsBreakpointFn brkCb, int clockFreqHz);

void interrupt6502(HBC56Device* device, HBC56InterruptType type, HBC56InterruptSignal signal);

// synchronise another device to run at the same timing as the cpu
void sync6502CpuDevice(HBC56Device* cpuDevice, HBC56Device* otherDevice);

void debug6502State(HBC56Device* device, HBC56CpuState state);

HBC56CpuState getDebug6502State(HBC56Device* device);
Expand Down
4 changes: 3 additions & 1 deletion emulator/src/devices/ay38910_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ HBC56Device createAY38910Device(uint16_t baseAddr, int clockFreq, int sampleRate
ayDevice->bufferEnd = 0;
ayDevice->deltaTimeOverFlow = 0.0;
ayDevice->timePerSample = 1.0 / (double)sampleRate;
ayDevice->lastCpuRuntimeSeconds = 0.0;


device.data = ayDevice;
Expand All @@ -81,7 +82,7 @@ HBC56Device createAY38910Device(uint16_t baseAddr, int clockFreq, int sampleRate
device.readFn = &readAy38910Device;
device.writeFn = &writeAy38910Device;
device.audioFn = &audioAy38910Device;
device.tickFn = &tickAy38910Device;
//device.tickFn = &tickAy38910Device;
}
else
{
Expand Down Expand Up @@ -142,6 +143,7 @@ static inline void addSampleToBuffer(AY38910Device* ayDevice)
ayDevice->deltaTimeOverFlow -= ayDevice->timePerSample;
}


static void tickAy38910Device(HBC56Device* device, uint32_t deltaTicks, float deltaTime)
{
AY38910Device* ayDevice = getAy38910Device(device);
Expand Down
36 changes: 20 additions & 16 deletions emulator/src/hbc56emu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,27 +478,29 @@ static int mouseZ = 0;
*/
static void doTick()
{
static double lastTime = 0.0;
static double unusedClockTicksTime = 0.0;
static const double maxTime = 1.0 / 60.0;
static double lastTime = (double)SDL_GetPerformanceCounter() / perfFreq;

double thisTime = (double)SDL_GetPerformanceCounter() / perfFreq;
if ((thisTime - lastTime) > maxTime) lastTime = thisTime - maxTime;
double deltaTime = 0.0001;
uint32_t deltaClockTicks = (uint32_t)(HBC56_CLOCK_FREQ * deltaTime);

double deltaClockTicksDbl = HBC56_CLOCK_FREQ * (thisTime - lastTime) + unusedClockTicksTime;
double currentTime = (double)SDL_GetPerformanceCounter() / perfFreq;

uint32_t deltaClockTicks = (uint32_t)deltaClockTicksDbl;
unusedClockTicksTime = deltaClockTicksDbl - (double)deltaClockTicks;

if (lastTime != 0)
if (currentTime - lastTime > 0.1)
{
for (size_t i = 0; i < deviceCount; ++i)
{
tickDevice(&devices[i], deltaClockTicks, thisTime - lastTime);
}
lastTime = ((double)SDL_GetPerformanceCounter() / perfFreq) + deltaTime;
}
else
{
lastTime += deltaTime;
}

lastTime = thisTime;
while ((currentTime = (double)SDL_GetPerformanceCounter() / perfFreq) < lastTime);


for (size_t i = 0; i < deviceCount; ++i)
{
tickDevice(&devices[i], deltaClockTicks, deltaTime);
}
}


Expand Down Expand Up @@ -1250,7 +1252,9 @@ int main(int argc, char* argv[])
#endif

#if HBC56_HAVE_VIA
debuggerInitVia(hbc56AddDevice(create65C22ViaDevice(HBC56_IO_ADDRESS(HBC56_VIA_PORT), HBC56_VIA_IRQ)));
HBC56Device *viaDevice = hbc56AddDevice(create65C22ViaDevice(HBC56_IO_ADDRESS(HBC56_VIA_PORT), HBC56_VIA_IRQ));
debuggerInitVia(viaDevice);
sync6502CpuDevice(cpuDevice, viaDevice);
#endif

/* initialise audio */
Expand Down
2 changes: 1 addition & 1 deletion emulator/wasm/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
</div>
</div>

<div class="fixed-bottom" style="background:white;text-align:center;font-size:20px;border-top:1px solid black;">HBC-56 Emulator - © 2022 Troy Schrapel - <a href="https://github.com/visrealm/hbc-56">https://github.com/visrealm/hbc-56</a></div>
<div class="fixed-bottom" style="background:white;text-align:center;font-size:20px;border-top:1px solid black;">HBC-56 Emulator - © 2023 Troy Schrapel - <a href="https://github.com/visrealm/hbc-56">https://github.com/visrealm/hbc-56</a></div>
</div>
<script src="hbc56-frontend.js"></script>
<script async src="Hbc56Emu.js"></script>
Expand Down

0 comments on commit 1d787bd

Please sign in to comment.