diff --git a/PDP10/pdp10_cpu.c b/PDP10/pdp10_cpu.c index 8a24bfed..4a66f701 100644 --- a/PDP10/pdp10_cpu.c +++ b/PDP10/pdp10_cpu.c @@ -197,6 +197,7 @@ jmp_buf save_env; int32 hst_p = 0; /* history pointer */ int32 hst_lnt = 0; /* history length */ InstHistory *hst = NULL; /* instruction history */ +int32 apr_serial = -1; /* CPU Serial number */ /* Forward and external declarations */ @@ -205,6 +206,9 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat cpu_set_serial (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_serial (FILE *st, UNIT *uptr, int32 val, void *desc); + d10 adjsp (d10 val, a10 ea); void ibp (a10 ea, int32 pflgs); d10 ldb (a10 ea, int32 pflgs); @@ -400,6 +404,7 @@ MTAB cpu_mod[] = { NULL, &show_iospace }, { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", &cpu_set_hist, &cpu_show_hist }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "SERIAL", "SERIAL", &cpu_set_serial, &cpu_show_serial }, { 0 } }; @@ -2104,7 +2109,14 @@ return; t_bool aprid (a10 ea, int32 prv) { -Write (ea, (Q_ITS)? UC_AIDITS: UC_AIDDEC, prv); +d10 value = (Q_ITS)? UC_AIDITS: UC_AIDDEC; + +if( (apr_serial == -1) || (!Q_ITS && apr_serial < 4096) ) + value |= (Q_ITS)? UC_SERITS: UC_SERDEC; +else + value |= apr_serial; + +Write (ea, value, prv); return FALSE; } @@ -2419,3 +2431,34 @@ for (k = 0; k < lnt; k++) { /* print specified */ } /* end for */ return SCPE_OK; } + +/* Set serial */ + +t_stat cpu_set_serial (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 lnt; +t_stat r; + +if (cptr == NULL) { + apr_serial = -1; + return SCPE_OK; + } +lnt = (int32) get_uint (cptr, 10, 077777, &r); +if ((r != SCPE_OK) || (lnt <= 0) || (!Q_ITS && lnt < 4096)) + return SCPE_ARG; +apr_serial = lnt & 077777; +return SCPE_OK; +} + +/* Show serial */ + +t_stat cpu_show_serial (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "Serial: " ); +if( (apr_serial == -1) || (!Q_ITS && apr_serial < 4096) ) { + fprintf (st, "%d (default)", (Q_ITS)? UC_SERITS: UC_SERDEC); + return SCPE_OK; + } +fprintf (st, "%d", apr_serial); +return SCPE_OK; +} diff --git a/PDP10/pdp10_defs.h b/PDP10/pdp10_defs.h index e42b0e2f..2798b589 100644 --- a/PDP10/pdp10_defs.h +++ b/PDP10/pdp10_defs.h @@ -476,8 +476,9 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ #define UC_SERDEC 4097 /* serial number */ #define UC_SERITS 1729 #define UC_AIDDEC (UC_INHCST | UC_UBABLT | UC_KIPAGE | UC_KLPAGE | \ - UC_VERDEC | UC_SERDEC) -#define UC_AIDITS (UC_KIPAGE | UC_VERITS | UC_SERITS) + UC_VERDEC) +#define UC_AIDITS (UC_KIPAGE | UC_VERITS) + #define UC_HSBDEC 0376000 /* DEC initial HSB */ #define UC_HSBITS 0000500 /* ITS initial HSB */ @@ -619,6 +620,7 @@ typedef struct pdp_dib DIB; #define DZ_MUXES 4 /* max # of muxes */ #define DZ_LINES 8 /* lines per mux */ +#define DUP_LINES 4 /* max # of DUP11's */ #define DIB_MAX 100 /* max DIBs */ #define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ @@ -712,6 +714,9 @@ 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 #define INT_RP (1u << INT_V_RP) #define INT_TU (1u << INT_V_TU) @@ -729,6 +734,8 @@ typedef struct pdp_dib DIB; #define INT_PTP (1u << INT_V_PTP) #define INT_LP20 (1u << INT_V_LP20) #define INT_CR (1u << INT_V_CR) +#define INT_DUPRX (1u << INT_V_DUPRX) +#define INT_DUPTX (1u << INT_V_DUPTX) #define IPL_RP 6 /* int levels */ #define IPL_TU 6 @@ -742,6 +749,8 @@ typedef struct pdp_dib DIB; #define IPL_DZRX 5 #define IPL_DZTX 5 #define IPL_RY 5 +#define IPL_DUPRX 5 +#define IPL_DUPTX 5 #define IPL_PTR 4 #define IPL_PTP 4 #define IPL_LP20 4 diff --git a/PDP10/pdp10_lp20.c b/PDP10/pdp10_lp20.c index fec1cda6..d8122f01 100644 --- a/PDP10/pdp10_lp20.c +++ b/PDP10/pdp10_lp20.c @@ -25,6 +25,8 @@ lp20 line printer + 29-May-13 TL Force append when an existing file is attached. + Previously over-wrote file from the top. 19-Jan-07 RMS Added UNIT_TEXT flag 04-Sep-05 RMS Fixed missing return (found by Peter Schorn) 07-Jul-05 RMS Removed extraneous externs @@ -374,17 +376,17 @@ return SCPE_OK; else if (paper) davfu_action; else print_xlate; - } + } else if (paper) { if (xlate || delim || delim_hold) davfu_action; else print_input; - } + } else { if (xlate || delim || delim_hold) print_xlate; else print_input; - } + } */ t_stat lp20_svc (UNIT *uptr) @@ -657,6 +659,10 @@ t_stat lp20_attach (UNIT *uptr, char *cptr) t_stat reason; reason = attach_unit (uptr, cptr); /* attach file */ +if (reason == SCPE_OK) { + sim_fseek (uptr->fileref, 0, SEEK_END); + uptr->pos = sim_ftell (uptr->fileref); + } if (lpcsa & CSA_ONL) /* just file chg? */ return reason; if (sim_is_active (&lp20_unit)) /* busy? no int */ diff --git a/PDP10/pdp10_sys.c b/PDP10/pdp10_sys.c index 2e2eb0f5..e6f4ede4 100644 --- a/PDP10/pdp10_sys.c +++ b/PDP10/pdp10_sys.c @@ -56,7 +56,7 @@ extern DEVICE ry_dev; extern DEVICE cr_dev; extern DEVICE lp20_dev; extern DEVICE kmc_dev; -extern DEVICE dup_dev[]; +extern DEVICE dup_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern d10 *M; @@ -92,9 +92,8 @@ DEVICE *sim_devices[] = { &rp_dev, &tu_dev, &dz_dev, - &kmc_dev, - &dup_dev[0], - &dup_dev[1], + &kmc_dev, + &dup_dev, NULL }; diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index 63e032c2..e4e853df 100644 --- a/PDP11/pdp11_cpu.c +++ b/PDP11/pdp11_cpu.c @@ -1,6 +1,6 @@ /* pdp11_cpu.c: PDP-11 CPU simulator - Copyright (c) 1993-2012, Robert M Supnik + Copyright (c) 1993-2013, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ cpu PDP-11 CPU + 10-Apr-13 RMS MMR1 does not track PC changes (Johnny Billquist) 29-Apr-12 RMS Fixed compiler warning (Mark Pizzolato) 19-Mar-12 RMS Fixed declaration of sim_switches (Mark Pizzolato) 29-Dec-08 RMS Fixed failure to clear cpu_bme on RESET (Walter Mueller) @@ -689,7 +690,8 @@ if (abortval != 0) { if ((trapea > 0) && stop_vecabort) reason = STOP_VECABORT; if ((trapea < 0) && /* stack push abort? */ - (CPUT (STOP_STKA) || stop_spabort)) reason = STOP_SPABORT; + (CPUT (STOP_STKA) || stop_spabort)) + reason = STOP_SPABORT; if (trapea == ~MD_KER) { /* kernel stk abort? */ setTRAP (TRAP_RED); setCPUERR (CPUE_RED); @@ -715,7 +717,7 @@ while (reason == 0) { cpu_astop = 0; reason = SCPE_STOP; break; - } + } AIO_CHECK_EVENT; if (sim_interval <= 0) { /* intv cnt expired? */ @@ -809,7 +811,7 @@ while (reason == 0) { if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ continue; - } + } if (update_MM) { /* if mm not frozen */ MMR1 = 0; @@ -907,7 +909,8 @@ while (reason == 0) { trap_req = calc_ints (ipl, trap_req); JMP_PC (src); if (CPUT (HAS_RTT) && tbit && /* RTT impl? */ - (IR == 000002)) setTRAP (TRAP_TRC); /* RTI immed trap */ + (IR == 000002)) + setTRAP (TRAP_TRC); /* RTI immed trap */ break; case 7: /* MFPT */ if (CPUT (HAS_MFPT)) /* implemented? */ @@ -1352,7 +1355,8 @@ while (reason == 0) { } else { dst = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - if (!dstreg) ea = GeteaW (dstspec); + if (!dstreg) + ea = GeteaW (dstspec); } N = GET_SIGN_W (dst); Z = GET_Z (dst); @@ -1888,6 +1892,7 @@ while (reason == 0) { R[dstspec] = (R[dstspec] & 0177400) | dst; else PWriteB (dst, last_pa); break; + /* Notes: - MTPS cannot alter the T bit - MxPD must mask GeteaW returned address, dspace is from cm not pm @@ -1981,7 +1986,8 @@ while (reason == 0) { } else { dst = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec)); - if (!dstreg) ea = GeteaB (dstspec); + if (!dstreg) + ea = GeteaB (dstspec); } N = GET_SIGN_B (dst); Z = GET_Z (dst); @@ -2161,20 +2167,20 @@ switch (spec >> 3) { /* decode spec<5:3> */ case 2: /* (R)+ */ R[reg] = ((adr = R[reg]) + 2) & 0177777; - if (update_MM) + if (update_MM && (reg != 7)) MMR1 = calc_MMR1 (020 | reg); return (adr | ds); case 3: /* @(R)+ */ R[reg] = ((adr = R[reg]) + 2) & 0177777; - if (update_MM) + if (update_MM && (reg != 7)) MMR1 = calc_MMR1 (020 | reg); adr = ReadW (adr | ds); return (adr | dsenable); case 4: /* -(R) */ adr = R[reg] = (R[reg] - 2) & 0177777; - if (update_MM) + if (update_MM && (reg != 7)) MMR1 = calc_MMR1 (0360 | reg); if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) set_stack_trap (adr); @@ -2182,7 +2188,7 @@ switch (spec >> 3) { /* decode spec<5:3> */ case 5: /* @-(R) */ adr = R[reg] = (R[reg] - 2) & 0177777; - if (update_MM) + if (update_MM && (reg != 7)) MMR1 = calc_MMR1 (0360 | reg); if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) set_stack_trap (adr); @@ -2219,13 +2225,13 @@ switch (spec >> 3) { /* decode spec<5:3> */ case 2: /* (R)+ */ delta = 1 + (reg >= 6); /* 2 if R6, PC */ R[reg] = ((adr = R[reg]) + delta) & 0177777; - if (update_MM) + if (update_MM && (reg != 7)) MMR1 = calc_MMR1 ((delta << 3) | reg); return (adr | ds); case 3: /* @(R)+ */ R[reg] = ((adr = R[reg]) + 2) & 0177777; - if (update_MM) + if (update_MM && (reg != 7)) MMR1 = calc_MMR1 (020 | reg); adr = ReadW (adr | ds); return (adr | dsenable); @@ -2233,7 +2239,7 @@ switch (spec >> 3) { /* decode spec<5:3> */ case 4: /* -(R) */ delta = 1 + (reg >= 6); /* 2 if R6, PC */ adr = R[reg] = (R[reg] - delta) & 0177777; - if (update_MM) + if (update_MM && (reg != 7)) MMR1 = calc_MMR1 ((((-delta) & 037) << 3) | reg); if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) set_stack_trap (adr); @@ -2241,7 +2247,7 @@ switch (spec >> 3) { /* decode spec<5:3> */ case 5: /* @-(R) */ adr = R[reg] = (R[reg] - 2) & 0177777; - if (update_MM) + if (update_MM && (reg != 7)) MMR1 = calc_MMR1 (0360 | reg); if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) set_stack_trap (adr); diff --git a/PDP11/pdp11_ddcmp.h b/PDP11/pdp11_ddcmp.h new file mode 100644 index 00000000..6ac3f1a9 --- /dev/null +++ b/PDP11/pdp11_ddcmp.h @@ -0,0 +1,145 @@ +/* pdp11_ddcmp.h: Digital Data Communications Message Protocol support + + Copyright (c) 2013, Mark Pizzolato + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + Digital Data Communications Message Protocol - DDCMP support routines + + 29-May-13 MP Initial implementation +*/ + +#ifndef PDP11_DDCMP_H_ +#define PDP11_DDCMP_H_ 0 + +/* DDCMP packet types */ + +#define DDCMP_SYN 0226u /* Sync character on synchronous links */ +#define DDCMP_DEL 0377u /* Sync character on asynchronous links */ +#define DDCMP_SOH 0201u /* Numbered Data Message Identifier */ +#define DDCMP_ENQ 0005u /* Control Message Identifier */ +#define DDCMP_DLE 0220u /* Maintenance Message Identifier */ + +/* Support routines */ + +/* crc16 polynomial x^16 + x^15 + x^2 + 1 (0xA001) CCITT LSB */ +static uint16 crc16_nibble[16] = { + 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, + 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400, + }; + +static uint16 ddcmp_crc16(uint16 crc, const void* vbuf, size_t len) +{ +const unsigned char* buf = (const unsigned char*)vbuf; + +while(0 != len--) { + crc = (crc>>4) ^ crc16_nibble[(*buf ^ crc) & 0xF]; + crc = (crc>>4) ^ crc16_nibble[((*buf++)>>4 ^ crc) & 0xF]; + }; +return(crc); +} + +/* Debug routines */ + +#include + +static void ddcmp_packet_trace (uint32 reason, DEVICE *dptr, const char *txt, const uint8 *msg, int32 len, t_bool detail) +{ +if (sim_deb && dptr && (reason & dptr->dctrl)) { + sim_debug(reason, dptr, "%s len: %d\n", txt, len); + if (detail) { + int i, same, group, sidx, oidx; + char outbuf[80], strbuf[18]; + static char hex[] = "0123456789ABCDEF"; + + switch (msg[0]) { + case DDCMP_SOH: /* Data Message */ + sim_debug (reason, dptr, "Data Message, Link: %d, Count: %d, Resp: %d, Num: %d, HDRCRC: %s, DATACRC: %s\n", msg[2]>>6, ((msg[2] & 0x3F) << 8)|msg[1], msg[3], msg[4], + (0 == ddcmp_crc16 (0, msg, 8)) ? "OK" : "BAD", (0 == ddcmp_crc16 (0, msg+8, 2+(((msg[2] & 0x3F) << 8)|msg[1]))) ? "OK" : "BAD"); + break; + case DDCMP_ENQ: /* Control Message */ + sim_debug (reason, dptr, "Control: Type: %d ", msg[1]); + switch (msg[1]) { + case 1: /* ACK */ + sim_debug (reason, dptr, "(ACK) ACKSUB: %d, Link: %d, Resp: %d\n", msg[2] & 0x3F, msg[2]>>6, msg[3]); + break; + case 2: /* NAK */ + sim_debug (reason, dptr, "(NAK) Reason: %d, Link: %d, Resp: %d\n", msg[2] & 0x3F, msg[2]>>6, msg[3]); + break; + case 3: /* REP */ + sim_debug (reason, dptr, "(REP) REPSUB: %d, Link: %d, Num: %d\n", msg[2] & 0x3F, msg[2]>>6, msg[4]); + break; + case 6: /* STRT */ + sim_debug (reason, dptr, "(STRT) STRTSUB: %d, Link: %d\n", msg[2] & 0x3F, msg[2]>>6); + break; + case 7: /* STACK */ + sim_debug (reason, dptr, "(STACK) STCKSUB: %d, Link: %d\n", msg[2] & 0x3F, msg[2]>>6); + break; + default: /* Unknown */ + sim_debug (reason, dptr, "(Unknown=0%o)\n", msg[1]); + break; + } + if (len != 8) { + sim_debug (reason, dptr, "Unexpected Control Message Length: %d expected 8\n", len); + } + if (0 != ddcmp_crc16 (0, msg, len)) { + sim_debug (reason, dptr, "Unexpected Message CRC\n"); + } + break; + case DDCMP_DLE: /* Maintenance Message */ + sim_debug (reason, dptr, "Maintenance Message, Link: %d, Count: %d, HDRCRC: %s, DATACRC: %s\n", msg[2]>>6, ((msg[2] & 0x3F) << 8)| msg[1], + (0 == ddcmp_crc16 (0, msg, 8)) ? "OK" : "BAD", (0 == ddcmp_crc16 (0, msg+8, 2+(((msg[2] & 0x3F) << 8)| msg[1]))) ? "OK" : "BAD"); + break; + } + for (i=same=0; i 0) && (0 == memcmp(&msg[i], &msg[i-16], 16))) { + ++same; + continue; + } + if (same > 0) { + sim_debug(reason, dptr, "%04X thru %04X same as above\n", i-(16*same), i-1); + same = 0; + } + group = (((len - i) > 16) ? 16 : (len - i)); + for (sidx=oidx=0; sidx>4)&0xf]; + outbuf[oidx++] = hex[msg[i+sidx]&0xf]; + if (isprint(msg[i+sidx])) + strbuf[sidx] = msg[i+sidx]; + else + strbuf[sidx] = '.'; + } + outbuf[oidx] = '\0'; + strbuf[sidx] = '\0'; + sim_debug(reason, dptr, "%04X%-48s %s\n", i, outbuf, strbuf); + } + if (same > 0) { + sim_debug(reason, dptr, "%04X thru %04X same as above\n", i-(16*same), len-1); + } + } + } +} + +uint16 ddcmp_crc16(uint16 crc, const void* vbuf, size_t len); + +#endif /* PDP11_DDCMP_H_ */ diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index 3c681c93..bc554fab 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -482,6 +482,7 @@ typedef struct { #define VH_MUXES 4 /* max # of VH muxes */ #define DLX_LINES 16 /* max # of KL11/DL11's */ #define DCX_LINES 16 /* max # of DC11's */ +#define DUP_LINES 8 /* max # of DUP11/DPV11's */ #define MT_MAXFR (1 << 16) /* magtape max rec */ #define AUTO_LNT 34 /* autoconfig ranks */ #define DIB_MAX 100 /* max DIBs */ @@ -601,6 +602,8 @@ typedef struct pdp_dib DIB; #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_PIR4 0 /* BR4 */ #define INT_V_TTI 1 @@ -648,6 +651,8 @@ typedef struct pdp_dib DIB; #define INT_DMCTX (1u << INT_V_DMCTX) #define INT_KMCA (1u << INT_V_KMCA) #define INT_KMCB (1u << INT_V_KMCB) +#define INT_DUPRX (1u << INT_V_DUPRX) +#define INT_DUPTX (1u << INT_V_DUPTX) #define INT_PIR4 (1u << INT_V_PIR4) #define INT_TTI (1u << INT_V_TTI) #define INT_TTO (1u << INT_V_TTO) @@ -698,6 +703,8 @@ typedef struct pdp_dib DIB; #define IPL_DMCTX 5 #define IPL_KMCA 5 #define IPL_KMCB 5 +#define IPL_DUPRX 5 +#define IPL_DUPTX 5 #define IPL_PTR 4 #define IPL_PTP 4 #define IPL_TTI 4 diff --git a/PDP11/pdp11_dup.c b/PDP11/pdp11_dup.c new file mode 100644 index 00000000..7f99d8c5 --- /dev/null +++ b/PDP11/pdp11_dup.c @@ -0,0 +1,1174 @@ +/* pdp11_dup.c: PDP-11 DUP11/DPV11 bit synchronous interface + + Copyright (c) 2013, Mark Pizzolato + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 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 interface are explicitly not supported. + + 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 + characters both initially and between DDCMP packets. + + 15-May-13 MP Initial implementation +*/ + +#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 + +#include "sim_tmxr.h" +#include "pdp11_ddcmp.h" +#include "pdp11_dup.h" + +#if !defined(DUP_LINES) +#define DUP_LINES 8 +#endif +#define INITIAL_DUP_LINES 1 + +#define DUP_WAIT 50 /* Minimum character time */ +#define DUP_CONNECT_POLL 2 /* Seconds */ + +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 */ + +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 */ + +PACKET_RECEIVE_CALLBACK dup_rcv_packet_callback[DUP_LINES]; +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); + +/* RXCSR - 16XXX0 - receiver control/status register */ + +BITFIELD dup_rxcsr_bits[] = { + BIT(BDATSET), /* Data Set Change B */ +#define RXCSR_V_BDATSET 0 +#define RXCSR_M_BDATSET (1<> TXCSR_V_MAISEL) + BIT(MAISSCLK), /* Maintenance Single Step Clock */ +#define TXCSR_V_MAISSCLK 13 +#define TXCSR_M_MAISSCLK (1<> 3); /* get line num */ +TMLN *lp = &dup_desc.ldsc[dup]; +int32 orig_val; + +if (dup >= dup_desc.lines) /* validate line number */ + return SCPE_IERR; + +orig_val = regs[(PA >> 1) & 03][dup]; +switch ((PA >> 1) & 03) { /* case on PA<2:1> */ + + case 00: /* RXCSR */ + dup_get_modem (dup); + *data = dup_rxcsr[dup]; + break; + + case 01: /* RXDBUF */ + *data = dup_rxdbuf[dup]; + dup_rxcsr[dup] &= ~RXCSR_M_RXDONE; + if (dup_rxcsr[dup] & RXCSR_M_RXACT) + sim_activate (dup_units+dup, dup_wait[dup]); + break; + + case 02: /* TXCSR */ + *data = dup_txcsr[dup]; + break; + + case 03: /* TXDBUF */ + *data = dup_txdbuf[dup]; + break; + } + +sim_debug(DBG_REG, DUPDPTR, "dup_rd(PA=0x%08X [%s], data=0x%X) ", PA, dup_rd_regs[(PA >> 1) & 03], *data); +sim_debug_bits(DBG_REG, DUPDPTR, bitdefs[(PA >> 1) & 03], (uint32)(orig_val), (uint32)(regs[(PA >> 1) & 03][dup]), TRUE); + +return SCPE_OK; +} + +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}; +int32 dup = ((PA - dup_dib.ba) >> 3); /* get line num */ +int32 orig_val; + +if (dup >= dup_desc.lines) /* validate line number */ + return SCPE_IERR; + +orig_val = regs[(PA >> 1) & 03][dup]; +if (PA & 1) /* unaligned byte access? */ + data = ((data << 8) & (orig_val & 0xFF)) & 0xFFFF; /* Merge with original word */ +else + if (access == WRITEB) /* byte access? */ + data = (orig_val & 0xFF00) | (data & 0xFF); /* Merge with original high word */ + +switch ((PA >> 1) & 03) { /* case on PA<2:1> */ + + case 00: /* RXCSR */ + dup_set_modem (dup, data); + dup_rxcsr[dup] &= ~RXCSR_WRITEABLE; + dup_rxcsr[dup] |= (data & RXCSR_WRITEABLE); + if ((dup_rxcsr[dup] & RXCSR_M_RTS) && /* Upward transition of RTS */ + (!(orig_val & RXCSR_M_RTS))) /* Enables Receive on the line */ + dup_desc.ldsc[dup].rcve = TRUE; + if ((dup_rxcsr[dup] & RXCSR_M_RTS) && /* Upward transition of RTS */ + (!(orig_val & RXCSR_M_RTS)) && /* while receiver is enabled and */ + (dup_rxcsr[dup] & RXCSR_M_RCVEN) && /* not stripping sync characters */ + (!(dup_rxcsr[dup] & RXCSR_M_STRSYN)) ) { /* Receive a SYNC character */ + dup_rxcsr[dup] |= RXCSR_M_RXDONE; + dup_rxdbuf[dup] &= ~RXDBUF_M_RXDBUF; + dup_rxdbuf[dup] |= (dup_parcsr[dup] & PARCSR_M_ADSYNC); + if (dup_rxcsr[dup] & RXCSR_M_RXIE) + dup_set_rxint (dup); + } + 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)) && + (orig_val & RXCSR_M_RCVEN)) { /* Downward transition of receiver enable */ + dup_rxcsr[dup] &= ~(RXCSR_M_RXDONE|RXCSR_M_RXACT); + if ((dup_rcvpkinoff[dup] != 0) || + (dup_rcvpkoffset[dup] != 0)) + dup_rcvpkinoff[dup] = dup_rcvpkoffset[dup] = 0; + } + 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)) + dup_set_rxint (dup); + break; + + case 01: /* PARCSR */ + dup_parcsr[dup] &= ~PARCSR_WRITEABLE; + dup_parcsr[dup] |= (data & PARCSR_WRITEABLE); + break; + + case 02: /* TXCSR */ + dup_txcsr[dup] &= ~TXCSR_WRITEABLE; + dup_txcsr[dup] |= (data & TXCSR_WRITEABLE); + if ((!(dup_txcsr[dup] & TXCSR_M_SEND)) && (orig_val & TXCSR_M_SEND)) + dup_txcsr[dup] &= ~TXCSR_M_TXACT; + if (dup_txcsr[dup] & TXCSR_M_DRESET) { + dup_clear(dup, FALSE); + break; + } + break; + + case 03: /* TXDBUF */ + dup_txdbuf[dup] &= ~TXDBUF_WRITEABLE; + dup_txdbuf[dup] |= (data & TXDBUF_WRITEABLE); + dup_txcsr[dup] &= ~TXCSR_M_TXDONE; + if (dup_txcsr[dup] & TXCSR_M_SEND) { + dup_txcsr[dup] |= TXCSR_M_TXACT; + sim_activate (dup_units+dup, dup_wait[dup]); + } + break; + } + +sim_debug(DBG_REG, DUPDPTR, "dup_wr(PA=0x%08X [%s], data=0x%X) ", PA, dup_wr_regs[(PA >> 1) & 03], data); +sim_debug_bits(DBG_REG, DUPDPTR, bitdefs[(PA >> 1) & 03], (uint32)orig_val, (uint32)regs[(PA >> 1) & 03][dup], TRUE); +return SCPE_OK; +} + +t_stat dup_set_modem (int32 dup, int32 rxcsr_bits) +{ +int32 bits_to_set, bits_to_clear; + +if ((rxcsr_bits & (RXCSR_M_DTR | RXCSR_M_RTS)) == (dup_rxcsr[dup] & (RXCSR_M_DTR | RXCSR_M_RTS))) + return SCPE_OK; +bits_to_set = ((rxcsr_bits & RXCSR_M_DTR) ? TMXR_MDM_DTR : 0) | ((rxcsr_bits & RXCSR_M_RTS) ? TMXR_MDM_RTS : 0); +bits_to_clear = (~bits_to_set) & (TMXR_MDM_DTR | TMXR_MDM_RTS); +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) +{ +int32 modem_bits; +int32 old_rxcsr_a_modem_bits, new_rxcsr_a_modem_bits, old_rxcsr_b_modem_bits, new_rxcsr_b_modem_bits; +TMLN *lp = &dup_desc.ldsc[dup]; + +old_rxcsr_a_modem_bits = dup_rxcsr[dup] & RXCSR_A_MODEM_BITS; +old_rxcsr_b_modem_bits = dup_rxcsr[dup] & RXCSR_B_MODEM_BITS; +tmxr_set_get_modem_bits (lp, 0, 0, &modem_bits); +new_rxcsr_a_modem_bits = (((modem_bits & TMXR_MDM_RNG) ? RXCSR_M_RING : 0) | + ((modem_bits & TMXR_MDM_DCD) ? RXCSR_M_DCD : 0) | + ((modem_bits & TMXR_MDM_CTS) ? RXCSR_M_CTS : 0)); +new_rxcsr_b_modem_bits = ((modem_bits & TMXR_MDM_DSR) ? RXCSR_M_DSR : 0); +dup_rxcsr[dup] &= ~(RXCSR_A_MODEM_BITS | RXCSR_B_MODEM_BITS); +dup_rxcsr[dup] |= new_rxcsr_a_modem_bits | new_rxcsr_b_modem_bits; +if (old_rxcsr_a_modem_bits != new_rxcsr_a_modem_bits) + dup_rxcsr[dup] |= RXCSR_M_DSCHNG; +else + dup_rxcsr[dup] &= ~RXCSR_M_DSCHNG; +if (old_rxcsr_b_modem_bits != new_rxcsr_b_modem_bits) + dup_rxcsr[dup] |= RXCSR_M_BDATSET; +else + dup_rxcsr[dup] &= ~RXCSR_M_BDATSET; +if ((dup_rxcsr[dup] & RXCSR_M_DSCHNG) && + (dup_rxcsr[dup] & RXCSR_M_DSCIE)) + dup_set_rxint (dup); +return SCPE_OK; +} + +/* + * Public routines for use by other devices (i.e. KDP11) + */ + +int32 dup_csr_to_linenum (int32 CSRPA) +{ +DEVICE *dptr = DUPDPTR; +DIB *dib = (DIB *)dptr->ctxt; + +CSRPA += IOPAGEBASE; +if ((dib->ba > (uint32)CSRPA) || ((uint32)CSRPA > (dib->ba + dib->lnt))) + return -1; + +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)) + return; +dup_rcv_packet_callback[dup] = receive; +dup_xmt_complete_callback[dup] = transmit; +} + +int32 dup_get_line_speed (int32 dup) +{ +if ((dup < 0) || (dup >= dup_desc.lines)) + return -1; +return dup_speed[dup]; +} + +int32 dup_get_DCD (int32 dup) +{ +if ((dup < 0) || (dup >= dup_desc.lines)) + 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)) + return SCPE_IERR; +dup_set_modem (dup, state ? (RXCSR_M_DTR | RXCSR_M_RTS) : 0); +return SCPE_OK; +} + +t_stat dup_set_DDCMP (int32 dup, t_bool state) +{ +if ((dup < 0) || (dup >= dup_desc.lines)) + return SCPE_IERR; +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); +return SCPE_OK; +} + +t_bool dup_put_msg_bytes (int32 dup, uint8 *bytes, size_t len, t_bool start, t_bool end) +{ +t_bool breturn = FALSE; + +if (!dup_xmtpkrdy[dup]) { /* Not Busy sending? */ + if (start) + dup_xmtpkoffset[dup] = 0; + if (dup_xmtpkoffset[dup] + 2 + len > dup_xmtpksize[dup]) { + dup_xmtpksize[dup] += 2 + len; + dup_xmtpacket[dup] = realloc (dup_xmtpacket[dup], dup_xmtpksize[dup]); + } + /* Strip sync bytes at the beginning of a message */ + while (len && (dup_xmtpkoffset[dup] == 0) && (bytes[0] == DDCMP_SYN)) { + --len; + ++bytes; + } + /* Insert remaining bytes into transmit buffer */ + if (len) { + memcpy (&dup_xmtpacket[dup][dup_xmtpkoffset[dup]], bytes, len); + dup_xmtpkoffset[dup] += len; + } + dup_txcsr[dup] |= TXCSR_M_TXDONE; + if (dup_txcsr[dup] & TXCSR_M_TXIE) + dup_set_txint (dup); + /* On End of Message, insert CRC and flag delivery start */ + if (end) { + uint16 crc16 = ddcmp_crc16 (0, dup_xmtpacket[dup], dup_xmtpkoffset[dup]); + + dup_xmtpacket[dup][dup_xmtpkoffset[dup]++] = crc16 & 0xFF; + dup_xmtpacket[dup][dup_xmtpkoffset[dup]++] = crc16 >> 8; + dup_xmtpkoutoff[dup] = 0; + dup_xmtpkrdy[dup] = TRUE; + } + breturn = TRUE; + } +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"); +return breturn; +} + +/* service routine to delay device activity */ +t_stat dup_svc (UNIT *uptr) +{ +DEVICE *dptr = DUPDPTR; +int32 dup = (int32)(uptr-dptr->units); +TMLN *lp = &dup_desc.ldsc[dup]; + +sim_debug(DBG_TRC, DUPDPTR, "dup_svc(dup=%d)\n", dup); +if (!(dup_txcsr[dup] & TXCSR_M_TXDONE) && (!dup_xmtpkrdy[dup])) { + uint8 data = dup_txdbuf[dup] & TXDBUF_M_TXDBUF; + + 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) { + t_stat st = SCPE_OK; + + while ((st == SCPE_OK) && (dup_xmtpkoutoff[dup] < dup_xmtpkoffset[dup])) { + st = tmxr_putc_ln (lp, dup_xmtpacket[dup][dup_xmtpkoutoff[dup]]); + if (st == SCPE_OK) + ++dup_xmtpkoutoff[dup]; + } + tmxr_send_buffered_data (lp); /* send any buffered data */ + if (st == SCPE_LOST) { /* line state transition? */ + dup_get_modem (dup); + dup_xmtpkrdy[dup] = FALSE; + dup_xmtpkoffset[dup] = 0; + } + else + if (st == SCPE_OK) { + sim_debug(DBG_PKT, DUPDPTR, "dup_svc(dup=%d) - %d byte packet transmission complete\n", dup, dup_xmtpkoutoff[dup]); + dup_xmtpkrdy[dup] = FALSE; + dup_xmtpkoffset[dup] = 0; + } + else { + sim_debug(DBG_PKT, DUPDPTR, "dup_svc(dup=%d) - Packet Transmission Stalled with %d bytes remaining\n", dup, (int)(dup_xmtpkoffset[dup]-dup_xmtpkoutoff[dup])); + } + if (!dup_xmtpkrdy[dup]) { /* Done transmitting? */ + dup_txcsr[dup] &= ~TXCSR_M_TXACT; /* Set idle */ + if (dup_xmt_complete_callback[dup]) + dup_xmt_complete_callback[dup](dup, (dup_rxcsr[dup] & RXCSR_M_DCD) ? 0 : 1); + } + } +if (dup_rxcsr[dup] & RXCSR_M_RXACT) + dup_rcv_byte (dup); +return SCPE_OK; +} + +t_stat dup_poll_svc (UNIT *uptr) +{ +int32 dup, active, attached, c; + +sim_debug(DBG_TRC, DUPDPTR, "dup_poll_svc()\n"); + +dup = tmxr_poll_conn(&dup_desc); +if (dup >= 0) { /* new connection? */ + dup_rxcsr[dup] |= RXCSR_M_RING | ((dup_rxcsr[dup] & RXCSR_M_DTR) ? (RXCSR_M_DCD | RXCSR_M_CTS | RXCSR_M_DSR) : 0); + dup_rxcsr[dup] |= RXCSR_M_DSCHNG; + if (dup_rxcsr[dup] & RXCSR_M_DSCIE) + dup_set_rxint (dup); /* Interrupt */ + } +tmxr_poll_rx (&dup_desc); +tmxr_poll_tx (&dup_desc); +for (dup=active=attached=0; dup < dup_desc.lines; dup++) { + TMLN *lp = &dup_desc.ldsc[dup]; + + if (dup_units[dup].flags & UNIT_ATT) + ++attached; + if (dup_ldsc[dup].conn) + ++active; + dup_get_modem (dup); + if (lp->xmte && dup_xmtpkrdy[dup]) { + sim_debug(DBG_PKT, DUPDPTR, "dup_poll_svc(dup=%d) - Packet Transmission of remaining %d bytes restarting...\n", dup, (int)(dup_xmtpkoffset[dup]-dup_xmtpkoutoff[dup])); + dup_svc (&dup_units[dup]); /* Flush pending output */ + } + if (!(dup_rxcsr[dup] & RXCSR_M_RXACT)) { + while (TMXR_VALID & (c = tmxr_getc_ln (lp))) { + if (dup_rcvpkoffset[dup] + 1 > dup_rcvpksize[dup]) { + dup_rcvpksize[dup] += 512; + dup_rcvpacket[dup] = realloc (dup_rcvpacket[dup], dup_rcvpksize[dup]); + } + dup_rcvpacket[dup][dup_rcvpkoffset[dup]] = c; + 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_rcvpkoffset[dup] = 0; + continue; + } + if (dup_parcsr[dup] & PARCSR_M_DECMODE) { + switch (dup_rcvpacket[dup][0]) { + default: + sim_debug (DBG_PKT, DUPDPTR, "Ignoring unexpected byte 0%o in DDCMP mode\n", dup_rcvpacket[dup][0]); + dup_rcvpkoffset[dup] = 0; + case DDCMP_SOH: + case DDCMP_ENQ: + case DDCMP_DLE: + continue; + } + } + } + if (dup_rcvpkoffset[dup] >= 8) { + if (dup_rcvpacket[dup][0] == DDCMP_ENQ) { /* Control Message? */ + ddcmp_packet_trace (DBG_PKT, DUPDPTR, "<<< RCV Packet", dup_rcvpacket[dup], dup_rcvpkoffset[dup], TRUE); + dup_rcvpkinoff[dup] = 0; + dup_rxcsr[dup] |= RXCSR_M_RXACT; + dup_rcv_byte (dup); + break; + } + else { + int32 count = ((dup_rcvpacket[dup][2] & 0x3F) << 8)| dup_rcvpacket[dup][1]; + + if (dup_rcvpkoffset[dup] >= 10 + count) { + ddcmp_packet_trace (DBG_PKT, DUPDPTR, "<<< RCV Packet", dup_rcvpacket[dup], dup_rcvpkoffset[dup], TRUE); + dup_rcvpkinoff[dup] = 0; + dup_rxcsr[dup] |= RXCSR_M_RXACT; + dup_rcv_byte (dup); + break; + } + } + } + } + } + } +if (active) + sim_clock_coschedule (uptr, tmxr_poll); /* reactivate */ +else { + for (dup=0; dup < dup_desc.lines; dup++) { + if (dup_speed[dup]/8) { + dup_wait[dup] = (tmr_poll*clk_tps)/(dup_speed[dup]/8); + if (dup_wait[dup] < DUP_WAIT) + dup_wait[dup] = DUP_WAIT; + } + else + dup_wait[dup] = DUP_WAIT; /* set minimum byte delay */ + } + if (attached) + sim_activate_after (uptr, DUP_CONNECT_POLL*1000000);/* periodic check for connections */ + } +return SCPE_OK; +} + +/* Interrupt routines */ + +void dup_clr_rxint (int32 dup) +{ +dup_rxi = dup_rxi & ~(1 << dup); /* clr mux rcv int */ +if (dup_rxi == 0) /* all clr? */ + CLR_INT (DUPRX); +else SET_INT (DUPRX); /* no, set intr */ +return; +} + +void dup_set_rxint (int32 dup) +{ +dup_rxi = dup_rxi | (1 << dup); /* set mux rcv int */ +SET_INT (DUPRX); /* set master intr */ +sim_debug(DBG_INT, DUPDPTR, "dup_set_rxint(dup=%d)\n", dup); +return; +} + +int32 dup_rxinta (void) +{ +int32 dup; + +for (dup = 0; dup < dup_desc.lines; dup++) { /* find 1st mux */ + if (dup_rxi & (1 << dup)) { + sim_debug(DBG_INT, DUPDPTR, "dup_rxinta(dup=%d)\n", dup); + dup_clr_rxint (dup); /* clear intr */ + return (dup_dib.vec + (dup * 010)); /* return vector */ + } + } +return 0; +} + +void dup_clr_txint (int32 dup) +{ +dup_txi = dup_txi & ~(1 << dup); /* clr mux xmt int */ +if (dup_txi == 0) /* all clr? */ + CLR_INT (DUPTX); +else SET_INT (DUPTX); /* no, set intr */ +return; +} + +void dup_set_txint (int32 dup) +{ +dup_txi = dup_txi | (1 << dup); /* set mux xmt int */ +SET_INT (DUPTX); /* set master intr */ +sim_debug(DBG_INT, DUPDPTR, "dup_set_txint(dup=%d)\n", dup); +return; +} + +int32 dup_txinta (void) +{ +int32 dup; + +for (dup = 0; dup < dup_desc.lines; dup++) { /* find 1st mux */ + if (dup_txi & (1 << dup)) { + sim_debug(DBG_INT, DUPDPTR, "dup_txinta(dup=%d)\n", dup); + dup_clr_txint (dup); /* clear intr */ + return (dup_dib.vec + 4 + (dup * 010)); /* return vector */ + } + } +return 0; +} + +/* Device reset */ + +t_stat dup_clear (int32 dup, t_bool flag) +{ +sim_debug(DBG_TRC, DUPDPTR, "dup_clear(dup=%d,flag=%d)\n", dup, flag); + +dup_rxdbuf[dup] = 0; /* silo empty */ +dup_txdbuf[dup] = 0; +dup_parcsr[dup] = 0; /* no params */ +dup_txcsr[dup] = TXCSR_M_TXDONE; /* clear CSR */ +dup_wait[dup] = DUP_WAIT; /* initial/default byte delay */ +if (flag) /* INIT? clr all */ + dup_rxcsr[dup] = 0; +else + dup_rxcsr[dup] &= ~(RXCSR_M_DTR|RXCSR_M_RTS); /* else save dtr */ +dup_clr_rxint (dup); /* clear int */ +dup_clr_txint (dup); +if (!dup_ldsc[dup].conn) /* set xmt enb */ + dup_ldsc[dup].xmte = 1; +dup_ldsc[dup].rcve = 0; /* clr rcv enb */ +return SCPE_OK; +} + +t_stat dup_reset (DEVICE *dptr) +{ +int32 i, ndev; + +sim_debug(DBG_TRC, dptr, "dup_reset()\n"); + +if ((UNIBUS) && (dptr == &dpv_dev)) { + if (!(dptr->flags & DEV_DIS)) { + printf ("Can't enable Qbus device on Unibus system\n"); + dptr->flags |= DEV_DIS; + return SCPE_ARG; + } + return SCPE_OK; + } + +if ((!UNIBUS) && (dptr == &dup_dev)) { + if (!(dptr->flags & DEV_DIS)) { + printf ("Can't enable Unibus device on Qbus system\n"); + dptr->flags |= DEV_DIS; + return SCPE_ARG; + } + return SCPE_OK; + } + +if (dup_ldsc == NULL) { /* First time startup */ + dup_desc.ldsc = dup_ldsc = calloc (dup_desc.lines, sizeof(*dup_ldsc)); + for (i = 0; i < dup_desc.lines; i++) /* init each line */ + dup_units[i] = dup_unit_template; + dup_units[dup_desc.lines] = dup_poll_unit_template; + } +for (i = 0; i < dup_desc.lines; i++) /* init each line */ + dup_clear (i, TRUE); +dup_rxi = dup_txi = 0; /* clr master int */ +CLR_INT (DUPRX); +CLR_INT (DUPTX); +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 */ +dup_desc.uptr = dup_units+dup_desc.lines; /* Identify polling unit */ +sim_cancel (dup_units+dup_desc.lines); /* stop poll */ +ndev = ((dptr->flags & DEV_DIS)? 0: dup_desc.lines ); +if (ndev) + sim_activate_after (dup_units+dup_desc.lines, DUP_CONNECT_POLL*1000000); +return auto_config (dptr->name, ndev); /* auto config */ +} + +t_stat dup_attach (UNIT *uptr, char *cptr) +{ +t_stat r; +DEVICE *dptr = DUPDPTR; +int32 dup = (int32)(uptr-dptr->units); +char attach_string[512]; + +if (!cptr || !*cptr) + return SCPE_ARG; +sprintf (attach_string, "Line=%d,Buffered=16384,%s", dup, cptr); +r = tmxr_open_master (&dup_desc, attach_string); /* open master socket */ +free (uptr->filename); +uptr->filename = tmxr_line_attach_string(&dup_desc.ldsc[dup]); +if (r != SCPE_OK) /* error? */ + return r; +uptr->flags |= UNIT_ATT; +sim_activate_after (dup_units+dup_desc.lines, 2000000); /* start poll */ +return r; +} + +t_stat dup_detach (UNIT *uptr) +{ +DEVICE *dptr = DUPDPTR; +int32 dup = (int32)(uptr-dptr->units); +TMLN *lp = &dup_ldsc[dup]; + +if (!(uptr->flags & UNIT_ATT)) /* attached? */ + return SCPE_OK; +uptr->flags &= ~UNIT_ATT; +free (uptr->filename); +uptr->filename = NULL; +free (dup_rcvpacket[dup]); +dup_rcvpacket[dup] = NULL; +dup_rcvpksize[dup] = 0; +dup_rcvpkoffset[dup] = 0; +free (dup_xmtpacket[dup]); +dup_xmtpacket[dup] = NULL; +dup_xmtpksize[dup] = 0; +dup_xmtpkoffset[dup] = 0; +dup_xmtpkrdy[dup] = FALSE; +dup_xmtpkoutoff[dup] = 0; +return tmxr_detach_ln (lp); +} + +/* SET/SHOW SPEED processor */ + +t_stat dup_showspeed (FILE* st, UNIT* uptr, int32 val, void* desc) +{ +DEVICE *dptr = DUPDPTR; +int32 dup = (int32)(uptr-dptr->units); + +if (dup_speed[dup]) + fprintf(st, "speed=%d bits/sec", dup_speed[dup]); +else + fprintf(st, "speed=0 (unrestricted)"); +return SCPE_OK; +} + +t_stat dup_setspeed (UNIT* uptr, int32 val, char* cptr, void* desc) +{ +DEVICE *dptr = DUPDPTR; +int32 dup = (int32)(uptr-dptr->units); +t_stat r; +int32 newspeed; + +if (cptr == NULL) + return SCPE_ARG; +newspeed = (int32) get_uint (cptr, 10, 100000000, &r); +if (r != SCPE_OK) + return r; +dup_speed[dup] = newspeed; +return SCPE_OK; +} + +/* SET LINES processor */ + +t_stat dup_setnl (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 newln, l; +uint32 i; +t_stat r; +DEVICE *dptr = DUPDPTR; + +for (i=0; inumunits; i++) + if (dptr->units[i].flags&UNIT_ATT) + return SCPE_ALATT; +if (cptr == NULL) + return SCPE_ARG; +newln = (int32) get_uint (cptr, 10, DUP_LINES, &r); +if ((r != SCPE_OK) || (newln == dup_desc.lines)) + return r; +if (newln == 0) + return SCPE_ARG; +sim_cancel (dup_units + dup_desc.lines); +dup_dib.lnt = newln * IOLN_DUP; /* set length */ +dup_desc.ldsc = dup_ldsc = realloc(dup_ldsc, newln*sizeof(*dup_ldsc)); +for (l=dup_desc.lines; l < newln; l++) { + memset (&dup_ldsc[l], 0, sizeof(*dup_ldsc)); + dup_units[l] = dup_unit_template; + } +dup_units[newln] = dup_poll_unit_template; +dup_desc.lines = newln; +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) +{ +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); +fprintf (st, "A maximum of %d %s devices/lines can be configured in the system.\n", DUP_LINES, dptr->name); +fprintf (st, "The number of configured devices can be changed with:\n\n"); +fprintf (st, " sim> SET %s LINES=n\n\n", dptr->name); +fprintf (st, "If you want to experience the actual data rates of the physical hardware you\n"); +fprintf (st, "can set the bit rate of the simulated line can be set using the following\n"); +fprintf (st, "command:\n\n"); +fprintf (st, " sim> SET %sn SPEED=bps\n\n", dptr->name); +fprintf (st, "Where bps is the number of data bits per second that the simulated line runs\n"); +fprintf (st, "at. Use a value of zero to run at full speed with no artificial\n"); +fprintf (st, "throttling.\n\n"); +fprint_set_help (st, dptr); +fprint_show_help (st, dptr); +fprint_reg_help (st, dptr); +return SCPE_OK; +} + +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"); +fprintf (st, "port to be used as well as the peer address:\n\n"); +fprintf (st, " sim> ATTACH %sn {interface:}port,Connect=peerhost:port\n\n", dptr->name); +fprintf (st, "where port is a decimal number between 1 and 65535 that is not being used for\n"); +fprintf (st, "other TCP/IP activities.\n\n"); +fprintf (st, "Specifying symmetric attach configuration (with both a listen port and\n"); +fprintf (st, "a peer address) will cause the side receiving an incoming\n"); +fprintf (st, "connection to validate that the connection actually comes from the\n"); +fprintf (st, "connecction destination system.\n\n"); +return SCPE_OK; +} + +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 new file mode 100644 index 00000000..4e49d603 --- /dev/null +++ b/PDP11/pdp11_dup.h @@ -0,0 +1,50 @@ +/* pdp11_dup.h: PDP-11 DUP11 bit synchronous shared device packet interface interface + + Copyright (c) 2013, Mark Pizzolato + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + dup DUP11 Unibus/DPV11 Qbus bit synchronous interface + + This module describes the interfaces exposed by the dup device for use by + a packet delivery devices (i.e. KMC11). + + 31-May-13 MP Initial implementation +*/ + +#ifndef PDP11_DUP_H_ +#define PDP11_DUP_H_ 0 + +typedef void (*PACKET_RECEIVE_CALLBACK)(int32 dup, uint8 *buf, size_t len); +typedef void (*PACKET_TRANSMIT_COMPLETE_CALLBACK)(int32 dup, int status); + +int32 dup_get_line_speed (int32 dup); +int32 dup_get_DCD (int32 dup); +t_stat dup_set_DTR (int32 dup, t_bool state); +t_stat dup_set_DDCMP (int32 dup, t_bool state); +int32 dup_csr_to_linenum (int32 CSRPA); + +void dup_set_callback_mode (int32 dup, PACKET_RECEIVE_CALLBACK receive, PACKET_TRANSMIT_COMPLETE_CALLBACK transmit); + +t_bool dup_put_msg_bytes (int32 dup, uint8 *bytes, size_t len, t_bool start, t_bool end); + +#endif /* PDP11_DUP_H_ */ \ No newline at end of file diff --git a/PDP11/pdp11_fp.c b/PDP11/pdp11_fp.c index fe7c9660..4b8a9993 100644 --- a/PDP11/pdp11_fp.c +++ b/PDP11/pdp11_fp.c @@ -1,6 +1,6 @@ /* pdp11_fp.c: PDP-11 floating point simulator (32b version) - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2013, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 20-Apr-13 RMS MMR1 does not track PC changes (Johnny Billquist) 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 04-Oct-04 RMS Added FIS instructions 19-Jan-03 RMS Changed mode definitions for Apple Dev Kit conflict @@ -584,20 +585,20 @@ switch (spec >> 3) { /* case on spec */ if (reg == 7) len = 2; R[reg] = ((adr = R[reg]) + len) & 0177777; - if (update_MM) + if (update_MM && (reg != 7)) MMR1 = (len << 3) | reg; return (adr | ds); case 3: /* @(R)+ */ R[reg] = ((adr = R[reg]) + 2) & 0177777; - if (update_MM) + if (update_MM && (reg != 7)) MMR1 = 020 | reg; adr = ReadW (adr | ds); return (adr | dsenable); case 4: /* -(R) */ adr = R[reg] = (R[reg] - len) & 0177777; - if (update_MM) + if (update_MM && (reg != 7)) MMR1 = (((-len) & 037) << 3) | reg; if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) set_stack_trap (adr); @@ -605,7 +606,7 @@ switch (spec >> 3) { /* case on spec */ case 5: /* @-(R) */ adr = R[reg] = (R[reg] - 2) & 0177777; - if (update_MM) + if (update_MM && (reg != 7)) MMR1 = 0360 | reg; if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) set_stack_trap (adr); diff --git a/PDP11/pdp11_io_lib.c b/PDP11/pdp11_io_lib.c index e53b870c..0c69b1d6 100644 --- a/PDP11/pdp11_io_lib.c +++ b/PDP11/pdp11_io_lib.c @@ -440,7 +440,7 @@ AUTO_CON auto_tab[] = {/*c #v am vm fxa fxv */ { { NULL }, 1, 2, 0, 8, {012400} }, /* KW11W */ { { NULL }, 1, 2, 8, 8 }, /* DU11 */ - { { "DUP0", "DUP1" },1, 2, 8, 8 }, /* DUP11 */ + { { "DUP" }, 1, 2, 8, 8 }, /* DUP11 */ { { NULL }, 1, 3, 0, 8, {015000, 015040, 015100, 015140, }}, /* DV11 */ { { NULL }, 1, 2, 8, 8 }, /* LK11A */ @@ -468,7 +468,7 @@ AUTO_CON auto_tab[] = {/*c #v am vm fxa fxv */ { { NULL }, 1, 1, 8, 4, {012410, 012410}, {0124} }, /* DR11B - fx CSRs,vec */ { { "DMP" }, 1, 2, 8, 8 }, /* DMP11 */ - { { NULL }, 1, 2, 8, 8 }, /* DPV11 */ + { { "DPV" }, 1, 2, 8, 8 }, /* DPV11 */ { { NULL }, 1, 2, 8, 8 }, /* ISB11 */ { { NULL }, 1, 2, 16, 8 }, /* DMV11 */ { { "XU", "XUB" }, 1, 1, 8, 4, diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index ebb2a554..76ecadfd 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -103,8 +103,9 @@ extern DEVICE xu_dev, xub_dev; extern DEVICE ke_dev; extern DEVICE kg_dev; extern DEVICE dmc_dev[]; +extern DEVICE dup_dev; +extern DEVICE dpv_dev; extern DEVICE kmc_dev; -extern DEVICE dup_dev[]; extern UNIT cpu_unit; extern REG cpu_reg[]; extern uint16 *M; @@ -169,13 +170,13 @@ DEVICE *sim_devices[] = { &xub_dev, &ke_dev, &kg_dev, - &dmc_dev[0], - &dmc_dev[1], - &dmc_dev[2], - &dmc_dev[3], + &dmc_dev[0], + &dmc_dev[1], + &dmc_dev[2], + &dmc_dev[3], &kmc_dev, - &dup_dev[0], - &dup_dev[1], + &dup_dev, + &dpv_dev, NULL }; diff --git a/README.md b/README.md index ba743650..9047c52d 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ A subset of normal simh commands are available for use in remote console session The Single Command Mode commands are: ATTACH, DETACH, PWD, SHOW, DIR, LS, ECHO, HELP The Multiple Command Mode commands are: EXAMINE, IEXAMINE, DEPOSIT, EVALUATE, ATTACH, DETACH, ASSIGN, DEASSIGN, STEP, CONTINUE, PWD, SAVE, SET, SHOW, DIR, LS, ECHO, HELP +A remote console session will close when an EOF character is entered (i.e. ^D or ^Z). + #### VAX/PDP11 Enhancements RQ has new disk types: RC25, RCF25, RA80 RQ device has a settable controller type (RQDX3, UDA50, KLESI, RUX50) @@ -276,15 +278,15 @@ See the 0readme_ethernet.txt file for details about the required network compone Compiling on windows is supported with recent versions of Microsoft Visual Studio (Standard or Express) and using GCC via the MinGW environment. Things may also work under Cygwin, but that is not the preferred windows environment. Not all features will be available as well as with either Visual Studio or MinGW. -##### Required related files. The file https://github.com/simh/simh/master/Visual%20Studio%20Projects/0ReadMe_Projects.txt +##### Required related files. The file https://github.com/simh/simh/blob/master/Visual%20Studio%20Projects/0ReadMe_Projects.txt ##### Visual Studio (Standard or Express) 2008, 2010 or 2012 -The file https://github.com/simh/simh/master/Visual%20Studio%20Projects/0ReadMe_Projects.txt describes the required steps to use the setup your environment to build using Visual Studio. +The file https://github.com/simh/simh/blob/master/Visual%20Studio%20Projects/0ReadMe_Projects.txt describes the required steps to use the setup your environment to build using Visual Studio. ##### MinGW -The file https://github.com/simh/simh/master/Visual%20Studio%20Projects/0ReadMe_Projects.txt describes the required steps to use the setup your environment to build using MinGW. +The file https://github.com/simh/simh/blob/master/Visual%20Studio%20Projects/0ReadMe_Projects.txt describes the required steps to use the setup your environment to build using MinGW. #### VMS diff --git a/VAX/vax730_defs.h b/VAX/vax730_defs.h index 39ed5618..9db8abff 100644 --- a/VAX/vax730_defs.h +++ b/VAX/vax730_defs.h @@ -205,6 +205,7 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, void* desc); #define VH_MUXES 4 /* max # of DHQ muxes */ #define DLX_LINES 16 /* max # of KL11/DL11's */ #define DCX_LINES 16 /* max # of DC11's */ +#define DUP_LINES 8 /* max # of DUP11's */ #define MT_MAXFR (1 << 16) /* magtape max rec */ #define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ @@ -256,6 +257,8 @@ typedef struct { #define INT_V_XU 9 #define INT_V_DMCRX 10 #define INT_V_DMCTX 11 +#define INT_V_DUPRX 12 +#define INT_V_DUPTX 13 #define INT_V_LPT 0 /* BR4 */ #define INT_V_PTR 1 @@ -282,6 +285,8 @@ typedef struct { #define INT_CR (1u << INT_V_CR) #define INT_DMCRX (1u << INT_V_DMCRX) #define INT_DMCTX (1u << INT_V_DMCTX) +#define INT_DUPRX (1u << INT_V_DUPRX) +#define INT_DUPTX (1u << INT_V_DUPTX) #define IPL_DZRX (0x15 - IPL_HMIN) #define IPL_DZTX (0x15 - IPL_HMIN) @@ -301,6 +306,8 @@ typedef struct { #define IPL_VHTX (0x14 - IPL_HMIN) #define IPL_DMCRX (0x15 - IPL_HMIN) #define IPL_DMCTX (0x15 - IPL_HMIN) +#define IPL_DUPRX (0x15 - IPL_HMIN) +#define IPL_DUPTX (0x15 - IPL_HMIN) /* Device vectors */ diff --git a/VAX/vax730_syslist.c b/VAX/vax730_syslist.c index 41e4e97c..23b0ea54 100644 --- a/VAX/vax730_syslist.c +++ b/VAX/vax730_syslist.c @@ -53,6 +53,7 @@ extern DEVICE dz_dev; extern DEVICE vh_dev; extern DEVICE xu_dev, xub_dev; extern DEVICE dmc_dev[]; +extern DEVICE dup_dev; extern UNIT cpu_unit; extern void WriteB (uint32 pa, int32 val); @@ -88,6 +89,7 @@ DEVICE *sim_devices[] = { &dmc_dev[1], &dmc_dev[2], &dmc_dev[3], + &dup_dev, NULL }; diff --git a/VAX/vax750_defs.h b/VAX/vax750_defs.h index ab536f22..7342482d 100644 --- a/VAX/vax750_defs.h +++ b/VAX/vax750_defs.h @@ -295,6 +295,8 @@ typedef struct { #define INT_V_XU 8 #define INT_V_DMCRX 9 #define INT_V_DMCTX 10 +#define INT_V_DUPRX 11 +#define INT_V_DUPTX 12 #define INT_V_LPT 0 /* BR4 */ #define INT_V_PTR 1 @@ -320,6 +322,8 @@ typedef struct { #define INT_CR (1u << INT_V_CR) #define INT_DMCRX (1u << INT_V_DMCRX) #define INT_DMCTX (1u << INT_V_DMCTX) +#define INT_DUPRX (1u << INT_V_DUPRX) +#define INT_DUPTX (1u << INT_V_DUPTX) #define IPL_DZRX (0x15 - IPL_HMIN) #define IPL_DZTX (0x15 - IPL_HMIN) @@ -338,6 +342,8 @@ typedef struct { #define IPL_VHTX (0x14 - IPL_HMIN) #define IPL_DMCRX (0x15 - IPL_HMIN) #define IPL_DMCTX (0x15 - IPL_HMIN) +#define IPL_DUPRX (0x15 - IPL_HMIN) +#define IPL_DUPTX (0x15 - IPL_HMIN) /* Device vectors */ diff --git a/VAX/vax750_syslist.c b/VAX/vax750_syslist.c index 44ebd5d8..ae815b99 100644 --- a/VAX/vax750_syslist.c +++ b/VAX/vax750_syslist.c @@ -55,6 +55,7 @@ extern DEVICE dz_dev; extern DEVICE vh_dev; extern DEVICE xu_dev, xub_dev; extern DEVICE dmc_dev[]; +extern DEVICE dup_dev; extern UNIT cpu_unit; extern void WriteB (uint32 pa, int32 val); @@ -93,6 +94,7 @@ DEVICE *sim_devices[] = { &dmc_dev[1], &dmc_dev[2], &dmc_dev[3], + &dup_dev, NULL }; diff --git a/VAX/vax780_defs.h b/VAX/vax780_defs.h index 8da9cc7b..a9a6153a 100644 --- a/VAX/vax780_defs.h +++ b/VAX/vax780_defs.h @@ -247,6 +247,7 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, void* desc); #define VH_MUXES 4 /* max # of DHU muxes */ #define DLX_LINES 16 /* max # of KL11/DL11's */ #define DCX_LINES 16 /* max # of DC11's */ +#define DUP_LINES 8 /* max # of DUP11's */ #define MT_MAXFR (1 << 16) /* magtape max rec */ #define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ @@ -306,6 +307,8 @@ typedef struct { #define INT_V_XU 8 #define INT_V_DMCRX 9 #define INT_V_DMCTX 10 +#define INT_V_DUPRX 11 +#define INT_V_DUPTX 12 #define INT_V_LPT 0 /* BR4 */ #define INT_V_PTR 1 @@ -331,6 +334,8 @@ typedef struct { #define INT_CR (1u << INT_V_CR) #define INT_DMCRX (1u << INT_V_DMCRX) #define INT_DMCTX (1u << INT_V_DMCTX) +#define INT_DUPRX (1u << INT_V_DUPRX) +#define INT_DUPTX (1u << INT_V_DUPTX) #define IPL_DZRX (0x15 - IPL_HMIN) #define IPL_DZTX (0x15 - IPL_HMIN) @@ -349,6 +354,8 @@ typedef struct { #define IPL_VHTX (0x14 - IPL_HMIN) #define IPL_DMCRX (0x15 - IPL_HMIN) #define IPL_DMCTX (0x15 - IPL_HMIN) +#define IPL_DUPRX (0x15 - IPL_HMIN) +#define IPL_DUPTX (0x15 - IPL_HMIN) /* Device vectors */ diff --git a/VAX/vax780_syslist.c b/VAX/vax780_syslist.c index 0b088d80..767a4144 100644 --- a/VAX/vax780_syslist.c +++ b/VAX/vax780_syslist.c @@ -55,6 +55,7 @@ extern DEVICE dz_dev; extern DEVICE vh_dev; extern DEVICE xu_dev, xub_dev; extern DEVICE dmc_dev[]; +extern DEVICE dup_dev; extern UNIT cpu_unit; extern void WriteB (uint32 pa, int32 val); @@ -95,6 +96,7 @@ DEVICE *sim_devices[] = { &dmc_dev[1], &dmc_dev[2], &dmc_dev[3], + &dup_dev, NULL }; diff --git a/VAX/vax860_defs.h b/VAX/vax860_defs.h index a1d0b7f2..2d8b9fbb 100644 --- a/VAX/vax860_defs.h +++ b/VAX/vax860_defs.h @@ -342,6 +342,9 @@ typedef struct { #define INT_V_XU 8 #define INT_V_DMCRX 9 #define INT_V_DMCTX 10 +#define INT_V_DUPRX 11 +#define INT_V_DUPTX 12 + #define INT_V_LPT 0 /* BR4 */ #define INT_V_PTR 1 #define INT_V_PTP 2 @@ -366,6 +369,9 @@ typedef struct { #define INT_CR (1u << INT_V_CR) #define INT_DMCRX (1u << INT_V_DMCRX) #define INT_DMCTX (1u << INT_V_DMCTX) +#define INT_DUPRX (1u << INT_V_DUPRX) +#define INT_DUPTX (1u << INT_V_DUPTX) + #define IPL_DZRX (0x15 - IPL_HMIN) #define IPL_DZTX (0x15 - IPL_HMIN) #define IPL_HK (0x15 - IPL_HMIN) @@ -383,6 +389,8 @@ typedef struct { #define IPL_VHTX (0x14 - IPL_HMIN) #define IPL_DMCRX (0x15 - IPL_HMIN) #define IPL_DMCTX (0x15 - IPL_HMIN) +#define IPL_DUPRX (0x15 - IPL_HMIN) +#define IPL_DUPTX (0x15 - IPL_HMIN) /* Device vectors */ diff --git a/VAX/vax860_syslist.c b/VAX/vax860_syslist.c index 795e091f..2038f046 100644 --- a/VAX/vax860_syslist.c +++ b/VAX/vax860_syslist.c @@ -55,6 +55,7 @@ extern DEVICE dz_dev; extern DEVICE vh_dev; extern DEVICE xu_dev, xub_dev; extern DEVICE dmc_dev[]; +extern DEVICE dup_dev; extern UNIT cpu_unit; extern void WriteB (uint32 pa, int32 val); @@ -93,6 +94,7 @@ DEVICE *sim_devices[] = { &dmc_dev[1], &dmc_dev[2], &dmc_dev[3], + &dup_dev, NULL }; diff --git a/Visual Studio Projects/0ReadMe_Projects.txt b/Visual Studio Projects/0ReadMe_Projects.txt index 9961d138..24445549 100644 --- a/Visual Studio Projects/0ReadMe_Projects.txt +++ b/Visual Studio Projects/0ReadMe_Projects.txt @@ -23,18 +23,29 @@ The contents of the windows-build directory can be downloaded from: https://github.com/simh/windows-build/archive/windows-build.zip +Download and extract the contents of this zip file into the appropriate +place in your directory structure. You do not need to do anything else +but have this directory properly located. Network devices are capable of using pthreads to enhance their performance. To realize these benefits, you must build the desire simulator with USE_READER_THREAD defined. The relevant simulators which have network -support are VAX, VAX780 and PDP11. +support are all of the VAX simulators and the PDP11 simulator. Additionally, simulators which contain devices which use the asynchronous APIs in sim_disk.c and sim_tape.c can also achieve greater performance by leveraging pthreads to perform blocking I/O in separate threads. Currently -the simulators which have such devices are VAX, VAX780 and PDP11. To -achieve these benefits the simulators must be built with SIM_ASYNCH_IO -defined. +the simulators which have such devices are all of the VAX simulators and +the PDP11. To achieve these benefits the simulators must be built with +SIM_ASYNCH_IO defined. The project files in this directory build these simulators with support for both network and asynchronous I/O. + +To build any of the supported simulators you should open the simh.sln file +in this directory. + +If you are using a version of Visual Studio beyond Visual Studio 2008, then +your later version of Visual Studio will automatically convert the Visual +Studio 2008 project fils. You should ignore any warnings produced by the +conversion process. diff --git a/Visual Studio Projects/PDP10.vcproj b/Visual Studio Projects/PDP10.vcproj index 27db5bec..00c05465 100644 --- a/Visual Studio Projects/PDP10.vcproj +++ b/Visual Studio Projects/PDP10.vcproj @@ -239,6 +239,10 @@ RelativePath="..\PDP11\pdp11_cr.c" > + + @@ -300,6 +304,10 @@ RelativePath="..\PDP10\pdp10_defs.h" > + + diff --git a/Visual Studio Projects/PDP11.vcproj b/Visual Studio Projects/PDP11.vcproj index 88b22ab3..f903bfc6 100644 --- a/Visual Studio Projects/PDP11.vcproj +++ b/Visual Studio Projects/PDP11.vcproj @@ -219,6 +219,10 @@ RelativePath="..\PDP11\pdp11_dmc.c" > + + @@ -416,6 +420,10 @@ RelativePath="..\PDP11\pdp11_cr_dat.h" > + + diff --git a/Visual Studio Projects/VAX730.vcproj b/Visual Studio Projects/VAX730.vcproj index deff6aca..b876604d 100644 --- a/Visual Studio Projects/VAX730.vcproj +++ b/Visual Studio Projects/VAX730.vcproj @@ -206,6 +206,10 @@ RelativePath="..\PDP11\pdp11_dmc.c" > + + @@ -379,6 +383,10 @@ RelativePath="..\dec_dz.h" > + + diff --git a/Visual Studio Projects/VAX750.vcproj b/Visual Studio Projects/VAX750.vcproj index 7868d9fa..491836cf 100644 --- a/Visual Studio Projects/VAX750.vcproj +++ b/Visual Studio Projects/VAX750.vcproj @@ -206,6 +206,10 @@ RelativePath="..\PDP11\pdp11_dmc.c" > + + @@ -387,6 +391,10 @@ RelativePath="..\dec_dz.h" > + + diff --git a/Visual Studio Projects/VAX780.vcproj b/Visual Studio Projects/VAX780.vcproj index d52b7466..7d38ef3f 100644 --- a/Visual Studio Projects/VAX780.vcproj +++ b/Visual Studio Projects/VAX780.vcproj @@ -209,6 +209,10 @@ RelativePath="..\PDP11\pdp11_dmc.c" > + + @@ -399,6 +403,10 @@ RelativePath="..\PDP11\pdp11_cr_dat.h" > + + diff --git a/Visual Studio Projects/VAX8600.vcproj b/Visual Studio Projects/VAX8600.vcproj index 3a228b42..73afff04 100644 --- a/Visual Studio Projects/VAX8600.vcproj +++ b/Visual Studio Projects/VAX8600.vcproj @@ -209,6 +209,10 @@ RelativePath="..\PDP11\pdp11_dmc.c" > + + @@ -391,6 +395,10 @@ Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc" > + + diff --git a/descrip.mms b/descrip.mms index 9756beb6..c727c74f 100644 --- a/descrip.mms +++ b/descrip.mms @@ -534,7 +534,7 @@ 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_IO_LIB.C + $(PDP11_DIR)PDP11_DUP.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,\ @@ -561,7 +561,8 @@ PDP10_SOURCE = $(PDP10_DIR)PDP10_FE.C,\ $(PDP10_DIR)PDP10_RP.C,$(PDP10_DIR)PDP10_SYS.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_RY.C,$(PDP11_DIR)PDP11_CR.C,\ + $(PDP11_DIR)PDP11_DUP.C PDP10_OPTIONS = /INCL=($(SIMH_DIR),$(PDP10_DIR),$(PDP11_DIR))\ /DEF=($(CC_DEFS),"USE_INT64=1","VM_PDP10=1"$(PCAP_DEFS)) @@ -749,7 +750,7 @@ VAX730_SOURCE2 = $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_XU.C,$(PDP11_DIR)PDP11_RY.C,\ $(PDP11_DIR)PDP11_CR.C,$(PDP11_DIR)PDP11_HK.C,\ $(PDP11_DIR)PDP11_VH.C,$(PDP11_DIR)PDP11_DMC.C,\ - $(PDP11_DIR)PDP11_IO_LIB.C + $(PDP11_DIR)PDP11_DUP.C,$(PDP11_DIR)PDP11_IO_LIB.C .IFDEF ALPHA_OR_IA64 VAX730_OPTIONS = /INCL=($(SIMH_DIR),$(VAX730_DIR),$(PDP11_DIR)$(PCAP_INC))\ /DEF=($(CC_DEFS),"VM_VAX=1","USE_ADDR64=1","USE_INT64=1"$(PCAP_DEFS),"VAX_730=1") @@ -780,7 +781,7 @@ VAX750_SOURCE2 = $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_CR.C,$(PDP11_DIR)PDP11_HK.C,\ $(PDP11_DIR)PDP11_RP.C,$(PDP11_DIR)PDP11_TU.C,\ $(PDP11_DIR)PDP11_VH.C,$(PDP11_DIR)PDP11_DMC.C,\ - $(PDP11_DIR)PDP11_IO_LIB.C + $(PDP11_DIR)PDP11_DUP.C,$(PDP11_DIR)PDP11_IO_LIB.C .IFDEF ALPHA_OR_IA64 VAX750_OPTIONS = /INCL=($(SIMH_DIR),$(VAX750_DIR),$(PDP11_DIR)$(PCAP_INC))\ /DEF=($(CC_DEFS),"VM_VAX=1","USE_ADDR64=1","USE_INT64=1"$(PCAP_DEFS),"VAX_750=1") @@ -811,7 +812,7 @@ VAX780_SOURCE2 = $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_CR.C,$(PDP11_DIR)PDP11_RP.C,\ $(PDP11_DIR)PDP11_TU.C,$(PDP11_DIR)PDP11_HK.C,\ $(PDP11_DIR)PDP11_VH.C,$(PDP11_DIR)PDP11_DMC.C,\ - $(PDP11_DIR)PDP11_IO_LIB.C + $(PDP11_DIR)PDP11_DUP.C,$(PDP11_DIR)PDP11_IO_LIB.C .IFDEF ALPHA_OR_IA64 VAX780_OPTIONS = /INCL=($(SIMH_DIR),$(VAX780_DIR),$(PDP11_DIR)$(PCAP_INC))\ /DEF=($(CC_DEFS),"VM_VAX=1","USE_ADDR64=1","USE_INT64=1"$(PCAP_DEFS),"VAX_780=1") @@ -842,7 +843,7 @@ VAX8600_SOURCE2 = $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_CR.C,$(PDP11_DIR)PDP11_RP.C,\ $(PDP11_DIR)PDP11_TU.C,$(PDP11_DIR)PDP11_HK.C,\ $(PDP11_DIR)PDP11_VH.C,$(PDP11_DIR)PDP11_DMC.C,\ - $(PDP11_DIR)PDP11_IO_LIB.C + $(PDP11_DIR)PDP11_DUP.C,$(PDP11_DIR)PDP11_IO_LIB.C .IFDEF ALPHA_OR_IA64 VAX8600_OPTIONS = /INCL=($(SIMH_DIR),$(VAX8600_DIR),$(PDP11_DIR)$(PCAP_INC))\ /DEF=($(CC_DEFS),"VM_VAX=1","USE_ADDR64=1","USE_INT64=1"$(PCAP_DEFS),"VAX_860=1") diff --git a/doc/simh_doc.doc b/doc/simh_doc.doc index 02cec35b..ad8c0810 100644 Binary files a/doc/simh_doc.doc and b/doc/simh_doc.doc differ diff --git a/makefile b/makefile index 33f08919..b7d0e7a9 100644 --- a/makefile +++ b/makefile @@ -399,7 +399,11 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) ifneq (,$(call find_include,libvdeplug)) # Provide support for vde networking NETWORK_CCDEFS += -DUSE_VDE_NETWORK - NETWORK_LDFLAGS += -lvdeplug -Wl,-R,$(dir $(call find_lib,vdeplug)) -L$(dir $(call find_lib,vdeplug)) + ifeq (Darwin,$(OSTYPE)) + NETWORK_LDFLAGS += -lvdeplug -L$(dir $(call find_lib,vdeplug)) + else + NETWORK_LDFLAGS += -lvdeplug -Wl,-R,$(dir $(call find_lib,vdeplug)) -L$(dir $(call find_lib,vdeplug)) + endif $(info using libvdeplug: $(call find_lib,vdeplug) $(call find_include,libvdeplug)) endif endif @@ -661,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_io_lib.c + ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_io_lib.c PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT} @@ -711,7 +715,7 @@ VAX730 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_hk.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c \ - ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_io_lib.c VAX730_OPT = -DVM_VAX -DVAX_730 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} @@ -725,7 +729,8 @@ VAX750 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_hk.c ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_tu.c \ - ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_dup.c \ + ${PDP11D}/pdp11_io_lib.c VAX750_OPT = -DVM_VAX -DVAX_750 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} @@ -739,7 +744,8 @@ VAX780 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_tu.c ${PDP11D}/pdp11_hk.c \ - ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_dup.c \ + ${PDP11D}/pdp11_io_lib.c VAX780_OPT = -DVM_VAX -DVAX_780 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} @@ -753,7 +759,8 @@ VAX8600 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_tu.c ${PDP11D}/pdp11_hk.c \ - ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_dup.c \ + ${PDP11D}/pdp11_io_lib.c VAX8600_OPT = -DVM_VAX -DVAX_860 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} @@ -762,7 +769,8 @@ PDP10 = ${PDP10D}/pdp10_fe.c ${PDP11D}/pdp11_dz.c ${PDP10D}/pdp10_cpu.c \ ${PDP10D}/pdp10_ksio.c ${PDP10D}/pdp10_lp20.c ${PDP10D}/pdp10_mdfp.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_pt.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ + ${PDP11D}/pdp11_dup.c PDP10_OPT = -DVM_PDP10 -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} diff --git a/scp.c b/scp.c index 8f5a3bf0..57252fbc 100644 --- a/scp.c +++ b/scp.c @@ -6431,8 +6431,9 @@ return 0; double sim_gtime (void) { -if (AIO_MAIN_THREAD) +if (AIO_MAIN_THREAD) { UPDATE_SIM_TIME; + } return sim_time; } diff --git a/sim_console.c b/sim_console.c index 6f072a3d..544e45b8 100644 --- a/sim_console.c +++ b/sim_console.c @@ -518,6 +518,7 @@ t_bool stepping = FALSE; int32 steps = 1; t_bool was_stepping = (sim_rem_step_line != -1); t_bool got_command; +t_bool close_session = FALSE; TMLN *lp; char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], *cptr, *argv[1] = {NULL}; CTAB *cmdp; @@ -535,15 +536,15 @@ for (i=(was_stepping ? sim_rem_step_line : 0); sim_rem_step_line = -1; /* Done with step */ stat = SCPE_STEP; cmdp = find_cmd ("STEP"); - stat_nomessage = stat & SCPE_NOMESSAGE; /* extract possible message supression flag */ - stat = SCPE_BARE_STATUS(stat); /* remove possible flag */ - if (!stat_nomessage) { /* displaying message status? */ + stat_nomessage = stat & SCPE_NOMESSAGE; /* extract possible message supression flag */ + stat = SCPE_BARE_STATUS(stat); /* remove possible flag */ + if (!stat_nomessage) { /* displaying message status? */ fflush (sim_log); cmd_log_start = sim_ftell (sim_log); - if (cmdp && (cmdp->message)) /* special message handler? */ - cmdp->message (NULL, stat); /* let it deal with display */ + if (cmdp && (cmdp->message)) /* special message handler? */ + cmdp->message (NULL, stat); /* let it deal with display */ else - if (stat >= SCPE_BASE) { /* error? */ + if (stat >= SCPE_BASE) { /* error? */ printf ("%s\r\n", sim_error_text (stat)); if (sim_log) fprintf (sim_log, "%s\n", sim_error_text (stat)); @@ -579,6 +580,12 @@ for (i=(was_stepping ? sim_rem_step_line : 0); tmxr_linemsgf (lp, "Simulation will resume automatically if input is not received in %d seconds\n", sim_rem_read_timeout); } else { + if ((c == '\004') || (c == '\032')) { /* EOF character (^D or ^Z) ? */ + tmxr_linemsgf (lp, "\r\nGoodbye\r\n"); + tmxr_send_buffered_data (lp); /* flush any buffered data */ + tmxr_reset_ln (lp); + continue; + } sim_rem_single_mode[i] = TRUE; tmxr_linemsgf (lp, "\r\n%s", sim_prompt); tmxr_send_buffered_data (lp); /* flush any buffered data */ @@ -648,6 +655,23 @@ for (i=(was_stepping ? sim_rem_step_line : 0); sim_rem_buf[i][sim_rem_buf_ptr[i]++] = '\0'; got_command = TRUE; break; + case '\004': /* EOF (^D) */ + case '\032': /* EOF (^Z) */ + while (sim_rem_buf_ptr[i] > 0) { /* Erase current input line */ + tmxr_linemsg (lp, "\b \b"); + --sim_rem_buf_ptr[i]; + } + if (!sim_rem_single_mode[i]) { + if (sim_rem_buf_ptr[i]+80 >= sim_rem_buf_size[i]) { + sim_rem_buf_size[i] += 1024; + sim_rem_buf[i] = realloc (sim_rem_buf[i], sim_rem_buf_size[i]); + } + strcpy (sim_rem_buf[i], "CONTINUE ! Automatic continue before close"); + tmxr_linemsgf (lp, "%s\n", sim_rem_buf[i]); + got_command = TRUE; + } + close_session = TRUE; + break; default: tmxr_putc_ln (lp, c); if (sim_rem_buf_ptr[i]+2 >= sim_rem_buf_size[i]) { @@ -662,8 +686,9 @@ for (i=(was_stepping ? sim_rem_step_line : 0); } } while ((!got_command) && (!sim_rem_single_mode[i])); tmxr_send_buffered_data (lp); /* flush any buffered data */ - if ((sim_rem_single_mode[i]) && !got_command) + if ((sim_rem_single_mode[i]) && !got_command) { break; + } printf ("Remote Console Command from %s> %s\r\n", lp->ipad, sim_rem_buf[i]); if (sim_log) fprintf (sim_log, "Remote Console Command from %s> %s\n", lp->ipad, sim_rem_buf[i]); @@ -679,13 +704,14 @@ for (i=(was_stepping ? sim_rem_step_line : 0); strcpy (cbuf, sim_rem_buf[i]); sim_rem_buf_ptr[i] = 0; sim_rem_buf[i][sim_rem_buf_ptr[i]] = '\0'; - if (cbuf[0] == '\0') + if (cbuf[0] == '\0') { if (sim_rem_single_mode[i]) { sim_rem_single_mode[i] = FALSE; break; } else continue; + } sim_sub_args (cbuf, sizeof(cbuf), argv); cptr = cbuf; cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ @@ -790,6 +816,11 @@ for (i=(was_stepping ? sim_rem_step_line : 0); break; } } + if (close_session) { + tmxr_linemsgf (lp, "\r\nGoodbye\r\n"); + tmxr_send_buffered_data (lp); /* flush any buffered data */ + tmxr_reset_ln (lp); + } } if (stepping) sim_activate(uptr, steps); /* check again after 'steps' instructions */ diff --git a/sim_tmxr.c b/sim_tmxr.c index 38802e55..d9062879 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -436,13 +436,15 @@ lp->tsta = 0; /* init telnet state */ lp->xmte = 1; /* enable transmit */ lp->dstb = 0; /* default bin mode */ lp->rxbpr = lp->rxbpi = lp->rxcnt = 0; /* init receive indexes */ -if (!lp->txbfd) /* if not buffered */ +if (!lp->txbfd || lp->notelnet) /* if not buffered telnet */ lp->txbpr = lp->txbpi = lp->txcnt = 0; /* init transmit indexes */ memset (lp->rbr, 0, sizeof(lp->rbr)); /* clear break status array */ lp->txdrp = 0; -if (lp->modem_control) - lp->modembits = TMXR_MDM_CTS | TMXR_MDM_DSR; -if (!lp->mp->buffered) { +if (lp->modem_control) { + lp->modembits &= ~TMXR_MDM_INCOMING; + lp->modembits |= TMXR_MDM_CTS | TMXR_MDM_DSR; + } +if ((!lp->mp->buffered) && (!lp->txbfd)) { lp->txbfd = 0; lp->txbsz = TMXR_MAXBUF; lp->txb = (char *)realloc (lp->txb, lp->txbsz); @@ -695,7 +697,7 @@ static char *growstring(char **string, size_t growth) return *string + strlen(*string); } -static char *_mux_attach_string(char *old, TMXR *mp) +static char *tmxr_mux_attach_string(char *old, TMXR *mp) { char* tptr = NULL; int32 i; @@ -767,6 +769,10 @@ if (lp->destination || lp->port || lp->txlogname) { sprintf (growstring(&tptr, 32), "Line=%d", (int)(lp-lp->mp->ldsc)); if (lp->modem_control != lp->mp->modem_control) sprintf (growstring(&tptr, 32), ",%s", lp->modem_control ? "Modem" : "NoModem"); + if (lp->txbfd && (lp->txbsz != lp->mp->buffered)) + sprintf (growstring(&tptr, 32), ",Buffered=%d", lp->txbsz); + if (!lp->txbfd && (lp->mp->buffered > 0)) + sprintf (growstring(&tptr, 32), ",UnBuffered"); if (lp->destination) { if (lp->serport) { char portname[CBUFSIZE]; @@ -1091,7 +1097,7 @@ if ((lp->destination) && (!lp->serport)) { tmxr_init_line (lp); /* initialize line state */ if (lp->mp->uptr) { /* Revise the unit's connect string to reflect the current attachments */ - lp->mp->uptr->filename = _mux_attach_string (lp->mp->uptr->filename, lp->mp); + lp->mp->uptr->filename = tmxr_mux_attach_string (lp->mp->uptr->filename, lp->mp); /* No connections or listeners exist, then we're equivalent to being fully detached. We should reflect that */ if (lp->mp->uptr->filename == NULL) tmxr_detach (lp->mp, lp->mp->uptr); @@ -1272,7 +1278,7 @@ else { r = SCPE_OK; } if (r == SCPE_OK) /* Record port state for proper restore */ - lp->mp->uptr->filename = _mux_attach_string (lp->mp->uptr->filename, lp->mp); + lp->mp->uptr->filename = tmxr_mux_attach_string (lp->mp->uptr->filename, lp->mp); return r; } @@ -1342,7 +1348,7 @@ for (i = 0; i < mp->lines; i++) { /* loop thru lines */ TMXR_MAXBUF - lp->rxbpi); if (nbytes < 0) { /* line error? */ - if (!lp->txbfd) + if (!lp->txbfd || lp->notelnet) lp->txbpi = lp->txbpr = 0; /* Drop the data we already know we can't send */ tmxr_close_ln (lp); /* disconnect line */ } @@ -1493,8 +1499,8 @@ return (lp->rxbpi - lp->rxbpr + ((lp->rxbpi < lp->rxbpr)? TMXR_MAXBUF: 0)); t_stat tmxr_putc_ln (TMLN *lp, int32 chr) { -if ((lp->conn == FALSE) && /* no conn & not buffered? */ - (!lp->txbfd)) { +if ((lp->conn == FALSE) && /* no conn & not buffered telnet? */ + (!lp->txbfd || lp->notelnet)) { ++lp->txdrp; /* lost */ return SCPE_LOST; } @@ -1506,8 +1512,8 @@ tmxr_debug_trace_line (lp, "tmxr_putc_ln()"); if (lp->txbpi == lp->txbpr) \ lp->txbpr = (1+lp->txbpr)%lp->txbsz, ++lp->txdrp; \ } -if ((lp->txbfd) || (TXBUF_AVAIL(lp) > 1)) { /* room for char (+ IAC)? */ - if ((TN_IAC == (u_char) chr) && (!lp->notelnet)) /* char == IAC in telnet session? */ +if ((lp->txbfd && !lp->notelnet) || (TXBUF_AVAIL(lp) > 1)) {/* room for char (+ IAC)? */ + if ((TN_IAC == (u_char) chr) && (!lp->notelnet)) /* char == IAC in telnet session? */ TXBUF_CHAR (lp, TN_IAC); /* stuff extra IAC char */ TXBUF_CHAR (lp, chr); /* buffer char & adv pointer */ if ((!lp->txbfd) && (TXBUF_AVAIL (lp) <= TMXR_GUARD))/* near full? */ @@ -1811,7 +1817,7 @@ while (*tptr) { sim_close_sock (sock, 1); strcpy(listen, port); cptr = get_glyph (cptr, option, ';'); - if (option[0]) + if (option[0]) { if (0 == MATCH_CMD (option, "NOTELNET")) listennotelnet = TRUE; else @@ -1819,6 +1825,7 @@ while (*tptr) { listennotelnet = FALSE; else return SCPE_ARG; + } } if (line == -1) { if (modem_control != mp->modem_control) @@ -2783,7 +2790,7 @@ r = tmxr_open_master (mp, cptr); /* open master socket */ if (r != SCPE_OK) /* error? */ return r; mp->uptr = uptr; /* save unit for polling */ -uptr->filename = _mux_attach_string (uptr->filename, mp);/* save */ +uptr->filename = tmxr_mux_attach_string (uptr->filename, mp);/* save */ uptr->flags = uptr->flags | UNIT_ATT; /* no more errors */ if ((mp->lines > 1) || ((mp->master == 0) && @@ -2828,9 +2835,12 @@ else { for (i=0; idptr->name); - fprintf(st, ", attached to %s, ", mp->uptr->filename); + fprintf(st, "Multiplexer device: %s, ", mp->dptr->name); + attach = tmxr_mux_attach_string (NULL, mp); + fprintf(st, "attached to %s, ", attach); + free (attach); if (mp->lines > 1) { tmxr_show_lines(st, NULL, 0, mp); fprintf(st, ", "); @@ -3427,7 +3437,7 @@ if (lp->txlog == NULL) { /* error? */ free (lp->txlogname); /* free buffer */ return SCPE_OPENERR; } -lp->mp->uptr->filename = _mux_attach_string (lp->mp->uptr->filename, lp->mp); +lp->mp->uptr->filename = tmxr_mux_attach_string (lp->mp->uptr->filename, lp->mp); return SCPE_OK; } @@ -3450,7 +3460,7 @@ if (lp->txlog) { /* logging? */ lp->txlog = NULL; lp->txlogname = NULL; } -lp->mp->uptr->filename = _mux_attach_string (lp->mp->uptr->filename, lp->mp); +lp->mp->uptr->filename = tmxr_mux_attach_string (lp->mp->uptr->filename, lp->mp); return SCPE_OK; }