From 531cdd42f7671bbf120fb024ac685b0df395de05 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 3 Jun 2013 10:03:46 -0700 Subject: [PATCH] Refactored (and renamed) pdp11_kdp to leverage the pdp11_dup dup implementation. --- PDP10/pdp10_defs.h | 24 +- PDP10/pdp10_ksio.c | 10 +- PDP10/pdp10_sys.c | 4 +- PDP11/pdp11_defs.h | 8 +- PDP11/pdp11_dup.c | 255 ++--- PDP11/pdp11_dup.h | 2 +- PDP11/pdp11_kdp.c | 1335 --------------------------- PDP11/pdp11_kdp.h | 24 - PDP11/pdp11_kmc.c | 971 +++++++++++++++++++ PDP11/pdp11_sys.c | 2 +- Visual Studio Projects/PDP10.vcproj | 8 + Visual Studio Projects/PDP11.vcproj | 12 +- descrip.mms | 5 +- makefile | 4 +- 14 files changed, 1140 insertions(+), 1524 deletions(-) delete mode 100644 PDP11/pdp11_kdp.c delete mode 100644 PDP11/pdp11_kdp.h create mode 100644 PDP11/pdp11_kmc.c diff --git a/PDP10/pdp10_defs.h b/PDP10/pdp10_defs.h index 2798b589..fb18a1f5 100644 --- a/PDP10/pdp10_defs.h +++ b/PDP10/pdp10_defs.h @@ -660,8 +660,6 @@ typedef struct pdp_dib DIB; #define IOLN_UBMNT3 001 #define IOBA_XU (IO_UBA3 + 0774510) /* DEUNA/DELUA */ #define IOLN_XU 010 -#define IOBA_DMR (IO_UBA3 + 0764000) /* DMR11 */ -#define IOLN_DMR 010 #define IOBA_CR (IO_UBA3 + 0777160) /* CD/CR/CM */ #define IOLN_CR 010 #define IOBA_RY (IO_UBA3 + 0777170) /* RX211 */ @@ -700,13 +698,8 @@ typedef struct pdp_dib DIB; #define INT_V_RP 6 /* RH11/RP,RM drives */ #define INT_V_TU 7 /* RH11/TM03/TU45 */ -#define INT_V_KMCA 8 /* KMC11 */ +#define INT_V_KMCA 8 /* KMC11 */ #define INT_V_KMCB 9 -#define INT_V_DMRA 10 /* DMR11 */ -#define INT_V_DMRB 11 -#define INT_V_DMCRX 13 -#define INT_V_DMCTX 14 -#define INT_V_XU 15 /* DEUNA/DELUA */ #define INT_V_DZRX 16 /* DZ11 */ #define INT_V_DZTX 17 #define INT_V_RY 18 /* RX211 */ @@ -714,7 +707,6 @@ typedef struct pdp_dib DIB; #define INT_V_PTP 25 #define INT_V_LP20 26 /* LPT20 */ #define INT_V_CR 27 /* CD20 (CD11) */ -#define INT_V_CR 27 /* CD20 (CD11) */ #define INT_V_DUPRX 28 /* DUP11 */ #define INT_V_DUPTX 29 @@ -722,10 +714,6 @@ typedef struct pdp_dib DIB; #define INT_TU (1u << INT_V_TU) #define INT_KMCA (1u << INT_V_KMCA) #define INT_KMCB (1u << INT_V_KMCB) -#define INT_DMRA (1u << INT_V_DMRA) -#define INT_DMRB (1u << INT_V_DMRB) -#define INT_DMCRX (1u << INT_V_DMCRX) -#define INT_DMCTX (1u << INT_V_DMCTX) #define INT_XU (1u << INT_V_XU) #define INT_DZRX (1u << INT_V_DZRX) #define INT_DZTX (1u << INT_V_DZTX) @@ -741,10 +729,6 @@ typedef struct pdp_dib DIB; #define IPL_TU 6 #define IPL_KMCA 5 #define IPL_KMCB 5 -#define IPL_DMRA 5 -#define IPL_DMRB 5 -#define IPL_DMCRX 5 -#define IPL_DMCTX 5 #define IPL_XU 5 #define IPL_DZRX 5 #define IPL_DZTX 5 @@ -772,12 +756,6 @@ typedef struct pdp_dib DIB; #define VEC_CR 0230 #define VEC_RP 0254 #define VEC_RY 0264 -#define VEC_DZRX 0340 -#define VEC_DZTX 0344 -#define VEC_KMCA 0540 -#define VEC_KMCB 0544 -#define VEC_DMRA 0610 -#define VEC_DMRB 0614 #define VEC_LP20 0754 #define VEC_AUTO 0 /* Set by Auto Configure */ diff --git a/PDP10/pdp10_ksio.c b/PDP10/pdp10_ksio.c index 3743d262..ba9e8b90 100644 --- a/PDP10/pdp10_ksio.c +++ b/PDP10/pdp10_ksio.c @@ -856,7 +856,7 @@ DIB *dibp; for (i = 0; i < 32; i++) { /* clear intr tables */ int_vec[i] = 0; int_ack[i] = NULL; - } + } for (i = j = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ @@ -961,12 +961,10 @@ AUTO_CON auto_tab[] = {/*c #v am vm fxa fxv */ {0017550}, {0070} }, /* PC11 reader - fx CSR, fx VEC */ { { "PTP" }, 1, 1, 0, 0, {0017554}, {0074} }, /* PC11 punch - fx CSR, fx VEC */ + { { "DUP" }, 1, 2, 0, 0, + {0000300}, {0300} }, /* DUP11 bit sync - fx CSR, fx VEC */ { { "KMC" }, 1, 2, 0, 0, - {0000540}, {0540} }, /* KMC11 - fx CSR, fx VEC */ - { { "DUP0" }, 1, 2, 0, 0, - {0000300}, {0300} }, /* DUP11 sync - fx CSR, fx VEC */ - { { "DUP1" }, 1, 2, 0, 0, - {0000310}, {0310} }, /* DUP11 sync - fx CSR, fx VEC */ + {0000540}, {0540} }, /* KMC11 comm - fx CSR, fx VEC */ #else { { "QBA" }, 1, 0, 0, 0, {017500} }, /* doorbell - fx CSR, no VEC */ diff --git a/PDP10/pdp10_sys.c b/PDP10/pdp10_sys.c index e6f4ede4..48748f5a 100644 --- a/PDP10/pdp10_sys.c +++ b/PDP10/pdp10_sys.c @@ -55,8 +55,8 @@ extern DEVICE dz_dev; extern DEVICE ry_dev; extern DEVICE cr_dev; extern DEVICE lp20_dev; -extern DEVICE kmc_dev; extern DEVICE dup_dev; +extern DEVICE kmc_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern d10 *M; @@ -92,8 +92,8 @@ DEVICE *sim_devices[] = { &rp_dev, &tu_dev, &dz_dev, - &kmc_dev, &dup_dev, + &kmc_dev, NULL }; diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index bc554fab..e1eecd2f 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -600,10 +600,10 @@ typedef struct pdp_dib DIB; #define INT_V_RC 17 #define INT_V_DMCRX 18 #define INT_V_DMCTX 19 -#define INT_V_KMCA 20 -#define INT_V_KMCB 21 -#define INT_V_DUPRX 20 -#define INT_V_DUPTX 21 +#define INT_V_KMCA 20 +#define INT_V_KMCB 21 +#define INT_V_DUPRX 22 +#define INT_V_DUPTX 23 #define INT_V_PIR4 0 /* BR4 */ #define INT_V_TTI 1 diff --git a/PDP11/pdp11_dup.c b/PDP11/pdp11_dup.c index 6c6a6102..ea933d1f 100644 --- a/PDP11/pdp11_dup.c +++ b/PDP11/pdp11_dup.c @@ -65,57 +65,57 @@ extern int32 tmxr_poll; /* calibrated delay */ extern int32 clk_tps; /* clock ticks per second */ extern int32 tmr_poll; /* instructions per tick */ -uint16 dup_rxcsr[DUP_LINES]; -uint16 dup_rxdbuf[DUP_LINES]; -uint16 dup_parcsr[DUP_LINES]; -uint16 dup_txcsr[DUP_LINES]; -uint16 dup_txdbuf[DUP_LINES]; -uint32 dup_rxi = 0; /* rcv interrupts */ -uint32 dup_txi = 0; /* xmt interrupts */ -uint32 dup_wait[DUP_LINES]; /* rcv/xmt byte delay */ -uint32 dup_speed[DUP_LINES]; /* line speed (bits/sec) */ -uint8 *dup_rcvpacket[DUP_LINES]; /* rcv buffer */ -uint16 dup_rcvpksize[DUP_LINES]; /* rcv buffer size */ -uint16 dup_rcvpkoffset[DUP_LINES]; /* rcv buffer offset */ -uint16 dup_rcvpkinoff[DUP_LINES]; /* rcv packet in offset */ -uint8 *dup_xmtpacket[DUP_LINES]; /* xmt buffer */ -uint16 dup_xmtpksize[DUP_LINES]; /* xmt buffer size */ -uint16 dup_xmtpkoffset[DUP_LINES]; /* xmt buffer offset */ -uint16 dup_xmtpkoutoff[DUP_LINES]; /* xmt packet out offset */ -t_bool dup_xmtpkrdy[DUP_LINES]; /* xmt packet ready */ +static uint16 dup_rxcsr[DUP_LINES]; +static uint16 dup_rxdbuf[DUP_LINES]; +static uint16 dup_parcsr[DUP_LINES]; +static uint16 dup_txcsr[DUP_LINES]; +static uint16 dup_txdbuf[DUP_LINES]; +static uint32 dup_rxi = 0; /* rcv interrupts */ +static uint32 dup_txi = 0; /* xmt interrupts */ +static uint32 dup_wait[DUP_LINES]; /* rcv/xmt byte delay */ +static uint32 dup_speed[DUP_LINES]; /* line speed (bits/sec) */ +static uint8 *dup_rcvpacket[DUP_LINES]; /* rcv buffer */ +static uint16 dup_rcvpksize[DUP_LINES]; /* rcv buffer size */ +static uint16 dup_rcvpkoffset[DUP_LINES]; /* rcv buffer offset */ +static uint16 dup_rcvpkinoff[DUP_LINES]; /* rcv packet in offset */ +static uint8 *dup_xmtpacket[DUP_LINES]; /* xmt buffer */ +static uint16 dup_xmtpksize[DUP_LINES]; /* xmt buffer size */ +static uint16 dup_xmtpkoffset[DUP_LINES]; /* xmt buffer offset */ +static uint16 dup_xmtpkoutoff[DUP_LINES]; /* xmt packet out offset */ +static t_bool dup_xmtpkrdy[DUP_LINES]; /* xmt packet ready */ -PACKET_RECEIVE_CALLBACK dup_rcv_packet_callback[DUP_LINES]; -PACKET_TRANSMIT_COMPLETE_CALLBACK dup_xmt_complete_callback[DUP_LINES]; +static PACKET_RECEIVE_CALLBACK dup_rcv_packet_callback[DUP_LINES]; +static PACKET_TRANSMIT_COMPLETE_CALLBACK dup_xmt_complete_callback[DUP_LINES]; -t_stat dup_rd (int32 *data, int32 PA, int32 access); -t_stat dup_wr (int32 data, int32 PA, int32 access); -t_stat dup_set_modem (int32 dup, int32 rxcsr_bits); -t_stat dup_get_modem (int32 dup); -t_stat dup_svc (UNIT *uptr); -t_stat dup_poll_svc (UNIT *uptr); -t_stat dup_rcv_byte (int32 dup); -t_stat dup_reset (DEVICE *dptr); -t_stat dup_attach (UNIT *uptr, char *ptr); -t_stat dup_detach (UNIT *uptr); -t_stat dup_clear (int32 dup, t_bool flag); -int32 dup_rxinta (void); -int32 dup_txinta (void); -void dup_update_rcvi (void); -void dup_update_xmti (void); -void dup_clr_rxint (int32 dup); -void dup_set_rxint (int32 dup); -void dup_clr_txint (int32 dup); -void dup_set_txint (int32 dup); -t_stat dup_setnl (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat dup_setspeed (UNIT* uptr, int32 val, char* cptr, void* desc); -t_stat dup_showspeed (FILE* st, UNIT* uptr, int32 val, void* desc); -t_stat dup_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); -t_stat dup_help_attach (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); -char *dup_description (DEVICE *dptr); +static t_stat dup_rd (int32 *data, int32 PA, int32 access); +static t_stat dup_wr (int32 data, int32 PA, int32 access); +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); +static t_stat dup_poll_svc (UNIT *uptr); +static t_stat dup_rcv_byte (int32 dup); +static t_stat dup_reset (DEVICE *dptr); +static t_stat dup_attach (UNIT *uptr, char *ptr); +static t_stat dup_detach (UNIT *uptr); +static t_stat dup_clear (int32 dup, t_bool flag); +static int32 dup_rxinta (void); +static int32 dup_txinta (void); +static void dup_update_rcvi (void); +static void dup_update_xmti (void); +static void dup_clr_rxint (int32 dup); +static void dup_set_rxint (int32 dup); +static void dup_clr_txint (int32 dup); +static void dup_set_txint (int32 dup); +static t_stat dup_setnl (UNIT *uptr, int32 val, char *cptr, void *desc); +static t_stat dup_setspeed (UNIT* uptr, int32 val, char* cptr, void* desc); +static t_stat dup_showspeed (FILE* st, UNIT* uptr, int32 val, void* desc); +static t_stat dup_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +static t_stat dup_help_attach (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +static char *dup_description (DEVICE *dptr); /* RXCSR - 16XXX0 - receiver control/status register */ -BITFIELD dup_rxcsr_bits[] = { +static BITFIELD dup_rxcsr_bits[] = { BIT(BDATSET), /* Data Set Change B */ #define RXCSR_V_BDATSET 0 #define RXCSR_M_BDATSET (1<> 1) & 03], (uint32)(orig_val), (u return SCPE_OK; } -t_stat dup_wr (int32 data, int32 PA, int32 access) +static t_stat dup_wr (int32 data, int32 PA, int32 access) { static BITFIELD* bitdefs[] = {dup_rxcsr_bits, dup_parcsr_bits, dup_txcsr_bits, dup_txdbuf_bits}; static uint16 *regs[] = {dup_rxcsr, dup_parcsr, dup_txcsr, dup_txdbuf}; @@ -579,7 +579,7 @@ sim_debug_bits(DBG_REG, DUPDPTR, bitdefs[(PA >> 1) & 03], (uint32)orig_val, (uin return SCPE_OK; } -t_stat dup_set_modem (int32 dup, int32 rxcsr_bits) +static t_stat dup_set_modem (int32 dup, int32 rxcsr_bits) { int32 bits_to_set, bits_to_clear; @@ -591,7 +591,7 @@ tmxr_set_get_modem_bits (dup_desc.ldsc+dup, bits_to_set, bits_to_clear, NULL); return SCPE_OK; } -t_stat dup_get_modem (int32 dup) +static t_stat dup_get_modem (int32 dup) { int32 modem_bits; int32 old_rxcsr_a_modem_bits, new_rxcsr_a_modem_bits, old_rxcsr_b_modem_bits, new_rxcsr_b_modem_bits; @@ -630,7 +630,7 @@ DEVICE *dptr = DUPDPTR; DIB *dib = (DIB *)dptr->ctxt; CSRPA += IOPAGEBASE; -if ((dib->ba > (uint32)CSRPA) || ((uint32)CSRPA > (dib->ba + dib->lnt))) +if ((dib->ba > (uint32)CSRPA) || ((uint32)CSRPA > (dib->ba + dib->lnt)) || (DUPDPTR->flags & DEV_DIS)) return -1; return ((uint32)CSRPA - dib->ba)/dib->lnt; @@ -638,7 +638,7 @@ return ((uint32)CSRPA - dib->ba)/dib->lnt; void dup_set_callback_mode (int32 dup, PACKET_RECEIVE_CALLBACK receive, PACKET_TRANSMIT_COMPLETE_CALLBACK transmit) { -if ((dup < 0) || (dup >= dup_desc.lines)) +if ((dup < 0) || (dup >= dup_desc.lines) || (DUPDPTR->flags & DEV_DIS)) return; dup_rcv_packet_callback[dup] = receive; dup_xmt_complete_callback[dup] = transmit; @@ -646,29 +646,30 @@ dup_xmt_complete_callback[dup] = transmit; int32 dup_get_line_speed (int32 dup) { -if ((dup < 0) || (dup >= dup_desc.lines)) +if ((dup < 0) || (dup >= dup_desc.lines) || (DUPDPTR->flags & DEV_DIS)) return -1; return dup_speed[dup]; } int32 dup_get_DCD (int32 dup) { -if ((dup < 0) || (dup >= dup_desc.lines)) +if ((dup < 0) || (dup >= dup_desc.lines) || (DUPDPTR->flags & DEV_DIS)) return -1; return (dup_rxcsr[dup] & RXCSR_M_DCD) ? 1 : 0; } t_stat dup_set_DTR (int32 dup, t_bool state) { -if ((dup < 0) || (dup >= dup_desc.lines)) +if ((dup < 0) || (dup >= dup_desc.lines) || (DUPDPTR->flags & DEV_DIS)) return SCPE_IERR; dup_set_modem (dup, state ? (RXCSR_M_DTR | RXCSR_M_RTS) : 0); +dup_ldsc[dup].rcve = state; return SCPE_OK; } t_stat dup_set_DDCMP (int32 dup, t_bool state) { -if ((dup < 0) || (dup >= dup_desc.lines)) +if ((dup < 0) || (dup >= dup_desc.lines) || (DUPDPTR->flags & DEV_DIS)) return SCPE_IERR; dup_rxcsr[dup] &= ~RXCSR_M_STRSYN; @@ -677,37 +678,7 @@ dup_parcsr[dup] &= ~PARCSR_M_NOCRC; dup_parcsr[dup] |= (state ? 0: PARCSR_M_NOCRC); dup_parcsr[dup] &= ~PARCSR_M_DECMODE; dup_parcsr[dup] |= (state ? PARCSR_M_DECMODE : 0); -return SCPE_OK; -} - -t_stat dup_rcv_byte (int32 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_rcvpkoffset[dup]); -if (!(dup_rxcsr[dup] & RXCSR_M_RCVEN) || (dup_rcvpkoffset[dup] == 0) || (dup_rxcsr[dup] & RXCSR_M_RXDONE)) - return SCPE_OK; -if (dup_rcv_packet_callback[dup]) { - dup_rcv_packet_callback[dup](dup, dup_rcvpacket[dup], dup_rcvpkoffset[dup]); - return SCPE_OK; - } -dup_rxcsr[dup] |= RXCSR_M_RXACT; -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) || - (dup_rcvpkinoff[dup] >= dup_rcvpkoffset[dup])) && - (0 == ddcmp_crc16 (0, dup_rcvpacket[dup], dup_rcvpkinoff[dup]))) - dup_rxdbuf[dup] |= RXDBUF_M_RCRCER; -else - dup_rxdbuf[dup] &= ~RXDBUF_M_RCRCER; -if (dup_rcvpkinoff[dup] >= dup_rcvpkoffset[dup]) { - dup_rcvpkinoff[dup] = dup_rcvpkoffset[dup] = 0; - dup_rxcsr[dup] &= ~RXCSR_M_RXACT; - } -if (dup_rxcsr[dup] & RXCSR_M_RXIE) - dup_set_rxint (dup); +dup_rxcsr[dup] |= RXCSR_M_RCVEN; return SCPE_OK; } @@ -715,6 +686,9 @@ t_bool dup_put_msg_bytes (int32 dup, uint8 *bytes, size_t len, t_bool start, t_b { t_bool breturn = FALSE; +if ((dup < 0) || (dup >= dup_desc.lines) || (DUPDPTR->flags & DEV_DIS)) + return FALSE; + if (!dup_xmtpkrdy[dup]) { /* Not Busy sending? */ if (start) dup_xmtpkoffset[dup] = 0; @@ -748,11 +722,50 @@ if (!dup_xmtpkrdy[dup]) { /* Not Busy sending? */ } sim_debug (DBG_TRC, DUPDPTR, "dup_put_msg_bytes(dup=%d, len=%d, start=%s, end=%s) %s\n", dup, len, start ? "TRUE" : "FALSE", end ? "TRUE" : "FALSE", breturn ? "Good" : "Busy"); +if (breturn && dup_xmtpkrdy[dup]) { + ddcmp_packet_trace (DBG_PKT, DUPDPTR, ">>> XMT Packet", dup_xmtpacket[dup], dup_xmtpkoffset[dup], TRUE); + if (dup_xmt_complete_callback[dup]) + dup_svc(dup_units+dup); + } return breturn; } +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, + (dup_rxcsr[dup] & RXCSR_M_RCVEN) ? "enabled" : "disabled", + dup_rcvpkinoff[dup], dup_rcvpkoffset[dup]); +if (!(dup_rxcsr[dup] & RXCSR_M_RCVEN) || (dup_rcvpkoffset[dup] == 0) || (dup_rxcsr[dup] & RXCSR_M_RXDONE)) + return SCPE_OK; +if (dup_rcv_packet_callback[dup]) { + dup_rcv_packet_callback[dup](dup, dup_rcvpacket[dup], dup_rcvpkoffset[dup]); + dup_rcvpkinoff[dup] = dup_rcvpkoffset[dup] = 0; + dup_rxcsr[dup] &= ~RXCSR_M_RXACT; + return SCPE_OK; + } +dup_rxcsr[dup] |= RXCSR_M_RXACT; +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) || + (dup_rcvpkinoff[dup] >= dup_rcvpkoffset[dup])) && + (0 == ddcmp_crc16 (0, dup_rcvpacket[dup], dup_rcvpkinoff[dup]))) + dup_rxdbuf[dup] |= RXDBUF_M_RCRCER; +else + dup_rxdbuf[dup] &= ~RXDBUF_M_RCRCER; +if (dup_rcvpkinoff[dup] >= dup_rcvpkoffset[dup]) { + dup_rcvpkinoff[dup] = dup_rcvpkoffset[dup] = 0; + dup_rxcsr[dup] &= ~RXCSR_M_RXACT; + } +if (dup_rxcsr[dup] & RXCSR_M_RXIE) + dup_set_rxint (dup); +return SCPE_OK; +} + /* service routine to delay device activity */ -t_stat dup_svc (UNIT *uptr) + +static t_stat dup_svc (UNIT *uptr) { DEVICE *dptr = DUPDPTR; int32 dup = (int32)(uptr-dptr->units); @@ -765,10 +778,9 @@ if (!(dup_txcsr[dup] & TXCSR_M_TXDONE) && (!dup_xmtpkrdy[dup])) { dup_put_msg_bytes (dup, &data, (dup_txdbuf[dup] & TXDBUF_M_TEOM) && (dptr == &dup_dev) ? 0 : 1, dup_txdbuf[dup] & TXDBUF_M_TSOM, (dup_txdbuf[dup] & TXDBUF_M_TEOM)); if (dup_xmtpkrdy[dup]) { /* Packet ready to send? */ sim_debug(DBG_TRC, DUPDPTR, "dup_svc(dup=%d) - Packet Done %d bytes\n", dup, dup_xmtpkoffset[dup]); - ddcmp_packet_trace (DBG_PKT, DUPDPTR, ">>> XMT Packet", dup_xmtpacket[dup], dup_xmtpkoffset[dup], TRUE); } } -if (dup_xmtpkrdy[dup] && lp->xmte) { +if (dup_xmtpkrdy[dup] && (lp->xmte || (!lp->conn))) { t_stat st = SCPE_OK; while ((st == SCPE_OK) && (dup_xmtpkoutoff[dup] < dup_xmtpkoffset[dup])) { @@ -802,7 +814,7 @@ if (dup_rxcsr[dup] & RXCSR_M_RXACT) return SCPE_OK; } -t_stat dup_poll_svc (UNIT *uptr) +static t_stat dup_poll_svc (UNIT *uptr) { int32 dup, active, attached, c; @@ -839,7 +851,8 @@ for (dup=active=attached=0; dup < dup_desc.lines; dup++) { dup_rcvpkoffset[dup] += 1; if (dup_rcvpkoffset[dup] == 1) { /* Validate first byte in packet */ if ((dup_rxcsr[dup] & RXCSR_M_STRSYN) && - (dup_rcvpacket[dup][0] == (dup_parcsr[dup] & PARCSR_M_ADSYNC))) { + ((dup_rcvpacket[dup][0] == (dup_parcsr[dup] & PARCSR_M_ADSYNC)) || + (dup_rcvpacket[dup][0] == DDCMP_DEL))) { dup_rcvpkoffset[dup] = 0; continue; } @@ -898,7 +911,7 @@ return SCPE_OK; /* Interrupt routines */ -void dup_clr_rxint (int32 dup) +static void dup_clr_rxint (int32 dup) { dup_rxi = dup_rxi & ~(1 << dup); /* clr mux rcv int */ if (dup_rxi == 0) /* all clr? */ @@ -907,7 +920,7 @@ else SET_INT (DUPRX); /* no, set intr */ return; } -void dup_set_rxint (int32 dup) +static void dup_set_rxint (int32 dup) { dup_rxi = dup_rxi | (1 << dup); /* set mux rcv int */ SET_INT (DUPRX); /* set master intr */ @@ -915,7 +928,7 @@ sim_debug(DBG_INT, DUPDPTR, "dup_set_rxint(dup=%d)\n", dup); return; } -int32 dup_rxinta (void) +static int32 dup_rxinta (void) { int32 dup; @@ -929,7 +942,7 @@ for (dup = 0; dup < dup_desc.lines; dup++) { /* find 1st mux */ return 0; } -void dup_clr_txint (int32 dup) +static void dup_clr_txint (int32 dup) { dup_txi = dup_txi & ~(1 << dup); /* clr mux xmt int */ if (dup_txi == 0) /* all clr? */ @@ -938,7 +951,7 @@ else SET_INT (DUPTX); /* no, set intr */ return; } -void dup_set_txint (int32 dup) +static void dup_set_txint (int32 dup) { dup_txi = dup_txi | (1 << dup); /* set mux xmt int */ SET_INT (DUPTX); /* set master intr */ @@ -946,7 +959,7 @@ sim_debug(DBG_INT, DUPDPTR, "dup_set_txint(dup=%d)\n", dup); return; } -int32 dup_txinta (void) +static int32 dup_txinta (void) { int32 dup; @@ -962,7 +975,7 @@ return 0; /* Device reset */ -t_stat dup_clear (int32 dup, t_bool flag) +static t_stat dup_clear (int32 dup, t_bool flag) { sim_debug(DBG_TRC, DUPDPTR, "dup_clear(dup=%d,flag=%d)\n", dup, flag); @@ -983,7 +996,7 @@ dup_ldsc[dup].rcve = 0; /* clr rcv enb */ return SCPE_OK; } -t_stat dup_reset (DEVICE *dptr) +static t_stat dup_reset (DEVICE *dptr) { int32 i, ndev; @@ -1029,7 +1042,7 @@ if (ndev) return auto_config (dptr->name, ndev); /* auto config */ } -t_stat dup_attach (UNIT *uptr, char *cptr) +static t_stat dup_attach (UNIT *uptr, char *cptr) { t_stat r; DEVICE *dptr = DUPDPTR; @@ -1038,6 +1051,8 @@ char attach_string[512]; if (!cptr || !*cptr) return SCPE_ARG; +if (!(uptr->flags & UNIT_ATTABLE)) + return SCPE_NOATT; sprintf (attach_string, "Line=%d,Buffered=16384,%s", dup, cptr); r = tmxr_open_master (&dup_desc, attach_string); /* open master socket */ free (uptr->filename); @@ -1049,7 +1064,7 @@ sim_activate_after (dup_units+dup_desc.lines, 2000000); /* start poll */ return r; } -t_stat dup_detach (UNIT *uptr) +static t_stat dup_detach (UNIT *uptr) { DEVICE *dptr = DUPDPTR; int32 dup = (int32)(uptr-dptr->units); @@ -1075,7 +1090,7 @@ return tmxr_detach_ln (lp); /* SET/SHOW SPEED processor */ -t_stat dup_showspeed (FILE* st, UNIT* uptr, int32 val, void* desc) +static t_stat dup_showspeed (FILE* st, UNIT* uptr, int32 val, void* desc) { DEVICE *dptr = DUPDPTR; int32 dup = (int32)(uptr-dptr->units); @@ -1087,7 +1102,7 @@ else return SCPE_OK; } -t_stat dup_setspeed (UNIT* uptr, int32 val, char* cptr, void* desc) +static t_stat dup_setspeed (UNIT* uptr, int32 val, char* cptr, void* desc) { DEVICE *dptr = DUPDPTR; int32 dup = (int32)(uptr-dptr->units); @@ -1105,7 +1120,7 @@ return SCPE_OK; /* SET LINES processor */ -t_stat dup_setnl (UNIT *uptr, int32 val, char *cptr, void *desc) +static t_stat dup_setnl (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 newln, l; uint32 i; @@ -1135,7 +1150,7 @@ dptr->numunits = newln + 1; return dup_reset (dptr); /* setup lines and auto config */ } -t_stat dup_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +static t_stat dup_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { fprintf (st, "Bit Serial Synchronous interface (%s)\n\n", dptr->name); fprintf (st, "The %s connects two systems to provide a network connection.\n", dptr->name); @@ -1155,7 +1170,7 @@ fprint_reg_help (st, dptr); return SCPE_OK; } -t_stat dup_help_attach (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +static t_stat dup_help_attach (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { fprintf (st, "The communication line performs input and output through a TCP session\n"); fprintf (st, "connected to a user-specified port. The ATTACH command specifies the\n"); @@ -1170,7 +1185,7 @@ fprintf (st, "connecction destination system.\n\n"); return SCPE_OK; } -char *dup_description (DEVICE *dptr) +static char *dup_description (DEVICE *dptr) { return (UNIBUS) ? "DUP11 bit synchronous interface" : "DPV11 bit synchronous interface"; diff --git a/PDP11/pdp11_dup.h b/PDP11/pdp11_dup.h index 4e49d603..bdfc9357 100644 --- a/PDP11/pdp11_dup.h +++ b/PDP11/pdp11_dup.h @@ -34,7 +34,7 @@ #ifndef PDP11_DUP_H_ #define PDP11_DUP_H_ 0 -typedef void (*PACKET_RECEIVE_CALLBACK)(int32 dup, uint8 *buf, size_t len); +typedef void (*PACKET_RECEIVE_CALLBACK)(int32 dup, uint8 *buf, int len); typedef void (*PACKET_TRANSMIT_COMPLETE_CALLBACK)(int32 dup, int status); int32 dup_get_line_speed (int32 dup); diff --git a/PDP11/pdp11_kdp.c b/PDP11/pdp11_kdp.c deleted file mode 100644 index 359f1a0b..00000000 --- a/PDP11/pdp11_kdp.c +++ /dev/null @@ -1,1335 +0,0 @@ -/* pdp11_kdp.c: KMC11/DUP11 Emulation - ------------------------------------------------------------------------------ - - - Written 2002 by Johnny Eriksson - - Adapted to SIMH 3.? by Robert M. A. Jarratt in 2013 - - ------------------------------------------------------------------------------ - - Modification history: - - 14-Apr-13 RJ Took original sources into latest source code. - 15-Feb-02 JE Massive changes/cleanups. - 23-Jan-02 JE Modify for version 2.9. - 17-Jan-02 JE First attempt. -------------------------------------------------------------------------------*/ - -/* -** Loose ends, known problems etc: -** -** We don't handle NXM on the unibus. At all. In fact, we don't -** generate control-outs. -** -** We don't really implement the DUP registers. -** -** We don't do anything but full-duplex DDCMP. -** -** We don't implement buffer flushing. -*/ - -#if defined (VM_PDP10) /* PDP10 version */ -#include "pdp10_defs.h" - -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -#endif - -#define KMC_RDX 8 -#define DUP_RDX 8 - -extern int32 IREQ (HLVL); -extern int32 tmxr_poll; /* calibrated delay */ -extern int32 clk_tps; /* clock ticks per second */ -extern int32 tmr_poll; /* instructions per tick */ - -#include "sim_tmxr.h" - -#define DF_CMD 0001 /* Print commands. */ -#define DF_TX 0002 /* Print tx done. */ -#define DF_RX 0004 /* Print rx done. */ -#define DF_DATA 0010 /* Print data. */ -#define DF_QUEUE 0020 /* Print rx/tx queue changes. */ -#define DF_TRC 0040 /* Detailed trace. */ -#define DF_INF 0100 /* Info */ - -//t_stat sync_open(int* retval, char* cptr) -//{ -// return SCPE_OK; -//} -int sync_read(int line, uint8* packet, int length) -{ - return 0; -} - -//void sync_write(int line, uint8* packet, int length) -//{ -//} - -//void sync_close(int line) -//{ -//} - -t_stat unibus_read(int32* data, int32 addr) -{ - t_stat ans; - uint16 d; - - *data = 0; - ans = Map_ReadW (addr, 2, &d); - *data = d; - return ans; -} - -extern t_stat unibus_write(int32 data, int32 addr) -{ - uint16 d; - - d = data & 0xFFFF; - -//printf("dma ub write 0x%08x=%06ho(oct)\n", addr, d); - return Map_WriteW (addr, 2, &d); -} -t_stat dma_write(int32 ba, uint8* data, int length) -{ - t_stat r; - uint32 wd; - - if (length <= 0) return SCPE_OK; - if (ba & 1) { - r = unibus_read((int32 *)&wd, ba-1); - if (r != SCPE_OK) - return r; - wd &= 0377; - wd |= (*data++ << 8); - r = unibus_write(wd, ba-1); - if (r != SCPE_OK) - return r; - length -= 1; - ba += 1; - } - while (length >= 2) { - wd = *data++; - wd |= *data++ << 8; - r = unibus_write(wd, ba); - if (r != SCPE_OK) - return r; - length -= 2; - ba += 2; - } - if (length == 1) { - r = unibus_read((int32 *)&wd, ba); - if (r != SCPE_OK) - return r; - wd &= 0177400; - wd |= *data++; - r = unibus_write(wd, ba); - if (r != SCPE_OK) - return r; - } - return SCPE_OK; -} - -/* dma a block from main memory */ - -t_stat dma_read(int32 ba, uint8* data, int length) -{ - t_stat r; - uint32 wd; - - if (ba & 1) { /* Starting on an odd boundary? */ - r = unibus_read((int32 *)&wd, ba-1); - if (r != SCPE_OK) { - return r; - } - *data++ = wd >> 8; - ba += 1; - length -= 1; - } - while (length > 0) { - r = unibus_read((int32 *)&wd, ba); - if (r != SCPE_OK) { - return r; - } - *data++ = wd & 0377; - if (length > 1) { - *data++ = wd >> 8; - } - ba += 2; - length -= 2; - } - return SCPE_OK; -} - -/* bits, sel0: */ - -#define KMC_RUN 0100000 /* Run bit. */ -#define KMC_MRC 0040000 /* Master clear. */ -#define KMC_CWR 0020000 /* CRAM write. */ -#define KMC_SLU 0010000 /* Step Line Unit. */ -#define KMC_LUL 0004000 /* Line Unit Loop. */ -#define KMC_RMO 0002000 /* ROM output. */ -#define KMC_RMI 0001000 /* ROM input. */ -#define KMC_SUP 0000400 /* Step microprocessor. */ -#define KMC_RQI 0000200 /* Request input. */ -#define KMC_IEO 0000020 /* Interrupt enable output. */ -#define KMC_IEI 0000001 /* Interrupt enable input. */ - -/* bits, sel2: */ - -#define KMC_OVR 0100000 /* Buffer overrun. */ -#define KMC_LINE 0177400 /* Line number. */ -#define KMC_RDO 0000200 /* Ready for output transaction. */ -#define KMC_RDI 0000020 /* Ready for input transaction. */ -#define KMC_IOT 0000004 /* I/O type, 1 = rx, 0 = tx. */ -#define KMC_CMD 0000003 /* Command code. */ -# define CMD_BUFFIN 0 /* Buffer in. */ -# define CMD_CTRLIN 1 /* Control in. */ -# define CMD_BASEIN 3 /* Base in. */ -# define CMD_BUFFOUT 0 /* Buffer out. */ -# define CMD_CTRLOUT 1 /* Control out. */ - -/* bits, sel6: */ - -#define BFR_EOM 0010000 /* End of message. */ -#define BFR_KIL 0010000 /* Buffer Kill. */ - -/* buffer descriptor list bits: */ - -#define BDL_LDS 0100000 /* Last descriptor in list. */ -#define BDL_RSY 0010000 /* Resync transmitter. */ -#define BDL_XAD 0006000 /* Buffer address bits 17 & 16. */ -#define BDL_EOM 0001000 /* End of message. */ -#define BDL_SOM 0000400 /* Start of message. */ - -#define KMC_CRAMSIZE 1024 /* Size of CRAM. */ - -#ifndef MAXDUP -# define MAXDUP 2 /* Number of DUP-11's we can handle. */ -#endif - -#define MAXQUEUE 16 /* Number of rx bdl's we can handle. */ - -#define MAXMSG 2000 /* Largest message we handle. */ - -/* local variables: */ - -int kmc_running; -uint32 kmc_sel0; -uint32 kmc_sel2; -uint32 kmc_sel4; -uint32 kmc_sel6; -int kmc_rxi; -int kmc_txi; - -uint16 kmc_microcode[KMC_CRAMSIZE]; - -uint32 dup_rxcsr[MAXDUP]; -uint32 dup_rxdbuf[MAXDUP]; -uint32 dup_parcsr[MAXDUP]; -uint32 dup_txcsr[MAXDUP]; -uint32 dup_txdbuf[MAXDUP]; - -struct dupblock { - uint32 rxqueue[MAXQUEUE]; /* Queue of bd's to receive into. */ - uint32 rxcount; /* No. bd's in above. */ - uint32 rxnext; /* Next bd to receive into. */ - uint32 txqueue[MAXQUEUE]; /* Queue of bd's to transmit. */ - uint32 txcount; /* No. bd's in above. */ - uint32 txnext; /* Next bd to transmit. */ - uint32 txnow; /* No. bd's we are transmitting now. */ - uint8 txbuf[MAXMSG + 2]; /* contains next buffer to transmit, including two bytes for length */ - uint8 txbuflen; /* length of message in buffer */ - uint8 txbufbytessent;/* number of bytes from the message actually sent so far */ -}; - -typedef struct dupblock dupblock; - -dupblock dup[MAXDUP] = { 0 }; - -/* state/timing/etc: */ - -t_bool kmc_output = FALSE; /* Flag, need at least one output. */ -int kmc_interval = 10000; /* Polling interval. */ - -TMLN kdp_ldsc[MAXDUP]; /* line descriptors */ -TMXR kdp_desc[MAXDUP] = -{ - { 1, 0, 0, &kdp_ldsc[0] }, - { 1, 0, 0, &kdp_ldsc[1] } -}; - -extern int32 tmxr_poll; /* calibrated delay */ - -/* forward decls: */ - -t_stat kmc_rd(int32* data, int32 PA, int32 access); -t_stat kmc_wr(int32 data, int32 PA, int32 access); -int32 kmc_rxint (void); -int32 kmc_txint (void); -void kmc_setrxint(); -void kmc_clrrxint(); -void kmc_settxint(); -void kmc_clrtxint(); -t_stat kmc_svc(UNIT * uptr); -t_stat kmc_reset(DEVICE * dptr); - -t_stat dup_rd(int32* data, int32 PA, int32 access); -t_stat dup_wr(int32 data, int32 PA, int32 access); -t_stat dup_svc(UNIT * uptr); -t_stat dup_reset(DEVICE * dptr); -t_stat dup_attach(UNIT * uptr, char * cptr); -t_stat dup_detach(UNIT * uptr); -void prbdl(uint32 dbits, DEVICE *dev, int32 ba, int prbuf); - -t_stat send_packet(DEVICE *device, TMLN *lp, uint8 *buf, size_t size); - -DEBTAB kmc_debug[] = { - {"CMD", DF_CMD}, - {"TX", DF_TX}, - {"RX", DF_RX}, - {"DATA", DF_DATA}, - {"QUEUE", DF_QUEUE}, - {"TRC", DF_TRC}, - {"INF", DF_INF}, - { "TMXRXMT", TMXR_DBG_XMT }, - { "TMXRRCV", TMXR_DBG_RCV }, - { "TMXRASY", TMXR_DBG_ASY }, - { "TMXRTRC", TMXR_DBG_TRC }, - { "TMXRCON", TMXR_DBG_CON }, - {0} -}; - -/* KMC11 data structs: */ - -#define IOLN_KMC 010 - -DIB kmc_dib = { IOBA_AUTO, IOLN_KMC, &kmc_rd, &kmc_wr, 2, IVCL (KMCA), VEC_AUTO, {&kmc_rxint, &kmc_txint} }; - -UNIT kmc_unit = { UDATA (&kmc_svc, 0, 0) }; - -REG kmc_reg[] = { - { ORDATA ( SEL0, kmc_sel0, 16) }, - { ORDATA ( SEL2, kmc_sel2, 16) }, - { ORDATA ( SEL4, kmc_sel4, 16) }, - { ORDATA ( SEL6, kmc_sel6, 16) }, - - { ORDATA ( DEBUG, kmc_debug, 32) }, - { DRDATA ( INTERVAL, kmc_interval, 32) }, - - { GRDATA (DEVADDR, kmc_dib.ba, KMC_RDX, 32, 0), REG_HRO }, -/* { FLDATA (*DEVENB, kmc_dib.enb, 0), REG_HRO }, */ - { NULL }, -}; - -MTAB kmc_mod[] = { - { MTAB_XTD|MTAB_VDV, 010, "address", "ADDRESS", - &set_addr, &show_addr, NULL, "IP address" }, -/* { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &kmc_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &kmc_dib },*/ - { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VECTOR", NULL, - &set_vec, &show_vec, NULL, "Interrupt vector" }, - { 0 }, -}; - -DEVICE kmc_dev = -{ - "KMC", &kmc_unit, kmc_reg, kmc_mod, - 1, KMC_RDX, 13, 1, KMC_RDX, 8, - NULL, NULL, &kmc_reset, - NULL, NULL, NULL, &kmc_dib, - DEV_UBUS | DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, kmc_debug -}; - -/* DUP11 data structs: */ - -#define IOLN_DUP 010 - -DIB dup0_dib = { IOBA_AUTO, IOLN_DUP, &dup_rd, &dup_wr, 0 }; -DIB dup1_dib = { IOBA_AUTO, IOLN_DUP, &dup_rd, &dup_wr, 0 }; - -UNIT dup_unit[MAXDUP] = { - { UDATA (&dup_svc, UNIT_ATTABLE, 0) }, - { UDATA (&dup_svc, UNIT_ATTABLE, 0) } -}; - -REG dup0_reg[] = -{ - { GRDATA (DEVADDR, dup0_dib.ba, DUP_RDX, 32, 0), REG_HRO }, -/* { FLDATA (*DEVENB, dup0_dib.enb, 0), REG_HRO },*/ - { NULL }, -}; - -REG dup1_reg[] = -{ - { GRDATA (DEVADDR, dup1_dib.ba, DUP_RDX, 32, 0), REG_HRO }, -/* { FLDATA (*DEVENB, dup1_dib.enb, 0), REG_HRO },*/ - { NULL }, -}; - -MTAB dup_mod[] = { - { MTAB_XTD|MTAB_VDV, 010, "address", "ADDRESS", - &set_addr, &show_addr }, -/* { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &dup_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &dup_dib },*/ - { 0 }, -}; - -DEVICE dup_dev[] = -{ - { - "DUP0", &dup_unit[0], dup0_reg, dup_mod, - 1, DUP_RDX, 13, 1, DUP_RDX, 8, - NULL, NULL, &dup_reset, - NULL, &dup_attach, &dup_detach, &dup0_dib, - DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, 0, kmc_debug - }, - { - "DUP1", &dup_unit[1], dup1_reg, dup_mod, - 1, DUP_RDX, 13, 1, DUP_RDX, 8, - NULL, NULL, &dup_reset, - NULL, &dup_attach, &dup_detach, &dup1_dib, - DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, 0, kmc_debug - } -}; - -t_stat send_buffer(int dupindex) -{ - t_stat r = SCPE_OK; - dupblock* d; - - d = &dup[dupindex]; - - if (d->txnow > 0 && kdp_ldsc[dupindex].conn) - { - r = send_packet(&dup_dev[dupindex], &kdp_ldsc[dupindex], d->txbuf, d->txbuflen); - d->txnext += d->txnow; - kmc_output = TRUE; - } - - d->txnow = 0; - - return r; -} - -char *format_packet_data(uint8 *data, size_t size) -{ - static char buf[3 * 128 + 1]; - int buflen; - int i; - int n; - - buflen = 0; - n = (size > 128) ? 128 : size; - for (i = 0; i < n; i++) - { - sprintf(&buf[buflen], " %02X", data[i]); - buflen += 3; - } - - return buf; -} - -t_stat send_packet(DEVICE *device, TMLN *lp, uint8 *buf, size_t size) -{ - int bytesLeft; - size_t i; - t_stat r = SCPE_OK; - - sim_debug(DF_DATA, device, "Sending packet, length %d:%s\n", size - 2, format_packet_data(buf + 2, size - 2)); - - for (i=0; imp); - - firstByte = tmxr_getc_ln(lp); - if (firstByte & TMXR_VALID) - { - actualLength = (firstByte & 0xFF) << 8; - actualLength += (tmxr_getc_ln(lp) & 0xFF); - - if (actualLength > size) - { - sim_debug(DF_INF, device, "Received message too long, expected %d, but was %d\n", size, actualLength); - actualLength = 0; - } - else - { - for (i = 0; i < actualLength; i++) - { - buf[i] = (uint8)(tmxr_getc_ln(lp) & 0xFF); - } - - sim_debug(DF_DATA, device, "Read packet, length %d:%s\n", actualLength, format_packet_data(buf, actualLength)); - } - } - - return actualLength; -} - -/* -** Update interrupt status: -*/ - -void kmc_updints(void) -{ - if (kmc_sel0 & KMC_IEI) { - if (kmc_sel2 & KMC_RDI) { - kmc_setrxint(); - } else { - kmc_clrrxint(); - } - } - - if (kmc_sel0 & KMC_IEO) { - if (kmc_sel2 & KMC_RDO) { - kmc_settxint(); - } else { - kmc_clrtxint(); - } - } -} - -/* -** Try to set the RDO bit. If it can be set, set it and return true, -** else return false. -*/ - -t_bool kmc_getrdo(void) -{ - if (kmc_sel2 & KMC_RDO) /* Already on? */ - return FALSE; - if (kmc_sel2 & KMC_RDI) /* Busy doing input? */ - return FALSE; - kmc_sel2 |= KMC_RDO; - return TRUE; -} - -/* -** Try to do an output command. -*/ - -void kmc_tryoutput(void) -{ - int i, j; - dupblock* d; - uint32 ba; - - if (kmc_output) { - kmc_output = FALSE; - for (i = 0; i < MAXDUP; i += 1) { - d = &dup[i]; - if (d->rxnext > 0) { - kmc_output = TRUE; /* At least one, need more scanning. */ - if (kmc_getrdo()) { - ba = d->rxqueue[0]; - kmc_sel2 &= ~KMC_LINE; - kmc_sel2 |= (i << 8); - kmc_sel2 &= ~KMC_CMD; - kmc_sel2 |= CMD_BUFFOUT; - kmc_sel2 |= KMC_IOT; /* Buffer type. */ - kmc_sel4 = ba & 0177777; - kmc_sel6 = (ba >> 2) & 0140000; - kmc_sel6 |= BFR_EOM; - - for (j = 1; j < (int)d->rxcount; j += 1) { - d->rxqueue[j-1] = d->rxqueue[j]; - } - d->rxcount -= 1; - d->rxnext -= 1; - - sim_debug(DF_QUEUE, &dup_dev[i], "DUP%d: (tryout) ba = %6o, rxcount = %d, rxnext = %d\r\n", i, ba, d->rxcount, d->rxnext); - kmc_updints(); - } - return; - } - if (d->txnext > 0) { - kmc_output = TRUE; /* At least one, need more scanning. */ - if (kmc_getrdo()) { - ba = d->txqueue[0]; - kmc_sel2 &= ~KMC_LINE; - kmc_sel2 |= (i << 8); - kmc_sel2 &= ~KMC_CMD; - kmc_sel2 |= CMD_BUFFOUT; - kmc_sel2 &= ~KMC_IOT; /* Buffer type. */ - kmc_sel4 = ba & 0177777; - kmc_sel6 = (ba >> 2) & 0140000; - - for (j = 1; j < (int)d->txcount; j += 1) { - d->txqueue[j-1] = d->txqueue[j]; - } - d->txcount -= 1; - d->txnext -= 1; - - sim_debug(DF_QUEUE, &dup_dev[i], "DUP%d: (tryout) ba = %6o, txcount = %d, txnext = %d\r\n", i, ba, d->txcount, d->txnext); - kmc_updints(); - } - return; - } - } - } -} - -/* -** Try to start output. Does nothing if output is already in progress, -** or if there are no packets in the output queue. -*/ - -void dup_tryxmit(int dupindex) -{ - dupblock* d; - - int pos; /* Offset into transmit buffer. */ - - uint32 bda; /* Buffer Descriptor Address. */ - uint32 bd[3]; /* Buffer Descriptor. */ - uint32 bufaddr; /* Buffer Address. */ - uint32 buflen; /* Buffer Length. */ - - int msglen; /* Message length. */ - int dcount; /* Number of descriptors to use. */ - t_bool lds; /* Found last descriptor. */ - - int i; /* Random loop var. */ - int delay; /* Estimated transmit time. */ - - extern int32 tmxr_poll; /* calibrated delay */ - - d = &dup[dupindex]; - - if (d->txnow > 0) return; /* If xmit in progress, quit. */ - if (d->txcount <= d->txnext) return; - - /* - ** check the transmit buffers we have queued up and find out if - ** we have a full DDCMP frame. - */ - - lds = FALSE; /* No last descriptor yet. */ - dcount = msglen = 0; /* No data yet. */ - - /* accumulate length, scan for LDS flag */ - - for (i = d->txnext; i < (int)d->txcount; i += 1) { - bda = d->txqueue[i]; - (void) unibus_read((int32 *)&bd[0], bda); - (void) unibus_read((int32 *)&bd[1], bda + 2); - (void) unibus_read((int32 *)&bd[2], bda + 4); - - dcount += 1; /* Count one more descriptor. */ - msglen += bd[1]; /* Count some more bytes. */ - if (bd[2] & BDL_LDS) { - lds = TRUE; - break; - } - } - - if (!lds) return; /* If no end of message, give up. */ - - d->txnow = dcount; /* Got a full frame, will send or ignore it. */ - - if (msglen <= MAXMSG) { /* If message fits in buffer, - */ - d->txbuf[0] = (uint8)(msglen>>8) & 0xFF; - d->txbuf[1] = (uint8)msglen & 0xFF; - d->txbuflen = msglen + 2; - pos = 2; - - for (i = d->txnext; i < (int)(d->txnext + dcount); i += 1) { - bda = d->txqueue[i]; - (void) unibus_read((int32 *)&bd[0], bda); - (void) unibus_read((int32 *)&bd[1], bda + 2); - (void) unibus_read((int32 *)&bd[2], bda + 4); - - bufaddr = bd[0] + ((bd[2] & 06000) << 6); - buflen = bd[1]; - - (void) dma_read(bufaddr, &d->txbuf[pos], buflen); - pos += buflen; - } - - send_buffer(dupindex); - } - -#define IPS() (tmxr_poll * 50) /* UGH! */ - - /* - ** Delay calculation: - ** delay (instructions) = bytes * IPS * 8 / speed; - ** either do this in floating point, or be very careful about - ** overflows... - */ - - delay = IPS() / (19200 >> 10); - delay *= msglen; - delay >>= 7; - - //sim_activate(&dup_unit[dupindex], delay); -} - -/* -** Here with a bdl for some new receive buffers. Set them up. -*/ - -void dup_newrxbuf(int line, int32 ba) -{ - dupblock* d; - int32 w3; - - d = &dup[line]; - - for (;;) { - if (d->rxcount < MAXQUEUE) { - d->rxqueue[d->rxcount] = ba; - d->rxcount += 1; - sim_debug(DF_QUEUE, &dup_dev[line], "Queued rx buffer %d, descriptor address=0x%04X(%06o octal)\n", d->rxcount - 1, ba, ba); - } - else - { - sim_debug(DF_QUEUE, &dup_dev[line], "(newrxb) no more room for buffers\n"); - } - - (void) unibus_read(&w3, ba + 4); - if (w3 & BDL_LDS) - break; - - ba += 6; - } - - sim_debug(DF_QUEUE, &dup_dev[line], "(newrxb) rxcount = %d, rxnext = %d\n", d->rxcount, d->rxnext); - -} - -/* -** Here with a bdl for some new transmit buffers. Set them up and then -** try to start output if not already active. -*/ - -void dup_newtxbuf(int line, int32 ba) -{ - dupblock* d; - int32 w3; - - d = &dup[line]; - - for (;;) { - if (d->txcount < MAXQUEUE) { - d->txqueue[d->txcount] = ba; - d->txcount += 1; - } - (void) unibus_read(&w3, ba + 4); - if (w3 & BDL_LDS) - break; - - ba += 6; - } - - sim_debug(DF_QUEUE, &dup_dev[line], "DUP%d: (newtxb) txcount = %d, txnext = %d\r\n", line, d->txcount, d->txnext); - - dup_tryxmit(line); /* Try to start output. */ -} - -/* -** Here to store a block of data into a receive buffer. -*/ - -void dup_receive(int line, uint8* data, int count) -{ - dupblock* d; - uint32 bda; - uint32 bd[3]; - uint32 ba; - uint32 bl; - - d = &dup[line]; - - if (d->rxcount > d->rxnext) { - bda = d->rxqueue[d->rxnext]; - (void) unibus_read((int32 *)&bd[0], bda); - (void) unibus_read((int32 *)&bd[1], bda + 2); - (void) unibus_read((int32 *)&bd[2], bda + 4); - sim_debug(DF_QUEUE, &dup_dev[line], "dup_receive ba=0x%04x(%06o octal). Descriptor is:\n", bda, bda); - prbdl(DF_QUEUE, &dup_dev[line], bda, 0); - - ba = bd[0] + ((bd[2] & 06000) << 6); - bl = bd[1]; - - if (count > (int)bl) count = bl; /* XXX */ - - sim_debug(DF_QUEUE, &dup_dev[line], "Receive buf[%d] writing to address=0x%04X(%06o octal), bytes=%d\n", d->rxnext, ba, ba, count); - (void) dma_write(ba, data, count); - - bd[2] |= (BDL_SOM | BDL_EOM); - - (void) unibus_write(bd[2], bda + 4); - - d->rxnext += 1; - } -} - -/* -** Try to receive data for a given line: -*/ - -void dup_tryreceive(int dupindex) -{ - int length; - uint8 buffer[MAXMSG]; - - if (kdp_ldsc[dupindex].conn) { /* Got a sync line? */ - length = read_packet(&dup_dev[dupindex], &kdp_ldsc[dupindex], buffer, MAXMSG); - if (length > 0) { /* Got data? */ - sim_debug(DF_RX, &dup_dev[dupindex], "DUP%d: receiving %d bytes\r\n", dupindex, length); - dup_receive(dupindex, buffer, length); - kmc_output = TRUE; /* Flag this. */ - } - } -} - -/* -** testing testing -*/ - -void prbdl(uint32 dbits, DEVICE *dev, int32 ba, int prbuf) -{ - int32 w1, w2, w3; - int32 dp; - - for (;;) { - (void) unibus_read(&w1, ba); - (void) unibus_read(&w2, ba + 2); - (void) unibus_read(&w3, ba + 4); - - sim_debug(dbits, dev, " Word 1 = 0x%04X(%06o octal)\n", w1, w1); - sim_debug(dbits, dev, " Word 2 = 0x%04X(%06o octal)\n", w2, w2); - sim_debug(dbits, dev, " Word 3 = 0x%04X(%06o octal)\n", w3, w3); - - if (prbuf) { - if (w2 > 20) w2 = 20; - dp = w1 + ((w3 & 06000) << 6); - - while (w2 > 0) { - (void) unibus_read(&w1, dp); - dp += 2; - w2 -= 2; - - sim_debug(DF_CMD, dev, " %2x %2x", w1 & 0xff, w1 >> 8); - } - sim_debug(DF_CMD, dev, "\r\n"); - } - if (w3 & BDL_LDS) break; - ba += 6; - } -} - -void kmc_setrxint() -{ - sim_debug(DF_TRC, &kmc_dev, "set rx interrupt\n"); - kmc_rxi = 1; - SET_INT(KMCA); -} - -void kmc_clrrxint() -{ - sim_debug(DF_TRC, &kmc_dev, "clear rx interrupt\n"); - kmc_rxi = 0; - CLR_INT(KMCA); -} - -void kmc_settxint() -{ - sim_debug(DF_TRC, &kmc_dev, "set tx interrupt\n"); - kmc_txi = 1; - SET_INT(KMCB); -} - -void kmc_clrtxint() -{ - sim_debug(DF_TRC, &kmc_dev, "clear tx interrupt\n"); - kmc_txi = 0; - CLR_INT(KMCB); -} - -/* -** Here to perform an input command: -*/ - -void kmc_doinput(void) -{ - int line; - int32 ba; - - line = (kmc_sel2 & 077400) >> 8; - ba = ((kmc_sel6 & 0140000) << 2) + kmc_sel4; - - sim_debug(DF_CMD, &kmc_dev, "Input command: sel2=%06o sel4=%06o sel6=%06o\n", kmc_sel2, kmc_sel4, kmc_sel6); - sim_debug(DF_CMD, &kmc_dev, "Line %d ba=0x%04x(%06o octal)\n", line, ba, ba); - switch (kmc_sel2 & 7) { - case 0: - sim_debug(DF_CMD, &kmc_dev, "Descriptor for tx buffer:\n"); - prbdl(DF_CMD, &kmc_dev, ba, 1); - break; - case 4: - sim_debug(DF_CMD, &kmc_dev, "Descriptor for rx buffer:\n"); - prbdl(DF_CMD, &kmc_dev, ba, 0); - } - - switch (kmc_sel2 & 7) { - case 0: /* Buffer in, data to send: */ - dup_newtxbuf(line, ba); - break; - case 1: /* Control in. */ - /* - ** The only thing this does is tell us to run DDCMP, in full duplex, - ** but that is the only thing we know how to do anyway... - */ - break; - case 3: /* Base in. */ - /* - ** The only thing this does is tell the KMC what unibus address - ** the dup is at. But we already know... - */ - break; - case 4: /* Buffer in, receive buffer for us... */ - dup_newrxbuf(line, ba); - break; - } -} - -/* -** master clear the KMC: -*/ - -void kmc_mclear(void) -{ - int i; - dupblock* d; - - sim_debug(DF_INF, &kmc_dev, "Master clear\n"); - kmc_running = 0; - kmc_sel0 = KMC_MRC; - kmc_sel2 = 0; - kmc_sel4 = 0; - kmc_sel6 = 0; - kmc_rxi = 0; - kmc_txi = 0; - - /* clear out the dup's as well. */ - - for (i = 0; i < MAXDUP; i += 1) { - d = &dup[i]; - d->rxcount = 0; - d->rxnext = 0; - d->txcount = 0; - d->txnext = 0; - d->txnow = 0; - sim_cancel(&dup_unit[i]); /* Stop xmit wait. */ - sim_clock_coschedule(&dup_unit[i], tmxr_poll); - } - sim_cancel(&kmc_unit); /* Stop the clock. */ - sim_clock_coschedule(&kmc_unit, tmxr_poll); -} - -/* -** DUP11, read registers: -*/ - -t_stat dup_rd(int32* data, int32 PA, int32 access) -{ - int dupno; - - dupno = ((PA - dup0_dib.ba) >> 3) & (MAXDUP - 1); - - switch ((PA >> 1) & 03) { - case 00: - *data = dup_rxcsr[dupno]; - break; - case 01: - *data = dup_rxdbuf[dupno]; - break; - case 02: - *data = dup_txcsr[dupno]; - break; - case 03: - *data = dup_txdbuf[dupno]; - break; - } - return SCPE_OK; -} - -/* -** KMC11, read registers: -*/ - -t_stat kmc_rd(int32* data, int32 PA, int32 access) -{ - switch ((PA >> 1) & 03) { - case 00: - *data = kmc_sel0; - break; - case 01: - *data = kmc_sel2; - break; - case 02: - *data = kmc_sel4; - break; - case 03: - if (kmc_sel0 == KMC_RMO) - { - kmc_sel6 = kmc_microcode[kmc_sel4 & (KMC_CRAMSIZE - 1)]; - } - *data = kmc_sel6; - break; - } - - sim_debug(DF_TRC, &kmc_dev, "kmc_rd(), addr=0%o access=%d, result=0x%04x\n", PA, access, *data); - return SCPE_OK; -} - -/* -** DUP11, write registers: -*/ - -t_stat dup_wr(int32 data, int32 PA, int32 access) -{ - int dupno; - - dupno = ((PA - dup0_dib.ba) >> 3) & (MAXDUP - 1); - - switch ((PA >> 1) & 03) { - case 00: - dup_rxcsr[dupno] = data; - break; - case 01: - dup_parcsr[dupno] = data; - break; - case 02: - dup_txcsr[dupno] = data; - break; - case 03: - dup_txdbuf[dupno] = data; - break; - } - return SCPE_OK; -} - -void kmc_domicroinstruction() -{ - static uint32 save; - if (kmc_sel6 == 041222) /* MOVE */ - { - kmc_sel2 = (kmc_sel2 & ~0xFF) | (save & 0xFF); - } - else if (kmc_sel6 == 0122440) /* MOVE */ - { - save = kmc_sel2 & 0xFF; - } -} - -/* -** KMC11, write registers: -*/ - -t_stat kmc_wr(int32 data, int32 PA, int32 access) -{ - uint32 toggle; - int reg = PA & 07; - int sel = (PA >> 1) & 03; - - if (access == WRITE) - { - sim_debug(DF_TRC, &kmc_dev, "kmc_wr(), addr=0%08o, SEL%d, data=0x%04x\n", PA, reg, data); - } - else - { - sim_debug(DF_TRC, &kmc_dev, "kmc_wr(), addr=0x%08o, BSEL%d, data=%04x\n", PA, reg, data); - } - - switch (sel) { - case 00: - if (access == WRITEB) { - data = (PA & 1) - ? (((data & 0377) << 8) | (kmc_sel0 & 0377)) - : ((data & 0377) | (kmc_sel0 & 0177400)); - } - toggle = kmc_sel0 ^ data; - kmc_sel0 = data; - if (kmc_sel0 & KMC_MRC) { - kmc_mclear(); - break; - } - if ((toggle & KMC_CWR) && (toggle & KMC_RMO) && !(data & KMC_CWR) && !(data & KMC_RMO)) { - kmc_microcode[kmc_sel4 & (KMC_CRAMSIZE - 1)] = kmc_sel6; - } - - if ((toggle & KMC_RMI) && (toggle & KMC_SUP) && !(data & KMC_RMI) && !(data & KMC_SUP)) - { - kmc_domicroinstruction(); - } - - if (toggle & KMC_RUN) { /* Changing the run bit? */ - if (kmc_sel0 & KMC_RUN) - { - sim_debug(DF_INF, &kmc_dev, "Started RUNing\n"); - kmc_running = 1; - } - else - { - sim_debug(DF_INF, &kmc_dev, "Stopped RUNing\n"); - sim_cancel(&kmc_unit); - kmc_running = 0; - } - } - break; - case 01: - if (access == WRITEB) { - data = (PA & 1) - ? (((data & 0377) << 8) | (kmc_sel2 & 0377)) - : ((data & 0377) | (kmc_sel2 & 0177400)); - } - if (kmc_running) - { - if ((kmc_sel2 & KMC_RDI) && (!(data & KMC_RDI))) { - kmc_sel2 = data; - kmc_doinput(); - } else if ((kmc_sel2 & KMC_RDO) && (!(data & KMC_RDO))) { - kmc_sel2 = data; - kmc_tryoutput(); - } else { - kmc_sel2 = data; - } - } - else - { - kmc_sel2 = data; - } - break; - case 02: - if (kmc_sel0 & KMC_RMO) { - kmc_sel6 = kmc_microcode[data & (KMC_CRAMSIZE - 1)]; - } - kmc_sel4 = data; - break; - case 03: - kmc_sel6 = data; - break; - } - - if (kmc_running) - { - if (kmc_output) { - kmc_tryoutput(); - } - if (kmc_sel0 & KMC_RQI) { - if (!(kmc_sel2 & KMC_RDO)) { - kmc_sel2 |= KMC_RDI; - } - } - - kmc_updints(); - } - - return SCPE_OK; -} - -int32 kmc_rxint (void) -{ - int32 ans = 0; /* no interrupt request active */ - if (kmc_rxi != 0) - { - ans = kmc_dib.vec; - kmc_clrrxint(); - } - - sim_debug(DF_TRC, &kmc_dev, "rx interrupt ack %d\n", ans); - - return ans; -} - -int32 kmc_txint (void) -{ - int32 ans = 0; /* no interrupt request active */ - if (kmc_txi != 0) - { - ans = kmc_dib.vec + 4; - kmc_clrtxint(); - } - - sim_debug(DF_TRC, &kmc_dev, "tx interrupt ack %d\n", ans); - - return ans; -} - -/* -** DUP11 service routine: -*/ - -t_stat dup_svc(UNIT* uptr) -{ - int dupindex; - int32 ln; - dupblock* d; - - dupindex = uptr->u3; - d = &dup[dupindex]; - //printf("dup_svc %d\n", dupindex); - - ln = tmxr_poll_conn(&kdp_desc[dupindex]); - if (ln >= 0) - { - kdp_ldsc[dupindex].rcve = 1; - } - - tmxr_poll_rx(&kdp_desc[dupindex]); - tmxr_poll_tx(&kdp_desc[dupindex]); - - //send_buffer(dupindex); - //if (d->txnow > 0) { - // d->txnext += d->txnow; - // d->txnow = 0; - // kmc_output = TRUE; - //} - - if (d->txcount > d->txnext) { - dup_tryxmit(dupindex); - } - - sim_clock_coschedule (uptr, tmxr_poll); - - return SCPE_OK; -} - -/* -** KMC11 service routine: -*/ - -t_stat kmc_svc (UNIT* uptr) -{ - int i; - int dupno; - - dupno = uptr->u3; - - for (i = 0; i < MAXDUP; i += 1) { - dup_tryreceive(i); - } - if (kmc_output) { - kmc_tryoutput(); /* Try to do an output transaction. */ - } - sim_clock_coschedule (uptr, tmxr_poll); - //sim_activate(&kmc_unit, kmc_interval); - return SCPE_OK; -} - -/* -** DUP11, reset device: -*/ - -t_stat dup_reset(DEVICE* dptr) -{ -// static t_bool firsttime = TRUE; - int i; - - for (i = 0; i < MAXDUP; i++) - { - dup_unit[i].u3 = i; - kdp_ldsc[i].rcve = 1; - } - - //if (firsttime) { - // for (i = 1; i < MAXDUP; i += 1) { - // dup_unit[i] = dup_unit[0]; /* Copy all the units. */ - // } - // for (i = 0; i < MAXDUP; i += 1) { - // //tmxr_reset_ln(&kdp_ldsc[i]); - // dup_unit[i].u3 = i; /* Link dupblock to unit. */ - // } - // firsttime = FALSE; /* Once-only init done now. */ - //} - - return auto_config (dptr->name, (dptr->flags & DEV_DIS)? 0: 1 ); /* auto config */ -} - -/* -** KMC11, reset device: -*/ - -t_stat kmc_reset(DEVICE* dptr) -{ - kmc_sel0 = 0; - kmc_sel2 = 0; - kmc_sel4 = 0; - kmc_sel6 = 0; - - return auto_config (dptr->name, (dptr->flags & DEV_DIS)? 0: 1 ); /* auto config */ -} - -/* -** DUP11, attach device: -*/ - -t_stat dup_attach(UNIT* uptr, char* cptr) -{ - int dupno; - t_stat r; - char* tptr; - - dupno = uptr->u3; - - tptr = (char *)malloc(strlen(cptr) + 1); - if (tptr == NULL) return SCPE_MEM; - strcpy(tptr, cptr); - - r = tmxr_attach(&kdp_desc[dupno], uptr, cptr); - if (r != SCPE_OK) { - free(tptr); - return r; - } - - uptr->filename = tptr; - uptr->flags |= UNIT_ATT; - - return SCPE_OK; -} - -/* -** DUP11, detach device: -*/ - -t_stat dup_detach(UNIT* uptr) -{ - int dupno; - - dupno = uptr->u3; - - tmxr_detach(&kdp_desc[dupno], uptr); - - if (uptr->flags & UNIT_ATT) { - free(uptr->filename); - uptr->filename = NULL; - uptr->flags &= ~UNIT_ATT; - } - - return SCPE_OK; -} diff --git a/PDP11/pdp11_kdp.h b/PDP11/pdp11_kdp.h deleted file mode 100644 index a67beee1..00000000 --- a/PDP11/pdp11_kdp.h +++ /dev/null @@ -1,24 +0,0 @@ -/* pdp11_kdp.h: KMC11/DUP11 Emulation - ------------------------------------------------------------------------------ - - - Written 2002 by Johnny Eriksson - - Adapted to SIMH 3.? by Robert M. A. Jarratt in 2013 - - ------------------------------------------------------------------------------ - - Modification history: - - 14-Apr-13 RJ Took original sources into latest source code. - ------------------------------------------------------------------------------*/ - -#include "pdp10_defs.h" - -#ifndef PDP11_KDP_H -#define PDP11_KDP_H - -#define KMC_RDX 8 /* Octal in this incarnation. */ -#define DUP_RDX 8 - -#endif \ No newline at end of file diff --git a/PDP11/pdp11_kmc.c b/PDP11/pdp11_kmc.c new file mode 100644 index 00000000..2d9d2909 --- /dev/null +++ b/PDP11/pdp11_kmc.c @@ -0,0 +1,971 @@ +/* pdp11_kdp.c: KMC11/DUP11 Emulation + ------------------------------------------------------------------------------ + + + Written 2002 by Johnny Eriksson + + Adapted to SIMH 3.? by Robert M. A. Jarratt in 2013 + + ------------------------------------------------------------------------------ + + Modification history: + + 14-Apr-13 RJ Took original sources into latest source code. + 15-Feb-02 JE Massive changes/cleanups. + 23-Jan-02 JE Modify for version 2.9. + 17-Jan-02 JE First attempt. +------------------------------------------------------------------------------*/ + +/* +** Loose ends, known problems etc: +** +** We don't handle NXM on the unibus. At all. In fact, we don't +** generate control-outs. +** +** We don't do anything but full-duplex DDCMP. +** +** We don't implement buffer flushing. +*/ + +#if defined (VM_PDP10) /* PDP10 version */ +#include "pdp10_defs.h" + +#elif defined (VM_VAX) /* VAX version */ +#include "vax_defs.h" + +#else /* PDP-11 version */ +#include "pdp11_defs.h" +#endif + +#define KMC_RDX 8 + +#include "pdp11_dup.h" + +#define DF_CMD 0001 /* Print commands. */ +#define DF_TX 0002 /* Print tx done. */ +#define DF_RX 0004 /* Print rx done. */ +#define DF_DATA 0010 /* Print data. */ +#define DF_QUEUE 0020 /* Print rx/tx queue changes. */ +#define DF_TRC 0040 /* Detailed trace. */ +#define DF_INF 0100 /* Info */ + +extern int32 IREQ (HLVL); +extern int32 tmxr_poll; /* calibrated delay */ +extern int32 clk_tps; /* clock ticks per second */ +extern int32 tmr_poll; /* instructions per tick */ + +t_stat unibus_read(int32* data, int32 addr) +{ + t_stat ans; + uint16 d; + + *data = 0; + ans = Map_ReadW (addr, 2, &d); + *data = d; + return ans; +} + +t_stat unibus_write(int32 data, int32 addr) +{ + uint16 d; + + d = data & 0xFFFF; + + return Map_WriteW (addr, 2, &d); +} + +t_stat dma_write(int32 ba, uint8* data, int length) +{ + t_stat r; + uint32 wd; + + if (length <= 0) return SCPE_OK; + if (ba & 1) { + r = unibus_read((int32 *)&wd, ba-1); + if (r != SCPE_OK) + return r; + wd &= 0377; + wd |= (*data++ << 8); + r = unibus_write(wd, ba-1); + if (r != SCPE_OK) + return r; + length -= 1; + ba += 1; + } + while (length >= 2) { + wd = *data++; + wd |= *data++ << 8; + r = unibus_write(wd, ba); + if (r != SCPE_OK) + return r; + length -= 2; + ba += 2; + } + if (length == 1) { + r = unibus_read((int32 *)&wd, ba); + if (r != SCPE_OK) + return r; + wd &= 0177400; + wd |= *data++; + r = unibus_write(wd, ba); + if (r != SCPE_OK) + return r; + } + return SCPE_OK; +} + +/* dma a block from main memory */ + +t_stat dma_read(int32 ba, uint8* data, int length) +{ + t_stat r; + uint32 wd; + + if (ba & 1) { /* Starting on an odd boundary? */ + r = unibus_read((int32 *)&wd, ba-1); + if (r != SCPE_OK) { + return r; + } + *data++ = wd >> 8; + ba += 1; + length -= 1; + } + while (length > 0) { + r = unibus_read((int32 *)&wd, ba); + if (r != SCPE_OK) { + return r; + } + *data++ = wd & 0377; + if (length > 1) { + *data++ = wd >> 8; + } + ba += 2; + length -= 2; + } + return SCPE_OK; +} + +/* bits, sel0: */ + +#define KMC_RUN 0100000 /* Run bit. */ +#define KMC_MRC 0040000 /* Master clear. */ +#define KMC_CWR 0020000 /* CRAM write. */ +#define KMC_SLU 0010000 /* Step Line Unit. */ +#define KMC_LUL 0004000 /* Line Unit Loop. */ +#define KMC_RMO 0002000 /* ROM output. */ +#define KMC_RMI 0001000 /* ROM input. */ +#define KMC_SUP 0000400 /* Step microprocessor. */ +#define KMC_RQI 0000200 /* Request input. */ +#define KMC_IEO 0000020 /* Interrupt enable output. */ +#define KMC_IEI 0000001 /* Interrupt enable input. */ + +/* bits, sel2: */ + +#define KMC_OVR 0100000 /* Buffer overrun. */ +#define KMC_LINE 0177400 /* Line number. */ +#define KMC_RDO 0000200 /* Ready for output transaction. */ +#define KMC_RDI 0000020 /* Ready for input transaction. */ +#define KMC_IOT 0000004 /* I/O type, 1 = rx, 0 = tx. */ +#define KMC_CMD 0000003 /* Command code. */ +# define CMD_BUFFIN 0 /* Buffer in. */ +# define CMD_CTRLIN 1 /* Control in. */ +# define CMD_BASEIN 3 /* Base in. */ +# define CMD_BUFFOUT 0 /* Buffer out. */ +# define CMD_CTRLOUT 1 /* Control out. */ + +/* bits, sel6: */ + +#define BFR_EOM 0010000 /* End of message. */ +#define BFR_KIL 0010000 /* Buffer Kill. */ + +/* buffer descriptor list bits: */ + +#define BDL_LDS 0100000 /* Last descriptor in list. */ +#define BDL_RSY 0010000 /* Resync transmitter. */ +#define BDL_XAD 0006000 /* Buffer address bits 17 & 16. */ +#define BDL_EOM 0001000 /* End of message. */ +#define BDL_SOM 0000400 /* Start of message. */ + +#define KMC_CRAMSIZE 1024 /* Size of CRAM. */ + +#ifndef MAXDUP +# define MAXDUP 2 /* Number of DUP-11's we can handle. */ +#endif + +#define MAXQUEUE 16 /* Number of rx bdl's we can handle. */ + +#define MAXMSG 2000 /* Largest message we handle. */ + +/* local variables: */ + +int kmc_running; +uint32 kmc_sel0; +uint32 kmc_sel2; +uint32 kmc_sel4; +uint32 kmc_sel6; +int kmc_rxi; +int kmc_txi; + +uint16 kmc_microcode[KMC_CRAMSIZE]; + +struct dupblock { + int32 dupnumber; /* Line Number of all DUP11's on Unibus */ + uint32 rxqueue[MAXQUEUE]; /* Queue of bd's to receive into. */ + uint32 rxcount; /* No. bd's in above. */ + uint32 rxnext; /* Next bd to receive into. */ + uint32 txqueue[MAXQUEUE]; /* Queue of bd's to transmit. */ + uint32 txcount; /* No. bd's in above. */ + uint32 txnext; /* Next bd to transmit. */ + uint32 txnow; /* No. bd's we are transmitting now. */ + uint8 txbuf[MAXMSG]; /* contains next buffer to transmit */ + uint8 txbuflen; /* length of message in buffer */ + uint8 txbufbytessent; /* number of bytes from the message actually sent so far */ +}; + +typedef struct dupblock dupblock; + +dupblock dup[MAXDUP] = { 0 }; + +/* state/timing/etc: */ + +t_bool kmc_output = FALSE; /* Flag, need at least one output. */ +int32 kmc_output_duetime; /* time to activate after buffer transmit */ + +/* forward decls: */ + +t_stat kmc_rd(int32* data, int32 PA, int32 access); +t_stat kmc_wr(int32 data, int32 PA, int32 access); +int32 kmc_rxint (void); +int32 kmc_txint (void); +void kmc_setrxint(); +void kmc_clrrxint(); +void kmc_settxint(); +void kmc_clrtxint(); +t_stat kmc_svc(UNIT * uptr); +t_stat kmc_reset(DEVICE * dptr); + +void prbdl(uint32 dbits, DEVICE *dev, int32 ba, int prbuf); + +DEBTAB kmc_debug[] = { + {"CMD", DF_CMD}, + {"TX", DF_TX}, + {"RX", DF_RX}, + {"DATA", DF_DATA}, + {"QUEUE", DF_QUEUE}, + {"TRC", DF_TRC}, + {"INF", DF_INF}, + {0} +}; + +/* KMC11 data structs: */ + +#define IOLN_KMC 010 + +DIB kmc_dib = { IOBA_AUTO, IOLN_KMC, &kmc_rd, &kmc_wr, 2, IVCL (KMCA), VEC_AUTO, {&kmc_rxint, &kmc_txint} }; + +UNIT kmc_unit = { UDATA (&kmc_svc, 0, 0) }; + +REG kmc_reg[] = { + { ORDATA ( SEL0, kmc_sel0, 16) }, + { ORDATA ( SEL2, kmc_sel2, 16) }, + { ORDATA ( SEL4, kmc_sel4, 16) }, + { ORDATA ( SEL6, kmc_sel6, 16) }, + { NULL }, +}; + +MTAB kmc_mod[] = { + { MTAB_XTD|MTAB_VDV, 010, "address", "ADDRESS", + &set_addr, &show_addr, NULL, "IP address" }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VECTOR", NULL, + &set_vec, &show_vec, NULL, "Interrupt vector" }, + { 0 }, +}; + +DEVICE kmc_dev = +{ + "KMC", &kmc_unit, kmc_reg, kmc_mod, + 1, KMC_RDX, 13, 1, KMC_RDX, 8, + NULL, NULL, &kmc_reset, + NULL, NULL, NULL, &kmc_dib, + DEV_UBUS | DEV_DIS | DEV_DISABLE | DEV_DEBUG, 0, kmc_debug +}; + +void dup_send_complete (int32 dup, int status) +{ + sim_activate_notbefore (&kmc_unit, kmc_output_duetime); +} + +t_stat send_buffer(int dupindex) +{ + t_stat r = SCPE_OK; + dupblock* d; + d = &dup[dupindex]; + + if (d->txnow > 0) { + if (dup_put_msg_bytes (d->dupnumber, d->txbuf, d->txbuflen, TRUE, TRUE)) { + int32 speed = dup_get_line_speed(d->dupnumber); + + d->txnext += d->txnow; + d->txnow = 0; + kmc_output = TRUE; + kmc_output_duetime = sim_grtime(); + if (speed > 7) + kmc_output_duetime += (tmxr_poll * clk_tps)/(speed/8); + } + } + + return r; +} + +char *format_packet_data(uint8 *data, size_t size) +{ + static char buf[3 * 128 + 1]; + int buflen; + int i; + int n; + + buflen = 0; + n = (size > 128) ? 128 : size; + for (i = 0; i < n; i++) + { + sprintf(&buf[buflen], " %02X", data[i]); + buflen += 3; + } + + return buf; +} + +/* +** Update interrupt status: +*/ + +void kmc_updints(void) +{ + if (kmc_sel0 & KMC_IEI) { + if (kmc_sel2 & KMC_RDI) { + kmc_setrxint(); + } else { + kmc_clrrxint(); + } + } + + if (kmc_sel0 & KMC_IEO) { + if (kmc_sel2 & KMC_RDO) { + kmc_settxint(); + } else { + kmc_clrtxint(); + } + } +} + +/* +** Try to set the RDO bit. If it can be set, set it and return true, +** else return false. +*/ + +t_bool kmc_getrdo(void) +{ + if (kmc_sel2 & KMC_RDO) /* Already on? */ + return FALSE; + if (kmc_sel2 & KMC_RDI) /* Busy doing input? */ + return FALSE; + kmc_sel2 |= KMC_RDO; + return TRUE; +} + +/* +** Try to do an output command. +*/ + +void kmc_tryoutput(void) +{ + int i, j; + dupblock* d; + uint32 ba; + + if (kmc_output) { + kmc_output = FALSE; + for (i = 0; i < MAXDUP; i += 1) { + d = &dup[i]; + if (d->rxnext > 0) { + kmc_output = TRUE; /* At least one, need more scanning. */ + if (kmc_getrdo()) { + ba = d->rxqueue[0]; + kmc_sel2 &= ~KMC_LINE; + kmc_sel2 |= (i << 8); + kmc_sel2 &= ~KMC_CMD; + kmc_sel2 |= CMD_BUFFOUT; + kmc_sel2 |= KMC_IOT; /* Buffer type. */ + kmc_sel4 = ba & 0177777; + kmc_sel6 = (ba >> 2) & 0140000; + kmc_sel6 |= BFR_EOM; + + for (j = 1; j < (int)d->rxcount; j += 1) { + d->rxqueue[j-1] = d->rxqueue[j]; + } + d->rxcount -= 1; + d->rxnext -= 1; + + sim_debug(DF_QUEUE, &kmc_dev, "DUP%d: (tryout) ba = %6o, rxcount = %d, rxnext = %d\r\n", i, ba, d->rxcount, d->rxnext); + kmc_updints(); + } + return; + } + if (d->txnext > 0) { + kmc_output = TRUE; /* At least one, need more scanning. */ + if (kmc_getrdo()) { + ba = d->txqueue[0]; + kmc_sel2 &= ~KMC_LINE; + kmc_sel2 |= (i << 8); + kmc_sel2 &= ~KMC_CMD; + kmc_sel2 |= CMD_BUFFOUT; + kmc_sel2 &= ~KMC_IOT; /* Buffer type. */ + kmc_sel4 = ba & 0177777; + kmc_sel6 = (ba >> 2) & 0140000; + + for (j = 1; j < (int)d->txcount; j += 1) { + d->txqueue[j-1] = d->txqueue[j]; + } + d->txcount -= 1; + d->txnext -= 1; + + sim_debug(DF_QUEUE, &kmc_dev, "DUP%d: (tryout) ba = %6o, txcount = %d, txnext = %d\r\n", i, ba, d->txcount, d->txnext); + kmc_updints(); + } + return; + } + } + } +} + +/* +** Try to start output. Does nothing if output is already in progress, +** or if there are no packets in the output queue. +*/ + +void dup_tryxmit(int dupindex) +{ + dupblock* d; + + int pos; /* Offset into transmit buffer. */ + + uint32 bda; /* Buffer Descriptor Address. */ + uint32 bd[3]; /* Buffer Descriptor. */ + uint32 bufaddr; /* Buffer Address. */ + uint32 buflen; /* Buffer Length. */ + + int msglen; /* Message length. */ + int dcount; /* Number of descriptors to use. */ + t_bool lds; /* Found last descriptor. */ + + int i; /* Random loop var. */ + + d = &dup[dupindex]; + + if (d->txnow > 0) return; /* If xmit in progress, quit. */ + if (d->txcount <= d->txnext) return; + + /* + ** check the transmit buffers we have queued up and find out if + ** we have a full DDCMP frame. + */ + + lds = FALSE; /* No last descriptor yet. */ + dcount = msglen = 0; /* No data yet. */ + + /* accumulate length, scan for LDS flag */ + + for (i = d->txnext; i < (int)d->txcount; i += 1) { + bda = d->txqueue[i]; + (void) unibus_read((int32 *)&bd[0], bda); + (void) unibus_read((int32 *)&bd[1], bda + 2); + (void) unibus_read((int32 *)&bd[2], bda + 4); + + dcount += 1; /* Count one more descriptor. */ + msglen += bd[1]; /* Count some more bytes. */ + if (bd[2] & BDL_LDS) { + lds = TRUE; + break; + } + } + + if (!lds) return; /* If no end of message, give up. */ + + d->txnow = dcount; /* Got a full frame, will send or ignore it. */ + + if (msglen <= MAXMSG) { /* If message fits in buffer, - */ + pos = 0; + d->txbuflen = msglen; + + for (i = d->txnext; i < (int)(d->txnext + dcount); i += 1) { + bda = d->txqueue[i]; + (void) unibus_read((int32 *)&bd[0], bda); + (void) unibus_read((int32 *)&bd[1], bda + 2); + (void) unibus_read((int32 *)&bd[2], bda + 4); + + bufaddr = bd[0] + ((bd[2] & 06000) << 6); + buflen = bd[1]; + + (void) dma_read(bufaddr, &d->txbuf[pos], buflen); + pos += buflen; + } + + send_buffer(dupindex); + } +} + +/* +** Here with a bdl for some new receive buffers. Set them up. +*/ + +void dup_newrxbuf(int line, int32 ba) +{ + dupblock* d; + int32 w3; + + d = &dup[line]; + + for (;;) { + if (d->rxcount < MAXQUEUE) { + d->rxqueue[d->rxcount] = ba; + d->rxcount += 1; + sim_debug(DF_QUEUE, &kmc_dev, "Queued rx buffer %d, descriptor address=0x%04X(%06o octal)\n", d->rxcount - 1, ba, ba); + } + else + { + sim_debug(DF_QUEUE, &kmc_dev, "(newrxb) no more room for buffers\n"); + } + + (void) unibus_read(&w3, ba + 4); + if (w3 & BDL_LDS) + break; + + ba += 6; + } + + sim_debug(DF_QUEUE, &kmc_dev, "(newrxb) rxcount = %d, rxnext = %d\n", d->rxcount, d->rxnext); + +} + +/* +** Here with a bdl for some new transmit buffers. Set them up and then +** try to start output if not already active. +*/ + +void dup_newtxbuf(int line, int32 ba) +{ + dupblock* d; + int32 w3; + + d = &dup[line]; + + for (;;) { + if (d->txcount < MAXQUEUE) { + d->txqueue[d->txcount] = ba; + d->txcount += 1; + } + (void) unibus_read(&w3, ba + 4); + if (w3 & BDL_LDS) + break; + + ba += 6; + } + + sim_debug(DF_QUEUE, &kmc_dev, "DUP%d: (newtxb) txcount = %d, txnext = %d\r\n", line, d->txcount, d->txnext); + + dup_tryxmit(line); /* Try to start output. */ +} + +/* +** Here to store a block of data into a receive buffer. +*/ + +void dup_receive(int line, uint8* data, int count) +{ + dupblock* d; + uint32 bda; + uint32 bd[3]; + uint32 ba; + uint32 bl; + + d = &dup[line]; + + if (d->rxcount > d->rxnext) { + count -= 2; /* strip incoming CSR */ + bda = d->rxqueue[d->rxnext]; + (void) unibus_read((int32 *)&bd[0], bda); + (void) unibus_read((int32 *)&bd[1], bda + 2); + (void) unibus_read((int32 *)&bd[2], bda + 4); + sim_debug(DF_QUEUE, &kmc_dev, "dup_receive ba=0x%04x(%06o octal). Descriptor is:\n", bda, bda); + prbdl(DF_QUEUE, &kmc_dev, bda, 0); + + ba = bd[0] + ((bd[2] & 06000) << 6); + bl = bd[1]; + + if (count > (int)bl) count = bl; /* XXX */ + + sim_debug(DF_QUEUE, &kmc_dev, "Receive buf[%d] writing to address=0x%04X(%06o octal), bytes=%d\n", d->rxnext, ba, ba, count); + (void) dma_write(ba, data, count); + + bd[2] |= (BDL_SOM | BDL_EOM); + + (void) unibus_write(bd[2], bda + 4); + + d->rxnext += 1; + } +} + +/* +** testing testing +*/ + +void prbdl(uint32 dbits, DEVICE *dev, int32 ba, int prbuf) +{ + int32 w1, w2, w3; + int32 dp; + + for (;;) { + (void) unibus_read(&w1, ba); + (void) unibus_read(&w2, ba + 2); + (void) unibus_read(&w3, ba + 4); + + sim_debug(dbits, dev, " Word 1 = 0x%04X(%06o octal)\n", w1, w1); + sim_debug(dbits, dev, " Word 2 = 0x%04X(%06o octal)\n", w2, w2); + sim_debug(dbits, dev, " Word 3 = 0x%04X(%06o octal)\n", w3, w3); + + if (prbuf) { + if (w2 > 20) w2 = 20; + dp = w1 + ((w3 & 06000) << 6); + + while (w2 > 0) { + (void) unibus_read(&w1, dp); + dp += 2; + w2 -= 2; + + sim_debug(DF_CMD, dev, " %2x %2x", w1 & 0xff, w1 >> 8); + } + sim_debug(DF_CMD, dev, "\r\n"); + } + if (w3 & BDL_LDS) break; + ba += 6; + } +} + +void kmc_setrxint() +{ + sim_debug(DF_TRC, &kmc_dev, "set rx interrupt\n"); + kmc_rxi = 1; + SET_INT(KMCA); +} + +void kmc_clrrxint() +{ + sim_debug(DF_TRC, &kmc_dev, "clear rx interrupt\n"); + kmc_rxi = 0; + CLR_INT(KMCA); +} + +void kmc_settxint() +{ + sim_debug(DF_TRC, &kmc_dev, "set tx interrupt\n"); + kmc_txi = 1; + SET_INT(KMCB); +} + +void kmc_clrtxint() +{ + sim_debug(DF_TRC, &kmc_dev, "clear tx interrupt\n"); + kmc_txi = 0; + CLR_INT(KMCB); +} + +/* +** Here to perform an input command: +*/ + +void kmc_doinput(void) +{ + int line; + int32 ba; + dupblock* d; + + line = (kmc_sel2 & 077400) >> 8; + d = &dup[line]; + ba = ((kmc_sel6 & 0140000) << 2) + kmc_sel4; + + sim_debug(DF_CMD, &kmc_dev, "Input command: sel2=%06o sel4=%06o sel6=%06o\n", kmc_sel2, kmc_sel4, kmc_sel6); + sim_debug(DF_CMD, &kmc_dev, "Line %d ba=0x%04x(%06o octal)\n", line, ba, ba); + switch (kmc_sel2 & 7) { + case 0: + sim_debug(DF_CMD, &kmc_dev, "Descriptor for tx buffer:\n"); + prbdl(DF_CMD, &kmc_dev, ba, 1); + break; + case 4: + sim_debug(DF_CMD, &kmc_dev, "Descriptor for rx buffer:\n"); + prbdl(DF_CMD, &kmc_dev, ba, 0); + } + + switch (kmc_sel2 & 7) { + case 0: /* Buffer in, data to send: */ + dup_newtxbuf(line, ba); + break; + case 1: /* Control in. */ + /* + ** This lets us setup the dup for DDCMP mode, and possibly turn up DTR + ** since nothing else seems to do that. + */ + sim_debug(DF_CMD, &kmc_dev, "Running DDCMP in full duplex on Line %d (dup %d):\n", line, d->dupnumber); + dup_set_DDCMP (d->dupnumber, TRUE); + dup_set_DTR (d->dupnumber, TRUE); + dup_set_callback_mode (d->dupnumber, dup_receive, dup_send_complete); + break; + case 3: /* Base in. */ + /* + ** This tell the KMC what unibus address the dup is at. + */ + sim_debug(DF_CMD, &kmc_dev, "Setting Line %d DUP unibus address to: 0x%x (0%o octal)\n", line, kmc_sel6+IOPAGEBASE, kmc_sel6+IOPAGEBASE); + d->dupnumber = dup_csr_to_linenum (kmc_sel6); + break; + case 4: /* Buffer in, receive buffer for us... */ + dup_newrxbuf(line, ba); + break; + } +} + +/* +** master clear the KMC: +*/ + +void kmc_mclear(void) +{ + int i; + dupblock* d; + + sim_debug(DF_INF, &kmc_dev, "Master clear\n"); + kmc_running = 0; + kmc_sel0 = KMC_MRC; + kmc_sel2 = 0; + kmc_sel4 = 0; + kmc_sel6 = 0; + kmc_rxi = 0; + kmc_txi = 0; + + /* clear out the dup's as well. */ + + for (i = 0; i < MAXDUP; i += 1) { + d = &dup[i]; + d->rxcount = 0; + d->rxnext = 0; + d->txcount = 0; + d->txnext = 0; + d->txnow = 0; + } + sim_cancel(&kmc_unit); /* Stop the clock. */ + sim_activate_after(&kmc_unit, 2000000); +} + +/* +** KMC11, read registers: +*/ + +t_stat kmc_rd(int32* data, int32 PA, int32 access) +{ + switch ((PA >> 1) & 03) { + case 00: + *data = kmc_sel0; + break; + case 01: + *data = kmc_sel2; + break; + case 02: + *data = kmc_sel4; + break; + case 03: + if (kmc_sel0 == KMC_RMO) + { + kmc_sel6 = kmc_microcode[kmc_sel4 & (KMC_CRAMSIZE - 1)]; + } + *data = kmc_sel6; + break; + } + + sim_debug(DF_TRC, &kmc_dev, "kmc_rd(), addr=0%o access=%d, result=0x%04x\n", PA, access, *data); + return SCPE_OK; +} + +void kmc_domicroinstruction() +{ + static uint32 save; + if (kmc_sel6 == 041222) /* MOVE */ + { + kmc_sel2 = (kmc_sel2 & ~0xFF) | (save & 0xFF); + } + else if (kmc_sel6 == 0122440) /* MOVE */ + { + save = kmc_sel2 & 0xFF; + } +} + +/* +** KMC11, write registers: +*/ + +t_stat kmc_wr(int32 data, int32 PA, int32 access) +{ + uint32 toggle; + int reg = PA & 07; + int sel = (PA >> 1) & 03; + + if (access == WRITE) + { + sim_debug(DF_TRC, &kmc_dev, "kmc_wr(), addr=0%08o, SEL%d, data=0x%04x\n", PA, reg, data); + } + else + { + sim_debug(DF_TRC, &kmc_dev, "kmc_wr(), addr=0x%08o, BSEL%d, data=%04x\n", PA, reg, data); + } + + switch (sel) { + case 00: + if (access == WRITEB) { + data = (PA & 1) + ? (((data & 0377) << 8) | (kmc_sel0 & 0377)) + : ((data & 0377) | (kmc_sel0 & 0177400)); + } + toggle = kmc_sel0 ^ data; + kmc_sel0 = data; + if (kmc_sel0 & KMC_MRC) { + kmc_mclear(); + break; + } + if ((toggle & KMC_CWR) && (toggle & KMC_RMO) && !(data & KMC_CWR) && !(data & KMC_RMO)) { + kmc_microcode[kmc_sel4 & (KMC_CRAMSIZE - 1)] = kmc_sel6; + } + + if ((toggle & KMC_RMI) && (toggle & KMC_SUP) && !(data & KMC_RMI) && !(data & KMC_SUP)) + { + kmc_domicroinstruction(); + } + + if (toggle & KMC_RUN) { /* Changing the run bit? */ + if (kmc_sel0 & KMC_RUN) + { + sim_debug(DF_INF, &kmc_dev, "Started RUNing\n"); + kmc_running = 1; + } + else + { + sim_debug(DF_INF, &kmc_dev, "Stopped RUNing\n"); + sim_cancel(&kmc_unit); + kmc_running = 0; + } + } + break; + case 01: + if (access == WRITEB) { + data = (PA & 1) + ? (((data & 0377) << 8) | (kmc_sel2 & 0377)) + : ((data & 0377) | (kmc_sel2 & 0177400)); + } + if (kmc_running) + { + if ((kmc_sel2 & KMC_RDI) && (!(data & KMC_RDI))) { + kmc_sel2 = data; + kmc_doinput(); + } else if ((kmc_sel2 & KMC_RDO) && (!(data & KMC_RDO))) { + kmc_sel2 = data; + kmc_tryoutput(); + } else { + kmc_sel2 = data; + } + } + else + { + kmc_sel2 = data; + } + break; + case 02: + if (kmc_sel0 & KMC_RMO) { + kmc_sel6 = kmc_microcode[data & (KMC_CRAMSIZE - 1)]; + } + kmc_sel4 = data; + break; + case 03: + kmc_sel6 = data; + break; + } + + if (kmc_running) + { + if (kmc_output) { + kmc_tryoutput(); + } + if (kmc_sel0 & KMC_RQI) { + if (!(kmc_sel2 & KMC_RDO)) { + kmc_sel2 |= KMC_RDI; + } + } + + kmc_updints(); + } + + return SCPE_OK; +} + +int32 kmc_rxint (void) +{ + int32 ans = 0; /* no interrupt request active */ + if (kmc_rxi != 0) + { + ans = kmc_dib.vec; + kmc_clrrxint(); + } + + sim_debug(DF_TRC, &kmc_dev, "rx interrupt ack %d\n", ans); + + return ans; +} + +int32 kmc_txint (void) +{ + int32 ans = 0; /* no interrupt request active */ + if (kmc_txi != 0) + { + ans = kmc_dib.vec + 4; + kmc_clrtxint(); + } + + sim_debug(DF_TRC, &kmc_dev, "tx interrupt ack %d\n", ans); + + return ans; +} + +/* +** KMC11 service routine: +*/ + +t_stat kmc_svc (UNIT* uptr) +{ + int dupno; + + dupno = uptr->u3; + + if (kmc_output) { + kmc_tryoutput(); /* Try to do an output transaction. */ + } + sim_activate_after(uptr, 2000000); + return SCPE_OK; +} + +/* +** KMC11, reset device: +*/ + +t_stat kmc_reset(DEVICE* dptr) +{ + kmc_sel0 = 0; + kmc_sel2 = 0; + kmc_sel4 = 0; + kmc_sel6 = 0; + return auto_config (dptr->name, ((dptr->flags & DEV_DIS)? 0: 1 )); /* auto config */ +} diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index 76ecadfd..44dc1da3 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -174,9 +174,9 @@ DEVICE *sim_devices[] = { &dmc_dev[1], &dmc_dev[2], &dmc_dev[3], - &kmc_dev, &dup_dev, &dpv_dev, + &kmc_dev, NULL }; diff --git a/Visual Studio Projects/PDP10.vcproj b/Visual Studio Projects/PDP10.vcproj index 00c05465..2b920bfa 100644 --- a/Visual Studio Projects/PDP10.vcproj +++ b/Visual Studio Projects/PDP10.vcproj @@ -247,6 +247,10 @@ RelativePath="..\PDP11\pdp11_dz.c" > + + @@ -308,6 +312,10 @@ RelativePath="..\PDP11\pdp11_ddcmp.h" > + + diff --git a/Visual Studio Projects/PDP11.vcproj b/Visual Studio Projects/PDP11.vcproj index f903bfc6..c222ae13 100644 --- a/Visual Studio Projects/PDP11.vcproj +++ b/Visual Studio Projects/PDP11.vcproj @@ -243,10 +243,6 @@ RelativePath="..\PDP11\pdp11_io_lib.c" > - - @@ -255,6 +251,10 @@ RelativePath="..\PDP11\pdp11_kg.c" > + + @@ -432,6 +432,10 @@ RelativePath="..\PDP11\pdp11_dmc.h" > + + diff --git a/descrip.mms b/descrip.mms index c727c74f..41ed37b9 100644 --- a/descrip.mms +++ b/descrip.mms @@ -534,7 +534,8 @@ PDP11_SOURCE1 = $(PDP11_DIR)PDP11_FP.C,$(PDP11_DIR)PDP11_CPU.C,\ $(PDP11_DIR)PDP11_SYS.C,$(PDP11_DIR)PDP11_TC.C, \ $(PDP11_DIR)PDP11_CPUMOD.C,$(PDP11_DIR)PDP11_CR.C,\ $(PDP11_DIR)PDP11_TA.C,$(PDP11_DIR)PDP11_DMC.C,\ - $(PDP11_DIR)PDP11_DUP.C,$(PDP11_DIR)PDP11_IO_LIB.C + $(PDP11_DIR)PDP11_DUP.C,$(PDP11_DIR)PDP11_KMC.C,\ + $(PDP11_DIR)PDP11_IO_LIB.C PDP11_LIB2 = $(LIB_DIR)PDP11L2-$(ARCH).OLB PDP11_SOURCE2 = $(PDP11_DIR)PDP11_TM.C,$(PDP11_DIR)PDP11_TS.C,\ $(PDP11_DIR)PDP11_IO.C,$(PDP11_DIR)PDP11_RQ.C,\ @@ -562,7 +563,7 @@ PDP10_SOURCE = $(PDP10_DIR)PDP10_FE.C,\ $(PDP10_DIR)PDP10_TIM.C,$(PDP10_DIR)PDP10_TU.C,\ $(PDP11_DIR)PDP11_PT.C,$(PDP11_DIR)PDP11_DZ.C,\ $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_CR.C,\ - $(PDP11_DIR)PDP11_DUP.C + $(PDP11_DIR)PDP11_DUP.C,$(PDP11_DIR)PDP11_KMC.C PDP10_OPTIONS = /INCL=($(SIMH_DIR),$(PDP10_DIR),$(PDP11_DIR))\ /DEF=($(CC_DEFS),"USE_INT64=1","VM_PDP10=1"$(PCAP_DEFS)) diff --git a/makefile b/makefile index b7d0e7a9..8d6e5370 100644 --- a/makefile +++ b/makefile @@ -665,7 +665,7 @@ PDP11 = ${PDP11D}/pdp11_fp.c ${PDP11D}/pdp11_cpu.c ${PDP11D}/pdp11_dz.c \ ${PDP11D}/pdp11_cr.c ${PDP11D}/pdp11_rf.c ${PDP11D}/pdp11_dl.c \ ${PDP11D}/pdp11_ta.c ${PDP11D}/pdp11_rc.c ${PDP11D}/pdp11_kg.c \ ${PDP11D}/pdp11_ke.c ${PDP11D}/pdp11_dc.c ${PDP11D}/pdp11_dmc.c \ - ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_kmc.c ${PDP11D}/pdp11_io_lib.c PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT} @@ -770,7 +770,7 @@ PDP10 = ${PDP10D}/pdp10_fe.c ${PDP11D}/pdp11_dz.c ${PDP10D}/pdp10_cpu.c \ ${PDP10D}/pdp10_pag.c ${PDP10D}/pdp10_rp.c ${PDP10D}/pdp10_sys.c \ ${PDP10D}/pdp10_tim.c ${PDP10D}/pdp10_tu.c ${PDP10D}/pdp10_xtnd.c \ ${PDP11D}/pdp11_pt.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ - ${PDP11D}/pdp11_dup.c + ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_kmc.c PDP10_OPT = -DVM_PDP10 -DUSE_INT64 -I ${PDP10D} -I ${PDP11D}