Asynchronous Support
scp.c, scp.h - added sim_uname (Unit Name) API to simplify places which might want to display it (mostly debug messages). - added support for clock co-scheduling - added debugging to trace event queue activities sim_defs.h - added support for clock co-scheduling - added support for sim_uname (Thread local storage macro) - added support for debugging to trace event queue activities - simplified debug code by using sim_uname - fixed support macro for sim_is_active when asynch timers are in use sim_rev.h - fixed nested comments sim_tmxr.c, sim_tmxr.h - added support for clock co-scheduling - simplified debug code by using sim_uname - added support for devices which poll for output on different units sim_timer.c, sim_timer.h - added support for clock co-scheduling - fixed asynchronous clock calibration to smooth out calibration adjustments - simplified debug code by using sim_uname - added ability (when running with asynchronous support) to explicitly disable or enable asynchronous timer support. - changed sim_timer_inst_per_sec to return a double value since the result is always used in a double expression and integer overflow could occur under strange timing conditions vax/vax_stddev.c - converted from simulator specific clock co-scheduling to generic clock co-scheduling. vax/vax_cpu.c - added EVENT and ACTIVATE debug flag (SET CPU DEBUG=EVENT;ACTIVATE) support pdp11/pdp11_dz.c - converted from simulator specific clock co-scheduling to generic clock co-scheduling. pdp11/pdp11_vh.c - converted from simulator specific clock co-scheduling to generic clock co-scheduling. pdp11/pdp11_xq.c - converted from simulator specific clock co-scheduling to generic clock co-scheduling.
This commit is contained in:
parent
030d790b4c
commit
7c7df669ad
14 changed files with 367 additions and 115 deletions
|
@ -272,6 +272,34 @@ drifted some 4 minutes in 35 minutes time (approximately 10%). The same OS
|
|||
disk also running with idling enabled booted for 4 hours had less that 5
|
||||
seconds of clock drift (approximately 0.03%).
|
||||
|
||||
Co-Scheduling Clock and Multiplexer (or other devices)
|
||||
|
||||
Many simulator devices have needs to periodically executed with timing on the
|
||||
order of the simulated system's clock ticks. There are numerous reasons for
|
||||
this type of execution. Meanwhile, many of these events aren't particular
|
||||
about exactly when they execute as long as they execute frequently enough.
|
||||
Frequently executing events has the potential to interfere with a simulator's
|
||||
attempts to idle when the simulated system isn't actually doing useful work.
|
||||
|
||||
Interactions with attempts to 'co-schedule' multiplexer polling with clock
|
||||
ticks can cause strange simulator behaviors. These strange behaviors only
|
||||
happen under a combination of conditions:
|
||||
1) a multiplexer device is defined in the simulator configuration,
|
||||
2) the multiplexor device is NOT attached, and thus is not being managed by
|
||||
the asynchronous multiplexer support
|
||||
3) the multiplexer device schedules polling (co-scheduled) when not
|
||||
attached (such polling will never produce anything input).
|
||||
In prior simh versions support for clock co-scheduling was implmented
|
||||
separately by each simulator, and usually was expressed by code of the form:
|
||||
sim_activate (uptr, clk_cosched (tmxr_poll));
|
||||
As a part of asynchronous timer support, the simulator framework has been
|
||||
extended to generically provide clock co-scheduling support. The use of this
|
||||
new capability requires an initial call (usually in the clock device reset
|
||||
routing) of the form:
|
||||
sim_register_clock_unit (&clk_unit);
|
||||
Once the clock unit has been registered, co-scheduling is achieved by replacing
|
||||
the earlier sim_activate with the following:
|
||||
sim_clock_coschedule (&dz_unit, tmxr_poll);
|
||||
|
||||
Run time requirements to use SIM_ASYNCH_IO.
|
||||
The Posix threads API (pthreads) is required for asynchronous execution.
|
||||
|
|
|
@ -334,7 +334,7 @@ switch ((PA >> 1) & 03) { /* case on PA<2:1> */
|
|||
if (data & CSR_CLR) /* clr? reset */
|
||||
dz_clear (dz, FALSE);
|
||||
if (data & CSR_MSE) /* MSE? start poll */
|
||||
sim_activate (&dz_unit, clk_cosched (tmxr_poll));
|
||||
sim_clock_coschedule (&dz_unit, tmxr_poll);
|
||||
else dz_csr[dz] &= ~(CSR_SA | CSR_RDONE | CSR_TRDY);
|
||||
if ((data & CSR_RIE) == 0) /* RIE = 0? */
|
||||
dz_clr_rxint (dz);
|
||||
|
@ -439,7 +439,7 @@ if (t) { /* any enabled? */
|
|||
dz_update_rcvi (); /* upd rcv intr */
|
||||
tmxr_poll_tx (&dz_desc); /* poll output */
|
||||
dz_update_xmti (); /* upd xmt intr */
|
||||
sim_activate (uptr, clk_cosched (tmxr_poll)); /* reactivate */
|
||||
sim_clock_coschedule (uptr, tmxr_poll); /* reactivate */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
|
|
@ -343,7 +343,7 @@ static DIB vh_dib = {
|
|||
|
||||
static UNIT vh_unit[VH_MUXES] = {
|
||||
{ UDATA (&vh_svc, UNIT_IDLE|UNIT_ATTABLE, 0) },
|
||||
{ UDATA (&vh_timersvc, 0, 0) },
|
||||
{ UDATA (&vh_timersvc, UNIT_IDLE, 0) },
|
||||
};
|
||||
|
||||
static const REG vh_reg[] = {
|
||||
|
@ -841,9 +841,9 @@ static t_stat vh_wr ( int32 data,
|
|||
if ((vh_unit[vh].flags & UNIT_MODEDHU) && (data & CSR_SKIP))
|
||||
data &= ~CSR_MASTER_RESET;
|
||||
if (vh == 0) /* Only start unit service on the first unit. Units are polled there */
|
||||
sim_activate (&vh_unit[0], clk_cosched (tmxr_poll));
|
||||
sim_clock_coschedule (&vh_unit[0], tmxr_poll);
|
||||
vh_mcount[vh] = MS2SIMH (1200); /* 1.2 seconds */
|
||||
sim_activate (&vh_unit[1], clk_cosched (tmxr_poll));
|
||||
sim_clock_coschedule (&vh_unit[1], tmxr_poll);
|
||||
}
|
||||
if ((data & CSR_RXIE) == 0)
|
||||
vh_clr_rxint (vh);
|
||||
|
@ -875,7 +875,7 @@ static t_stat vh_wr ( int32 data,
|
|||
break;
|
||||
if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
|
||||
vh_mcount[vh] = 1;
|
||||
sim_activate (&vh_unit[1], clk_cosched (tmxr_poll));
|
||||
sim_clock_coschedule (&vh_unit[1], tmxr_poll);
|
||||
break;
|
||||
}
|
||||
if (vh_unit[vh].flags & UNIT_MODEDHU) {
|
||||
|
@ -920,7 +920,7 @@ static t_stat vh_wr ( int32 data,
|
|||
case 2: /* LPR */
|
||||
if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
|
||||
vh_mcount[vh] = 1;
|
||||
sim_activate (&vh_unit[1], clk_cosched (tmxr_poll));
|
||||
sim_clock_coschedule (&vh_unit[1], tmxr_poll);
|
||||
break;
|
||||
}
|
||||
if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES)
|
||||
|
@ -947,7 +947,7 @@ static t_stat vh_wr ( int32 data,
|
|||
case 3: /* STAT/FIFODATA */
|
||||
if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
|
||||
vh_mcount[vh] = 1;
|
||||
sim_activate (&vh_unit[1], clk_cosched (tmxr_poll));
|
||||
sim_clock_coschedule (&vh_unit[1], tmxr_poll);
|
||||
break;
|
||||
}
|
||||
if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES)
|
||||
|
@ -971,7 +971,7 @@ static t_stat vh_wr ( int32 data,
|
|||
case 4: /* LNCTRL */
|
||||
if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
|
||||
vh_mcount[vh] = 1;
|
||||
sim_activate (&vh_unit[1], clk_cosched (tmxr_poll));
|
||||
sim_clock_coschedule (&vh_unit[1], tmxr_poll);
|
||||
break;
|
||||
}
|
||||
if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES)
|
||||
|
@ -1039,7 +1039,7 @@ static t_stat vh_wr ( int32 data,
|
|||
case 5: /* TBUFFAD1 */
|
||||
if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
|
||||
vh_mcount[vh] = 1;
|
||||
sim_activate (&vh_unit[1], clk_cosched (tmxr_poll));
|
||||
sim_clock_coschedule (&vh_unit[1], tmxr_poll);
|
||||
break;
|
||||
}
|
||||
if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES)
|
||||
|
@ -1055,7 +1055,7 @@ static t_stat vh_wr ( int32 data,
|
|||
case 6: /* TBUFFAD2 */
|
||||
if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
|
||||
vh_mcount[vh] = 1;
|
||||
sim_activate (&vh_unit[1], clk_cosched (tmxr_poll));
|
||||
sim_clock_coschedule (&vh_unit[1], tmxr_poll);
|
||||
break;
|
||||
}
|
||||
if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES)
|
||||
|
@ -1076,7 +1076,7 @@ static t_stat vh_wr ( int32 data,
|
|||
case 7: /* TBUFFCT */
|
||||
if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) {
|
||||
vh_mcount[vh] = 1;
|
||||
sim_activate (&vh_unit[1], clk_cosched (tmxr_poll));
|
||||
sim_clock_coschedule (&vh_unit[1], tmxr_poll);
|
||||
break;
|
||||
}
|
||||
if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES)
|
||||
|
@ -1154,7 +1154,7 @@ static t_stat vh_timersvc ( UNIT *uptr )
|
|||
}
|
||||
}
|
||||
if (again)
|
||||
sim_activate (uptr, clk_cosched (tmxr_poll)); /* requeue ourselves */
|
||||
sim_clock_coschedule (uptr, tmxr_poll); /* requeue ourselves */
|
||||
return (SCPE_OK);
|
||||
}
|
||||
|
||||
|
|
|
@ -435,10 +435,10 @@ REG xqb_reg[] = {
|
|||
};
|
||||
|
||||
MTAB xq_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL,
|
||||
NULL, &show_addr, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,
|
||||
NULL, &show_vec, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL,
|
||||
NULL, &show_addr, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,
|
||||
NULL, &show_vec, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx",
|
||||
&xq_setmac, &xq_showmac, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "ETH", "ETH",
|
||||
|
@ -2139,13 +2139,20 @@ void xq_start_receiver(CTLR* xq)
|
|||
return;
|
||||
|
||||
/* start the read service timer or enable asynch reading as appropriate */
|
||||
if (xq->var->must_poll)
|
||||
sim_activate(xq->unit, (sim_idle_enab ? clk_cosched(tmxr_poll) : (tmr_poll*clk_tps)/xq->var->poll));
|
||||
if (xq->var->must_poll) {
|
||||
if (sim_idle_enab)
|
||||
sim_clock_coschedule(xq->unit, tmxr_poll);
|
||||
else
|
||||
sim_activate(xq->unit, (tmr_poll*clk_tps)/xq->var->poll);
|
||||
}
|
||||
else
|
||||
if ((xq->var->poll == 0) || (xq->var->mode == XQ_T_DELQA_PLUS))
|
||||
eth_set_async(xq->var->etherface, xq->var->coalesce_latency_ticks);
|
||||
else
|
||||
sim_activate(xq->unit, (sim_idle_enab ? clk_cosched(tmxr_poll) : (tmr_poll*clk_tps)/xq->var->poll));
|
||||
if (sim_idle_enab)
|
||||
sim_clock_coschedule(xq->unit, tmxr_poll);
|
||||
else
|
||||
sim_activate(xq->unit, (tmr_poll*clk_tps)/xq->var->poll);
|
||||
}
|
||||
|
||||
void xq_stop_receiver(CTLR* xq)
|
||||
|
@ -2520,7 +2527,10 @@ t_stat xq_svc(UNIT* uptr)
|
|||
|
||||
/* resubmit service timer */
|
||||
if ((xq->var->must_poll) || (xq->var->poll && (xq->var->mode != XQ_T_DELQA_PLUS)))
|
||||
sim_activate(uptr, (sim_idle_enab ? clk_cosched(tmxr_poll) : (tmr_poll*clk_tps)/xq->var->poll));
|
||||
if (sim_idle_enab)
|
||||
sim_clock_coschedule(uptr, tmxr_poll);
|
||||
else
|
||||
sim_activate(uptr, (tmr_poll*clk_tps)/xq->var->poll);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
|
|
@ -491,6 +491,8 @@ DEBTAB cpu_deb[] = {
|
|||
{ "INTEXC", LOG_CPU_I },
|
||||
{ "REI", LOG_CPU_R },
|
||||
{ "CONTEXT", LOG_CPU_P },
|
||||
{ "EVENT", SIM_DBG_EVENT },
|
||||
{ "ACTIVATE", SIM_DBG_ACTIVATE },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
|
|
|
@ -321,7 +321,7 @@ t_stat tti_svc (UNIT *uptr)
|
|||
{
|
||||
int32 c;
|
||||
|
||||
sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmr_poll)));
|
||||
sim_clock_coschedule (uptr, KBD_WAIT (uptr->wait, tmr_poll));
|
||||
/* continue poll */
|
||||
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */
|
||||
return c;
|
||||
|
@ -405,16 +405,6 @@ if (!todr_blow && todr_reg) /* if running? */
|
|||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Clock coscheduling routine */
|
||||
|
||||
int32 clk_cosched (int32 wait)
|
||||
{
|
||||
int32 t;
|
||||
|
||||
t = sim_is_active (&clk_unit);
|
||||
return (t? t - 1: wait);
|
||||
}
|
||||
|
||||
int32 todr_rd (void)
|
||||
{
|
||||
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||
|
@ -498,6 +488,7 @@ t_stat clk_reset (DEVICE *dptr)
|
|||
{
|
||||
int32 t;
|
||||
|
||||
sim_register_clock_unit (&clk_unit);
|
||||
clk_csr = 0;
|
||||
CLR_INT (CLK);
|
||||
if (!sim_is_running) { /* RESET (not IORESET)? */
|
||||
|
|
50
scp.c
50
scp.c
|
@ -313,6 +313,7 @@ pthread_t sim_asynch_main_threadid;
|
|||
UNIT * volatile sim_asynch_queue = QUEUE_LIST_END;
|
||||
UNIT * volatile sim_wallclock_queue = QUEUE_LIST_END;
|
||||
UNIT * volatile sim_wallclock_entry = NULL;
|
||||
UNIT * volatile sim_clock_cosched_queue = QUEUE_LIST_END;
|
||||
int32 sim_asynch_check;
|
||||
int32 sim_asynch_latency = 4000; /* 4 usec interrupt latency */
|
||||
int32 sim_asynch_inst_latency = 20; /* assume 5 mip simulator */
|
||||
|
@ -2311,11 +2312,11 @@ int32 accum;
|
|||
if (cptr && (*cptr != 0))
|
||||
return SCPE_2MARG;
|
||||
if (sim_clock_queue == QUEUE_LIST_END)
|
||||
fprintf (st, "%s event queue empty, time = %.0f\n",
|
||||
sim_name, sim_time);
|
||||
fprintf (st, "%s event queue empty, time = %.0f, executing %.0f instructios/sec\n",
|
||||
sim_name, sim_time, sim_timer_inst_per_sec ());
|
||||
else {
|
||||
fprintf (st, "%s event queue status, time = %.0f\n",
|
||||
sim_name, sim_time);
|
||||
fprintf (st, "%s event queue status, time = %.0f, executing %.0f instructions/sec\n",
|
||||
sim_name, sim_time, sim_timer_inst_per_sec ());
|
||||
accum = 0;
|
||||
for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
|
||||
if (uptr == &sim_step_unit)
|
||||
|
@ -2334,10 +2335,10 @@ else {
|
|||
pthread_mutex_lock (&sim_timer_lock);
|
||||
if (sim_wallclock_queue == QUEUE_LIST_END)
|
||||
fprintf (st, "%s wall clock event queue empty, time = %.0f\n",
|
||||
sim_name, sim_time);
|
||||
sim_name, sim_time);
|
||||
else {
|
||||
fprintf (st, "%s wall clock event queue status, time = %.0f\n",
|
||||
sim_name, sim_time);
|
||||
sim_name, sim_time);
|
||||
for (uptr = sim_wallclock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
|
||||
if ((dptr = find_dev_from_unit (uptr)) != NULL) {
|
||||
fprintf (st, " %s", sim_dname (dptr));
|
||||
|
@ -2348,6 +2349,19 @@ else {
|
|||
fprintf (st, " after %d usec\n", uptr->a_usec_delay);
|
||||
}
|
||||
}
|
||||
if (sim_clock_cosched_queue != QUEUE_LIST_END) {
|
||||
fprintf (st, "%s clock co-schedule event queue status, time = %.0f\n",
|
||||
sim_name, sim_time);
|
||||
for (uptr = sim_clock_cosched_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
|
||||
if ((dptr = find_dev_from_unit (uptr)) != NULL) {
|
||||
fprintf (st, " %s", sim_dname (dptr));
|
||||
if (dptr->numunits > 1)
|
||||
fprintf (st, " unit %d", (int32) (uptr - dptr->units));
|
||||
}
|
||||
else fprintf (st, " Unknown");
|
||||
fprintf (st, "\n");
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock (&sim_timer_lock);
|
||||
pthread_mutex_lock (&sim_asynch_lock);
|
||||
fprintf (st, "asynchronous pending event queue\n");
|
||||
|
@ -3090,6 +3104,19 @@ char *sim_dname (DEVICE *dptr)
|
|||
return (dptr->lname? dptr->lname: dptr->name);
|
||||
}
|
||||
|
||||
/* Get unit display name */
|
||||
|
||||
char *sim_uname (UNIT *uptr)
|
||||
{
|
||||
DEVICE *d = find_dev_from_unit(uptr);
|
||||
static AIO_TLS char uname[CBUFSIZE];
|
||||
|
||||
if (d->numunits == 1)
|
||||
return sim_dname (d);
|
||||
sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
|
||||
return uname;
|
||||
}
|
||||
|
||||
/* Save command
|
||||
|
||||
sa[ve] filename save state to specified file
|
||||
|
@ -5303,6 +5330,7 @@ if (stop_cpu) /* stop CPU? */
|
|||
UPDATE_SIM_TIME; /* update sim time */
|
||||
if (sim_clock_queue == QUEUE_LIST_END) { /* queue empty? */
|
||||
sim_interval = noqueue_time = NOQUEUE_WAIT; /* flag queue empty */
|
||||
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Queue Emptry New Interval = %d\n", sim_interval);
|
||||
return SCPE_OK;
|
||||
}
|
||||
do {
|
||||
|
@ -5314,6 +5342,7 @@ do {
|
|||
sim_interval = sim_clock_queue->time;
|
||||
else
|
||||
sim_interval = noqueue_time = NOQUEUE_WAIT;
|
||||
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Processing Event for %s\n", sim_uname (uptr));
|
||||
AIO_EVENT_BEGIN(uptr);
|
||||
if (uptr->action != NULL)
|
||||
reason = uptr->action (uptr);
|
||||
|
@ -5324,9 +5353,12 @@ do {
|
|||
(sim_interval <= 0) &&
|
||||
(sim_clock_queue != QUEUE_LIST_END));
|
||||
|
||||
if (sim_clock_queue == QUEUE_LIST_END) /* queue empty? */
|
||||
if (sim_clock_queue == QUEUE_LIST_END) { /* queue empty? */
|
||||
sim_interval = noqueue_time = NOQUEUE_WAIT; /* flag queue empty */
|
||||
|
||||
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Processing Queue Complete New Interval = %d\n", sim_interval);
|
||||
}
|
||||
else
|
||||
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Processing Queue Complete New Interval = %d(%s)\n", sim_interval, sim_uname(sim_clock_queue));
|
||||
return reason;
|
||||
}
|
||||
|
||||
|
@ -5354,6 +5386,8 @@ if (sim_is_active_bool (uptr)) /* already active? */
|
|||
return SCPE_OK;
|
||||
UPDATE_SIM_TIME; /* update sim time */
|
||||
|
||||
sim_debug (SIM_DBG_ACTIVATE, sim_dflt_dev, "Activating %s delay=%d\n", sim_uname (uptr), event_time);
|
||||
|
||||
prvptr = NULL;
|
||||
accum = 0;
|
||||
for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
|
||||
|
|
1
scp.h
1
scp.h
|
@ -103,6 +103,7 @@ t_stat deassign_device (DEVICE *dptr);
|
|||
t_stat reset_all (uint32 start_device);
|
||||
t_stat reset_all_p (uint32 start_device);
|
||||
char *sim_dname (DEVICE *dptr);
|
||||
char *sim_uname (UNIT *dptr);
|
||||
t_stat get_yn (char *ques, t_stat deflt);
|
||||
char *get_sim_opt (int32 opt, char *cptr, t_stat *st);
|
||||
char *get_glyph (char *iptr, char *optr, char mchar);
|
||||
|
|
48
sim_defs.h
48
sim_defs.h
|
@ -527,6 +527,9 @@ struct sim_debtab {
|
|||
#define DEBUG_PRI(d,m) (sim_deb && (d.dctrl & (m)))
|
||||
#define DEBUG_PRJ(d,m) (sim_deb && (d->dctrl & (m)))
|
||||
|
||||
#define SIM_DBG_EVENT 0x10000
|
||||
#define SIM_DBG_ACTIVATE 0x20000
|
||||
|
||||
/* File Reference */
|
||||
struct sim_fileref {
|
||||
char name[CBUFSIZE]; /* file name */
|
||||
|
@ -579,6 +582,7 @@ typedef struct sim_fileref FILEREF;
|
|||
#include "sim_timer.h"
|
||||
#include "sim_ether.h"
|
||||
#include "sim_fio.h"
|
||||
#include "sim_tmxr.h"
|
||||
|
||||
/* Asynch/Threaded I/O support */
|
||||
|
||||
|
@ -598,11 +602,25 @@ 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_clock_cosched_queue;
|
||||
extern volatile t_bool sim_idle_wait;
|
||||
extern int32 sim_asynch_check;
|
||||
extern int32 sim_asynch_latency;
|
||||
extern int32 sim_asynch_inst_latency;
|
||||
|
||||
/* Thread local storage */
|
||||
#if defined(__GNUC__) && !defined(__APPLE__)
|
||||
#define AIO_TLS __thread
|
||||
#elif defined(__DECC_VER) || defined(_MSC_VER)
|
||||
#define AIO_TLS __declspec(thread)
|
||||
#else
|
||||
/* Other compiler environment, then don't worry about thread local storage. */
|
||||
/* It is primarily used only used in debugging messages */
|
||||
#define AIO_TLS
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define AIO_INIT \
|
||||
if (1) { \
|
||||
sim_asynch_main_threadid = pthread_self(); \
|
||||
|
@ -662,6 +680,23 @@ extern int32 sim_asynch_inst_latency;
|
|||
} \
|
||||
if ((uptr)->next == NULL) \
|
||||
(uptr)->a_due_time = (uptr)->a_usec_delay = 0; \
|
||||
else { \
|
||||
nptr = QUEUE_LIST_END; \
|
||||
if ((uptr) == sim_clock_cosched_queue) { \
|
||||
sim_clock_cosched_queue = (uptr)->next; \
|
||||
(uptr)->next = NULL; \
|
||||
} \
|
||||
else \
|
||||
for (cptr = sim_clock_cosched_queue; \
|
||||
(cptr != QUEUE_LIST_END); \
|
||||
cptr = cptr->next) \
|
||||
if (cptr->next == (uptr)) { \
|
||||
cptr->next = (uptr)->next; \
|
||||
nptr = cptr; \
|
||||
(uptr)->next = NULL; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
pthread_mutex_unlock (&sim_timer_lock); \
|
||||
} \
|
||||
} \
|
||||
|
@ -674,10 +709,12 @@ extern int32 sim_asynch_inst_latency;
|
|||
cptr != QUEUE_LIST_END; \
|
||||
cptr = cptr->next) \
|
||||
if ((uptr) == cptr) { \
|
||||
int32 inst_per_sec = sim_timer_inst_per_sec (); \
|
||||
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; \
|
||||
} \
|
||||
|
@ -756,10 +793,8 @@ extern int32 sim_asynch_inst_latency;
|
|||
} else (void)0
|
||||
#define AIO_ACTIVATE(caller, uptr, event_time) \
|
||||
if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) { \
|
||||
DEVICE *d; \
|
||||
if (sim_deb) \
|
||||
d = find_dev_from_unit(uptr); \
|
||||
sim_debug (TIMER_DBG_QUEUE, &sim_timer_dev, "asynch event on %s after %d instructions\n", d->name, event_time);\
|
||||
UNIT *ouptr = (uptr); \
|
||||
sim_debug (TIMER_DBG_QUEUE, &sim_timer_dev, "asynch event on %s after %d instructions\n", sim_uname(uptr), event_time);\
|
||||
if (uptr->a_next) { /* already queued? */ \
|
||||
uptr->a_activate_call = sim_activate_abs; \
|
||||
} else { \
|
||||
|
@ -781,7 +816,7 @@ extern int32 sim_asynch_inst_latency;
|
|||
} \
|
||||
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", d->name, event_time);\
|
||||
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_idle_wake); \
|
||||
} \
|
||||
return SCPE_OK; \
|
||||
|
@ -858,6 +893,7 @@ extern int32 sim_asynch_inst_latency;
|
|||
#define AIO_EVENT_BEGIN(uptr)
|
||||
#define AIO_EVENT_COMPLETE(uptr, reason)
|
||||
#define AIO_SET_INTERRUPT_LATENCY(instpersec)
|
||||
#define AIO_TLS
|
||||
#endif /* SIM_ASYNCH_IO */
|
||||
|
||||
#endif
|
||||
|
|
22
sim_rev.h
22
sim_rev.h
|
@ -356,7 +356,7 @@ patch date module(s) and fix(es)
|
|||
- moved all Qbus devices to BR4; deleted RP definitions
|
||||
|
||||
|
||||
/* V3.8 revision history
|
||||
V3.8 revision history
|
||||
|
||||
1 08-Feb-09 scp.c:
|
||||
- revised RESTORE unit logic for consistency
|
||||
|
@ -709,7 +709,7 @@ patch date module(s) and fix(es)
|
|||
- fixed declarations (Mark Pizzolato)
|
||||
|
||||
|
||||
/* V3.7 revision history
|
||||
V3.7 revision history
|
||||
|
||||
3 02-Sep-07 scp.c:
|
||||
- fixed bug in SET THROTTLE command
|
||||
|
@ -981,7 +981,7 @@ patch date module(s) and fix(es)
|
|||
- fixed operand order in EIS instructions (W.F.J. Mueller)
|
||||
|
||||
|
||||
/* V3.6 revision history
|
||||
V3.6 revision history
|
||||
|
||||
1 25-Jul-06 sim_console.c:
|
||||
- implemented SET/SHOW PCHAR
|
||||
|
@ -1155,7 +1155,7 @@ patch date module(s) and fix(es)
|
|||
- fixed bug in reported VA on faulting cross-page write
|
||||
|
||||
|
||||
/* V3.5 revision history
|
||||
V3.5 revision history
|
||||
|
||||
patch date module(s) and fix(es)
|
||||
|
||||
|
@ -1291,7 +1291,7 @@ patch date module(s) and fix(es)
|
|||
|
||||
vax_io.c: revised autoconfiguration algorithm and interface
|
||||
|
||||
/* V3.4 revision history
|
||||
V3.4 revision history
|
||||
|
||||
0 01-May-04 scp.c:
|
||||
- fixed ASSERT code
|
||||
|
@ -1329,7 +1329,7 @@ patch date module(s) and fix(es)
|
|||
|
||||
pdp11_tu.c: fixed error reporting
|
||||
|
||||
/* V3.3 revision history
|
||||
V3.3 revision history
|
||||
|
||||
2 08-Mar-05 scp.c: added ASSERT command (Dave Bryan)
|
||||
|
||||
|
@ -1581,7 +1581,7 @@ patch date module(s) and fix(es)
|
|||
- split from vax_sys.c
|
||||
- removed PTR, PTP
|
||||
|
||||
/* V3.2 revision history
|
||||
V3.2 revision history
|
||||
|
||||
3 03-Sep-04 scp.c:
|
||||
- added ECHO command (Dave Bryan)
|
||||
|
@ -1780,7 +1780,7 @@ patch date module(s) and fix(es)
|
|||
- added PC read fault in EXTxV
|
||||
- fixed PC write fault in INSV
|
||||
|
||||
/* V3.1 revision history
|
||||
V3.1 revision history
|
||||
|
||||
0 29-Dec-03 sim_defs.h, scp.c: added output stall status
|
||||
|
||||
|
@ -1893,7 +1893,7 @@ patch date module(s) and fix(es)
|
|||
- revised instruction decoding
|
||||
- added instruction history
|
||||
|
||||
/* V3.0 revision history
|
||||
V3.0 revision history
|
||||
|
||||
2 15-Sep-03 scp.c:
|
||||
- fixed end-of-file problem in dep, idep
|
||||
|
@ -2059,7 +2059,7 @@ patch date module(s) and fix(es)
|
|||
|
||||
gri_cpu.c: fixed bug in SC queue pointer management
|
||||
|
||||
/* V2.10 revision history
|
||||
V2.10 revision history
|
||||
|
||||
4 03-Mar-03 scp.c
|
||||
- added .ini startup file capability
|
||||
|
@ -2357,7 +2357,7 @@ patch date module(s) and fix(es)
|
|||
|
||||
IBM 1620: first release
|
||||
|
||||
/* V2.9 revision history
|
||||
V2.9 revision history
|
||||
|
||||
11 20-Jul-02 i1401_mt.c: on read, end of record stores group mark
|
||||
without word mark (Van Snyder)
|
||||
|
|
177
sim_timer.c
177
sim_timer.c
|
@ -79,6 +79,8 @@
|
|||
routines are not.
|
||||
*/
|
||||
|
||||
#define NOT_MUX_USING_CODE /* sim_tmxr library provider or agnostic */
|
||||
|
||||
#include "sim_defs.h"
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
@ -99,7 +101,13 @@ static uint32 sim_throt_val = 0;
|
|||
static uint32 sim_throt_state = 0;
|
||||
static uint32 sim_throt_sleep_time = 0;
|
||||
static int32 sim_throt_wait = 0;
|
||||
|
||||
static UNIT *sim_clock_unit = NULL;
|
||||
static t_bool sim_asynch_timer =
|
||||
#if defined (SIM_ASYNCH_IO)
|
||||
TRUE;
|
||||
#else
|
||||
FALSE;
|
||||
#endif
|
||||
extern int32 sim_interval, sim_switches;
|
||||
extern FILE *sim_log;
|
||||
extern UNIT *sim_clock_queue;
|
||||
|
@ -577,17 +585,20 @@ int32 sim_rtcn_calb (int32 ticksper, int32 tmr)
|
|||
uint32 new_rtime, delta_rtime;
|
||||
int32 delta_vtime;
|
||||
double new_gtime;
|
||||
int32 new_currd;
|
||||
|
||||
if ((tmr < 0) || (tmr >= SIM_NTIMERS))
|
||||
return 10000;
|
||||
rtc_hz[tmr] = ticksper;
|
||||
rtc_ticks[tmr] = rtc_ticks[tmr] + 1; /* count ticks */
|
||||
if (rtc_ticks[tmr] < ticksper) /* 1 sec yet? */
|
||||
if (rtc_ticks[tmr] < ticksper) { /* 1 sec yet? */
|
||||
return rtc_currd[tmr];
|
||||
}
|
||||
rtc_ticks[tmr] = 0; /* reset ticks */
|
||||
rtc_elapsed[tmr] = rtc_elapsed[tmr] + 1; /* count sec */
|
||||
if (!rtc_avail) /* no timer? */
|
||||
if (!rtc_avail) { /* no timer? */
|
||||
return rtc_currd[tmr];
|
||||
}
|
||||
new_rtime = sim_os_msec (); /* wall time */
|
||||
sim_debug (DBG_TRC, &sim_timer_dev, "sim_rtcn_calb(ticksper=%d, tmr=%d) rtime=%d\n", ticksper, tmr, new_rtime);
|
||||
if (sim_idle_idled) {
|
||||
|
@ -609,21 +620,32 @@ rtc_rtime[tmr] = new_rtime; /* adv wall time */
|
|||
rtc_vtime[tmr] = rtc_vtime[tmr] + 1000; /* adv sim time */
|
||||
if (delta_rtime > 30000) { /* gap too big? */
|
||||
rtc_currd[tmr] = rtc_initd[tmr];
|
||||
rtc_gtime[tmr] = sim_gtime(); /* save instruction time */
|
||||
sim_debug (DBG_CAL, &sim_timer_dev, "gap too big: delta = %d - result: %d\n", delta_rtime, rtc_initd[tmr]);
|
||||
return rtc_initd[tmr]; /* can't calibr */
|
||||
}
|
||||
new_gtime = sim_gtime();
|
||||
if (sim_asynch_enabled)
|
||||
if (sim_asynch_enabled && sim_asynch_timer)
|
||||
if (rtc_elapsed[tmr] > sim_idle_stable) {
|
||||
/* An asynchronous clock, merely needs to divide the number of */
|
||||
/* instructions actually executed by the clock rate. */
|
||||
rtc_currd[tmr] = (int32)((new_gtime - rtc_gtime[tmr])/ticksper);
|
||||
new_currd = (int32)((new_gtime - rtc_gtime[tmr])/ticksper);
|
||||
/* avoid excessive swings in the calibrated result */
|
||||
if (new_currd > 10*rtc_currd[tmr]) /* don't swing big too fast */
|
||||
new_currd = 10*rtc_currd[tmr];
|
||||
else
|
||||
if (new_currd < rtc_currd[tmr]/10) /* don't swing small too fast */
|
||||
new_currd = rtc_currd[tmr]/10;
|
||||
rtc_currd[tmr] = new_currd;
|
||||
rtc_gtime[tmr] = new_gtime; /* save instruction time */
|
||||
if (rtc_currd[tmr] == 127)
|
||||
sim_debug (DBG_CAL, &sim_timer_dev, "asynch calibration small: %d\n", rtc_currd[tmr]);
|
||||
sim_debug (DBG_CAL, &sim_timer_dev, "asynch calibration result: %d\n", rtc_currd[tmr]);
|
||||
return rtc_currd[tmr]; /* calibrated result */
|
||||
}
|
||||
else {
|
||||
rtc_currd[tmr] = rtc_initd[tmr];
|
||||
rtc_gtime[tmr] = new_gtime; /* save instruction time */
|
||||
sim_debug (DBG_CAL, &sim_timer_dev, "asynch not stable calibration result: %d\n", rtc_initd[tmr]);
|
||||
return rtc_initd[tmr]; /* initial result until stable */
|
||||
}
|
||||
|
@ -685,7 +707,7 @@ for (tmr=0; tmr<SIM_NTIMERS; ++tmr) {
|
|||
if (0 == rtc_initd[tmr])
|
||||
continue;
|
||||
|
||||
fprintf (st, "%s%sTimer %d:\n", sim_asynch_enabled ? "Asynchronous " : "", rtc_hz[tmr] ? "Calibrated " : "Uncalibrated ", tmr);
|
||||
fprintf (st, "%s%sTimer %d:\n", (sim_asynch_enabled && sim_asynch_timer) ? "Asynchronous " : "", rtc_hz[tmr] ? "Calibrated " : "Uncalibrated ", tmr);
|
||||
if (rtc_hz[tmr]) {
|
||||
fprintf (st, " Running at: %dhz\n", rtc_hz[tmr]);
|
||||
fprintf (st, " Ticks in current second: %d\n", rtc_ticks[tmr]);
|
||||
|
@ -693,7 +715,7 @@ for (tmr=0; tmr<SIM_NTIMERS; ++tmr) {
|
|||
fprintf (st, " Seconds Running: %u\n", rtc_elapsed[tmr]);
|
||||
fprintf (st, " Calibrations: %u\n", rtc_calibrations[tmr]);
|
||||
fprintf (st, " Instruction Time: %.0f\n", rtc_gtime[tmr]);
|
||||
if (!sim_asynch_enabled) {
|
||||
if (!(sim_asynch_enabled && sim_asynch_timer)) {
|
||||
fprintf (st, " Real Time: %u\n", rtc_rtime[tmr]);
|
||||
fprintf (st, " Virtual Time: %u\n", rtc_vtime[tmr]);
|
||||
fprintf (st, " Next Interval: %u\n", rtc_nxintv[tmr]);
|
||||
|
@ -706,6 +728,7 @@ for (tmr=0; tmr<SIM_NTIMERS; ++tmr) {
|
|||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
REG sim_timer_reg[] = {
|
||||
{ DRDATA (TICKS_PER_SEC, rtc_hz[0], 32), PV_RSPC|REG_RO},
|
||||
{ DRDATA (INSTS_PER_TICK, rtc_currd[0], 32), PV_RSPC|REG_RO},
|
||||
|
@ -725,7 +748,39 @@ REG sim_timer_reg[] = {
|
|||
{ NULL }
|
||||
};
|
||||
|
||||
/* Clear, Set and show asynch */
|
||||
|
||||
/* Clear asynch */
|
||||
|
||||
t_stat sim_timer_clr_async (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if (sim_asynch_timer) {
|
||||
sim_asynch_timer = FALSE;
|
||||
sim_timer_change_asynch ();
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat sim_timer_set_async (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if (!sim_asynch_timer) {
|
||||
sim_asynch_timer = TRUE;
|
||||
sim_timer_change_asynch ();
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat sim_timer_show_async (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
fprintf (st, "%s", (sim_asynch_enabled && sim_asynch_timer) ? "Asynchronous" : "Synchronous");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
MTAB sim_timer_mod[] = {
|
||||
#if defined (SIM_ASYNCH_IO)
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "ASYNC", "ASYNC", &sim_timer_set_async, &sim_timer_show_async },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, NULL, "NOASYNC", &sim_timer_clr_async, NULL },
|
||||
#endif
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
|
@ -755,11 +810,11 @@ static uint32 cyc_ms = 0;
|
|||
uint32 w_ms, w_idle, act_ms;
|
||||
int32 act_cyc;
|
||||
|
||||
sim_idle_idled = TRUE; /* record idle attempt */
|
||||
//sim_idle_idled = TRUE; /* record idle attempt */
|
||||
if ((!sim_idle_enab) || /* idling disabled */
|
||||
((sim_clock_queue == QUEUE_LIST_END) && /* or clock queue empty? */
|
||||
#if defined(SIM_ASYNCH_IO)
|
||||
(!sim_asynch_enabled)) || /* and not asynch? */
|
||||
(!(sim_asynch_enabled && sim_asynch_timer)))|| /* and not asynch? */
|
||||
#else
|
||||
(TRUE)) ||
|
||||
#endif
|
||||
|
@ -789,10 +844,8 @@ if (w_idle == 0) { /* none? */
|
|||
}
|
||||
if (sim_clock_queue == QUEUE_LIST_END)
|
||||
sim_debug (DBG_IDL, &sim_timer_dev, "sleeping for %d ms - pending event in %d instructions\n", w_ms, sim_interval);
|
||||
else {
|
||||
DEVICE *d = find_dev_from_unit(sim_clock_queue);
|
||||
sim_debug (DBG_IDL, &sim_timer_dev, "sleeping for %d ms - pending event on %s in %d instructions\n", w_ms, d->name, sim_interval);
|
||||
}
|
||||
else
|
||||
sim_debug (DBG_IDL, &sim_timer_dev, "sleeping for %d ms - pending event on %s in %d instructions\n", w_ms, sim_uname(sim_clock_queue), sim_interval);
|
||||
act_ms = SIM_IDLE_MS_SLEEP (w_ms); /* wait */
|
||||
act_cyc = act_ms * cyc_ms;
|
||||
if (act_ms < w_ms) /* awakened early? */
|
||||
|
@ -802,10 +855,8 @@ if (sim_interval > act_cyc)
|
|||
else sim_interval = 0; /* or fire immediately */
|
||||
if (sim_clock_queue == QUEUE_LIST_END)
|
||||
sim_debug (DBG_IDL, &sim_timer_dev, "slept for %d ms - pending event in %d instructions\n", act_ms, sim_interval);
|
||||
else {
|
||||
DEVICE *d = find_dev_from_unit(sim_clock_queue);
|
||||
sim_debug (DBG_IDL, &sim_timer_dev, "slept for %d ms - pending event on %s in %d instructions\n", act_ms, d->name, sim_interval);
|
||||
}
|
||||
else
|
||||
sim_debug (DBG_IDL, &sim_timer_dev, "slept for %d ms - pending event on %s in %d instructions\n", act_ms, sim_uname(sim_clock_queue), sim_interval);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1099,21 +1150,19 @@ sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - starting\n");
|
|||
|
||||
pthread_mutex_lock (&sim_timer_lock);
|
||||
pthread_cond_signal (&sim_timer_startup_cond); /* Signal we're ready to go */
|
||||
while (sim_asynch_enabled && sim_is_running) {
|
||||
while (sim_asynch_enabled && sim_asynch_timer && sim_is_running) {
|
||||
struct timespec start_time, stop_time;
|
||||
struct timespec due_time;
|
||||
double wait_usec;
|
||||
int32 inst_delay;
|
||||
int32 inst_per_sec;
|
||||
double inst_per_sec;
|
||||
UNIT *uptr;
|
||||
DEVICE *d;
|
||||
|
||||
if (sim_wallclock_entry) { /* something to insert in queue? */
|
||||
UNIT *cptr, *prvptr;
|
||||
|
||||
d = find_dev_from_unit(sim_wallclock_entry);
|
||||
sim_debug (DBG_TIM, &sim_timer_dev, (d->numunits > 1) ? "_timer_thread() - timing %s%d for %d usec\n" : "_timer_thread() - timing %s%.0d for %d usec\n",
|
||||
d->name, (int)(sim_wallclock_entry-d->units), sim_wallclock_entry->time);
|
||||
sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - timing %s for %d usec\n",
|
||||
sim_uname(sim_wallclock_entry), sim_wallclock_entry->time);
|
||||
|
||||
uptr = sim_wallclock_entry;
|
||||
sim_wallclock_entry = NULL;
|
||||
|
@ -1140,7 +1189,6 @@ while (sim_asynch_enabled && sim_is_running) {
|
|||
/* the goal being to let the last fractional part of the due time */
|
||||
/* be done by counting instructions */
|
||||
_double_to_timespec (&due_time, sim_wallclock_queue->a_due_time-(((double)sim_idle_rate_ms)*0.0005));
|
||||
d = find_dev_from_unit(sim_wallclock_queue); /* find this before waiting */
|
||||
}
|
||||
else {
|
||||
due_time.tv_sec = 0x7FFFFFFF; /* Sometime when 32 bit time_t wraps */
|
||||
|
@ -1171,9 +1219,16 @@ while (sim_asynch_enabled && sim_is_running) {
|
|||
inst_delay = (int32)(inst_per_sec*(_timespec_to_double(&due_time)-_timespec_to_double(&stop_time)));
|
||||
uptr->a_last_fired_time = uptr->a_due_time;
|
||||
}
|
||||
sim_debug (DBG_TIM, &sim_timer_dev, (d->numunits > 1) ? "_timer_thread() - slept %.0fms - activating(%s%d,%d)\n" : "_timer_thread() - slept %.0fms - activating(%s%.0d,%d)\n",
|
||||
1000.0*(_timespec_to_double (&stop_time)-_timespec_to_double (&start_time)), d->name, (int)(uptr-d->units), inst_delay);
|
||||
sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - slept %.0fms - activating(%s,%d)\n",
|
||||
1000.0*(_timespec_to_double (&stop_time)-_timespec_to_double (&start_time)), sim_uname(uptr), inst_delay);
|
||||
sim_activate (uptr, inst_delay);
|
||||
if (sim_clock_unit == uptr)
|
||||
while (sim_clock_cosched_queue != QUEUE_LIST_END) {
|
||||
uptr = sim_clock_cosched_queue;
|
||||
sim_clock_cosched_queue = uptr->next;
|
||||
uptr->next = NULL;
|
||||
sim_activate (uptr, inst_delay);
|
||||
}
|
||||
}
|
||||
else /* Something wants to adjust the queue */
|
||||
if (sim_timer_event_canceled)
|
||||
|
@ -1195,7 +1250,7 @@ void sim_start_timer_services (void)
|
|||
{
|
||||
#if defined(SIM_ASYNCH_IO)
|
||||
pthread_mutex_lock (&sim_timer_lock);
|
||||
if (sim_asynch_enabled) {
|
||||
if (sim_asynch_enabled && sim_asynch_timer) {
|
||||
pthread_attr_t attr;
|
||||
UNIT *cptr;
|
||||
double delta_due_time;
|
||||
|
@ -1247,7 +1302,7 @@ else
|
|||
t_stat sim_timer_change_asynch (void)
|
||||
{
|
||||
#if defined(SIM_ASYNCH_IO)
|
||||
if (sim_asynch_enabled)
|
||||
if (sim_asynch_enabled && sim_asynch_timer)
|
||||
sim_start_timer_services ();
|
||||
else {
|
||||
UNIT *uptr;
|
||||
|
@ -1270,13 +1325,17 @@ else {
|
|||
return SCPE_OK;
|
||||
}
|
||||
|
||||
int32 sim_timer_inst_per_sec (void)
|
||||
/* Instruction Execution rate. */
|
||||
/* returns a double since it is mostly used in double expressions and
|
||||
to avoid overflow if/when strange timing delays might produce unexpected results */
|
||||
|
||||
double sim_timer_inst_per_sec (void)
|
||||
{
|
||||
int32 inst_per_sec;
|
||||
double inst_per_sec = SIM_INITIAL_IPS;
|
||||
|
||||
if (sim_calb_tmr == -1)
|
||||
return SIM_INITIAL_IPS;
|
||||
inst_per_sec = rtc_currd[sim_calb_tmr]*rtc_hz[sim_calb_tmr];
|
||||
return inst_per_sec;
|
||||
inst_per_sec = ((double)rtc_currd[sim_calb_tmr])*rtc_hz[sim_calb_tmr];
|
||||
if (0 == inst_per_sec)
|
||||
inst_per_sec = SIM_INITIAL_IPS;
|
||||
return inst_per_sec;
|
||||
|
@ -1285,23 +1344,20 @@ return inst_per_sec;
|
|||
t_stat sim_timer_activate_after (UNIT *uptr, int32 usec_delay)
|
||||
{
|
||||
int32 inst_delay;
|
||||
int32 inst_per_sec;
|
||||
DEVICE *d;
|
||||
double inst_per_sec;
|
||||
|
||||
AIO_VALIDATE;
|
||||
if (sim_is_active_bool (uptr)) /* already active? */
|
||||
return SCPE_OK;
|
||||
inst_per_sec = sim_timer_inst_per_sec ();
|
||||
inst_delay = (int32)((((double)inst_per_sec)*usec_delay)/1000000.0);
|
||||
inst_delay = (int32)((inst_per_sec*usec_delay)/1000000.0);
|
||||
#if defined(SIM_ASYNCH_IO)
|
||||
if ((sim_calb_tmr == -1) || /* if No timer initialized
|
||||
if ((sim_calb_tmr == -1) || /* if No timer initialized */
|
||||
(inst_delay < rtc_currd[sim_calb_tmr]) || /* or sooner than next clock tick? */
|
||||
(rtc_elapsed[sim_calb_tmr] < sim_idle_stable) || /* or not idle stable yet */
|
||||
(!sim_asynch_enabled)) { /* or asynch disabled */
|
||||
if (sim_deb)
|
||||
d = find_dev_from_unit(uptr);
|
||||
sim_debug (DBG_TIM, &sim_timer_dev, (d->numunits > 1) ? "sim_timer_activate_after() - activating %s%d after %d instructions\n" : "sim_timer_activate_after() - activating %s%.0d after %d instructions\n" ,
|
||||
d->name, (int)(uptr-d->units), inst_delay);
|
||||
(!(sim_asynch_enabled && sim_asynch_timer))) { /* or asynch disabled */
|
||||
sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after() - activating %s after %d instructions\n",
|
||||
sim_uname(uptr), inst_delay);
|
||||
return _sim_activate (uptr, inst_delay); /* queue it now */
|
||||
}
|
||||
if (1) {
|
||||
|
@ -1349,10 +1405,8 @@ if (1) {
|
|||
}
|
||||
uptr->time = usec_delay;
|
||||
|
||||
if (sim_deb)
|
||||
d = find_dev_from_unit(uptr);
|
||||
sim_debug (DBG_TIM, &sim_timer_dev, (d->numunits > 1) ? "sim_timer_activate_after() - queue addition %s%d at %.6f\n" : "sim_timer_activate_after() - queue addition %s%.0d at %.6f\n" ,
|
||||
d->name, (int)(uptr-d->units), uptr->a_due_time);
|
||||
sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after() - queue addition %s at %.6f\n",
|
||||
sim_uname(uptr), uptr->a_due_time);
|
||||
}
|
||||
pthread_mutex_lock (&sim_timer_lock);
|
||||
sim_wallclock_entry = uptr;
|
||||
|
@ -1364,3 +1418,36 @@ return _sim_activate (uptr, inst_delay); /* queue it now */
|
|||
#endif
|
||||
}
|
||||
|
||||
/* Clock coscheduling routines */
|
||||
|
||||
t_stat sim_register_clock_unit (UNIT *uptr)
|
||||
{
|
||||
sim_clock_unit = uptr;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat sim_clock_coschedule (UNIT *uptr, int32 interval)
|
||||
{
|
||||
if (NULL == sim_clock_unit)
|
||||
return sim_activate (uptr, interval);
|
||||
else
|
||||
if (sim_asynch_enabled && sim_asynch_timer) {
|
||||
if (!sim_is_active_bool (uptr)) { /* already active? */
|
||||
#if defined(SIM_ASYNCH_IO)
|
||||
sim_debug (DBG_TIM, &sim_timer_dev, "sim_clock_coschedule() - queueing %s for clock co-schedule\n", sim_uname (uptr));
|
||||
pthread_mutex_lock (&sim_timer_lock);
|
||||
uptr->next = sim_clock_cosched_queue;
|
||||
sim_clock_cosched_queue = uptr;
|
||||
pthread_mutex_unlock (&sim_timer_lock);
|
||||
#endif
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
else {
|
||||
int32 t;
|
||||
|
||||
t = sim_is_active (sim_clock_unit);
|
||||
return sim_activate (uptr, t? t - 1: interval);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,9 @@ void sim_start_timer_services (void);
|
|||
void sim_stop_timer_services (void);
|
||||
t_stat sim_timer_change_asynch (void);
|
||||
t_stat sim_timer_activate_after (UNIT *uptr, int32 usec_delay);
|
||||
int32 sim_timer_inst_per_sec (void);
|
||||
t_stat sim_register_clock_unit (UNIT *uptr);
|
||||
t_stat sim_clock_coschedule (UNIT *uptr, int32 interval);
|
||||
double sim_timer_inst_per_sec (void);
|
||||
|
||||
extern t_bool sim_idle_enab; /* idle enabled flag */
|
||||
extern volatile t_bool sim_idle_wait; /* idle waiting flag */
|
||||
|
|
77
sim_tmxr.c
77
sim_tmxr.c
|
@ -699,6 +699,25 @@ for (i = 0; i < mp->lines; i++) { /* initialize lines */
|
|||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Declare which unit polls for input
|
||||
|
||||
Inputs:
|
||||
*mp = the mux
|
||||
line = the line number
|
||||
*uptr_poll = the unit which polls
|
||||
|
||||
Outputs:
|
||||
none
|
||||
|
||||
Implementation note:
|
||||
|
||||
Only devices which poll on a unit different from the unit provided
|
||||
at MUX attach time need call this function. Calling this API is
|
||||
necessary for asynchronous multiplexer support and unnecessary
|
||||
otherwise.
|
||||
|
||||
*/
|
||||
|
||||
t_stat tmxr_set_line_unit (TMXR *mp, int line, UNIT *uptr_poll)
|
||||
{
|
||||
if ((line < 0) || (line >= mp->lines))
|
||||
|
@ -720,6 +739,33 @@ else
|
|||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Declare which unit polls for output
|
||||
|
||||
Inputs:
|
||||
*mp = the mux
|
||||
line = the line number
|
||||
*uptr_poll = the unit which polls for output
|
||||
|
||||
Outputs:
|
||||
none
|
||||
|
||||
Implementation note:
|
||||
|
||||
Only devices which poll on a unit different from the unit provided
|
||||
at MUX attach time need call this function AND different from the
|
||||
unit which polls for input. Calling this API is necessary for
|
||||
asynchronous multiplexer support and unnecessary otherwise.
|
||||
|
||||
*/
|
||||
|
||||
t_stat tmxr_set_line_output_unit (TMXR *mp, int line, UNIT *uptr_poll)
|
||||
{
|
||||
if ((line < 0) || (line >= mp->lines))
|
||||
return SCPE_ARG;
|
||||
mp->ldsc[line].o_uptr = uptr_poll;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
static TMXR **tmxr_open_devices = NULL;
|
||||
static int tmxr_open_device_count = 0;
|
||||
|
@ -770,7 +816,7 @@ while (sim_asynch_enabled) {
|
|||
|
||||
if ((tmxr_open_device_count == 0) || (!sim_is_running)) {
|
||||
for (j=0; j<wait_count; ++j) {
|
||||
sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Removing interest in %s%d. Other interest: %d\n", d->name, (int)(activated[j]-d->units), activated[j]->a_poll_waiter_count);
|
||||
sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Removing interest in %s. Other interest: %d\n", sim_uname(activated[j]), activated[j]->a_poll_waiter_count);
|
||||
--activated[j]->a_poll_waiter_count;
|
||||
--sim_tmxr_poll_count;
|
||||
}
|
||||
|
@ -827,7 +873,7 @@ while (sim_asynch_enabled) {
|
|||
mp->uptr->a_polling_now = TRUE;
|
||||
mp->uptr->a_poll_waiter_count = 0;
|
||||
d = find_dev_from_unit(mp->uptr);
|
||||
sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Activating %s%d to poll connect\n", d->name, (int)(mp->uptr-d->units));
|
||||
sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Activating %s to poll connect\n", sim_uname(mp->uptr));
|
||||
pthread_mutex_unlock (&sim_tmxr_poll_lock);
|
||||
_sim_activate (mp->uptr, 0);
|
||||
pthread_mutex_lock (&sim_tmxr_poll_lock);
|
||||
|
@ -847,8 +893,8 @@ while (sim_asynch_enabled) {
|
|||
mp->ldsc[j].uptr->a_polling_now = TRUE;
|
||||
mp->ldsc[j].uptr->a_poll_waiter_count = 0;
|
||||
d = find_dev_from_unit(mp->ldsc[j].uptr);
|
||||
sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Line %d Activating %s%d to poll data: %d/%d\n",
|
||||
j, d->name, (int)(mp->ldsc[j].uptr-d->units), tmxr_tqln(&mp->ldsc[j]), tmxr_rqln (&mp->ldsc[j]));
|
||||
sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Line %d Activating %s to poll data: %d/%d\n",
|
||||
j, sim_uname(mp->ldsc[j].uptr), tmxr_tqln(&mp->ldsc[j]), tmxr_rqln (&mp->ldsc[j]));
|
||||
pthread_mutex_unlock (&sim_tmxr_poll_lock);
|
||||
_sim_activate (mp->ldsc[j].uptr, 0);
|
||||
pthread_mutex_lock (&sim_tmxr_poll_lock);
|
||||
|
@ -884,14 +930,14 @@ while (sim_asynch_enabled) {
|
|||
activated[j]->a_polling_now = TRUE;
|
||||
activated[j]->a_poll_waiter_count = 1;
|
||||
d = find_dev_from_unit(activated[j]);
|
||||
sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Activating for data %s%d\n", d->name, (int)(activated[j]-d->units));
|
||||
sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Activating for data %s\n", sim_uname(activated[j]));
|
||||
pthread_mutex_unlock (&sim_tmxr_poll_lock);
|
||||
_sim_activate (activated[j], 0);
|
||||
pthread_mutex_lock (&sim_tmxr_poll_lock);
|
||||
}
|
||||
else {
|
||||
d = find_dev_from_unit(activated[j]);
|
||||
sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Already Activated %s%d %d times\n", d->name, (int)(activated[j]-d->units), activated[j]->a_poll_waiter_count);
|
||||
sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Already Activated %s%d %d times\n", sim_uname(activated[j]), activated[j]->a_poll_waiter_count);
|
||||
++activated[j]->a_poll_waiter_count;
|
||||
}
|
||||
}
|
||||
|
@ -1040,10 +1086,8 @@ else {
|
|||
for (j = 0; j < mp->lines; j++) {
|
||||
lp = mp->ldsc + j;
|
||||
fprintf (st, "Line: %d", j);
|
||||
if (lp->uptr && (lp->uptr != lp->mp->uptr)) {
|
||||
DEVICE *dptr = find_dev_from_unit (lp->uptr);
|
||||
fprintf (st, " - Unit: %s%d\n", dptr->name, (int)(lp->uptr-dptr->units));
|
||||
}
|
||||
if (lp->uptr && (lp->uptr != lp->mp->uptr))
|
||||
fprintf (st, " - Unit: %s\n", sim_uname (lp->uptr));
|
||||
else
|
||||
fprintf (st, "\n");
|
||||
if (!lp->conn)
|
||||
|
@ -1157,6 +1201,19 @@ return _sim_activate_after (uptr, usecs_walltime);
|
|||
#endif
|
||||
}
|
||||
|
||||
t_stat tmxr_clock_coschedule (UNIT *uptr, int32 interval)
|
||||
{
|
||||
#if defined(SIM_ASYNCH_IO)
|
||||
if ((!(uptr->flags & UNIT_TM_POLL)) ||
|
||||
(!sim_asynch_enabled)) {
|
||||
return sim_clock_coschedule (uptr, interval);
|
||||
}
|
||||
return SCPE_OK;
|
||||
#else
|
||||
return sim_clock_coschedule (uptr, interval);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Stub examine and deposit */
|
||||
|
||||
t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
||||
|
|
|
@ -91,7 +91,8 @@ struct tmln {
|
|||
char rbr[TMXR_MAXBUF]; /* rcv break */
|
||||
char *txb; /* xmt buffer */
|
||||
TMXR *mp; /* back pointer to mux */
|
||||
UNIT *uptr; /* pointer to receive poll unit */
|
||||
UNIT *uptr; /* input polling unit (default to mp->uptr) */
|
||||
UNIT *o_uptr; /* output polling unit (default to lp->uptr)*/
|
||||
};
|
||||
|
||||
struct tmxr {
|
||||
|
@ -101,7 +102,7 @@ struct tmxr {
|
|||
TMLN *ldsc; /* line descriptors */
|
||||
int32 *lnorder; /* line connection order */
|
||||
DEVICE *dptr; /* multiplexer device */
|
||||
UNIT *uptr; /* polling unit */
|
||||
UNIT *uptr; /* polling unit (connection) */
|
||||
char logfiletmpl[FILENAME_MAX]; /* template logfile name */
|
||||
int32 txcount; /* count of transmit bytes */
|
||||
int32 buffered; /* Buffered Line Behavior and Buffer Size Flag */
|
||||
|
@ -119,6 +120,7 @@ t_stat tmxr_close_master (TMXR *mp);
|
|||
t_stat tmxr_attach_ex (TMXR *mp, UNIT *uptr, char *cptr, t_bool async);
|
||||
t_stat tmxr_detach (TMXR *mp, UNIT *uptr);
|
||||
t_stat tmxr_set_line_unit (TMXR *mp, int line, UNIT *uptr_poll);
|
||||
t_stat tmxr_set_line_output_unit (TMXR *mp, int line, UNIT *uptr_poll);
|
||||
t_stat tmxr_set_console_input_unit (UNIT *uptr);
|
||||
t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||
|
@ -140,6 +142,7 @@ t_stat tmxr_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc);
|
|||
t_stat tmxr_show_open_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, char* desc);
|
||||
t_stat tmxr_activate (UNIT *uptr, int32 interval);
|
||||
t_stat tmxr_activate_after (UNIT *uptr, int32 usecs_walltime);
|
||||
t_stat tmxr_clock_coschedule (UNIT *uptr, int32 interval);
|
||||
t_stat tmxr_change_async (void);
|
||||
t_stat tmxr_startup (void);
|
||||
t_stat tmxr_shutdown (void);
|
||||
|
@ -156,6 +159,7 @@ extern FILE *sim_deb; /* debug file */
|
|||
#if (!defined(NOT_MUX_USING_CODE))
|
||||
#define sim_activate tmxr_activate
|
||||
#define sim_activate_after tmxr_activate_after
|
||||
#define sim_clock_coschedule tmxr_clock_coschedule
|
||||
#endif
|
||||
#else
|
||||
#define tmxr_attach(mp, uptr, cptr) tmxr_attach_ex(mp, uptr, cptr, FALSE)
|
||||
|
|
Loading…
Add table
Reference in a new issue