mirror of
https://github.com/ctm/executor.git
synced 2024-09-25 22:56:22 +00:00
634 lines
17 KiB
C
634 lines
17 KiB
C
/* Copyright 1995, 1996 by Abacus Research and
|
|
* Development, Inc. All rights reserved.
|
|
*/
|
|
|
|
#if !defined (OMIT_RCSID_STRINGS)
|
|
char ROMlib_rcsid_syncint[] =
|
|
"$Id: syncint.c 97 2005-06-22 20:08:38Z ctm $";
|
|
#endif
|
|
|
|
#include "rsys/common.h"
|
|
|
|
/* We only have synchronous interrupts under syn68k. */
|
|
#if defined (SYN68K)
|
|
|
|
#include "rsys/syncint.h"
|
|
#include "rsys/blockinterrupts.h"
|
|
|
|
#if defined (CYGWIN32)
|
|
#include "win_queue.h"
|
|
#include "rsys/m68kint.h"
|
|
#endif
|
|
|
|
#if defined (MSDOS)
|
|
|
|
#include <go32.h>
|
|
#include <dpmi.h>
|
|
#include "dpmilock.h"
|
|
#include "dosmem.h"
|
|
#include "dpmicall.h"
|
|
#include "rmint70.h"
|
|
|
|
#define BIOS_SET_EVENT_WAIT 0x8300
|
|
#define BIOS_CLEAR_EVENT_WAIT 0x8301
|
|
|
|
|
|
#define TIMER_INT_NUM 0x70
|
|
#define WATCHDOG_INT_NUM 0x08
|
|
|
|
/* This is the old timer interrupt handler. These cannot be static
|
|
* because they are used by the interrupt asm code.
|
|
*/
|
|
__dpmi_paddr old_watchdog_handler;
|
|
__dpmi_paddr old_pm_timer_handler;
|
|
__dpmi_raddr old_rm_timer_handler;
|
|
|
|
uint16 rm_timer_handler_sel;
|
|
|
|
/* Here's our new one. */
|
|
static __dpmi_paddr new_watchdog_handler;
|
|
static __dpmi_paddr new_pm_timer_handler;
|
|
static __dpmi_raddr new_rm_timer_handler;
|
|
|
|
/* TRUE if we shouldn't get concerned if the 1024 Hz clock isn't
|
|
* working well, e.g. during disk accesses.
|
|
*/
|
|
static boolean_t expect_slow_clock_p;
|
|
|
|
/* These variables are referenced in our interrupt handlers. */
|
|
volatile uint32 watchdog_last_elapsed_1024 = -1;
|
|
volatile uint32 slow_clock_count;
|
|
uint8 use_bios_timer_p = TRUE;
|
|
|
|
#define ELAPSED_1024_OFFSET 0
|
|
#define ELAPSED_1024_OFFSET_STR "0"
|
|
#define REMAINING_1024_OFFSET 4
|
|
#define REMAINING_1024_OFFSET_STR "4"
|
|
|
|
void
|
|
_dummy_timer_asm_function_ (void)
|
|
{
|
|
/* We put this asm in a dummy function so we can pass it "arguments"
|
|
* to let it reference cpu_state fields.
|
|
*/
|
|
asm (
|
|
/* We maintain two distinct timer interrupts: "timer" and "watchdog".
|
|
* "timer" is a 1024 Hz interrupt which the BIOS sometimes turns off.
|
|
* "watchdog" is an 18.2 Hz interrupt that checks to see if "timer"
|
|
* has been turned off. If it has, it sets things up so that
|
|
* "timer" will get turned back on. This solution should be fairly
|
|
* robust, although if "timer" gets turned off often then we'll
|
|
* appear to "lose time".
|
|
*
|
|
* If use_bios_p is FALSE, then we exclusively use the 18.2 Hz
|
|
* timer. This may work around some problems with various BIOSes
|
|
* and DPMI providers, although we're not sure.
|
|
*/
|
|
"\n"
|
|
".text\n\t"
|
|
".align 4,0x90\n"
|
|
"_timer_handler_data_start:\n"
|
|
"_handle_watchdog_tick:\n\t"
|
|
|
|
/* Save stuff we're about to clobber. */
|
|
"pushfl\n\t"
|
|
"pushal\n\t"
|
|
"pushl %%ds\n\t"
|
|
"pushl %%es\n\t"
|
|
"pushl %%fs\n\t"
|
|
"pushl %%gs\n\t"
|
|
|
|
/* Set up %ds for protected mode memory. */
|
|
".byte 0x2E\n\t" /* %cs: prefix, for gas botch. */
|
|
QUOTED_DATA16 "movw _dos_pm_interrupt_ds,%%ds\n\t"
|
|
|
|
/* See if any virtual mouse interrupts are pending. */
|
|
"call _dosevq_note_mouse_interrupt\n\t"
|
|
|
|
/* Fetch elapsed 1024ths of a second. */
|
|
"movzwl _rm_timer_handler_sel,%%eax\n\t"
|
|
"testl %%eax,%%eax\n\t"
|
|
"jz 1f\n\t" /* zero selector? bail! */
|
|
QUOTED_DATA16 "movw %%ax,%%fs\n\t"
|
|
".byte 0x64\n\t" /* %fs: prefix */
|
|
"movl " ELAPSED_1024_OFFSET_STR ",%%eax\n\t"
|
|
|
|
/* See if we care about the 1024Hz BIOS timer. */
|
|
"cmpb $0,_use_bios_timer_p\n\t"
|
|
"jz 3f\n\t"
|
|
|
|
/* See if the 1024Hz timer is still running. */
|
|
"cmpl %%eax,_watchdog_last_elapsed_1024\n\t"
|
|
"jz 4f\n\t"
|
|
|
|
/* See if it's running, but very slowly (for WinNT) */
|
|
"pushl %%eax\n\t"
|
|
"subl _watchdog_last_elapsed_1024,%%eax\n\t"
|
|
"cmpl $28,%%eax\n\t" /* We should get about 56 ticks here. */
|
|
"popl %%eax\n\t"
|
|
|
|
"jnge 4f\n\t" /* too slow? */
|
|
|
|
/* Clock is moving quickly enough this time. */
|
|
"movl $0,_slow_clock_count\n\t" /* start "slow count" over */
|
|
"jmp 1f\n"
|
|
|
|
"4:\n\t"
|
|
|
|
/* Note that the clock has not advanced quickly enough here. */
|
|
"incl _slow_clock_count\n\t"
|
|
|
|
/* Indicate a watchdog interrupt. */
|
|
"movb $1,%1\n"
|
|
"movl %3,%2\n\t"
|
|
|
|
"3:\n\t"
|
|
|
|
/* Increment the 1024 Hz clock by 1/18.2 of a second. */
|
|
"addl $56,%%eax\n\t"
|
|
".byte 0x64\n\t" /* %fs: prefix */
|
|
"movl " REMAINING_1024_OFFSET_STR ",%%ebx\n\t"
|
|
".byte 0x64\n\t" /* %fs: prefix */
|
|
"movl %%eax," ELAPSED_1024_OFFSET_STR "\n\t"
|
|
"cmpl $0x80000000,%%ebx\n\t"
|
|
"je 1f\n\t"
|
|
"subl $56,%%ebx\n\t"
|
|
"jnle 8f\n\t"
|
|
"movb $1,%0\n\t"
|
|
"movl %3,%2\n\t"
|
|
"movl $0x80000000,%%ebx\n"
|
|
|
|
"8:\n\t"
|
|
".byte 0x64\n\t" /* %fs: prefix */
|
|
"movl %%ebx," REMAINING_1024_OFFSET_STR "\n\t"
|
|
|
|
/* Restore everything we clobbered. */
|
|
"1:\n\t"
|
|
"movl %%eax,_watchdog_last_elapsed_1024\n\t"
|
|
"popl %%gs\n\t"
|
|
"popl %%fs\n\t"
|
|
"popl %%es\n\t"
|
|
"popl %%ds\n\t"
|
|
"popal\n\t"
|
|
"popfl\n\t"
|
|
|
|
".byte 0x2E\n\t" /* %cs: prefix, for gas botch. */
|
|
"ljmp _old_watchdog_handler\n\t"
|
|
"iret\n\t" /* Not sure why this is necessary, but djgpp does it. */
|
|
|
|
/* This is the timer interrupt handler. It executes the
|
|
* equivalent of this C code:
|
|
*
|
|
* ++elapsed_1024;
|
|
* r1024 = remaining_1024;
|
|
* if (r1024 > 0)
|
|
* {
|
|
* --r1024;
|
|
* remaining_1024 = r1024;
|
|
* if (r1024 <= 0)
|
|
* {
|
|
* SET_INTERRUPT_STATUS (INTERRUPT_STATUS_CHANGED);
|
|
* }
|
|
* }
|
|
*/
|
|
|
|
".align 4,0xcf\n"
|
|
"_handle_timer_tick:\n\t"
|
|
|
|
/* Save stuff we're about to clobber. */
|
|
"pushfl\n\t"
|
|
"pushl %%eax\n\t"
|
|
"pushl %%ds\n\t"
|
|
"pushl %%fs\n\t"
|
|
|
|
/* Set up %%ds for protected mode. */
|
|
".byte 0x2E\n\t" /* %cs: prefix, for gas botch. */
|
|
QUOTED_DATA16 "movw _dos_pm_interrupt_ds,%%ds\n\t"
|
|
|
|
/* Set up %fs appropriately. */
|
|
"movzwl _rm_timer_handler_sel,%%eax\n\t"
|
|
"testl %%eax,%%eax\n\t"
|
|
"je 2f\n\t" /* bail if selector is zero */
|
|
QUOTED_DATA16 "movw %%ax,%%fs\n\t"
|
|
|
|
/* Increment elapsed_1024, and decrement remaining_1024
|
|
* (if appropriate). If remaining_1024 hits zero, then set
|
|
* the interrupt_status_changed bit.
|
|
*/
|
|
".byte 0x64\n\t" /* %fs prefix */
|
|
"movl " REMAINING_1024_OFFSET_STR ",%%eax\n\t"
|
|
".byte 0x64\n\t" /* %fs prefix */
|
|
"incl " ELAPSED_1024_OFFSET_STR "\n\t"
|
|
"cmpl $0x80000000,%%eax\n\t" /* countdown not running? */
|
|
"je 2f\n\t"
|
|
"subl $1,%%eax\n\t" /* decl doesn't set carry */
|
|
"jnle 7f\n\t"
|
|
"movb $1,%0\n\t"
|
|
"movl %3,%2\n\t"
|
|
"movl $0x80000000,%%eax\n"
|
|
|
|
"7:\n\t"
|
|
".byte 0x64\n\t" /* %fs prefix */
|
|
"movl %%eax," REMAINING_1024_OFFSET_STR "\n"
|
|
|
|
"2:\n\t"
|
|
|
|
#if 1
|
|
/* Reset real-time clock timer (docs are extremely shaky here). */
|
|
"movb $0x0C,%%al\n\t"
|
|
"outb %%al,$0x70\n\t"
|
|
"inb $0x71,%%al\n\t"
|
|
|
|
/* Indicate end-of-interrupt to the interrupt controller. */
|
|
"movb $0x20,%%al\n\t"
|
|
"outb %%al,$0xA0\n\t" /* Needed since INT 0x70 is IRQ 8 */
|
|
"outb %%al,$0x20\n\t"
|
|
|
|
/* Restore the stuff we changed. */
|
|
"popl %%fs\n\t"
|
|
"popl %%ds\n\t"
|
|
"popl %%eax\n\t"
|
|
"popfl\n\t"
|
|
|
|
"sti\n\t"
|
|
"iret\n"
|
|
#else
|
|
|
|
/* This is old code you could use if you wanted to chain the
|
|
* interrupt.
|
|
*/
|
|
|
|
/* Restore the stuff we changed. */
|
|
"popl %%fs\n\t"
|
|
"popl %%ds\n\t"
|
|
"popl %%eax\n\t"
|
|
"popfl\n\t"
|
|
|
|
/* Chain on to the next interrupt handler. */
|
|
".byte 0x2E\n\t" /* %cs: prefix, for gas botch. */
|
|
"ljmp _old_pm_timer_handler\n\t"
|
|
"iret\n" /* Not sure why this is necessary, but djgpp does it. */
|
|
#endif
|
|
|
|
"_timer_handler_data_end:\n"
|
|
".text"
|
|
|
|
: "=m" (cpu_state.interrupt_pending[M68K_TIMER_PRIORITY]),
|
|
"=m" (cpu_state.interrupt_pending[M68K_WATCHDOG_PRIORITY]),
|
|
"=m" (cpu_state.interrupt_status_changed)
|
|
: "g" (INTERRUPT_STATUS_CHANGED));
|
|
}
|
|
|
|
|
|
/* Trick the C compiler so it knows about some of these asm symbols. */
|
|
extern char handle_timer_tick, handle_watchdog_tick;
|
|
extern char timer_handler_data_start, timer_handler_data_end;
|
|
|
|
|
|
uint32
|
|
fetch_elapsed_1024 (void)
|
|
{
|
|
uint32 retval;
|
|
|
|
if (rm_timer_handler_sel)
|
|
retval = _farpeekl (rm_timer_handler_sel, ELAPSED_1024_OFFSET);
|
|
else
|
|
retval = 0;
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
void
|
|
set_elapsed_1024 (uint32 v)
|
|
{
|
|
if (rm_timer_handler_sel)
|
|
_farpokel (rm_timer_handler_sel, ELAPSED_1024_OFFSET, v);
|
|
}
|
|
|
|
|
|
static void
|
|
syncint_shutdown (void)
|
|
{
|
|
BLOCK_VIRTUAL_INTERRUPTS_EXCURSION
|
|
({
|
|
__dpmi_regs regs;
|
|
|
|
/* Clear any pending interrupt. */
|
|
syncint_post (0);
|
|
|
|
__dpmi_set_protected_mode_interrupt_vector (WATCHDOG_INT_NUM,
|
|
&old_watchdog_handler);
|
|
__dpmi_set_protected_mode_interrupt_vector (TIMER_INT_NUM,
|
|
&old_pm_timer_handler);
|
|
__dpmi_set_real_mode_interrupt_vector (TIMER_INT_NUM,
|
|
&old_rm_timer_handler);
|
|
|
|
/* Turn off the BIOS event wait, in case anyone else wants it. */
|
|
dpmi_zero_regs (®s);
|
|
regs.x.ax = BIOS_CLEAR_EVENT_WAIT;
|
|
__dpmi_int (0x15, ®s);
|
|
|
|
|
|
/* THIS HAS BEEN DISABLED.
|
|
* Freeing this memory causes Executor to crash on exit under
|
|
* WinNT. It's not clear why; we've already reset all the
|
|
* interrupt vectors and no one should be using this memory once
|
|
* rm_timer_handler_sel is zero.
|
|
*/
|
|
if (0 && rm_timer_handler_sel != 0)
|
|
{
|
|
uint16 sel;
|
|
sel = rm_timer_handler_sel;
|
|
rm_timer_handler_sel = 0; /* just in case of any race condition */
|
|
__dpmi_free_dos_memory (sel);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
/* This routine starts int 0x70 going by turning on a dummy BIOS
|
|
* event wait.
|
|
*/
|
|
static syn68k_addr_t
|
|
restart_timer (syn68k_addr_t interrupt_addr, void *unused)
|
|
{
|
|
if (use_bios_timer_p)
|
|
{
|
|
__dpmi_regs regs;
|
|
|
|
/* See if we've gotten two seconds worth of sluggish 1024 Hz clock
|
|
* ticks in a row. If so, disable that clock and just use the
|
|
* 18 Hz clock. This seems to be needed for WinNT.
|
|
*/
|
|
if (!expect_slow_clock_p && slow_clock_count > 36) /* 18 Hz * 2 == 36 */
|
|
{
|
|
use_bios_timer_p = FALSE;
|
|
__dpmi_set_protected_mode_interrupt_vector (TIMER_INT_NUM,
|
|
&old_pm_timer_handler);
|
|
__dpmi_set_real_mode_interrupt_vector (TIMER_INT_NUM,
|
|
&old_rm_timer_handler);
|
|
warning_unexpected ("1024 Hz timer is unreliable. Switching "
|
|
"to 18 Hz timer. elapsed_1024 = %lu",
|
|
(unsigned long) fetch_elapsed_1024 ());
|
|
}
|
|
else
|
|
{
|
|
/* Start the clock running by turning on a bogus event wait that
|
|
* we never want to finish.
|
|
*/
|
|
dpmi_zero_regs (®s);
|
|
regs.x.ax = BIOS_SET_EVENT_WAIT;
|
|
regs.x.cx = 0x7FFF;
|
|
regs.x.dx = 0xFFFF;
|
|
regs.x.es = 0x40; /* Use the MSB of the BIOS countdown address, */
|
|
regs.x.bx = 0x9C + 3; /* since setting that bit is harmless. */
|
|
if (dpmi_int_check_carry (0x15, ®s))
|
|
{
|
|
/* It won't let us set the 1024 timer! Let's not be rude and
|
|
* clear it; that may be causing problems under Windows. We'll
|
|
* just let the 18.2 Hz watchdog limp along and keep trying to
|
|
* start the clock.
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
return MAGIC_RTE_ADDRESS;
|
|
}
|
|
|
|
|
|
/* Sets a flag indicating whether a slow 1024 Hz clock is acceptable
|
|
* (i.e. we shouldn't turn it off if it seems to be misbehaving).
|
|
*/
|
|
boolean_t
|
|
set_expect_slow_clock (boolean_t will_be_slow_p)
|
|
{
|
|
boolean_t old;
|
|
|
|
old = expect_slow_clock_p;
|
|
if (expect_slow_clock_p != will_be_slow_p)
|
|
{
|
|
if (!will_be_slow_p)
|
|
slow_clock_count = 0;
|
|
expect_slow_clock_p = will_be_slow_p;
|
|
}
|
|
return old;
|
|
}
|
|
|
|
|
|
/* Sets up real-mode memory and handler used for timer stuff. */
|
|
static void
|
|
set_up_rm_timer_stuff (void)
|
|
{
|
|
int sel, seg;
|
|
|
|
seg = __dpmi_allocate_dos_memory ((&rm_int_70_handler_end
|
|
- &rm_int_70_handler_start + 15) / 16,
|
|
&sel);
|
|
if (seg != -1)
|
|
{
|
|
rm_timer_handler_sel = sel;
|
|
|
|
rm_int_70_chain_address = old_rm_timer_handler;
|
|
rm_int_70_seg = seg;
|
|
|
|
/* Copy the timer handler to DOS memory. */
|
|
movedata (dos_pm_ds, (unsigned) &rm_int_70_handler_start,
|
|
sel, 0,
|
|
&rm_int_70_handler_end - &rm_int_70_handler_start);
|
|
|
|
if (use_bios_timer_p)
|
|
{
|
|
/* Make it so that the timer doesn't reflect to us from real
|
|
* mode, which would require a mode switch. Sandmann thinks
|
|
* that setting the RM vector after we set the PM vector
|
|
* will cause RM interrupts not to get reflected to PM.
|
|
* We're doing this as a test because mode switches from RM to
|
|
* PM during disk accesses seem to cause trouble on some
|
|
* machines.
|
|
*/
|
|
new_rm_timer_handler.segment = seg;
|
|
new_rm_timer_handler.offset16 = (&rm_int_70_handler_code_start
|
|
- &rm_int_70_handler_start);
|
|
__dpmi_set_real_mode_interrupt_vector (TIMER_INT_NUM,
|
|
&new_rm_timer_handler);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
syncint_init (void)
|
|
{
|
|
static char beenhere = FALSE;
|
|
syn68k_addr_t watchdog_callback;
|
|
|
|
/* Guard against getting called multiple times. */
|
|
if (beenhere)
|
|
return TRUE;
|
|
beenhere = TRUE;
|
|
|
|
/* Wire down our timer interrupt handler so it won't get paged out. */
|
|
dpmi_lock_memory (&timer_handler_data_start,
|
|
&timer_handler_data_end - &timer_handler_data_start);
|
|
dpmi_lock_memory (&rm_timer_handler_sel, sizeof rm_timer_handler_sel);
|
|
dpmi_lock_memory (&old_watchdog_handler, sizeof old_watchdog_handler);
|
|
dpmi_lock_memory (&old_pm_timer_handler, sizeof old_pm_timer_handler);
|
|
dpmi_lock_memory (&old_rm_timer_handler, sizeof old_rm_timer_handler);
|
|
dpmi_lock_memory ((void *)&use_bios_timer_p, sizeof use_bios_timer_p);
|
|
dpmi_lock_memory ((void *)&slow_clock_count, sizeof slow_clock_count);
|
|
dpmi_lock_memory ((void *)&watchdog_last_elapsed_1024,
|
|
sizeof watchdog_last_elapsed_1024);
|
|
|
|
/* Set up the m68k trap vector for the watchdog interrupt. */
|
|
watchdog_callback = callback_install (restart_timer, NULL);
|
|
*(syn68k_addr_t *)SYN68K_TO_US(M68K_WATCHDOG_VECTOR * 4) = CL (watchdog_callback);
|
|
|
|
/* Fetch the old interrupt handlers. */
|
|
__dpmi_get_real_mode_interrupt_vector (TIMER_INT_NUM, &old_rm_timer_handler);
|
|
__dpmi_get_protected_mode_interrupt_vector (TIMER_INT_NUM,
|
|
&old_pm_timer_handler);
|
|
__dpmi_get_protected_mode_interrupt_vector (WATCHDOG_INT_NUM,
|
|
&old_watchdog_handler);
|
|
|
|
/* Set up real-mode timer memory. */
|
|
set_up_rm_timer_stuff ();
|
|
|
|
if (use_bios_timer_p)
|
|
{
|
|
new_pm_timer_handler.offset32 = (unsigned long) &handle_timer_tick;
|
|
new_pm_timer_handler.selector = dos_pm_cs;
|
|
__dpmi_set_protected_mode_interrupt_vector (TIMER_INT_NUM,
|
|
&new_pm_timer_handler);
|
|
|
|
/* Start the 1024 Hz clock running. */
|
|
restart_timer (0, NULL);
|
|
}
|
|
|
|
/* Install the new watchdog interrupt handler. */
|
|
new_watchdog_handler.offset32 = (unsigned long) &handle_watchdog_tick;
|
|
new_watchdog_handler.selector = dos_pm_cs;
|
|
__dpmi_set_protected_mode_interrupt_vector (WATCHDOG_INT_NUM,
|
|
&new_watchdog_handler);
|
|
|
|
atexit (syncint_shutdown);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* Posting a delay of 0 will clear any pending interrupt. */
|
|
void
|
|
syncint_post (unsigned long usecs)
|
|
{
|
|
long new;
|
|
|
|
if (rm_timer_handler_sel)
|
|
{
|
|
if (usecs == 0)
|
|
new = 0x80000000; /* magic value meaning timer is stopped. */
|
|
else
|
|
{
|
|
/* Convert usecs to 1024ths of a second, rounding up. */
|
|
new = (usecs * 16 + 15624) / 15625;/* 16 / 15625 == 1024 / 1000000 */
|
|
if (new <= 0)
|
|
new = 1;
|
|
}
|
|
|
|
_farpokel (rm_timer_handler_sel, REMAINING_1024_OFFSET, new);
|
|
}
|
|
}
|
|
|
|
#else /* !MSDOS */
|
|
|
|
|
|
#if defined (SDL)
|
|
|
|
static Uint32
|
|
handle_sdltimer_tick (Uint32 n)
|
|
{
|
|
// fprintf (stderr, "T");
|
|
// fflush (stderr);
|
|
#if defined (CYGWIN32)
|
|
win_queue(&cpu_state.interrupt_pending[M68K_EVENT_PRIORITY]);
|
|
#endif
|
|
cpu_state.interrupt_pending[M68K_TIMER_PRIORITY] = TRUE;
|
|
SET_INTERRUPT_STATUS (INTERRUPT_STATUS_CHANGED);
|
|
// SDL_mutexP (ROMlib_shouldbeawake_mutex);
|
|
SDL_CondSignal (ROMlib_shouldbeawake_cond);
|
|
// SDL_mutexV (ROMlib_shouldbeawake_mutex);
|
|
|
|
#if !defined (SDL_TIMER_FIXED)
|
|
#warning returning 1 here to work around SDL timer bug(s)
|
|
return 1;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
static void
|
|
handle_itimer_tick (int n)
|
|
{
|
|
cpu_state.interrupt_pending[M68K_TIMER_PRIORITY] = TRUE;
|
|
SET_INTERRUPT_STATUS (INTERRUPT_STATUS_CHANGED);
|
|
}
|
|
|
|
#endif
|
|
|
|
int
|
|
syncint_init (void)
|
|
{
|
|
#if defined (SDL)
|
|
|
|
return (SDL_Init(SDL_INIT_TIMER) == 0);
|
|
|
|
#else /* !SDL */
|
|
|
|
#if !defined(USE_BSD_SIGNALS)
|
|
|
|
struct sigaction s;
|
|
|
|
s.sa_handler = handle_itimer_tick;
|
|
sigemptyset(&s.sa_mask);
|
|
s.sa_flags = 0;
|
|
s.sa_restorer = NULL;
|
|
return (sigaction (SIGALRM, &s, NULL) == 0);
|
|
|
|
#else
|
|
struct sigvec s;
|
|
|
|
s.sv_handler = handle_itimer_tick;
|
|
s.sv_mask = 0;
|
|
s.sv_flags = 0;
|
|
return sigvec (SIGALRM, &s, NULL) == 0;
|
|
#endif
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
/* Posting a delay of 0 will clear any pending interrupt. */
|
|
void
|
|
syncint_post (unsigned long usecs)
|
|
{
|
|
#if defined (SDL)
|
|
// fprintf (stderr, "P(%ul)", usecs);
|
|
// fflush (stderr);
|
|
SDL_SetTimer(usecs/1000, handle_sdltimer_tick);
|
|
#else
|
|
struct itimerval t;
|
|
|
|
t.it_value.tv_sec = usecs / 1000000;
|
|
t.it_value.tv_usec = usecs % 1000000;
|
|
t.it_interval.tv_sec = 0;
|
|
t.it_interval.tv_usec = 0;
|
|
setitimer (ITIMER_REAL, &t, NULL);
|
|
#endif
|
|
}
|
|
|
|
#endif /* !MSDOS */
|
|
|
|
#endif /* SYN68K */
|