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 */
dci_clr_int (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;
case 02: /* dco csr */
@ -387,7 +389,6 @@ int32 ln, c, temp;
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return SCPE_OK;
sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */
ln = tmxr_poll_conn (&dcx_desc); /* look for connect */
if (ln >= 0) { /* got one? */
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;
}
}
return SCPE_OK;
return sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */
}
/* Terminal output service */
@ -531,7 +532,7 @@ int32 ln;
dcx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
sim_cancel (&dci_unit); /* assume stop */
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 */
dcx_reset_ln (ln);
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;
dli_csr[ln] &= ~CSR_DONE; /* clr rcv done */
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;
case 02: /* tto csr */
@ -377,7 +379,6 @@ sim_debug(DBG_TRC, &dli_dev, "dli_svc()\n");
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return SCPE_OK;
sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */
ln = tmxr_poll_conn (&dlx_desc); /* look for connect */
if (ln >= 0) { /* got one? rcv enb */
dlx_ldsc[ln].rcve = 1;
@ -418,7 +419,8 @@ for (ln = 0; ln < DLX_LINES; ln++) { /* loop thru lines */
/* clr CDT,RNG,CTS */
}
}
return SCPE_OK;
return sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */
}
/* Terminal output service */
@ -532,7 +534,7 @@ sim_debug(DBG_TRC, dptr, "dlx_reset()\n");
dlx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
sim_cancel (&dli_unit); /* assume stop */
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 */
dlx_reset_ln (ln);
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 */
dz_update_rcvi (); /* update rx intr */
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. */
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 {

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. */
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);
}
/* TX Q manipulation */

View file

@ -129,6 +129,7 @@
#include "sim_serial.h"
#include "sim_timer.h"
#include <ctype.h>
#include <math.h>
#ifdef __HAIKU__
#define nice(n) ({})
@ -1938,7 +1939,7 @@ if (!sim_rem_master_mode) {
(sim_con_ldsc.serport == 0)) { /* and not serial? */
if (c && sim_con_ldsc.rxbps) /* got something && rate limiting? */
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 */
}
if (!sim_con_ldsc.conn) { /* no telnet or serial connection? */

View file

@ -488,6 +488,7 @@ struct sim_unit {
int32 u6; /* device specific */
void *up7; /* device specific */
void *up8; /* device specific */
void *tmxr; /* TMXR linkage */
#ifdef SIM_ASYNCH_IO
void (*a_check_completion)(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);
}
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)
{
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_register_clock_unit (UNIT *uptr);
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_abs (UNIT *uptr, int32 tmr, int32 interval);
double sim_timer_inst_per_sec (void);
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 <ctype.h>
#include <math.h>
/* 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 */
lp->rxbpi = lp->rxbpr = 0;
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);
return val;
}
@ -1884,13 +1885,20 @@ return;
/* 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 (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
@ -3505,6 +3513,7 @@ if (r != SCPE_OK) /* error? */
mp->uptr = uptr; /* save unit for polling */
uptr->filename = tmxr_mux_attach_string (uptr->filename, mp);/* save */
uptr->flags = uptr->flags | UNIT_ATT; /* no more errors */
uptr->tmxr = (void *)mp;
if ((mp->lines > 1) ||
((mp->master == 0) &&
(mp->ldsc[0].connecting == 0) &&
@ -3703,6 +3712,7 @@ if (!(uptr->flags & UNIT_ATT)) /* attached? */
tmxr_close_master (mp); /* close master socket */
free (uptr->filename); /* free setup string */
uptr->filename = NULL;
uptr->tmxr = NULL;
mp->last_poll_time = 0;
for (i=0; i < mp->lines; i++) {
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);
}
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)
{
TMXR *mp = (TMXR *)uptr->tmxr;
double sim_gtime_now = sim_gtime ();
#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX)
if ((!(uptr->dynflags & UNIT_TM_POLL)) ||
(!sim_asynch_enabled)) {
@ -3771,10 +3792,35 @@ if ((!(uptr->dynflags & UNIT_TM_POLL)) ||
}
return SCPE_OK;
#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);
#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 */
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_abs (UNIT *uptr, int32 usecs_walltime);
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_abs (UNIT *uptr, int32 tmr, int32 interval);
t_stat tmxr_change_async (void);
t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
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)
#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))
#define sim_activate tmxr_activate
#define sim_activate_after tmxr_activate_after
#define sim_activate_after_abs tmxr_activate_after_abs
#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
#endif
#else
#define tmxr_attach(mp, uptr, cptr) tmxr_attach_ex(mp, uptr, cptr, FALSE)
#define sim_clock_coschedule_tmr_abs tmxr_clock_coschedule_tmr_abs
#endif