PDP11, VAX: Change VH programmed I/O to consistently complete after delay

previously, programmed I/O was initiated and completed as the time it was
initiated.  Now that output is rate limited to the port selected speeds the
output buffer can fill and I/O be dropped when the buffer was full.  Now all
output is setup in the register write path and completed in the unit service
path.  A separate transmit service unit now performs all transmit I/O
completion activity.
This commit is contained in:
Mark Pizzolato 2018-06-21 08:42:05 -07:00
parent 90327012a9
commit 91bd90c368

View file

@ -457,6 +457,7 @@ DEBTAB vh_debug[] = {
static t_stat vh_rd (int32 *data, int32 PA, int32 access);
static t_stat vh_wr (int32 data, int32 PA, int32 access);
static t_stat vh_svc (UNIT *uptr);
static t_stat vh_xmt_svc (UNIT *uptr);
static t_stat vh_timersvc (UNIT *uptr);
static int32 vh_rxinta (void);
static int32 vh_txinta (void);
@ -496,12 +497,13 @@ static DIB vh_dib = {
IOLN_VH, /* IO space per device */
};
static UNIT vh_unit[VH_MUXES+1] = {
{ UDATA (&vh_svc, UNIT_IDLE|UNIT_ATTABLE, 0) },
static UNIT vh_unit[VH_MUXES+3] = {
{ UDATA (NULL, UNIT_ATTABLE, 0) },
};
static UNIT *vh_poll_unit;
static UNIT *vh_xmit_unit;
static UNIT *vh_timer_unit;
static UNIT *vh_poll_unit = &vh_unit[0];
static const REG vh_reg[] = {
{ BRDATADF (CSR, vh_csr, DEV_RDX, 16, VH_MUXES, "control/status register, boards 0 to 3", vh_csr_bits) },
@ -1120,17 +1122,8 @@ static t_stat vh_wr ( int32 ldata,
(lp->txchar & 0377) | (data << 8) :
(lp->txchar & ~0377) | (data & 0377);
lp->txchar = data; /* TXCHAR */
if (lp->txchar & TXCHAR_TX_DATA_VALID) {
if (lp->tbuf2 & TB2_TX_ENA) {
if (vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]),
lp->txchar) != SCPE_STALL) {
q_tx_report (vh, CSR_GETCHAN (vh_csr[vh]) << CSR_V_TX_LINE);
lp->txchar &= ~TXCHAR_TX_DATA_VALID;
}
else
sim_activate_after_abs (vh_unit, lp->tmln->txdeltausecs);
}
}
if (lp->txchar & TXCHAR_TX_DATA_VALID)
sim_activate_after_abs (vh_xmit_unit, lp->tmln->txdeltausecs);
}
break;
case 2: /* LPR */
@ -1387,7 +1380,7 @@ static t_stat vh_timersvc ( UNIT *uptr )
static t_stat vh_svc ( UNIT *uptr )
{
int32 vh, newln, i;
int32 vh, newln;
sim_debug(DBG_TRC, find_dev_from_unit(uptr), "vh_svc()\n");
@ -1408,6 +1401,20 @@ static t_stat vh_svc ( UNIT *uptr )
((lp->lstat >> 8) & 0376));
/* BUG: should check for overflow above */
}
/* interrupt driven in a real DHQ */
tmxr_poll_rx (&vh_desc);
for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++)
vh_getc (vh);
sim_clock_coschedule (uptr, tmxr_poll); /* requeue ourselves */
return SCPE_OK;
}
static t_stat vh_xmt_svc ( UNIT *uptr )
{
int32 vh, i;
sim_debug(DBG_TRC, find_dev_from_unit(uptr), "vh_xmt_svc()\n");
/* scan all muxes lines */
for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++) {
for (i = 0; i < VH_LINES; i++) {
@ -1429,13 +1436,9 @@ static t_stat vh_svc ( UNIT *uptr )
doDMA (vh, i);
}
}
/* interrupt driven in a real DHQ */
tmxr_poll_rx (&vh_desc);
for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++)
vh_getc (vh);
tmxr_poll_tx (&vh_desc);
sim_clock_coschedule (uptr, tmxr_poll); /* requeue ourselves */
return (SCPE_OK);
return SCPE_OK;
}
/* init a channel on a controller */
@ -1544,24 +1547,41 @@ static t_stat vh_reset ( DEVICE *dptr )
tmxr_set_port_speed_control (&vh_desc);
if (vh_desc.lines > VH_MUXES*VH_LINES)
vh_desc.lines = VH_MUXES*VH_LINES;
for (i = 0; i < vh_desc.lines; i++)
for (i = 0; i < vh_desc.lines; i++) {
vh_parm[i].tmln = &vh_ldsc[i];
vh_dev.numunits = (vh_desc.lines / VH_LINES) + 1;
vh_timer_unit = &vh_unit[vh_dev.numunits-1];
tmxr_set_line_unit (&vh_desc, i, vh_poll_unit);
tmxr_set_line_output_unit (&vh_desc, i, vh_xmit_unit);
}
vh_dev.numunits = (vh_desc.lines / VH_LINES) + 3;
if (vh_poll_unit)
sim_cancel (vh_poll_unit);
vh_poll_unit = &vh_unit[(vh_desc.lines / VH_LINES) + 0];
vh_poll_unit->action = &vh_svc;
vh_poll_unit->flags = UNIT_DIS | UNIT_IDLE;
if (vh_xmit_unit)
sim_cancel (vh_xmit_unit);
vh_xmit_unit = &vh_unit[(vh_desc.lines / VH_LINES) + 1];
vh_xmit_unit->action = &vh_xmt_svc;
vh_xmit_unit->flags = UNIT_DIS;
if (vh_timer_unit)
sim_cancel (vh_timer_unit);
vh_timer_unit = &vh_unit[(vh_desc.lines / VH_LINES) + 2];
vh_timer_unit->action = &vh_timersvc;
vh_timer_unit->flags = UNIT_DIS | UNIT_IDLE;
for (i = 0; i < vh_desc.lines/VH_LINES; i++) {
/* if Unibus, force DHU mode */
if (UNIBUS)
vh_unit[i].flags |= UNIT_MODEDHU;
vh_unit[i].flags &= ~UNIT_DIS;
vh_clear (i, TRUE);
for (i = 0; i < VH_MUXES; i++) {
if (i < vh_desc.lines/VH_LINES) {
/* if Unibus, force DHU mode */
if (UNIBUS)
vh_unit[i].flags |= UNIT_MODEDHU;
vh_unit[i].flags &= ~UNIT_DIS;
vh_clear (i, TRUE);
} else {
vh_unit[i].flags |= UNIT_DIS;
}
}
vh_rxi = vh_txi = 0;
CLR_INT (VHRX);
CLR_INT (VHTX);
sim_cancel (vh_poll_unit);
sim_cancel (vh_timer_unit);
vh_dib.lnt = (vh_desc.lines / VH_LINES) * IOLN_VH; /* set length */
return (auto_config (dptr->name, (dptr->flags & DEV_DIS) ? 0 : vh_desc.lines/VH_LINES));
}
@ -1570,9 +1590,9 @@ static t_stat vh_reset ( DEVICE *dptr )
static t_stat vh_attach ( UNIT *uptr,
CONST char *cptr )
{
if (uptr == vh_poll_unit)
return (tmxr_attach (&vh_desc, uptr, cptr));
return (SCPE_NOATT);
if (uptr == vh_unit)
return tmxr_attach (&vh_desc, uptr, cptr);
return SCPE_NOATT;
}
static t_stat vh_detach ( UNIT *uptr )
@ -1661,7 +1681,7 @@ newln = (int32) get_uint (cptr, 10, (VH_MUXES * VH_LINES), &r);
if ((r != SCPE_OK) || (newln == vh_desc.lines))
return r;
if ((newln == 0) || (newln % VH_LINES))
return SCPE_ARG;
return sim_messagef (SCPE_ARG, "VH line count must be a multiple of %d\n", VH_LINES);
if (newln < vh_desc.lines) {
for (i = newln, t = 0; i < vh_desc.lines; i++)
t = t | vh_ldsc[i].conn;