1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-05-01 22:07:31 +00:00

SCP: Updated to current version

This commit is contained in:
Richard Cornwell
2017-03-12 11:02:04 -04:00
parent 719c19c660
commit 7b42641606
23 changed files with 6164 additions and 2149 deletions

View File

@@ -243,8 +243,15 @@ typedef uint32 t_addr;
#if defined (_WIN32) /* Actually, a GCC issue */
#define LL_FMT "I64"
#define LL_TYPE long long
#else
#if defined (__VAX) /* No 64 bit ints on VAX */
#define LL_FMT "l"
#define LL_TYPE long
#else
#define LL_FMT "ll"
#define LL_TYPE long long
#endif
#endif
#if defined (VMS) && (defined (__ia64) || defined (__ALPHA))
@@ -267,10 +274,13 @@ typedef uint32 t_addr;
#if defined(_MSC_VER)
#define SIM_INLINE _inline
#define SIM_NOINLINE _declspec (noinline)
#elif defined(__GNUC__)
#define SIM_INLINE inline
#define SIM_NOINLINE __attribute__ ((noinline))
#else
#define SIM_INLINE
#define SIM_NOINLINE
#endif
/* Storage class modifier for weak link definition for sim_vm_init() */
@@ -301,8 +311,8 @@ typedef uint32 t_addr;
/* Breakpoint spaces definitions */
#define SIM_BKPT_N_SPC 16 /* max number spaces */
#define SIM_BKPT_V_SPC 28 /* location in arg */
#define SIM_BKPT_N_SPC (1 << (32 - SIM_BKPT_V_SPC)) /* max number spaces */
#define SIM_BKPT_V_SPC (BRK_TYP_MAX + 1) /* location in arg */
/* Extended switch definitions (bits >= 26) */
@@ -310,6 +320,7 @@ typedef uint32 t_addr;
#define SIM_SW_REST (1u << 27) /* attach/restore */
#define SIM_SW_REG (1u << 28) /* register value */
#define SIM_SW_STOP (1u << 29) /* stop message */
#define SIM_SW_SHUT (1u << 30) /* shutdown */
/* Simulator status codes
@@ -366,9 +377,10 @@ typedef uint32 t_addr;
#define SCPE_INVREM (SCPE_BASE + 43) /* invalid remote console command */
#define SCPE_NOTATT (SCPE_BASE + 44) /* not attached */
#define SCPE_EXPECT (SCPE_BASE + 45) /* expect matched */
#define SCPE_REMOTE (SCPE_BASE + 46) /* remote console command */
#define SCPE_AMBREG (SCPE_BASE + 46) /* ambiguous register */
#define SCPE_REMOTE (SCPE_BASE + 47) /* remote console command */
#define SCPE_MAX_ERR (SCPE_BASE + 47) /* Maximum SCPE Error Value */
#define SCPE_MAX_ERR (SCPE_BASE + 48) /* Maximum SCPE Error Value */
#define SCPE_KFLAG 0x1000 /* tti data flag */
#define SCPE_BREAK 0x2000 /* tti break flag */
#define SCPE_NOMESSAGE 0x10000000 /* message display supression flag */
@@ -397,7 +409,7 @@ typedef uint32 t_addr;
/* String match - at least one character required */
#define MATCH_CMD(ptr,cmd) ((NULL == (ptr)) || (!*(ptr)) || strncmp ((ptr), (cmd), strlen (ptr)))
#define MATCH_CMD(ptr,cmd) ((NULL == (ptr)) || (!*(ptr)) || sim_strncasecmp ((ptr), (cmd), strlen (ptr)))
/* End of Linked List/Queue value */
/* Chosen for 2 reasons: */
@@ -418,11 +430,13 @@ typedef struct SHTAB SHTAB;
typedef struct MTAB MTAB;
typedef struct SCHTAB SCHTAB;
typedef struct BRKTAB BRKTAB;
typedef struct BRKTYPTAB BRKTYPTAB;
typedef struct EXPTAB EXPTAB;
typedef struct EXPECT EXPECT;
typedef struct SEND SEND;
typedef struct DEBTAB DEBTAB;
typedef struct FILEREF FILEREF;
typedef struct MEMFILE MEMFILE;
typedef struct BITFIELD BITFIELD;
typedef t_stat (*ACTIVATE_API)(UNIT *unit, int32 interval);
@@ -465,6 +479,7 @@ struct DEVICE {
/* attach help */
void *help_ctx; /* Context available to help routines */
const char *(*description)(DEVICE *dptr); /* Device Description */
BRKTYPTAB *brk_types; /* Breakpoint types */
};
/* Device flags */
@@ -538,10 +553,12 @@ struct UNIT {
void *up7; /* device specific */
void *up8; /* device specific */
void *tmxr; /* TMXR linkage */
t_bool (*cancel)(UNIT *);
double usecs_remaining; /* time balance for long delays */
char *uname; /* Unit name */
#ifdef SIM_ASYNCH_IO
void (*a_check_completion)(UNIT *);
t_bool (*a_is_active)(UNIT *);
void (*a_cancel)(UNIT *);
UNIT *a_next; /* next asynch active */
int32 a_event_time;
ACTIVATE_API a_activate_call;
@@ -552,9 +569,8 @@ struct UNIT {
/* waiting for this unit */
/* Asynchronous Timer control */
double a_due_time; /* due time for timer event */
double a_skew; /* accumulated skew being corrected */
double a_last_fired_time; /* time last event fired */
int32 a_usec_delay; /* time delay for timer event */
double a_due_gtime; /* due time (in instructions) for timer event */
double a_usec_delay; /* time delay for timer event */
#endif
};
@@ -593,7 +609,8 @@ struct UNIT {
#define UNIT_TM_POLL 0000002 /* TMXR Polling unit */
#define UNIT_NO_FIO 0000004 /* fileref is NOT a FILE * */
#define UNIT_DISK_CHK 0000010 /* disk data debug checking (sim_disk) */
#define UNIT_V_DF_TAPE 4 /* Bit offset for Tape Density reservation */
#define UNIT_TMR_UNIT 0000020 /* Unit registered as a calibrated timer */
#define UNIT_V_DF_TAPE 5 /* Bit offset for Tape Density reservation */
#define UNIT_S_DF_TAPE 3 /* Bits Reserved for Tape Density */
struct BITFIELD {
@@ -713,13 +730,26 @@ struct SCHTAB {
struct BRKTAB {
t_addr addr; /* address */
uint32 typ; /* mask of types */
#define BRK_TYP_USR_TYPES ((1 << ('Z'-'A'+1)) - 1)/* all types A-Z */
#define BRK_TYP_DYN_STEPOVER (SWMASK ('Z'+1))
#define BRK_TYP_DYN_USR (SWMASK ('Z'+2))
#define BRK_TYP_DYN_ALL (BRK_TYP_DYN_USR|BRK_TYP_DYN_STEPOVER) /* Mask of All Dynamic types */
#define BRK_TYP_TEMP (SWMASK ('Z'+3)) /* Temporary (one-shot) */
#define BRK_TYP_MAX (('Z'-'A')+3) /* Maximum breakpoint type */
int32 cnt; /* proceed count */
char *act; /* action string */
double time_fired[SIM_BKPT_N_SPC]; /* instruction count when match occurred */
BRKTAB *next; /* list with same address value */
};
/* Breakpoint table */
struct BRKTYPTAB {
uint32 btyp; /* type mask */
const char *desc; /* description */
};
#define BRKTYPE(typ,descrip) {SWMASK(typ), descrip}
/* Expect rule */
struct EXPTAB {
@@ -786,13 +816,18 @@ struct DEBTAB {
#define SIM_DBG_ACTIVATE 0x20000
#define SIM_DBG_AIO_QUEUE 0x40000
/* File Reference */
/* Open File Reference */
struct FILEREF {
char name[CBUFSIZE]; /* file name */
FILE *file; /* file handle */
int32 refcount; /* reference count */
};
struct MEMFILE {
char *buf; /* buffered data */
size_t size; /* size */
size_t pos; /* data used */
};
/*
The following macros exist to help populate structure contents
@@ -915,6 +950,8 @@ struct FILEREF {
#if defined (SIM_ASYNCH_IO)
#include <pthread.h>
#define SIM_ASYNCH_CLOCKS 1
extern pthread_mutex_t sim_asynch_lock;
extern pthread_cond_t sim_asynch_wake;
extern pthread_mutex_t sim_timer_lock;
@@ -925,8 +962,6 @@ extern pthread_cond_t sim_tmxr_poll_cond;
extern pthread_mutex_t sim_tmxr_poll_lock;
extern pthread_t sim_asynch_main_threadid;
extern UNIT * volatile sim_asynch_queue;
extern UNIT * volatile sim_wallclock_queue;
extern UNIT * volatile sim_wallclock_entry;
extern volatile t_bool sim_idle_wait;
extern int32 sim_asynch_check;
extern int32 sim_asynch_latency;
@@ -942,198 +977,43 @@ extern int32 sim_asynch_inst_latency;
/* It is primarily used only used in debugging messages */
#define AIO_TLS
#endif
#define AIO_QUEUE_CHECK(que, lock) \
if (1) { \
UNIT *_cptr; \
if (lock) \
pthread_mutex_lock (lock); \
for (_cptr = que; \
(_cptr != QUEUE_LIST_END); \
_cptr = _cptr->next) \
if (!_cptr->next) { \
if (sim_deb) { \
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Queue Corruption detected\n");\
fclose(sim_deb); \
} \
sim_printf("Queue Corruption detected\n"); \
abort(); \
} \
if (lock) \
pthread_mutex_unlock (lock); \
} else (void)0
#define AIO_QUEUE_CHECK(que, lock) \
do { \
UNIT *_cptr; \
if (lock) \
pthread_mutex_lock (lock); \
for (_cptr = que; \
(_cptr != QUEUE_LIST_END); \
_cptr = _cptr->next) \
if (!_cptr->next) { \
if (sim_deb) { \
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Queue Corruption detected\n");\
fclose(sim_deb); \
} \
sim_printf("Queue Corruption detected\n"); \
abort(); \
} \
if (lock) \
pthread_mutex_unlock (lock); \
} while (0)
#define AIO_MAIN_THREAD (pthread_equal ( pthread_self(), sim_asynch_main_threadid ))
#define AIO_LOCK \
pthread_mutex_lock(&sim_asynch_lock)
#define AIO_UNLOCK \
pthread_mutex_unlock(&sim_asynch_lock)
#define AIO_IS_ACTIVE(uptr) (((uptr)->a_is_active ? (uptr)->a_is_active (uptr) : FALSE) || ((uptr)->a_next))
#if !defined(SIM_ASYNCH_MUX) && !defined(SIM_ASYNCH_CLOCKS)
#define AIO_CANCEL(uptr) \
if ((uptr)->a_cancel) \
(uptr)->a_cancel (uptr); \
else \
(void)0
#endif /* !defined(SIM_ASYNCH_MUX) && !defined(SIM_ASYNCH_CLOCKS) */
#if !defined(SIM_ASYNCH_MUX) && defined(SIM_ASYNCH_CLOCKS)
#define AIO_CANCEL(uptr) \
if ((uptr)->a_cancel) \
(uptr)->a_cancel (uptr); \
else { \
AIO_UPDATE_QUEUE; \
if ((uptr)->a_next) { \
UNIT *cptr; \
pthread_mutex_lock (&sim_timer_lock); \
if ((uptr) == sim_wallclock_queue) { \
sim_wallclock_queue = (uptr)->a_next; \
(uptr)->a_next = NULL; \
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Timer Event for %s\n", sim_uname(uptr));\
sim_timer_event_canceled = TRUE; \
pthread_cond_signal (&sim_timer_wake); \
} \
else \
for (cptr = sim_wallclock_queue; \
(cptr != QUEUE_LIST_END); \
cptr = cptr->a_next) \
if (cptr->a_next == (uptr)) { \
cptr->a_next = (uptr)->a_next; \
(uptr)->a_next = NULL; \
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Timer Event for %s\n", sim_uname(uptr));\
break; \
} \
if ((uptr)->a_next == NULL) \
(uptr)->a_due_time = (uptr)->a_usec_delay = 0; \
else { \
int tmr; \
for (tmr=0; tmr<SIM_NTIMERS; tmr++) { \
if ((uptr) == sim_clock_cosched_queue[tmr]) { \
sim_clock_cosched_queue[tmr] = (uptr)->a_next; \
(uptr)->a_next = NULL; \
} \
else \
for (cptr = sim_clock_cosched_queue[tmr]; \
(cptr != QUEUE_LIST_END); \
cptr = cptr->a_next) \
if (cptr->a_next == (uptr)) { \
cptr->a_next = (uptr)->a_next; \
(uptr)->a_next = NULL; \
break; \
} \
if ((uptr)->a_next == NULL) { \
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Clock Coscheduling Event for %s\n", sim_uname(uptr));\
} \
} \
} \
while (sim_timer_event_canceled) { \
pthread_mutex_unlock (&sim_timer_lock); \
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Waiting for Timer Event cancelation for %s\n", sim_uname(uptr));\
sim_os_ms_sleep (0); \
pthread_mutex_lock (&sim_timer_lock); \
} \
pthread_mutex_unlock (&sim_timer_lock); \
} \
#if defined(SIM_ASYNCH_MUX)
#define AIO_CANCEL(uptr) \
if (((uptr)->dynflags & UNIT_TM_POLL) && \
!((uptr)->next) && !((uptr)->a_next)) { \
(uptr)->a_polling_now = FALSE; \
sim_tmxr_poll_count -= (uptr)->a_poll_waiter_count; \
(uptr)->a_poll_waiter_count = 0; \
}
#endif
#if defined(SIM_ASYNCH_MUX) && !defined(SIM_ASYNCH_CLOCKS)
#define AIO_CANCEL(uptr) \
if ((uptr)->a_cancel) \
(uptr)->a_cancel (uptr); \
else { \
if (((uptr)->dynflags & UNIT_TM_POLL) && \
!((uptr)->next) && !((uptr)->a_next)) { \
(uptr)->a_polling_now = FALSE; \
sim_tmxr_poll_count -= (uptr)->a_poll_waiter_count; \
(uptr)->a_poll_waiter_count = 0; \
} \
}
#endif /* defined(SIM_ASYNCH_MUX) && !defined(SIM_ASYNCH_CLOCKS) */
#if defined(SIM_ASYNCH_MUX) && defined(SIM_ASYNCH_CLOCKS)
#define AIO_CANCEL(uptr) \
if ((uptr)->a_cancel) \
(uptr)->a_cancel (uptr); \
else { \
AIO_UPDATE_QUEUE; \
if (((uptr)->dynflags & UNIT_TM_POLL) && \
!((uptr)->next) && !((uptr)->a_next)) { \
(uptr)->a_polling_now = FALSE; \
sim_tmxr_poll_count -= (uptr)->a_poll_waiter_count; \
(uptr)->a_poll_waiter_count = 0; \
} \
if ((uptr)->a_next) { \
UNIT *cptr; \
pthread_mutex_lock (&sim_timer_lock); \
if ((uptr) == sim_wallclock_queue) { \
sim_wallclock_queue = (uptr)->a_next; \
(uptr)->a_next = NULL; \
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Timer Event for %s\n", sim_uname(uptr));\
sim_timer_event_canceled = TRUE; \
pthread_cond_signal (&sim_timer_wake); \
} \
else \
for (cptr = sim_wallclock_queue; \
(cptr != QUEUE_LIST_END); \
cptr = cptr->a_next) \
if (cptr->a_next == (uptr)) { \
cptr->a_next = (uptr)->a_next; \
(uptr)->a_next = NULL; \
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Timer Event for %s\n", sim_uname(uptr));\
break; \
} \
if ((uptr)->a_next == NULL) \
(uptr)->a_due_time = (uptr)->a_usec_delay = 0; \
else { \
if ((uptr) == sim_clock_cosched_queue) { \
sim_clock_cosched_queue = (uptr)->a_next; \
(uptr)->a_next = NULL; \
} \
else \
for (cptr = sim_clock_cosched_queue; \
(cptr != QUEUE_LIST_END); \
cptr = cptr->a_next) \
if (cptr->a_next == (uptr)) { \
cptr->a_next = (uptr)->a_next; \
(uptr)->a_next = NULL; \
break; \
} \
if ((uptr)->a_next == NULL) { \
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Clock Coscheduling Event for %s\n", sim_uname(uptr));\
} \
} \
while (sim_timer_event_canceled) { \
pthread_mutex_unlock (&sim_timer_lock); \
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Waiting for Timer Event cancelation for %s\n", sim_uname(uptr));\
sim_os_ms_sleep (0); \
pthread_mutex_lock (&sim_timer_lock); \
} \
pthread_mutex_unlock (&sim_timer_lock); \
} \
}
#endif
#if defined(SIM_ASYNCH_CLOCKS)
#define AIO_RETURN_TIME(uptr) \
if (1) { \
pthread_mutex_lock (&sim_timer_lock); \
for (cptr = sim_wallclock_queue; \
cptr != QUEUE_LIST_END; \
cptr = cptr->a_next) \
if ((uptr) == cptr) { \
double inst_per_sec = sim_timer_inst_per_sec (); \
int32 result; \
\
result = (int32)(((uptr)->a_due_time - sim_timenow_double())*inst_per_sec);\
if (result < 0) \
result = 0; \
pthread_mutex_unlock (&sim_timer_lock); \
return result + 1; \
} \
pthread_mutex_unlock (&sim_timer_lock); \
if ((uptr)->a_next) /* On asynch queue? */ \
return (uptr)->a_event_time + 1; \
} \
else \
(void)0
#else
#define AIO_RETURN_TIME(uptr) (void)0
#endif
#endif /* defined(SIM_ASYNCH_MUX) */
#if !defined(AIO_CANCEL)
#define AIO_CANCEL(uptr)
#endif /* !defined(AIO_CANCEL) */
#define AIO_EVENT_BEGIN(uptr) \
do { \
int __was_poll = uptr->dynflags & UNIT_TM_POLL
@@ -1170,33 +1050,27 @@ extern int32 sim_asynch_inst_latency;
/* This approach uses intrinsics to manage access to the link list head */
/* sim_asynch_queue. This implementation is a completely lock free design */
/* which avoids the potential ABA issues. */
#define AIO_QUEUE_MODE "Lock free asynchronous event queue access"
#define AIO_QUEUE_MODE "Lock free asynchronous event queue"
#define AIO_INIT \
if (1) { \
do { \
int tmr; \
sim_asynch_main_threadid = pthread_self(); \
/* Empty list/list end uses the point value (void *)1. \
This allows NULL in an entry's a_next pointer to \
indicate that the entry is not currently in any list */ \
sim_asynch_queue = QUEUE_LIST_END; \
sim_wallclock_queue = QUEUE_LIST_END; \
sim_wallclock_entry = NULL; \
for (tmr=0; tmr<SIM_NTIMERS; tmr++) \
sim_clock_cosched_queue[tmr] = QUEUE_LIST_END; \
} \
else \
(void)0
} while (0)
#define AIO_CLEANUP \
if (1) { \
do { \
pthread_mutex_destroy(&sim_asynch_lock); \
pthread_cond_destroy(&sim_asynch_wake); \
pthread_mutex_destroy(&sim_timer_lock); \
pthread_cond_destroy(&sim_timer_wake); \
pthread_mutex_destroy(&sim_tmxr_poll_lock); \
pthread_cond_destroy(&sim_tmxr_poll_cond); \
} \
else \
(void)0
} while (0)
#ifdef _WIN32
#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
#define InterlockedCompareExchangePointer(Destination, Exchange, Comparand) __sync_val_compare_and_swap(Destination, Comparand, Exchange)
@@ -1205,100 +1079,23 @@ extern int32 sim_asynch_inst_latency;
#else
#error "Implementation of function InterlockedCompareExchangePointer() is needed to build with USE_AIO_INTRINSICS"
#endif
#define AIO_ILOCK AIO_LOCK
#define AIO_IUNLOCK AIO_UNLOCK
#define AIO_QUEUE_VAL (UNIT *)(InterlockedCompareExchangePointer((void * volatile *)&sim_asynch_queue, (void *)sim_asynch_queue, NULL))
#define AIO_QUEUE_SET(val, queue) (UNIT *)(InterlockedCompareExchangePointer((void * volatile *)&sim_asynch_queue, (void *)val, queue))
#define AIO_UPDATE_QUEUE \
if (AIO_QUEUE_VAL != QUEUE_LIST_END) { /* List !Empty */ \
UNIT *q, *uptr; \
int32 a_event_time; \
do \
q = AIO_QUEUE_VAL; \
while (q != AIO_QUEUE_SET(QUEUE_LIST_END, q)); \
while (q != QUEUE_LIST_END) { /* List !Empty */ \
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Migrating Asynch event for %s after %d instructions\n", sim_uname(q), q->a_event_time);\
uptr = q; \
q = q->a_next; \
uptr->a_next = NULL; /* hygiene */ \
if (uptr->a_activate_call != &sim_activate_notbefore) { \
a_event_time = uptr->a_event_time-((sim_asynch_inst_latency+1)/2); \
if (a_event_time < 0) \
a_event_time = 0; \
} \
else \
a_event_time = uptr->a_event_time; \
uptr->a_activate_call (uptr, a_event_time); \
if (uptr->a_check_completion) { \
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Calling Completion Check for asynch event on %s\n", sim_uname(uptr));\
uptr->a_check_completion (uptr); \
} \
} \
} else (void)0
#define AIO_QUEUE_SET(newval, oldval) (UNIT *)(InterlockedCompareExchangePointer((void * volatile *)&sim_asynch_queue, (void *)newval, oldval))
#define AIO_UPDATE_QUEUE sim_aio_update_queue ()
#define AIO_ACTIVATE(caller, uptr, event_time) \
if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) { \
UNIT *ouptr = (uptr); \
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Queueing Asynch event for %s after %d instructions\n", sim_uname(ouptr), event_time);\
if (ouptr->a_next) { \
ouptr->a_activate_call = sim_activate_abs; \
} else { \
UNIT *q, *qe; \
ouptr->a_event_time = event_time; \
ouptr->a_activate_call = (ACTIVATE_API)&caller; \
ouptr->a_next = QUEUE_LIST_END; /* Mark as on list */ \
do { \
do \
q = AIO_QUEUE_VAL; \
while (q != AIO_QUEUE_SET(QUEUE_LIST_END, q));/* Grab current list */\
for (qe = ouptr; qe->a_next != QUEUE_LIST_END; qe = qe->a_next); \
qe->a_next = q; /* append current list */\
do \
q = AIO_QUEUE_VAL; \
while (q != AIO_QUEUE_SET(ouptr, q)); \
ouptr = q; \
} while (ouptr != QUEUE_LIST_END); \
} \
sim_asynch_check = 0; /* try to force check */ \
if (sim_idle_wait) { \
sim_debug (TIMER_DBG_IDLE, &sim_timer_dev, "waking due to event on %s after %d instructions\n", sim_uname(ouptr), event_time);\
pthread_cond_signal (&sim_asynch_wake); \
} \
sim_aio_activate ((ACTIVATE_API)caller, uptr, event_time); \
return SCPE_OK; \
} else (void)0
#define AIO_ACTIVATE_LIST(caller, list, event_time) \
if (list) { \
UNIT *ouptr, *q, *qe; \
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Queueing Asynch events for %s after %d instructions\n", sim_uname(list), event_time);\
for (qe=(list); qe->a_next != QUEUE_LIST_END;) { \
qe->a_event_time = event_time; \
qe->a_activate_call = (ACTIVATE_API)&caller; \
qe = qe->a_next; \
} \
qe->a_event_time = event_time; \
qe->a_activate_call = (ACTIVATE_API)&caller; \
ouptr = (list); \
do { \
do \
q = AIO_QUEUE_VAL; \
while (q != AIO_QUEUE_SET(QUEUE_LIST_END, q));/* Grab current list */ \
for (qe = ouptr; qe->a_next != QUEUE_LIST_END; qe = qe->a_next); \
qe->a_next = q; /* append current list */ \
do \
q = AIO_QUEUE_VAL; \
while (q != AIO_QUEUE_SET(ouptr, q)); \
ouptr = q; \
} while (ouptr != QUEUE_LIST_END); \
sim_asynch_check = 0; /* try to force check */ \
if (sim_idle_wait) { \
sim_debug (TIMER_DBG_IDLE, &sim_timer_dev, "waking due to event on %s after %d instructions\n", sim_uname(ouptr), event_time);\
pthread_cond_signal (&sim_asynch_wake); \
} \
} else (void)0
#else /* !USE_AIO_INTRINSICS */
/* This approach uses a pthread mutex to manage access to the link list */
/* head sim_asynch_queue. It will always work, but may be slower than the */
/* lock free approach when using USE_AIO_INTRINSICS */
#define AIO_QUEUE_MODE "Lock based asynchronous event queue access"
#define AIO_QUEUE_MODE "Lock based asynchronous event queue"
#define AIO_INIT \
if (1) { \
do { \
int tmr; \
pthread_mutexattr_t attr; \
\
@@ -1311,51 +1108,23 @@ extern int32 sim_asynch_inst_latency;
This allows NULL in an entry's a_next pointer to \
indicate that the entry is not currently in any list */ \
sim_asynch_queue = QUEUE_LIST_END; \
sim_wallclock_queue = QUEUE_LIST_END; \
sim_wallclock_entry = NULL; \
for (tmr=0; tmr<SIM_NTIMERS; tmr++) \
sim_clock_cosched_queue[tmr] = QUEUE_LIST_END; \
} \
else \
(void)0
} while (0)
#define AIO_CLEANUP \
if (1) { \
do { \
pthread_mutex_destroy(&sim_asynch_lock); \
pthread_cond_destroy(&sim_asynch_wake); \
pthread_mutex_destroy(&sim_timer_lock); \
pthread_cond_destroy(&sim_timer_wake); \
pthread_mutex_destroy(&sim_tmxr_poll_lock); \
pthread_cond_destroy(&sim_tmxr_poll_cond); \
} \
else \
(void)0
#define AIO_UPDATE_QUEUE \
if (1) { \
UNIT *uptr; \
AIO_LOCK; \
while (sim_asynch_queue != QUEUE_LIST_END) { /* List !Empty */ \
int32 a_event_time; \
uptr = sim_asynch_queue; \
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Migrating Asynch event for %s after %d instructions\n", sim_uname(uptr), uptr->a_event_time);\
sim_asynch_queue = uptr->a_next; \
uptr->a_next = NULL; /* hygiene */ \
if (uptr->a_activate_call != &sim_activate_notbefore) { \
a_event_time = uptr->a_event_time-((sim_asynch_inst_latency+1)/2); \
if (a_event_time < 0) \
a_event_time = 0; \
} \
else \
a_event_time = uptr->a_event_time; \
AIO_UNLOCK; \
uptr->a_activate_call (uptr, a_event_time); \
if (uptr->a_check_completion) { \
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Calling Completion Check for asynch event on %s\n", sim_uname(uptr));\
uptr->a_check_completion (uptr); \
} \
AIO_LOCK; \
} \
AIO_UNLOCK; \
} else (void)0
} while (0)
#define AIO_ILOCK AIO_LOCK
#define AIO_IUNLOCK AIO_UNLOCK
#define AIO_QUEUE_VAL sim_asynch_queue
#define AIO_QUEUE_SET(newval, oldval) ((sim_asynch_queue = newval),oldval)
#define AIO_UPDATE_QUEUE sim_aio_update_queue ()
#define AIO_ACTIVATE(caller, uptr, event_time) \
if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) { \
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Queueing Asynch event for %s after %d instructions\n", sim_uname(uptr), event_time);\
@@ -1376,40 +1145,19 @@ extern int32 sim_asynch_inst_latency;
sim_asynch_check = 0; \
return SCPE_OK; \
} else (void)0
#define AIO_ACTIVATE_LIST(caller, list, event_time) \
if (list) { \
UNIT *qe; \
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Queueing Asynch events for %s after %d instructions\n", sim_uname(list), event_time);\
for (qe=list; qe->a_next != QUEUE_LIST_END;) { \
qe->a_event_time = event_time; \
qe->a_activate_call = (ACTIVATE_API)&caller; \
qe = qe->a_next; \
} \
qe->a_event_time = event_time; \
qe->a_activate_call = (ACTIVATE_API)&caller; \
AIO_LOCK; \
qe->a_next = sim_asynch_queue; \
sim_asynch_queue = list; \
sim_asynch_check = 0; /* try to force check */ \
if (sim_idle_wait) { \
sim_debug (TIMER_DBG_IDLE, &sim_timer_dev, "waking due to event on %s after %d instructions\n", sim_uname(list), event_time);\
pthread_cond_signal (&sim_asynch_wake); \
} \
AIO_UNLOCK; \
} else (void)0
#endif /* USE_AIO_INTRINSICS */
#define AIO_VALIDATE if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) {sim_printf("Improper thread context for operation\n"); abort();}
#define AIO_CHECK_EVENT \
if (0 > --sim_asynch_check) { \
AIO_UPDATE_QUEUE; \
sim_asynch_check = sim_asynch_inst_latency; \
} else (void)0
} else (void)0
#define AIO_SET_INTERRUPT_LATENCY(instpersec) \
if (1) { \
do { \
sim_asynch_inst_latency = (int32)((((double)(instpersec))*sim_asynch_latency)/1000000000);\
if (sim_asynch_inst_latency == 0) \
sim_asynch_inst_latency = 1; \
} else (void)0
} while (0)
#else /* !SIM_ASYNCH_IO */
#define AIO_QUEUE_MODE "Asynchronous I/O is not available"
#define AIO_UPDATE_QUEUE
@@ -1421,7 +1169,6 @@ extern int32 sim_asynch_inst_latency;
#define AIO_LOCK
#define AIO_UNLOCK
#define AIO_CLEANUP
#define AIO_RETURN_TIME(uptr)
#define AIO_EVENT_BEGIN(uptr)
#define AIO_EVENT_COMPLETE(uptr, reason)
#define AIO_IS_ACTIVE(uptr) FALSE