PDP11, VAX: MUX input rate limiting works correctly with input arriving on multiple lines concurrently.

This commit is contained in:
Mark Pizzolato 2015-11-28 12:49:54 -08:00
parent d66b5a4671
commit 0938d31e59
10 changed files with 89 additions and 20 deletions

View file

@ -290,7 +290,9 @@ switch ((PA >> 1) & 03) { /* decode PA<2:1> */
case 01: /* dci buf */ case 01: /* dci buf */
dci_clr_int (ln); dci_clr_int (ln);
*data = dci_buf[ln]; *data = dci_buf[ln];
sim_activate_after_abs (&dci_unit, dci_unit.wait); /* Rechedule the next poll preceisely so that
the programmed input speed is observed. */
sim_clock_coschedule_abs (&dci_unit, tmxr_poll);
return SCPE_OK; return SCPE_OK;
case 02: /* dco csr */ case 02: /* dco csr */
@ -387,7 +389,6 @@ int32 ln, c, temp;
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return SCPE_OK; return SCPE_OK;
sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */
ln = tmxr_poll_conn (&dcx_desc); /* look for connect */ ln = tmxr_poll_conn (&dcx_desc); /* look for connect */
if (ln >= 0) { /* got one? */ if (ln >= 0) { /* got one? */
dcx_ldsc[ln].rcve = 1; /* set rcv enb */ dcx_ldsc[ln].rcve = 1; /* set rcv enb */
@ -432,7 +433,7 @@ for (ln = 0; ln < DCX_LINES; ln++) { /* loop thru lines */
dco_csr[ln] &= ~DCOCSR_CTS; dco_csr[ln] &= ~DCOCSR_CTS;
} }
} }
return SCPE_OK; return sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */
} }
/* Terminal output service */ /* Terminal output service */
@ -531,7 +532,7 @@ int32 ln;
dcx_enbdis (dptr->flags & DEV_DIS); /* sync enables */ dcx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
sim_cancel (&dci_unit); /* assume stop */ sim_cancel (&dci_unit); /* assume stop */
if (dci_unit.flags & UNIT_ATT) /* if attached, */ if (dci_unit.flags & UNIT_ATT) /* if attached, */
sim_activate (&dci_unit, tmxr_poll); /* activate */ sim_clock_coschedule (&dci_unit, tmxr_poll); /* activate */
for (ln = 0; ln < DCX_LINES; ln++) /* for all lines */ for (ln = 0; ln < DCX_LINES; ln++) /* for all lines */
dcx_reset_ln (ln); dcx_reset_ln (ln);
return auto_config (dci_dev.name, dcx_desc.lines); /* auto config */ return auto_config (dci_dev.name, dcx_desc.lines); /* auto config */

View file

@ -272,7 +272,9 @@ switch ((PA >> 1) & 03) { /* decode PA<2:1> */
*data = dli_buf[ln] & DLIBUF_RD; *data = dli_buf[ln] & DLIBUF_RD;
dli_csr[ln] &= ~CSR_DONE; /* clr rcv done */ dli_csr[ln] &= ~CSR_DONE; /* clr rcv done */
dli_clr_int (ln, DLI_RCI); /* clr rcv int req */ dli_clr_int (ln, DLI_RCI); /* clr rcv int req */
sim_activate_after_abs (&dli_unit, dli_unit.wait); /* Rechedule the next poll preceisely so that
the programmed input speed is observed. */
sim_clock_coschedule_abs (&dli_unit, tmxr_poll);
break; break;
case 02: /* tto csr */ case 02: /* tto csr */
@ -377,7 +379,6 @@ sim_debug(DBG_TRC, &dli_dev, "dli_svc()\n");
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return SCPE_OK; return SCPE_OK;
sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */
ln = tmxr_poll_conn (&dlx_desc); /* look for connect */ ln = tmxr_poll_conn (&dlx_desc); /* look for connect */
if (ln >= 0) { /* got one? rcv enb */ if (ln >= 0) { /* got one? rcv enb */
dlx_ldsc[ln].rcve = 1; dlx_ldsc[ln].rcve = 1;
@ -418,7 +419,8 @@ for (ln = 0; ln < DLX_LINES; ln++) { /* loop thru lines */
/* clr CDT,RNG,CTS */ /* clr CDT,RNG,CTS */
} }
} }
return SCPE_OK; return sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */
} }
/* Terminal output service */ /* Terminal output service */
@ -532,7 +534,7 @@ sim_debug(DBG_TRC, dptr, "dlx_reset()\n");
dlx_enbdis (dptr->flags & DEV_DIS); /* sync enables */ dlx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
sim_cancel (&dli_unit); /* assume stop */ sim_cancel (&dli_unit); /* assume stop */
if (dli_unit.flags & UNIT_ATT) /* if attached, */ if (dli_unit.flags & UNIT_ATT) /* if attached, */
sim_activate (&dli_unit, tmxr_poll); /* activate */ sim_clock_coschedule (&dli_unit, tmxr_poll); /* activate */
for (ln = 0; ln < DLX_LINES; ln++) /* for all lines */ for (ln = 0; ln < DLX_LINES; ln++) /* for all lines */
dlx_reset_ln (ln); dlx_reset_ln (ln);
return auto_config (dli_dev.name, dlx_desc.lines); /* auto config */ return auto_config (dli_dev.name, dlx_desc.lines); /* auto config */

View file

@ -392,9 +392,9 @@ switch ((PA >> 1) & 03) { /* case on PA<2:1> */
tmxr_poll_rx (&dz_desc); /* poll input */ tmxr_poll_rx (&dz_desc); /* poll input */
dz_update_rcvi (); /* update rx intr */ dz_update_rcvi (); /* update rx intr */
if (dz_rbuf[dz]) { if (dz_rbuf[dz]) {
/* Schedule the next poll somewhat preceisely so that /* Rechedule the next poll preceisely so that
the programmed input speed is observed. */ the programmed input speed is observed. */
sim_activate_after_abs (&dz_unit, dz_ldsc[(dz * DZ_LINES) + (dz_rbuf[dz]>>RBUF_V_RLINE) & 07].rxdelta + dz_wait); sim_clock_coschedule_abs (&dz_unit, tmxr_poll);
} }
} }
else { else {

View file

@ -681,9 +681,9 @@ static int32 fifo_get ( int32 vh )
} }
} }
} }
/* Schedule the next poll somewhat preceisely so that the /* Reschedule the next poll preceisely so that the
programmed input speed is observed. */ programmed input speed is observed. */
sim_activate_after_abs (&vh_unit[0], vh_parm[(vh * VH_LINES) + RBUF_GETLINE(data)].tmln->rxdelta + vh_wait); sim_clock_coschedule_abs (&vh_unit[0], tmxr_poll);
return (data & 0177777); return (data & 0177777);
} }
/* TX Q manipulation */ /* TX Q manipulation */

View file

@ -129,7 +129,8 @@
#include "sim_serial.h" #include "sim_serial.h"
#include "sim_timer.h" #include "sim_timer.h"
#include <ctype.h> #include <ctype.h>
#include <math.h>
#ifdef __HAIKU__ #ifdef __HAIKU__
#define nice(n) ({}) #define nice(n) ({})
#endif #endif
@ -1938,7 +1939,7 @@ if (!sim_rem_master_mode) {
(sim_con_ldsc.serport == 0)) { /* and not serial? */ (sim_con_ldsc.serport == 0)) { /* and not serial? */
if (c && sim_con_ldsc.rxbps) /* got something && rate limiting? */ if (c && sim_con_ldsc.rxbps) /* got something && rate limiting? */
sim_con_ldsc.rxnexttime = /* compute next input time */ sim_con_ldsc.rxnexttime = /* compute next input time */
sim_gtime () + ((sim_con_ldsc.rxdelta * sim_timer_inst_per_sec ())/sim_con_ldsc.rxbpsfactor); floor (sim_gtime () + ((sim_con_ldsc.rxdelta * sim_timer_inst_per_sec ())/sim_con_ldsc.rxbpsfactor));
return c; /* in-window */ return c; /* in-window */
} }
if (!sim_con_ldsc.conn) { /* no telnet or serial connection? */ if (!sim_con_ldsc.conn) { /* no telnet or serial connection? */

View file

@ -488,6 +488,7 @@ struct sim_unit {
int32 u6; /* device specific */ int32 u6; /* device specific */
void *up7; /* device specific */ void *up7; /* device specific */
void *up8; /* device specific */ void *up8; /* device specific */
void *tmxr; /* TMXR linkage */
#ifdef SIM_ASYNCH_IO #ifdef SIM_ASYNCH_IO
void (*a_check_completion)(struct sim_unit *); void (*a_check_completion)(struct sim_unit *);
t_bool (*a_is_active)(struct sim_unit *); t_bool (*a_is_active)(struct sim_unit *);

View file

@ -1578,6 +1578,12 @@ t_stat sim_clock_coschedule (UNIT *uptr, int32 interval)
return sim_clock_coschedule_tmr (uptr, 0, interval); return sim_clock_coschedule_tmr (uptr, 0, interval);
} }
t_stat sim_clock_coschedule_abs (UNIT *uptr, int32 interval)
{
sim_cancel (uptr);
return sim_clock_coschedule_tmr (uptr, 0, interval);
}
t_stat sim_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 interval) t_stat sim_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 interval)
{ {
if (NULL == sim_clock_unit[tmr]) if (NULL == sim_clock_unit[tmr])
@ -1616,3 +1622,9 @@ else
} }
} }
t_stat sim_clock_coschedule_tmr_abs (UNIT *uptr, int32 tmr, int32 interval)
{
sim_cancel (uptr);
return sim_clock_coschedule_tmr (uptr, tmr, interval);
}

View file

@ -122,7 +122,9 @@ t_stat sim_timer_change_asynch (void);
t_stat sim_timer_activate_after (UNIT *uptr, int32 usec_delay); t_stat sim_timer_activate_after (UNIT *uptr, int32 usec_delay);
t_stat sim_register_clock_unit (UNIT *uptr); t_stat sim_register_clock_unit (UNIT *uptr);
t_stat sim_clock_coschedule (UNIT *uptr, int32 interval); t_stat sim_clock_coschedule (UNIT *uptr, int32 interval);
t_stat sim_clock_coschedule_abs (UNIT *uptr, int32 interval);
t_stat sim_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 interval); t_stat sim_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 interval);
t_stat sim_clock_coschedule_tmr_abs (UNIT *uptr, int32 tmr, int32 interval);
double sim_timer_inst_per_sec (void); double sim_timer_inst_per_sec (void);
t_bool sim_timer_idle_capable (uint32 *host_ms_sleep_1, uint32 *host_tick_ms); t_bool sim_timer_idle_capable (uint32 *host_ms_sleep_1, uint32 *host_tick_ms);

View file

@ -340,6 +340,7 @@
#include "scp.h" #include "scp.h"
#include <ctype.h> #include <ctype.h>
#include <math.h>
/* Telnet protocol constants - negatives are for init'ing signed char data */ /* Telnet protocol constants - negatives are for init'ing signed char data */
@ -1565,7 +1566,7 @@ if ((lp->conn && lp->rcve) && /* conn & enb & */
if (lp->rxbpi == lp->rxbpr) /* empty? zero ptrs */ if (lp->rxbpi == lp->rxbpr) /* empty? zero ptrs */
lp->rxbpi = lp->rxbpr = 0; lp->rxbpi = lp->rxbpr = 0;
if (val && lp->rxbps) if (val && lp->rxbps)
lp->rxnexttime = sim_gtime () + ((lp->rxdelta * sim_timer_inst_per_sec ())/lp->rxbpsfactor); lp->rxnexttime = floor (sim_gtime () + ((lp->rxdelta * sim_timer_inst_per_sec ())/lp->rxbpsfactor));
tmxr_debug_return(lp, val); tmxr_debug_return(lp, val);
return val; return val;
} }
@ -1884,13 +1885,20 @@ return;
/* Return count of available characters for line */ /* Return count of available characters for line */
int32 tmxr_rqln (TMLN *lp) int32 tmxr_rqln_bare (TMLN *lp, t_bool speed)
{ {
if ((lp->rxbps) && (sim_gtime () < lp->rxnexttime)) /* rate limiting and too soon */ if ((speed) &&
(lp->rxbps) &&
(sim_gtime () < lp->rxnexttime)) /* rate limiting and too soon */
return 0; return 0;
return (lp->rxbpi - lp->rxbpr + ((lp->rxbpi < lp->rxbpr)? lp->rxbsz: 0)); return (lp->rxbpi - lp->rxbpr + ((lp->rxbpi < lp->rxbpr)? lp->rxbsz: 0));
} }
int32 tmxr_rqln (TMLN *lp)
{
return tmxr_rqln_bare (lp, TRUE);
}
/* Store character in line buffer /* Store character in line buffer
@ -3505,6 +3513,7 @@ if (r != SCPE_OK) /* error? */
mp->uptr = uptr; /* save unit for polling */ mp->uptr = uptr; /* save unit for polling */
uptr->filename = tmxr_mux_attach_string (uptr->filename, mp);/* save */ uptr->filename = tmxr_mux_attach_string (uptr->filename, mp);/* save */
uptr->flags = uptr->flags | UNIT_ATT; /* no more errors */ uptr->flags = uptr->flags | UNIT_ATT; /* no more errors */
uptr->tmxr = (void *)mp;
if ((mp->lines > 1) || if ((mp->lines > 1) ||
((mp->master == 0) && ((mp->master == 0) &&
(mp->ldsc[0].connecting == 0) && (mp->ldsc[0].connecting == 0) &&
@ -3703,6 +3712,7 @@ if (!(uptr->flags & UNIT_ATT)) /* attached? */
tmxr_close_master (mp); /* close master socket */ tmxr_close_master (mp); /* close master socket */
free (uptr->filename); /* free setup string */ free (uptr->filename); /* free setup string */
uptr->filename = NULL; uptr->filename = NULL;
uptr->tmxr = NULL;
mp->last_poll_time = 0; mp->last_poll_time = 0;
for (i=0; i < mp->lines; i++) { for (i=0; i < mp->lines; i++) {
UNIT *uptr = mp->ldsc[i].uptr ? mp->ldsc[i].uptr : mp->uptr; UNIT *uptr = mp->ldsc[i].uptr ? mp->ldsc[i].uptr : mp->uptr;
@ -3762,8 +3772,19 @@ t_stat tmxr_clock_coschedule (UNIT *uptr, int32 interval)
return tmxr_clock_coschedule_tmr (uptr, 0, interval); return tmxr_clock_coschedule_tmr (uptr, 0, interval);
} }
t_stat tmxr_clock_coschedule_abs (UNIT *uptr, int32 interval)
{
sim_cancel (uptr);
return tmxr_clock_coschedule_tmr (uptr, 0, interval);
}
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
t_stat tmxr_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 interval) t_stat tmxr_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 interval)
{ {
TMXR *mp = (TMXR *)uptr->tmxr;
double sim_gtime_now = sim_gtime ();
#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX) #if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX)
if ((!(uptr->dynflags & UNIT_TM_POLL)) || if ((!(uptr->dynflags & UNIT_TM_POLL)) ||
(!sim_asynch_enabled)) { (!sim_asynch_enabled)) {
@ -3771,10 +3792,35 @@ if ((!(uptr->dynflags & UNIT_TM_POLL)) ||
} }
return SCPE_OK; return SCPE_OK;
#else #else
if (mp) {
int32 i, soon = interval;
for (i = 0; i < mp->lines; i++) {
TMLN *lp = &mp->ldsc[i];
if (tmxr_rqln_bare (lp, FALSE)) {
int32 due;
if (lp->rxbps)
due = (int32)(lp->rxnexttime - sim_gtime_now);
else
due = (int32)((uptr->wait * sim_timer_inst_per_sec ())/TMXR_RX_BPS_UNIT_SCALE);
soon = MIN(soon, due);
}
}
if (soon != interval)
return _sim_activate (uptr, soon);
}
return sim_clock_coschedule_tmr (uptr, tmr, interval); return sim_clock_coschedule_tmr (uptr, tmr, interval);
#endif #endif
} }
t_stat tmxr_clock_coschedule_tmr_abs (UNIT *uptr, int32 tmr, int32 interval)
{
sim_cancel (uptr);
return tmxr_clock_coschedule_tmr (uptr, tmr, interval);
}
/* Generic Multiplexer attach help */ /* Generic Multiplexer attach help */
t_stat tmxr_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) t_stat tmxr_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)

View file

@ -275,7 +275,9 @@ t_stat tmxr_activate (UNIT *uptr, int32 interval);
t_stat tmxr_activate_after (UNIT *uptr, int32 usecs_walltime); t_stat tmxr_activate_after (UNIT *uptr, int32 usecs_walltime);
t_stat tmxr_activate_after_abs (UNIT *uptr, int32 usecs_walltime); t_stat tmxr_activate_after_abs (UNIT *uptr, int32 usecs_walltime);
t_stat tmxr_clock_coschedule (UNIT *uptr, int32 interval); t_stat tmxr_clock_coschedule (UNIT *uptr, int32 interval);
t_stat tmxr_clock_coschedule_abs (UNIT *uptr, int32 interval);
t_stat tmxr_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 interval); t_stat tmxr_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 interval);
t_stat tmxr_clock_coschedule_tmr_abs (UNIT *uptr, int32 tmr, int32 interval);
t_stat tmxr_change_async (void); t_stat tmxr_change_async (void);
t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd); t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp); t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
@ -294,15 +296,17 @@ void _tmxr_debug (uint32 dbits, TMLN *lp, const char *msg, char *buf, int bufsiz
#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX) #if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX)
#define tmxr_attach(mp, uptr, cptr) tmxr_attach_ex(mp, uptr, cptr, TRUE) #define tmxr_attach(mp, uptr, cptr) tmxr_attach_ex(mp, uptr, cptr, TRUE)
#else
#define tmxr_attach(mp, uptr, cptr) tmxr_attach_ex(mp, uptr, cptr, FALSE)
#endif
#if (!defined(NOT_MUX_USING_CODE)) #if (!defined(NOT_MUX_USING_CODE))
#define sim_activate tmxr_activate #define sim_activate tmxr_activate
#define sim_activate_after tmxr_activate_after #define sim_activate_after tmxr_activate_after
#define sim_activate_after_abs tmxr_activate_after_abs #define sim_activate_after_abs tmxr_activate_after_abs
#define sim_clock_coschedule tmxr_clock_coschedule #define sim_clock_coschedule tmxr_clock_coschedule
#define sim_clock_coschedule_abs tmxr_clock_coschedule_abs
#define sim_clock_coschedule_tmr tmxr_clock_coschedule_tmr #define sim_clock_coschedule_tmr tmxr_clock_coschedule_tmr
#endif #define sim_clock_coschedule_tmr_abs tmxr_clock_coschedule_tmr_abs
#else
#define tmxr_attach(mp, uptr, cptr) tmxr_attach_ex(mp, uptr, cptr, FALSE)
#endif #endif