AppleWin/source/CommonVICE/alarm.h
2014-05-23 22:59:02 +01:00

192 lines
5.6 KiB
C

/*
* alarm.h - Alarm handling.
*
* Written by
* Ettore Perazzoli <ettore@comm2000.it>
* Andreas Boose <viceteam@t-online.de>
*
* This file is part of VICE, the Versatile Commodore Emulator.
* See README for copyright notice.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA.
*
*/
#ifndef _ALARM_H
#define _ALARM_H
#include "..\CommonVICE\types.h"
#define ALARM_CONTEXT_MAX_PENDING_ALARMS 0x100
typedef void (*alarm_callback_t)(CLOCK offset, void *data);
/* An alarm. */
struct alarm_s {
/* Descriptive name of the alarm. */
char *name;
/* Alarm context this alarm is in. */
struct alarm_context_s *context;
/* Callback to be called when the alarm is dispatched. */
alarm_callback_t callback;
/* Index into the pending alarm list. If < 0, the alarm is not
pending. */
int pending_idx;
/* Call data */
void *data;
/* Link to the next and previous alarms in the list. */
struct alarm_s *next, *prev;
};
typedef struct alarm_s alarm_t;
struct pending_alarms_s {
/* The alarm. */
struct alarm_s *alarm;
/* Clock tick at which this alarm should be activated. */
CLOCK clk;
};
typedef struct pending_alarms_s pending_alarms_t;
/* An alarm context. */
struct alarm_context_s {
/* Descriptive name of the alarm context. */
char *name;
/* Alarm list. */
struct alarm_s *alarms;
/* Pending alarm array. Statically allocated because it's slightly
faster this way. */
pending_alarms_t pending_alarms[ALARM_CONTEXT_MAX_PENDING_ALARMS];
unsigned int num_pending_alarms;
/* Clock tick for the next pending alarm. */
CLOCK next_pending_alarm_clk;
/* Pending alarm number. */
int next_pending_alarm_idx;
};
typedef struct alarm_context_s alarm_context_t;
/* ------------------------------------------------------------------------ */
extern alarm_context_t *alarm_context_new(const char *name);
extern void alarm_context_init(alarm_context_t *context, const char *name);
extern void alarm_context_destroy(alarm_context_t *context);
extern void alarm_context_time_warp(alarm_context_t *context, CLOCK warp_amount,
int warp_direction);
extern alarm_t *alarm_new(alarm_context_t *context, const char *name,
alarm_callback_t callback, void *data);
extern void alarm_destroy(alarm_t *alarm);
extern void alarm_unset(alarm_t *alarm);
extern void alarm_log_too_many_alarms(void);
/* ------------------------------------------------------------------------- */
#if 1 //TC
/* Inline functions. */
/*inline*/ static CLOCK alarm_context_next_pending_clk(alarm_context_t *context)
{
return context->next_pending_alarm_clk;
}
/*inline*/ static void alarm_context_update_next_pending(alarm_context_t *context)
{
CLOCK next_pending_alarm_clk = (CLOCK)~0L;
unsigned int next_pending_alarm_idx;
unsigned int i;
next_pending_alarm_idx = context->next_pending_alarm_idx;
for (i = 0; i < context->num_pending_alarms; i++) {
CLOCK pending_clk = context->pending_alarms[i].clk;
if (pending_clk <= next_pending_alarm_clk) {
next_pending_alarm_clk = pending_clk;
next_pending_alarm_idx = i;
}
}
context->next_pending_alarm_clk = next_pending_alarm_clk;
context->next_pending_alarm_idx = next_pending_alarm_idx;
}
/*inline*/ static void alarm_context_dispatch(alarm_context_t *context,
CLOCK cpu_clk)
{
CLOCK offset;
unsigned int idx;
alarm_t *alarm;
offset = (CLOCK)(cpu_clk - context->next_pending_alarm_clk);
idx = context->next_pending_alarm_idx;
alarm = context->pending_alarms[idx].alarm;
(alarm->callback)(offset, alarm->data);
}
/*inline*/ static void alarm_set(alarm_t *alarm, CLOCK cpu_clk)
{
alarm_context_t *context;
int idx;
context = alarm->context;
idx = alarm->pending_idx;
if (idx < 0) {
unsigned int new_idx;
/* Not pending yet: add. */
new_idx = context->num_pending_alarms;
if (new_idx >= ALARM_CONTEXT_MAX_PENDING_ALARMS) {
alarm_log_too_many_alarms();
return;
}
context->pending_alarms[new_idx].alarm = alarm;
context->pending_alarms[new_idx].clk = cpu_clk;
context->num_pending_alarms++;
if (cpu_clk < context->next_pending_alarm_clk) {
context->next_pending_alarm_clk = cpu_clk;
context->next_pending_alarm_idx = new_idx;
}
alarm->pending_idx = new_idx;
} else {
/* Already pending: modify. */
context->pending_alarms[idx].clk = cpu_clk;
if (context->next_pending_alarm_clk > cpu_clk
|| idx == context->next_pending_alarm_idx)
alarm_context_update_next_pending(context);
}
}
#endif // TC
#endif