From 0938d31e59ac065e88880dc24410a1c7f6c284a8 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sat, 28 Nov 2015 12:49:54 -0800 Subject: [PATCH] PDP11, VAX: MUX input rate limiting works correctly with input arriving on multiple lines concurrently. --- PDP11/pdp11_dc.c | 9 +++++---- PDP11/pdp11_dl.c | 10 ++++++---- PDP11/pdp11_dz.c | 4 ++-- PDP11/pdp11_vh.c | 4 ++-- sim_console.c | 5 +++-- sim_defs.h | 1 + sim_timer.c | 12 +++++++++++ sim_timer.h | 2 ++ sim_tmxr.c | 52 +++++++++++++++++++++++++++++++++++++++++++++--- sim_tmxr.h | 10 +++++++--- 10 files changed, 89 insertions(+), 20 deletions(-) diff --git a/PDP11/pdp11_dc.c b/PDP11/pdp11_dc.c index 1f431322..aafe8a20 100644 --- a/PDP11/pdp11_dc.c +++ b/PDP11/pdp11_dc.c @@ -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 */ diff --git a/PDP11/pdp11_dl.c b/PDP11/pdp11_dl.c index 6dccfb5b..49321d2a 100644 --- a/PDP11/pdp11_dl.c +++ b/PDP11/pdp11_dl.c @@ -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 */ diff --git a/PDP11/pdp11_dz.c b/PDP11/pdp11_dz.c index 3a4bb65d..21b6ee22 100644 --- a/PDP11/pdp11_dz.c +++ b/PDP11/pdp11_dz.c @@ -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 { diff --git a/PDP11/pdp11_vh.c b/PDP11/pdp11_vh.c index e888c81d..4d6ea323 100644 --- a/PDP11/pdp11_vh.c +++ b/PDP11/pdp11_vh.c @@ -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 */ diff --git a/sim_console.c b/sim_console.c index 849f85c4..0e8697bf 100644 --- a/sim_console.c +++ b/sim_console.c @@ -129,7 +129,8 @@ #include "sim_serial.h" #include "sim_timer.h" #include - +#include + #ifdef __HAIKU__ #define nice(n) ({}) #endif @@ -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? */ diff --git a/sim_defs.h b/sim_defs.h index 507446e4..8f4204ae 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -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 *); diff --git a/sim_timer.c b/sim_timer.c index d4e6923a..4172bf60 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -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); +} + diff --git a/sim_timer.h b/sim_timer.h index ea22503e..9675253c 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -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); diff --git a/sim_tmxr.c b/sim_tmxr.c index eac0f07c..e8732836 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -340,6 +340,7 @@ #include "scp.h" #include +#include /* 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) diff --git a/sim_tmxr.h b/sim_tmxr.h index d6b36711..929f347e 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -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