Closed dirkwhoffmann closed 4 years ago
I need to think about it in more detail, but the most obvious solution might be to simply skip the exec call in Moira::execute() if a trace or interrupt exception has occurred.
void
Moira::execute()
{
// Process execution flags (if any)
if (flags) {
// Process pending trace exception (if any)
if (flags & CPU_TRACE_EXCEPTION) {
execTraceException();
}
// Check if the T flag is set inside the status register
if (flags & CPU_TRACE_FLAG) {
flags |= CPU_TRACE_EXCEPTION;
>>> ADD LINE: goto exit;
}
// Process pending interrupt (if any)
if (flags & CPU_CHECK_IRQ) {
checkForIrq();
>>> ADD LINE: IF "IRQ HAS TRIGGERED" goto exit;
}
// If the CPU is stopped, poll the IPL lines and return
if (flags & CPU_IS_STOPPED) {
pollIrq();
sync(MIMIC_MUSASHI ? 1 : 2);
return;
}
// If logging is enabled, record the executed instruction
if (flags & CPU_LOG_INSTRUCTION) {
debugger.logInstruction();
}
}
// Execute the instruction
reg.pc += 2;
(this->*exec[queue.ird])(queue.ird);
>>> ADD LABEL: exit:
// Check if a breakpoint has been reached
if (debugger.breakpoints.needsCheck)
if (debugger.breakpointMatches(reg.pc)) breakpointReached(reg.pc);
}
@elmerucr: I think I have a decent fix for the breakpoint issue. My plan is to change the execution function as follows:
void
Moira::execute()
{
//
// The quick execution path: Call the instruction handler and return
//
if (!flags) {
reg.pc += 2;
(this->*exec[queue.ird])(queue.ird);
return;
}
//
// The slow execution path: Process flags one by one
//
// Process pending trace exception (if any)
if (flags & CPU_TRACE_EXCEPTION) {
execTraceException();
goto done;
}
// Check if the T flag is set inside the status register
if (flags & CPU_TRACE_FLAG) {
flags |= CPU_TRACE_EXCEPTION;
}
// Process pending interrupt (if any)
if (flags & CPU_CHECK_IRQ) {
if (checkForIrq()) goto done;
}
// If the CPU is stopped, poll the IPL lines and return
if (flags & CPU_IS_STOPPED) {
pollIrq();
sync(MIMIC_MUSASHI ? 1 : 2);
return;
}
// If logging is enabled, record the executed instruction
if (flags & CPU_LOG_INSTRUCTION) {
debugger.logInstruction();
}
// Execute the instruction
reg.pc += 2;
(this->*exec[queue.ird])(queue.ird);
done:
// Check if a breakpoint has been reached
if (flags & CPU_CHECK_BP)
if (debugger.breakpointMatches(reg.pc)) breakpointReached(reg.pc);
}
In addition to returning directly from this function after executing an exception condition, I have moved breakpoint checking into the "slow execution path". Now, the "quick execution path" only consists of a single call to the instruction handler which should slightly speed up emulation (I guess, the quick execution path is called 99% of the time under normal operating conditions).
I haven't checked in the code yet, but I did some experiments with it in vAmiga. With the new code, I was successful to interrupt the CPU right at the beginning of the VBLANK IRQ handler.
Looks like a good solution! Are you going to commit the changes to the repository?
New code has been checked in and uploaded.
Thanks, code works great so far!
Posted by Elmer: