mirror of
https://github.com/ctm/syn68k.git
synced 2024-11-25 07:32:17 +00:00
104 lines
2.7 KiB
C
104 lines
2.7 KiB
C
|
#include "interrupt.h"
|
||
|
|
||
|
#ifdef SYNCHRONOUS_INTERRUPTS
|
||
|
|
||
|
#include "trap.h"
|
||
|
|
||
|
#ifdef USE_BIOS_TIMER
|
||
|
uint16 dos_memory_selector;
|
||
|
uint32 dos_interrupt_flag_addr;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
void
|
||
|
interrupt_generate (unsigned priority)
|
||
|
{
|
||
|
/* Calling this with a weird priority will just note that an interrupt
|
||
|
* should be checked for.
|
||
|
*/
|
||
|
if (priority >= 1 && priority <= 7)
|
||
|
cpu_state.interrupt_pending[priority] = TRUE;
|
||
|
|
||
|
SET_INTERRUPT_STATUS (INTERRUPT_STATUS_CHANGED);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* This function turns on the global "check for an interrupt" bit if
|
||
|
* any interrupts are currently pending.
|
||
|
*/
|
||
|
void
|
||
|
interrupt_note_if_present ()
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 1; i <= 7; i++)
|
||
|
if (cpu_state.interrupt_pending[i])
|
||
|
{
|
||
|
SET_INTERRUPT_STATUS (INTERRUPT_STATUS_CHANGED);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* This function looks to see if any interrupts of high enough
|
||
|
* priority are pending, and if they are it processes the highest
|
||
|
* priority interrupt. It adjusts the machine state appropriately for
|
||
|
* the interrupt and returns the 68k PC at which execution should
|
||
|
* resume. The INTERRUPT_PC parameter specifies the address
|
||
|
* of the 68k instruction about to be executed when the interrupt
|
||
|
* was detected.
|
||
|
*/
|
||
|
syn68k_addr_t
|
||
|
interrupt_process_any_pending (syn68k_addr_t interrupt_pc)
|
||
|
{
|
||
|
int priority;
|
||
|
syn68k_addr_t continuation_pc;
|
||
|
int cpu_priority;
|
||
|
|
||
|
/* First note that the interrupt has been processed. The RTE
|
||
|
* will end up causing another check when it reloads the SR, so
|
||
|
* we shouldn't miss any interrupts.
|
||
|
*/
|
||
|
SET_INTERRUPT_STATUS (INTERRUPT_STATUS_UNCHANGED);
|
||
|
|
||
|
/* Determine if any interrupt with high enough priority is pending. */
|
||
|
cpu_priority = (cpu_state.sr >> 8) & 7;
|
||
|
if (cpu_state.interrupt_pending[7])
|
||
|
priority = 7; /* Priority 7 interrupt cannot be masked. */
|
||
|
else
|
||
|
{
|
||
|
for (priority = 6; priority > cpu_priority; priority--)
|
||
|
if (cpu_state.interrupt_pending[priority])
|
||
|
break;
|
||
|
if (priority <= cpu_priority)
|
||
|
priority = -1;
|
||
|
}
|
||
|
|
||
|
#ifdef USE_BIOS_TIMER
|
||
|
/* The BIOS has no way of specifying the interrupt priority when
|
||
|
* an interrupt comes in. Therefore if we don't see any other
|
||
|
* explicitly specified interrupts, we'll assume it must have been
|
||
|
* a timer interrupt and act accordingly.
|
||
|
*/
|
||
|
if (priority == -1 && cpu_priority < M68K_TIMER_PRIORITY)
|
||
|
priority = M68K_TIMER_PRIORITY;
|
||
|
#endif
|
||
|
|
||
|
/* Did we find an interrupt of high enough priority? */
|
||
|
if (priority != -1)
|
||
|
{
|
||
|
/* Process the interrupt. */
|
||
|
cpu_state.interrupt_pending[priority] = 0;
|
||
|
continuation_pc = trap_direct (24 + priority, interrupt_pc, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Nothing interesting after all, so just return unchanged. */
|
||
|
continuation_pc = interrupt_pc;
|
||
|
}
|
||
|
|
||
|
return continuation_pc;
|
||
|
}
|
||
|
|
||
|
#endif /* SYNCHRONOUS_INTERRUPTS */
|