PDP11, VAX: Rework receive descriptor list processing and PDP11 Boot.
PDP11 network boot ROM of the DEQNA, DELQA, and DELQA-T along with the MicroVAX I ROM boot each expect particular behavior from the XQ device. Prior efforts to get the PDP11 boot working added several device specific complications to the receive buffer processing. These are now simplified. Meanwhile, the generic device 'work alike' boot process has been implemented to provide an XQ (device independent) primary loader which extracts the first 512 bytes of the device internal boot ROM and passes control to it for a complete boot.
This commit is contained in:
parent
e054a78398
commit
746c4fdc15
3 changed files with 240 additions and 86 deletions
132
PDP11/pdp11_xq.c
132
PDP11/pdp11_xq.c
|
@ -47,9 +47,8 @@
|
||||||
seen by the simulated cpu since there are no minimum response times.
|
seen by the simulated cpu since there are no minimum response times.
|
||||||
|
|
||||||
Known Bugs or Unsupported features, in priority order:
|
Known Bugs or Unsupported features, in priority order:
|
||||||
1) PDP11 bootstrap
|
1) MOP functionality not implemented
|
||||||
2) MOP functionality not implemented
|
2) Local packet processing not implemented
|
||||||
3) Local packet processing not implemented
|
|
||||||
|
|
||||||
Regression Tests:
|
Regression Tests:
|
||||||
VAX: 1. Console SHOW DEVICE
|
VAX: 1. Console SHOW DEVICE
|
||||||
|
@ -617,7 +616,6 @@ CTLR* xq_pa2ctlr(uint32 PA)
|
||||||
t_stat xq_ex (t_value* vptr, t_addr addr, UNIT* uptr, int32 sw)
|
t_stat xq_ex (t_value* vptr, t_addr addr, UNIT* uptr, int32 sw)
|
||||||
{
|
{
|
||||||
/* on PDP-11, allow EX command to look at bootrom */
|
/* on PDP-11, allow EX command to look at bootrom */
|
||||||
#ifdef VM_PDP11
|
|
||||||
CTLR* xq = xq_unit2ctlr(uptr);
|
CTLR* xq = xq_unit2ctlr(uptr);
|
||||||
uint16 *bootrom = NULL;
|
uint16 *bootrom = NULL;
|
||||||
|
|
||||||
|
@ -634,9 +632,6 @@ t_stat xq_ex (t_value* vptr, t_addr addr, UNIT* uptr, int32 sw)
|
||||||
else
|
else
|
||||||
*vptr = 0;
|
*vptr = 0;
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
#else
|
|
||||||
return SCPE_NOFNC;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stop simh from writing non-existant unit data stream */
|
/* stop simh from writing non-existant unit data stream */
|
||||||
|
@ -854,7 +849,7 @@ t_stat xq_show_sanity (FILE* st, UNIT* uptr, int32 val, void* desc)
|
||||||
{
|
{
|
||||||
CTLR* xq = xq_unit2ctlr(uptr);
|
CTLR* xq = xq_unit2ctlr(uptr);
|
||||||
|
|
||||||
fprintf(st, "sanity=%s", (xq->var->sanity.enabled == 2) ? "ON" : "OFF");
|
fprintf(st, "sanity=%s", (xq->var->sanity.enabled & XQ_SAN_HW_SW) ? "ON" : "OFF");
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,7 +860,7 @@ t_stat xq_set_sanity (UNIT* uptr, int32 val, char* cptr, void* desc)
|
||||||
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
|
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
|
||||||
|
|
||||||
/* this assumes that the parameter has already been upcased */
|
/* this assumes that the parameter has already been upcased */
|
||||||
if (!strcmp(cptr, "ON")) xq->var->sanity.enabled = 2;
|
if (!strcmp(cptr, "ON")) xq->var->sanity.enabled = XQ_SAN_HW_SW;
|
||||||
else if (!strcmp(cptr, "OFF")) xq->var->sanity.enabled = 0;
|
else if (!strcmp(cptr, "OFF")) xq->var->sanity.enabled = 0;
|
||||||
else return SCPE_ARG;
|
else return SCPE_ARG;
|
||||||
|
|
||||||
|
@ -1110,35 +1105,38 @@ t_stat xq_process_rbdl(CTLR* xq)
|
||||||
/* process buffer descriptors */
|
/* process buffer descriptors */
|
||||||
while(1) {
|
while(1) {
|
||||||
|
|
||||||
/* DEQNA stops processing if nothing in read queue while loading boot code */
|
/* get receive bdl flags and descriptor bits from memory */
|
||||||
if ((xq->var->type == XQ_T_DEQNA) && (!xq->var->ReadQ.count) && (xq->var->csr & XQ_CSR_BD)) break;
|
rstatus = Map_ReadW (xq->var->rbdl_ba, 4, &xq->var->rbdl_buf[0]);
|
||||||
|
if (rstatus) return xq_nxm_error(xq);
|
||||||
|
|
||||||
|
/* DEQNA stops processing if nothing in read queue */
|
||||||
|
if ((xq->var->type == XQ_T_DEQNA) && (!xq->var->ReadQ.count)) break;
|
||||||
|
|
||||||
/* get receive bdl from memory */
|
/* set descriptor processed flag */
|
||||||
xq->var->rbdl_buf[0] = 0xFFFF;
|
xq->var->rbdl_buf[0] = 0xFFFF;
|
||||||
wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]);
|
wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]);
|
||||||
rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]);
|
if (wstatus) return xq_nxm_error(xq);
|
||||||
if (rstatus || wstatus) return xq_nxm_error(xq);
|
|
||||||
|
|
||||||
/* DEQNA stops normal processing if nothing in read queue */
|
|
||||||
if ((xq->var->type == XQ_T_DEQNA) && (!xq->var->ReadQ.count)) break;
|
|
||||||
|
|
||||||
/* invalid buffer? */
|
/* invalid buffer? */
|
||||||
if (~xq->var->rbdl_buf[1] & XQ_DSC_V) {
|
if (~xq->var->rbdl_buf[1] & XQ_DSC_V) {
|
||||||
xq_csr_set_clr(xq, XQ_CSR_RL, 0);
|
xq_csr_set_clr(xq, XQ_CSR_RL, 0);
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DELQA stops processing if nothing in read queue */
|
|
||||||
if (!xq->var->ReadQ.count) break;
|
|
||||||
|
|
||||||
/* explicit chain buffer? */
|
/* explicit chain buffer? */
|
||||||
if (xq->var->rbdl_buf[1] & XQ_DSC_C) {
|
if (xq->var->rbdl_buf[1] & XQ_DSC_C) {
|
||||||
|
/* get low part of chain address */
|
||||||
|
rstatus = Map_ReadW (xq->var->rbdl_ba + 4, 2, &xq->var->rbdl_buf[2]);
|
||||||
|
if (rstatus) return xq_nxm_error(xq);
|
||||||
xq->var->rbdl_ba = ((xq->var->rbdl_buf[1] & 0x3F) << 16) | xq->var->rbdl_buf[2];
|
xq->var->rbdl_ba = ((xq->var->rbdl_buf[1] & 0x3F) << 16) | xq->var->rbdl_buf[2];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get status words */
|
/* stop if nothing in read queue */
|
||||||
rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);
|
if (!xq->var->ReadQ.count) break;
|
||||||
|
|
||||||
|
/* get address, length and status words */
|
||||||
|
rstatus = Map_ReadW(xq->var->rbdl_ba + 4, 8, &xq->var->rbdl_buf[2]);
|
||||||
if (rstatus) return xq_nxm_error(xq);
|
if (rstatus) return xq_nxm_error(xq);
|
||||||
|
|
||||||
/* get host memory address */
|
/* get host memory address */
|
||||||
|
@ -1150,9 +1148,12 @@ t_stat xq_process_rbdl(CTLR* xq)
|
||||||
if (xq->var->rbdl_buf[1] & XQ_DSC_H) {
|
if (xq->var->rbdl_buf[1] & XQ_DSC_H) {
|
||||||
b_length -= 1;
|
b_length -= 1;
|
||||||
address += 1;
|
address += 1;
|
||||||
}
|
}
|
||||||
if (xq->var->rbdl_buf[1] & XQ_DSC_L) b_length -= 1;
|
if (xq->var->rbdl_buf[1] & XQ_DSC_L) b_length -= 1;
|
||||||
|
|
||||||
|
sim_debug(DBG_TRC, xq->dev, "Using receive descriptor=0x%X, flags=0x%04X, bits=0x%04X, addr=0x%X, len=0x%X, st1=0x%04X, st2=0x%04X\n",
|
||||||
|
xq->var->rbdl_ba, xq->var->rbdl_buf[0], xq->var->rbdl_buf[1] & 0xFFC0, address, b_length, xq->var->rbdl_buf[4], xq->var->rbdl_buf[5]);
|
||||||
|
|
||||||
item = &xq->var->ReadQ.item[xq->var->ReadQ.head];
|
item = &xq->var->ReadQ.item[xq->var->ReadQ.head];
|
||||||
rbl = (uint16)item->packet.len;
|
rbl = (uint16)item->packet.len;
|
||||||
rbuf = item->packet.msg;
|
rbuf = item->packet.msg;
|
||||||
|
@ -1164,7 +1165,7 @@ t_stat xq_process_rbdl(CTLR* xq)
|
||||||
uint16 used = (uint16)item->packet.used;
|
uint16 used = (uint16)item->packet.used;
|
||||||
rbl -= used;
|
rbl -= used;
|
||||||
rbuf = &rbuf[used];
|
rbuf = &rbuf[used];
|
||||||
} else {
|
} else {
|
||||||
/* there should be no need to adjust runt packets
|
/* there should be no need to adjust runt packets
|
||||||
the physical layer (sim_ether) won't deliver any short packets
|
the physical layer (sim_ether) won't deliver any short packets
|
||||||
via eth_read, so the only short packets which get here are loopback
|
via eth_read, so the only short packets which get here are loopback
|
||||||
|
@ -1176,7 +1177,7 @@ t_stat xq_process_rbdl(CTLR* xq)
|
||||||
processing of those weird short ARP packets that seem to occur occasionally */
|
processing of those weird short ARP packets that seem to occur occasionally */
|
||||||
memset(&item->packet.msg[rbl], 0, ETH_MIN_PACKET-rbl);
|
memset(&item->packet.msg[rbl], 0, ETH_MIN_PACKET-rbl);
|
||||||
rbl = ETH_MIN_PACKET;
|
rbl = ETH_MIN_PACKET;
|
||||||
};
|
}
|
||||||
|
|
||||||
/* adjust oversized non-loopback packets */
|
/* adjust oversized non-loopback packets */
|
||||||
if ((item->type != ETH_ITM_LOOPBACK) && (rbl > ETH_FRAME_SIZE)) {
|
if ((item->type != ETH_ITM_LOOPBACK) && (rbl > ETH_FRAME_SIZE)) {
|
||||||
|
@ -1187,8 +1188,8 @@ t_stat xq_process_rbdl(CTLR* xq)
|
||||||
item->packet.len = XQ_MAX_RCV_PACKET;
|
item->packet.len = XQ_MAX_RCV_PACKET;
|
||||||
rbl = XQ_MAX_RCV_PACKET;
|
rbl = XQ_MAX_RCV_PACKET;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/* make sure entire packet fits in buffer - if not, will need to split into multiple buffers */
|
/* make sure entire packet fits in buffer - if not, will need to split into multiple buffers */
|
||||||
if (rbl > b_length)
|
if (rbl > b_length)
|
||||||
|
@ -1213,8 +1214,8 @@ t_stat xq_process_rbdl(CTLR* xq)
|
||||||
if (b_length <= rbl + 2) {
|
if (b_length <= rbl + 2) {
|
||||||
wstatus = Map_WriteW(address + rbl, 2, &qdtc_chip_extra);
|
wstatus = Map_WriteW(address + rbl, 2, &qdtc_chip_extra);
|
||||||
if (wstatus) return xq_nxm_error(xq);
|
if (wstatus) return xq_nxm_error(xq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ETH_ITM_LOOPBACK: /* loopback packet */
|
case ETH_ITM_LOOPBACK: /* loopback packet */
|
||||||
xq->var->stats.loop += 1;
|
xq->var->stats.loop += 1;
|
||||||
|
@ -1232,7 +1233,7 @@ t_stat xq_process_rbdl(CTLR* xq)
|
||||||
xq->var->rbdl_buf[4] = (rbl & 0x0700); /* high bits of rbl */
|
xq->var->rbdl_buf[4] = (rbl & 0x0700); /* high bits of rbl */
|
||||||
xq->var->rbdl_buf[4] |= 0x00f8; /* set reserved bits to 1 */
|
xq->var->rbdl_buf[4] |= 0x00f8; /* set reserved bits to 1 */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (item->packet.used < item->packet.len)
|
if (item->packet.used < item->packet.len)
|
||||||
xq->var->rbdl_buf[4] |= XQ_RST_LASTNOT; /* not last segment */
|
xq->var->rbdl_buf[4] |= XQ_RST_LASTNOT; /* not last segment */
|
||||||
xq->var->rbdl_buf[5] = ((rbl & 0x00FF) << 8) | (rbl & 0x00FF);
|
xq->var->rbdl_buf[5] = ((rbl & 0x00FF) << 8) | (rbl & 0x00FF);
|
||||||
|
@ -1261,7 +1262,7 @@ t_stat xq_process_rbdl(CTLR* xq)
|
||||||
|
|
||||||
/* signal reception complete */
|
/* signal reception complete */
|
||||||
xq_csr_set_clr(xq, XQ_CSR_RI, 0);
|
xq_csr_set_clr(xq, XQ_CSR_RI, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set to next bdl (implicit chain) */
|
/* set to next bdl (implicit chain) */
|
||||||
xq->var->rbdl_ba += 12;
|
xq->var->rbdl_ba += 12;
|
||||||
|
@ -1414,11 +1415,11 @@ t_stat xq_process_setup(CTLR* xq)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finalize sanity timer state */
|
/* finalize sanity timer state */
|
||||||
if (xq->var->sanity.enabled != 2) {
|
if (xq->var->sanity.enabled & XQ_SAN_HW_SW) {
|
||||||
if (xq->var->csr & XQ_CSR_SE)
|
if (xq->var->csr & XQ_CSR_SE)
|
||||||
xq->var->sanity.enabled = 1;
|
xq->var->sanity.enabled |= XQ_SAN_ENABLE;
|
||||||
else
|
else
|
||||||
xq->var->sanity.enabled = 0;
|
xq->var->sanity.enabled &= ~XQ_SAN_ENABLE;
|
||||||
}
|
}
|
||||||
xq_reset_santmr(xq);
|
xq_reset_santmr(xq);
|
||||||
|
|
||||||
|
@ -1635,35 +1636,20 @@ void xq_show_debug_bdl(CTLR* xq, uint32 bdl_ba)
|
||||||
|
|
||||||
t_stat xq_dispatch_rbdl(CTLR* xq)
|
t_stat xq_dispatch_rbdl(CTLR* xq)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
int32 rstatus, wstatus;
|
|
||||||
|
|
||||||
sim_debug(DBG_TRC, xq->dev, "xq_dispatch_rbdl()\n");
|
sim_debug(DBG_TRC, xq->dev, "xq_dispatch_rbdl()\n");
|
||||||
|
|
||||||
/* mark receive bdl valid */
|
/* mark receive bdl valid */
|
||||||
xq_csr_set_clr(xq, 0, XQ_CSR_RL);
|
xq_csr_set_clr(xq, 0, XQ_CSR_RL);
|
||||||
|
|
||||||
/* init receive bdl buffer */
|
|
||||||
for (i=0; i<6; i++)
|
|
||||||
xq->var->rbdl_buf[i] = 0;
|
|
||||||
|
|
||||||
/* get address of first receive buffer */
|
/* get address of first receive buffer */
|
||||||
xq->var->rbdl_ba = ((xq->var->rbdl[1] & 0x3F) << 16) | (xq->var->rbdl[0] & ~01);
|
xq->var->rbdl_ba = ((xq->var->rbdl[1] & 0x3F) << 16) | (xq->var->rbdl[0] & ~01);
|
||||||
|
|
||||||
/* When debugging, walk and display the buffer descriptor list */
|
/* When debugging, walk and display the buffer descriptor list */
|
||||||
xq_show_debug_bdl(xq, xq->var->rbdl_ba);
|
xq_show_debug_bdl(xq, xq->var->rbdl_ba);
|
||||||
|
|
||||||
/* get first receive buffer */
|
/* get receive bdl flags and descriptor bits from memory */
|
||||||
xq->var->rbdl_buf[0] = 0xFFFF;
|
if (Map_ReadW (xq->var->rbdl_ba, 4, &xq->var->rbdl_buf[0]))
|
||||||
wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]);
|
return xq_nxm_error(xq);
|
||||||
rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]);
|
|
||||||
if (rstatus || wstatus) return xq_nxm_error(xq);
|
|
||||||
|
|
||||||
/* is buffer valid? */
|
|
||||||
if (~xq->var->rbdl_buf[1] & XQ_DSC_V) {
|
|
||||||
xq_csr_set_clr(xq, XQ_CSR_RL, 0);
|
|
||||||
return SCPE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* process any waiting packets in receive queue */
|
/* process any waiting packets in receive queue */
|
||||||
if (xq->var->ReadQ.count)
|
if (xq->var->ReadQ.count)
|
||||||
|
@ -2199,7 +2185,6 @@ t_stat xq_wr_var(CTLR* xq, int32 data)
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VM_PDP11
|
|
||||||
t_stat xq_process_bootrom (CTLR* xq)
|
t_stat xq_process_bootrom (CTLR* xq)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -2258,7 +2243,6 @@ t_stat xq_process_bootrom (CTLR* xq)
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
#endif /* ifdef VM_PDP11 */
|
|
||||||
|
|
||||||
t_stat xq_wr_csr(CTLR* xq, int32 data)
|
t_stat xq_wr_csr(CTLR* xq, int32 data)
|
||||||
{
|
{
|
||||||
|
@ -2294,11 +2278,9 @@ t_stat xq_wr_csr(CTLR* xq, int32 data)
|
||||||
/* update CSR bits */
|
/* update CSR bits */
|
||||||
xq_csr_set_clr (xq, set_bits, clr_bits);
|
xq_csr_set_clr (xq, set_bits, clr_bits);
|
||||||
|
|
||||||
#ifdef VM_PDP11
|
|
||||||
/* request boot/diagnostic rom? [PDP-11 only] */
|
/* request boot/diagnostic rom? [PDP-11 only] */
|
||||||
if ((xq->var->csr & XQ_CSR_BP) == XQ_CSR_BP) /* all bits must be on */
|
if ((xq->var->csr & XQ_CSR_BP) == XQ_CSR_BP) /* all bits must be on */
|
||||||
xq_process_bootrom(xq);
|
xq_process_bootrom(xq);
|
||||||
#endif
|
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
@ -2371,7 +2353,7 @@ t_stat xq_wr_srqr(CTLR* xq, int32 data)
|
||||||
|
|
||||||
xq->dib->vec = xq->var->init.vector;
|
xq->dib->vec = xq->var->init.vector;
|
||||||
xq->var->tbindx = xq->var->rbindx = 0;
|
xq->var->tbindx = xq->var->rbindx = 0;
|
||||||
if ((xq->var->sanity.enabled) && (xq->var->init.options & XQ_IN_OP_HIT)) {
|
if ((xq->var->sanity.enabled & XQ_SAN_HW_SW) && (xq->var->init.options & XQ_IN_OP_HIT)) {
|
||||||
xq->var->sanity.quarter_secs = 4*xq->var->init.hit_timeout;
|
xq->var->sanity.quarter_secs = 4*xq->var->init.hit_timeout;
|
||||||
}
|
}
|
||||||
xq->var->icr = xq->var->init.options & XQ_IN_OP_INT;
|
xq->var->icr = xq->var->init.options & XQ_IN_OP_INT;
|
||||||
|
@ -2537,7 +2519,7 @@ t_stat xq_reset(DEVICE* dptr)
|
||||||
break;
|
break;
|
||||||
case XQ_T_DELQA:
|
case XQ_T_DELQA:
|
||||||
case XQ_T_DELQA_PLUS:
|
case XQ_T_DELQA_PLUS:
|
||||||
xq->var->var = (xq->var->lockmode ? 0 : XQ_VEC_MS) | ((xq->var->sanity.enabled == 2) ? XQ_VEC_OS : 0);
|
xq->var->var = (xq->var->lockmode ? 0 : XQ_VEC_MS) | ((xq->var->sanity.enabled & XQ_SAN_HW_SW) ? XQ_VEC_OS : 0);
|
||||||
xq->var->mode = (xq->var->lockmode ? XQ_T_DEQNA : XQ_T_DELQA);
|
xq->var->mode = (xq->var->lockmode ? XQ_T_DEQNA : XQ_T_DELQA);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2575,9 +2557,8 @@ t_stat xq_reset(DEVICE* dptr)
|
||||||
sim_cancel(&xq->unit[2]);
|
sim_cancel(&xq->unit[2]);
|
||||||
|
|
||||||
/* set hardware sanity controls */
|
/* set hardware sanity controls */
|
||||||
if (xq->var->sanity.enabled) {
|
if (xq->var->sanity.enabled & XQ_SAN_HW_SW)
|
||||||
xq->var->sanity.quarter_secs = XQ_HW_SANITY_SECS * 4/*qsec*/;
|
xq->var->sanity.quarter_secs = XQ_HW_SANITY_SECS * 4/*qsec*/;
|
||||||
}
|
|
||||||
|
|
||||||
if (sim_switches & SWMASK ('P')) { /* Powerup? */
|
if (sim_switches & SWMASK ('P')) { /* Powerup? */
|
||||||
memset (&xq->var->setup, 0, sizeof(xq->var->setup));
|
memset (&xq->var->setup, 0, sizeof(xq->var->setup));
|
||||||
|
@ -2592,8 +2573,8 @@ t_stat xq_reset(DEVICE* dptr)
|
||||||
|
|
||||||
void xq_reset_santmr(CTLR* xq)
|
void xq_reset_santmr(CTLR* xq)
|
||||||
{
|
{
|
||||||
sim_debug(DBG_TRC, xq->dev, "xq_reset_santmr(enable=%d, qsecs=%d)\n", (xq->var->sanity.enabled ? 1 : 0), xq->var->sanity.quarter_secs);
|
sim_debug(DBG_TRC, xq->dev, "xq_reset_santmr(enable=%d, qsecs=%d)\n", ((xq->var->sanity.enabled & XQ_SAN_ENABLE) ? 1 : 0), xq->var->sanity.quarter_secs);
|
||||||
if (xq->var->sanity.enabled) {
|
if (xq->var->sanity.enabled & XQ_SAN_ENABLE) {
|
||||||
sim_debug(DBG_SAN, xq->dev, "SANITY TIMER RESETTING, qsecs: %d\n", xq->var->sanity.quarter_secs);
|
sim_debug(DBG_SAN, xq->dev, "SANITY TIMER RESETTING, qsecs: %d\n", xq->var->sanity.quarter_secs);
|
||||||
|
|
||||||
/* reset sanity countdown timer to max count */
|
/* reset sanity countdown timer to max count */
|
||||||
|
@ -2736,18 +2717,21 @@ t_stat xq_tmrsvc(UNIT* uptr)
|
||||||
{
|
{
|
||||||
CTLR* xq = xq_unit2ctlr(uptr);
|
CTLR* xq = xq_unit2ctlr(uptr);
|
||||||
|
|
||||||
/* has sanity timer expired? if so, reboot */
|
/* is sanity timer running and has it expired? if so, reboot */
|
||||||
if (xq->var->sanity.enabled)
|
if (xq->var->sanity.enabled & XQ_SAN_ENABLE) {
|
||||||
|
sim_debug(DBG_SAN, xq->dev, "SANITY TIMER TICK, %d qsecs remaining out of %d qsecs\n", xq->var->sanity.timer-1, xq->var->sanity.quarter_secs);
|
||||||
if (--xq->var->sanity.timer <= 0) {
|
if (--xq->var->sanity.timer <= 0) {
|
||||||
|
sim_debug(DBG_SAN, xq->dev, "SANITY TIMER EXPIRED, after %d qsecs\n", xq->var->sanity.quarter_secs);
|
||||||
if (xq->var->mode != XQ_T_DELQA_PLUS)
|
if (xq->var->mode != XQ_T_DELQA_PLUS)
|
||||||
return xq_boot_host(xq);
|
return xq_boot_host(xq);
|
||||||
else { /* DELQA-T Host Inactivity Timer expiration means switch out of DELQA-T mode */
|
else { /* DELQA-T Host Inactivity Timer expiration means switch out of DELQA-T mode */
|
||||||
sim_debug(DBG_TRC, xq->dev, "xq_tmrsvc(DELQA-PLUS Host Inactivity Expired\n");
|
sim_debug(DBG_TRC, xq->dev, "xq_tmrsvc(DELQA-PLUS Host Inactivity Expired\n");
|
||||||
xq->var->mode = XQ_T_DELQA;
|
xq->var->mode = XQ_T_DELQA;
|
||||||
xq->var->iba = xq->var->srr = 0;
|
xq->var->iba = xq->var->srr = 0;
|
||||||
xq->var->var = (xq->var->lockmode ? 0 : XQ_VEC_MS) | ((xq->var->sanity.enabled == 2) ? XQ_VEC_OS : 0);
|
xq->var->var = (xq->var->lockmode ? 0 : XQ_VEC_MS) | ((xq->var->sanity.enabled & XQ_SAN_HW_SW) ? XQ_VEC_OS : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* has system id timer expired? if so, do system id */
|
/* has system id timer expired? if so, do system id */
|
||||||
if (--xq->var->idtmr <= 0) {
|
if (--xq->var->idtmr <= 0) {
|
||||||
|
@ -3078,25 +3062,13 @@ t_stat xq_boot (int32 unitno, DEVICE *dptr)
|
||||||
#ifdef VM_PDP11
|
#ifdef VM_PDP11
|
||||||
size_t i;
|
size_t i;
|
||||||
DIB *dib = (DIB *)dptr->ctxt;
|
DIB *dib = (DIB *)dptr->ctxt;
|
||||||
CTLR *xq = xq_unit2ctlr(&dptr->units[unitno]);
|
|
||||||
uint16 *bootrom = NULL;
|
|
||||||
extern int32 REGFILE[6][2]; /* R0-R5, two sets */
|
extern int32 REGFILE[6][2]; /* R0-R5, two sets */
|
||||||
extern uint16 *M; /* Memory */
|
extern uint16 *M; /* Memory */
|
||||||
|
|
||||||
if (xq->var->type == XQ_T_DEQNA)
|
|
||||||
bootrom = xq_bootrom_deqna;
|
|
||||||
else
|
|
||||||
if (xq->var->type == XQ_T_DELQA)
|
|
||||||
bootrom = xq_bootrom_delqa;
|
|
||||||
else
|
|
||||||
if (xq->var->type == XQ_T_DELQA_PLUS)
|
|
||||||
bootrom = xq_bootrom_delqat;
|
|
||||||
|
|
||||||
for (i = 0; i < BOOT_LEN; i++)
|
for (i = 0; i < BOOT_LEN; i++)
|
||||||
M[(BOOT_START >> 1) + i] = bootrom[i];
|
M[(BOOT_START >> 1) + i] = boot_rom[i];
|
||||||
cpu_set_boot (BOOT_ENTRY);
|
cpu_set_boot (BOOT_ENTRY);
|
||||||
REGFILE[0][0] = 0;
|
REGFILE[0][0] = ((dptr == &xq_dev) ? 4 : 5);
|
||||||
REGFILE[1][0] = dib->ba;
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
#else
|
#else
|
||||||
return SCPE_NOFNC;
|
return SCPE_NOFNC;
|
||||||
|
|
|
@ -104,6 +104,8 @@ enum xq_type {XQ_T_DEQNA, XQ_T_DELQA, XQ_T_DELQA_PLUS};
|
||||||
|
|
||||||
struct xq_sanity {
|
struct xq_sanity {
|
||||||
int enabled; /* sanity timer enabled? 2=HW, 1=SW, 0=off */
|
int enabled; /* sanity timer enabled? 2=HW, 1=SW, 0=off */
|
||||||
|
#define XQ_SAN_HW_SW 2
|
||||||
|
#define XQ_SAN_ENABLE 1
|
||||||
int quarter_secs; /* sanity timer value in 1/4 seconds */
|
int quarter_secs; /* sanity timer value in 1/4 seconds */
|
||||||
int timer; /* countdown timer */
|
int timer; /* countdown timer */
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,7 +37,6 @@
|
||||||
#ifndef PDP11_XQ_BOOTROM_H
|
#ifndef PDP11_XQ_BOOTROM_H
|
||||||
#define PDP11_XQ_BOOTROM_H
|
#define PDP11_XQ_BOOTROM_H
|
||||||
|
|
||||||
#ifdef VM_PDP11
|
|
||||||
/*
|
/*
|
||||||
Word 0: NOP
|
Word 0: NOP
|
||||||
Word 1: Branch to extended primary boot (EPB)
|
Word 1: Branch to extended primary boot (EPB)
|
||||||
|
@ -50,11 +49,6 @@
|
||||||
which are being simulated (DEQNA, DELQA and DELQA-T)
|
which are being simulated (DEQNA, DELQA and DELQA-T)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define BOOT_LEN 512 /* EPB Code size */
|
|
||||||
#define BOOT_START 0 /* Initial load Address of the EPB code */
|
|
||||||
#define BOOT_ENTRY 0 /* Start address of EPB code */
|
|
||||||
#define BOOT_XSUM_OFFSET 6 /* Location containing checksum offset */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Bootrom code is from executing a Boot Diagnostic load command to a real
|
Bootrom code is from executing a Boot Diagnostic load command to a real
|
||||||
DEQNA (M7504) board (thus loading the ROM contents to RAM) and using ODT
|
DEQNA (M7504) board (thus loading the ROM contents to RAM) and using ODT
|
||||||
|
@ -1112,6 +1106,192 @@ uint16 xq_bootrom_delqat[2048] = {
|
||||||
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, /* 0FE0 (0007740) */
|
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, /* 0FE0 (0007740) */
|
||||||
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x84D2, /* 0FF0 (0007760) */
|
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x84D2, /* 0FF0 (0007760) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef VM_PDP11
|
||||||
|
#if 0
|
||||||
|
Tim Shoppa said:
|
||||||
|
|
||||||
|
Hopefully better late than never, but I finally got to digging and
|
||||||
|
found that the CIQNDC0 sources give an example bootstrap:
|
||||||
|
|
||||||
|
IDENTIFICATION
|
||||||
|
--------------
|
||||||
|
|
||||||
|
PRODUCT CODE: AC-T612A-MC
|
||||||
|
|
||||||
|
PRODUCT NAME: CIQNDC0 DEQNA ROM RESIDENT CODE
|
||||||
|
|
||||||
|
PRODUCT DATE: 29 June 1984
|
||||||
|
|
||||||
|
MAINTAINER: DIAGNOSTIC ENGINEERING
|
||||||
|
|
||||||
|
[...]
|
||||||
|
|
||||||
|
4.1 PRIMARY BOOT PROCESS
|
||||||
|
|
||||||
|
The primary boot, resident in the host, normally checks for the existence
|
||||||
|
of the device it is going to boot from, boots 512. bytes from the device,
|
||||||
|
verifies the operation, sets parameters and transfers to the "booted" code.
|
||||||
|
|
||||||
|
A suggested method for "checking" for a QNA is as follows:
|
||||||
|
|
||||||
|
Write a "2" (a module reset) into the QNA's CSR at location
|
||||||
|
17774456 or 17774476.
|
||||||
|
|
||||||
|
Read back the CSR and compare against an octal 000062.
|
||||||
|
|
||||||
|
If equal then there is most likely a QNA there.
|
||||||
|
|
||||||
|
If not equal (Bus time-out?) then "sniff" elsewhere.
|
||||||
|
|
||||||
|
Write a "0" back into the CSR to "reset" the reset bit.
|
||||||
|
|
||||||
|
If a QNA is present and it is to be used for the boot the first thing
|
||||||
|
then:
|
||||||
|
|
||||||
|
A descriptor for a 256. word "receive" is validated in the QNA.
|
||||||
|
|
||||||
|
Data is read into the host starting at location 0
|
||||||
|
The descriptor is 8 words long, words 0, 4, 5 and 6 will
|
||||||
|
contain operation status. Words 1, 2, 3, and 7 are constant.
|
||||||
|
|
||||||
|
Write a "1010" into the CSR to move the boot code into the QNA's
|
||||||
|
internal receive buffer and delay for approximately one second.
|
||||||
|
|
||||||
|
Write a "1000" into the CSR to move the data in the internal
|
||||||
|
receive buffer into host memory and delay for approximately one
|
||||||
|
second.
|
||||||
|
|
||||||
|
Reset the QNA and check the CSR for proper status.
|
||||||
|
|
||||||
|
Checked the receive descriptor for nominal states.
|
||||||
|
|
||||||
|
The Data transfer is verified.
|
||||||
|
|
||||||
|
If the QNA primary boot code detects a failure at this point the
|
||||||
|
host boot is re-entered.
|
||||||
|
|
||||||
|
Transfer is made to the first location of the freshly loaded
|
||||||
|
portion of the QNA BD ROM.
|
||||||
|
|
||||||
|
R1 contains the I/O Page address of the QNA (174440)
|
||||||
|
|
||||||
|
R0 contains a "000000" if the DECnet boot resident on the
|
||||||
|
QNA is to be used.
|
||||||
|
- or -
|
||||||
|
If R0 is greater than "000777" an effective JMP (R0) is
|
||||||
|
executed in lieu of the DECnet boot.
|
||||||
|
|
||||||
|
|
||||||
|
Location 12 contains a "000000" if the EPB is to halt when
|
||||||
|
an error is detected.
|
||||||
|
- or -
|
||||||
|
If loaction 12 is greater than "000000" an effective JMP @12
|
||||||
|
is executed in lieu of a "HALT".
|
||||||
|
|
||||||
|
4.1.1 EXPECTED VALUES FOR VERIFICATION
|
||||||
|
|
||||||
|
CSR is checked for a nominal state as are the status words in the receive
|
||||||
|
descriptor.
|
||||||
|
|
||||||
|
Status Nominal
|
||||||
|
---------------
|
||||||
|
CSR 000060 or 010060
|
||||||
|
FLAG 14xxxx
|
||||||
|
BSW1 14xxxx
|
||||||
|
BSW2 14xxxx
|
||||||
|
CSW0 177777
|
||||||
|
|
||||||
|
x - don't care bits
|
||||||
|
|
||||||
|
Next the actual data transfer is verified by checking the first three bytes
|
||||||
|
of the data transferred for standard values. These first locations and their
|
||||||
|
expected contents are:
|
||||||
|
|
||||||
|
Location Contents
|
||||||
|
--------------------------
|
||||||
|
0000-1 000240 (NOP)
|
||||||
|
0002 001 (a BR instruction)
|
||||||
|
0003 xxx
|
||||||
|
|
||||||
|
0004
|
||||||
|
.. The QNA Extended Primary Boot (EPB) code
|
||||||
|
0777
|
||||||
|
|
||||||
|
4.1.2 SAMPLE PRIMARY BOOT CODE
|
||||||
|
|
||||||
|
Below is an example of how a primary boot could be implemented on a typical
|
||||||
|
PDP-11 based host.
|
||||||
|
|
||||||
|
Upon entry R0 is coded to indicate which QNA is to be used for the boot.
|
||||||
|
The first 32K bytes of the host memory is assumed to be mapped 1 to 1
|
||||||
|
physical to logical. The I/O page is mapped to the last 4K.
|
||||||
|
|
||||||
|
Assume settings for R0 as follows:
|
||||||
|
|
||||||
|
R0 - Contains a "4" for QNA#1 @ 174440
|
||||||
|
Contains a "5" for QNA#2 @ 174460
|
||||||
|
PDP-11 code for booting the DEQNA EPB might be as follows:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BOOT_LEN (sizeof(boot_rom)/sizeof(uint16))/* Code size */
|
||||||
|
#define BOOT_START 020000 /* Initial load Address of the Boot code */
|
||||||
|
#define BOOT_ENTRY (BOOT_START+0) /* Start address of Boot code */
|
||||||
|
|
||||||
|
static const uint16 boot_rom[] = {
|
||||||
|
// DESC = 4000 ; Descriptor List Address
|
||||||
|
// DECnet = 0 ; MOP boot request
|
||||||
|
0012701, 0174440, // 0000 mov #174440,r1 ; assume device is DEQNA #1
|
||||||
|
0022700, 0000004, // 0004 cmp #4,r0
|
||||||
|
0001402, // 0010 beq 10$ ; good assumption
|
||||||
|
0012701, 0177460, // 0012 mov #174460,r1 ; select device at DEQNA #2
|
||||||
|
|
||||||
|
0012761, 0000002, 0000016, // 0016 10$: mov #SR,16(r1) ; assert QNA software reset
|
||||||
|
0032761, 0000062, 0000016, // 0024 bit #<RL|XL|SR>,16(r1); "nominal" status during reset
|
||||||
|
0001466, // 0032 beq 90$ ;? not a proper response, halt
|
||||||
|
0005061, 0000016, // 0034 clr 16(r1) ; clear reset state and all others
|
||||||
|
|
||||||
|
0012703, 0004000, // 0040 mov #DESC,r3 ; pick an address for descriptor
|
||||||
|
0010304, // 0044 mov r3,r4
|
||||||
|
0012724, 0100000, // 0046 mov #100000,(r4)+ ; Flag word, changed to -1
|
||||||
|
0011324, // 0052 mov (r3),(r4)+ ; Valid buffer descriptor, receive
|
||||||
|
0005024, // 0054 clr (r4)+ ; location zero
|
||||||
|
0012724, 0177400, // 0056 mov #-400,(r4)+ ; 256. words or 512. bytes
|
||||||
|
0005024, // 0062 clr (r4)+ ; Descriptor status 1, changed to -1
|
||||||
|
0005024, // 0064 clr (r4)+ ; Descriptor status 2, changed to -1
|
||||||
|
0011324, // 0066 mov (r3),(r4)+ ; Another flag word, changed to -1
|
||||||
|
0012714, 0020000, // 0070 mov #020000,(r4) ; end descriptor code
|
||||||
|
0010361, 0000004, // 0074 mov r3,04(r1) ; receive descriptor low address
|
||||||
|
0005061, 0000006, // 0100 clr 06(r1) ; validate a receive descriptor
|
||||||
|
|
||||||
|
0012761, 0001010, 0000016, // 0104 mov #<EL|BD>,16(r1) ; Instruct QNA to unload the EPB code
|
||||||
|
0005000, // 0112 clr r0 ; delay about 60 ms for transfer of
|
||||||
|
0077001, // 0114 sob r0,. ; i8051 contents to receive FIFO
|
||||||
|
0012761, 0001000, 0000016, // 0116 mov #<EL>,16(r1) ; Complete the EPB unload
|
||||||
|
0005000, // 0124 clr r0 ; delay about 60 ms for transfer of
|
||||||
|
0077001, // 0126 sob r0,. ; receive FIFO to host memory
|
||||||
|
0012761, 0000002, 0000016, // 0130 mov #SR,16(r1) ; reset
|
||||||
|
0005061, 0000016, // 0136 clr 16(r1) ; Final reset to complete operation
|
||||||
|
|
||||||
|
0012704, 0004014, // 0142 mov #<DESC+14>,r4
|
||||||
|
0042714, 0037777, // 0146 bic #037777,(r4) ; check if last status word was updated
|
||||||
|
0022714, 0140000, // 0152 cmp #140000,(r4) ;
|
||||||
|
0001014, // 0156 bne 90$ ;
|
||||||
|
|
||||||
|
0022737, 0000240, 0000000, // 0160 cmp #240,@#0 ; check for QNA boot block
|
||||||
|
0001010, // 0166 bne 90$ ;? operation data check
|
||||||
|
0122737, 0000001, 0000003, // 0170 cmpb #001,@#3 ; check for "BR" opcode
|
||||||
|
0001004, // 0176 bne 90$ ;? operation data check
|
||||||
|
|
||||||
|
0012700, 0000000, // 0200 mov #DECnet,r0 ; Load DECnet code (or other code into R0)
|
||||||
|
0000137, 0000000, // 0204 jmp @#0 ; go to extended primary boot
|
||||||
|
|
||||||
|
// ; R0 - set to zero for DECnet boot
|
||||||
|
// ; R1 - has address of QNA #1 or #2
|
||||||
|
|
||||||
|
0000000, // 0210 90$: halt ;? QNA error, get back to host boot control?
|
||||||
|
0000776, // 0212 br 90$
|
||||||
|
};
|
||||||
#endif /* VM_PDP11 */
|
#endif /* VM_PDP11 */
|
||||||
|
|
||||||
#endif /* _PDP11_XQ_BOOTROM_H */
|
#endif /* _PDP11_XQ_BOOTROM_H */
|
||||||
|
|
Loading…
Add table
Reference in a new issue