1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-01-13 15:27:04 +00:00

KA10: Redid interrupt system for KS.

This commit is contained in:
Richard Cornwell 2022-02-15 21:48:38 -05:00
parent c8526dde8f
commit 265a4ae4a2
13 changed files with 358 additions and 482 deletions

View File

@ -77,7 +77,6 @@
int ch11_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access);
int ch11_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access);
uint16 ch11_checksum (const uint8 *p, int count);
int ch11_test_int (struct pdp_dib *dibp);
void ch11_validate (const uint8 *p, int count);
t_stat ch11_transmit (struct pdp_dib *dibp);
void ch11_receive (struct pdp_dib *dibp);
@ -95,7 +94,7 @@ t_stat ch11_help_attach (FILE *, DEVICE *, UNIT *, int32, const char *);
const char *ch11_description (DEVICE *);
static char peer[256];
int address;
static int address;
static uint16 ch11_csr;
static int rx_count;
static int tx_count;
@ -170,23 +169,26 @@ ch11_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
switch (addr & 016) {
case 000: /* CSR */
if (data & CSR_RST) {
sim_debug (DBG_REG, &ch11_dev, "Reset\n");
ch11_clear (dibp);
}
ch11_csr &= ~(CSR_REN|CSR_TEN|CSR_SPY);
ch11_csr |= data & (CSR_REN|CSR_TEN|CSR_SPY);
if (data & CSR_RCL) {
sim_debug (DBG_REG, &ch11_dev, "Clear RX\n");
ch11_csr &= ~CSR_RDN;
rx_count = 0;
ch11_lines[0].rcve = TRUE;
}
if (data & CSR_RST) {
sim_debug (DBG_REG, &ch11_dev, "Reset\n");
ch11_clear (dibp);
uba_clr_irq(dibp, dibp->uba_vect);
}
if (data & CSR_TCL) {
sim_debug (DBG_REG, &ch11_dev, "Clear TX\n");
tx_count = 0;
ch11_csr |= CSR_TDN;
if (ch11_csr & CSR_TEN)
uba_set_irq(dibp, dibp->uba_vect);
}
ch11_csr &= ~(CSR_REN|CSR_TEN);
ch11_csr |= data & (CSR_REN|CSR_TEN);
break;
case 002: /* Write buffer */
@ -237,6 +239,7 @@ ch11_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access)
} else {
i = 512-rx_count;
ch11_csr &= ~CSR_RDN;
uba_clr_irq(dibp, dibp->uba_vect);
*data = ((uint64)(rx_buffer[i]) & 0xff) << 8;
*data |= ((uint64)(rx_buffer[i+1]) & 0xff);
rx_count-=2;
@ -283,25 +286,6 @@ ch11_checksum (const uint8 *p, int count)
return (~sum) & 0xffff;
}
int
ch11_test_int (struct pdp_dib *dibp)
{
if ((ch11_csr & (CSR_RDN|CSR_REN)) == (CSR_RDN|CSR_REN) ||
(ch11_csr & (CSR_TDN|CSR_TEN)) == (CSR_TDN|CSR_TEN)) {
sim_debug (DBG_INT, &ch11_dev, "%s %s Interrupt\n",
ch11_csr & CSR_RDN ? "RX" : "",
ch11_csr & CSR_TDN ? "TX" : "");
uba_set_irq(dibp);
} else {
/* Nothing found, so clear any flags */
sim_debug(DEBUG_DETAIL, &dz_dev, "Clr irq\n");
uba_clr_irq(dibp);
return 0;
}
return 1;
}
void
ch11_validate (const uint8 *p, int count)
{
@ -363,7 +347,6 @@ ch11_transmit (struct pdp_dib *dibp)
ch11_csr |= CSR_TAB;
}
tx_count = 0;
ch11_test_int (dibp);
return SCPE_OK;
}
@ -395,9 +378,12 @@ ch11_receive (struct pdp_dib *dibp)
sim_debug (DBG_TRC, &ch11_dev, "Rx count, %d\n", rx_count);
ch11_validate (p + CHUDP_HEADER, count - CHUDP_HEADER);
ch11_csr |= CSR_RDN;
if (ch11_csr & CSR_REN) {
sim_debug (DBG_INT, &ch11_dev, "RX Interrupt\n");
uba_set_irq(dibp, dibp->uba_vect);
}
ch11_lines[0].rcve = FALSE;
sim_debug (DBG_TRC, &ch11_dev, "Rx off\n");
ch11_test_int (dibp);
} else {
sim_debug (DBG_ERR, &ch11_dev, "Lost packet\n");
if ((ch11_csr & CSR_LOS) != CSR_LOS)
@ -418,7 +404,7 @@ ch11_clear (struct pdp_dib *dibp)
tx_buffer[3] = 0;
ch11_lines[0].rcve = TRUE;
ch11_test_int (dibp);
uba_clr_irq(dibp, dibp->uba_vect);
}
t_stat
@ -432,9 +418,13 @@ ch11_svc(UNIT *uptr)
if (ch11_lines[0].conn) {
ch11_receive (dibp);
}
if (tx_count == 0)
if (tx_count == 0) {
ch11_csr |= CSR_TDN;
ch11_test_int (dibp);
if (ch11_csr & CSR_TEN) {
sim_debug (DBG_INT, &ch11_dev, "RX Interrupt\n");
uba_set_irq(dibp, dibp->uba_vect);
}
}
return SCPE_OK;
}

View File

@ -27,13 +27,13 @@
dup DUP11 Unibus/DPV11 Qbus bit synchronous interface
This module implements a bit synchronous interface to support DDCMP. Other
synchronous protocols which may have been supported on the DUP11/DPV11 bit
synchronous protocols which may have been supported on the DUP11/DPV11 bit
synchronous interface are explicitly not supported.
Connections are modeled with a tcp session with connection management and
Connections are modeled with a tcp session with connection management and
I/O provided by the tmxr library.
The wire protocol implemented is native DDCMP WITHOUT the DDCMP SYNC
The wire protocol implemented is native DDCMP WITHOUT the DDCMP SYNC
characters both initially and between DDCMP packets.
15-May-13 MP Initial implementation
@ -82,7 +82,6 @@ static MODEM_CHANGE_CALLBACK dup_modem_change_callback[NUM_DEVS_DUP];
static int dup_rd (DEVICE *dptr, t_addr PA, uint16 *data, int32 access);
static int dup_wr (DEVICE *dptr, t_addr PA, uint16 data, int32 access);
static uint16 dup_irq(struct pdp_dib *dibp);
static t_stat dup_set_modem (int32 dup, int32 rxcsr_bits);
static t_stat dup_get_modem (int32 dup);
static t_stat dup_svc (UNIT *uptr);
@ -313,14 +312,14 @@ static BITFIELD dup_txdbuf_bits[] = {
#define IOLN_DUP 010
DIB dup_dib = { 0760300, 017, 0570, 5, 3, &dup_rd, &dup_wr, &dup_irq, 0, 0};
DIB dup_dib = { 0760300, 017, 0570, 5, 3, &dup_rd, &dup_wr, 0, 0, 0};
static UNIT dup_unit_template = {
UDATA (&dup_svc, UNIT_ATTABLE|UNIT_IDLE, 0),
UDATA (&dup_svc, UNIT_ATTABLE|UNIT_IDLE, 0),
};
static UNIT dup_poll_unit_template = {
UDATA (&dup_poll_svc, UNIT_DIS|UNIT_IDLE, 0),
UDATA (&dup_poll_svc, UNIT_DIS|UNIT_IDLE, 0),
};
static UNIT dup_units[NUM_DEVS_DUP+1]; /* One unit per line and a polling unit */
@ -391,6 +390,8 @@ static MTAB dup_mod[] = {
};
/* debugging bitmaps */
#define DBG_REG 0x0001 /* trace read/write registers */
#define DBG_INT 0x0002 /* display transfer requests */
#define DBG_PKT (TMXR_DBG_PXMT|TMXR_DBG_PRCV) /* display packets */
#define DBG_XMT TMXR_DBG_XMT /* display Transmitted Data */
#define DBG_RCV TMXR_DBG_RCV /* display Received Data */
@ -400,8 +401,8 @@ static MTAB dup_mod[] = {
#define DBG_ASY TMXR_DBG_ASY /* display Asynchronous Activities */
static DEBTAB dup_debug[] = {
{"DETAIL", DEBUG_DETAIL},
{"IRQ", DEBUG_IRQ},
{"REG", DBG_REG},
{"INT", DBG_INT},
{"PKT", DBG_PKT},
{"XMT", DBG_XMT},
{"RCV", DBG_RCV},
@ -413,20 +414,20 @@ static DEBTAB dup_debug[] = {
};
/*
We have two devices defined here (dup_dev and dpv_dev) which have the
We have two devices defined here (dup_dev and dpv_dev) which have the
same units. This would normally never be allowed since two devices can't
actually share units. This problem is avoided in this case since both
devices start out as disabled and the logic in dup_reset allows only
one of these devices to be enabled at a time. The DUP device is allowed
actually share units. This problem is avoided in this case since both
devices start out as disabled and the logic in dup_reset allows only
one of these devices to be enabled at a time. The DUP device is allowed
on Unibus systems and the DPV device Qbus systems.
This monkey business is necessary due to the fact that although both
the DUP and DPV devices have almost the same functionality and almost
the same register programming interface, they are different enough that
they fall in different priorities in the autoconfigure address and vector
rules.
This 'shared' unit model therefore means we can't call the
find_dev_from_unit api to uniquely determine the device structure.
We define the DUPDPTR macro to return the active device pointer when
This 'shared' unit model therefore means we can't call the
find_dev_from_unit api to uniquely determine the device structure.
We define the DUPDPTR macro to return the active device pointer when
necessary.
*/
DEVICE dup_dev = {
@ -435,7 +436,7 @@ DEVICE dup_dev = {
NULL, NULL, &dup_reset,
NULL, &dup_attach, &dup_detach,
&dup_dib, DEV_DIS | DEV_DISABLE | DEV_DEBUG, 0,
dup_debug, NULL, NULL, &dup_help, dup_help_attach, &dup_desc,
dup_debug, NULL, NULL, &dup_help, dup_help_attach, &dup_desc,
&dup_description
};
@ -444,7 +445,7 @@ DEVICE dup_dev = {
/* Register names for Debug tracing */
static const char *dup_rd_regs[] =
{"RXCSR ", "RXDBUF", "TXCSR ", "TXDBUF" };
static const char *dup_wr_regs[] =
static const char *dup_wr_regs[] =
{"RXCSR ", "PARCSR", "TXCSR ", "TXDBUF"};
@ -547,19 +548,19 @@ switch ((PA >> 1) & 03) { /* case on PA<2:1> */
if (dup_rxcsr[dup] & RXCSR_M_RXIE)
dup_set_rxint (dup);
}
if ((dup_rxcsr[dup] & RXCSR_M_RCVEN) &&
if ((dup_rxcsr[dup] & RXCSR_M_RCVEN) &&
(!(orig_val & RXCSR_M_RCVEN))) { /* Upward transition of receiver enable */
dup_rcv_byte (dup); /* start any pending receive */
}
if ((!(dup_rxcsr[dup] & RXCSR_M_RCVEN)) &&
if ((!(dup_rxcsr[dup] & RXCSR_M_RCVEN)) &&
(orig_val & RXCSR_M_RCVEN)) { /* Downward transition of receiver enable */
dup_rxdbuf[dup] &= ~RXDBUF_M_RXDBUF;
dup_rxcsr[dup] &= ~RXCSR_M_RXACT;
if ((dup_rcvpkinoff[dup] != 0) ||
if ((dup_rcvpkinoff[dup] != 0) ||
(dup_rcvpkbytes[dup] != 0))
dup_rcvpkinoff[dup] = dup_rcvpkbytes[dup] = 0;
}
if ((!(dup_rxcsr[dup] & RXCSR_M_RXIE)) &&
if ((!(dup_rxcsr[dup] & RXCSR_M_RXIE)) &&
(orig_val & RXCSR_M_RXIE)) /* Downward transition of receiver interrupt enable */
dup_clr_rxint (dup);
if ((dup_rxcsr[dup] & RXCSR_M_RXIE) && (dup_rxcsr[dup] & RXCSR_M_RXDONE))
@ -591,20 +592,20 @@ switch ((PA >> 1) & 03) { /* case on PA<2:1> */
break;
}
}
if ((dup_txcsr[dup] & TXCSR_M_TXACT) &&
(!(orig_val & TXCSR_M_TXACT)) &&
if ((dup_txcsr[dup] & TXCSR_M_TXACT) &&
(!(orig_val & TXCSR_M_TXACT)) &&
(orig_val & TXCSR_M_TXDONE)) {
dup_txcsr[dup] &= ~TXCSR_M_TXDONE;
}
if ((!(dup_txcsr[dup] & TXCSR_M_SEND)) &&
if ((!(dup_txcsr[dup] & TXCSR_M_SEND)) &&
(orig_val & TXCSR_M_SEND)) {
dup_txcsr[dup] &= ~TXCSR_M_TXACT;
dup_put_msg_bytes (dup, NULL, 0, FALSE, TRUE);
}
if ((dup_txcsr[dup] & TXCSR_M_HALFDUP) ^ (orig_val & TXCSR_M_HALFDUP))
tmxr_set_line_halfduplex (dup_desc.ldsc+dup, dup_txcsr[dup] & TXCSR_M_HALFDUP);
if ((dup_txcsr[dup] & TXCSR_M_TXIE) &&
(!(orig_val & TXCSR_M_TXIE)) &&
if ((dup_txcsr[dup] & TXCSR_M_TXIE) &&
(!(orig_val & TXCSR_M_TXIE)) &&
(dup_txcsr[dup] & TXCSR_M_TXDONE)) {
dup_set_txint (dup);
}
@ -625,25 +626,6 @@ dup_get_modem (dup);
return 0;
}
static uint16 dup_irq(struct pdp_dib *dibp)
{
int dup;
for (dup = 0; dup < dup_desc.lines; dup++) { /* find 1st mux */
if (dup_rxi & (1 << dup)) {
sim_debug(DEBUG_IRQ, DUPDPTR, "dup_rxinta(dup=%d)\n", dup);
// dup_clr_rxint (dup); /* clear intr */
return (dup_dib.uba_vect + (dup * 010)); /* return vector */
}
if (dup_txi & (1 << dup)) {
sim_debug(DEBUG_IRQ, DUPDPTR, "dup_txinta(dup=%d)\n", dup);
// dup_clr_txint (dup); /* clear intr */
return (dup_dib.uba_vect + 4 + (dup * 010)); /* return vector */
}
}
return 0;
}
static t_stat dup_set_modem (int32 dup, int32 rxcsr_bits)
{
int32 bits_to_set, bits_to_clear;
@ -717,7 +699,7 @@ int32 dup_csr_to_linenum (int32 CSRPA)
DEVICE *dptr = DUPDPTR;
DIB *dib = (DIB *)dptr->ctxt;
if ((dib->uba_addr < (uint32)CSRPA) ||
if ((dib->uba_addr < (uint32)CSRPA) ||
((uint32)CSRPA > (dib->uba_addr + (IOLN_DUP * dup_desc.lines))) ||
(DUPDPTR->flags & DEV_DIS))
return -1;
@ -807,7 +789,7 @@ if ((dup < 0) || (dup >= dup_desc.lines) || (DUPDPTR->flags & DEV_DIS))
orig_val = dup_rxcsr[dup];
dup_rxcsr[dup] &= ~RXCSR_M_RCVEN;
dup_rxcsr[dup] |= (state ? RXCSR_M_RCVEN : 0);
if ((dup_rxcsr[dup] & RXCSR_M_RCVEN) &&
if ((dup_rxcsr[dup] & RXCSR_M_RCVEN) &&
(!(orig_val & RXCSR_M_RCVEN))) { /* Upward transition of receiver enable */
UNIT *uptr = dup_units + dup;
@ -830,7 +812,7 @@ if (!protocol_DDCMP) {
if (crc_inhibit) {
return SCPE_ARG; /* Must enable CRC for DDCMP */
}
/* These settings reflect how RSX operates a bare DUP when used for
/* These settings reflect how RSX operates a bare DUP when used for
DECnet communications */
dup_clear(dup, FALSE);
dup_rxcsr[dup] |= RXCSR_M_STRSYN | RXCSR_M_RCVEN;
@ -917,7 +899,7 @@ if (!tmxr_tpbusyln(&dup_ldsc[dup])) { /* Not Busy sending? */
}
breturn = TRUE;
}
sim_debug (DBG_TRC, DUPDPTR, "dup_put_msg_bytes(dup=%d, len=%d, start=%s, end=%s) %s\n",
sim_debug (DBG_TRC, DUPDPTR, "dup_put_msg_bytes(dup=%d, len=%d, start=%s, end=%s) %s\n",
dup, (int)len, start ? "TRUE" : "FALSE", end ? "TRUE" : "FALSE", breturn ? "Good" : "Busy");
if (breturn && (tmxr_tpbusyln (&dup_ldsc[dup]) || dup_xmtpkbytes[dup])) {
if (dup_xmt_complete_callback[dup])
@ -941,20 +923,20 @@ if ((dup_rcvpkinoff[dup] == 0) && (dup_rcvpkbytes[dup] != 0)) {
*pbuf = &dup_rcvpacket[dup][0];
*psize = dup_rcvpkbytes[dup];
}
sim_debug (DBG_TRC, DUPDPTR, "dup_get_packet(dup=%d, psize=%d)\n",
sim_debug (DBG_TRC, DUPDPTR, "dup_get_packet(dup=%d, psize=%d)\n",
dup, (int)*psize);
return SCPE_OK;
}
static t_stat dup_rcv_byte (int32 dup)
{
sim_debug (DBG_TRC, DUPDPTR, "dup_rcv_byte(dup=%d) - %s, byte %d of %d\n", dup,
sim_debug (DBG_TRC, DUPDPTR, "dup_rcv_byte(dup=%d) - %s, byte %d of %d\n", dup,
(dup_rxcsr[dup] & RXCSR_M_RCVEN) ? "enabled" : "disabled",
dup_rcvpkinoff[dup], dup_rcvpkbytes[dup]);
if (!(dup_rxcsr[dup] & RXCSR_M_RCVEN) || (dup_rcvpkbytes[dup] == 0) || (dup_rxcsr[dup] & RXCSR_M_RXDONE))
return SCPE_OK;
if (dup_rcv_packet_data_callback[dup]) {
sim_debug (DBG_TRC, DUPDPTR, "dup_rcv_byte(dup=%d, psize=%d) - Invoking Receive Data callback\n",
sim_debug (DBG_TRC, DUPDPTR, "dup_rcv_byte(dup=%d, psize=%d) - Invoking Receive Data callback\n",
dup, (int)dup_rcvpkbytes[dup]);
dup_rcv_packet_data_callback[dup](dup, dup_rcvpkbytes[dup]);
return SCPE_OK;
@ -964,7 +946,7 @@ dup_rxdbuf[dup] &= ~RXDBUF_M_RCRCER;
dup_rxdbuf[dup] &= ~RXDBUF_M_RXDBUF;
dup_rxdbuf[dup] |= dup_rcvpacket[dup][dup_rcvpkinoff[dup]++];
dup_rxcsr[dup] |= RXCSR_M_RXDONE;
if (((dup_rcvpkinoff[dup] == 8) ||
if (((dup_rcvpkinoff[dup] == 8) ||
(dup_rcvpkinoff[dup] >= dup_rcvpkbytes[dup])) &&
(0 == ddcmp_crc16 (0, dup_rcvpacket[dup], dup_rcvpkinoff[dup])))
dup_rxdbuf[dup] |= RXDBUF_M_RCRCER;
@ -1086,7 +1068,7 @@ if (active)
else {
for (dup=0; dup < dup_desc.lines; dup++) {
if (dup_speed[dup]/8) {
dup_wait[dup] = (tmxr_poll)/(dup_speed[dup]/8);
dup_wait[dup] = (tmxr_poll*2)/(dup_speed[dup]/8);
if (dup_wait[dup] < DUP_WAIT)
dup_wait[dup] = DUP_WAIT;
}
@ -1103,36 +1085,36 @@ return SCPE_OK;
static void dup_clr_rxint (int32 dup)
{
dup_rxi = dup_rxi & ~(1 << dup); /* clr mux rcv int */
if (dup_rxi == 0 && dup_txi == 0) /* all clr? */
uba_clr_irq(&dup_dib);
else uba_set_irq(&dup_dib); /* no, set intr */
return;
int vect;
vect = dup_dib.uba_vect + (dup * 010); /* return vector */
uba_clr_irq(&dup_dib, vect);
return;
}
static void dup_set_rxint (int32 dup)
{
dup_rxi = dup_rxi | (1 << dup); /* set mux rcv int */
uba_set_irq (&dup_dib); /* set master intr */
sim_debug(DEBUG_IRQ, DUPDPTR, "dup_set_rxint(dup=%d)\n", dup);
return;
int vect;
vect = dup_dib.uba_vect + (dup * 010); /* return vector */
uba_set_irq(&dup_dib, vect);
sim_debug(DEBUG_IRQ, DUPDPTR, "dup_set_rxint(dup=%d)\n", dup);
return;
}
static void dup_clr_txint (int32 dup)
{
dup_txi = dup_txi & ~(1 << dup); /* clr mux xmt int */
if (dup_txi == 0 && dup_rxi == 0) /* all clr? */
uba_clr_irq (&dup_dib);
else uba_set_irq (&dup_dib); /* no, set intr */
return;
int vect;
vect = dup_dib.uba_vect + 4 + (dup * 010); /* return vector */
uba_clr_irq(&dup_dib, vect);
return;
}
static void dup_set_txint (int32 dup)
{
dup_txi = dup_txi | (1 << dup); /* set mux xmt int */
uba_set_irq (&dup_dib); /* set master intr */
sim_debug(DEBUG_IRQ, DUPDPTR, "dup_set_txint(dup=%d)\n", dup);
return;
int vect;
vect = dup_dib.uba_vect + 4 + (dup * 010); /* return vector */
uba_set_irq(&dup_dib, vect);
sim_debug(DEBUG_IRQ, DUPDPTR, "dup_set_txint(dup=%d)\n", dup);
return;
}
/* Device reset */
@ -1189,8 +1171,12 @@ for (i = 0; i < dup_desc.lines; i++) { /* init each line */
if (dup_units[i].flags & UNIT_ATT)
++attached;
}
dup_rxi = dup_txi = 0; /* clr master int */
uba_clr_irq (&dup_dib);
for (i = 0; i < dup_desc.lines; i++) { /* Clear irq's */
int vect = dup_dib.uba_vect + (i * 010);
uba_clr_irq(&dup_dib, vect);
vect += 4;
uba_clr_irq(&dup_dib, vect);
}
tmxr_set_modem_control_passthru (&dup_desc); /* We always want Modem Control */
dup_desc.notelnet = TRUE; /* We always want raw tcp socket */
dup_desc.dptr = DUPDPTR; /* Connect appropriate device */

View File

@ -124,7 +124,7 @@ t_stat dz_detach (UNIT *uptr);
t_stat dz_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
const char *cptr);
const char *dz_description (DEVICE *dptr);
DIB dz_dib = { 0760000, 077, 0340, 5, 3, &dz_read, &dz_write, &dz_vect, 0, 0 };
DIB dz_dib = { 0760000, 077, 0340, 5, 3, &dz_read, &dz_write, 0, 0, 0 };
UNIT dz_unit = {
UDATA (&dz_svc, TT_MODE_7B+UNIT_IDLE+UNIT_DISABLE+UNIT_ATTABLE, 0), KBD_POLL_WAIT
@ -188,6 +188,8 @@ dz_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
TMLN *lp;
int i;
if ((dptr->flags & DEV_DIS) != 0)
return 1;
if ((dptr->units[0].flags & UNIT_DIS) != 0)
return 1;
addr &= dibp->uba_mask;
@ -221,6 +223,15 @@ dz_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
}
dz_csr[base] &= ~(TIE|SAE|RIE|MSE|CLR|MAINT);
dz_csr[base] |= data & (TIE|SAE|RIE|MSE|MAINT);
if (((dz_csr[base] & (RDONE|RIE)) == (RDONE|RIE)) ||
(dz_csr[base] & (SA|SAE)) == (SA|SAE))
uba_set_irq(dibp, dibp->uba_vect + (010 * base));
else
uba_clr_irq(dibp, dibp->uba_vect + (010 * base));
if ((dz_csr[base] & (TRDY|TIE)) == (TRDY|TIE))
uba_set_irq(dibp, dibp->uba_vect + 4 + (010 * base));
else
uba_clr_irq(dibp, dibp->uba_vect + 4 + (010 * base));
break;
case 2:
@ -245,6 +256,7 @@ dz_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
else
data = (temp & 0177400) | data;
}
dz_csr[base] &= ~(TRDY);
for (i = 0; i < 8; i++) {
lp = &dz_ldsc[ln + i];
if ((data & (LINE_ENB << i)) != 0)
@ -255,8 +267,9 @@ dz_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
tmxr_set_get_modem_bits(lp, TMXR_MDM_OUTGOING, 0, NULL);
else
tmxr_set_get_modem_bits(lp, 0, TMXR_MDM_OUTGOING, NULL);
sim_debug(DEBUG_DETAIL, dptr, "DZ%o sstatus %07o %o %o\n", base, data, i, dz_flags[ln+i]);
sim_debug(DEBUG_EXP, dptr, "DZ%o sstatus %07o %o %o\n", base, data, i, dz_flags[ln+i]);
}
uba_clr_irq(dibp, dibp->uba_vect + 4 + (010 * base));
break;
case 6:
@ -280,12 +293,11 @@ dz_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
if (r == SCPE_STALL)
dz_xmit[ln] = TRDY | ch;
}
dz_csr[base] &= ~TRDY;
uba_clr_irq(dibp, dibp->uba_vect + 4 + (010 * base));
break;
}
dz_csr[base] &= ~TRDY;
if ((dz_csr[base] & MSE) == 0)
return 0;
dz_checkirq(dibp);
return 0;
}
@ -300,6 +312,8 @@ dz_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access)
TMLN *lp;
int i;
if ((dptr->flags & DEV_DIS) != 0)
return 1;
if ((dptr->units[0].flags & UNIT_DIS) != 0)
return 1;
addr &= dibp->uba_mask;
@ -318,26 +332,29 @@ dz_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access)
if ((dz_csr[base] & MSE) == 0)
return 0;
dz_csr[base] &= ~(SA|RDONE);
uba_clr_irq(dibp, dibp->uba_vect + (010 * base));
if (!empty(&dz_recv[base])) {
*data = dz_recv[base].buff[dz_recv[base].out_ptr];
inco(&dz_recv[base]);
dz_recv[base].len = 0;
}
if (!empty(&dz_recv[base]))
if (!empty(&dz_recv[base])) {
dz_csr[base] |= RDONE;
dz_checkirq(dibp);
if (dz_csr[base] & RIE) {
uba_set_irq(dibp, dibp->uba_vect + (010 * base));
}
}
break;
case 4:
temp = 0;
ln = base << 3;
base <<= 3;
/* Set up the current status */
for (i = 0; i < 8; i++) {
sim_debug(DEBUG_DETAIL, dptr, "DZ%o status %o %o\n", base, i, dz_flags[ln+i]);
if (dz_flags[ln + i] & LINE_EN)
temp |= LINE_ENB << i;
if (dz_flags[ln + i] & DTR_FLAG)
temp |= DTR << i;
for (ln = 0; ln < 8; ln++) {
if (dz_flags[base + ln] & LINE_EN)
temp |= LINE_ENB << ln;
if (dz_flags[base + ln] & DTR_FLAG)
temp |= DTR << ln;
}
*data = temp;
break;
@ -374,7 +391,8 @@ t_stat dz_svc (UNIT *uptr)
ln = tmxr_poll_conn (&dz_desc); /* look for connect */
if (ln >= 0) { /* got one? rcv enb*/
dz_ring[(ln & 030) >> 3] |= (1 << (ln & 7));
sim_debug(DEBUG_DETAIL, &dz_dev, "DC line connect %d\n", ln);
sim_debug(DEBUG_DETAIL, &dz_dev, "DZ line connect %d\n", ln);
dz_xmit[ln] = 0;
}
tmxr_poll_tx(&dz_desc);
tmxr_poll_rx(&dz_desc);
@ -392,7 +410,7 @@ t_stat dz_svc (UNIT *uptr)
while (!full(&dz_recv[base])) {
int32 ch = tmxr_getc_ln(lp);
if ((ch & TMXR_VALID) != 0) {
if (ch & SCPE_BREAK) { /* break? */
if (ch & SCPE_BREAK) { /* break? */
temp = FRM_ERR;
} else {
ch = sim_tt_inpcvt (ch, TT_GET_MODE(dz_unit.flags) | TTUF_KSR);
@ -402,10 +420,15 @@ t_stat dz_svc (UNIT *uptr)
inci(&dz_recv[base]);
dz_recv[base].len++;
dz_csr[base] |= RDONE;
if (dz_recv[base].len > 16)
if (dz_csr[base] & RIE)
uba_set_irq(dibp, dibp->uba_vect + (010 * base));
if (dz_recv[base].len > 16) {
dz_csr[base] |= SA;
sim_debug(DEBUG_DETAIL, dptr, "TTY recieve %d: %o\n",
ln, ch);
if (dz_csr[base] & SAE) {
uba_set_irq(dibp, dibp->uba_vect + (010 * base));
}
}
sim_debug(DEBUG_DETAIL, dptr, "TTY recieve %d: %o\n", ln, ch);
} else
break;
}
@ -423,56 +446,36 @@ dz_checkirq(struct pdp_dib *dibp)
int j;
int i;
int ln;
int stop;
TMLN *lp;
int irq = 0;
for (i = 0; i < NUM_DEVS_DZ; i++) {
if ((dz_csr[i] & MSE) == 0)
continue;
ln = ((dz_csr[i] & TLINE) >> TLINE_V) + (i << 3);
dz_csr[i] &= ~TRDY;
/* See if there is another line ready */
for (j = 0; j < 8; j++) {
ln = (ln & 070) | ((ln + 1) & 07);
lp = &dz_ldsc[ln];
/* Connected and empty xmit_buffer */
if ((dz_flags[ln] & LINE_EN) != 0 && dz_xmit[ln] == 0) {
dz_csr[i] &= ~(TLINE);
dz_csr[i] |= TRDY | ((ln & 07) << TLINE_V);
break;
}
}
stop = ln;
if ((dz_csr[i] & TRDY) == 0) {
/* See if there is another line ready */
do {
ln = (ln & 070) | ((ln + 1) & 07);
lp = &dz_ldsc[ln];
/* Connected and empty xmit_buffer */
if ((dz_flags[ln] & LINE_EN) != 0 && dz_xmit[ln] == 0) {
sim_debug(DEBUG_DETAIL, &dz_dev, "DZ line ready %o\n", ln);
/* Check flags to see if anything would generate an interrupt */
if ((dz_csr[i] & (TIE|TRDY)) == (TIE|TRDY) ||
(dz_csr[i] & (SA|SAE)) == (SA|SAE) ||
(dz_csr[i] & (RDONE|SAE|RIE)) == (RDONE|RIE)) {
sim_debug(DEBUG_DETAIL, &dz_dev, "Set irq %05o\n", dz_csr[i]);
uba_set_irq(dibp);
return;
dz_csr[i] &= ~(TRDY|TLINE);
dz_csr[i] |= TRDY | ((ln & 07) << TLINE_V);
if (dz_csr[i] & TIE) {
uba_set_irq(dibp, dibp->uba_vect + 4 + (010 * i));
}
break;
}
} while (ln != stop);
}
}
sim_debug(DEBUG_DETAIL, &dz_dev, "Clr irq\n");
/* Nothing found, so clear any flags */
uba_clr_irq(dibp);
}
/* Return the vector of first ready device */
uint16
dz_vect(struct pdp_dib *dibp)
{
int i;
uint16 vect = dibp->uba_vect;
for (i = 0; i < NUM_DEVS_DZ; i++) {
if ((dz_csr[i] & (SA|SAE)) == (SA|SAE) ||
(dz_csr[i] & (RDONE|SAE|RIE)) == (RDONE|RIE))
return vect;
if ((dz_csr[i] & (TIE|TRDY)) == (TIE|TRDY))
return vect + 4;
vect += 010;
}
return 0;
}
/* Reset routine */
t_stat

View File

@ -359,7 +359,7 @@ static int32 BintPending = 0;
* For this to work, k, a uint32 must be in scope and valid.
*
* k can be found in several ways:
* k is the offset into any of the tables.
* k is the offset into any of the tables.
* Given a UNIT pointer k = txup->unit_kmc.
* The KMC assigned to control a DUP is stored it its dupstate.
* k = dupState[dupno]->kmc; (-1 if not controlled by any KMC)
@ -398,7 +398,7 @@ static int32 BintPending = 0;
/* KMC event notifications are funneled through the small number of CSRs.
* Since the CSRs may not be available when an event happens, events are
* queued in these structures. An event is represented by the values to
* be exposed in BSEL2, BSEL4, and BSEL6.
* be exposed in BSEL2, BSEL4, and BSEL6.
*
* Queue overflow is signalled by setting the overflow bit in the entry
* at the tail of the completion queue at the time a new entry fails to
@ -489,15 +489,13 @@ static t_stat kmc_showLineSpeed (FILE *st, UNIT *txup, int32 val, CONST void *de
static t_stat kmc_showStatus (FILE *st, UNIT *up, int32 v, CONST void *dp);
static t_stat kmc_help (FILE *st, DEVICE *dptr,
UNIT *uptr, int32 flag, const char *cptr);
UNIT *uptr, int32 flag, const char *cptr);
static const char *kmc_description (DEVICE *dptr);
/* Global data */
extern int32 tmxr_poll; /* calibrated delay */
static uint16 kmc_intvect(DIB *dibp);
#define IOLN_KMC 010
static DIB kmc_dib = {
@ -506,10 +504,10 @@ static DIB kmc_dib = {
0540, /* Interrupt vector */
5, /* Interrupt level */
3, /* UBA Adaptor number */
&kmc_readCsr, /* rd - read IO */
&kmc_writeCsr, /* wr - write IO */
&kmc_intvect, /* Return interrupt vector */
NULL,
};
/* One UNIT for each (possible) active line for transmit, and another for receive */
@ -529,7 +527,7 @@ static UNIT tx_units[MAX_ACTIVE][KMC_UNITS]; /* Line 0 is primary unit. txup re
static UNIT rx_units[MAX_ACTIVE][KMC_UNITS]; /* Secondary unit, used for RX. rxup references */
DEVICE kmc_int_rxdev = {
"KDP-RX", rx_units[0],
"KDP-RX", rx_units[0],
NULL, /* Register decode tables */
NULL, /* Modifier table */
INITIAL_KMCS, /* Number of units */
@ -619,8 +617,8 @@ MTAB kmc_mod[] = {
};
DEVICE kmc_dev = {
"KDP",
tx_units[0],
"KDP",
tx_units[0],
kmc_reg, /* Register decode tables */
kmc_mod, /* Modifier table */
INITIAL_KMCS, /* Number of units */
@ -753,7 +751,7 @@ static t_stat kmc_reset(DEVICE* dptr) {
if (sim_switches & SWMASK ('P'))
gflags &= ~FLG_INIT;
if (!(gflags & FLG_INIT)) { /* Power-up reset */
sel0 = 0x00aa;
sel2 = 0xa5a5;
@ -773,7 +771,6 @@ static t_stat kmc_reset(DEVICE* dptr) {
return SCPE_OK;
}
/*
* Read registers:
*/
@ -809,7 +806,7 @@ static t_stat kmc_readCsr(DEVICE *dptr, t_addr PA, uint16* data, int32 access) {
}
break;
}
sim_debug (DF_RGR, &kmc_dev, "KMC%u CSR rd: addr=0%06o SEL%d, data=%06o 0x%04x access=%d\n",
k, PA, PA & 07, *data, *data, access);
return SCPE_OK;
@ -937,40 +934,6 @@ static t_stat kmc_writeCsr(DEVICE *dptr, t_addr PA, uint16 data, int32 access) {
return SCPE_OK;
}
static uint16
kmc_intvect(DIB *dibp)
{
int32 vec = 0; /* no interrupt request active */
int32 k;
for (k = 0; ((size_t)k) < DIM (kmc_gflags); k++) {
if (gflags & FLG_AINT) {
vec = dibp->uba_vect + (k*010);
gflags &= ~FLG_AINT;
--AintPending;
break;
}
}
if (vec == 0) {
for (k = 0; ((size_t)k) < DIM (kmc_gflags); k++) {
if (gflags & FLG_BINT) {
vec = dibp->uba_vect + 4 + (k*010);
gflags &= ~FLG_BINT;
--BintPending;
break;
}
}
}
if (AintPending != 0 || BintPending != 0)
uba_set_irq(dibp);
// else
// uba_clr_irq(dibp);
return vec;
}
/* Microengine simulator
*
@ -999,7 +962,7 @@ static void kmc_doMicroinstruction (int32 k, uint16 instr) {
break;
case 0121202: /* MOVE <NPR><BSEL2> */
case 0021002: /* MOVE <IBUS 0><BSEL2> */
sel2 = (sel2 & ~0xFF) | 0;
sel2 = (sel2 & ~0xFF) | 0;
break;
default:
if ((instr & 0160000) == 0000000) { /* MVI */
@ -1053,7 +1016,7 @@ static void kmc_doMicroinstruction (int32 k, uint16 instr) {
* o When a new buffer descriptor is delivered by the host
* o When a state machine timeout expires
* o When a DUP transmit completion occurs.
*
*
*/
static t_stat kmc_txService (UNIT *txup) {
@ -1110,12 +1073,13 @@ static t_stat kmc_txService (UNIT *txup) {
switch (d->txstate) {
case TXDONE: /* Resume from completions */
d->txstate = TXIDLE;
/* Fall through */
case TXIDLE: /* Check for new BD */
if (!kmc_txNewBdl(d)) {
TXSTOP;
}
d->txmlen =
d->txmlen =
d->txslen = 0;
d->txstate = TXRTS;
@ -1124,8 +1088,8 @@ static t_stat kmc_txService (UNIT *txup) {
k, d->line, d->dupidx);
kmc_ctrlOut (k, SEL6_CO_NXM, 0, d->line, 0);
}
/* Fall through */
case TXRTS: /* Wait for CTS */
if (dup_get_CTS (d->dupidx) <= 0) {
TXDELAY (TXRTS, TXCTS_DELAY);
@ -1135,6 +1099,8 @@ static t_stat kmc_txService (UNIT *txup) {
sim_debug (DF_BUF, &kmc_dev, "KMC%u line %u: transmitting bdl=%06o\n",
k, txup->unit_line, d->tx.bda);
/* Fall through */
case TXSOM: /* Start assembling a message */
if (!(d->tx.bd[2] & BDL_SOM)) {
sim_debug (DF_ERR, &kmc_dev, "KMC%u line %u: TX BDL not SOM\n", k, d->line);
@ -1155,12 +1121,14 @@ static t_stat kmc_txService (UNIT *txup) {
}
d->txstate = TXHDR;
/* Fall through */
case TXHDR: /* Assemble the header */
if (!kmc_txAppendBuffer(d)) { /* NXM - Try next list */
TXDELAY (TXDONE, TXDONE_DELAY);
}
TXDELAY (TXHDRX, XTIME (d->tx.bd[1], d->linespeed));
/* Fall through */
case TXHDRX: /* Report header descriptor done */
if (!kmc_bufferAddressOut (k, 0, 0, d->line, d->tx.bda)) {
@ -1185,7 +1153,7 @@ static t_stat kmc_txService (UNIT *txup) {
/* EOM expecting data to follow.
* However, if the OS computes and includes HRC in a data/MOP message, this can
* be the last descriptor. In that case, this is EOM.
*/
*/
if (d->tx.bd[2] & BDL_LDS) {
TXSTATE (TXMRDY);
break;
@ -1203,12 +1171,14 @@ static t_stat kmc_txService (UNIT *txup) {
TXSTOP;
}
d->txstate = TXDATA;
/* Fall through */
case TXDATA: /* Assemble data/maint payload */
if (!kmc_txAppendBuffer(d)) { /* NXM */
TXDELAY (TXDONE, TXDONE_DELAY);
}
TXDELAY (TXDATAX, XTIME (d->tx.bd[1], d->linespeed));
/* Fall through */
case TXDATAX: /* Report BD completion */
if (!kmc_bufferAddressOut (k, 0, 0, d->line, d->tx.bda)) {
@ -1221,13 +1191,14 @@ static t_stat kmc_txService (UNIT *txup) {
TXDELAY (TXDONE, TXDONE_DELAY);
}
TXSTATE (TXDATA);
/* Fall through */
/* These states hand-off the message to the DUP.
* txService suspends until transmit complete.
* Note that txComplete can happen within the calls to the DUP.
*/
case TXMRDY: /* Data with OS-embedded HCRC */
d->txstate = TXACT;
d->txstate = TXACT;
ASSURE (d->txmsg[d->txslen + 0] != DDCMP_ENQ);
ASSURE (((d->txmlen - d->txslen) > 8) && /* Data, length should match count */
(((size_t)(((d->txmsg[d->txslen + 2] & 077) << 8) | d->txmsg[d->txslen + 1])) ==
@ -1334,7 +1305,7 @@ static t_stat kmc_rxService (UNIT *rxup) {
uint16 xrem, seglen;
int i;
t_addr ba;
ASSURE ((k >= 0) && (k < (int32) kmc_dev.numunits) && (d->kmc == k) &&
(d->line == rxup->unit_line));
@ -1349,7 +1320,7 @@ static t_stat kmc_rxService (UNIT *rxup) {
rxup->wait = RXPOLL_DELAY;
/* CAUTION: This switch statement uses fall-through cases
/* CAUTION: This switch statement uses fall-through cases
*
* The KILL logic in kmc_rxBufferIn tracks these states.
*/
@ -1403,7 +1374,7 @@ static t_stat kmc_rxService (UNIT *rxup) {
uint8 type = d->rxmsg[1];
sim_debug (DF_BUF, &kmc_dev, "KMC%u line %u: receiving %s\n",
k, rxup->unit_line,
k, rxup->unit_line,
((type >= DIM (ctlnames))? "UNKNOWN" : ctlnames[type]));
} else {
sim_debug (DF_BUF, &kmc_dev, "KMC%u line %u: receiving %s len=%u\n",
@ -1463,7 +1434,9 @@ static t_stat kmc_rxService (UNIT *rxup) {
ASSURE (seglen > 0);
ba = d->rx.ba;
sim_debug (DF_PKT, &kmc_dev, "Send to: ");
for (i = 0; i < seglen; i++) {
sim_debug (DF_PKT, &kmc_dev, "%02x ", d->rxmsg[d->rxused + i]);
if (uba_write_npr_byte(ba, kmc_dib.uba_ctl, d->rxmsg[d->rxused + i]) == 0) {
uint16 bd[3];
memcpy(bd, &d->rx.bd, sizeof bd);
@ -1476,9 +1449,10 @@ static t_stat kmc_rxService (UNIT *rxup) {
}
ba++;
}
sim_debug (DF_PKT, &kmc_dev, "\n");
d->rx.ba += seglen;
d->rxused += seglen;
d->rx.rcvc += seglen;
d->rxused += seglen;
if (d->rxused == 6) {
if (0 != ddcmp_crc16 (0, d->rxmsg, 8)) {
@ -1584,7 +1558,7 @@ static t_stat kmc_rxService (UNIT *rxup) {
}
rxup->wait = RXNEWBD_DELAY;
break;
case RXNOBUF:
kmc_ctrlOut (k, SEL6_CO_NOBUF, SEL2_IOT, d->line, 0);
d->rxstate = RXIDLE;
@ -1723,7 +1697,7 @@ static void kmc_startUcode (int32 k) {
initqueue (&d->rxqh, &d->rxavail, INIT_HDR_ONLY);
initqueue (&d->txqh, &d->txavail, INIT_HDR_ONLY);
initqueue (&d->bdqh, &d->bdavail, MAX_LIST_SIZE(d->bdq));
d->rxstate = RXIDLE;
d->txstate = TXIDLE;
}
@ -1738,7 +1712,7 @@ static void kmc_startUcode (int32 k) {
kmc_updints (k);
return;
}
/*
* Perform an input command
*
@ -1748,7 +1722,7 @@ static void kmc_startUcode (int32 k) {
*
* The microcode sets RDI by writing the entire BSEL2 with just RDI.
* This works because RDO can not be set at the same time as RDI.
*
*
* Mark P found that VMS drivers rely on this and BIS the command code.
* The COM IOP-DUP manual does say that all bits of BSEL2 are
* cleared on completion of a command. However, an output command could
@ -1758,7 +1732,7 @@ static void kmc_startUcode (int32 k) {
* clears RDI. Upon completion of a command, 'all bits of bsel2
* are cleared by the KMC'. This is not implemented literally, since
* the processing of a command can result in an immediate completion,
* setting RDO and the other registers.
* setting RDO and the other registers.
* Thus, although all bits are cleared before dispatching, RDO
* and the other other bits of BSEL2 may be set for a output command
* due to a completion if the host has cleared RQI.
@ -1769,7 +1743,7 @@ static void kmc_dispatchInputCmd(int32 k) {
int32 ba;
int16 cmdsel2 = sel2;
dupstate* d;
line = (cmdsel2 & SEL2_LINE) >> SEL2_V_LINE;
sel2 &= ~0xFF; /* Clear BSEL2. */
@ -1783,10 +1757,10 @@ static void kmc_dispatchInputCmd(int32 k) {
}
d = line2dup[line];
ba = ((sel6 & SEL6_CO_XAD) << (16-SEL6_V_CO_XAD)) | sel4;
sim_debug (DF_CMD, &kmc_dev, "KMC%u line %u: INPUT COMMAND sel2=%06o sel4=%06o sel6=%06o ba=%06o\n", k, line,
cmdsel2, sel4, sel6, ba);
switch (cmdsel2 & (SEL2_IOT | SEL2_CMD)) {
case CMD_BUFFIN: /* TX BUFFER IN */
kmc_txBufferIn(d, ba, sel6);
@ -1816,7 +1790,7 @@ static void kmc_dispatchInputCmd(int32 k) {
* assigned by a KMC. The CSR address is expressed as bits <12:3>
* only. <17:13> are all set for IO page addresses and added by ucode.
* The DUP has 8 registers, so <2:1> must be zero. The other bits are
* reserved and must be zero.
* reserved and must be zero.
*
* There is no way to release a line, short of re-starting the microcode.
*
@ -1845,7 +1819,7 @@ static void kmc_baseIn (int32 k, dupstate *d, uint16 cmdsel2, uint8 line) {
dupidx = dup_csr_to_linenum (csraddress);
if ((dupidx < 0) || (((size_t) dupidx) >= DIM(dupState))) { /* Call this a NXM so OS can recover */
sim_debug (DF_ERR, &kmc_dev, "KMC%u line %u: BASE IN %06o 0x%05x is not an enabled DUP %d\n",
sim_debug (DF_ERR, &kmc_dev, "KMC%u line %u: BASE IN %06o 0x%05x is not an enabled DUP %d\n",
k, line, csraddress, csraddress, dupidx);
kmc_ctrlOut (k, SEL6_CO_NXM, 0, line, 0);
return;
@ -1870,7 +1844,7 @@ static void kmc_baseIn (int32 k, dupstate *d, uint16 cmdsel2, uint8 line) {
line2dup[line] = d;
d->line = line;
/*
/*
* Jumper W3 Installed causes RTS,DTR, and SecTxD to be cleared on Device Reset or bus init.
* Jumper W3 is installed in factory DUPs, and in the KS10 config.
* Make sure the DUP emulation enables this option.
@ -1891,7 +1865,7 @@ static void kmc_baseIn (int32 k, dupstate *d, uint16 cmdsel2, uint8 line) {
d->dupidx = dupidx;
sim_debug (DF_INF, &kmc_dev, "KMC%u line %u: BASE IN DUP%u address=%06o 0x%05x assigned\n",
sim_debug (DF_INF, &kmc_dev, "KMC%u line %u: BASE IN DUP%u address=%06o 0x%05x assigned\n",
k, line, d->dupidx,csraddress, csraddress);
return;
}
@ -1916,7 +1890,7 @@ static void kmc_ctrlIn (int32 k, dupstate *d, int line) {
if (!(sel6 & SEL6_CI_ENABLE)) {
sim_debug (DF_CMD, &kmc_dev, "line disabled\n");
} else {
sim_debug (DF_CMD, &kmc_dev, "enabled for %s in %s duplex",
sim_debug (DF_CMD, &kmc_dev, "enabled for %s in %s duplex",
(sel6 & SEL6_CI_DDCMP)? "DDCMP":"Bit-stuffing",
(sel6 & SEL6_CI_HDX)? "half" : "full");
if (sel6 & SEL6_CI_ENASS) {
@ -1929,17 +1903,17 @@ static void kmc_ctrlIn (int32 k, dupstate *d, int line) {
/* BSEL4 has the polling count, which isn't needed for emulation */
d->linkstate &= ~(LINK_DSR|LINK_SEL);/* Initialize modem state reporting. */
d->linkstate &= ~(LINK_DSR|LINK_SEL);/* Initialize modem state reporting. */
d->ctrlFlags = sel6;
/* Initialize DUP interface in the appropriate mode
* DTR will be turned on.
*/
r = dup_setup_dup (d->dupidx, (sel6 & SEL6_CI_ENABLE),
(sel6 & SEL6_CI_DDCMP),
(sel6 & SEL6_CI_NOCRC),
(sel6 & SEL6_CI_HDX),
r = dup_setup_dup (d->dupidx, (sel6 & SEL6_CI_ENABLE),
(sel6 & SEL6_CI_DDCMP),
(sel6 & SEL6_CI_NOCRC),
(sel6 & SEL6_CI_HDX),
(sel6 & SEL6_CI_ENASS) ? (sel6 & SEL6_CI_SADDR) : 0);
/* If setup succeeded, enable packet callbacks.
@ -1962,14 +1936,14 @@ static void kmc_ctrlIn (int32 k, dupstate *d, int line) {
* RX BUFFER IN delivers a buffer descriptor list from the host to
* the KMC. It may also deassign a buffer descriptor list.
*
* A buffer descriptor list is a sequential list of three word blocks in
* A buffer descriptor list is a sequential list of three word blocks in
* host memory space. Each 3-word block points to and describes the
* boundaries of a single buffer, which is also in host CPU memory.
* boundaries of a single buffer, which is also in host CPU memory.
*
* A buffer descriptor list is defined by its starting address. The
* end of a buffer descriptor list is marked in the list. A maximum of
* MAXQUEUE transmit and MAXQUEUE receive lists can be assigned to each
* COMM IOP-DUP communications line.
* COMM IOP-DUP communications line.
*
* The starting address of a buffer descriptor list must be word aligned.
*
@ -2003,7 +1977,7 @@ void kmc_rxBufferIn(dupstate *d, int32 ba, uint16 sel6v) {
if (!kmc_printBufferIn (k, &kmc_dev, d->line, TRUE, d->rxavail, ba, sel6v))
return;
if (sel6v & SEL6_BI_KILL) {
/* Kill all current RX buffers.
* Resync the DUP receiver.
@ -2044,7 +2018,7 @@ void kmc_rxBufferIn(dupstate *d, int32 ba, uint16 sel6v) {
}
qe->ba = ba;
ASSURE (insqueue (&qe->hdr, d->rxqh.prev, &d->rxavail, MAXQUEUE));
if (sel6v & SEL6_BI_KILL) { /* KILL & Replace - ENABLE is set too */
kmc_ctrlOut (k, SEL6_CO_KDONE, SEL2_IOT, d->line, bda);
}
@ -2059,7 +2033,7 @@ void kmc_rxBufferIn(dupstate *d, int32 ba, uint16 sel6v) {
/* Message available callback
*
* The DUP calls this routine when a new message is available
* The DUP calls this routine when a new message is available
* to be read.
*
* If the line's receive thread is idle, it is called to start the
@ -2122,7 +2096,7 @@ void kmc_txBufferIn(dupstate *d, int32 ba, uint16 sel6v) {
if (!kmc_printBufferIn (k, &kmc_dev, d->line, FALSE, d->txavail, ba, sel6v))
return;
if (sel6v & SEL6_BI_KILL) {
/* Kill all current TX buffers. The DUP can't abort transmission in simulation, so
* anything pending will stop when complete. The queue is reset here because
@ -2152,7 +2126,7 @@ void kmc_txBufferIn(dupstate *d, int32 ba, uint16 sel6v) {
}
}
}
if (!(qe = (BDL *)remqueue (d->bdqh.next, &d->bdavail))) {
sim_debug (DF_ERR, &kmc_dev, "KMC%u line %u: Too many transmit buffers from host\n", k, d->line);
kmc_halt (k, HALT_XMTOVF);
@ -2161,13 +2135,13 @@ void kmc_txBufferIn(dupstate *d, int32 ba, uint16 sel6v) {
qe->ba = ba;
ASSURE (insqueue (&qe->hdr, d->txqh.prev, &d->txavail, MAXQUEUE));
if (d->txstate == TXIDLE) {
UNIT *txup = &tx_units[d->line][k];
UNIT *txup = &tx_units[d->line][k];
if (!sim_is_active (txup)) {
txup->wait = TXSTART_DELAY;
txup->wait = TXSTART_DELAY;
sim_activate_after (txup, txup->wait);
}
}
return;
}
@ -2212,7 +2186,7 @@ static void kmc_txComplete (int32 dupidx, int status) {
} else {
if (d->tx.bd[2] & BDL_LDS)
d->txstate = TXDONE;
else
else
d->txstate = TXSOM;
}
sim_cancel (txup);
@ -2225,13 +2199,13 @@ static void kmc_txComplete (int32 dupidx, int status) {
static t_bool kmc_txNewBdl(dupstate *d) {
BDL *qe;
if (!(qe = (BDL *)remqueue (d->txqh.next, &d->txavail))) {
return FALSE;
}
d->tx.bda = qe->ba;
ASSURE (insqueue (&qe->hdr, d->bdqh.prev, &d->bdavail, DIM(d->bdq)));
d->tx.first = TRUE;
d->tx.bd[1] = 0;
return kmc_txNewBd(d);
@ -2269,7 +2243,7 @@ static t_bool kmc_txNewBd(dupstate *d) {
}
ba += 2;
}
d->tx.ba = ((d->tx.bd[2] & BDL_XAD) << BDL_S_XAD) | d->tx.bd[0];
return TRUE;
}
@ -2299,6 +2273,7 @@ static t_bool kmc_txAppendBuffer(dupstate *d) {
}
ba++;
}
kmc_updateBDCount (d->tx.bda, d->tx.bd);
d->txmlen += d->tx.bd[1];
return TRUE;
}
@ -2317,7 +2292,7 @@ static t_bool kmc_txAppendBuffer(dupstate *d) {
* should be writing a command to them. Output is not possible.
*
* If neither is set, the KMC takes ownership of the CSRs and updates
* them from the queue before setting RDO.
* them from the queue before setting RDO.
*
* There is aditional prioitization of RDI/RDO in the logic that detects
* RDO clearing. If RQI has been set by the host before clearing RDO,
@ -2341,7 +2316,7 @@ static void kmc_processCompletions (int32 k) {
sel6 = qe->bsel6;
sim_debug (DF_QUE, &kmc_dev, "KMC%u line %u: %s %s delivered: sel2=%06o sel4=%06o sel6=%06o\n",
k, ((sel2 & SEL2_LINE)>>SEL2_V_LINE),
k, ((sel2 & SEL2_LINE)>>SEL2_V_LINE),
(sel2 & SEL2_IOT)? "RX":"TX",
((sel2 & SEL2_CMD) == CMD_BUFFOUT)? "BUFFER OUT":"CONTROL OUT",
sel2, sel4, sel6);
@ -2456,7 +2431,7 @@ static t_bool kmc_bufferAddressOut (int32 k, uint16 flags, uint16 rx, uint8 line
sim_debug (DF_BFO, &kmc_dev, "KMC%u line %u: %s BUFFER OUT Flags=%06o Address=%06o\n",
k, line, rx? "RX": "TX", flags, bda);
if (!kmc_printBDL(k, DF_BFO, &kmc_dev, line, bda, rx? 6: 2))
return FALSE;
if (!(qe = (CQ *)remqueue (freecqHead.next, &freecqCount))) {
@ -2504,7 +2479,7 @@ static int32 kmc_updateBDCount(uint32 bda, uint16 *bd) {
if (uba_write_npr_word(bda, kmc_dib.uba_ctl, bd[1]) == 0) {
return 1;
}
if ((bda & 2) == 0) {
if ((bda & 2) != 0) {
if (uba_write_npr_word(bda + 2, kmc_dib.uba_ctl, bd[2]) == 0) {
return 1;
}
@ -2563,51 +2538,36 @@ static void kmc_halt (int32 k, int error) {
*/
static void kmc_updints(int32 k) {
uint16 vect = kmc_dib.uba_vect;
if (!(gflags & FLG_UCINI)) {
return;
}
if ((sel0 & SEL0_IEI) && (sel2 & SEL2_RDI)) {
if (!(gflags & FLG_AINT)) {
sim_debug (DF_INT, &kmc_dev, "KMC%u: set input interrupt pending\n", k);
gflags |= FLG_AINT;
AintPending++;
}
sim_debug (DF_INT, &kmc_dev, "KMC%u: set input interrupt pending\n", k);
uba_set_irq(&kmc_dib, vect + (k*10));
} else {
if (gflags & FLG_AINT) {
sim_debug (DF_INT, &kmc_dev, "KMC%u: cleared pending input interrupt\n", k);
gflags &= ~FLG_AINT;
--AintPending;
}
uba_clr_irq(&kmc_dib, vect + (k*10));
sim_debug (DF_INT, &kmc_dev, "KMC%u: cleared pending input interrupt\n", k);
}
if ((sel0 & SEL0_IEO) && (sel2 & SEL2_RDO)) {
if (!(gflags & FLG_BINT)) {
sim_debug (DF_INT, &kmc_dev, "KMC%u: set output interrupt\n", k);
gflags |= FLG_BINT;
BintPending++;
}
uba_set_irq(&kmc_dib, vect + 4 + (k*10));
sim_debug (DF_INT, &kmc_dev, "KMC%u: set output interrupt\n", k);
} else {
if (gflags & FLG_BINT) {
sim_debug (DF_INT, &kmc_dev, "KKMC%u: clear output interrupt\n", k);
gflags &= ~FLG_BINT;
--BintPending;
}
uba_clr_irq(&kmc_dib, vect + 4 + (k*10));
sim_debug (DF_INT, &kmc_dev, "KKMC%u: clear output interrupt\n", k);
}
if (AintPending != 0 || BintPending != 0)
uba_set_irq(&kmc_dib);
else
uba_clr_irq(&kmc_dib);
return;
}
/* Debug: Log a BUFFER IN or BUFFER OUT command.
* returns FALSE if print encounters a NXM as (a) it's fatal and
* returns FALSE if print encounters a NXM as (a) it's fatal and
* (b) only one completion per bdl.
*/
static t_bool kmc_printBufferIn (int32 k, DEVICE *dev, uint8 line, t_bool rx,
static t_bool kmc_printBufferIn (int32 k, DEVICE *dev, uint8 line, t_bool rx,
int32 count, int32 ba, uint16 sel6v) {
t_bool kill = ((sel6v & (SEL6_BI_KILL|SEL6_BI_ENABLE)) == SEL6_BI_KILL);
const char *dir = rx? "RX": "TX";
@ -2653,7 +2613,7 @@ static t_bool kmc_printBDL(int32 k, uint32 dbits, DEVICE *dev, uint8 line, int32
}
ba += 2;
}
dp = bd[0] | ((bd[2] & BDL_XAD) << BDL_S_XAD);
sim_debug (dbits, dev, " bd[0] = %06o 0x%04X Adr=%06o\n", bd[0], bd[0], dp);
sim_debug (dbits, dev, " bd[1] = %06o 0x%04X Len=%u.\n", bd[1], bd[1], bd[1]);
@ -2685,8 +2645,8 @@ static t_bool kmc_printBDL(int32 k, uint32 dbits, DEVICE *dev, uint8 line, int32
return FALSE;
}
}
if (prbuf != 5) { /* Don't print RX buffer in */
if (prbuf != 5) { /* Don't print RX buffer in */
for (i = 0; i < bd[1] ; i++) {
sim_debug (dbits, dev, " %02x", buf[i]);
}
@ -2817,7 +2777,7 @@ static t_stat kmc_setDeviceCount (UNIT *txup, int32 val, CONST char *cptr, void
uint32 dupidx;
t_stat r;
DEVICE *dptr = find_dev_from_unit(txup);
if (cptr == NULL)
return SCPE_ARG;
@ -2948,7 +2908,7 @@ t_stat kmc_showStatus (FILE *st, UNIT *up, int32 v, CONST void *dp) {
fprintf (st, "KMC%u ", k);
if (!(sel0 & SEL0_RUN)) {
fprintf (st, "%s halted at uPC %04o\n",
fprintf (st, "%s halted at uPC %04o\n",
(ucname?ucname: "(No or unknown microcode)"), upc);
return SCPE_OK;
}

View File

@ -551,9 +551,9 @@ lp20_update_chkirq (UNIT *uptr, int done, int irq)
lp20_cs2 |= CS2_NRDY|CS2_OFFL;
}
if ((lp20_cs1 & CS1_IE) && (irq || (lp20_cs1 & CS1_DONE)))
uba_set_irq(dibp);
uba_set_irq(dibp, dibp->uba_vect);
else
uba_clr_irq(dibp);
uba_clr_irq(dibp, dibp->uba_vect);
}
/*
@ -568,8 +568,8 @@ lp20_update_ready(UNIT *uptr, uint16 setrdy, uint16 clrrdy)
uint16 new_cs1 = (lp20_cs1 | setrdy) & ~clrrdy;
if ((new_cs1 ^ lp20_cs1) & (CS1_ONL|CS1_DVON) && !sim_is_active(uptr)) {
if (new_cs1 & CS1_IE)
uba_set_irq(dibp);
if (new_cs1 & CS1_IE)
uba_set_irq(dibp, dibp->uba_vect);
}
if (new_cs1 & CS1_DVON)
lp20_cs2 &= ~CS2_DVOF;
@ -871,7 +871,7 @@ t_stat lp20_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
const char *cptr)
{
fprintf (st, "Line Printer (LPT)\n\n");
fprintf (st, "The line printer (LPT) writes data to a disk file. \n");
fprintf (st, "The line printer (LPT) writes data to a disk file. \n");
fprintf (st, "The Line printer can be configured to any number of lines per page with the:\n");
fprintf (st, " sim> SET %s LINESPERPAGE=n\n\n", dptr->name);
fprintf (st, "The default is 66 lines per page.\n\n");

View File

@ -1,4 +1,4 @@
/* ks10_tcu.c: PDP-10
/* ks10_tcu.c: PDP-10
Copyright (c) 2021, Richard Cornwell

View File

@ -45,11 +45,17 @@
#define UBST_BAD 000000200000 /* Bad mem transfer */
#define UBST_TIM 000000400000 /* UBA Timout */
#define VECT_L 0x10
#define VECT_H 0x20
#define VECT_CTR 0x0F
uint32 uba_map[2][64];
uint32 uba_status[2];
uint32 uba_status[2];
int uba_device[16] = { -1, 0, -1, 1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 };
int uba_irq_ctlr[128];
int
uba_read(t_addr addr, int ctl, uint64 *data, int access)
{
@ -74,21 +80,15 @@ uba_read(t_addr addr, int ctl, uint64 *data, int access)
return 0;
} else if ((addr & 077) == 0) {
int pih, pil;
int irqf = 0;
*data = (uint64)uba_status[ubm];
pih = 0200 >> ((uba_status[ubm] >> 3) & 07);
pil = 0200 >> (uba_status[ubm] & 07);
for(i = 0; (dptr = sim_devices[i]) != NULL; i++) {
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
continue;
/* If device is pending on this level save */
if (dibp->uba_ctl == ctl) {
if ((dibp->uba_irq_pend & pil) != 0)
*data |= UBST_INTL;
if ((dibp->uba_irq_pend & pih) != 0)
*data |= UBST_INTH;
}
for (i = 0; i < 128; i++) {
if ((uba_irq_ctlr[i] & VECT_CTR) == ctl)
irqf |= uba_irq_ctlr[i];
}
*data |= (irqf & (VECT_L|VECT_H)) << 6;
return 0;
} else if ((addr & 077) == 1) {
*data = 0;
@ -104,7 +104,7 @@ uba_read(t_addr addr, int ctl, uint64 *data, int access)
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
continue;
if (ctl == dibp->uba_ctl &&
if (ctl == dibp->uba_ctl &&
dibp->uba_addr == (addr & (~dibp->uba_mask))) {
uint16 buf;
int r = dibp->rd_io(dptr, addr, &buf, access);
@ -154,7 +154,7 @@ uba_write(t_addr addr, int ctl, uint64 data, int access)
uint32 map = (uint32)(data & 03777) << 9;
map |= (uint32)(data & 0740000) << 13;
uba_map[ubm][addr & 077] = map;
sim_debug(DEBUG_EXP, &cpu_dev, "Wr MAP %02o %012llo %06o\n",
sim_debug(DEBUG_EXP, &cpu_dev, "Wr MAP %02o %012llo %06o\n",
addr & 077, data, map);
return 0;
} else if ((addr & 077) == 0) {
@ -167,10 +167,13 @@ uba_write(t_addr addr, int ctl, uint64 data, int access)
continue;
if (ctl == dibp->uba_ctl && dptr->reset != NULL)
(void)(dptr->reset)(dptr);
if (ctl == dibp->uba_ctl)
dibp->uba_irq_pend = 0;
}
clr_interrupt(ctl<<2);
}
for (i = 0; i < 128; i++) {
if ((uba_irq_ctlr[i] & VECT_CTR) == ctl) {
uba_irq_ctlr[i] = 0;
clr_interrupt(i << 2);
}
}
uba_status[ubm] |= (uint32)(0277 & data);
return 0;
@ -243,12 +246,12 @@ uba_read_npr_byte(t_addr addr, uint16 ctl, uint8 *data)
return 0;
addr = (map & PAGE_MASK) | (addr >> 2) & 0777;
wd = M[addr];
sim_debug(DEBUG_DATA, &cpu_dev, "RD NPR B %08o %08o %012llo ", oaddr, addr, wd);
sim_debug(DEBUG_DATA, &kmc_dev, "RD NPR B %08o %08o %012llo ", oaddr, addr, wd);
if ((oaddr & 02) == 0)
wd >>= 18;
if ((oaddr & 01))
wd >>= 8;
sim_debug(DEBUG_DATA, &cpu_dev, "%03llo ", wd & 0377);
sim_debug(DEBUG_DATA, &kmc_dev, "%03llo\n", wd & 0377);
*data = (uint8)(wd & 0377);
return 1;
}
@ -270,6 +273,7 @@ uba_write_npr_byte(t_addr addr, uint16 ctl, uint8 data)
msk = 0377;
buf = (uint64)(data & msk);
wd = M[addr];
sim_debug(DEBUG_DATA, &kmc_dev, "WR NPR B %08o %08o %012llo ", oaddr, addr, wd);
if ((oaddr & 02) == 0) {
buf <<= 18;
msk <<= 18;
@ -281,6 +285,7 @@ uba_write_npr_byte(t_addr addr, uint16 ctl, uint8 data)
wd &= ~msk;
wd |= buf;
M[addr] = wd;
sim_debug(DEBUG_DATA, &kmc_dev, "%012llo\n", wd);
return 1;
}
@ -333,26 +338,31 @@ uba_write_npr_word(t_addr addr, uint16 ctl, uint16 data)
}
void
uba_set_irq(DIB *dibp)
uba_set_irq(DIB *dibp, int vect)
{
int ubm = uba_device[dibp->uba_ctl];
int pi;
int flg;
if (ubm < 0)
return;
/* Figure out what channel device should IRQ on */
if (dibp->uba_br > 5) {
pi = uba_status[ubm] >> 3;
flg = VECT_H;
} else {
pi = uba_status[ubm];
flg = VECT_L;
}
sim_debug(DEBUG_IRQ, &cpu_dev, "set uba irq %06o %03o %o pi=%o\n",
dibp->uba_addr, vect, dibp->uba_br, pi);
/* Save in device temp the irq value */
dibp->uba_irq_pend = 0200 >> (pi & 07);
set_interrupt(dibp->uba_ctl<<2, pi);
set_interrupt(vect, pi);
uba_irq_ctlr[vect >> 2] = flg | dibp->uba_ctl;
}
void
uba_clr_irq(DIB *idev)
uba_clr_irq(DIB *idev, int vect)
{
DEVICE *dptr;
int ubm = uba_device[idev->uba_ctl];
@ -361,35 +371,13 @@ uba_clr_irq(DIB *idev)
int j;
int lvl;
int high = 0;
if (ubm < 0)
return;
/* Figure out what channel device should IRQ on */
if (idev->uba_br > 5) {
pi = uba_status[ubm] >> 3;
} else {
pi = uba_status[ubm];
}
/* Save in device temp the irq value */
idev->uba_irq_pend = 0;
clr_interrupt(idev->uba_ctl<<2);
for(i = 0; (dptr = sim_devices[i]) != NULL; i++) {
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
continue;
/* If device is pending on this level save */
if (dibp->uba_ctl == idev->uba_ctl &&
dibp->uba_irq_pend != 0) {
lvl = 0;
for (j = 0200; j != 0; j>>=1) {
/* At least one, no need to continue */
if ((dibp->uba_irq_pend & j) != 0) {
set_interrupt(dibp->uba_ctl<<2, pi);
return;
}
}
}
}
sim_debug(DEBUG_IRQ, &cpu_dev, "clr uba irq %06o %03o %o\n",
idev->uba_addr, vect, idev->uba_br);
clr_interrupt(vect);
uba_irq_ctlr[vect >> 2] = 0;
}
void
@ -406,70 +394,27 @@ uba_reset()
uba_status[0] = 0;
uba_status[1] = 0;
for(i = 0; (dptr = sim_devices[i]) != NULL; i++) {
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
continue;
/* Clear any pending interrupt */
dibp->uba_irq_pend = 0;
}
for (i = 0; i < 128; i++)
uba_irq_ctlr[i] = 0;
}
t_addr
uba_get_vect(t_addr addr, int lvl, int *dev, int *new_lvl)
uba_get_vect(t_addr addr, int lvl, int dev)
{
DEVICE *dptr;
DIB *idev = NULL;
uint64 buffer;
uint16 ivect;
int i;
int ctl = 17;
int pi;
int ubm;
*dev = 0; /* Adaptor 0 is special */
/* Look for device */
for(i = 0; (dptr = sim_devices[i]) != NULL; i++) {
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
continue;
/* If device is pending on this level save */
if ((dibp->uba_irq_pend & lvl) != 0) {
/* But only if it is highest UBA */
if (dibp->uba_ctl < ctl) {
ctl = dibp->uba_ctl;
idev = dibp;
}
}
}
/* Should have a device */
if (idev != NULL) {
*new_lvl = 0;
*dev = idev->uba_ctl;
/* Figure out what pi channel this will interrupt on */
ubm = uba_device[idev->uba_ctl];
/* Clear interrupts */
idev->uba_irq_pend = 0;
/* Fetch vector */
if (Mem_read_word(0100 | idev->uba_ctl, &buffer, 1))
ubm = uba_irq_ctlr[dev];
if (ubm != 0) {
/* Fetch vector base */
ubm &= VECT_CTR;
if (Mem_read_word(0100 | ubm, &buffer, 1))
return addr;
idev->uba_irq_pend = 0;
ivect = idev->uba_vect;
if (idev->irqv != NULL)
ivect = (idev->irqv)(idev);
addr = (buffer + (ivect >> 2)) & RMASK;
/* Any other devices waiting on this PI channel? */
for(pi = i = 0; (dptr = sim_devices[i]) != NULL; i++) {
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
continue;
/* If device is pending on this level save */
if (dibp->uba_ctl == idev->uba_ctl &&
dibp->uba_irq_pend != 0) {
/* At least one, no need to continue */
*new_lvl |= dibp->uba_irq_pend;
}
}
/* Compute unibus vector */
addr = (buffer + dev) & RMASK;
sim_debug(DEBUG_IRQ, &cpu_dev, "get_vect d=%03o l=%03o ir=%02o v=%012llo\n",
dev << 2, lvl, uba_irq_ctlr[dev], buffer);
uba_irq_ctlr[dev] = 0;
}
return addr;
}

View File

@ -184,6 +184,7 @@ int t20_page; /* Tops 20 paging selected */
int ptr_flg; /* Access to pointer value */
int extend = 0; /* Process extended instruction */
int fe_xct = 0; /* Execute instruction at address */
int pi_vect; /* Last pi location used for IRQ */
#elif KL
int pi_vect; /* Last pi location used for IRQ */
int ext_ac; /* Extended instruction AC */
@ -725,11 +726,7 @@ DEVICE cpu_dev = {
#else
#define QSLAVE 0
#endif
#if KS
#define MAX_DEV 16
#else
#define MAX_DEV 128
#endif
#if KL
struct _byte {
@ -825,11 +822,7 @@ get_quantum()
void set_interrupt(int dev, int lvl) {
lvl &= 07;
if (lvl) {
#if KS
dev_irq[dev>>2] |= 0200 >> lvl;
#else
dev_irq[dev>>2] = 0200 >> lvl;
#endif
pi_pending = 1;
#if DEBUG
sim_debug(DEBUG_IRQ, &cpu_dev, "set irq %o %o %03o %03o %03o\n",
@ -4641,18 +4634,18 @@ st_pi:
AB |= eb_ptr;
extend = 0;
if ((dev_irq[0] & pi_mask) == 0) {
int new_lvl;
int dev;
AB = uba_get_vect(AB, pi_mask, &dev, &new_lvl);
if (dev != 0) {
dev_irq[dev] = new_lvl;
if (new_lvl != 0)
pi_pending = 1;
}
for (f = 1; f < MAX_DEV; f++) {
if (dev_irq[f] & pi_mask) {
AB = uba_get_vect(AB, pi_mask, f);
dev_irq[f] = 0;
break;
}
#if DEBUG
sim_debug(DEBUG_IRQ, &cpu_dev, "vect irq %o %06o\n", pi_enc, AB);
sim_debug(DEBUG_IRQ, &cpu_dev, "vect irq %o %06o\n", pi_enc, AB);
#endif
}
}
pi_vect = AB;
goto fetch;
#endif
#if KI | KL
@ -12038,7 +12031,7 @@ fprintf(stderr, "PIH = %03o\n\r", PIH);
if ((!pi_hold) & f_inst_fetch) {
pi_cycle = 0;
} else {
#if KL
#if KL | KS
AB = pi_vect | pi_ov;
#else
AB = 040 | (pi_enc << 1) | maoff | pi_ov;
@ -12056,7 +12049,7 @@ fprintf(stderr, "PIH = %03o\n\r", PIH);
if ((IR & 0700) == 0700) {
(void)check_irq_level();
}
#if KL
#if KL | KS
AB = pi_vect | pi_ov;
#else
AB = 040 | (pi_enc << 1) | maoff | pi_ov;

View File

@ -580,9 +580,9 @@ int uba_read_npr_byte(t_addr addr, uint16 ctl, uint8 *data);
int uba_write_npr_byte(t_addr addr, uint16 ctl, uint8 data);
int uba_read_npr_word(t_addr addr, uint16 ctl, uint16 *data);
int uba_write_npr_word(t_addr addr, uint16 ctl, uint16 data);
void uba_set_irq(DIB *dibp);
void uba_clr_irq(DIB *dibp);
t_addr uba_get_vect(t_addr addr, int lvl, int *dev, int *new_lvl);
void uba_set_irq(DIB *dibp, int vect);
void uba_clr_irq(DIB *dibp, int vect);
t_addr uba_get_vect(t_addr addr, int lvl, int dev);
void uba_set_parity(uint16 ctl);
uint16 uba_rh_vect(struct pdp_dib *dibp);
int uba_rh_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access);

View File

@ -84,10 +84,8 @@
/* Bits in STATUS */
#define IMPID 010 /* Input done. */
#define IMPI32 020 /* Input in 32 bit mode. */
#define IMPIB 040 /* Input busy. */
#define IMPOD 0100 /* Output done. */
#define IMPO32 0200 /* Output in 32-bit mode. */
#define IMPOB 0400 /* Output busy. */
#define IMPERR 01000 /* IMP error. */
#define IMPR 02000 /* IMP ready. */
@ -564,7 +562,7 @@ UNIT imp_unit[] = {
};
#if KS
DIB imp_dib = {0767600, 017, 0250, 6, 3, &imp_rd, &imp_wr, &imp_vect, 0, 0};
DIB imp_dib = {0767600, 017, 0250, 6, 3, &imp_rd, &imp_wr, 0, 0, 0};
#else
DIB imp_dib = {IMP_DEVNUM, 1, &imp_devio,
#if KL
@ -668,22 +666,12 @@ DEVICE imp_dev = {
#if KS
static void check_interrupts (UNIT *uptr)
{
DEVICE *dptr = find_dev_from_unit (uptr);
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
int irq = 0;
DEVICE *dptr = &imp_dev;
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
if (imp_icsr & CSR_IE) {
if (imp_icsr & CSR_RDY)
irq = 1;
if ((uptr->STATUS & IMPID) != 0 && imp_icsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect);
}
if (imp_ocsr & CSR_IE) {
if (imp_ocsr & CSR_RDY)
irq = 1;
}
if (irq)
uba_set_irq(dibp);
else
uba_clr_irq(dibp);
}
int
@ -708,7 +696,7 @@ imp_wr(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
imp_icsr = CSR_INR|CSR_RDY;
imp_iba = 0;
imp_iwcnt = 0;
uba_clr_irq(dibp);
uba_clr_irq(dibp, dibp->uba_vect);
}
data &= (CSR_GO|CSR_RST|CSR_UBA|CSR_IE|CSR_HRC|CSR_SE);
imp_icsr &= ~(CSR_GO|CSR_RST|CSR_UBA|CSR_IE|CSR_HRC|CSR_SE|CSR_ERR
@ -722,7 +710,8 @@ imp_wr(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
}
if (data & CSR_GO) {
imp_icsr &= ~CSR_RDY;
uptr->STATUS &= ~IMPID;
uptr->STATUS &= ~(IMPID|IMPLW);
uba_clr_irq(dibp, dibp->uba_vect);
}
sim_debug(DEBUG_DETAIL, dptr, "IMP11 icsr %06o\n", imp_icsr);
break;
@ -739,6 +728,7 @@ imp_wr(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
case 004: /* Input Bus Address */
imp_iba = (data & 0177777);
imp_icsr &= ~(CSR_ERR);
break;
case 006: /* Input Word Count */
@ -756,7 +746,7 @@ imp_wr(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
imp_ocsr |= CSR_RDY;
imp_oba = 0;
imp_owcnt = 0;
uba_clr_irq(dibp);
uba_clr_irq(dibp, dibp->uba_vect + 4);
}
data &= (CSR_GO|CSR_RST|CSR_UBA|CSR_IE|CSR_BB|CSR_ELB);
imp_ocsr &= ~(CSR_GO|CSR_RST|CSR_UBA|CSR_IE|CSR_BB|CSR_ELB|CSR_ERR
@ -764,7 +754,8 @@ imp_wr(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
imp_ocsr |= data;
if (data & CSR_GO) {
imp_ocsr &= ~CSR_RDY;
uptr->STATUS &= ~IMPOD;
uptr->STATUS &= ~(IMPOD);
uba_clr_irq(dibp, dibp->uba_vect + 4);
}
sim_debug(DEBUG_DETAIL, dptr, "IMP11 ocsr %06o\n", imp_ocsr);
break;
@ -781,13 +772,13 @@ imp_wr(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
case 014: /* Output Bus Address */
imp_oba = (data & 0177777);
imp_ocsr &= ~(CSR_ERR);
break;
case 016: /* Output Word Count */
imp_owcnt = (data & 0177777);
break;
}
check_interrupts (uptr);
if (imp_ocsr & CSR_GO || imp_icsr & CSR_GO)
sim_activate(uptr, 100);
return 0;
@ -806,6 +797,8 @@ imp_rd(DEVICE *dptr, t_addr addr, uint16 *data, int32 access)
*data = imp_icsr;
if ((uptr->STATUS & (IMPID)) != 0)
*data |= CSR_IBF;
if ((uptr->STATUS & (IMPLW)) != 0)
*data |= CSR_EOM;
break;
case 002: /* Input Data Buffer */
*data = imp_idb;
@ -843,19 +836,6 @@ imp_rd(DEVICE *dptr, t_addr addr, uint16 *data, int32 access)
}
uint16
imp_vect(struct pdp_dib *dibp)
{
uint16 vect = dibp->uba_vect;
if (imp_unit[0].STATUS & IMPID && (imp_unit[0].STATUS & IMPLW) == 0)
return vect;
if (imp_unit[0].STATUS & IMPOD)
return vect+4;
return 0;
}
#else
static void check_interrupts (UNIT *uptr)
{
@ -1046,7 +1026,9 @@ t_stat imp_srv(UNIT * uptr)
imp_ocsr |= CSR_NXM;
imp_ocsr &= ~CSR_GO;
uptr->STATUS |= IMPOD;
check_interrupts (uptr);
if (imp_ocsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect + 4);
}
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP out npr failed\n");
return SCPE_OK;
}
@ -1062,7 +1044,9 @@ t_stat imp_srv(UNIT * uptr)
imp_ocsr |= CSR_NXM;
imp_ocsr &= ~CSR_GO;
uptr->STATUS |= IMPOD;
check_interrupts (uptr);
if (imp_ocsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect + 4);
}
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP out npr failed\n");
return SCPE_OK;
}
@ -1086,7 +1070,9 @@ t_stat imp_srv(UNIT * uptr)
imp_ocsr |= CSR_ERR;
imp_ocsr &= ~CSR_GO;
uptr->STATUS |= IMPOD;
check_interrupts (uptr);
if (imp_ocsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect + 4);
}
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP oba overflow\n");
return SCPE_OK;
}
@ -1094,6 +1080,9 @@ t_stat imp_srv(UNIT * uptr)
imp_ocsr |= CSR_RDY;
imp_ocsr &= ~CSR_GO;
uptr->STATUS |= IMPOD;
if (imp_ocsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect + 4);
}
if (imp_ocsr & CSR_ELB) {
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP send\n");
@ -1102,7 +1091,6 @@ t_stat imp_srv(UNIT * uptr)
memset(imp_data.sbuffer, 0, ETH_FRAME_SIZE);
uptr->OPOS = 0;
}
check_interrupts (uptr);
}
}
if (uptr->STATUS & IMPIB && imp_icsr & CSR_GO) {
@ -1111,7 +1099,9 @@ t_stat imp_srv(UNIT * uptr)
imp_icsr |= CSR_ERR;
imp_icsr &= ~CSR_GO;
uptr->STATUS |= IMPID;
check_interrupts (uptr);
if (imp_icsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect);
}
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP oba overflow\n");
return SCPE_OK;
}
@ -1125,7 +1115,9 @@ t_stat imp_srv(UNIT * uptr)
imp_icsr |= CSR_NXM;
imp_icsr &= ~CSR_GO;
uptr->STATUS |= IMPID;
check_interrupts (uptr);
if (imp_icsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect);
}
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP in npr failed\n");
return SCPE_OK;
}
@ -1144,8 +1136,10 @@ t_stat imp_srv(UNIT * uptr)
if (uba_write_npr(pa, dibp->uba_ctl, wd64) == 0) {
imp_ocsr |= CSR_NXM;
imp_ocsr &= ~CSR_GO;
uptr->STATUS |= IMPOD;
check_interrupts (uptr);
uptr->STATUS |= IMPID;
if (imp_icsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect);
}
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP out npr failed\n");
return SCPE_OK;
}
@ -1158,18 +1152,23 @@ t_stat imp_srv(UNIT * uptr)
imp_iba += 2;
imp_iwcnt++;
if (uptr->IPOS > uptr->ILEN) {
imp_icsr |= CSR_EOM|CSR_RDY;
imp_icsr &= ~CSR_GO;
uptr->STATUS |= IMPID;
uptr->STATUS &= ~IMPIB;
uptr->ILEN = 0;
imp_icsr |= CSR_EOM|CSR_RDY;
imp_icsr &= ~CSR_GO;
uptr->STATUS |= IMPID|IMPLW;
uptr->STATUS &= ~IMPIB;
if (imp_icsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect);
}
uptr->ILEN = 0;
}
if (imp_iwcnt == 0) {
imp_icsr |= CSR_RDY;
imp_icsr &= ~CSR_GO;
uptr->STATUS |= IMPID;
}
check_interrupts (uptr);
if (imp_icsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect);
}
}
}
if (imp_ocsr & CSR_GO || imp_icsr & CSR_GO)
sim_activate(uptr, 100);

View File

@ -230,7 +230,7 @@ uba_rh_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access) {
if ((rhc->status & BUSY) == 0)
rhc->cda = ((data << 8) & 0600000) | (rhc->cda & 0177777);
if ((data & CS1_GO) != 0 || (rhc->cs1 & CS1_IE) == 0)
uba_clr_irq(rhc->dib);
uba_clr_irq(rhc->dib, rhc->dib->uba_vect);
if ((data & CS1_GO) != 0 && (rhc->status & BUSY) != 0 && GET_FNC(data) >= FNC_XFER) {
rhc->cs2 |= CS2_PGE;
break;
@ -829,7 +829,7 @@ void rh_setattn(struct rh_if *rhc, int unit)
rhc->attn |= 1<<unit;
#if KS
if ((rhc->status & BUSY) == 0 && (rhc->cs1 & CS1_IE) != 0)
uba_set_irq(rhc->dib);
uba_set_irq(rhc->dib, rhc->dib->uba_vect);
#else
if ((rhc->status & BUSY) == 0 && (rhc->status & IADR_ATTN) != 0)
set_interrupt(rhc->devnum, rhc->status);
@ -864,7 +864,7 @@ void rh_setirq(struct rh_if *rhc) {
rhc->status |= PI_ENABLE;
#if KS
if ((rhc->status & BUSY) == 0 && (rhc->cs1 & CS1_IE) != 0)
uba_set_irq(rhc->dib);
uba_set_irq(rhc->dib, rhc->dib->uba_vect);
#else
set_interrupt(rhc->devnum, rhc->status);
#endif

View File

@ -329,7 +329,7 @@ struct rh_if rp_rh[NUM_DEVS_RP] = {
};
DIB rp_dib[] = {
{0776700, 077, 0254, 6, 1, &uba_rh_read, &uba_rh_write, &uba_rh_vect, 0, &rp_rh[0]},
{0776700, 077, 0254, 6, 1, &uba_rh_read, &uba_rh_write, 0, 0, &rp_rh[0]},
};
#else
struct rh_if rp_rh[NUM_DEVS_RP] = {

View File

@ -198,7 +198,7 @@ struct rh_if tu_rh[NUM_DEVS_TU] = {
};
DIB tu_dib[NUM_DEVS_TU] = {
{0772440, 037, 0224, 6, 3, &uba_rh_read, &uba_rh_write, &uba_rh_vect, 0, &tu_rh[0]},
{0772440, 037, 0224, 6, 3, &uba_rh_read, &uba_rh_write, 0, 0, &tu_rh[0]},
};
#else
struct rh_if tu_rh[NUM_DEVS_TU] = {