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:
Mark Pizzolato 2012-11-12 15:33:35 -08:00
parent 030d790b4c
commit 7c7df669ad
14 changed files with 367 additions and 115 deletions

View file

@ -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.

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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 }
};

View file

@ -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
View file

@ -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
View file

@ -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);

View file

@ -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

View file

@ -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)

View file

@ -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);
}
}

View file

@ -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 */

View file

@ -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)

View file

@ -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)