From 48830b9ab91cc7eb80c1a46173ae07cd35e7de0e Mon Sep 17 00:00:00 2001 From: Patrick Linstruth Date: Thu, 18 Jul 2024 19:19:04 -0400 Subject: [PATCH] Release V3.12-5 --- H316/h316_mt.c | 7 +- NOVA/nova_mta.c | 5 +- PDP10/pdp10_defs.h | 9 +- PDP10/pdp10_rp.c | 12 +- PDP10/pdp10_sys.c | 5 +- PDP10/pdp10_tu.c | 59 +- PDP11/pdp11_ch.c | 560 +++++++++++ PDP11/pdp11_cpu.c | 117 ++- PDP11/pdp11_cpumod.c | 12 +- PDP11/pdp11_defs.h | 21 +- PDP11/pdp11_dz.c | 12 +- PDP11/pdp11_fp.c | 5 +- PDP11/pdp11_io.c | 3 +- PDP11/pdp11_rf.c | 5 +- PDP11/pdp11_rh.c | 56 +- PDP11/pdp11_rk.c | 2 +- PDP11/pdp11_rr.c | 1265 +++++++++++++++++++++++++ PDP11/pdp11_sys.c | 13 +- PDP11/pdp11_ts.c | 93 +- PDP11/pdp11_tu.c | 44 +- PDP18B/pdp18b_fpp.c | 5 +- PDP8/pdp8_mt.c | 7 +- PDP8/pdp8_sys.c | 5 +- SDS/sds_cpu.c | 25 +- SDS/sds_cr.c | 5 +- SDS/sds_mt.c | 9 +- descrip.mms | 6 +- makefile | 32 +- scp.c | 113 ++- scp.h | 5 +- sigma/Design Notes on the Sigma 7.doc | Bin 30208 -> 31232 bytes sigma/sigma_bugs.txt | 38 +- sigma/sigma_coc.c | 21 +- sigma/sigma_cp.c | 337 +++++++ sigma/sigma_cpu.c | 14 +- sigma/sigma_cr.c | 435 +++++++++ sigma/sigma_dk.c | 29 +- sigma/sigma_dp.c | 64 +- sigma/sigma_io.c | 83 +- sigma/sigma_io_defs.h | 10 +- sigma/sigma_lp.c | 33 +- sigma/sigma_mt.c | 37 +- sigma/sigma_pt.c | 10 +- sigma/sigma_rad.c | 46 +- sigma/sigma_sys.c | 74 +- sigma/sigma_tt.c | 10 +- sim_console.c | 56 +- sim_defs.h | 4 +- sim_rev.h | 10 +- sim_sock.c | 5 +- sim_tape.c | 11 +- sim_tmxr.c | 146 ++- sim_tmxr.h | 17 +- 53 files changed, 3634 insertions(+), 373 deletions(-) create mode 100644 PDP11/pdp11_ch.c create mode 100644 PDP11/pdp11_rr.c create mode 100644 sigma/sigma_cp.c create mode 100644 sigma/sigma_cr.c diff --git a/H316/h316_mt.c b/H316/h316_mt.c index 731e207b4..f5efd6a5d 100644 --- a/H316/h316_mt.c +++ b/H316/h316_mt.c @@ -1,6 +1,6 @@ /* h316_mt.c: H316/516 magnetic tape simulator - Copyright (c) 2003-2022, Robert M. Supnik + Copyright (c) 2003-2023, 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 @@ mt 516-4100 seven track magnetic tape + 01-Nov-23 RMS Reset should use sim_tape_bot 26-Mar-22 RMS Added extra case points for new MTSE definitions 03-Jul-13 RLA compatibility changes for extended interrupts 19-Mar-12 RMS Fixed declaration of chan_req (Mark Pizzolato) @@ -590,7 +591,9 @@ for (i = 0; i < MT_NUMDR; i++) { /* loop thru units */ uptr = mt_dev.units + i; sim_tape_reset (uptr); /* reset tape */ sim_cancel (uptr); /* cancel op */ - uptr->UST = uptr->pos? 0: STA_BOT; /* update status */ + if ((uptr->flags & UNIT_ATT) && sim_tape_bot (uptr)) + uptr->UST = STA_BOT; + else uptr->UST = 0; uptr->FNC = FNC_NOP; } return SCPE_OK; diff --git a/NOVA/nova_mta.c b/NOVA/nova_mta.c index b7277a919..09d3fe971 100644 --- a/NOVA/nova_mta.c +++ b/NOVA/nova_mta.c @@ -1,6 +1,6 @@ /* nova_mta.c: NOVA magnetic tape simulator - Copyright (c) 1993-2022, Robert M. Supnik + Copyright (c) 1993-2023, 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 @@ mta magnetic tape + 02-Nov-23 RMS Mode change should test STA_BOT, not sim_tape_BOT 26-Mar-22 RMS Added extra case points for new MTSE definitions 23-Mar-20 RMS Unload should call sim_tape_detach (Mark Pizzolato) 13-Mar-17 RMS Annotated fall through in switch @@ -371,7 +372,7 @@ else switch (c) { /* case on command */ break; case CU_DMODE: /* drive mode */ - if (!sim_tape_bot (uptr)) /* must be BOT */ + if ((uptr->USTAT & STA_BOT) == 0) /* must be BOT */ mta_sta = mta_sta | STA_ILL; else mta_upddsta (uptr, (mta_cu & CU_PE)? /* update drv status */ uptr->USTAT | STA_PEM: uptr->USTAT & ~ STA_PEM); diff --git a/PDP10/pdp10_defs.h b/PDP10/pdp10_defs.h index 028a2b91c..581401ef8 100644 --- a/PDP10/pdp10_defs.h +++ b/PDP10/pdp10_defs.h @@ -1,6 +1,6 @@ /* pdp10_defs.h: PDP-10 simulator definitions - Copyright (c) 1993-2017, Robert M Supnik + Copyright (c) 1993-2024, 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. + 05-May-24 RMS Merged CH11 (Lars Brinkhoff) 19-Jan-17 RMS Fixed CD11 definition (Mark Pizzolatto) 30-Jun-13 RMS Fixed IPL4 mask definition (Tim Litt) 22-May-10 RMS Added check for 64b addresses @@ -683,6 +684,8 @@ typedef struct pdp_dib DIB; #define IOLN_PTR 004 #define IOBA_PTP (IO_UBA3 + 017554) /* PC11 punch */ #define IOLN_PTP 004 +#define IOBA_CH (IO_UBA3 + 0764140) /* CH11 Chaosnet */ +#define IOLN_CH 020 /* Common Unibus CSR flags */ @@ -721,6 +724,7 @@ typedef struct pdp_dib DIB; #define INT_V_CR 27 /* CD20 (CD11) */ #define INT_V_DUPRX 28 /* DUP11 */ #define INT_V_DUPTX 29 +#define INT_V_CH 30 #define INT_RP (1u << INT_V_RP) #define INT_TU (1u << INT_V_TU) @@ -738,6 +742,7 @@ typedef struct pdp_dib DIB; #define INT_CR (1u << INT_V_CD) #define INT_DUPRX (1u << INT_V_DUPRX) #define INT_DUPTX (1u << INT_V_DUPTX) +#define INT_CH (1u << INT_V_CH) #define IPL_RP 6 /* int levels */ #define IPL_TU 6 @@ -750,6 +755,7 @@ typedef struct pdp_dib DIB; #define IPL_RY 5 #define IPL_DUPRX 5 #define IPL_DUPTX 5 +#define IPL_CH 5 #define IPL_PTR 4 #define IPL_PTP 4 #define IPL_LP20 4 @@ -771,6 +777,7 @@ typedef struct pdp_dib DIB; #define VEC_CR 0230 #define VEC_RP 0254 #define VEC_RY 0264 +#define VEC_CH 0270 #define VEC_DZRX 0340 #define VEC_DZTX 0344 #define VEC_LP20 0754 diff --git a/PDP10/pdp10_rp.c b/PDP10/pdp10_rp.c index 070640c10..d369970e7 100644 --- a/PDP10/pdp10_rp.c +++ b/PDP10/pdp10_rp.c @@ -1123,12 +1123,12 @@ for (i = 0; i < RP_NUMDR; i++) { if (uptr->flags & UNIT_ATT) if (uptr->flags & UNIT_UTS) { sim_cancel (uptr); - rpds[i] = (rpds[i] & DS_VV) | DS_DPR | DS_RDY | DS_MOL | + rpds[i] = (rpds[i] & DS_VV) | DS_DPR | DS_RDY | DS_MOL | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); } else { if (!sim_is_active (uptr)) sim_activate (uptr, SPINUP_DLY); - rpds[i] = DS_DPR | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); + rpds[i] = DS_DPR | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); } else { sim_cancel (uptr); @@ -1194,10 +1194,10 @@ rpds[drv] = (rpds[drv] & ~(DS_MOL | DS_RDY | DS_WRL | DS_VV | DS_OF)) | if (sim_is_active (uptr)) { /* unit active? */ sim_cancel (uptr); /* cancel operation */ if (uptr->flags & UNIT_UTS) { - rper1[drv] = rper1[drv] | ER1_OPI; /* set drive error */ - if (uptr->FUNC >= FNC_WCHK) /* data transfer? */ - rpcs1 = rpcs1 | CS1_DONE | CS1_TRE; /* set done, err */ - } + rper1[drv] = rper1[drv] | ER1_OPI; /* set drive error */ + if (uptr->FUNC >= FNC_WCHK) /* data transfer? */ + rpcs1 = rpcs1 | CS1_DONE | CS1_TRE; /* set done, err */ + } } uptr->flags &= ~UNIT_UTS; update_rpcs (0, drv); /* request intr */ diff --git a/PDP10/pdp10_sys.c b/PDP10/pdp10_sys.c index 5f4239c0e..ae9ffdc57 100644 --- a/PDP10/pdp10_sys.c +++ b/PDP10/pdp10_sys.c @@ -1,6 +1,6 @@ /* pdp10_sys.c: PDP-10 simulator interface - Copyright (c) 1993-2017, Robert M Supnik + Copyright (c) 1993-2024, 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. + 05-May-24 RMS Merged CH11 (Lars Brinkhoff) 09-Mar-17 RMS Added mask on EXE repeat count (COVERITY) Fixed word count test in EXE loader (COVERITY) 20-Jan-17 RMS Fixed RIM loader to handle ITS and RIM10B formats @@ -58,6 +59,7 @@ extern DEVICE dz_dev; extern DEVICE ry_dev; extern DEVICE cr_dev; extern DEVICE lp20_dev; +extern DEVICE ch_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern d10 *M; @@ -93,6 +95,7 @@ DEVICE *sim_devices[] = { &rp_dev, &tu_dev, &dz_dev, + &ch_dev, NULL }; diff --git a/PDP10/pdp10_tu.c b/PDP10/pdp10_tu.c index e1568c0ad..f41d40e59 100644 --- a/PDP10/pdp10_tu.c +++ b/PDP10/pdp10_tu.c @@ -1,6 +1,6 @@ /* pdp10_tu.c - PDP-10 RH11/TM03/TU45 magnetic tape simulator - Copyright (c) 1993-2022, Robert M Supnik + Copyright (c) 1993-2023, 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 @@ tu RH11/TM03/TU45 magtape + 06-Nov-23 RMS Fixed BOT logic 26-Mar-22 RMS Added extra case points for new MTSE definitions 07-Sep-20 RMS Fixed || -> | in macro (Mark Pizzolato) 23-Mar-20 RMS Unload should call sim_tape_detach (Mark Pizzolato) @@ -95,6 +96,10 @@ level sensitive. - The DONE interrupt, once set, is not disabled if IE is cleared, but the SC interrupt is. + + BOT is not the same as POS == 0. BOT is set after rewinding or after + a reverse operation from before the first record. It is cleared by + any successful motion operation. */ #include "pdp10_defs.h" @@ -185,7 +190,7 @@ */ #define FS_SAT 0000001 /* slave attention */ -#define FS_BOT 0000002 /* ^beginning of tape */ +#define FS_BOT 0000002 /* +beginning of tape */ #define FS_TMK 0000004 /* end of file */ #define FS_ID 0000010 /* ID burst detected */ #define FS_SLOW 0000020 /* slowing down NI */ @@ -193,7 +198,7 @@ #define FS_SSC 0000100 /* slave stat change */ #define FS_RDY 0000200 /* ^formatter ready */ #define FS_FPR 0000400 /* formatter present */ -#define FS_EOT 0002000 /* +end of tape */ +#define FS_EOT 0002000 /* ^end of tape */ #define FS_WRL 0004000 /* ^write locked */ #define FS_MOL 0010000 /* ^medium online */ #define FS_PIP 0020000 /* +pos in progress */ @@ -678,7 +683,7 @@ switch (fnc) { /* case on function */ tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR); if (!(uptr->TU_STATEFLAGS & TUS_ATTPENDING)) sim_cancel (uptr); /* stop motion, not on-line delay */ - uptr->USTAT = 0; /* fall through */ + uptr->USTAT &= FS_BOT; /* fall through */ case FNC_NOP: tucs1 = tucs1 & ~CS1_GO; /* no operation */ return; @@ -689,8 +694,10 @@ switch (fnc) { /* case on function */ break; } tutc = TC_RIP; /* density = 800 */ - sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */ - tu_unit[0].USTAT = 0; + if (tu_unit[0].flags & UNIT_ATT) { /* attached? */ + sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */ + tu_unit[0].USTAT = FS_BOT; + } tucs1 = tucs1 & ~CS1_GO; tufs = tufs & ~FS_TMK; return; @@ -735,7 +742,7 @@ switch (fnc) { /* case on function */ set_tuer (ER_UNS); break; } - if (sim_tape_bot (uptr) || ((tutc & TC_FCS) == 0)) { + if ((uptr->USTAT & FS_BOT) || ((tutc & TC_FCS) == 0)) { set_tuer (ER_NXF); break; } @@ -763,7 +770,7 @@ switch (fnc) { /* case on function */ case FNC_WCHKR: /* wchk = read */ case FNC_READR: /* read rev */ - if (tufs & FS_BOT) { /* beginning of tape? */ + if (uptr->USTAT & FS_BOT) { /* beginning of tape? */ set_tuer (ER_NXF); break; } @@ -837,7 +844,9 @@ if (uptr->TU_STATEFLAGS & TUS_ATTPENDING) { if (uptr->USTAT & FS_REW) { /* rewind or unload? */ sim_tape_rewind (uptr); /* rewind tape */ - uptr->USTAT = 0; /* clear status */ + if (uptr->flags & UNIT_ATT) /* attached? */ + uptr->USTAT = FS_BOT; /* set BOT */ + else uptr->USTAT = 0; /* clear status */ tufs = tufs | FS_ATA | FS_SSC; update_tucs (CS1_SC, drv); /* update status */ return SCPE_OK; @@ -1043,23 +1052,19 @@ if ((flag & ~tucs1) & CS1_DONE) /* DONE 0 to 1? */ tuiff = (tucs1 & CS1_IE)? 1: 0; /* CSTB INTR <- IE */ if (GET_FMTR (tucs2) == 0) { /* formatter present? */ tufs = (tufs & ~FS_DYN) | FS_FPR; - if (tu_unit[drv].TU_STATEFLAGS & TUS_ATTPENDING) /* Delayed on-line timer running? */ - act = 0; /* Not a tape motion op */ + if (tu_unit[drv].TU_STATEFLAGS & TUS_ATTPENDING) /* delayed on-line timer running? */ + act = 0; /* bot a tape motion op */ else { - if (tu_unit[drv].flags & UNIT_ATT) { - tufs = tufs | FS_MOL | tu_unit[drv].USTAT; - if (tu_unit[drv].UDENS == TC_1600) - tufs = tufs | FS_PE; - if (sim_tape_wrp (&tu_unit[drv])) - tufs = tufs | FS_WRL; - if (!act) { - if (sim_tape_bot (&tu_unit[drv])) - tufs = tufs | FS_BOT; - if (sim_tape_eot (&tu_unit[drv])) + if (tu_unit[drv].flags & UNIT_ATT) { + tufs = tufs | FS_MOL | (tu_unit[drv].USTAT & 0177777); + if (tu_unit[drv].UDENS == TC_1600) + tufs = tufs | FS_PE; + if (sim_tape_wrp (&tu_unit[drv])) + tufs = tufs | FS_WRL; + if (!act && sim_tape_eot (&tu_unit[drv])) tufs = tufs | FS_EOT; } } - } if (tuer) tufs = tufs | FS_ERR; } @@ -1140,6 +1145,7 @@ switch (st) { break; case MTSE_BOT: /* reverse into BOT */ + uptr->USTAT = FS_BOT; /* set BOT */ break; case MTSE_WRP: /* write protect */ @@ -1178,8 +1184,9 @@ for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */ sim_cancel (uptr); /* cancel activity */ else if (!sim_is_active(uptr) ) sim_activate (uptr, SPINUPDLY); - - uptr->USTAT = 0; + if ((uptr->flags & UNIT_ATT) && sim_tape_bot (uptr)) + uptr->USTAT = FS_BOT; + else uptr->USTAT = 0; } if (xbuf == NULL) xbuf = (uint8 *) calloc (MT_MAXFR + 4, sizeof (uint8)); @@ -1198,7 +1205,7 @@ t_stat r; r = sim_tape_attach (uptr, cptr); if (r != SCPE_OK) return r; -uptr->USTAT = 0; /* clear unit status */ +uptr->USTAT = FS_BOT; /* set BOT */ uptr->UDENS = UD_UNK; /* unknown density */ /* Delay setting MOL since we may have just detached a previous file. * In that case, the OS must see MOL clear, so that it will know that the @@ -1244,7 +1251,7 @@ return sim_tape_detach (uptr); } /* Device bootstrap */ -/* Note that the dec and ITS boot code is word for word identical, +/* Note that the DEC and ITS boot code is word for word identical, * except for the IO instructions. The ITS instructions encode the * UBA number. No attempt is made to allow UBA selection under ITS, * though it should work with the DEC rom. diff --git a/PDP11/pdp11_ch.c b/PDP11/pdp11_ch.c new file mode 100644 index 000000000..5f9310e60 --- /dev/null +++ b/PDP11/pdp11_ch.c @@ -0,0 +1,560 @@ +/* pdp11_ch.c: CH11 Chaosnet interface. + ------------------------------------------------------------------------------ + + Copyright (c) 2018, 2020, 2023, Lars Brinkhoff. + + 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 + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + ------------------------------------------------------------------------------ + +*/ + +#if defined (VM_PDP11) +#include "pdp11_defs.h" +extern int32 int_req[IPL_HLVL]; + +#elif defined (VM_PDP10) +#include "pdp10_defs.h" +extern int32 int_req; + +#elif defined (VM_VAX) +#include "vax_defs.h" +extern int32 int_req[IPL_HLVL]; + +#else +#error The CH11 device only works with Unibus machines. +#endif + +#include "sim_tmxr.h" + +/* CSR bits */ +#define TIE 0000001 /* Timer interrupt enable */ +#define LOOP 0000002 /* Loop back */ +#define SPY 0000004 /* Loop back */ +#define CRX 0000010 /* Clear receiver */ +#define RXIE 0000020 /* Receive interrupt enable */ +#define TXIE 0000040 /* Transmit interrupt enable */ +#define TXA 0000100 /* Transmit abort */ +#define TXD 0000200 /* Transmit done */ +#define CTX 0000400 /* Clear transmitter */ +#define LOST 0017000 /* Lost count */ +#define RESET 0020000 /* Reset */ +#define CRC 0040000 /* CRC error */ +#define RXD 0100000 /* Receive done */ + +#define STATUS_BITS (TIE|LOOP|SPY|RXIE|TXIE|TXA|TXD|LOST|CRC|RXD) +#define COMMAND_BITS (TIE|LOOP|SPY|RXIE|TXIE) + +#define CHUDP_HEADER 4 +#define DBG_TRC 0x0001 +#define DBG_REG 0x0002 +#define DBG_PKT 0x0004 +#define DBG_DAT 0x0008 +#define DBG_INT 0x0010 +#define DBG_ERR 0x0020 + +t_stat ch_svc(UNIT *); +t_stat ch_reset (DEVICE *); +t_stat ch_attach (UNIT *, CONST char *); +t_stat ch_detach (UNIT *); +int32 ch_inta (void); +void ch_test_int (void); +t_stat ch_rd(int32 *, int32, int32); +t_stat ch_wr(int32, int32, int32); +t_stat ch_show_peer (FILE* st, UNIT* uptr, int32 val, CONST void* desc); +t_stat ch_set_peer (UNIT* uptr, int32 val, CONST char* cptr, void* desc); +t_stat ch_show_node (FILE* st, UNIT* uptr, int32 val, CONST void* desc); +t_stat ch_set_node (UNIT* uptr, int32 val, CONST char* cptr, void* desc); +t_stat ch_help (FILE *, DEVICE *, UNIT *, int32, CONST char *); +t_stat ch_help_attach (FILE *, DEVICE *, UNIT *, int32, CONST char *); +CONST char *ch_description (DEVICE *); + +#define CH11_NO_ADDRESS 0XFFFF + +static char peer[256]; +static uint16 status; +static uint16 address = CH11_NO_ADDRESS; +static uint16 rx_count; +static uint16 tx_count; +static uint8 rx_buffer[512+100]; +static uint8 tx_buffer[512+100]; + +TMLN ch_lines[1] = { {0} }; +TMXR ch_tmxr = { 1, 0, 0, ch_lines}; + +UNIT ch_unit[] = { + { UDATA (&ch_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_V4XTND, 0) }, +}; + +REG ch_reg[] = { + { GRDATAD(CSR, status, 16, 16, 0, "Control and status"), 0 }, + { GRDATAD(RXCNT, rx_count, 16, 16, 0, "Receive word count"), REG_RO}, + { GRDATAD(TXCNT, tx_count, 16, 16, 0, "Transmit word count"), REG_RO}, + { BRDATAD(RXBUF, rx_buffer, 16, 8, sizeof rx_buffer, "Receive packet buffer"), 0}, + { BRDATAD(TXBUF, tx_buffer, 16, 8, sizeof tx_buffer, "Transmit packet buffer"), 0}, + { BRDATAD(PEER, peer, 16, 8, sizeof peer, "Network peer"), REG_HRO}, + { GRDATAD(NODE, address, 16, 16, 0, "Node address"), REG_HRO}, + { NULL } }; + +MTAB ch_mod[] = { + { MTAB_XTD|MTAB_VDV, 010, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL, "Unibus address" }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL, "Interrupt vector" }, + { MTAB_XTD|MTAB_VDV, 0, "PEER", "PEER", + &ch_set_peer, &ch_show_peer, NULL, "Remote host name and port" }, + { MTAB_XTD|MTAB_VDV, 0, "NODE", "NODE", + &ch_set_node, &ch_show_node, NULL, "Chaosnet node address" }, + { 0 }, +}; + +DIB ch_dib = { + IOBA_CH, IOLN_CH, &ch_rd, &ch_wr, + 1, IVCL (CH), VEC_CH, { &ch_inta } +}; + +DEBTAB ch_debug[] = { + { "TRC", DBG_TRC }, + { "REG", DBG_REG }, + { "PKT", DBG_PKT }, + { "DAT", DBG_DAT }, + { "INT", DBG_INT }, + { "ERR", DBG_ERR }, + { 0 } +}; + +DEVICE ch_dev = { + "CH", ch_unit, ch_reg, ch_mod, + 1, 8, 16, 1, 8, 16, + NULL, NULL, &ch_reset, + NULL, &ch_attach, &ch_detach, + &ch_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG | DEV_MUX, + 0, ch_debug, NULL, NULL, &ch_help, &ch_help_attach, NULL, + &ch_description + }; + +int ch_checksum (CONST uint8 *p, int length) +{ + int i, sum = 0; + for (i = 0; i < length; i += 2) + sum += (p[i] << 8) + p[i+1]; + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + return sum ^ 0xffff; +} + +t_stat ch_rx_word (int32 *data) +{ + if (rx_count == 0) { + *data = 0; + sim_debug (DBG_ERR, &ch_dev, "Read empty buffer\n"); + } else { + int i = 512-2*rx_count; + *data = (rx_buffer[i] << 8) + rx_buffer[i+1]; + sim_debug (DBG_DAT, &ch_dev, "Read buffer word %d: %06o\n", + rx_count, *data); + rx_count--; + if (rx_count == 0) { + ch_lines[0].rcve = TRUE; + sim_debug (DBG_TRC, &ch_dev, "Read all, rx on\n"); + status &= ~RXD; + ch_test_int (); + } + } + return SCPE_OK; +} + +t_stat ch_tx_word (int data) +{ + if (tx_count < 246) { + int i = CHUDP_HEADER + 2*tx_count; + sim_debug (DBG_DAT, &ch_dev, "Write buffer word %d: %06o\n", + tx_count, data); + status &= ~TXD; + ch_test_int(); + tx_buffer[i] = data >> 8; + tx_buffer[i+1] = data; + tx_count++; + return SCPE_OK; + } else { + sim_debug (DBG_ERR, &ch_dev, "Write buffer overflow\n"); + return SCPE_INCOMP; + } +} + +void ch_test_int (void) +{ + if ((status & (RXD|RXIE)) == (RXD|RXIE) || + (status & (TXD|TXIE)) == (TXD|TXIE)) { + sim_debug (DBG_INT, &ch_dev, "%s %s Interrupt\n", + status & RXD ? "RX" : "", + status & TXD ? "TX" : ""); + SET_INT(CH); + } else { + CLR_INT(CH); + } +} + +t_stat ch_transmit () +{ + size_t len; + t_stat r; + + if (ch_tx_word (address) != SCPE_OK || + ch_tx_word (ch_checksum (tx_buffer + CHUDP_HEADER, 2*tx_count)) != SCPE_OK) + return SCPE_INCOMP; + + tmxr_poll_tx (&ch_tmxr); + len = CHUDP_HEADER + 2 * (size_t)tx_count; + r = tmxr_put_packet_ln (&ch_lines[0], (CONST uint8 *)&tx_buffer, len); + if (r == SCPE_OK) { + sim_debug (DBG_PKT, &ch_dev, "Sent UDP packet, %d bytes.\n", (int)len); + tmxr_poll_tx (&ch_tmxr); + } else + sim_debug (DBG_ERR, &ch_dev, "Sending UDP failed: %d.\n", r); + tx_count = 0; + status |= TXD; + ch_test_int (); + return SCPE_OK; +} + +void ch_validate (CONST uint8 *p, int count) +{ + int chksum; + int size; + + sim_debug (DBG_TRC, &ch_dev, "Packet opcode: %02x\n", p[0]); + sim_debug (DBG_TRC, &ch_dev, "MBZ: %02x\n", p[1]); + sim_debug (DBG_TRC, &ch_dev, "Forwarding count: %02x\n", p[2] >> 4); + size = ((p[2] & 0xF) << 8) + p[3]; + sim_debug (DBG_TRC, &ch_dev, "Packet size: %03x\n", size); + sim_debug (DBG_TRC, &ch_dev, "Destination address: %02x\n", (p[4] << 8) + p[5]); + sim_debug (DBG_TRC, &ch_dev, "Destination index: %02x\n", (p[6] << 8) + p[7]); + sim_debug (DBG_TRC, &ch_dev, "Source address: %02x\n", (p[8] << 8) + p[9]); + sim_debug (DBG_TRC, &ch_dev, "Source index: %02x\n", (p[10] << 8) + p[11]); + sim_debug (DBG_TRC, &ch_dev, "Packet number: %02x\n", (p[12] << 8) + p[13]); + sim_debug (DBG_TRC, &ch_dev, "Acknowledgement: %02x\n", (p[14] << 8) + p[15]); + + if (p[1] != 0) + sim_debug (DBG_ERR, &ch_dev, "Bad packet\n"); + + chksum = ch_checksum (p, count); + if (chksum != 0) { + sim_debug (DBG_ERR, &ch_dev, "Checksum error: %05o\n", chksum); + status |= CRC; + } else + sim_debug (DBG_TRC, &ch_dev, "Checksum: %05o\n", chksum); +} + +int ch_receive (void) +{ + size_t count; + CONST uint8 *p; + + tmxr_poll_rx (&ch_tmxr); + if (tmxr_get_packet_ln (&ch_lines[0], &p, &count) != SCPE_OK) { + sim_debug (DBG_ERR, &ch_dev, "TMXR error receiving packet\n"); + return 0; + } + if (p == NULL) + return 0; + + sim_debug (DBG_PKT, &ch_dev, "Received UDP packet, %d bytes\n", (int)count); + if ((status & RXD) == 0) { + count -= CHUDP_HEADER; + count = (count + 1) & 0776; + memcpy (rx_buffer + (512 - count), p + CHUDP_HEADER, count); + rx_count = (uint16)(count >> 1); + sim_debug (DBG_TRC, &ch_dev, "Rx count, %d\n", rx_count); + ch_validate (p + CHUDP_HEADER, count); + status |= RXD; + ch_lines[0].rcve = FALSE; + sim_debug (DBG_TRC, &ch_dev, "Rx off\n"); + ch_test_int (); + } else { + sim_debug (DBG_ERR, &ch_dev, "Lost packet\n"); + if ((status & LOST) < LOST) + status += 01000; + } + + return 1; +} + +int32 ch_inta (void) +{ +if (status & (RXD|TXD)) + return ch_dib.vec; +return 0; +} + +t_stat ch_rd (int32 *data, int32 PA, int32 access) +{ + int reg = (PA >> 1) & 07; + + switch (reg) { + case 00: /* Status */ + *data = status & STATUS_BITS; + sim_debug (DBG_REG, &ch_dev, "Read status: %06o\n", *data); + break; + case 01: /* Address */ + *data = address; + sim_debug (DBG_REG, &ch_dev, "Read address: %06o\n", *data); + break; + case 02: /* Read buffer */ + return ch_rx_word (data); + case 03: /* Count */ + *data = ((16 * rx_count) - 1) & 07777; + sim_debug (DBG_REG, &ch_dev, "Read bit count: %d\n", *data); + break; + case 05: /* Start */ + sim_debug (DBG_REG, &ch_dev, "Start transmission\n"); + *data = address; + return ch_transmit (); + default: + *data = 0; + break; + } + + return SCPE_OK; +} + +void ch_clear (void) +{ + status = TXD; + rx_count = 0; + tx_count = 0; + + tx_buffer[0] = 1; /* CHUDP header */ + tx_buffer[1] = 1; + tx_buffer[2] = 0; + tx_buffer[3] = 0; + + ch_test_int (); +} + +void ch_command (int32 data) +{ + if (data & RESET) { + /* Do this first so other bits can do their things. */ + sim_debug (DBG_REG, &ch_dev, "Reset\n"); + ch_clear (); + } + if (data & CRX) { + sim_debug (DBG_REG, &ch_dev, "Clear RX\n"); + rx_count = 0; + status &= ~(RXD|CRC|LOST); + ch_lines[0].rcve = TRUE; + sim_debug (DBG_TRC, &ch_dev, "Rx on\n"); + sim_activate_after (ch_unit, 10); /* Force next packet read attempt */ + } + if (data & CTX) { + sim_debug (DBG_REG, &ch_dev, "Clear TX\n"); + tx_count = 0; + status |= TXD; + status &= ~TXA; + } + ch_test_int (); +} + +t_stat ch_wr (int32 data, int32 PA, int32 access) +{ + int reg = (PA >> 1) & 07; + + switch (reg) { + case 00: /* Command */ + ch_command (data); /* Do this first in case of reset. */ + if (data & TIE) + sim_debug (DBG_REG, &ch_dev, "Timer interrupt enable\n"); + if (data & LOOP) + sim_debug (DBG_REG, &ch_dev, "Loopback\n"); + if (data & SPY) + sim_debug (DBG_REG, &ch_dev, "Spy mode\n"); + if (data & RXIE) + sim_debug (DBG_REG, &ch_dev, "RX interrupt enable\n"); + if (data & TXIE) + sim_debug (DBG_REG, &ch_dev, "TX interrupt enable\n"); + status = (status & ~COMMAND_BITS) | (data & COMMAND_BITS); + sim_debug (DBG_REG, &ch_dev, "Status: %06o\n", status); + ch_test_int (); + break; + case 01: /* Write */ + return ch_tx_word (data); + } + + return SCPE_OK; +} + +t_stat ch_svc(UNIT *uptr) +{ + if (ch_lines[0].rcve && ch_receive ()) { + sim_activate_after (uptr, 300); + return SCPE_OK; + } + sim_activate_after (uptr, 1000); + return SCPE_OK; +} + +t_stat ch_attach (UNIT *uptr, CONST char *cptr) +{ + char *linkinfo; + t_stat r; + + if (address == CH11_NO_ADDRESS) + return sim_messagef (SCPE_2FARG, "Must set Chaosnet NODE address first \"SET CH NODE=val\"\n"); + if (peer[0] == '\0') + return sim_messagef (SCPE_2FARG, "Must set Chaosnet PEER \"SET CH PEER=host:port\"\n"); + + linkinfo = (char *)calloc (100 + strlen (cptr) + strlen (peer), sizeof (*linkinfo)); + if (linkinfo == NULL) + return SCPE_MEM; + sprintf (linkinfo, "Buffer=%d,Line=%d,UDP,%s,PACKET,Connect=%s", + (int)sizeof (tx_buffer), 0, cptr, peer); + r = tmxr_attach (&ch_tmxr, uptr, linkinfo); + free (linkinfo); + if (r != SCPE_OK) { + sim_debug (DBG_ERR, &ch_dev, "TMXR error opening master\n"); + return sim_messagef (r, "Error Opening connection to: %s, using: %s\n", peer, cptr); + } + + ch_lines[0].rcve = TRUE; + sim_activate_after (uptr, 10000); /* make sure polling starts */ + uptr->filename = (char *)realloc (uptr->filename, 1 + strlen (cptr)); + strcpy (uptr->filename, cptr); + return SCPE_OK; +} + +t_stat ch_detach (UNIT *uptr) +{ + sim_cancel (uptr); + tmxr_detach (&ch_tmxr, uptr); + return SCPE_OK; +} + +t_stat ch_reset (DEVICE *dptr) +{ + DEVICE *ng_dptr = find_dev ("NG"); + + if ((ng_dptr != NULL) && + !(ng_dptr->flags & DEV_DIS) && + !(dptr->flags & DEV_DIS)) { + dptr->flags |= DEV_DIS; + return sim_messagef (SCPE_ALATT, "CH device in conflict with NG.\n"); + } + + ch_clear (); + + if (dptr->units->flags & UNIT_ATT) + sim_activate_after (dptr->units, 10000); /* poll for connections */ + + return auto_config (dptr->name, (dptr->flags & DEV_DIS)? 0 : 1); /* auto config */ +} + +t_stat ch_show_peer (FILE* st, UNIT* uptr, int32 val, CONST void* desc) +{ + fprintf (st, "peer=%s", peer[0] ? peer : "unspecified"); + return SCPE_OK; +} + +t_stat ch_set_peer (UNIT* uptr, int32 val, CONST char* cptr, void* desc) +{ + char host[256], port[256]; + + if ((cptr == NULL) || (*cptr == 0)) + return SCPE_ARG; + if (uptr->flags & UNIT_ATT) + return SCPE_ALATT; + if (sim_parse_addr (cptr, host, sizeof host, NULL, port, sizeof port, NULL, NULL)) + return SCPE_ARG; + if (host[0] == '\0') + return SCPE_ARG; + + strlcpy (peer, cptr, sizeof peer); + return SCPE_OK; +} + +t_stat ch_show_node (FILE* st, UNIT* uptr, int32 val, CONST void* desc) +{ + if (address == CH11_NO_ADDRESS) + fprintf (st, "node=unspecified"); + else + fprintf (st, "node=%o", address); + return SCPE_OK; +} + +t_stat ch_set_node (UNIT* uptr, int32 val, CONST char* cptr, void* desc) +{ + t_stat r; + int x; + + if ((cptr == NULL) || (*cptr == 0)) + return SCPE_ARG; + if (uptr->flags & UNIT_ATT) + return SCPE_ALATT; + + x = (int)get_uint (cptr, 8, 0177777, &r); + if (r != SCPE_OK) + return SCPE_ARG; + + address = x; + return SCPE_OK; +} + +CONST char *ch_description (DEVICE *dptr) +{ + return "CH11 Chaosnet interface"; +} + +t_stat ch_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr) +{ + fprintf (st, "CH11 Chaosnet interface\n\n"); + fprintf (st, "The CH11 is a Unibus device which can be used with PDP-11, VAX, and\n"); + fprintf (st, "KS10. It's a network interface for MIT's Chaosnet. Options allow\n"); + fprintf (st, "control of the node address and network peer. The node address must\n"); + fprintf (st, "be a 16-bit octal number.\n"); + fprintf (st, "\nConfigured options and controller state can be displayed with:\n"); + fprintf (st, "\nThe CH11 simulation will encapsulate Chaosnet packets in UDP or TCP.\n"); + fprintf (st, "To access the network, the simulated Chaosnet interface must be attached\n"); + fprintf (st, "to a network peer.\n\n"); + ch_help_attach (st, dptr, uptr, flag, cptr); + fprintf (st, "Software that runs on SIMH that supports this device include:\n"); + fprintf (st, " - ITS, the PDP-10 Incompatible Timesharing System\n"); + fprintf (st, " - Berkeley Unix with MIT patches\n"); + fprintf (st, " - MINITS, a PDP-11 Chaosnet router/terminal concentrator\n\n"); + fprintf (st, "Outside SIMH, there's KLH10 and Lisp machine simulators. Various\n"); + fprintf (st, "encapsulating transport mechanisms exist: UDP, IP, Ethernet.\n\n"); + fprintf (st, "Documentation:\n"); + fprintf (st, "https://lm-3.github.io/amber.html#Hardware-Programming-Documentation\n\n"); + return SCPE_OK; +} + +t_stat ch_help_attach (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr) +{ + fprintf (st, "To configure CH11, first set the local Chaosnet node address, and\n"); + fprintf (st, "the peer:\n\n"); + fprintf (st, " sim> SET CH NODE=\n"); + fprintf (st, " sim> SET CH PEER=:\n\n"); + fprintf (st, "Then, attach a local port. By default UDP is used:\n\n"); + fprintf (st, " sim> ATTACH CH \n\n"); + fprintf (st, "If TCP is desired, add \"TCP\":\n\n"); + fprintf (st, " sim> ATTACH CH ,TCP\n\n"); + return SCPE_OK; +} diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index 7042bdb28..7fd7e85d9 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-2022, Robert M Supnik + Copyright (c) 1993-2023, 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,7 +25,11 @@ cpu PDP-11 CPU - 30-Nov022 RMS More 11/45,11/70 trap hackery (Walter Mueller) + 04-Feb-23 RMS WRTLCK reads and tosses destination data + Writes must test for aborts before changing CCs + 27-Dec-22 RMS Vector with T set traps immediately (Walter Mueller) + 22-Dec-22 RMS RTT clears pending trace trap (Walter Mueller) + 30-Nov-22 RMS More 11/45,11/70 trap hackery (Walter Mueller) 29-Nov-22 RMS Trap stack abort must clear other traps/aborts (Walter Mueller) 23-Oct-22 RMS Fixed priority of MME traps (Walter Mueller) 02-Sep-22 RMS Fixed handling of PDR (Walter Mueller) @@ -350,6 +354,8 @@ int32 ReadW (int32 addr); int32 ReadB (int32 addr); int32 ReadMW (int32 addr); int32 ReadMB (int32 addr); +static int32 TestMW (int32 va); +static int32 TestMB (int32 va); void WriteW (int32 data, int32 addr); void WriteB (int32 data, int32 addr); void PWriteW (int32 data, int32 addr); @@ -753,7 +759,7 @@ if (abortval != 0) { while (reason == 0) { int32 IR, srcspec, srcreg, dstspec, dstreg; - int32 src, src2, dst, ea; + int32 src, src2, dst, pa; int32 i, t, sign, oldrs, trapnum; if (cpu_astop) { @@ -837,6 +843,8 @@ while (reason == 0) { if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y)) && (trapnum != TRAP_V_RED) && (trapnum != TRAP_V_YEL)) set_stack_trap (SP); + if (tbit) /* tbit now set? */ + setTRAP (TRAP_TRC); /* immediate trap */ continue; /* end if traps */ } @@ -957,6 +965,7 @@ while (reason == 0) { if (CPUT (HAS_RTT) && tbit && /* RTT impl? */ (IR == 000002)) setTRAP (TRAP_TRC); /* RTI immed trap */ + else trap_req = trap_req & ~TRAP_TRC; /* no trace trap */ break; case 7: /* MFPT */ if (CPUT (HAS_MFPT)) /* implemented? */ @@ -1134,11 +1143,13 @@ while (reason == 0) { break; /* end JSR */ case 050: /* CLR */ - N = V = C = 0; + if (!dstreg) /* not reg? */ + pa = TestMW (GeteaW (dstspec)); /* relocate */ + N = V = C = 0; /* now set CC's */ Z = 1; if (dstreg) R[dstspec] = 0; - else WriteW (0, GeteaW (dstspec)); + else PWriteW (0, pa); break; case 051: /* COM */ @@ -1292,15 +1303,16 @@ while (reason == 0) { i = ((cm == pm) && (cm == MD_USR))? (int32)calc_ds (pm): (int32)calc_is (pm); dst = ReadW ((GeteaW (dstspec) & 0177777) | i); } - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; SP = (SP - 2) & 0177777; if (update_MM) MMR1 = calc_MMR1 (0366); if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y))) set_stack_trap (SP); - WriteW (dst, SP | dsenable); + pa = TestMW (SP | dsenable); /* relocate SP */ + N = GET_SIGN_W (dst); /* now update CC's */ + Z = GET_Z (dst); + V = 0; + PWriteW (dst, pa); } else setTRAP (TRAP_ILL); break; @@ -1308,29 +1320,34 @@ while (reason == 0) { case 066: /* MTPI */ if (CPUT (HAS_MXPY)) { dst = ReadW (SP | dsenable); - N = GET_SIGN_W (dst); + SP = (SP + 2) & 0177777; + if (update_MM) + MMR1 = 026; + if (!dstreg) + pa = TestMW ((GeteaW (dstspec) & 0177777) | calc_is (pm)); + N = GET_SIGN_W (dst); /* now update CCs */ Z = GET_Z (dst); V = 0; - SP = (SP + 2) & 0177777; - if (update_MM) MMR1 = 026; if (dstreg) { if ((dstspec == 6) && (cm != pm)) STACKFILE[pm] = dst; else R[dstspec] = dst; } - else WriteW (dst, (GeteaW (dstspec) & 0177777) | calc_is (pm)); + else PWriteW (dst, pa); } else setTRAP (TRAP_ILL); break; case 067: /* SXT */ if (CPUT (HAS_SXS)) { - dst = N? 0177777: 0; + if (!dstreg) + pa = TestMW (GeteaW (dstspec)); + dst = N? 0177777: 0; /* now update CCs */ Z = N ^ 1; V = 0; if (dstreg) R[dstspec] = dst; - else WriteW (dst, GeteaW (dstspec)); + else PWriteW (dst, pa); } else setTRAP (TRAP_ILL); break; @@ -1369,10 +1386,11 @@ while (reason == 0) { case 073: /* WRTLCK */ if (CPUT (HAS_TSWLK) && !dstreg) { + dst = ReadMW (GeteaW (dstspec)); /* data thrown away */ N = GET_SIGN_W (R[0]); Z = GET_Z (R[0]); V = 0; - WriteW (R[0], GeteaW (dstspec)); + PWriteW (R[0], last_pa); /* dst <- R[0] */ } else setTRAP (TRAP_ILL); break; @@ -1396,20 +1414,20 @@ while (reason == 0) { case 001: /* MOV */ if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - ea = GeteaW (dstspec); + pa = TestMW (GeteaW (dstspec)); /* reloc dest */ dst = R[srcspec]; } else { dst = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); if (!dstreg) - ea = GeteaW (dstspec); + pa = TestMW (GeteaW (dstspec)); } - N = GET_SIGN_W (dst); + N = GET_SIGN_W (dst); /* now update CCs */ Z = GET_Z (dst); V = 0; if (dstreg) R[dstspec] = dst; - else WriteW (dst, ea); + else PWriteW (dst, pa); break; case 002: /* CMP */ @@ -1807,11 +1825,13 @@ while (reason == 0) { break; case 050: /* CLRB */ - N = V = C = 0; + if (!dstreg) + pa = TestMB (GeteaB (dstspec)); + N = V = C = 0; /* now update CCs */ Z = 1; if (dstreg) R[dstspec] = R[dstspec] & 0177400; - else WriteB (0, GeteaB (dstspec)); + else PWriteB (0, pa); break; case 051: /* COMB */ @@ -1968,15 +1988,16 @@ while (reason == 0) { else dst = R[dstspec]; } else dst = ReadW ((GeteaW (dstspec) & 0177777) | calc_ds (pm)); - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; SP = (SP - 2) & 0177777; if (update_MM) MMR1 = calc_MMR1 (0366); if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y))) set_stack_trap (SP); - WriteW (dst, SP | dsenable); + pa = TestMW (SP | dsenable); + N = GET_SIGN_W (dst); /* now update CCs */ + Z = GET_Z (dst); + V = 0; + PWriteW (dst, pa); } else setTRAP (TRAP_ILL); break; @@ -1984,18 +2005,20 @@ while (reason == 0) { case 066: /* MTPD */ if (CPUT (HAS_MXPY)) { dst = ReadW (SP | dsenable); - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; SP = (SP + 2) & 0177777; if (update_MM) MMR1 = 026; - if (dstreg) { + if (!dstreg) + pa = TestMW ((GeteaW (dstspec) & 0177777) | calc_ds (pm)); + N = GET_SIGN_W (dst); /* now set CCs */ + Z = GET_Z (dst); + V = 0; + if (dstreg) { if ((dstspec == 6) && (cm != pm)) STACKFILE[pm] = dst; else R[dstspec] = dst; } - else WriteW (dst, (GeteaW (dstspec) & 0177777) | calc_ds (pm)); + else PWriteW (dst, pa); } else setTRAP (TRAP_ILL); break; @@ -2003,12 +2026,14 @@ while (reason == 0) { case 067: /* MFPS */ if (CPUT (HAS_MXPS)) { dst = get_PSW () & 0377; + if (!dstreg) + pa = TestMB (GeteaB (dstspec)); N = GET_SIGN_B (dst); Z = GET_Z (dst); V = 0; if (dstreg) R[dstspec] = (dst & 0200)? 0177400 | dst: dst; - else WriteB (dst, GeteaB (dstspec)); + else PWriteB (dst, pa); } else setTRAP (TRAP_ILL); break; @@ -2027,20 +2052,20 @@ while (reason == 0) { case 011: /* MOVB */ if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - ea = GeteaB (dstspec); + pa = TestMB (GeteaB (dstspec)); dst = R[srcspec] & 0377; } else { dst = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec)); if (!dstreg) - ea = GeteaB (dstspec); + pa = TestMB (GeteaB (dstspec)); } N = GET_SIGN_B (dst); Z = GET_Z (dst); V = 0; if (dstreg) R[dstspec] = (dst & 0200)? 0177400 | dst: dst; - else WriteB (dst, ea); + else PWriteB (dst, pa); break; case 012: /* CMPB */ @@ -2425,6 +2450,28 @@ if (iopageR (&data, last_pa, READ) != SCPE_OK) { /* invalid I/O addr? */ return ((va & 1)? data >> 8: data) & 0377; } +/* Test write byte and word routines + + Inputs: + va = virtual address, <18:16> = mode, I/D space + Outputs: + pa = physical address +*/ + +int32 TestMW (int32 va) +{ +if ((va & 1) && CPUT (HAS_ODD)) { /* odd address? */ + setCPUERR (CPUE_ODD); + ABORT (TRAP_ODD); + } +return relocW (va); /* relocate */ +} + +int32 TestMB (int32 va) +{ +return relocW (va); /* relocate */ +} + /* Write byte and word routines Inputs: diff --git a/PDP11/pdp11_cpumod.c b/PDP11/pdp11_cpumod.c index db44c0383..5c7cf69fc 100644 --- a/PDP11/pdp11_cpumod.c +++ b/PDP11/pdp11_cpumod.c @@ -1,6 +1,6 @@ /* pdp11_cpumod.c: PDP-11 CPU model-specific features - Copyright (c) 2004-2022, Robert M Supnik + Copyright (c) 2004-2023, 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 @@ system PDP-11 model-specific registers + 10-Oct-23 RMS Fixed writes to 11/70 RO registers (Tony Lawrence) 19-Nov-22 RMS Fixed byte access errors in PIRQ, STKLIM, CDR (Walter Mueller) 15-Sep-20 RMS Fixed problem in KDJ11E programmable clock (Paul Koning) 04-Mar-16 RMS Fixed maximum memory sizes to exclude IO page @@ -647,6 +648,12 @@ t_stat CPU70_wr (int32 data, int32 pa, int32 access) { switch ((pa >> 1) & 017) { /* decode pa<4:1> */ + case 000: /* low error */ + return SCPE_OK; + + case 001: /* high error */ + return SCPE_OK; + case 002: /* MEMERR */ ODD_SHF (data); MEMERR = MEMERR & ~data; @@ -669,6 +676,9 @@ switch ((pa >> 1) & 017) { /* decode pa<4:1> */ case 011: /* high size */ return SCPE_OK; + case 012: /* system ID */ + return SCPE_OK; + case 013: /* CPUERR */ CPUERR = 0; return SCPE_OK; diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index 64a849dac..4e17d605c 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -1,6 +1,6 @@ /* pdp11_defs.h: PDP-11 simulator definitions - Copyright (c) 1993-2022, Robert M Supnik + Copyright (c) 1993-2024, 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"), @@ -26,6 +26,8 @@ The author gratefully acknowledges the help of Max Burnet, Megan Gentry, and John Wilson in resolving questions about the PDP-11 + 05-May-24 RMS Merged CH11 definitions (Lars Brinkhoff) + 12-May-23 RMS Added fourth Massbus adapter 23-Oct-22 RMS Moved NXM abort priority above MME trap priority 25-Jul-22 RMS Removed OPT_RH11 (Mark Pizzolato) 10-Feb-17 RMS Fixed RJS11 register block length (Mark Hill) @@ -575,6 +577,8 @@ typedef struct pdp_dib DIB; #define IOLN_PCLK 006 #define IOBA_DC (IOPAGEBASE + 014000) /* DC11 */ #define IOLN_DC (DCX_LINES * 010) +#define IOBA_CH (IOPAGEBASE + 004140) /* CH11 Chaosnet */ +#define IOLN_CH 020 #define IOBA_RL (IOPAGEBASE + 014400) /* RL11 */ #define IOLN_RL 012 #define IOBA_XQ (IOPAGEBASE + 014440) /* DEQNA/DELQA */ @@ -585,6 +589,8 @@ typedef struct pdp_dib DIB; #define IOLN_TQ 004 #define IOBA_XU (IOPAGEBASE + 014510) /* DEUNA/DELUA */ #define IOLN_XU 010 +#define IOBA_RPB (IOPAGEBASE + 016300) /* RHD: 2nd RP */ +#define IOLN_RPB 040 #define IOBA_DL (IOPAGEBASE + 016500) /* extra KL11/DL11 */ #define IOLN_DL (DLX_LINES * 010) #define IOBA_RP (IOPAGEBASE + 016700) /* RHA: RP/RM */ @@ -683,6 +689,8 @@ typedef struct pdp_dib DIB; #define INT_V_RC 17 #define INT_V_RS 18 #define INT_V_UCB 19 +#define INT_V_RPB 20 +#define INT_V_CH 21 #define INT_V_PIR4 0 /* BR4 */ #define INT_V_TTI 1 @@ -730,6 +738,7 @@ typedef struct pdp_dib DIB; #define INT_RC (1u << INT_V_RC) #define INT_RS (1u << INT_V_RS) #define INT_UCA (1u << INT_V_UCA) +#define INT_RPB (1u << INT_V_RPB) #define INT_PIR4 (1u << INT_V_PIR4) #define INT_TTI (1u << INT_V_TTI) #define INT_TTO (1u << INT_V_TTO) @@ -746,6 +755,7 @@ typedef struct pdp_dib DIB; #define INT_PIR3 (1u << INT_V_PIR3) #define INT_PIR2 (1u << INT_V_PIR2) #define INT_PIR1 (1u << INT_V_PIR1) +#define INT_CH (1u << INT_V_CH) #define INT_INTERNAL7 (INT_PIR7) #define INT_INTERNAL6 (INT_PIR6 | INT_CLK) @@ -780,6 +790,8 @@ typedef struct pdp_dib DIB; #define IPL_RC 5 #define IPL_RS 5 #define IPL_UCA 5 +#define IPL_RPB 5 +#define IPL_CH 5 #define IPL_PTR 4 #define IPL_PTP 4 #define IPL_TTI 4 @@ -813,6 +825,7 @@ typedef struct pdp_dib DIB; #define VEC_PCLK 0104 #define VEC_XQ 0120 #define VEC_XU 0120 +#define VEC_RPB 0150 #define VEC_RQ 0154 #define VEC_RL 0160 #define VEC_LPT 0200 @@ -831,6 +844,7 @@ typedef struct pdp_dib DIB; #define VEC_TA 0260 #define VEC_RX 0264 #define VEC_RY 0264 +#define VEC_CH 0270 #define VEC_DLI 0300 #define VEC_DLO 0304 #define VEC_DCI 0300 @@ -852,10 +866,11 @@ typedef struct pdp_dib DIB; /* Massbus definitions */ -#define MBA_NUM 3 /* number of MBA's */ +#define MBA_NUM 4 /* number of MBA's */ #define MBA_RP 0 /* MBA for RP */ #define MBA_TU 1 /* MBA for TU */ #define MBA_RS 2 /* MBA for RS */ +#define MBA_RPB 3 /* MBA for RPB */ #define MBA_RMASK 037 /* max 32 reg */ #define MBE_NXD 1 /* nx drive */ #define MBE_NXR 2 /* nx reg */ @@ -905,7 +920,7 @@ void cpu_set_boot (int32 pc); #define WrMemW(pa,d) uc15_WrMemW (pa, d) #define WrMemB(pa, d) uc15_WrMemB (pa, d) -uint32 uc15_memsize; +extern uint32 uc15_memsize; int32 uc15_RdMemW (int32 pa); int32 uc15_RdMemB (int32 pa); void uc15_WrMemW (int32 pa, int32 d); diff --git a/PDP11/pdp11_dz.c b/PDP11/pdp11_dz.c index d146a8957..f1352cb15 100644 --- a/PDP11/pdp11_dz.c +++ b/PDP11/pdp11_dz.c @@ -1,6 +1,6 @@ /* pdp11_dz.c: DZ11 terminal multiplexor simulator - Copyright (c) 2001-2008, Robert M Supnik + Copyright (c) 2001-2023, 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 @@ dz DZ11 terminal multiplexor + 23-Feb-23 RMS Fixed line number calculation in connect (Walter Mueller) 29-Dec-08 RMS Added MTAB_NC to SET LOG command (Walter Mueller) 19-Nov-08 RMS Revised for common TMXR show routines 18-Jun-07 RMS Added UNIT_IDLE flag @@ -394,7 +395,7 @@ return SCPE_OK; t_stat dz_svc (UNIT *uptr) { -int32 dz, t, newln; +int32 dz, t, newln, muxln; for (dz = t = 0; dz < DZ_MUXES; dz++) /* check enabled */ t = t | (dz_csr[dz] & CSR_MSE); @@ -402,9 +403,10 @@ if (t) { /* any enabled? */ newln = tmxr_poll_conn (&dz_desc); /* poll connect */ if ((newln >= 0) && dz_mctl) { /* got a live one? */ dz = newln / DZ_LINES; /* get mux num */ - if (dz_tcr[dz] & (1 << (newln + TCR_V_DTR))) /* DTR set? */ - dz_msr[dz] |= (1 << (newln + MSR_V_CD)); /* set cdet */ - else dz_msr[dz] |= (1 << newln); /* set ring */ + muxln = newln % DZ_LINES; /* line # within mux */ + if (dz_tcr[dz] & (1 << (muxln + TCR_V_DTR))) /* DTR set? */ + dz_msr[dz] |= (1 << (muxln + MSR_V_CD)); /* set cdet */ + else dz_msr[dz] |= (1 << (muxln + MSR_V_RI)); /* set ring */ } tmxr_poll_rx (&dz_desc); /* poll input */ dz_update_rcvi (); /* upd rcv intr */ diff --git a/PDP11/pdp11_fp.c b/PDP11/pdp11_fp.c index af3d57f3f..4d30e348c 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-2018, Robert M Supnik + Copyright (c) 1993-2023, 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. + 05-Jun-23 RMS Fixed bug in FIS dirty zero check ("Joonio") 10-Dec-22 RMS Fixed bug in FUIV operation (James Fehlinger) 21-Aug-22 RMS Restored MMR1 operation for 11/44, 11/45-70 (Walter Mueller) 28-May-18 RMS Fixed FPCHG macro to avoid undefined operation (Mark Pizzolato) @@ -889,7 +890,7 @@ fac.h = (ReadW (exta | ((R[reg] + 4) & 0177777)) << FP_V_F0) | fac.l = 0; if (GET_SIGN (fsrc.h) && (GET_EXP (fsrc.h) == 0)) /* clean 0's */ fsrc.h = fsrc.l = 0; -if (GET_SIGN (fac.h) && (GET_EXP (fac.l) == 0)) +if (GET_SIGN (fac.h) && (GET_EXP (fac.h) == 0)) fac.h = fac.l = 0; N = Z = V = C = 0; /* clear cc's */ diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c index 06f999744..f7b154837 100644 --- a/PDP11/pdp11_io.c +++ b/PDP11/pdp11_io.c @@ -1,6 +1,6 @@ /* pdp11_io.c: PDP-11 I/O simulator - Copyright (c) 1993-2012, Robert M Supnik + Copyright (c) 1993-2023, 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. + 11-Jun-23 RMS Fixed GCC complaint about uc15_memsiz (Mark Pizzolato) 27-Mar-12 RMS Fixed order of int_internal (Jordi Guillaumes i Pons) 19-Mar-12 RMS Fixed declaration of cpu_opt (Mark Pizzolato) 12-Dec-11 RMS Fixed Qbus interrupts to treat all IO devices as BR4 diff --git a/PDP11/pdp11_rf.c b/PDP11/pdp11_rf.c index 7cc1471d1..5da1e51c0 100644 --- a/PDP11/pdp11_rf.c +++ b/PDP11/pdp11_rf.c @@ -1,6 +1,6 @@ /* pdp11_rf.c: RF11 fixed head disk simulator - Copyright (c) 2006-2017, Robert M Supnik + Copyright (c) 2006-2023, 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 @@ rf RF11 fixed head disk + 18-Jun-23 RMS Fixed bug in DAE update (Tony Lawrence) 13-Feb-17 RMS Fixed CSR address in boot code (Paul Koning) 23-Oct-13 RMS Revised for new boot setup routine 03-Sep-13 RMS Added explicit void * cast @@ -380,7 +381,7 @@ do { } while ((rf_wc != 0) && (rf_burst != 0)); /* brk if wc, no brst */ rf_da = da & DMASK; /* split da */ -rf_dae = (rf_dae & ~RFDAE_DAE) | ((rf_da >> 16) & RFDAE_DAE); +rf_dae = (rf_dae & ~RFDAE_DAE) | ((da >> 16) & RFDAE_DAE); rf_cma = ma & DMASK; /* split ma */ rf_cs = (rf_cs & ~RFCS_MEX) | ((ma >> (16 - RFCS_V_MEX)) & RFCS_MEX); if ((rf_wc != 0) && ((rf_cs & RFCS_ERR) == 0)) /* more to do? */ diff --git a/PDP11/pdp11_rh.c b/PDP11/pdp11_rh.c index ccc841a43..405e17e1e 100644 --- a/PDP11/pdp11_rh.c +++ b/PDP11/pdp11_rh.c @@ -1,6 +1,6 @@ /* pdp11_rh.c: PDP-11 Massbus adapter simulator - Copyright (c) 2005-2022, Robert M Supnik + Copyright (c) 2005-2023, 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,8 +23,9 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - rha, rhb RH11/RH70 Massbus adapter + rha, rhb, rhc, rhd RH11/RH70 Massbus adapter + 12-May-23 RMS Added fourth adapter 25-Jul-22 RMS Removed OPT_RH11, changed adapter type test 02-Sep-13 RMS Added third Massbus adapter, debug printouts 19-Mar-12 RMS Fixed declaration of cpu_opt (Mark Pizzolato) @@ -174,6 +175,7 @@ t_stat mba_show_type (FILE *st, UNIT *uptr, int32 val, void *desc); int32 mba0_inta (void); int32 mba1_inta (void); int32 mba2_inta (void); +int32 mba3_inta (void); void mba_set_int (uint32 mb); void mba_clr_int (uint32 mb); void mba_upd_cs1 (uint32 set, uint32 clr, uint32 mb); @@ -309,6 +311,41 @@ MTAB mba2_mod[] = { { 0 } }; +DIB mba3_dib = { + IOBA_RPB, IOLN_RPB, &mba_rd, &mba_wr, + 1, IVCL (RPB), VEC_RPB, { &mba3_inta } + }; + +UNIT mba3_unit = { UDATA (NULL, 0, 0) }; + +REG mba3_reg[] = { + { ORDATA (CS1, massbus[3].cs1, 16) }, + { ORDATA (WC, massbus[3].wc, 16) }, + { ORDATA (BA, massbus[3].ba, 16) }, + { ORDATA (CS2, massbus[3].cs2, 16) }, + { ORDATA (DB, massbus[3].db, 16) }, + { ORDATA (BAE, massbus[3].bae, 6) }, + { ORDATA (CS3, massbus[3].cs3, 16) }, + { FLDATA (IFF, massbus[3].iff, 0) }, + { FLDATA (INT, IREQ (RPB), INT_V_RPB) }, + { FLDATA (SC, massbus[3].cs1, CSR_V_ERR) }, + { FLDATA (DONE, massbus[3].cs1, CSR_V_DONE) }, + { FLDATA (IE, massbus[3].cs1, CSR_V_IE) }, + { ORDATA (DEVADDR, mba3_dib.ba, 32), REG_HRO }, + { ORDATA (DEVVEC, mba3_dib.vec, 16), REG_HRO }, + { NULL } + }; + +MTAB mba3_mod[] = { + { MTAB_XTD|MTAB_VDV, 0040, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "TYPE", NULL, + NULL, &mba_show_type, NULL }, + { 0 } + }; + DEVICE mba_dev[] = { { "RHA", &mba0_unit, mba0_reg, mba0_mod, @@ -330,6 +367,13 @@ DEVICE mba_dev[] = { NULL, NULL, &mba_reset, NULL, NULL, NULL, &mba2_dib, DEV_DEBUG | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS + }, + { + "RHD", &mba3_unit, mba3_reg, mba3_mod, + 1, 0, 0, 0, 0, 0, + NULL, NULL, &mba_reset, + NULL, NULL, NULL, + &mba3_dib, DEV_DEBUG | DEV_DIS | DEV_UBUS | DEV_QBUS } }; @@ -784,6 +828,14 @@ massbus[2].iff = 0; /* clear CSTB INTR */ return mba2_dib.vec; /* acknowledge */ } +int32 mba3_inta (void) +{ +massbus[3].cs1 &= ~CS1_IE; /* clear int enable */ +massbus[3].cs3 &= ~CS1_IE; /* in both registers */ +massbus[3].iff = 0; /* clear CSTB INTR */ +return mba2_dib.vec; /* acknowledge */ +} + /* Map physical address to Massbus number, offset */ int32 mba_map_pa (int32 pa, int32 *ofs) diff --git a/PDP11/pdp11_rk.c b/PDP11/pdp11_rk.c index f501ba994..953a2741c 100644 --- a/PDP11/pdp11_rk.c +++ b/PDP11/pdp11_rk.c @@ -590,7 +590,7 @@ if (wc && (err == 0)) { /* seek ok? */ rkxb[i] = comp; } else { /* normal fetch */ - if ((t = MAP_RDW (ma, wc << 1, rkxb))) { /* get buf */ + if ((t = MAP_RDW (ma, wc << 1, rkxb))) { /* get buf */ rker = rker | RKER_NXM; /* NXM? set flg */ wc = wc - (t >> 1); /* adj wd cnt */ } diff --git a/PDP11/pdp11_rr.c b/PDP11/pdp11_rr.c new file mode 100644 index 000000000..5e93f2633 --- /dev/null +++ b/PDP11/pdp11_rr.c @@ -0,0 +1,1265 @@ +/* pdp11_rr.c: RP11/-C/-E/RP02/RP03 disk pack device + + Copyright (c) 2022 Tony Lawrence + + 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. + + Inspired by PDP-11's RK/RL implementations by Robert Supnik. +*/ + +#if defined(VM_PDP11) && !defined(UC15) + +#include + +#include "pdp11_defs.h" +#include "sim_disk.h" + +/* Constants */ + +#define RPCONTR uint16 +#define RPWRDSZ 16 +#define MAP_RDW(a,c,b) (Map_ReadW (a, (c) << 1, b) >> 1) +#define MAP_WRW(a,c,b) (Map_WriteW(a, (c) << 1, b) >> 1) + +/* RP02 parameters; PR03 doubles # of cylinders (both total and spare) */ +#define RP_NUMWD 256 /* words/sector */ +#define RP_NUMCY 203 /* cylinders/drive */ +#define RP_SPARE 3 /* of those, spare */ +#define RP_NUMSF 20 /* surfaces/cylinder */ +#define RP_NUMSC 10 /* sectors/track */ +#define RP_NUMTR (RP_NUMCY * RP_NUMSF) /* tracks/drive */ +#define RP_NUMBL (RP_NUMTR * RP_NUMSC) /* blocks/drive */ +#define RP_NUMDR 8 /* drives/controller */ +#define RP_MAXFR (1 << 16) /* max transfer */ +#define RP_SIZE(n) (RP_NUMWD * (n)) /* words in n blocks */ +#define RP_SIZE_RP02 RP_SIZE(RP_NUMBL) /* RP02 capacity, words */ +#define RP_SIZE_RP03 RP_SIZE(RP_NUMBL*2) /* RP03 capacity, words */ +#define RP_ROT_12 125 /* Half rotation, 0.1ms */ + +/* Flags in the unit flags word */ +#define UNIT_NOAUTO DKUF_NOAUTOSIZE /* autosize disabled */ +#define UNIT_V_RP03 (DKUF_V_UF + 0) +#define UNIT_RP03 (1 << UNIT_V_RP03) /* RP03 vs RP02 (0) */ +#define GET_DTYPE(x) (((x) & UNIT_RP03) >> UNIT_V_RP03) + +/* Controller / drive types */ +#define RP_RP11 "RP11-C" +#define RP_RP02 "RP02" +#define RP_RP03 "RP03" + +/* Parameters in the unit descriptor */ +#define CYL u3 /* current cylinder */ +#define FUNC u4 /* function */ +#define HEAD u5 /* current track */ +#define SEEKING u6 /* unit performing a seek */ + +/* 12 UNIBUS registers */ +#define RP_IOLN 030 + +/* RP02/RP03 particulars */ +static struct drv_typ { + const char* name; /* device type name */ + int32 cyl; /* cylinders */ + int32 size; /* #blocks */ + int32 spare; /* spare (out of cyl) */ + int32 seek_1; /* one track move, 0.1ms */ + int32 seek_ave; /* average seek, 0.1ms */ + int32 seek_max; /* maximal seek, 0.1ms */ +} drv_tab[] = { + { RP_RP02, RP_NUMCY, RP_NUMBL, RP_SPARE, 200, 500, 800 }, + { RP_RP03, RP_NUMCY*2, RP_NUMBL*2, RP_SPARE*2, 75, 290, 550 } +}; + +/* RPDS 776710, selected drive status, read-only except for the attention bits */ +static BITFIELD rp_ds_bits[] = { +#define RPDS_ATTN 0000377 /* attention (read/clear) */ + BITF(ATTN,8), +#define RPDS_WLK 0000400 /* write locked */ + BIT(WLK), +#define RPDS_UNSAFE 0001000 /* unsafe */ + BIT(UNSAFE), +#define RPDS_SEEK 0002000 /* seek underway */ + BIT(SEEK), +#define RPDS_INC 0004000 /* seek incomplete */ + BIT(INC), +#define RPDS_HNF 0010000 /* header not found */ + BIT(HNF), +#define RPDS_RP03 0020000 /* drive is RP03 */ + BIT(RP03=), +#define RPDS_ONLN 0040000 /* unit online */ + BIT(ONLN), +#define RPDS_RDY 0100000 /* unit ready */ + BIT(RDY), + ENDBITS +}; +#define RPDS_DKER(x) ((x) & (RPDS_HNF | RPDS_INC) ? RPER_DRE : 0) + +/* RPER 776712, error register, read-only */ +static BITFIELD rp_er_bits[] = { +#define RPER_DRE 0000001 /* drive error (HNF|INC) */ + BIT(DRE), +#define RPER_EOP 0000002 /* end of pack (overrun) */ + BIT(EOP), +#define RPER_NXM 0000004 /* nx memory */ + BIT(NXM), +#define RPER_WCE 0000010 /* write check error */ + BIT(WCE), +#define RPER_TE 0000020 /* timing error */ + BIT(TE), +#define RPER_CSE 0000040 /* serial checksum error */ + BIT(CSE), +#define RPER_WPE 0000100 /* word parity error */ + BIT(WPE), +#define RPER_LPE 0000200 /* longitudinal parity error */ + BIT(LPE), +#define RPER_MODE 0000400 /* mode error */ + BIT(MODE), +#define RPER_FMTE 0001000 /* format error */ + BIT(FMTE), +#define RPER_PGE 0002000 /* programming error */ + BIT(PGE), +#define RPER_NXS 0004000 /* nx sector */ + BIT(NXS), +#define RPER_NXT 0010000 /* nx track */ + BIT(NXT), +#define RPER_NXC 0020000 /* nx cylinder */ + BIT(NXC), +#define RPER_FUV 0040000 /* unsafe violation */ + BIT(FUV), +#define RPER_WPV 0100000 /* write lock violation */ + BIT(WPV), + ENDBITS +}; +#define RPER_REAL 0177776 +/* hard errors: drawing 19 */ +#define RPER_HARDERR (RPER_WPV | RPER_FUV | RPER_NXC | RPER_NXT | \ + RPER_NXS | RPER_PGE | RPER_NXM | RPER_DRE | RPER_MODE) +/* soft errors: drawing 19 */ +#define RPER_SOFTERR (RPER_LPE | RPER_WPE | RPER_CSE | RPER_WCE | \ + RPER_EOP | RPER_TE | RPER_FMTE) +#define RPER_HARD(x) ((x) & RPER_HARDERR ? (RPCS_ERR | RPCS_HERR) : 0) +#define RPER_SOFT(x) ((x) & RPER_SOFTERR ? RPCS_ERR : 0) + +/* RPCS 776714, command/status register */ +static const char* rp_funcs[] = { + "RESET", "WRITE", "READ", "WCHK", "SEEK", "WRNOSEEK", "HOME", "RDNOSEEK" +}; + +static BITFIELD rp_cs_bits[] = { +/* CSR_GO */ /* the GO! bit */ + BIT(GO), +#define RPCS_V_FUNC 1 +#define RPCS_M_FUNC 7 +#define RPCS_FUNC (RPCS_M_FUNC << RPCS_V_FUNC) /* function */ +#define RPCS_RESET 0 +#define RPCS_WRITE 1 +#define RPCS_READ 2 +#define RPCS_WCHK 3 +#define RPCS_SEEK 4 +#define RPCS_WR_NOSEEK 5 +#define RPCS_HOME 6 +#define RPCS_RD_NOSEEK 7 + BITFNAM(FUNC,3,rp_funcs), +#define RPCS_V_MEX 4 +#define RPCS_M_MEX 3 +#define RPCS_MEX (RPCS_M_MEX << RPCS_V_MEX) /* memory extension */ + BITF(MEX,2), +/* CSR_IE */ /* interrupt enable */ + BIT(IE), +/* CSR_DONE */ /* controller ready */ + BIT(DONE), +#define RPCS_V_DRV 8 +#define RPCS_M_DRV 7 +#define RPCS_DRV (RPCS_M_DRV << RPCS_V_DRV) /* drive id */ + BITFFMT(DRV,3,%u), +#define RPCS_HDR 0004000 /* header operation */ + BIT(HDR), +#define RPCS_MODE 0010000 /* 0=PDP-11; 1=PDP-10/-15 or format */ + BIT(MODE), +#define RPCS_AIE 0020000 /* attention interrupt enable */ + BIT(AIE), +#define RPCS_HERR 0040000 /* hard error */ + BIT(HERR), +#define RPCS_ERR CSR_ERR /* error (hard or soft) */ + BIT(ERR), +#define RPCS_REAL 0037776 /* bits kept here */ +#define RPCS_RW 0037576 /* read/write */ +#define GET_FUNC(x) (((x) & RPCS_FUNC) >> RPCS_V_FUNC) +#define GET_DRIVE(x) (((x) & RPCS_DRV) >> RPCS_V_DRV) + ENDBITS +}; + +/* RPWC 776716, two's complement word count */ +/* For PDP-11 must be even for data, and in multiples of 3 for format */ +static BITFIELD rp_wc_bits[] = { + BITFFMT(WC,16,%u), + ENDBITS +}; + +/* RPBA 776720, bus address */ +static BITFIELD rp_ba_bits[] = { +#define RPBA_IMP 0177776 /* implemented */ + BITF(BA,16), + ENDBITS +}; + +/* RPCA 776722, cylinder address */ +static BITFIELD rp_ca_bits[] = { +#define RPCA_IMP 0000777 /* implemented */ + BITFFMT(CYL,9,%u), + ENDBITS +}; + +/* RPDA 776724, disk address (track/sector) */ +static BITFIELD rp_da_bits[] = { +#define RPDA_IMPL 0017777 /* implemented */ +#define RPDA_RW 0017417 /* bits here */ +#define RPDA_M_SECT 017 +#define RPDA_SECT RPDA_M_SECT /* sector */ + BITFFMT(SECT,4,%u), +#define RPDA_V_SOT 4 +#define RPDA_SOT (RPDA_M_SECT << RPDA_V_SOT) /* current sect on track */ + BITFFMT(SOT,4,%u), +#define RPDA_V_TRACK 8 +#define RPDA_M_TRACK 037 +#define RPDA_TRACK (RPDA_M_TRACK << RPDA_V_TRACK) /* track */ + BITFFMT(SURF,5,%u), +#define GET_SECT(x) ((x) & RPDA_SECT) +#define GET_TRACK(x) (((x) & RPDA_TRACK) >> RPDA_V_TRACK) +#define GET_DA(c,h,s) (((c) * RP_NUMSF + (h)) * RP_NUMSC + (s)) + ENDBITS +}; + +/* RPM1 776726 maintenance 1, read-only, not implemented */ + +/* RPM2 776730 maintenance 2, read-only, not implemented */ + +/* RPM1 776732 maintenance 3, write-only, not implemented */ + +/* SUCA 776734 selected unit cylinder address, read-only */ +static BITFIELD rp_suca_bits[] = { + BITFFMT(CYL,9,%u), + ENDBITS +}; + +/* SILO 776736 silo memory, not implemented */ + +/* Maintenance Write Lockout Address (LOA) (the switches on the maint. panel) */ +static const char* offon[] = { "OFF", "ON" }; +static BITFIELD rp_wloa_bits[] = { +#define RPWLOA_IMPL 01777 +#define RPWLOA_CYL2 0377 /* cyls locked (x2) */ + BITFFMT(CYL2,8,%u), +#define RPWLOA_V_DRV 8 +#define RPWLOA_M_DRV 3 +#define RPWLOA_DRV (RPWLOA_M_DRV << RPWLOA_V_DRV) /* drive(s) locked */ + BITFFMT(DRV,3,%u), +#define GET_WLOACYL(x) ((((x) & RPWLOA_CYL2) << 1) | 1) +#define GET_WLOADRV(x) (((x) & RPWLOA_DRV) >> RPWLOA_V_DRV) + BITNCF(4), +#define RPWLOA_ON 0100000 + BITFNAM(PROTECT,1,offon), + ENDBITS +}; + +/* Data buffer and device registers */ + +static RPCONTR* rpxb = NULL; /* xfer buffer */ +static int32 rpds = 0; /* drive status */ +static int32 rper = 0; /* error status */ +static int32 rpcs = 0; /* control/status */ +static int32 rpwc = 0; /* word count */ +static int32 rpba = 0; /* memory address */ +static int32 rpca = 0; /* cylinder address */ +static int32 rpda = 0; /* disk address */ +static int32 suca = 0; /* current cylinder address */ +static int32 wloa = 0; /* write lockout address */ +static int32 not_impl = 0; /* dummy register value */ + +/* Debug detail levels */ + +#define RRDEB_OPS 001 /* transactions */ +#define RRDEB_RRD 002 /* reg reads */ +#define RRDEB_RWR 004 /* reg writes */ +#define RRDEB_TRC 010 /* trace */ +#define RRDEB_INT 020 /* interrupts */ +#define RRDEB_DAT 0100 /* transfer data */ + +static DEBTAB rr_deb[] = { + { "OPS", RRDEB_OPS, "transactions" }, + { "RRD", RRDEB_RRD, "register reads" }, + { "RWR", RRDEB_RWR, "register writes" }, + { "INTERRUPT", RRDEB_INT, "interrupts" }, + { "TRACE", RRDEB_TRC, "trace" }, + { "DATA", RRDEB_DAT, "transfer data" }, + { NULL, 0 } +}; + +static struct { + const char* name; + int32* valp; + BITFIELD* bits; +} rr_regs[] = { + { "RPDS", &rpds, rp_ds_bits }, + { "RPER", &rper, rp_er_bits }, + { "RPCS", &rpcs, rp_cs_bits }, + { "RPWC", &rpwc, rp_wc_bits }, + { "RPBA", &rpba, rp_ba_bits }, + { "RPCA", &rpca, rp_ca_bits }, + { "RPDA", &rpda, rp_da_bits }, + { "RPM1", ¬_impl, NULL }, + { "RPM2", ¬_impl, NULL }, + { "RPM3", ¬_impl, NULL }, + { "SUCA", &suca, rp_suca_bits }, + { "SILO", ¬_impl, NULL } +}; + +/* Forward decls */ + +static t_stat rr_rd (int32 *data, int32 PA, int32 access); +static t_stat rr_wr (int32 data, int32 PA, int32 access); +static int32 rr_inta (void); +static t_stat rr_svc (UNIT *uptr); +static t_stat rr_reset (DEVICE *dptr); +static void rr_go (void); +static void rr_set_done (int32 error); +static void rr_clr_done (void); +static t_stat rr_boot (int32 unitno, DEVICE *dptr); +static t_stat rr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +static t_stat rr_attach (UNIT *uptr, CONST char *cptr); +static t_stat rr_detach (UNIT *uptr); +static t_stat rr_set_type (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +static t_stat rr_show_type (FILE *st, UNIT *uptr, int32 val, CONST void *desc); +static t_stat rr_set_wloa (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +static t_stat rr_show_ctrl (FILE *st, UNIT *uptr, int32 val, CONST void *desc); +static const char *rr_description (DEVICE *dptr); + +/* RP11 data structures + + rr_reg RR register list + rr_unit RR unit list + rr_mod RR modifier list + rr_dev RR device descriptor +*/ + +static DIB rr_dib = { + IOBA_AUTO/*base address*/, RP_IOLN/*addresses used*/, + rr_rd, rr_wr, + 1/*# of vectors*/, IVCL(RR)/*locator*/, VEC_AUTO, + { rr_inta }, RP_IOLN/*addresses per device*/, +}; + +static REG rr_reg[] = { + /* registers */ + { ORDATADF(RPCS, rpcs, 16, "control/status", rp_cs_bits) }, + { ORDATADF(RPCA, rpca, 16, "cylinder address", rp_ca_bits) }, + { ORDATADF(RPDA, rpda, 16, "disk address", rp_da_bits) }, + { ORDATADF(RPBA, rpba, 16, "memory address", rp_ba_bits) }, + { ORDATADF(RPWC, rpwc, 16, "word count", rp_wc_bits) }, + { ORDATADF(RPDS, rpds, 16, "drive status", rp_ds_bits) }, + { ORDATADF(RPER, rper, 16, "error status", rp_er_bits) }, + { ORDATADF(SUCA, suca, 16, "cylinder address", rp_suca_bits) }, + { ORDATADF(WLOA, wloa, 16, "write lockout address", rp_wloa_bits) }, + + /* standard stuff */ + { FLDATAD (INT, IREQ(RR), INT_V_RR, "interrupt pending flag") }, + { FLDATAD (ERR, rpcs, CSR_V_ERR, "error flag (CSR<15>)") }, + { FLDATAD (DONE, rpcs, CSR_V_DONE, "device done flag (CSR<7>)") }, + { FLDATAD (IE, rpcs, CSR_V_IE, "interrupt enable flag (CSR<6>)") }, + { ORDATA (DEVADDR, rr_dib.ba, 32), REG_HRO }, + { ORDATA (DEVVEC, rr_dib.vec, 16), REG_HRO }, + { NULL } +}; + +static UNIT rr_unit[RP_NUMDR] = { + { UDATA(rr_svc, + UNIT_FIX | UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | UNIT_RP03, + RP_SIZE_RP03) }, + { UDATA(rr_svc, + UNIT_FIX | UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | UNIT_RP03, + RP_SIZE_RP03) }, + { UDATA(rr_svc, + UNIT_FIX | UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | UNIT_RP03, + RP_SIZE_RP03) }, + { UDATA(rr_svc, + UNIT_FIX | UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | UNIT_RP03, + RP_SIZE_RP03) }, + { UDATA(rr_svc, + UNIT_FIX | UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | UNIT_RP03, + RP_SIZE_RP03) }, + { UDATA(rr_svc, + UNIT_FIX | UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | UNIT_RP03, + RP_SIZE_RP03) }, + { UDATA(rr_svc, + UNIT_FIX | UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | UNIT_RP03, + RP_SIZE_RP03) }, + { UDATA(rr_svc, + UNIT_FIX | UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | UNIT_RP03, + RP_SIZE_RP03) } +}; + +static MTAB rr_mod[] = { + { MTAB_VDV, 0, + "TYPE", NULL, + NULL, rr_show_ctrl, NULL, + "Display controller type" }, + { MTAB_VDV | MTAB_VALR, 0, + NULL, "PROTECT", + rr_set_wloa, NULL, NULL, + "Set write lockout mode/address" }, + { MTAB_VUN, 0, + "WRITEENABLED", "WRITEENABLED", + set_writelock, show_writelock, NULL, + "Write enable disk drive" }, + { MTAB_VUN, 1, + NULL, "LOCKED", + set_writelock, NULL, NULL, + "Write lock disk drive" }, + { MTAB_VUN, 0, + "TYPE", NULL, + NULL, rr_show_type, NULL, + "Display device type" }, + { MTAB_VUN, 0/*RP02*/, + NULL, RP_RP02, + rr_set_type, NULL, NULL, + "Set " RP_RP02 " disk type" }, + { MTAB_VUN, UNIT_RP03, + NULL, RP_RP03, + rr_set_type, NULL, NULL, + "Set " RP_RP03 " disk type"}, + { UNIT_NOAUTO, 0, + "autosize", "AUTOSIZE", + NULL, NULL, NULL, + "Set type based on file size at attach" }, + { UNIT_NOAUTO, UNIT_NOAUTO, + "noautosize", "NOAUTOSIZE", NULL, + NULL, NULL, + "Disable disk autosize on attach" }, + { MTAB_VUN | MTAB_VALR, 0, + "FORMAT", "FORMAT={AUTO|SIMH|VHD|RAW}", + sim_disk_set_fmt, sim_disk_show_fmt, NULL, + "Set/Display disk format" }, + { MTAB_VDV | MTAB_VALR, 010, + "ADDRESS", "ADDRESS", + set_addr, show_addr, NULL, + "Bus address" }, + { MTAB_VDV | MTAB_VALR, 0, + "VECTOR", "VECTOR", + set_vec, show_vec, NULL, + "Interrupt vector" }, + { 0 } +}; + +DEVICE rr_dev = { + "RR", rr_unit, rr_reg, rr_mod, RP_NUMDR, + 8/*address radix*/, 24/*address width*/, 1/*address increment*/, + 8/*data radix*/, RPWRDSZ/*data width*/, + NULL/*examine()*/, NULL/*deposit()*/, + rr_reset, rr_boot, rr_attach, rr_detach, + &rr_dib, + DEV_DIS | DEV_DISABLE | DEV_UBUS | DEV_Q18 | DEV_DEBUG | DEV_DISK, + 0/*debug control*/, rr_deb, + NULL/*msize()*/, NULL/*logical name*/, + rr_help, NULL/*attach_help()*/, NULL/*help_ctx*/, + rr_description, +}; + +/* I/O dispatch routine, I/O addresses 17776710 - 17776736 + + 17776710 RPDS read-only except for attention bits + 17776712 RPER read-only + 17776714 RPCS read/write + 17776716 RPWC read/write + 17776720 RPBA read/write + 17776722 RPCA read/write + 17776724 RPDA read/write + 17776726 RPM1 read-only, unimplemented + 17776730 RPM2 read-only, unimplemented + 17776732 RPM3 write-only, unimplemented + 17776734 SUCA read-only + 17776736 SILO read/write, unimplemented + +RP11-C actually responds to the range 17776700 - 17776736 with the first 4 word +locations unused. + +The original RP11 had the following differences: it responded to the address +range 17776710 - 17776746 (3 buffer registers RPB1-RPB3 followed RPM3, then 3 +unused 42-46). RPCA was both the cylinder address in the lower 8 bits <00:07> +(read-write), and the selected unit current cylinder address (a la SUCA in +RP11-C) in the higher 8 bits <08:15> (read-only). The RP11 only supported the +RP02 disk drives, and so it only required 8 bits for cylinder addresses. The +RP03 bit in RPDS was always 0. But programmatically it was compatible with the +-C revision (except for the separate SUCA, which was not used in most software). + +RP11-E was just a newer version of RP11-C and supported both RP02 and RP03 disk +drives on the same controller. + +Some operating systems want you to specify the latter range (RSTS/E), but some +just want to know where the CSR is located, so they auto-calculate the range. +*/ + +static t_stat rr_rd (int32 *data, int32 PA, int32 access) +{ + /* offset by base then decode <4:1> */ + int rn = ((PA - rr_dib.ba) >> 1) & 017; + UNIT* uptr; + + switch (rn) { + case 0: /* RPDS */ + case 1: /* RPER */ + case 2: /* RPCS */ + /* RPDS */ + uptr = rr_dev.units + GET_DRIVE(rpcs); /* selected unit */ + rpds &= RPDS_ATTN; /* attention bits */ + if (!(uptr->flags & UNIT_DIS)) { /* not disabled? */ + if (GET_DTYPE(uptr->flags)) + rpds |= RPDS_RP03; + if (uptr->flags & UNIT_ATT) { /* attached? */ + rpds |= RPDS_ONLN; + if (uptr->flags & UNIT_WPRT) /* write locked? */ + rpds |= RPDS_WLK; + if (uptr->SEEKING) /* still seeking? */ + rpds |= RPDS_SEEK; + else if (!sim_is_active(uptr)) /* idle? */ + rpds |= RPDS_RDY; + } + } + + /* RPER */ + rper &= RPER_REAL; + rper |= RPDS_DKER(rpds); + + /* RPCS */ + rpcs &= RPCS_REAL; + rpcs |= RPER_HARD(rper) | RPER_SOFT(rper); + + *data = *rr_regs[rn].valp; + break; + + case 3: /* RPWC */ + *data = rpwc; + break; + + case 4: /* RPBA */ + *data = rpba; + break; + + case 5: /* RPCA */ + *data = rpca; + break; + + case 6: /* RPDA */ + rpda &= RPDA_RW; + rpda |= (rand() % RP_NUMSC) << RPDA_V_SOT; /* a random sect */ + *data = rpda; + break; + + case 10: /* SUCA */ + *data = suca; + break; + + default: /* not implemented */ + *data = 0; + return SCPE_OK; + } + sim_debug(RRDEB_RRD, &rr_dev, ">>RR read: %s=%#o\n", rr_regs[rn].name, *data); + sim_debug_bits(RRDEB_RRD, &rr_dev, rr_regs[rn].bits, *data, *data, 1); + return SCPE_OK; +} + +#define RR_DATOB(r, d) (PA & 1 ? ((d) << 8) | ((r) & 0377) : ((r) & ~0377) | (d)) + +static t_stat rr_wr (int32 data, int32 PA, int32 access) +{ + /* offset by base then decode <4:1> */ + int rn = ((PA - rr_dib.ba) >> 1) & 017; + int32 n, old_val = *rr_regs[rn].valp; + + switch (rn) { + case 0: /* RPDS */ + if (access != WRITEB || !(PA & 1)) { + rpds &= ~(data & RPDS_ATTN); /* clr attention bits */ + if (!(rpds & RPDS_ATTN) && (rpcs & RPCS_AIE) + && (!(rpcs & CSR_IE) || !(rpcs & CSR_DONE))) { + sim_debug(RRDEB_INT, &rr_dev, "rr_wr(ATT:CLR_INT)\n"); + CLR_INT(RR); /* clr int request */ + } + } + break; + + case 1: /* RPER: read-only */ + break; + + case 2: /* RPCS */ + if (access == WRITEB) + data = RR_DATOB(rpcs, data); + if (!(data & (RPCS_AIE | CSR_IE))) { /* int disable? */ + sim_debug(RRDEB_INT, &rr_dev, "rr_wr(CSR:CLR_INT)\n"); + CLR_INT(RR); /* clr int request */ + } else if (((data & CSR_IE) + && (rpcs & (CSR_DONE | CSR_IE)) == CSR_DONE) || + ((data & RPCS_AIE) + && !(rpcs & RPCS_AIE) && (rpds & RPDS_ATTN))) { + sim_debug(RRDEB_INT, &rr_dev, "rr_wr(CSR:SET_INT)\n"); + SET_INT(RR); /* set int request */ + } + rpcs &= ~RPCS_RW; + rpcs |= data & RPCS_RW; + n = GET_DRIVE(rpcs); + if (n != GET_DRIVE(old_val)) { + UNIT* uptr = rr_dev.units + n; /* new selected unit */ + suca = uptr->CYL; + n = 1; + } else + n = 0; /* same old */ + if (!(rpcs & CSR_DONE)) { /* not ready? */ + if ((data & CSR_GO) || n) /* GO or de-selected? */ + rper |= RPER_PGE; + } else if (data & CSR_GO) /* new function? */ + rr_go(); + break; + + case 3: /* RPWC */ + if (access == WRITEB) + data = RR_DATOB(rpwc, data); + rpwc = data; + break; + + case 4: /* RPBA */ + if (access == WRITEB) + data = RR_DATOB(rpba, data); + rpba = data & RPBA_IMP; + break; + + case 5: /* RPCA */ + if (access == WRITEB) + data = RR_DATOB(rpca, data); + rpca = data & RPCA_IMP; + break; + + case 6: /* RPDA */ + if (access == WRITEB) + data = RR_DATOB(rpda, data); + rpda &= ~RPDA_RW; + rpda |= data & RPDA_RW; + break; + + case 10: /* SUCA: read-only */ + break; + + default: + return SCPE_OK; + } + sim_debug(RRDEB_RWR, &rr_dev, ">>RR write: %s=%#o\n", rr_regs[rn].name, data); + /* note that this is post-op; so e.g. it won't ever show the GO bit as 1 */ + sim_debug_bits(RRDEB_RWR, &rr_dev, rr_regs[rn].bits, old_val, *rr_regs[rn].valp, 1); + return SCPE_OK; +} + +/* Initiate new function */ + +static void rr_go (void) +{ + int32 i, cyl, head, sect, func, type; + int rd, wr; + UNIT* uptr; + + assert(rpcs & CSR_DONE); + + func = GET_FUNC(rpcs); /* get function */ + if (func == RPCS_RESET) { /* control reset? */ + rpds = 0; + rper = 0; + rpcs = CSR_DONE; + rpwc = 0; + rpba = 0; + rpca = 0; + rpda = 0; + suca = rr_dev.units[0].CYL; + sim_debug(RRDEB_INT, &rr_dev, "rr_go(RESET:CLR_INT)\n"); + CLR_INT(RR); /* clr int request */ + return; + } + + rr_clr_done(); /* clear done */ + rper = 0; /* clear errors */ + rpcs &= ~(CSR_ERR | RPCS_HERR); /* clear summary */ + i = GET_DRIVE(rpcs); /* get drive no */ + uptr = rr_dev.units + i; /* selected unit */ + + if (!(uptr->flags & UNIT_ATT)) { /* not attached? */ + rr_set_done(RPER_PGE); + return; + } + + i = 0; /* errors detected */ + rd = func == RPCS_READ || func == RPCS_RD_NOSEEK || func == RPCS_WCHK; + wr = func == RPCS_WRITE || func == RPCS_WR_NOSEEK; + + if (wr && (uptr->flags & UNIT_WPRT)) /* write and locked? */ + i |= RPER_WPV; + if (uptr->SEEKING || sim_is_active(uptr)) /* still busy? */ + i |= RPER_PGE; + if (rpcs & RPCS_HDR) { /* format and ... */ + if (!(rpcs & RPCS_MODE)) /* ... not 18b? */ + i |= RPER_MODE; + else if (!(rd | wr) || /* ... or not R/W? or ... */ + (rd && -((int16) rpwc) != 3) || /* rd hdr: wc m.b. 3 */ + (wr && -((int16) rpwc) % 3)) { /* wr hdr: wc m.b. mult of 3 */ + i |= RPER_PGE; + } + } else if (rd | wr) { /* regular R/W and ... */ + if (rpcs & RPCS_MODE) /* ... 18b? */ + i |= RPER_MODE; +#if 0 /* per doc, rpwc must be even; but DOS/Batch uses odd wc xfers (?!) */ + else if (rpwc & 1) /* ... or odd wc? */ + i |= RPER_PGE; +#endif + } + sect = GET_SECT(rpda); + if (sect >= RP_NUMSC) + i |= RPER_NXS; + type = GET_DTYPE(uptr->flags); /* get drive type */ + if (func == RPCS_HOME) { + head = 0; + cyl = 0; + } else if (func == RPCS_RD_NOSEEK || func == RPCS_WR_NOSEEK) { + head = uptr->HEAD; + cyl = uptr->CYL; + } else { + head = GET_TRACK(rpda); + cyl = rpca; + if (head >= RP_NUMSF) + i |= RPER_NXT; + if (cyl >= drv_tab[type].cyl) + i |= RPER_NXC; + } + if ((wloa & RPWLOA_ON) && wr + && !(i & (RPER_WPV | RPER_NXC | RPER_NXT | RPER_NXS))) { + if (GET_DRIVE(rpcs) <= GET_WLOADRV(wloa)) /* unit protected? */ + i |= RPER_WPV; + else if (cyl <= GET_WLOACYL(wloa)) /* cyl protected? */ + i |= RPER_WPV; + } + if (i) { + rr_set_done(i); /* set done */ + return; + } + + /* seek time */ + if (func == RPCS_HOME) + i = drv_tab[type].seek_ave / 2; + else if (!(i = abs(cyl - uptr->CYL))) + i = drv_tab[type].seek_1 / 2; + else if (i <= 2) + i *= drv_tab[type].seek_1; + else if (i <= (3 * drv_tab[type].cyl) / 4) + i = drv_tab[type].seek_ave; + else + i = drv_tab[type].seek_max; + if (func == RPCS_SEEK || func == RPCS_HOME) { /* seek? */ + uptr->SEEKING = 1; /* start seeking */ + rr_set_done(0); /* set done */ + sim_activate(uptr, i / 10); /* schedule */ + } else + sim_activate(uptr, (i + RP_ROT_12) / 10); /* I/O takes longer */ + + uptr->CYL = cyl; /* put on cylinder */ + uptr->HEAD = head; /* save head too */ + uptr->FUNC = func; /* save func */ + return; +} + +/* Complete seek */ + +static t_stat rr_seek_done (UNIT *uptr, int cancel) +{ + int32 n; + + assert(uptr->SEEKING); + assert(uptr->FUNC == RPCS_SEEK || uptr->FUNC == RPCS_HOME); + n = (int32)(uptr - rr_dev.units); /* get drv number */ + if (n == GET_DRIVE(rpcs)) + suca = cancel ? 0 : uptr->CYL; /* update cyl shown */ + uptr->SEEKING = 0; /* set seek done */ + assert((1 << n) | RPDS_ATTN); + rpds |= 1 << n; /* set attention */ + if (rpcs & RPCS_AIE) { /* att ints enabled? */ + sim_debug(RRDEB_INT, &rr_dev, "rr_seek_done(SET_INT)\n"); + SET_INT(RR); + } + return SCPE_OK; +} + +/* Service a unit + + If seek in progress, complete seek command + Else complete data transfer command + + The unit control block contains the function and disk address for + the current command. + + Some registers must be revalidated because they could have been + modified in between go() and now. +*/ + +static t_stat rr_svc (UNIT *uptr) +{ + int32 func, cyl, head, sect, da, err, wc, n; + t_seccnt todo, done; + t_stat ioerr; + uint32 ma; + int rd; + + if (uptr->SEEKING) /* seek? */ + return rr_seek_done(uptr, 0); + + func = uptr->FUNC; + assert(func && ~(rpcs & CSR_DONE)); + + if (!(uptr->flags & UNIT_ATT)) { /* attached? */ + rr_set_done(RPER_PGE); + return SCPE_UNATT; + } + sect = GET_SECT(rpda); /* get sect */ + if (sect >= RP_NUMSC) { /* bad sector? */ + rr_set_done(RPER_NXS); + return SCPE_OK; + } + + rd = func == RPCS_READ || func == RPCS_RD_NOSEEK || func == RPCS_WCHK; + wc = 0200000 - rpwc; /* get wd cnt */ + cyl = uptr->CYL; + head = uptr->HEAD; + n = GET_DTYPE(uptr->flags); /* get drive type */ + assert(cyl < drv_tab[n].cyl && head < RP_NUMSF); + da = GET_DA(cyl, head, sect); /* form full disk addr */ + assert(da < drv_tab[n].size); + n = drv_tab[n].size - da; /* sectors available */ + err = 0; /* errors detected */ + if (rpcs & RPCS_HDR) { /* header ops? */ + if (!(rpcs & RPCS_MODE)) + err |= RPER_MODE; /* must be in 18b mode */ + else if ((rd && wc != 3) || (!rd && wc % 3)) /* DEC-11-HRPCA-C-D 3.8 */ + err |= RPER_PGE; + else if (rd) /* a typo in doc??? */ + n = 3; /* can only read 3 wds */ + else + n *= 3; /* 3 wds per sector */ + } else { /* no: regular R/W */ + if (rpcs & RPCS_MODE) + err |= RPER_MODE; /* must be in PDP-11 mode */ +#if 0 /* per doc, wc must be even; but DOS/Batch uses odd wc xfers (?!) */ + else if (wc & 1) /* must be even */ + err |= RPER_PGE; +#endif + else + n *= RP_NUMWD; /* can do this many */ + } + if (err) { + rr_set_done(err); + return SCPE_OK; + } + if (wc > n) + wc = n; + assert(wc); + + /* A note on error handling: + * RP11 processes data words between drive and memory absolutely sequentially + * (not by the sector like the SIMH API provides). Therefore, controller + * errors should be asserted to follow that scenario. + * + * 1. When reading from disk, an I/O error must be deferred until all words + * (read from the disk so far) have been verified not to cause NXM. If any + * word did, then NXM gets reported, and the I/O error gets discarded + * (because the real controller would have stopped the operation right then + * and there, and would not have encountered the (later) I/O condition). + * + * 2. When writing, I/O errors take precedence, provided that words keep + * passing the address check in extraction from memory. But no NXM should + * be reported for any words that reside after the completed I/O boundary in + * case of a short write to disk. + * + * 3. Disk pack overrun is strictly a run-off of an otherwise successful + * completion, which has left a residual word counter non-zero, because had + * an earlier error stopped the disk operation, the overrun situation could + * not have been experienced (the end of pack would not have been reached). + */ + + ma = ((rpcs & RPCS_MEX) << (16 - RPCS_V_MEX)) | rpba; /* get mem addr */ + + if (rd) { /* read */ + if (rpcs & RPCS_HDR) { /* format? */ + /* Sector header is loaded in the 36-bit Buffer Register(BR): + 17 0-bits, 9-bit cyl, 5-bit track, a spare bit, 4-bit sect */ + rpxb[0] = 0; /* BR<35:20> */ + rpxb[1] = (cyl << 6) | (head << 1); /* BR<19:04> */ + rpxb[2] = sect; /* BR<03:00> */ + ioerr = 0; + done = 1; /* 1 sector done */ + } else { /* normal read */ + DEVICE* dptr = find_dev_from_unit(uptr); + todo = (wc + (RP_NUMWD - 1)) / RP_NUMWD; /* sectors to read */ + ioerr = sim_disk_rdsect(uptr, da, (uint8*) rpxb, &done, todo); + n = done * RP_NUMWD; /* words read */ + sim_disk_data_trace(uptr, (uint8*) rpxb, da, n * sizeof(*rpxb), "rr_read", + RRDEB_DAT & (dptr->dctrl | uptr->dctrl), RRDEB_OPS); + if (done >= todo) + ioerr = 0; /* good stuff */ + else if (ioerr) + wc = n; /* short, adj wc */ + else { + todo -= done; /* to clear ... */ + todo *= RP_NUMWD * sizeof(*rpxb); /* ... bytes */ + memset(rpxb + n, 0, todo); + } + } + if (func == RPCS_WCHK) { + uint32 a = ma; + for (n = 0; n < wc; ++n) { /* loop thru buf */ + RPCONTR data; + if (MAP_RDW(a, 1, &data)) { /* mem wd */ + err |= RPER_NXM; /* NXM? set flg */ + break; + } + a += 2; + if (ioerr) + continue; + if (data != rpxb[n]) /* match to disk? */ + err |= RPER_WCE; /* no, err */ + } + n %= wc; + } else if ((n = MAP_WRW(ma, wc, rpxb))) { /* store buf */ + err |= RPER_NXM; /* NXM? set flag */ + wc -= n; /* adj wd cnt */ + } + if (!n && ioerr) { /* all wrds ok but I/O? */ + err |= RPER_FMTE; /* report as FMTE */ + if (func == RPCS_WCHK) + err |= RPER_WCE; + } + } else { /* write */ + if ((n = MAP_RDW(ma, wc, rpxb))) /* get buf */ + wc -= n; /* adj wd cnt */ + if (wc && !(rpcs & RPCS_HDR)) { /* regular write? */ + DEVICE* dptr = find_dev_from_unit(uptr); + int32 m = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1); /* clr to */ + memset(rpxb + wc, 0, (m - wc) * sizeof(*rpxb)); /* end of blk */ + sim_disk_data_trace(uptr, (uint8*) rpxb, da, m * sizeof(*rpxb), "rr_write", + RRDEB_DAT & (dptr->dctrl | uptr->dctrl), RRDEB_OPS); + todo = m / RP_NUMWD; /* sectors to write */ + ioerr = sim_disk_wrsect(uptr, da, (uint8*) rpxb, &done, todo); + if (done < todo) { + wc = done * RP_NUMWD; /* words written */ + err |= RPER_FMTE; /* report as FMTE */ + if (!ioerr) + ioerr = 1; /* just in case */ + } else if (n) + err |= RPER_NXM; /* NXM? set flg */ + else + ioerr = 0; /* good stuff */ + } else { + ioerr = 0; /* good stuff */ + done = wc / 3; + if (n) + err |= RPER_NXM; /* NXM? set flg */ + } + } + + if (wc) { /* any xfer? */ + rpwc += wc; + rpwc &= 0177777; + ma += wc << 1; + rpba = ma & RPBA_IMP; + rpcs &= ~RPCS_MEX; + rpcs |= (ma >> (16 - RPCS_V_MEX)) & RPCS_MEX; + + assert(done); + rd = func == RPCS_RD_NOSEEK || func == RPCS_WR_NOSEEK; + if (!rd || --done) { /* w/SEEK or 2+ sects? */ + da += done; /* update DA */ + n = GET_DTYPE(uptr->flags); /* drive type */ + assert(da <= drv_tab[n].size); + head = da / RP_NUMSC; /* new head (w/cyl) */ + cyl = head / RP_NUMSF; /* new cyl */ + if (cyl == drv_tab[n].cyl) { /* at the end? */ + cyl = drv_tab[n].cyl - 1; /* last cyl and ... */ + head = RP_NUMSF - 1; /* ... head keep on */ + } else + head %= RP_NUMSF; /* wrap up head */ + n = (int32)(uptr - rr_dev.units); /* get drv number */ + if (!rd) /* w/SEEK I/O? */ + uptr->HEAD = head; /* yes: select new head */ + else if (uptr->CYL != cyl || /* no: arm moved or */ + (rpwc && !(err | ioerr))) { /* boundary exceeded? */ + assert((1 << n) & RPDS_ATTN); + rpds |= 1 << n; /* set attention */ + if (rpcs & RPCS_AIE) { /* att ints enabled? */ + sim_debug(RRDEB_INT, &rr_dev, "rr_svc(SET_INT)\n"); + SET_INT(RR); /* request interrupt */ + } + } + uptr->CYL = cyl; /* update new cyl */ + if (n == GET_DRIVE(rpcs)) + suca = uptr->CYL; /* let it out */ + } + } else + assert(err); + + if (rpwc && !(err | ioerr)) + err |= RPER_EOP; /* disk pack overrun */ + rr_set_done(err); + + if (ioerr) { /* I/O error? */ + sim_perror("RR I/O error"); + return SCPE_IOERR; + } + return SCPE_OK; +} + +/* Interrupt state change routines + + rr_clr_done clear done + rr_set_done set done and possibly errors + rr_inta interrupt acknowledge +*/ + +static void rr_clr_done (void) +{ + rpcs &= ~CSR_DONE; /* clear done */ + if ((rpcs & CSR_IE) && (!(rpcs & RPCS_AIE) || !(rpds & RPDS_ATTN))) { + sim_debug(RRDEB_INT, &rr_dev, "rr_clr_done(CLR_INT)\n"); + CLR_INT(RR); /* clear int req */ + } + return; +} + +static void rr_set_done (int32 error) +{ + rper |= error; + rpcs |= CSR_DONE; /* set done */ + if (rpcs & CSR_IE) { /* int enable? */ + sim_debug(RRDEB_INT, &rr_dev, "rr_set_done(SET_INT)\n"); + SET_INT(RR); /* request int */ + } + return; +} + +static int32 rr_inta (void) +{ + sim_debug(RRDEB_INT, &rr_dev, "rr_inta()\n"); + assert(((rpcs & RPCS_AIE) && (rpds & RPDS_ATTN)) || + ((rpcs & CSR_IE) && (rpcs & CSR_DONE))); + rpcs &= ~RPCS_AIE; /* AIE is one-shot */ + return rr_dib.vec; /* return vector */ +} + +/* Device reset */ + +static t_stat rr_reset (DEVICE *dptr) +{ + int i; + + /* some sanity check first */ + assert(sizeof(rr_regs)/sizeof(rr_regs[0]) == RP_IOLN/2); + + /* clear everything now */ + rpds = 0; + rper = 0; + rpcs = CSR_DONE; + rpwc = 0; + rpba = 0; + rpca = 0; + rpda = 0; + suca = 0; + assert(dptr == &rr_dev); + sim_debug(RRDEB_INT, &rr_dev, "rr_reset(CLR_INT)\n"); + CLR_INT(RR); + for (i = 0; i < RP_NUMDR; ++i) { + UNIT* uptr = rr_dev.units + i; + sim_cancel(uptr); + uptr->CYL = 0; + uptr->FUNC = 0; + uptr->HEAD = 0; + uptr->SEEKING = 0; + } + if (rpxb == NULL) + rpxb = (RPCONTR*) calloc(RP_MAXFR, sizeof (*rpxb)); + if (rpxb == NULL) + return SCPE_MEM; + return auto_config(NULL, 0); +} + +/* Attach/detach routines */ + +static t_stat rr_attach (UNIT *uptr, CONST char *cptr) +{ + static const char* rr_types[] = { RP_RP03, RP_RP02, NULL }; + int type = GET_DTYPE(uptr->flags); + return sim_disk_attach_ex2(uptr, cptr, + RP_NUMWD * sizeof(*rpxb), sizeof (*rpxb), + TRUE, 0, drv_tab[type].name, + 0, 0, rr_types, 0); +} + +static t_stat rr_detach (UNIT *uptr) +{ + if (uptr->SEEKING) + rr_seek_done(uptr, 1/*cancel*/); + else if (sim_is_active(uptr)) + rr_set_done(RPER_TE); + sim_cancel(uptr); + uptr->CYL = 0; + uptr->FUNC = 0; + uptr->HEAD = 0; + return sim_disk_detach(uptr); +} + +/* Set / show drive type */ + +static t_stat rr_set_type (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + if ((val & ~UNIT_RP03) || cptr) + return SCPE_ARG; + if (uptr->flags & UNIT_ATT) + return SCPE_ALATT; + uptr->capac = RP_SIZE(drv_tab[GET_DTYPE(val)].size); + uptr->flags &= ~UNIT_RP03; + uptr->flags |= val; + return SCPE_OK; +} + +static t_stat rr_show_type (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + fputs(drv_tab[GET_DTYPE(uptr->flags)].name, st); + return SCPE_OK; +} + +/* Set WLOA */ + +static t_stat rr_set_wloa (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + DEVICE* dptr = find_dev_from_unit(uptr); + if (!cptr || !*cptr) + return SCPE_ARG; + if (strcasecmp(cptr, "OFF") == 0) { + wloa &= ~RPWLOA_ON; + return SCPE_OK; + } + if (strncasecmp(cptr, "ON", 2) != 0) + return SCPE_ARG; + cptr += 2; + if (*cptr == ';') { + char* end; + long val; + errno = 0; + val = strtol(++cptr, &end, 0); + if (errno || !end || *end || end == cptr || (val & ~RPWLOA_IMPL)) + return SCPE_ARG; + wloa &= ~RPWLOA_IMPL; + wloa |= val; + } else if (!*cptr) + return SCPE_2FARG; + wloa |= RPWLOA_ON; + return SCPE_OK; +} + +/* Device bootstrap */ + +static t_stat rr_boot (int32 unitno, DEVICE *dptr) +{ + return SCPE_NOFNC; +} + +/* Misc */ + +#define RP_DESCRIPTION RP_RP11 "/" RP_RP02 "/" RP_RP03 " disk pack device" + +static t_stat rr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ + size_t i; + static const char text[] = + /*567901234567890123456789012345678901234567890123456789012345678901234567890*/ + RP_DESCRIPTION "\n\n" + "Implementation does not include any maintenance registers or disk\n" + "formatting operations yet supports the Write Lockout Address (LOA)\n" + "register, which can be set with a PROTECT command:\n\n" + " sim> SET RR PROTECT=ON;0407\n\n" + "to turn the protection on (in this case, the entire units 0 and 1,\n" + "and 7x2=14 first cylinders of unit 2 will become write-locked).\n" + "The current setting can be obtained by examining the WLOA register in\n" + "the device:\n\n" + " sim> EXAMINE RR WLOA\n" + " WLOA: 100407 PROTECT=ON DRV=1 CYL2=7\n\n" + "To remove the lockout:\n\n" + " sim> SET RR PROTECT=OFF\n" + " sim> EXAMINE RR WLOA\n" + " WLOA: 000407 PROTECT=OFF DRV=1 CYL2=7\n\n" + "Note that it does not clear the address but turns the feature off.\n\n" + "A detailed description of this device can be found in the\n" + "\"PDP-11 Peripherals Handbook\" (1973 - 1976) and in the technical manual\n" + "\"RP11-C Disk Pack Drive Controller Maintenance Manual\" (1974)\n" + "(DEC-11-HRPCA-C-D).\n\n" + "In default configuration " RP_RP11 " responds to range 17776700 - 17776736\n" + "with the first 4 word locations not occupied by any device registers (and\n" + "so 17776710 is the first used location). Some operating systems want you\n" + "to specify the extended range (e.g. RSTS/E), but some -- the relevant range\n" + "(17776710 - 17776736), yet some just want to know where the CSR is located\n" + "(17776714 by default), so they can auto-calculate the range on their own.\n\n" + "Disk drive parameters:\n\n" + " Cylinders Heads Sects/Trk Capacity Average access\n" + " Total Spare Nominal Usable time, ms\n"; + fputs(text, st); + for (i = 0; i < sizeof(drv_tab)/sizeof(drv_tab[0]); ++i) { + uint32 spare = GET_DA(drv_tab[i].spare, RP_NUMSF, RP_NUMSC); + uint32 total = drv_tab[i].size; + fprintf(st, "%.6s: %5u %5u %5u %5u" + " %5.1fMB %5.1fMB %5u.%1u\n", drv_tab[i].name, + drv_tab[i].cyl, drv_tab[i].spare, RP_NUMSF, RP_NUMSC, + RP_SIZE(total - spare) / .5e6, RP_SIZE(total) / .5e6, + (drv_tab[i].seek_ave + RP_ROT_12)/10, + (drv_tab[i].seek_ave + RP_ROT_12)%10); + } + fprint_set_help (st, dptr); + fprint_show_help(st, dptr); + fprintf(st, + "\nThe " RP_RP11 " is disabled in a Qbus system with more than 256KB of memory.\n"); + fprint_reg_help (st, dptr); + return SCPE_OK; +} + +static const char *rr_description (DEVICE *dptr) +{ + return RP_DESCRIPTION; +} + +/* Show / switch controller type */ + +static t_stat rr_show_ctrl (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + fputs(RP_RP11, st); + return SCPE_OK; +} + +#elif !defined(UC15) +#error "RP11/-C/-E can only be used in PDP-11 configuration" +#endif /*VM_PDP11 && !UC15*/ diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index 189b020a4..15b9a32b7 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -1,6 +1,6 @@ /* pdp11_sys.c: PDP-11 simulator interface - Copyright (c) 1993-2022, Robert M Supnik + Copyright (c) 1993-2024, 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,9 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 05-May-24 RMS Merged CH11 (Lars Brinkhoff) + 18-Dec-23 RMS Fixed disassembly of ASH,ASHC,MUL,DIV (Paul Koning) + 12-May-23 RMS Added RPB support 31-Dec-22 RMS Floating loads are src,dst (nickd4) 25-Jul-22 RMS Re-enabled VH11 after fixes (Mark Pizzolato) 17-Feb-20 RMS Disabled VH11 @@ -98,6 +101,7 @@ extern DEVICE rx_dev; extern DEVICE ry_dev; extern DEVICE mba_dev[]; extern DEVICE rp_dev; +extern DEVICE rpb_dev; extern DEVICE rs_dev; extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev; extern DEVICE tm_dev; @@ -110,6 +114,7 @@ extern DEVICE xu_dev, xub_dev; extern DEVICE ke_dev; extern DEVICE kg_dev; extern DEVICE uca_dev, ucb_dev; +extern DEVICE ch_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern uint16 *M; @@ -142,6 +147,7 @@ DEVICE *sim_devices[] = { &mba_dev[0], &mba_dev[1], &mba_dev[2], + &mba_dev[3], &clk_dev, &pclk_dev, &ptr_dev, @@ -164,6 +170,7 @@ DEVICE *sim_devices[] = { &rx_dev, &ry_dev, &rp_dev, +// &rpb_dev, &rs_dev, &rq_dev, &rqb_dev, @@ -181,6 +188,7 @@ DEVICE *sim_devices[] = { &xub_dev, &kg_dev, &ke_dev, + &ch_dev, #else &clk_dev, &tti_dev, @@ -339,8 +347,7 @@ static const int32 masks[] = { 0177700+I_D, 0177400+I_D, 0177700, 0177400, 0177400, 0177000, 0177000, 0177400, 0177400+I_D+I_L, 0170000, 0177777, 0177777, -0177700+I_D, 0177400+I_D, 0177700, 0177400, -0177000, 0177700+I_D, 0177400, 0177400+I_D+I_L +0177000, 0177400+I_D, 0177400, 0177400+I_D+I_L }; static const char *opcode[] = { diff --git a/PDP11/pdp11_ts.c b/PDP11/pdp11_ts.c index 4f0342327..930cb7bb9 100644 --- a/PDP11/pdp11_ts.c +++ b/PDP11/pdp11_ts.c @@ -1,6 +1,6 @@ /* pdp11_ts.c: TS11/TSV05 magnetic tape simulator - Copyright (c) 1993-2022, Robert M Supnik + Copyright (c) 1993-2023, 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,8 @@ ts TS11/TSV05 magtape + 29-Oct-23 RMS Implemented distinction between BOT and POS==0 + INIT command is a NOP 26-Mar-22 RMS Added extra case points for new MTSE definitions 27-Oct-14 RMS Fixed bug in read forward with byte swap 23-Oct-13 RMS Revised for new boot setup routine @@ -87,6 +89,25 @@ - PDP-11 Unibus 22b systems - the TS11 behaves as an 18b Unibus peripheral and must go through the I/O map - VAX Q22 systems - the TS11 must go through the I/O map + + The TS11 must distinguish between true beginning of tape (BOT) - + positioned at the tape marker - and positioned before the first + record (POS == 0). BOT is set under the following circumstances: + + - Mount (ATTACH) + - Rewind + - Backward operation, !BOT && POS==0. This sets RIB (rewind into + BOT) and is an error + + It is cleared by any successful forward operation. + + Therefore, reverse operations (except rewind) have three states: + + - !BOT, POS != 0. BOT unchanaged. + - !BOT, POS == 0. Set BOT and RIB; error. + - BOT. Set function reject. + + Rewind always moves the tape to BOT, even if it is already at BOT. */ #if defined (VM_PDP10) /* PDP10 version */ @@ -279,6 +300,7 @@ int32 tsdbx = 0; /* data buf ext */ int32 tscmdp[CMD_PLNT] = { 0 }; /* command packet */ int32 tsmsgp[MSG_PLNT] = { 0 }; /* message packet */ int32 tswchp[WCH_PLNT] = { 0 }; /* wr char packet */ +int32 ts_bot = 0; /* at BOT */ int32 ts_ownc = 0; /* tape owns cmd */ int32 ts_ownm = 0; /* tape owns msg */ int32 ts_qatn = 0; /* queued attn */ @@ -297,6 +319,7 @@ int32 ts_updtssr (int32 t); int32 ts_updxs0 (int32 t); void ts_cmpendcmd (int32 s0, int32 s1); void ts_endcmd (int32 ssf, int32 xs0f, int32 msg); +void ts_set_mot (int32 bot); int32 ts_map_status (t_stat st); /* TS data structures @@ -335,6 +358,7 @@ REG ts_reg[] = { { GRDATA (WOPT, wchopt, DEV_RDX, 16, 0) }, { GRDATA (WXOPT, wchxopt, DEV_RDX, 16, 0) }, { FLDATA (INT, IREQ (TS), INT_V_TS) }, + { FLDATA (BOT, ts_bot, 0) }, { FLDATA (ATTN, ts_qatn, 0) }, { FLDATA (BOOT, ts_bcmd, 0) }, { FLDATA (OWNC, ts_ownc, 0) }, @@ -381,6 +405,7 @@ switch ((PA >> 1) & 01) { /* decode PA<1> */ case 0: /* TSBA */ *data = tsba & DMASK; /* low 16b of ba */ break; + case 1: /* TSSR */ *data = tssr = ts_updtssr (tssr); /* update tssr */ break; @@ -409,7 +434,7 @@ switch ((PA >> 1) & 01) { /* decode PA<1> */ CLR_INT (TS); /* clr int req */ t = Map_ReadW (tsba, CMD_PLNT << 1, cpy_buf); /* read cmd pkt */ tsba = tsba + ((CMD_PLNT << 1) - t); /* incr tsba */ - if (t) { /* nxm? */ + if (t != 0) { /* nxm? */ ts_endcmd (TSSR_NXM + TC5, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL); return SCPE_OK; } @@ -454,11 +479,11 @@ switch (st) { break; case MTSE_TMK: - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ + ts_set_mot (0); /* tape has moved, !BOT */ return (XTC (XS0_TMK | XS0_RLS, TC2)); case MTSE_RECE: /* record in error */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ + ts_set_mot (0); /* tape has moved, !BOT */ case MTSE_INVRL: /* invalid rec lnt */ case MTSE_IOERR: /* IO error */ default: /* unknown error */ @@ -473,6 +498,7 @@ switch (st) { case MTSE_BOT: /* reverse into BOT */ msgxs3 = msgxs3 | XS3_RIB; /* set status */ + ts_bot = 1; /* set BOT */ return (XTC (XS0_BOT | XS0_RLS, TC2)); /* tape alert */ case MTSE_WRP: /* write protect */ @@ -494,7 +520,7 @@ do { msgrfc = fc; if ((st = sim_tape_sprecf (uptr, &tbc))) /* space rec fwd, err? */ return ts_map_status (st); /* map status */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ + ts_set_mot (0); /* tape has moved, !BOT */ } while (fc != 0); return 0; } @@ -512,7 +538,7 @@ do { st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */ if (st == MTSE_TMK) { /* tape mark? */ msgrfc = (msgrfc - 1) & DMASK; /* decr count */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ + ts_set_mot (0); /* tape has moved, !BOT */ if (tmkprv && (wchopt & WCH_ESS)) /* 2nd tmk & ESS? */ return (XTC ((msgrfc? XS0_RLS: 0) | XS0_TMK | XS0_LET, TC2)); @@ -521,7 +547,7 @@ do { else if (st != MTSE_OK) return ts_map_status (st); else tmkprv = FALSE; /* not a tmk */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ + ts_set_mot (0); /* tape has moved, !BOT */ } while (msgrfc != 0); return 0; } @@ -537,7 +563,7 @@ do { msgrfc = fc; if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rec rev, err? */ return ts_map_status (st); /* map status */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ + ts_set_mot (0); /* tape has moved, !BOT */ } while (fc != 0); return 0; } @@ -553,7 +579,7 @@ do { st = sim_tape_sprecr (uptr, &tbc); /* space rec rev */ if (st == MTSE_TMK) { /* tape mark? */ msgrfc = (msgrfc - 1) & DMASK; /* decr count */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ + ts_set_mot (0); /* tape has moved, !BOT */ if (tmkprv && (wchopt & WCH_ESS)) /* 2nd tmk & ESS? */ return (XTC ((msgrfc? XS0_RLS: 0) | XS0_TMK | XS0_LET, TC2)); @@ -562,7 +588,7 @@ do { else if (st != MTSE_OK) return ts_map_status (st); else tmkprv = FALSE; /* not a tmk */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ + ts_set_mot (0); /* tape has moved, !BOT */ } while (msgrfc != 0); return 0; } @@ -581,7 +607,7 @@ if (fc == 0) /* byte count */ fc = 0200000; tsba = (cmdadh << 16) | cmdadl; /* buf addr */ wbc = (tbc > fc)? fc: tbc; /* cap buf size */ -msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ +ts_set_mot (0); /* tape has moved, !BOT */ if (cmdhdr & CMD_SWP) { /* swapped? */ for (i = 0; i < wbc; i++) { /* copy buffer */ wa = tsba ^ 1; /* apply OPP */ @@ -596,7 +622,7 @@ if (cmdhdr & CMD_SWP) { /* swapped? */ else { t = Map_WriteB (tsba, wbc, tsxb); /* store record */ tsba = tsba + (wbc - t); /* update tsba */ - if (t) { /* nxm? */ + if (t != 0) { /* nxm? */ tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */ return (XTC (XS0_RLS, TC4)); } @@ -623,7 +649,7 @@ if (fc == 0) /* byte count */ fc = 0200000; tsba = ((cmdadh << 16) | cmdadl) + fc; /* buf addr */ wbc = (tbc > fc)? fc: tbc; /* cap buf size */ -msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ +ts_set_mot (0); /* tape has moved, !BOT */ for (i = wbc; i > 0; i--) { /* copy buffer */ tsba = tsba - 1; wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */ @@ -663,14 +689,14 @@ if (cmdhdr & CMD_SWP) { /* swapped? */ else { t = Map_ReadB (tsba, fc, tsxb); /* fetch record */ tsba = tsba + (fc - t); /* update tsba */ - if (t) { /* nxm? */ + if (t != 0) { /* nxm? */ tssr = ts_updtssr (tssr | TSSR_NXM); return TC5; } } if ((st = sim_tape_wrrecf (uptr, tsxb, fc))) /* write rec, err? */ return ts_map_status (st); /* return status */ -msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ +ts_set_mot (0); /* tape has moved, !BOT */ msgrfc = 0; if (sim_tape_eot (&ts_unit)) /* EOT on write? */ return XTC (XS0_EOT, TC2); @@ -683,7 +709,7 @@ t_stat st; if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ return ts_map_status (st); /* return status */ -msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ +ts_set_mot (0); /* tape has moved, !BOT */ if (sim_tape_eot (&ts_unit)) /* EOT on write? */ return XTC (XS0_EOT, TC2); return XTC (XS0_TMK, TC0); @@ -714,7 +740,7 @@ static const char *fnc_name[CMD_N_FNC] = { "30", "31", "32", "33", "34", "35", "36", "37" }; -if (ts_bcmd) { /* boot? */ +if (ts_bcmd != 0) { /* boot? */ ts_bcmd = 0; /* clear flag */ sim_tape_rewind (uptr); /* rewind */ if (uptr->flags & UNIT_ATT) { /* attached? */ @@ -726,6 +752,7 @@ if (ts_bcmd) { /* boot? */ else tssr = ts_updtssr (tssr | TSSR_SSR | TC3); if (cmdhdr & CMD_IE) SET_INT (TS); + ts_bot = 0; /* unatt or !BOT */ return SCPE_OK; } @@ -772,7 +799,7 @@ if ((fnc_flg[fnc] & FLG_WR) && /* write? */ } if ((((fnc == FNC_READ) && (mod == 1)) || /* read rev */ ((fnc == FNC_POS) && (mod & 1))) && /* space rev */ - sim_tape_bot (uptr)) { /* BOT? */ + (ts_bot != 0)) { /* BOT? */ ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL); return SCPE_OK; } @@ -785,9 +812,6 @@ st0 = st1 = 0; switch (fnc) { /* case on func */ case FNC_INIT: /* init */ - if (!sim_tape_bot (uptr)) /* set if tape moves */ - msgxs0 = msgxs0 | XS0_MOT; - sim_tape_rewind (uptr); /* rewind */ case FNC_WSSM: /* write mem */ case FNC_GSTA: /* get status */ ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* send end packet */ @@ -802,7 +826,7 @@ switch (fnc) { /* case on func */ bc = ((WCH_PLNT << 1) > cmdlnt)? cmdlnt: WCH_PLNT << 1; t = Map_ReadW (tsba, bc, cpy_buf); /* fetch packet */ tsba = tsba + (bc - t); /* inc tsba */ - if (t) { /* nxm? */ + if (t != 0) { /* nxm? */ ts_endcmd (TSSR_NBA | TSSR_NXM | TC5, 0, 0); return SCPE_OK; } @@ -824,11 +848,12 @@ switch (fnc) { /* case on func */ tssr = ts_updtssr (tssr | TSSR_SSR); /* set SSR */ if (wchopt & WCH_ERI) SET_INT (TS); - ts_ownc = 0; ts_ownm = 1; /* keep msg */ + ts_ownc = 0; + ts_ownm = 1; /* keep msg */ break; case 01: /* rewind and unload */ - if (!sim_tape_bot (uptr)) /* if tape moves */ + if (ts_bot == 0) /* if tape moves */ msgxs0 = msgxs0 | XS0_MOT; sim_tape_detach (uptr); /* unload */ ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); @@ -843,9 +868,8 @@ switch (fnc) { /* case on func */ return SCPE_OK; case 04: /* rewind */ - if (!sim_tape_bot (uptr)) /* if tape moves */ - msgxs0 = msgxs0 | XS0_MOT; sim_tape_rewind (uptr); + ts_set_mot (1); /* always moves, BOT */ ts_endcmd (TC0, XS0_BOT, MSG_ACK | MSG_CEND); break; } @@ -940,9 +964,8 @@ switch (fnc) { /* case on func */ break; case 04: /* rewind */ - if (!sim_tape_bot (uptr)) /* if tape moves */ - msgxs0 = msgxs0 | XS0_MOT; sim_tape_rewind (uptr); + ts_set_mot (1); /* always moves, BOT */ break; } ts_cmpendcmd (st0, 0); @@ -963,6 +986,13 @@ else t = t | TSSR_OFL; return (t & ~TSSR_MBZ); } +void ts_set_mot (int32 bot) +{ +msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ +ts_bot = bot; /* set BOT state */ +return; +} + int32 ts_updxs0 (int32 t) { t = (t & ~(XS0_ONL | XS0_WLK | XS0_BOT | XS0_IE)) | XS0_PET; @@ -970,7 +1000,7 @@ if (ts_unit.flags & UNIT_ATT) { t = t | XS0_ONL; if (sim_tape_wrp (&ts_unit)) t = t | XS0_WLK; - if (sim_tape_bot (&ts_unit)) + if (ts_bot != 0) t = (t | XS0_BOT) & ~XS0_EOT; if (sim_tape_eot (&ts_unit)) t = (t | XS0_EOT) & ~XS0_BOT; @@ -1040,6 +1070,9 @@ t_stat ts_reset (DEVICE *dptr) int32 i; sim_tape_rewind (&ts_unit); +if ((ts_unit.flags & UNIT_ATT) != 0) + ts_bot = 1; +else ts_bot = 0; tsba = tsdbx = 0; ts_ownc = ts_ownm = 0; ts_bcmd = 0; @@ -1069,6 +1102,7 @@ t_stat r; r = sim_tape_attach (uptr, cptr); /* attach unit */ if (r != SCPE_OK) /* error? */ return r; +ts_bot = 1; /* at BOT */ tssr = tssr & ~TSSR_OFL; /* clr offline */ if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) /* attn msg? */ return r; @@ -1092,6 +1126,7 @@ if (!(uptr->flags & UNIT_ATT)) /* attached? */ r = sim_tape_detach (uptr); /* detach unit */ if (r != SCPE_OK) return r; /* error? */ +ts_bot = 0; tssr = tssr | TSSR_OFL; /* set offline */ if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) /* attn msg? */ return r; diff --git a/PDP11/pdp11_tu.c b/PDP11/pdp11_tu.c index 75164afc0..18cee8292 100644 --- a/PDP11/pdp11_tu.c +++ b/PDP11/pdp11_tu.c @@ -1,6 +1,6 @@ /* pdp11_tu.c - PDP-11 TM02/TU16 TM03/TU45/TU77 Massbus magnetic tape controller - Copyright (c) 1993-2020, Robert M Supnik + Copyright (c) 1993-2023, 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 @@ tu TM02/TM03 magtape + 06-Nov-23 RMS Fixed BOT logic 23-Mar-20 RMS Unload should call sim_tape_detach (Mark Pizzolato) 28-Dec-17 RMS Read tape mark must set Massbus EXC 13-Mar-17 RMS Annotated fall through in switch @@ -54,6 +55,10 @@ If the byte count is odd, the record is padded with an extra byte of junk. File marks are represented by a single record length of 0. End of tape is two consecutive end of file marks. + + BOT is not the same as POS == 0. BOT is set after rewinding or after + a reverse operation from before the first record. It is cleared by + any successful motion operation. */ #if defined (VM_PDP10) @@ -118,11 +123,12 @@ /* TUFS - formatter status - offset 1 + indicates kept in drive status ^ indicates calculated on the fly + Rewinding is a pseudo-status flag and never appears in TUFS */ #define FS_OF 1 #define FS_SAT 0000001 /* slave attention */ -#define FS_BOT 0000002 /* ^beginning of tape */ +#define FS_BOT 0000002 /* +beginning of tape */ #define FS_TMK 0000004 /* end of file */ #define FS_ID 0000010 /* ID burst detected */ #define FS_SLOW 0000020 /* slowing down NI */ @@ -130,7 +136,7 @@ #define FS_SSC 0000100 /* slave stat change */ #define FS_RDY 0000200 /* ^formatter ready */ #define FS_FPR 0000400 /* formatter present */ -#define FS_EOT 0002000 /* +end of tape */ +#define FS_EOT 0002000 /* ^end of tape */ #define FS_WRL 0004000 /* ^write locked */ #define FS_MOL 0010000 /* ^medium online */ #define FS_PIP 0020000 /* +pos in progress */ @@ -491,15 +497,17 @@ switch (fnc) { /* case on function */ tutc = tutc & ~TC_FCS; /* clear fc status */ tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR); sim_cancel (uptr); /* reset drive */ - uptr->USTAT = 0; /* fall through */ + uptr->USTAT &= FS_BOT; /* fall through */ case FNC_NOP: tucs1 = tucs1 & ~CS1_GO; /* no operation */ return SCPE_OK; case FNC_RIP: /* read-in preset */ tutc = TC_RIP; /* set tutc */ - sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */ - tu_unit[0].USTAT = 0; + if (tu_unit[0].flags & UNIT_ATT) { /* unit 0 attached? */ + sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */ + tu_unit[0].USTAT = FS_BOT; + } tucs1 = tucs1 & ~CS1_GO; tufs = tufs & ~FS_TMK; return SCPE_OK; @@ -544,7 +552,7 @@ switch (fnc) { /* case on function */ tu_set_er (ER_UNS); break; } - if (sim_tape_bot (uptr) || ((tutc & TC_FCS) == 0)) { + if ((uptr->USTAT & FS_BOT) || ((tutc & TC_FCS) == 0)) { tu_set_er (ER_NXF); break; } @@ -553,7 +561,7 @@ switch (fnc) { /* case on function */ case FNC_WCHKR: /* wchk = read */ case FNC_READR: /* read rev */ - if (tufs & FS_BOT) { /* beginning of tape? */ + if (uptr->USTAT & FS_BOT) { /* beginning of tape? */ tu_set_er (ER_NXF); break; } @@ -624,7 +632,9 @@ t_stat st, r = SCPE_OK; drv = (int32) (uptr - tu_dev.units); /* get drive # */ if (uptr->USTAT & FS_REW) { /* rewind or unload? */ sim_tape_rewind (uptr); /* rewind tape */ - uptr->USTAT = 0; /* clear status */ + if (uptr->flags & UNIT_ATT) /* standard rewind? */ + uptr->USTAT = FS_BOT; /* set BOT */ + else uptr->USTAT = 0; /* clear status */ tu_update_fs (FS_ATA | FS_SSC, drv); return SCPE_OK; } @@ -823,17 +833,13 @@ int32 act = sim_is_active (&tu_unit[drv]); tufs = (tufs & ~FS_DYN) | FS_FPR | flg; if (tu_unit[drv].flags & UNIT_ATT) { - tufs = tufs | FS_MOL | tu_unit[drv].USTAT; + tufs = tufs | FS_MOL | (tu_unit[drv].USTAT & 0177777); if (tu_unit[drv].UDENS == TC_1600) tufs = tufs | FS_PE; if (sim_tape_wrp (&tu_unit[drv])) tufs = tufs | FS_WRL; - if (!act) { - if (sim_tape_bot (&tu_unit[drv])) - tufs = tufs | FS_BOT; - if (sim_tape_eot (&tu_unit[drv])) + if (!act && sim_tape_eot (&tu_unit[drv])) tufs = tufs | FS_EOT; - } } if (tuer) tufs = tufs | FS_ERR; @@ -892,6 +898,7 @@ switch (st) { break; case MTSE_BOT: /* reverse into BOT */ + tu_unit[drv].USTAT = FS_BOT; /* set BOT */ return SCPE_OK; case MTSE_WRP: /* write protect */ @@ -926,7 +933,10 @@ for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */ uptr = tu_dev.units + u; sim_tape_reset (uptr); /* clear pos flag */ sim_cancel (uptr); /* cancel activity */ - uptr->USTAT = 0; + if ((uptr->flags & UNIT_ATT) && /* if attached */ + sim_tape_bot (uptr)) /* and BOT */ + uptr->USTAT = FS_BOT; /* set BOT */ + else uptr->USTAT = 0; } if (xbuf == NULL) xbuf = (uint8 *) calloc (MT_MAXFR + 4, sizeof (uint8)); @@ -949,7 +959,7 @@ t_stat r; r = sim_tape_attach (uptr, cptr); if (r != SCPE_OK) return r; -uptr->USTAT = 0; /* clear unit status */ +uptr->USTAT = FS_BOT; /* set BOT */ uptr->UDENS = UD_UNK; /* unknown density */ flg = FS_ATA | FS_SSC; /* set attention */ if (GET_DRV (tutc) == drv) /* sel drv? set SAT */ diff --git a/PDP18B/pdp18b_fpp.c b/PDP18B/pdp18b_fpp.c index cc698c668..ffbf70d42 100644 --- a/PDP18B/pdp18b_fpp.c +++ b/PDP18B/pdp18b_fpp.c @@ -140,7 +140,6 @@ static int32 fir; /* instruction */ static int32 jea; /* exc address */ static int32 fguard; /* guard bit */ static int32 stop_fpp = STOP_RSRV; /* stop if fp dis */ -#define fma fma_X /* Avoid name conflict with math.h defined fma() routine */ static UFP fma; /* FMA */ static UFP fmb; /* FMB */ static UFP fmq; /* FMQ - hi,lo only */ @@ -379,7 +378,7 @@ return SCPE_OK; t_stat fp15_opnd (int32 ir, int32 addr, UFP *fpn) { -int32 i, numwd, wd[3] = { 0,0,0 }; +int32 i, numwd, wd[3]; fguard = 0; /* clear guard */ if (ir & FI_NOLOAD) /* no load? */ @@ -426,7 +425,7 @@ return FP_OK; t_stat fp15_store (int32 ir, int32 addr, UFP *a) { -int32 i, numwd, wd[3]={ 0,0,0 }; +int32 i, numwd, wd[3]; t_stat sta; fguard = 0; /* clear guard */ diff --git a/PDP8/pdp8_mt.c b/PDP8/pdp8_mt.c index 62dc8a896..24b74130c 100644 --- a/PDP8/pdp8_mt.c +++ b/PDP8/pdp8_mt.c @@ -1,6 +1,6 @@ /* pdp8_mt.c: PDP-8 magnetic tape simulator - Copyright (c) 1993-2022, Robert M Supnik + Copyright (c) 1993-2023, 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 @@ mt TM8E/TU10 magtape + 01-Nov-23 RMS Fixed illegal op test to use BOT flag 26-Mar-22 RMS Added extra case points for new MTSE definitions 23-Mar-20 RMS Unload should call sim_tape_detach (Mark Pizzolato) 16-Feb-06 RMS Added tape capacity checking @@ -267,7 +268,7 @@ switch (IR & 07) { /* decode IR<9:11> */ if (((uptr->flags & UNIT_ATT) == 0) || sim_is_active (uptr) || (((f == FN_WRITE) || (f == FN_WREOF)) && sim_tape_wrp (uptr)) - || (((f == FN_SPACER) || (f == FN_REWIND)) && sim_tape_bot (uptr))) { + || (((f == FN_SPACER) || (f == FN_REWIND)) && (uptr->USTAT & STA_BOT))) { mt_sta = mt_sta | STA_ILL | STA_ERR; /* illegal op error */ mt_set_done (); /* set done */ mt_updcsta (uptr); /* update status */ @@ -607,7 +608,7 @@ for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */ uptr = mt_dev.units + u; sim_cancel (uptr); /* cancel activity */ sim_tape_reset (uptr); /* reset tape */ - if (uptr->flags & UNIT_ATT) uptr->USTAT = + if (uptr->flags & UNIT_ATT) uptr->USTAT = (sim_tape_bot (uptr)? STA_BOT: 0) | (sim_tape_wrp (uptr)? STA_WLK: 0); else uptr->USTAT = STA_REM; diff --git a/PDP8/pdp8_sys.c b/PDP8/pdp8_sys.c index 87e1d2029..a39f1750e 100644 --- a/PDP8/pdp8_sys.c +++ b/PDP8/pdp8_sys.c @@ -1,6 +1,6 @@ /* pdp8_sys.c: PDP-8 simulator interface - Copyright (c) 1993-2021, Robert M Supnik + Copyright (c) 1993-2023, 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. + 04-Apr-23 RMS Fixed decoding of DVI (Reindert Voorhorst) 11-May-21 RMS Fixed RF/DF and LP decoding 13-Mar-21 RMS Fixed bug in binary loader (Mark Pizzolato) 15-Dec-16 RMS Added PKLF (Dave Gesswein) @@ -411,7 +412,7 @@ static const int32 opc_val[] = { 07411+I_OP3, 07413+I_OP3, 07415+I_OP3, 07417+I_OP3, 07441+I_OP3, 07443+I_OP3, 07445+I_OP3, 07447+I_OP3, 07451+I_OP3, 07453+I_OP3, 07455+I_OP3, 07457+I_OP3, - 017403+I_OP3, 017405+I_OP3, 0174017+I_OP3, + 017403+I_OP3, 017405+I_OP3, 017407+I_OP3, 017411+I_OP3, 017413+I_OP3, 017415+I_OP3, 017417+I_OP3, 017441+I_OP3, 017443+I_OP3, 017445+I_OP3, 017447+I_OP3, 017451+I_OP3, 017453+I_OP3, 017455+I_OP3, 017457+I_OP3, diff --git a/SDS/sds_cpu.c b/SDS/sds_cpu.c index d77cdbadf..a57b9d083 100644 --- a/SDS/sds_cpu.c +++ b/SDS/sds_cpu.c @@ -1,6 +1,6 @@ /* sds_cpu.c: SDS 940 CPU simulator - Copyright (c) 2001-2021, Robert M. Supnik + Copyright (c) 2001-2023, 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"), @@ -26,6 +26,7 @@ cpu central processor rtc real time clock + 07-Nov-23 RMS Fixed shift counts > 48 (Howard Bussey) 17-Feb-21 kenr Added C register implementation to support console 07-Sep-17 RMS Fixed sim_eval declaration in history routine (COVERITY) 09-Mar-17 RMS trap_P not set if mem mgt trap during fetch (COVERITY) @@ -994,18 +995,19 @@ switch (op) { /* case on opcode */ return r; shf_op = I_GETSHFOP (va); /* get eff op */ sc = va & I_SHFMSK; /* get eff count */ + if (sc > 48) /* > 48 same as 48 */ + sc = 48; switch (shf_op) { /* case on sub-op */ case 00: /* right arithmetic */ - if (sc) + if (sc != 0) ShfR48 (sc, (A & SIGN)? DMASK: 0); break; case 04: /* right cycle */ - sc = sc % 48; /* mod 48 */ - if (sc) + if ((sc != 0) && (sc != 48)) /* rotate */ RotR48 (sc); break; case 05: /* right logical */ - if (sc) + if (sc != 0) ShfR48 (sc, 0); break; default: @@ -1019,11 +1021,11 @@ switch (op) { /* case on opcode */ return r; shf_op = I_GETSHFOP (va); /* get eff op */ sc = va & I_SHFMSK; /* get eff count */ + if (sc > 48) /* > 48 same as 48 */ + sc = 48; switch (shf_op) { /* case on sub-op */ case 00: /* left arithmetic */ dat = A; /* save sign */ - if (sc > 48) - sc = 48; for (i = 0; i < sc; i++) { /* loop */ A = ((A << 1) | (B >> 23)) & DMASK; B = (B << 1) & DMASK; @@ -1032,8 +1034,6 @@ switch (op) { /* case on opcode */ } break; case 02: /* normalize */ - if (sc > 48) - sc = 48; for (i = 0; i < sc; i++) { /* until max count */ if ((A ^ (A << 1)) & SIGN) break; @@ -1043,13 +1043,10 @@ switch (op) { /* case on opcode */ X = (X - i) & DMASK; break; case 04: /* left cycle */ - sc = sc % 48; /* mod 48 */ - if (sc) /* rotate */ + if ((sc != 0) && (sc != 48)) /* rotate */ RotR48 (48 - sc); break; case 06: /* cycle normalize */ - if (sc > 48) - sc = 48; for (i = 0; i < sc; i++) { /* until max count */ if ((A ^ (A << 1)) & SIGN) break; @@ -1395,6 +1392,8 @@ else B = dvdh; /* B = rem */ return; } +/* Input is in the range [1,47] */ + void RotR48 (uint32 sc) { uint32 t = A; diff --git a/SDS/sds_cr.c b/SDS/sds_cr.c index 20206a8a9..206ae8028 100644 --- a/SDS/sds_cr.c +++ b/SDS/sds_cr.c @@ -1,6 +1,6 @@ /* sds_cr.c: SDS-930 card reader simulator - Copyright (c) 2020-2021, Ken Rector + Copyright (c) 2020-2023, Ken Rector 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 Ken Rector. + 24-Jan-23 kenr Disconnect does not reset status 17-Feb-21 kenr Initial Version 17-Feb-21 kenr Added C register support to CDR boot */ @@ -220,6 +221,8 @@ t_stat cr_devio (uint32 fnc, uint32 inst, uint32 *dat) { case IO_DISC: /* disconnect */ xfr_req = xfr_req & ~XFR_CR; /* clr xfr flag */ sim_cancel (uptr); /* deactivate unit */ + cr_eor = 0; /* clr status */ + uptr->STATUS = 0; break; case IO_SKS: /* SKS */ new_ch = I_GETSKCH (inst); /* get chan # */ diff --git a/SDS/sds_mt.c b/SDS/sds_mt.c index c00838a99..1ad3ef48f 100644 --- a/SDS/sds_mt.c +++ b/SDS/sds_mt.c @@ -1,6 +1,6 @@ /* sds_mt.c: SDS 940 magnetic tape simulator - Copyright (c) 2001-2021, Robert M. Supnik + Copyright (c) 2001-2023, 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 @@ mt 7 track magnetic tape + 01-Nov-23 RMS Fixed to set botf on reverse into BOT 03-Mar-21 kenr Added C register support to MT boot 09-Oct-16 RMS Added precise gap erase 19-Mar-12 RMS Fixed bug in scan function decode (Peter Schorn) @@ -381,6 +382,8 @@ if (st != MTSE_OK) { /* other error? */ return SCPE_MTRLNT; if (st == MTSE_EOM) /* eom? set eot */ uptr->eotf = 1; + if (st == MTSE_BOT) /* bot? set bot */ + uptr->botf = 1; return SCPE_OK; } mt_blnt = tbc; /* set buf lnt */ @@ -471,7 +474,9 @@ xfr_req = xfr_req & ~XFR_MT0; /* clr xfr flag */ for (i = 0; i < MT_NUMDR; i++) { /* deactivate */ sim_cancel (&mt_unit[i]); sim_tape_reset (&mt_unit[i]); - mt_unit[i].eotf = 0; + mt_unit[i].eotf = 0; /* clear eotf */ + if ((mt_unit[i].flags & UNIT_ATT) == 0) /* not attached? */ + mt_unit[i].botf = 0; /* clear botf */ } return SCPE_OK; } diff --git a/descrip.mms b/descrip.mms index d5c1932b8..583a404a3 100644 --- a/descrip.mms +++ b/descrip.mms @@ -449,7 +449,8 @@ PDP11_SOURCE2 = $(PDP11_DIR)PDP11_TM.C,$(PDP11_DIR)PDP11_TS.C,\ $(PDP11_DIR)PDP11_XU.C,$(PDP11_DIR)PDP11_TU.C,\ $(PDP11_DIR)PDP11_DL.C,$(PDP11_DIR)PDP11_RF.C, \ $(PDP11_DIR)PDP11_RC.C,$(PDP11_DIR)PDP11_KG.C,\ - $(PDP11_DIR)PDP11_KE.C,$(PDP11_DIR)PDP11_DC.C + $(PDP11_DIR)PDP11_KE.C,$(PDP11_DIR)PDP11_DC.C, \ + $(PDP11_DIR)PDP11_CH.C PDP11_OPTIONS = /INCL=($(SIMH_DIR),$(PDP11_DIR)$(PCAP_INC))\ /DEF=($(CC_DEFS),"VM_PDP11=1"$(PCAP_DEFS)) @@ -465,7 +466,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_CH.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 058a52bac..c1e88895a 100644 --- a/makefile +++ b/makefile @@ -96,18 +96,15 @@ ifneq (,${GREP_OPTIONS}) $(error 1) endif ifneq ($(findstring Windows,${OS}),) - # Cygwin can return SHELL := C:/cygwin/bin/sh.exe cygwin is OK & NOT WIN32 - ifeq ($(findstring /cygwin/,$(SHELL)),) - ifeq ($(findstring .exe,${SHELL}),.exe) - # MinGW - WIN32 := 1 - # Tests don't run under MinGW - TESTS := 0 - else # Msys or cygwin - ifeq (MINGW,$(findstring MINGW,$(shell uname))) - $(info *** This makefile can not be used with the Msys bash shell) - $(error Use build_mingw.bat ${MAKECMDGOALS} from a Windows command prompt) - endif + ifeq ($(findstring .exe,${SHELL}),.exe) + # MinGW + WIN32 := 1 + # Tests don't run under MinGW + TESTS := 0 + else # Msys or cygwin + ifeq (MINGW,$(findstring MINGW,$(shell uname))) + $(info *** This makefile can not be used with the Msys bash shell) + $(error Use build_mingw.bat ${MAKECMDGOALS} from a Windows command prompt) endif endif endif @@ -204,7 +201,7 @@ endif ifeq (${WIN32},) #*nix Environments (&& cygwin) ifeq (${GCC},) ifeq (,$(shell which gcc 2>/dev/null)) - $(info *** Warning *** Using local cc since gcc is not available locally.) + $(info *** Warning *** Using local cc since gcc isn't available locally.) $(info *** Warning *** You may need to install gcc to build working simulators.) GCC = cc else @@ -512,7 +509,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) # Some gcc versions don't support LTO, so only use LTO when the compiler is known to support it ifeq (,$(NO_LTO)) ifneq (,$(GCC_VERSION)) - ifeq (,$(shell ${GCC} -v /dev/null 2>&1 | grep -- '--enable-lto')) + ifeq (,$(shell ${GCC} -v /dev/null 2>&1 | grep '\--enable-lto')) LTO_EXCLUDE_VERSIONS += $(GCC_VERSION) endif endif @@ -1372,7 +1369,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_rs.c \ - ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_io_lib.c $(PDP11D)/pdp11_ch.c PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT} @@ -1419,7 +1416,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_cr.c $(PDP11D)/pdp11_ch.c PDP10_OPT = -DVM_PDP10 -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} @@ -1506,7 +1503,8 @@ SIGMA = ${SIGMAD}/sigma_cpu.c ${SIGMAD}/sigma_sys.c ${SIGMAD}/sigma_cis.c \ ${SIGMAD}/sigma_coc.c ${SIGMAD}/sigma_dk.c ${SIGMAD}/sigma_dp.c \ ${SIGMAD}/sigma_fp.c ${SIGMAD}/sigma_io.c ${SIGMAD}/sigma_lp.c \ ${SIGMAD}/sigma_map.c ${SIGMAD}/sigma_mt.c ${SIGMAD}/sigma_pt.c \ - ${SIGMAD}/sigma_rad.c ${SIGMAD}/sigma_rtc.c ${SIGMAD}/sigma_tt.c + ${SIGMAD}/sigma_rad.c ${SIGMAD}/sigma_rtc.c ${SIGMAD}/sigma_tt.c \ + $(SIGMAD)/sigma_cr.c $(SIGMAD)/sigma_cp.c SIGMA_OPT = -I ${SIGMAD} ### diff --git a/scp.c b/scp.c index b26ac42e8..9a37f3ecf 100644 --- a/scp.c +++ b/scp.c @@ -1,6 +1,6 @@ /* scp.c: simulator control program - Copyright (c) 1993-2022, Robert M Supnik + Copyright (c) 1993-2023, 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,11 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 13-Jun-23 RMS Defanged system library call warning (Mark Pizzolata) + 10-Jun-23 JDB Move release string after delta number in "show_version" + Report the SCP patch delta as a decimal fraction + 08-Jun-23 JDB Fixed find_unit where dptr->name is a substring of dptr->lname + 07-Feb-23 RMS Silenced Mac compiler warnings (Ken Rector) 01-Oct-22 RMS Replaced readline with editline due to licensing issues (Paul Koning) 15-Aug-22 RMS Fixed inconsistent SIM_HAVE_DLOPEN naming (Walter Mueller) 06-Mar-22 RMS Removed UNIT_RAW support @@ -792,14 +797,14 @@ else if (*argv[0]) { /* sim name arg? */ char nbuf[PATH_MAX + 7], *np; /* "path.ini" */ nbuf[0] = '"'; /* starting " */ strncpy (nbuf + 1, argv[0], PATH_MAX + 1); /* copy sim name */ - if (np = match_ext (nbuf, "EXE")) /* remove .exe */ + if ((np = match_ext (nbuf, "EXE"))) /* remove .exe */ *np = 0; strcat (nbuf, ".ini\""); /* add .ini" */ stat = find_cmd ("DO")->action (-1, nbuf); /* proc cmd file */ } while (stat != SCPE_EXIT) { /* in case exit */ - if (cptr = sim_brk_getact (cbuf, CBUFSIZE)) /* pending action? */ + if ((cptr = sim_brk_getact (cbuf, CBUFSIZE))) /* pending action? */ printf ("sim> %s\n", cptr); /* echo */ else if (sim_vm_read != NULL) { /* sim routine? */ printf ("sim> "); /* prompt */ @@ -820,7 +825,7 @@ while (stat != SCPE_EXIT) { /* in case exit */ fprintf (sim_log, "sim> %s\n", cptr); cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ sim_switches = 0; /* init switches */ - if (cmdp = find_cmd (gbuf)) /* lookup command */ + if ((cmdp = find_cmd (gbuf))) /* lookup command */ stat = cmdp->action (cmdp->arg, cptr); /* if found, exec */ else stat = SCPE_UNK; if (stat >= SCPE_BASE) /* error? */ @@ -885,7 +890,7 @@ if (*cptr) { cptr = get_glyph (cptr, gbuf, 0); if (*cptr) return SCPE_2MARG; - if (cmdp = find_cmd (gbuf)) + if ((cmdp = find_cmd (gbuf))) sim_printf ("%s", cmdp->help); else return SCPE_ARG; } @@ -912,7 +917,7 @@ if ((cptr == NULL) || (strlen (cptr) == 0)) fflush(stdout); /* flush stdout */ if (sim_log) /* flush log if enabled */ fflush (sim_log); -system (cptr); +(void) system (cptr); #if defined (VMS) printf ("\n"); #endif @@ -983,7 +988,7 @@ echo = sim_switches & SWMASK ('V'); /* -v means echo */ errabort = sim_switches & SWMASK ('E'); /* -e means abort on error */ if (flag >= 0) /* if this is not the initialization file */ - echo = echo | flag & ~0377; /* then propagate the echo flag to the current level */ + echo = echo | (flag & ~0377); /* then propagate the echo flag to the current level */ c = fcptr; for (nargs = 0; nargs < 10; ) { /* extract arguments */ @@ -1032,7 +1037,7 @@ do { cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ sim_switches = 0; /* init switches */ isdo = FALSE; - if (cmdp = find_cmd (gbuf)) { /* lookup command */ + if ((cmdp = find_cmd (gbuf))) { /* lookup command */ isdo = (strcmp (cmdp->name, "DO") == 0); if (isdo) { /* DO command? */ if (flag >= DO_NEST_LVL) /* nest too deep? */ @@ -1219,18 +1224,18 @@ if (*cptr == 0) /* must be more */ return SCPE_2FARG; cptr = get_glyph (cptr, gbuf, 0); /* get glob/dev/unit */ -if (dptr = find_dev (gbuf)) { /* device match? */ +if ((dptr = find_dev (gbuf))) { /* device match? */ uptr = dptr->units; /* first unit */ ctbr = set_dev_tab; /* global table */ lvl = MTAB_VDV; /* device match */ } -else if (dptr = find_unit (gbuf, &uptr)) { /* unit match? */ +else if ((dptr = find_unit (gbuf, &uptr))) { /* unit match? */ if (uptr == NULL) /* invalid unit */ return SCPE_NXUN; ctbr = set_unit_tab; /* global table */ lvl = MTAB_VUN; /* unit match */ } -else if (gcmdp = find_ctab (set_glob_tab, gbuf)) /* global? */ +else if ((gcmdp = find_ctab (set_glob_tab, gbuf))) /* global? */ return gcmdp->action (gcmdp->arg, cptr); /* do the rest */ else return SCPE_NXDEV; /* no match */ if (*cptr == 0) /* must be more */ @@ -1238,7 +1243,7 @@ if (*cptr == 0) /* must be more */ while (*cptr != 0) { /* do all mods */ cptr = get_glyph (svptr = cptr, gbuf, ','); /* get modifier */ - if (cvptr = strchr (gbuf, '=')) /* = value? */ + if ((cvptr = strchr (gbuf, '='))) /* = value? */ *cvptr++ = 0; for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) { if ((mptr->mstring) && /* match string */ @@ -1251,7 +1256,7 @@ while (*cptr != 0) { /* do all mods */ if (mptr->valid) { /* validation rtn? */ if (cvptr && (mptr->mask & MTAB_NC)) { get_glyph_nc (svptr, gbuf, ','); - if (cvptr = strchr (gbuf, '=')) + if ((cvptr = strchr (gbuf, '='))) *cvptr++ = 0; } r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc); @@ -1279,7 +1284,7 @@ while (*cptr != 0) { /* do all mods */ } /* end if match */ } /* end for */ if (!mptr || (mptr->mask == 0)) { /* no match? */ - if (glbr = find_c1tab (ctbr, gbuf)) { /* global match? */ + if ((glbr = find_c1tab (ctbr, gbuf))) { /* global match? */ r = glbr->action (dptr, uptr, glbr->arg, cvptr); /* do global */ if (r != SCPE_OK) return r; @@ -1468,15 +1473,15 @@ GET_SWITCHES (cptr); /* get switches */ if (*cptr == 0) /* must be more */ return SCPE_2FARG; cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -if (shptr = find_shtab (show_glob_tab, gbuf)) /* global? */ +if ((shptr = find_shtab (show_glob_tab, gbuf))) /* global? */ return shptr->action (ofile, NULL, NULL, shptr->arg, cptr); -if (dptr = find_dev (gbuf)) { /* device match? */ +if ((dptr = find_dev (gbuf))) { /* device match? */ uptr = dptr->units; /* first unit */ shtb = show_dev_tab; /* global table */ lvl = MTAB_VDV; /* device match */ } -else if (dptr = find_unit (gbuf, &uptr)) { /* unit match? */ +else if ((dptr = find_unit (gbuf, &uptr))) { /* unit match? */ if (uptr == NULL) /* invalid unit */ return SCPE_NXUN; if (uptr->flags & UNIT_DIS) /* disabled? */ @@ -1494,7 +1499,7 @@ if (*cptr == 0) { /* now eol? */ while (*cptr != 0) { /* do all mods */ cptr = get_glyph (cptr, gbuf, ','); /* get modifier */ - if (cvptr = strchr (gbuf, '=')) /* = value? */ + if ((cvptr = strchr (gbuf, '='))) /* = value? */ *cvptr++ = 0; for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) { if (((mptr->mask & MTAB_XTD)? /* right level? */ @@ -1508,7 +1513,7 @@ while (*cptr != 0) { /* do all mods */ } /* end if */ } /* end for */ if (!mptr || (mptr->mask == 0)) { /* no match? */ - if (shptr = find_shtab (shtb, gbuf)) { /* global match? */ + if ((shptr = find_shtab (shtb, gbuf))) { /* global match? */ r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr); if (r != SCPE_OK) return r; @@ -1631,10 +1636,10 @@ int32 vmaj = SIM_MAJOR, vmin = SIM_MINOR, vpat = SIM_PATCH, vdelt = SIM_DELTA; if (cptr && (*cptr != 0)) return SCPE_2MARG; fprintf (st, "%s simulator V%d.%d-%d", sim_name, vmaj, vmin, vpat); +if (vdelt) + fprintf (st, ".%d", vdelt); if (sim_vm_release != NULL) /* if a release string is defined */ fprintf (st, " Release %s", sim_vm_release); /* then display it */ -if (vdelt) - fprintf (st, "(%d)", vdelt); if (flag) fprintf (st, " [%s, %s, %s]", sim_si64, sim_sa64, eth_capabilities()); fprintf (st, "\n"); @@ -1929,7 +1934,7 @@ uptr = dptr->units; if (uptr == NULL) return SCPE_IERR; max = uptr->capac - 1; -if (aptr = strchr (cptr, ';')) { /* ;action? */ +if ((aptr = strchr (cptr, ';'))) { /* ;action? */ if (flg != SSH_ST) /* only on SET */ return SCPE_ARG; *aptr++ = 0; /* separate strings */ @@ -3423,19 +3428,19 @@ ptr = ((char *) rptr->loc) + (idx * rptr->stride); /* point at the starting if (rptr->size == sizeof (uint8)) /* store the value */ *((uint8 *) ptr) = /* using a size */ - (uint8) (*((uint8 *) ptr) & mask | val); /* appropriate to */ + (uint8) ((*((uint8 *) ptr) & mask) | val); /* appropriate to */ /* the size of */ else if (rptr->size == sizeof (uint16)) /* the underlying type */ *((uint16 *) ptr) = - (uint16) (*((uint16 *) ptr) & mask | val); + (uint16) ((*((uint16 *) ptr) & mask) | val); else if (rptr->size == sizeof (uint32)) *((uint32 *) ptr) = - (uint32) (*((uint32 *) ptr) & mask | val); + (uint32) ((*((uint32 *) ptr) & mask) | val); else /* if the element size is non-standard */ *((t_value *) ptr) = /* then access using the largest size permitted */ - *((t_value *) ptr) & mask | val; + (*((t_value *) ptr) & mask) | val; return; } @@ -4091,7 +4096,7 @@ return NULL; DEVICE *find_unit (char *cptr, UNIT **uptr) { -uint32 i, u; +uint32 i, j, u; char *nptr, *tptr; t_stat r; DEVICE *dptr; @@ -4099,7 +4104,7 @@ DEVICE *dptr; sim_ref_type = REF_NONE; /* start with no reference type */ if (uptr == NULL) /* arg error? */ return NULL; -if (dptr = find_dev (cptr)) { /* exact match? */ +if ((dptr = find_dev (cptr))) { /* exact match? */ sim_ref_type = REF_DEVICE; /* indicate a device reference */ if (qdisable (dptr)) /* disabled? */ return NULL; @@ -4108,21 +4113,27 @@ if (dptr = find_dev (cptr)) { /* exact match? */ } for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* base + unit#? */ - if (dptr->numunits && /* any units? */ - (((nptr = dptr->name) && - (strncmp (cptr, nptr, strlen (nptr)) == 0)) || - ((nptr = dptr->lname) && - (strncmp (cptr, nptr, strlen (nptr)) == 0)))) { - tptr = cptr + strlen (nptr); - if (isdigit (*tptr)) { - sim_ref_type = REF_UNIT; /* indicate a unit reference */ - if (qdisable (dptr)) /* disabled? */ - return NULL; - u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r); - if (r != SCPE_OK) /* error? */ - *uptr = NULL; - else *uptr = dptr->units + u; - return dptr; + if (dptr->numunits) { /* any units? */ + for (j = 0; j < 2; j++) { /* check both device names for matches */ + if (((j == 0) && /* if checking the name */ + (((nptr = dptr->name) == NULL) || /* and it is not defined */ + (strncmp (cptr, nptr, strlen (nptr)) != 0))) || /* or it does not match */ + ((j == 1) && /* or if checking the logical name */ + (((nptr = dptr->lname) == NULL) || /* and it is not defined */ + (strncmp (cptr, nptr, strlen (nptr)) != 0)))) /* or it does not match */ + continue; /* then continue the search */ + + tptr = cptr + strlen (nptr); + if (isdigit (*tptr)) { + sim_ref_type = REF_UNIT; /* indicate a unit reference */ + if (qdisable (dptr)) /* disabled? */ + return NULL; + u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r); + if (r != SCPE_OK) /* error? */ + *uptr = NULL; + else *uptr = dptr->units + u; + return dptr; + } } } } @@ -4181,7 +4192,7 @@ REG *rptr, *srptr = NULL; for (i = 0; (dptr = sim_devices[i]) != 0; i++) { /* all dev */ if (dptr->flags & DEV_DIS) /* skip disabled */ continue; - if (rptr = find_reg (cptr, optr, dptr)) { /* found? */ + if ((rptr = find_reg (cptr, optr, dptr))) { /* found? */ if (srptr) /* ambig? err */ return NULL; srptr = rptr; /* save reg */ @@ -4399,15 +4410,15 @@ const char logstr[] = "|&^", cmpstr[] = "=!><"; logval = cmpval = 0; if (*cptr == 0) /* check for clause */ return NULL; -for (logop = cmpop = -1; c = *cptr++; ) { /* loop thru clauses */ - if (sptr = strchr (logstr, c)) { /* check for mask */ +for (logop = cmpop = -1; (c = *cptr++) != 0; ) { /* loop thru clauses */ + if ((sptr = strchr (logstr, c))) { /* check for mask */ logop = (int32)(sptr - logstr); logval = strtotv (cptr, &tptr, radix); if (cptr == tptr) return NULL; cptr = tptr; } - else if (sptr = strchr (cmpstr, c)) { /* check for boolop */ + else if ((sptr = strchr (cmpstr, c))) { /* check for boolop */ cmpop = (int32)(sptr - cmpstr); if (*cptr == '=') { cmpop = cmpop + strlen (cmpstr); @@ -5213,12 +5224,12 @@ while (ep != NULL && (*ep == '\'' || *ep == '"')) { /* if a quoted string is quote = *ep++; /* save the opening quotation mark */ - while (ep [0] != '\0' && ep [0] != quote) /* while characters remain within the quotes */ + while (ep [0] != '\0' && ep [0] != quote) { /* while characters remain within the quotes */ if (ep [0] == '\\' && ep [1] == quote) /* if an escaped quote sequence follows */ ep = ep + 2; /* then skip over the pair */ else /* otherwise */ ep = ep + 1; /* skip the non-quote character */ - + } if (quoted_cmd && *ep == quote) { /* if the entire command is quoted */ sim_brk_act++; /* then skip the leading quote */ cmd_len = (size_t) (ep - sim_brk_act); /* and set the size to trim the trailing quote */ @@ -5227,12 +5238,12 @@ while (ep != NULL && (*ep == '\'' || *ep == '"')) { /* if a quoted string is ep = strpbrk (++ep, ";\"'"); /* search for the next semicolon or single or double quote */ } -if (cmd_len == 0) /* if the command length has not been set */ +if (cmd_len == 0) { /* if the command length has not been set */ if (ep == NULL) /* then if no semicolon is present */ cmd_len = strlen (sim_brk_act); /* then only a single, non-quoted command remains */ else /* otherwise */ cmd_len = (size_t) (ep - sim_brk_act); /* the command extends to the semicolon */ - + } if (cmd_len > (size_t) size - 1) /* if the command length won't fit in the buffer */ cmd_len = (size_t) size - 1; /* then copy only as much as will fit */ diff --git a/scp.h b/scp.h index 50bb567b3..368bd0094 100644 --- a/scp.h +++ b/scp.h @@ -1,6 +1,6 @@ /* scp.h: simulator control program headers - Copyright (c) 1993-2020, Robert M Supnik + Copyright (c) 1993-2024, 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 @@ 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. + 04-Apr-24 JDB Added "get_aval" and "show_break" global declarations 04-Jun-20 JDB Declaration of "sim_vm_init" is now conditional on USE_VM_INIT 08-Dec-19 JDB Added "sim_vm_unit_name" extension hook 09-Oct-19 JDB Added "detach_all" global declaration @@ -187,6 +188,8 @@ t_stat sim_brk_clr (t_addr loc, int32 sw); void sim_brk_clract (void); char *sim_brk_getact (char *buf, int32 size); char *read_line (char *ptr, int32 size, FILE *stream); +t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr); +t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); /* Global data */ diff --git a/sigma/Design Notes on the Sigma 7.doc b/sigma/Design Notes on the Sigma 7.doc index 1a99ffaf20b25b265a43169be4707f75e203b0d9..8c03cf010173bc88bbb210510b7059b8aa61d24f 100644 GIT binary patch delta 3478 zcmcJSe{5UT701uB9VZU8X+nNBIJx~nnt)?$`XePx+EnX8NgLX(g~D1`U+fp>1^d0s z@3{@-52s_&&|s+Tl_)CzAWfPoh}5ax82h0iwGx6!t5yjO(XmNG8_HU`CJUZ4Mw@-l zvrQdZP5FoGeBOQc-gECc_nddndzt)Hnfy#S77-h$Se6p?;8p=Q=I7_Rw;SYY(mz#B zxIBX?@_C46YTxD&B8a0@;V(!Opy9FMvCjja2b|so7oVqr!tF$_#9tj|s_Nx&PpeG2 ze&RhPh^7=N+$&^{TMRX$>B8I=)La%*uY%mb3ZgeL@e4FwM0>L!s+YT6cgbJ5`(2xb z{KCEdp1tU7;K3$bZc{&v!QaY#o|Uz1MtRxXBxgPAyI6qBt;2q@0rf^}ek@pz{FBn!@sJmw^OB81Dq^}CBDJ)SY;7Aqc`}dk6r5k!m zKcWd+9fm2^xEj;4p@r*M&Q6n%v$eReO|j0|b4WxcA`$U2s^~yi?76uap&IexUdpVp ziVhGlxWlwX%rr)lddv=sZRTO^kd_V!>_E3fcHFcqoy~!+goZxD)(l%W4K)datzrbA zFDwSkw9qEh)Ob>J?1?(MBNGp19HWO#dvxJuL^LEUQy>h(jlPogk%iv8=fkW;EjbJ0_1^wU~U=VBv z?;)f94jf0modNr5i1vf0fCjFC>RRLr;0I0MGLpp{_zb**v;ICfhwN32{IH>;nWz)Y zw-B}7T}a>g%lVK0c;Wmn@Vjt6e7uaN!025+EYwC{nZ z<&NMkITh>}Y^)#s)7EKf7~LB9gf`u)>>PB{Zcta=U+N@GX1Oohn9XgcR~`%AE#D8` zr>r{Bx~-F)(gb<{JBOXI1H{1(!4&vCxGrnjn&nHa=jGD2wepv3ei>}@cU&ptuEO>I zH1L+F0a0UDe z%z+gM+I}z#RwGy);8E}x7y*fzEYV5ayag_T@<{%>d>gZiYg{WAySj)5^wVPGzA83d zzV;#;x6{M=QEoT%wU1B*k-XC8V;eZsHv@m`L(#%#s~P)k?UJVvJ&x~TE&s>d7GRlzmz8a@S)efU!dF6NI%91`b4 zl1~@AnEP;82xoz6b3fWxs|@BU;dSs9I1fGmm%!h^G?)W8Wpt_#q!M+x0_EpJe z`<5gsu*Q3sFENLCy~rD=nd2~N23+I0)i~;44!eHGk0cGwA&*qUOwJLVU<}@1TJfMU zmGB_z{7c`;+||C*m07IGk1TtV{tmc6KP{^W6OuHwjHKz=?7P&^@ey%i<4nzkLxF{y z!r5)U-#w`~s#!f31;5gLsdjNxxbXB>5Tx9afq-jGw>-yo&>eI?t}ERz1-82hn}c!g zrR}%$w&#YneMj-$z?N>*;p2LfoO$?X9;?=)2d9Tlo(%&#y_UXW^|hmG+D&35yLt#)XXuh-}7smbWWqU`TWkk z=l<@w=bU?gr=!babU}>OY7LZXE}}+s1^6?ONU(MT(A@{#7EzPBWiQ!OqQ%^kJVS)n z(X2$VVj>3(>>1e8YwNWc+8Z7=)k8Ht7~k>i026b|adnLxG`(i&)`;E|Qd4~LHbuMl zyqCy?wckQ=`#-WA@0nnI8VldU;0VSmSYIHwn)2lPO2o9{mDiPq3YSLY!K6}z$3Muu zn4FRisB3fCjm)ML$tATR#4m8Wc{-_Q!`h=#M^lEz3X*Ris|oH6Rej$w z^Wt}$X``j}s|$&?L*vG}?9?2KPcY7h^lL=5keoJdtD!##*;-)?=`hwmlN!Srg^qgR zM`vAnKKT~Wwv<2YUp18J$kI}gw_EPBa~8QFf8(m(ge*YF8Kp>c%N5H>(W-xt)nU=U za9y{^bA>V8UhK9E;yz4(X>d9R)*VC=OoC(JRS@4o@iN{{H)9++sZ2Cxw4=ri2B;Aijcr! za1mSres~iAH6RSOgGmr_$j5vayYW+J1f^!exxH<~RPP@@* zL}sqZ&;5RR-e2+`)K|tbL;Cl@0^;+?p97^G88MdfR%>yk%0V+|0ogc|9B?^xFxN6S zxSBcmE$yVZs`pzT74kyBj6|e2Kmx5(l|6+UVs0V?icgrx_z-Y)_{ecKMtR}vvM0$h zgR23xOMl_6T+wm`^=Jt!g9ONfaSzZyIS7L~FbR%cW zoj2wrB-=R2yk;%l$I(3vmfkhOKHt4EkN zk?h?XXk2`1f&+~JI#M^fd;XL#`V&q+7fuE0G`u_a4G;9D{<|H~z7KP?)En#(&(68^ zGkph~+5FFj+h&wg*)km163dhssYc}K!yR=-a2qASP$v}&;J27>OT#6 w#dx1JIy`6_JD4o+o8qzdPx30JSu$h(7r>WLdN%vh>*VjiRaCK0oCwa!~g&Q diff --git a/sigma/sigma_bugs.txt b/sigma/sigma_bugs.txt index 594d8a600..829fe4ed4 100644 --- a/sigma/sigma_bugs.txt +++ b/sigma/sigma_bugs.txt @@ -114,20 +114,32 @@ 108. DP: TIO status routine always returns DVS_AUTO instead of proper status. 109. DP: DP_SEEK definition is off by 1. 110. DP: reset does not properly initialize controller, seek threads. -111. DP: device address must include unit identifier everywhere, for interrupt generation. -112. DK: device address must include unit identifier everywhere, for interrupt generation. -113. MT: device address must include unit identifier everywhere, for interrupt generation. -114: RAD: device address must include unit identifier everywhere, for interrupt generation. -115. MT: error handling not consistent. -116: IO: dangling else in write direct mode 1 code causes incorrect behavior. -117: CPU: sim_interval is decremented before breakpoint test, which is incorrect. -118. MT: revised error handling failed to set tape mark status on space file forward/reverse. -119. IO: UEND flag in the wrong bit position in status word. -120. DP: SEEK(I), RECAL(I) must be coded as fast operations. -121. COC: Transmit long space is 0x6, and stop transmit is 0xE. -122. COC: Received break generates a data-in channel transaction with a flag bit set +111. DP, DK, MT, RAD: device address must include unit identifier everywhere, for interrupt generation. +112. MT: error handling not consistent. +113: IO: dangling else in write direct mode 1 code causes incorrect behavior. +114: CPU: sim_interval is decremented before breakpoint test, which is incorrect. +115. MT: revised error handling failed to set tape mark status on space file forward/reverse. +116. IO: UEND flag in the wrong bit position in status word. +117. DP: SEEK(I), RECAL(I) must be coded as fast operations. +118. COC: Transmit long space is 0x6, and stop transmit is 0xE. +119. COC: Received break generates a data-in channel transaction with a flag bit set in the line number. -123. DP: dp_inv_adr error must set a TDV visible flag (i.e., PGE) before UEND. +120. DP: dp_inv_adr error must set a TDV visible flag (i.e., PGE) before UEND. +121. IO, all devices: moved SIO reject-on-interrupt test to devices. +122. DP: SIO will knock down pending device interrupts and allow operation to proceed. +123. MT: AIO must mask unit number before calling TDV status. +124. IO: location 20/21 set incorrectly in the even, non-zero register case. +125. CPU: WAIT must be implemented for correct operation of CP-V. +126. DP: On 10 byte models, SENSE length errors can't happen. On 16 byte models, + SENSE length errors only occur if length == 0 || length > 16. +127. IO: DVT_NOTDEV macro incorrect. +128. DP, DK, MT, RAD: Test for non-existent device returns wrong status. +129. DP, DK, MT: TIO status should return non-operational for unattached device. +130. IO: Device mapping algorithm creates false dispatch points. +131. All devices: dispatch time to INIT state must be 0. +132. LPT: device must flag illegal commands in IDLE state. +133. COC: must flag 0xFF as illegal command in IDLE state. +134. IO: multiplexor channel implements a "chain modifier" capability, needed by punch. Diagnostic Notes ---------------- diff --git a/sigma/sigma_coc.c b/sigma/sigma_coc.c index 6509daa1e..a83f7f49d 100644 --- a/sigma/sigma_coc.c +++ b/sigma/sigma_coc.c @@ -1,6 +1,6 @@ /* sigma_coc.c: Sigma character-oriented communications subsystem simulator - Copyright (c) 2007-2022, Robert M Supnik + Copyright (c) 2007-2024, 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,9 @@ coc 7611 communications multiplexor + 17-Feb-24 RMS Zero delay from SIO to INIT state (Ken Rector) + Detect and UEN on 0xFF order + 15-Dec-22 RMS Moved SIO int pending test to devices 24-Aug-22 RMS Transmit long space is 0x6, not 0xD (Ken Rector) Added LNORDER modifier */ @@ -277,9 +280,11 @@ switch (op) { /* case on op */ case OP_SIO: /* start I/O */ *dvst = mux_tio_status (); /* get status */ - if ((*dvst & DVS_CST) == 0) { /* ctrl idle? */ + if (chan_chk_dvi (dva)) /* int pending? */ + *dvst |= (CC2 << DVT_V_CC); /* SIO fails */ + else if ((*dvst & DVS_CST) == 0) { /* ctrl idle? */ muxc_cmd = MUXC_INIT; /* start dev thread */ - sim_activate (&mux_unit[MUXC], chan_ctl_time); + sim_activate (&mux_unit[MUXC], 0); } break; @@ -403,7 +408,11 @@ else { /* receive */ return 0; } -/* Unit service - channel overhead */ +/* Unit service - channel overhead + + The documentation says that the channel command is thrown away, + but the system exerciser requires a UEN on command 0xFF. +*/ t_stat muxc_svc (UNIT *uptr) { @@ -415,6 +424,10 @@ if (muxc_cmd == MUXC_INIT) { /* init state? */ if (CHS_IFERR (st)) /* channel error? */ mux_chan_err (st); /* go idle */ else muxc_cmd = MUXC_RCV; /* no, receive */ + if (cmd == 0xFF) { /* invalid cmd? */ + chan_uen (mux_dib.dva); /* uend */ + return SCPE_OK; + } } else if (muxc_cmd == MUXC_END) { /* end state? */ st = chan_end (mux_dib.dva); /* set channel end */ diff --git a/sigma/sigma_cp.c b/sigma/sigma_cp.c new file mode 100644 index 000000000..ee5c7165b --- /dev/null +++ b/sigma/sigma_cp.c @@ -0,0 +1,337 @@ +/* sigma_cp.c Sigma 7160 Card Punch + + Copyright (c) 2024, Ken Rector + + 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 + KEN RECTOR 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 Ken Rector shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Ken Rector. + + cp 7160 300 cpm card punch + + The 7160 card punch is described in the SDS Reference Manual, 900971A. + + The simulator writes 120 byte records to the cp attached output file. There + is no control or formatting meta data included in the file. + + Output requests in EBCDIC mode produce hollerith encoded card images. + Output in binary mode produces column binary card images. + + Capacity describes the number of punched cards in the outout stacker. This + accumulates indefinitely. It is not reset when the output file is detached. + +*/ + +#include "sigma_io_defs.h" + + +/* Local unit Commands */ + +#define CPS_INIT 0x101 +#define CPS_STOP 0x00 /* stop*/ +#define CPS_PU01 0x01 /* punch binary normal */ +#define CPS_PU05 0x05 /* punch ebcdic normal */ +#define CPS_PU09 0x09 /* punch binary, error alternate */ +#define CPS_PU0D 0x0d /* punch ebcdic, error alternate */ +#define CPS_PU11 0x11 /* punch binary, alternate */ +#define CPS_PU15 0x15 /* punch ebcdic, alternate */ +#define CPS_PU19 0x19 /* punch binary, alternate */ +#define CPS_PU1D 0x1d /* punch ebcdic, alternate */ +#define CPS_STOPI 0x80 /* stop and interrupt */ + + +#define UST u3 /* unit status */ +#define UCMD u4 /* unit command */ + +#define LEN 120 /* output length */ + +#define DPS_UEN 0x04 /* unusual end occured */ + +char cp_buffer[LEN]; /* card output image */ +int32 cp_bptr = 0; /* buf ptr */ +int32 cp_row = 0; /* row counter */ +int32 cp_stacker1; +int32 cp_stacker2; + +uint32 cp_disp(uint32 fnc, uint32 inst, uint32 *dat); +uint32 cp_tio_status(void); +uint32 cp_tdv_status(void); +t_stat cp_chan_err (uint32 st); +t_stat cp_svc(UNIT *); +t_stat cp_reset (DEVICE *dptr); +t_stat cp_attach(UNIT * uptr, CONST char *file); +t_stat cp_detach(UNIT * uptr); +t_stat cp_show_cap (FILE *st, UNIT *uptr, int32 val, CONST void *desc); + +uint8 cp_op[] = { + 1, 1, 0, 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1 +}; + + +extern uint32 chan_ctl_time; +extern uint16 ebcdic_to_hol[]; + +dib_t cp_dib = { DVA_CP, cp_disp, 0, NULL }; + +UNIT cp_unit = {UDATA(&cp_svc, UNIT_ATTABLE , 0), 2000 }; + +MTAB cp_mod[] = { + {MTAB_XTD | MTAB_VDV, 0, "CHANNEL", "CHANNEL", + &io_set_dvc,&io_show_dvc,NULL}, + { MTAB_XTD|MTAB_VDV, 0, "CAPACITY", NULL, + NULL, &cp_show_cap, NULL, "Punch stacker Count" }, + {0} +}; + +REG cp_reg[] = { + { BRDATA (BUFF, cp_buffer, 8, 8, sizeof(cp_buffer)/sizeof(*cp_buffer)), REG_HRO}, + { DRDATA (BPTR, cp_bptr, 18), PV_LEFT }, + { DRDATA (POS, cp_unit.pos, T_ADDR_W), PV_LEFT }, + { NULL } +}; + +DEVICE cp_dev = { + "CP", &cp_unit, cp_reg, cp_mod, + 1, 10, 31, 1, 16, 8, + NULL, NULL, &cp_reset, NULL, &cp_attach, &cp_detach, + &cp_dib, 0 +}; + +/* Card Punch : IO Dispatch rotine*/ + +uint32 cp_disp (uint32 op, uint32 dva, uint32 *dvst) { + + switch (op) { + + case OP_SIO: /* start I/O */ + *dvst = cp_tio_status (); /* get status */ + /* if automatic mode and ready */ + if ((*dvst & DVS_AUTO) && !sim_is_active(&cp_unit)) { + cp_unit.UCMD = CPS_INIT; /* start dev thread */ + cp_unit.UST = 0; + cp_row = 0; + sim_activate (&cp_unit, 0); + } + break; + + case OP_TIO: /* test status */ + *dvst = cp_tio_status (); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = cp_tdv_status (); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (cp_dib.dva); /* clear int */ + *dvst = cp_tio_status (); /* get status */ + if ((*dvst & DVS_DST) != 0) { /* busy? */ + sim_cancel (&cp_unit); /* stop dev thread */ + cp_unit.UST = DPS_UEN; + chan_uen (cp_dib.dva); /* uend */ + cp_unit.UCMD = 0; /* ctlr idle */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (cp_dib.dva); /* clr int*/ + *dvst = 0; /* no status */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + + return 0; +} + + +/* punch service */ +t_stat cp_svc(UNIT *uptr) { + uint32 cmd; + uint32 dva = cp_dib.dva; + uint32 st; + uint32 i; + uint32 c; + + if (uptr->UCMD == CPS_INIT) { /* init state? */ + st = chan_get_cmd (cp_dib.dva, &cmd); /* get order */ + if (CHS_IFERR (st)) + return cp_chan_err (st); + if ((cmd > 0x80) || + (cp_op[cmd] == 0)) { /* invalid order? */ + uptr->UST = DPS_UEN; + chan_uen (cp_dib.dva); /* report uend */ + return SCPE_OK; + } + uptr->UCMD = cmd; + sim_activate (uptr, chan_ctl_time); + return SCPE_OK; + } + + switch (uptr->UCMD) { + case CPS_PU01: + case CPS_PU05: + case CPS_PU09: + case CPS_PU0D: + case CPS_PU11: + case CPS_PU15: + case CPS_PU19: + case CPS_PU1D: + if (cp_row++ == 11) { /* last row? */ + memset(cp_buffer,0,sizeof(cp_buffer)); + if (uptr->UCMD & 0x4) { /* mode? */ + i = 0; /* ebcdic */ + while (i < LEN) { + st = chan_RdMemB(dva,&c); + if (CHS_IFERR (st)) /* channel error? */ + return cp_chan_err (st); + unsigned short int col = ebcdic_to_hol[c]; /* byte and 1/2 */ + cp_buffer[i++] = (col >> 4) & 0xff; + cp_buffer[i] = (col & 0x0f) << 4; + if (st == CHS_ZBC) /* end request size? */ + break; + st = chan_RdMemB(dva,&c); + if (CHS_IFERR (st)) /* channel error? */ + return cp_chan_err (st); + col = ebcdic_to_hol[c]; /* 1/2 and byte */ + cp_buffer[i++] |= (col >> 8) & 0xf; + cp_buffer[i++] = (col & 0xff); + if (st == CHS_ZBC) /* end request size? */ + break; + } + } + else { + for (i = 0; i < LEN; i++) { /* Binary */ + st = chan_RdMemB(dva,&c); + if (CHS_IFERR (st)) /* channel error? */ + return cp_chan_err (st); + cp_buffer[i] = c; + if (st == CHS_ZBC) /* end request size? */ + break; + + } + } + sim_fwrite (cp_buffer, LEN, 1, uptr->fileref); + cp_stacker1++; + chan_set_cm (dva); /* set Chaining Modifier flag */ + } + st = chan_end (dva); + uptr->UCMD = CPS_INIT; + break; + case CPS_STOPI: + chan_set_chi(dva,CHI_END); /* interrupt */ + case CPS_STOP: + st = chan_end (dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return cp_chan_err (st); + return SCPE_OK; /* done */ + } + sim_activate (uptr, chan_ctl_time); + return SCPE_OK; +} + +/* CP status routine */ + +uint32 cp_tio_status (void) +{ + uint32 st; + + st = cp_unit.flags & UNIT_ATT? DVS_AUTO: 0; /* AUTO : MANUAL */ + if (sim_is_active (&cp_unit)) /* dev busy? */ + st |= ( DVS_DBUSY | (CC2 << DVT_V_CC)); + st |= cp_unit.UST; /* uend? */ + return st; +} + +uint32 cp_tdv_status (void) +{ + + if (cp_unit.flags & UNIT_ATT) /* rdr att? */ + return cp_unit.UST; /* uend */ + return CC2 << DVT_V_CC; +} + +/* Channel error */ + +t_stat cp_chan_err (uint32 st) +{ + cp_unit.UST = DPS_UEN; + chan_uen (cp_dib.dva); /* uend */ + if (st < CHS_ERR) + return st; + return SCPE_OK; +} + +/* Reset routine */ + +t_stat cp_reset (DEVICE *dptr) +{ + + sim_cancel (&cp_unit); /* stop dev thread */ + cp_bptr = 0; + cp_row = 0; + chan_reset_dev (cp_dib.dva); /* clr int, active */ + return SCPE_OK; +} + +/* Attach routine */ + +t_stat cp_attach(UNIT * uptr, CONST char *cptr) { + + return (attach_unit(uptr, cptr)); +} + +t_stat cp_detach(UNIT * uptr) { + + return (detach_unit(uptr)); +} + + +t_stat cp_show_cap (FILE *st, UNIT *uptr, int32 val, CONST void *desc) { + int n; + + if ((n = cp_stacker1) == 0) + fprintf(st,"stacker empty"); + else { + if (n == 1) + fprintf(st,"1 card"); + else + fprintf(st,"%d cards",n); + fprintf(st," in stacker"); + } + return SCPE_OK; +} diff --git a/sigma/sigma_cpu.c b/sigma/sigma_cpu.c index 5942f6c26..8b248147b 100644 --- a/sigma/sigma_cpu.c +++ b/sigma/sigma_cpu.c @@ -1,6 +1,6 @@ /* sigma_cpu.c: XDS Sigma CPU simulator - Copyright (c) 2007-2008, Robert M Supnik + Copyright (c) 2007-2023, 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 central processor + 04-May-23 RMS Implement WAIT 12-Jul-22 RMS Fix incorrect decrement on breakpoint (Ken Rector) The system state for the Sigma CPU is as follows: @@ -174,6 +175,7 @@ uint32 cpu_pdf = 0; /* proc detected fault * uint32 cons_alarm = 0; /* console alarm */ uint32 cons_alarm_enb = 0; /* alarm enable */ uint32 cons_pcf = 0; +uint32 wait_state = 0; /* wait state */ uint32 rf_bmax = 4; /* num reg blocks */ uint32 exu_lim = 32; /* nested EXU limit */ uint32 stop_op = 0; /* stop on ill op */ @@ -446,7 +448,8 @@ while (reason == 0) { /* loop until stop */ if (int_hireq < NO_INT) { /* interrupt req? */ uint32 sav_hi, vec, wd, op; - + + wait_state = 0; /* exit wait state */ sav_hi = int_hireq; /* save level */ vec = io_ackn_int (int_hireq); /* get vector */ if (vec == 0) { /* illegal vector? */ @@ -474,7 +477,7 @@ while (reason == 0) { /* loop until stop */ } else reason = tr2; /* normal status code */ } - else { /* normal instruction */ + else if (wait_state == 0) { /* wait state? skip fetch */ if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ @@ -1501,7 +1504,7 @@ switch (op) { if (!io_poss_int ()) /* intr possible? */ return STOP_WAITNOINT; /* machine is hung */ // put idle here - int_hireq = io_eval_int (); /* re-eval intr */ + wait_state = 1; /* wait for intr */ break; case OP_AIO: /* acknowledge int */ @@ -1539,7 +1542,7 @@ switch (op) { return TR_PRV; if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ return tr; - if ((tr = io_tio (rn, bva)) != 0) /* do AIO */ + if ((tr = io_tio (rn, bva)) != 0) /* do TIO */ return tr; int_hireq = io_eval_int (); /* re-eval intr */ break; @@ -2513,6 +2516,7 @@ cpu_new_PSD (1, PSW1_DFLT | (PSW1 & PSW1_PCMASK), PSW2_DFLT); cpu_pdf = 0; cons_alarm = 0; cons_pcf = 0; +wait_state = 0; set_rf_display (R); if (M == NULL) M = (uint32 *) calloc (MAXMEMSIZE, sizeof (uint32)); diff --git a/sigma/sigma_cr.c b/sigma/sigma_cr.c new file mode 100644 index 000000000..46a4a0b1c --- /dev/null +++ b/sigma/sigma_cr.c @@ -0,0 +1,435 @@ +/* sigma_cr.c: Sigma 7120/7122/7140 card reader + + Copyright (c) 2024, Ken Rector + + 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 + KEN RECTOR 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 Ken Rector shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Ken Rector. + + cr 7120 card reader + + 27-Feb-2024 kenr Initial version + + The 7120, 7122 and 7140 card readers are described in the SDS + reference manual, 900970C. + + The simulator expects input data to be a file of 120 byte records with no control + or other extraneous data, to simulate a punched card deck. Each 120 byte record + is translated to 80 16 bit columns with data in the loworder 12 bits. In + automatic mode each column (1-1/2 bytes) is translated from a hollerith code + to an ebcdic character (1 byte). In binary mode each pair of columns is + translated to 3 data bytes. + + A length error in the input data will not be detected until the end of file + and results in an Invalid Length and Unusual End status. CPV sets the ignore + incorrect length flag so this can cause trouble in the symbiont input process. + + Card reader speed for the 7120, 7122 and 7140 machines was 400, 400 and 1500 + cards per minute respectively, or 150, 150 and 40 msec per card. The simulator + runs much faster than this, transmitting 80 columns in ~400 instruction cycles, + or 5 cycles per column. + + The cr device capacity indicates the number of cards in the hopper and stacker. + There is no limit on the number of records in the hopper or stacker. The + stacker is never emptied and the count can overflow. The hopper counter is + set when a file is attached and reduced as each card is read. + + The cardreader is detached from the input file when the hopper count + reaches zero. + + The card reader reports a Data Transmission Error if an incorrect EBCDIC character + is detected, (more than 1 punch in rows 1-7). + + */ + +#include +#include "sigma_io_defs.h" + + +/* Unit status */ + +#define CDR_DTE 0x08 /* data error */ + +/* Device States */ + +#define CRS_INIT 0x101 /* feed card */ +#define CRS_END 0x102 /* end card */ + +#define UST u3 /* unit status */ +#define UCMD u4 /* unit command */ + +uint32 cr_bptr; /* buffer index */ +uint32 cr_blnt; /* buffer length */ +uint32 cr_col; /* current column */ +uint32 cr_hopper; /* hopper count */ +uint32 *cr_stkptr; /* selected stacker */ +uint32 cr_stacker = 0; /* stacker count */ +uint32 cr_stacker1 = 0; /* stacker 1 count */ +uint32 cr_stacker2 = 0; /* stacker 2 count */ +uint16 cr_buffer[80]; /* 80 column data */ +uint32 cr_ebcdic_init = 0; /* translate initial flag */ +uint16 hol_to_ebcdic[4096]; /* translation table */ + +uint8 cr_ord[] = { /* valid order codes*/ + 0, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 1, 0 +}; + +extern uint32 chan_ctl_time; +extern uint16 ebcdic_to_hol[]; + + +uint32 cr_disp (uint32 op, uint32 dva, uint32 *dvst); +t_stat cr_readrec (UNIT *uptr); +uint32 cr_tio_status (void); +uint32 cr_tdv_status (void); +t_stat cr_chan_err (uint32 st); +t_stat cr_svc (UNIT *uptr); +t_stat cr_reset (DEVICE *dptr); +t_stat cr_attach (UNIT *uptr, CONST char *cptr); +t_stat cr_detach (UNIT *uptr); +t_stat cr_show_cap (FILE *st, UNIT *uptr, int32 val, CONST void *desc); + + +dib_t cr_dib = { DVA_CR, cr_disp, 0, NULL }; + +UNIT cr_unit = { + UDATA(&cr_svc, UNIT_ATTABLE | UNIT_RO , 0), + 60 +}; + +REG cr_reg[] = { + { DRDATA (BPTR, cr_bptr, 17), PV_LEFT }, + { DRDATA (BLNT, cr_blnt, 17), PV_LEFT }, + { NULL } +}; + +MTAB cr_mod[] = { + {MTAB_XTD | MTAB_VDV, 0, "CHANNEL", "CHANNEL", + &io_set_dvc,&io_show_dvc,NULL}, + {MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + {MTAB_XTD|MTAB_VDV, 0, "CAPACITY", NULL, + NULL, &cr_show_cap, NULL, "Card hopper size" }, + {0} +}; + +DEVICE cr_dev = { + "CR", &cr_unit, cr_reg, cr_mod, + 1, 10, 31, 1, 16, 8, + NULL, NULL, &cr_reset, &io_boot,&cr_attach,&cr_detach, + &cr_dib, 0 +}; + + +/* Card Reader : IO dispatch routine */ + +uint32 cr_disp (uint32 op, uint32 dva, uint32 *dvst) +{ + switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = cr_tio_status (); /* get status */ + if ((*dvst & DVS_AUTO) && !sim_is_active(&cr_unit)) { + cr_unit.UCMD = CRS_INIT; /* start dev thread */ + cr_stkptr = &cr_stacker; + sim_activate (&cr_unit, 0); + } + break; + + case OP_TIO: /* test status */ + *dvst = cr_tio_status (); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = cr_tdv_status (); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (cr_dib.dva); /* clear int */ + *dvst = cr_tio_status (); + if ((*dvst & DVS_DST) != 0) { /* busy? */ + sim_cancel (&cr_unit); /* stop dev thread */ + chan_uen (cr_dib.dva); /* uend */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (cr_dib.dva); /* clr int*/ + *dvst = 0; /* no status */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + + return 0; +} + +/* Service routine */ + +t_stat cr_svc (UNIT *uptr) +{ + uint32 cmd = uptr->UCMD; + t_stat st; + char c; + + if (cmd == CRS_INIT) { /* init state */ + st = chan_get_cmd (cr_dib.dva, &cmd); /* get order */ + if (CHS_IFERR (st)) /* bad device id, inactive state */ + return cr_chan_err (st); + if ((cmd > 0x3e) || /* invalid order? */ + (cr_ord[cmd] == 0)) { + chan_uen (cr_dib.dva); + return SCPE_OK; + } + uptr->UCMD = cmd; /* save order */ + cr_blnt = 0; /* empty buffer */ + cr_col = 0; /* initial column */ + switch (cmd & 0x30) { /* note stacker */ + case 0x10: + cr_stkptr = &cr_stacker1; + break; + case 0x30: + cr_stkptr = &cr_stacker2; + break; + default: + cr_stkptr = &cr_stacker; + break; + } + sim_activate (uptr, chan_ctl_time); + return SCPE_OK; + } + if (cmd == CRS_END) { /* end of card */ + st = chan_end (cr_dib.dva); /* set channel end, inactive */ + if (CHS_IFERR (st)) /* bad dev/inactive? */ + return cr_chan_err (st); + ++*cr_stkptr; /* add to stacker */ + if (--cr_hopper == 0) /* remove from hopper */ + cr_detach(uptr); /* end input deck */ + if (st == CHS_CCH) { /* command chain? */ + uptr->UCMD = CRS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + return SCPE_OK; + } + + if (cr_blnt == 0) { /* card arriving? */ + if (cr_readrec (uptr) == 0) { /* unexpected EOF, inv reclnt? */ + uptr->UCMD = CRS_END; /* end state */ + sim_activate (uptr, chan_ctl_time); /* sched ctlr */ + return SCPE_OK; + } + if ((cmd & 0x04) && /* mode change? */ + ((cr_buffer[0] & 0x180) == 0x180)) { + cmd &= ~0x04; /* automatic(EBCDIC) and row 1 2 */ + uptr->UCMD = cmd; /* switch to binary mode */ + } + } + if (cmd & 0x04) { /* mode? */ + c = (char) hol_to_ebcdic[cr_buffer[cr_bptr]]; /* automatic */ + int i = 0; /* invalid punches? */ + int n = cr_buffer[cr_bptr++] & 0x1fc; + while (n) { /* Kerninghams bit count alg */ + n &= (n-1); /* count bits in row 1-7 */ + i++; + } + if (i > 1) { /* >2 punches? */ + c = 0x00; /* return 0x00 */ + uptr->UST |= CDR_DTE; /* Transmission Data Error*/ + chan_set_chf (cr_dib.dva, CHF_XMDE); /* operational status byte */ + } + } + else { + switch (cr_col % 3) { /* binary */ + case 0: + c = ((cr_buffer[cr_bptr] >> 4) & 0xff); + break; + case 1: + c = ((cr_buffer[cr_bptr] & 0x0f) << 4); + cr_bptr++; + c |= ((cr_buffer[cr_bptr] & 0xf00) >> 8); + break; + case 2: + c = (cr_buffer[cr_bptr++] & 0xff); + break; + } + } + cr_col++; + st = chan_WrMemB (cr_dib.dva, c); /* write to memory */ + if (CHS_IFERR (st)) /* channel error? */ + return cr_chan_err (st); + if ((st != CHS_ZBC) && (cr_bptr != cr_blnt)) { /* not done? */ + sim_activate (uptr, chan_ctl_time); /* continue */ + return SCPE_OK; + } + if (((st == CHS_ZBC) ^ (cr_bptr == cr_blnt)) && /* length err? */ + chan_set_chf (cr_dib.dva, CHF_LNTE)) /* Incorrect Length */ + return SCPE_OK; /* to operational status byte */ + + uptr->UCMD = CRS_END; /* end state */ + sim_activate (uptr, chan_ctl_time); /* sched ctlr */ + return SCPE_OK; +} + + +/* get next record */ + +t_stat cr_readrec (UNIT *uptr) { + + int col; + FILE *fp = uptr->fileref; + + for (col = 0; col < 80; ) { + int16 i; + int c1, c2, c3; + + c1 = fgetc (fp); /* read 3 bytes */ + c2 = fgetc (fp); + c3 = fgetc (fp); + if (feof(fp) || (c1 == EOF) || (c2 == EOF) || (c3 == EOF)) { + cr_blnt = cr_bptr = 0; + chan_set_chf (cr_dib.dva, CHF_LNTE); + return 0; + } + i = ((c1 << 4) | ( c2 >> 4)) & 0xFFF; /* pack 1-1/2 bytes per column */ + cr_buffer[col] = i; + col++; + i = (((c2 & 017) << 8) | c3) & 0xFFF; + cr_buffer[col] = i; + col++; + } + cr_bptr = 0; + cr_blnt = 80; + return 80; +} + + +/* CR status routine */ + +uint32 cr_tio_status (void) +{ + uint32 st; + + st = (cr_unit.flags & UNIT_ATT) ? DVS_AUTO: 0; /* AUTO : MANUAL */ + if (sim_is_active (&cr_unit)) /* dev busy? */ + st |= ( DVS_CBUSY | DVS_DBUSY | (CC2 << DVT_V_CC)); + return st; +} + +uint32 cr_tdv_status (void) +{ + uint32 st; + + if (cr_unit.flags & UNIT_ATT && + (cr_hopper > 0)) /* rdr att? */ + st = cr_unit.UST; + else + st = (CC2 << DVT_V_CC); + return st; +} + +/* Channel error */ + +t_stat cr_chan_err (uint32 st) +{ + chan_uen (cr_dib.dva); + if (st < CHS_ERR) + return st; + return SCPE_OK; +} + +/* Reset routine */ + +t_stat cr_reset (DEVICE *dptr) +{ + if (!cr_ebcdic_init) { /* initialize translate table */ + for (int i = 0; i < 4096; i++) + hol_to_ebcdic[i] = 0x100; /* a la sim_card */ + for (int i = 0; i < 256; i++) { + uint16 temp = ebcdic_to_hol[i]; + if (hol_to_ebcdic[temp] != 0x100) { + fprintf(stderr, "Translation error %02x is %03x and %03x\n", + i, temp, hol_to_ebcdic[temp]); + } else { + hol_to_ebcdic[temp] = i; + } + } + cr_ebcdic_init = 1; + } + sim_cancel (&cr_unit); /* stop dev thread */ + chan_reset_dev (cr_dib.dva); /* clr int, active */ + return SCPE_OK; +} + +/* Attach routine */ + +t_stat cr_attach (UNIT *uptr, CONST char *cptr) +{ + char *saved_filename; + int r; + + saved_filename = uptr->filename; + uptr->filename = NULL; + if ((r = attach_unit(uptr, cptr)) != SCPE_OK) { + uptr->filename = saved_filename; + return r; + } + r = sim_fsize(uptr->fileref); + if ((r % 120) != 0) { /* multiple of 120 byte cards? */ + detach_unit(uptr); + fprintf(stderr,"CR file size error\n"); + return SCPE_IOERR; + } + cr_hopper = r / 120; + return SCPE_OK; +} + +/* Detach routine */ + +t_stat cr_detach (UNIT *uptr) +{ + cr_hopper = 0; + return detach_unit(uptr); +} + +t_stat cr_show_cap (FILE *st, UNIT *uptr, int32 val, CONST void *desc) { + + if (cr_hopper == 0) + fprintf(st,"hopper empty"); + else { + if (cr_hopper == 1) + fprintf(st,"1 card"); + else + fprintf(st,"%d cards",cr_hopper); + fprintf(st," in hopper"); + } + fprintf(st,"\nNormal Stacker %d\n",cr_stacker); + fprintf(st,"Alt Stacker 1 %d\n",cr_stacker1); + fprintf(st,"Alt Stacker 2 %d",cr_stacker2); + return SCPE_OK; +} diff --git a/sigma/sigma_dk.c b/sigma/sigma_dk.c index 220bceb08..cef9f35b1 100644 --- a/sigma/sigma_dk.c +++ b/sigma/sigma_dk.c @@ -1,6 +1,6 @@ /* sigma_dk.c: 7250/7251-7252 cartridge disk simulator - Copyright (c) 2007-2022, Robert M Supnik + Copyright (c) 2007-2024, 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,10 @@ dk 7250/7251-7252 cartridge disk + 17-Feb-24 RMS Zero delay from SIO to INIT state (Ken Rector) + 11-Feb-24 RMS Report non-operational if not attached (Ken Rector) + 01-Feb-24 RMS Fixed nx unit test (Ken Rector) + 15-Dec-22 RMS Moved SIO interrupt test to devices 02-Jul-22 RMS Fixed bugs in multi-unit operation Transfers are always done a sector at a time. @@ -165,15 +169,19 @@ int32 iu; UNIT *uptr; if ((un >= DK_NUMDR) || /* inv unit num? */ - (dk_unit[un].flags & UNIT_DIS)) /* disabled unit? */ - return DVT_NODEV; + (dk_unit[un].flags & UNIT_DIS)) { /* disabled unit? */ + *dvst = DVT_NODEV; + return 0; + } switch (op) { /* case on op */ case OP_SIO: /* start I/O */ *dvst = dk_tio_status (un); /* get status */ - if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + if (chan_chk_dvi (dva)) /* int pending? */ + *dvst |= (CC2 << DVT_V_CC); /* SIO fails */ + else if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ dk_cmd = DKS_INIT; /* start dev thread */ - sim_activate (&dk_unit[un], chan_ctl_time); + sim_activate (&dk_unit[un], 0); } break; @@ -411,12 +419,17 @@ return FALSE; /* cmd done */ uint32 dk_tio_status (uint32 un) { -uint32 i; +uint32 i, st; +st = DVS_AUTO; /* flags */ +if (sim_is_active (&dk_unit[un])) /* active => busy */ + st |= DVS_DBUSY; +else if ((dk_unit[un].flags & UNIT_ATT) == 0) /* not att => offl */ + st |= DVS_DOFFL; for (i = 0; i < DK_NUMDR; i++) { /* loop thru units */ if (sim_is_active (&dk_unit[i])) /* active? */ - return (DVS_AUTO | DVS_CBUSY | (CC2 << DVT_V_CC) | - ((i == un)? DVS_DBUSY: 0)); + st |= (DVS_CBUSY | (CC2 << DVT_V_CC)); /* ctrl is busy */ + return st; } return DVS_AUTO; } diff --git a/sigma/sigma_dp.c b/sigma/sigma_dp.c index 91d5ddcc7..617364f9c 100644 --- a/sigma/sigma_dp.c +++ b/sigma/sigma_dp.c @@ -1,6 +1,6 @@ /* sigma_dp.c: moving head disk pack controller - Copyright (c) 2008-2022, Robert M Supnik + Copyright (c) 2008-2024, 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,13 @@ dp moving head disk pack controller + 05-Apr-24 RMS Added case points for RDEES, CRIOF (Ken Rector) + 17-Feb-24 RMS Zero delay from SIO to INIT state (Ken Rector) + 11-Feb-24 RMS Report non-operational if not attached (Ken Rector) + 01-Feb-24 RMS Fixed nx unit test (Ken Rector) + 03-Jun-23 RMS Fixed SENSE length error detection (Ken Rector) + 06-Mar-23 RMS SIO can start despite outstanding seek interrupt (Ken Rector) + 15-Dec-22 RMS Moved SIO interrupt test to devices 09-Dec-22 RMS Invalid address must set a TDV-visible error flag (Ken Rector) 23-Jul-22 RMS SEEK(I), RECAL(I) should be fast operations (Ken Rector) 02-Jul-22 RMS Fixed bugs in multi-unit operation @@ -47,6 +54,16 @@ one for timing asynchronous seek completions. The controller will not start a new operation is it is busy (any of the main units active) or if the target device is busy (its seek unit is active). + + The DP's seek interrupt has a unique feature: it comes and goes, lasting only + a sector's time; and it gets "knocked down" by any SIO to a different unit. + Therefore, the SIO interrupt check is complicated. + + 1. If there's a controller interrupt, the SIO fails. + 2. If there's a seek interrupt on the selected unit, the SIO fails. + 3. All other seek interrupts are "knocked down" and rescheduled for + some time "in the future." + 4. The SIO completes normally. */ #include "sigma_io_defs.h" @@ -577,22 +594,39 @@ int32 iu; uint32 i; DP_CTX *ctx; -if (cidx >= DP_NUMCTL) /* inv ctrl num? */ - return DVT_NODEV; +if (cidx >= DP_NUMCTL) { /* inv ctrl num? */ + *dvst = DVT_NODEV; + return 0; + } ctx = &dp_ctx[cidx]; if (((un < DP_NUMDR) && /* un valid and */ ((dp_unit[un].flags & UNIT_DIS) == 0)) || /* not disabled OR */ ((un == 0xF) && (ctx->dp_ctype == DP_C3281))) /* 3281 unit F? */ uptr = dp_unit + un; /* un exists */ -else return DVT_NODEV; +else { + *dvst = DVT_NODEV; + return 0; + } switch (op) { /* case on op */ case OP_SIO: /* start I/O */ *dvst = dp_tio_status (cidx, un); /* get status */ + if ((chan_chk_chi (dva) >= 0) || /* channel int pending? */ + (dp_ctx[cidx].dp_ski & (1u << un))) { /* seek int on sel unit? */ + *dvst |= (CC2 << DVT_V_CC); /* SIO fails */ + break; + } + for (i = 0; i < DP_NUMDR; i++) { /* knock down other seek ints */ + if (dp_ctx[cidx].dp_ski & (1u << i)) { /* seek int on unit? */ + dp_clr_ski (cidx, i); /* knock it down */ + sim_activate (&dp_unit[i + DP_SEEK], chan_ctl_time * 10); + dp_unit[i + DP_SEEK].UCMD = DSC_SEEKW; /* resched interrupt */ + } + } if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ uptr->UCMD = DPS_INIT; /* start dev thread */ - sim_activate (uptr, chan_ctl_time); + sim_activate (uptr, 0); } break; @@ -759,7 +793,7 @@ switch (uptr->UCMD) { if (CHS_IFERR (st)) /* channel error? */ return dp_chan_err (dva, st); } - if ((i != DPS_NBY) || (st != CHS_ZBC)) { /* length error? */ + if (!DP_Q10B (ctx->dp_ctype) && (st != CHS_ZBC)) { /* 16B only: length error? */ ctx->dp_flags |= DPF_PGE; /* set prog err */ if (chan_set_chf (dva, CHF_LNTE)) /* do we care? */ return SCPE_OK; @@ -852,6 +886,7 @@ switch (uptr->UCMD) { return SCPE_OK; /* err or cont */ break; + case DPS_RDEES: /* read */ case DPS_READ: /* read */ if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ ctx->dp_flags |= DPF_PGE; @@ -903,6 +938,7 @@ switch (uptr->UCMD) { return SCPE_OK; break; + case DPS_CRIOF: /* cond rls intr */ case DPS_RSRV: /* reserve */ case DPS_RLS: /* release */ case DPS_RLSA: /* release */ @@ -974,21 +1010,23 @@ return FALSE; /* cmd done */ uint32 dp_tio_status (uint32 cidx, uint32 un) { -uint32 i; +uint32 i, st; DP_CTX *ctx = &dp_ctx[cidx]; UNIT *dp_unit = dp_dev[cidx].units; -uint32 stat = DVS_AUTO; +st = DVS_AUTO; +if (sim_is_active (&dp_unit[un]) || + sim_is_active (&dp_unit[un + DP_SEEK])) + st |= (DVS_DBUSY | (CC2 << DVT_V_CC)); +else if ((un != 0xF) && ((dp_unit[un].flags & UNIT_ATT) == 0)) + st |= DVS_DOFFL; for (i = 0; i < DP_NUMDR; i++) { if (sim_is_active (&dp_unit[i])) { - stat |= (DVS_CBUSY | (CC2 << DVT_V_CC)); + st |= (DVS_CBUSY | (CC2 << DVT_V_CC)); break; } } -if (sim_is_active (&dp_unit[un]) || - sim_is_active (&dp_unit[un + DP_SEEK])) - stat |= (DVS_DBUSY | (CC2 << DVT_V_CC)); -return stat; +return st; } uint32 dp_tdv_status (uint32 cidx, uint32 un) diff --git a/sigma/sigma_io.c b/sigma/sigma_io.c index c9085c6c8..6759dff17 100644 --- a/sigma/sigma_io.c +++ b/sigma/sigma_io.c @@ -1,6 +1,6 @@ /* sigma_io.c: XDS Sigma IO simulator - Copyright (c) 2007-2022, Robert M Supnik + Copyright (c) 2007-2024, 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,10 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 19-Mar-2024 RMS Added chaining modifier flag (Ken Rector) + 11-Feb-2024 RMS Fixed false dispatch bug (Ken Rector) + 04-May-2023 RMS Fixed location 21 usage in even register case (Ken Rector) + 15-Dec-2022 RMS Moved SIO interrupt test to devices 23-Jul-2022 RMS Made chan_ctl_time accessible as a register 21-Jul-2022 RMS Added numeric channel numbers to SET/SHOW 07-Jul-2022 RMS Fixed dangling else in read/write direct (Ken Rector) @@ -353,11 +357,6 @@ if (!io_init_inst (rn, ad, ch, dev, R[0])) { /* valid inst? */ CC |= CC1|CC2; return 0; } -if (chan[ch].chf[dev] & CHF_INP) { /* int pending? */ - chan[ch].disp[dev] (OP_TIO, ad, &dvst); /* get status */ - CC |= (CC2 | io_set_status (rn, ch, dev, dvst, 0)); /* set status */ - return 0; - } st = chan[ch].disp[dev] (OP_SIO, ad, &dvst); /* start I/O */ CC |= io_set_status (rn, ch, dev, dvst, 0); /* set status */ if (CC & cpu_tab[cpu_model].iocc) /* error? */ @@ -365,6 +364,7 @@ if (CC & cpu_tab[cpu_model].iocc) /* error? */ chan[ch].chf[dev] = 0; /* clear flags */ chan[ch].chi[dev] = 0; /* clear intrs */ chan[ch].chsf[dev] |= CHSF_ACT; /* set chan active */ +chan[ch].chsf[dev] &= ~CHSF_CM; /* clear chain mod */ chan_new_cmd (ch, dev, R[0]); /* new command */ return st; } @@ -478,14 +478,27 @@ CC |= CC1|CC2; /* no recognition */ return 0; } -/* Initiate I/O instruction */ +/* Initiate I/O instruction + + False dispatch problem. Although device numbers are not permitted to overlap, + there is nothing to stop programs from issuing IO instructions to a multi- + unit device address using its single-unit counterpart, or vice-versa. + For example, an IO address of 0x00 will map to the dispatch used for + 0x80, and vice versa. This routine must detect that the device + address actually agrees with the type of device in that dispatch slot. +*/ t_bool io_init_inst (uint32 rn, uint32 ad, uint32 ch, uint32 dev, uint32 r0) { uint32 loc20; +t_bool ch_mu, dva_mu; -if (ch >= chan_num) /* bad chan? */ +if ((dev >= CHAN_N_DEV) || (ch >= chan_num)) /* bad dev or chan? */ return FALSE; +ch_mu = (chan[ch].chsf[dev] & CHSF_MU) != 0; /* does chan think MU? */ +dva_mu = (ad & DVA_MU) != 0; /* is dva MU? */ +if (ch_mu != dva_mu) /* not the same? */ + return FALSE; /* dev not there */ loc20 = ((ad & 0xFF) << 24) | /* <0:7> = dev ad */ ((rn & 1) | (rn? 3: 0) << 22) | /* <8:9> = reg ind */ (r0 & (cpu_tab[cpu_model].pamask >> 1)); /* <14/16:31> = r0 */ @@ -498,17 +511,17 @@ return (chan[ch].disp[dev] != NULL)? TRUE: FALSE; uint32 io_set_status (uint32 rn, uint32 ch, uint32 dev, uint32 dvst, t_bool tdv) { uint32 mrgst; -uint32 odd = rn & 1; if ((rn != 0) && !(dvst & DVT_NOST)) { /* return status? */ if (tdv) mrgst = (DVT_GETDVS (dvst) << 8) | (chan[ch].chf[dev] & 0xFF); else mrgst = ((DVT_GETDVS(dvst) << 8) & ~CHF_ALL) | (chan[ch].chf[dev] & CHF_ALL); - R[rn] = chan[ch].clc[dev]; /* even reg */ - if (!odd) /* even pair? */ - WritePW (0x20, R[rn]); /* write to 20 */ + if ((rn & 1) == 0) { /* even reg? */ + R[rn] = chan[ch].clc[dev]; /* current addr to R */ + WritePW (0x20, R[rn]); /* and loc 20 */ + } R[rn|1] = (mrgst << 16) | chan[ch].bc[dev]; /* odd reg */ - WritePW (0x20 + odd, R[rn|1]); /* write to 20/21 */ + WritePW (0x21, R[rn|1]); /* write loc 21 */ } return DVT_GETCC (dvst); } @@ -533,16 +546,18 @@ return 0; uint32 chan_end (uint32 dva) { uint32 ch, dev; -uint32 st; +uint32 st, cm; if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ return st; if (chan[ch].cmf[dev] & CMF_ICE) /* int on chan end? */ chan_set_chi (dva, CHI_END); +cm = chan[ch].chsf[dev] & CHSF_CM ? 1 : 0; /* get modifier flag, */ +chan[ch].chsf[dev] &= ~CHSF_CM; /* then clear it */ if ((chan[ch].cmf[dev] & CMF_CCH) && /* command chain? */ - !chan_new_cmd (ch, dev, chan[ch].clc[dev] + 1)) /* next command? */ + !chan_new_cmd (ch, dev, chan[ch].clc[dev] + 1 + cm)) /* next command? */ return CHS_CCH; -else chan[ch].chsf[dev] &= ~CHSF_ACT; /* channel inactive */ +else chan[ch].chsf[dev] &= ~(CHSF_ACT|CHSF_CM); /* channel inactive */ return 0; } @@ -600,7 +615,7 @@ if (!VALID_DVA (ch, dev)) /* valid? */ if (chan[ch].cmf[dev] & CMF_IUE) /* int on uend? */ chan_set_chi (dva, CHI_UEN); chan[ch].chf[dev] |= CHF_UEN; /* flag uend */ -chan[ch].chsf[dev] &= ~CHSF_ACT; +chan[ch].chsf[dev] &= ~(CHSF_ACT|CHSF_CM); return CHS_INACTV; /* done */ } @@ -749,7 +764,7 @@ for (i = 0; i < 2; i++) { /* max twice */ chan[ch].clc[dev] = clc; /* and save */ if (ReadPW (clc << 1, &ccw1)) { /* get ccw1, nxm? */ chan[ch].chf[dev] |= CHF_IOME; /* memory error */ - chan[ch].chsf[dev] &= ~CHSF_ACT; /* stop channel */ + chan[ch].chsf[dev] &= ~(CHSF_ACT|CHSF_CM); /* stop channel */ return CHS_INACTV; } ReadPW ((clc << 1) + 1, &ccw2); /* get ccw2 */ @@ -765,7 +780,7 @@ for (i = 0; i < 2; i++) { /* max twice */ } } chan[ch].chf[dev] |= CHF_IOCE; /* control error */ -chan[ch].chsf[dev] &= ~CHSF_ACT; /* stop channel */ +chan[ch].chsf[dev] &= ~(CHSF_ACT|CHSF_CM); /* stop channel */ return CHS_INACTV; } @@ -806,7 +821,7 @@ if (chan[ch].chi[dev] & CHI_CTL) /* ctl int pending? */ else return -1; } -/* Set device interrupt */ +/* Set, check device interrupt */ void chan_set_dvi (uint32 dva) { @@ -817,6 +832,30 @@ chan[ch].chf[dev] |= CHF_INP; /* int pending */ return; } +t_bool chan_chk_dvi (uint32 dva) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); + +if ((chan[ch].chf[dev] & CHF_INP) != 0) + return TRUE; +return FALSE; +} + +/* Channel set Chaining Modifier flag */ + +uint32 chan_set_cm (uint32 dva) +{ +uint32 ch, dev; + +ch = DVA_GETCHAN (dva); /* get chan, dev */ +dev = DVA_GETDEV (dva); +if (!VALID_DVA (ch, dev)) /* valid? */ + return SCPE_IERR; +chan[ch].chsf[dev] |= CHSF_CM; +return 0; +} + /* Called by device reset to reset channel registers */ t_stat chan_reset_dev (uint32 dva) @@ -828,7 +867,7 @@ dev = DVA_GETDEV (dva); if (!VALID_DVA (ch, dev)) /* valid? */ return SCPE_IERR; chan[ch].chf[dev] &= ~CHF_INP; /* clear intr */ -chan[ch].chsf[dev] &= ~CHSF_ACT; /* clear active */ +chan[ch].chsf[dev] &= ~(CHSF_ACT|CHSF_CM); /* clear active */ return SCPE_OK; } @@ -1224,7 +1263,7 @@ for (i = 0; i < CHAN_N_DEV; i++) { chan[ch].bc[i] = 0; chan[ch].chf[i] = 0; chan[ch].chi[i] = 0; - chan[ch].chsf[i] &= ~CHSF_ACT; + chan[ch].chsf[i] &= ~(CHSF_ACT|CHSF_CM); for (j = 0; (devp = sim_devices[j]) != NULL; j++) { /* loop thru dev */ if (devp->ctxt != NULL) { dib_t *dibp = (dib_t *) devp->ctxt; diff --git a/sigma/sigma_io_defs.h b/sigma/sigma_io_defs.h index 921c6f3ac..d109ed837 100644 --- a/sigma/sigma_io_defs.h +++ b/sigma/sigma_io_defs.h @@ -1,6 +1,6 @@ /* sigma_io_defs.h: XDS Sigma I/O device simulator definitions - Copyright (c) 2007-2008, Robert M Supnik + Copyright (c) 2007-2024, 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,9 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 19-Mar-24 RMS Added chaining modifier flag (Ken Rector) + 01-Feb-24 RMS Fixed DVT_NODEV definition (Ken Rector) + 15-Dec-22 RMS Added chan_chk_dvi definition 21-Jul-22 RMS Channel UEND flag in wrong bit position (Ken Rector) */ @@ -126,6 +129,7 @@ typedef struct { #define CHSF_ACT 0x0001 /* channel active */ #define CHSF_MU 0x0002 /* multi-unit dev */ +#define CHSF_CM 0x0004 /* chaining modifier */ /* Dispatch routine status return value */ @@ -149,7 +153,7 @@ typedef struct { #define DVT_GETCC(x) (((x) >> DVT_V_CC) & DVT_M_CC) #define DVT_GETDVS(x) (((x) >> DVT_V_DVS) & DVT_M_DVS) #define DVT_NOST (CC1 << DVT_V_CC) /* no status */ -#define DVT_NODEV ((CC1|CC2) < DVT_V_CC) /* no device */ +#define DVT_NODEV ((CC1|CC2) << DVT_V_CC) /* no device */ /* Read and write direct address format */ @@ -252,6 +256,8 @@ void chan_set_chi (uint32 dva, uint32 fl); void chan_set_dvi (uint32 dva); int32 chan_clr_chi (uint32 dva); int32 chan_chk_chi (uint32 dva); +t_bool chan_chk_dvi (uint32 dva); +uint32 chan_set_cm (uint32 dva); uint32 chan_end (uint32 dva); uint32 chan_uen (uint32 dva); uint32 chan_RdMemB (uint32 dva, uint32 *dat); diff --git a/sigma/sigma_lp.c b/sigma/sigma_lp.c index 5a25633f7..39598e86d 100644 --- a/sigma/sigma_lp.c +++ b/sigma/sigma_lp.c @@ -1,6 +1,6 @@ /* sigma_lp.c: Sigma 7440/7450 line printer - Copyright (c) 2007-2021, Robert M. Supnik + Copyright (c) 2007-2024, 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,9 @@ lp 7440/7445 or 7450 line printer + 18-Feb-24 RMS Zero delay from SIO to INIT state (Ken Rector) + Added INIT test for illegal command (Ken Rector) + 15-Dec-2022 RMS Moved SIO interrupt test to devices 10-Jun-2021 RMS Removed use of ftell for pipe compatibility 09-Mar-2017 RMS Fixed unclosed file returns in CCT load (COVERITY) */ @@ -97,6 +100,24 @@ uint8 lp_to_ascii[64] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '#', '@', '\'', '=', '"' }; +static uint8 lp_valid_cmd[256] = { + 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0n */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x4n */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; extern uint32 chan_ctl_time; @@ -180,9 +201,11 @@ switch (op) { /* case on op */ case OP_SIO: /* start I/O */ *dvst = lp_tio_status (); /* get status */ - if ((*dvst & DVS_DST) == 0) { /* idle? */ + if (chan_chk_dvi (dva)) /* int pending? */ + *dvst |= (CC2 << DVT_V_CC); /* SIO fails */ + else if ((*dvst & DVS_DST) == 0) { /* idle? */ lp_cmd = LPS_INIT; /* start dev thread */ - sim_activate (&lp_unit, chan_ctl_time); + sim_activate (&lp_unit, 0); } break; @@ -230,6 +253,10 @@ switch (lp_cmd) { /* case on state */ st = chan_get_cmd (lp_dib.dva, &cmd); /* get command */ if (CHS_IFERR (st)) /* channel error? */ return lp_chan_err (st); + if (lp_valid_cmd[cmd] == 0) { /* bad command? */ + chan_uen (lp_dib.dva); /* uend */ + return SCPE_OK; + } lp_inh = 0; /* clear inhibit, */ lp_run = 0; /* runaway */ lp_cmd = lp_lastcmd = cmd; /* save command */ diff --git a/sigma/sigma_mt.c b/sigma/sigma_mt.c index 96e143828..d6b08c17b 100644 --- a/sigma/sigma_mt.c +++ b/sigma/sigma_mt.c @@ -1,6 +1,6 @@ /* sigma_mt.c: Sigma 732X 9-track magnetic tape - Copyright (c) 2007-2022, Robert M. Supnik + Copyright (c) 2007-2024, 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,13 @@ mt 7320 and 7322/7323 magnetic tape + 17-Feb-24 RMS Zero delay from SIO to INIT state (Ken Rector) + 11-Feb-24 RMS Report non-operational if not attached (Ken Rector) + 01-Feb-24 RMS Fixed nx unit test (Ken Rector) + 01-Nov-23 RMS Fixed reset not to clear BOT + 31-Mar-23 RMS Mask unit flag before calling status in AIO (Ken Rector) + 07-Feb-23 RMS Silenced Mac compiler warnings (Ken Rector) + 15-Dec-22 RMS Moved SIO interrupt test to devices 20-Jul-22 RMS Space record must set EOF flag on tape mark (Ken Rector) 03-Jul-22 RMS Fixed error in handling of channel errors (Ken Rector) 02-Jul-22 RMS Fixed bugs in multi-unit operation @@ -230,15 +237,19 @@ uint32 un = DVA_GETUNIT (dva); UNIT *uptr = &mt_unit[un]; if ((un >= MT_NUMDR) || /* inv unit num? */ - (uptr-> flags & UNIT_DIS)) /* disabled unit? */ - return DVT_NODEV; + (uptr-> flags & UNIT_DIS)) { /* disabled unit? */ + *dvst = DVT_NODEV; + return 0; + } switch (op) { /* case on op */ case OP_SIO: /* start I/O */ *dvst = mt_tio_status (un); /* get status */ - if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + if (chan_chk_dvi (dva)) /* int pending? */ + *dvst |= (CC2 << DVT_V_CC); /* SIO fails */ + else if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ uptr->UCMD = MCM_INIT; /* start dev thread */ - sim_activate (uptr, chan_ctl_time); + sim_activate (uptr, 0); } break; @@ -264,7 +275,8 @@ switch (op) { /* case on op */ case OP_AIO: /* acknowledge int */ un = mt_clr_int (mt_dib.dva); /* clr int, get unit and flag */ - *dvst = (mt_tdv_status (un) & MTAI_MASK) | /* device status */ + *dvst = + (mt_tdv_status (un & DVA_M_DEVMU) & MTAI_MASK) | /* device status */ (un & MTAI_INT) | /* device int flag */ ((un & DVA_M_UNIT) << DVT_V_UN); /* unit number */ break; @@ -476,7 +488,7 @@ switch (cmd) { /* case on command */ sim_activate (uptr, mt_time); /* continue thread */ return SCPE_OK; } - if (r = mt_flush_buf (uptr)) { /* flush buffer */ + if ((r = mt_flush_buf (uptr)) != 0) { /* flush buffer */ st = mt_map_err (uptr, r); /* map error */ if (CHS_IFERR (st)) /* chan or SCP err? */ return mt_chan_err (dva, st); /* uend and stop */ @@ -560,10 +572,12 @@ uint32 mt_tio_status (uint32 un) uint32 i, st; UNIT *uptr = &mt_unit[un]; -st = (uptr->flags & UNIT_ATT)? DVS_AUTO: 0; /* AUTO */ +st = DVS_AUTO; /* flags */ if (sim_is_active (uptr) || /* unit busy */ sim_is_active (uptr + MT_REW)) /* or rewinding? */ st |= DVS_DBUSY; +else if ((uptr -> flags & UNIT_ATT) == 0) /* not att => offl */ + st |= DVS_DOFFL; for (i = 0; i < MT_NUMDR; i++) { /* loop thru units */ if (sim_is_active (&mt_unit[i])) { /* active? */ st |= (DVS_CBUSY | (CC2 << DVT_V_CC)); /* ctrl is busy */ @@ -651,7 +665,9 @@ uint32 i; for (i = 0; i < MT_NUMDR; i++) { sim_cancel (&mt_unit[i]); /* stop unit */ sim_cancel (&mt_unit[i + MT_REW]); /* stop rewind */ - mt_unit[i].UST = 0; + if (mt_unit[i].flags & UNIT_ATT) /* attached? */ + mt_unit[i].UST &= MTDV_BOT; /* clr sta exc BOT */ + else mt_unit[i].UST = 0; mt_unit[i].UCMD = 0; } mt_rwi = 0; @@ -670,7 +686,8 @@ t_stat mt_attach (UNIT *uptr, CONST char *cptr) t_stat r; r = sim_tape_attach (uptr, cptr); -if (r != SCPE_OK) return r; +if (r != SCPE_OK) + return r; uptr->UST = MTDV_BOT; return r; } diff --git a/sigma/sigma_pt.c b/sigma/sigma_pt.c index cbda30522..9771bf52d 100644 --- a/sigma/sigma_pt.c +++ b/sigma/sigma_pt.c @@ -1,6 +1,6 @@ /* sigma_pt.c: Sigma 7060 paper tape reader/punch - Copyright (c) 2007-2018, Robert M. Supnik + Copyright (c) 2007-2024, 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,8 @@ pt 7060 paper-tape reader/punch + 17-Feb-24 RMS Zero delay from SIO to INIT state (Ken Rector) + 15-Dec-2022 RMS Moved SIO interrupt test to devices 02-Jun-2018 RMS Defanged clang signed/unsigned whining (Mark Pizzolato) */ @@ -119,9 +121,11 @@ switch (op) { /* case on op */ case OP_SIO: /* start I/O */ *dvst = pt_tio_status (); /* get status */ - if ((*dvst & DVS_DST) == 0) { /* idle? */ + if (chan_chk_dvi (dva)) /* int pending? */ + *dvst |= (CC2 << DVT_V_CC); /* SIO fails */ + else if ((*dvst & DVS_DST) == 0) { /* idle? */ pt_cmd = PTS_INIT; /* start dev thread */ - sim_activate (&pt_unit[PTR], chan_ctl_time); + sim_activate (&pt_unit[PTR], 0); } break; diff --git a/sigma/sigma_rad.c b/sigma/sigma_rad.c index 845abbdb1..a4b33c2c0 100644 --- a/sigma/sigma_rad.c +++ b/sigma/sigma_rad.c @@ -1,6 +1,6 @@ /* sigma_rad.c: Sigma 7211/7212 or 7231/7232 fixed head disk simulator - Copyright (c) 2007-2022, Robert M Supnik + Copyright (c) 2007-2024, 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,10 @@ rad 7211/7212 or 7231/7232 fixed head disk + 17-Feb-24 RMS Zero delay from SIO to INIT state (Ken Rector) + 01-Feb-24 RMS Fixed nx unit test (Ken Rector) + 22-Apr-23 RMS Fixed write protect test (Ken Rector) + 15-Dec-22 RMS Moved SIO interrupt test to devices 02-Jul-22 RMS Fixed bugs in multi-unit operation The RAD is a head-per-track disk. To minimize overhead, the entire RAD @@ -64,9 +68,9 @@ #define RADA_GETTK(x) (((x) >> rad_tab[rad_model].tk_v) & rad_tab[rad_model].tk_m) #define RADA_GETSC(x) (((x) >> rad_tab[rad_model].sc_v) & rad_tab[rad_model].sc_m) -/* Address bad flag */ +/* Write protect flag */ -#define RADA_INV 0x80 +#define RADA_WP 0x80 /* Status byte 3 is current sector */ /* Status byte 4 (7212 only) is failing sector */ @@ -131,6 +135,7 @@ t_stat rad_showtype (FILE *st, UNIT *uptr, int32 val, CONST void *desc); t_bool rad_inv_ad (uint32 *da); t_bool rad_inc_ad (void); t_bool rad_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st); +t_bool rad_wp_trk (uint32 adr); /* RAD data structures @@ -205,15 +210,19 @@ int32 iu; UNIT *uptr; if ((un >= RAD_NUMDR) || /* inv unit num? */ - (rad_unit[un].flags & UNIT_DIS)) /* disabled unit? */ - return DVT_NODEV; + (rad_unit[un].flags & UNIT_DIS)) { /* disabled unit? */ + *dvst = DVT_NODEV; + return 0; + } switch (op) { /* case on op */ case OP_SIO: /* start I/O */ *dvst = rad_tio_status (un); /* get status */ - if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + if (chan_chk_dvi (dva)) /* int pending? */ + *dvst |= (CC2 << DVT_V_CC); /* SIO fails */ + else if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ rad_cmd = RADS_INIT; /* start dev thread */ - sim_activate (&rad_unit[un], chan_ctl_time); + sim_activate (&rad_unit[un], 0); } break; @@ -261,7 +270,7 @@ return 0; t_stat rad_svc (UNIT *uptr) { -uint32 i, sc, da, cmd, wd, wd1, c[4], gp; +uint32 i, sc, da, cmd, wd, wd1, c[4]; uint32 *fbuf = (uint32 *) uptr->filebuf; uint32 un = uptr - rad_unit; uint32 dva = rad_dib.dva | un; @@ -316,8 +325,10 @@ switch (rad_cmd) { break; case RADS_SENSE: /* sense */ - c[0] = ((rad_ad >> 8) & 0x7F) | (rad_inv_ad (NULL)? RADA_INV: 0); - c[1] = rad_ad & 0xFF; /* address */ + c[0] = (rad_ad >> 8) & 0x7F; /* addr hi */ + if (rad_wp_trk (rad_ad)) /* addr wr prot? */ + c[0] |= RADA_WP; /* set flag */ + c[1] = rad_ad & 0xFF; /* addr lo */ c[2] = GET_PSC (rad_time); /* curr sector */ c[3] = 0; for (i = 0, st = 0; (i < rad_tab[rad_model].nbys) && (st != CHS_ZBC); i++) { @@ -331,9 +342,7 @@ switch (rad_cmd) { break; case RADS_WRITE: /* write */ - gp = (RADA_GETSC (rad_ad) * RAD_N_WLK) / /* write lock group */ - rad_tab[rad_model].tkun; - if ((rad_wlk >> gp) & 1) { /* write lock set? */ + if (rad_wp_trk (rad_ad)) { /* write protected? */ rad_flags |= RADV_WPE; /* set status */ chan_uen (dva); /* uend */ return SCPE_OK; @@ -498,6 +507,17 @@ if (tk >= rad_tab[rad_model].tkun) /* overflow? */ return FALSE; } +/* Test disk addr for protected tracks */ + +t_bool rad_wp_trk (uint32 adr) +{ +uint32 trk = RADA_GETTK (adr); /* track */ +uint32 sw = (trk * RAD_N_WLK) / rad_tab[rad_model].tkun; /* switch num */ + +if ((rad_wlk >> sw) & 1) /* switch set? */ + return TRUE; +return FALSE; +} /* Channel error */ t_stat rad_chan_err (uint32 dva, uint32 st) diff --git a/sigma/sigma_sys.c b/sigma/sigma_sys.c index 69d89775a..4507ced78 100644 --- a/sigma/sigma_sys.c +++ b/sigma/sigma_sys.c @@ -1,6 +1,6 @@ /* sigma_sys.c: Sigma system interface - Copyright (c) 2007-2017, Robert M Supnik + Copyright (c) 2007-2024, 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. + 03-Apr-2024 RMS Added CR, CP support (Ken Rector) 09-Mar-2017 RMS Added LOAD processor for CCT */ @@ -43,6 +44,8 @@ extern DEVICE rad_dev; extern DEVICE dk_dev; extern DEVICE dp_dev[]; extern DEVICE mt_dev; +extern DEVICE cr_dev; +extern DEVICE cp_dev; extern DEVICE mux_dev, muxl_dev; extern REG cpu_reg[]; extern uint32 *M; @@ -93,6 +96,8 @@ DEVICE *sim_devices[] = { &dp_dev[1], &mux_dev, &muxl_dev, + &cr_dev, + &cp_dev, NULL }; @@ -166,6 +171,73 @@ uint8 ebcdic_to_ascii[256] = { '8', '9', 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, }; +uint16 ebcdic_to_hol[256] = { + /* T918 T91 T92 T93 T94 T95 T96 T97 0x0x */ + 0xB03, 0x901, 0x881, 0x841, 0x821, 0x811, 0x809, 0x805, + /* T98, T189 , T289, T389, T489, T589, T689, T789 */ + 0x803, 0x903, 0x883, 0x843, 0x823, 0x813, 0x80B, 0x807, + /* TE189 E91 E92 E93 E94 E95 E96 E97 0x1x */ + 0xD03, 0x501, 0x481, 0x441, 0x421, 0x411, 0x409, 0x405, + /* E98 E918 E928 E938 E948 E958 E968 E978 */ + 0x403, 0x503, 0x483, 0x443, 0x423, 0x413, 0x40B, 0x407, + /* E0918 091 092 093 094 095 096 097 0x2x */ + 0x703, 0x301, 0x281, 0x241, 0x221, 0x211, 0x209, 0x205, + /* 098 0918 0928 0938 0948 0958 0968 0978 */ + 0x203, 0x303, 0x283, 0x243, 0x223, 0x213, 0x20B, 0x207, + /* TE0918 91 92 93 94 95 96 97 0x3x */ + 0xF03, 0x101, 0x081, 0x041, 0x021, 0x011, 0x009, 0x005, + /* 98 189 289 389 489 589 689 789 */ + 0x003, 0x103, 0x083, 0x043, 0x023, 0x013, 0x00B, 0x007, + /* T091 T092 T093 T094 T095 T096 T097 0x4x */ + 0x000, 0xB01, 0xA81, 0xA41, 0xA21, 0xA11, 0xA09, 0xA05, + /* T098 T18 T28 T38 T48 T58 T68 T78 */ + 0xA03, 0x902, 0x882, 0x842, 0x822, 0x812, 0x80A, 0x806, + /* T TE91 TE92 TE93 TE94 TE95 TE96 TE97 0x5x */ + 0x800, 0xD01, 0xC81, 0xC41, 0xC21, 0xC11, 0xC09, 0xC05, + /* TE98 E18 E28 E38 E48 E58 E68 E78 */ + 0xC03, 0x502, 0x482, 0x442, 0x422, 0x412, 0x40A, 0x406, + /* E 01 E092 E093 E094 E095 E096 E097 0x6x */ + 0x400, 0x300, 0x681, 0x641, 0x621, 0x611, 0x609, 0x605, + /* E098 018 TE 038 048 68 068 078 */ + 0x603, 0x302, 0xC00, 0x242, 0x222, 0x212, 0x20A, 0x206, + /* TE0 TE091 TE092 TE093 TE094 TE095 TE096 TE097 0x7x */ + 0xE00, 0xF01, 0xE81, 0xE41, 0xE21, 0xE11, 0xE09, 0xE05, + /* TE098 18 28 38 48 58 68 78 */ + 0xE03, 0x102, 0x082, 0x042, 0x022, 0x012, 0x00A, 0x006, + /* T018 T01 T02 T03 T04 T05 T06 T07 0x8x */ + 0xB02, 0xB00, 0xA80, 0xA40, 0xA20, 0xA10, 0xA08, 0xA04, + /* T08 T09 T028 T038 T048 T058 T068 T078 */ + 0xA02, 0xA01, 0xA82, 0xA42, 0xA22, 0xA12, 0xA0A, 0xA06, + /* TE18 TE1 TE2 TE3 TE4 TE5 TE6 TE7 0x9x */ + 0xD02, 0xD00, 0xC80, 0xC40, 0xC20, 0xC10, 0xC08, 0xC04, + /* TE8 TE9 TE28 TE38 TE48 TE58 TE68 TE78 */ + 0xC02, 0xC01, 0xC82, 0xC42, 0xC22, 0xC12, 0xC0A, 0xC06, + /* E018 E01 E02 E03 E04 E05 E06 E07 0xax */ + 0x702, 0x700, 0x680, 0x640, 0x620, 0x610, 0x608, 0x604, + /* E08 E09 E028 E038 E048 E058 E068 E078 */ + 0x602, 0x601, 0x682, 0x642, 0x622, 0x612, 0x60A, 0x606, + /* TE018 TE01 TE02 TE03 TE04 TE05 TE06 TE07 0xbx */ + 0xF02, 0xF00, 0xE80, 0xE40, 0xE20, 0xE10, 0xE08, 0xE04, + /* TE08 TE09 TE028 TE038 TE048 TE058 TE068 TE078 */ + 0xE02, 0xE01, 0xE82, 0xE42, 0xE22, 0xE12, 0xE0A, 0xE06, + /* T0 T1 T2 T3 T4 T5 T6 T7 0xcx */ + 0xA00, 0x900, 0x880, 0x840, 0x820, 0x810, 0x808, 0x804, + /* T8 T9 T0928 T0938 T0948 T0958 T0968 T0978 */ + 0x802, 0x801, 0xA83, 0xA43, 0xA23, 0xA13, 0xA0B, 0xA07, + /* E0 E1 E2 E3 E4 E5 E6 E7 0xdx */ + 0x600, 0x500, 0x480, 0x440, 0x420, 0x410, 0x408, 0x404, + /* E8 E9 TE928 TE938 TE948 TE958 TE968 TE978 */ + 0x402, 0x401, 0xC83, 0xC43, 0xC23, 0xC13, 0xC0B, 0xC07, + /* 028 E091 02 03 04 05 06 07 0xex */ + 0x282, 0x701, 0x280, 0x240, 0x220, 0x210, 0x208, 0x204, + /* 08 09 E0928 E0938 E0948 E0958 E0968 E0978 */ + 0x202, 0x201, 0x683, 0x643, 0x623, 0x613, 0x60B, 0x607, + /* 0 1 2 3 4 5 6 7 0xfx */ + 0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004, + /* 8 9 TE0928 TE0938 TE0948 TE0958 TE0968 TE0978 */ + 0x002, 0x001, 0xE83, 0xE43, 0xE23, 0xE13, 0xE0B, 0xE07 +}; + /* Binary loader */ t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) diff --git a/sigma/sigma_tt.c b/sigma/sigma_tt.c index 1c357d2ab..99850d7a7 100644 --- a/sigma/sigma_tt.c +++ b/sigma/sigma_tt.c @@ -1,6 +1,6 @@ /* sigma_tt.c: Sigma 7012 console teletype - Copyright (c) 2007-2018, Robert M. Supnik + Copyright (c) 2007-2024, 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"), @@ -31,6 +31,8 @@ ^H input, mapped to EOM and not echoed HT input or output, simulates tabbing with fixed 8 character stops + 18-Feb-2024 RMS Zero delay from SIO to INIT state (Ken Rector) + 15-Dec-2922 RMS Moved SIO int pending test to devices 02-Jun-2018 RMS Defanged clang signed/unsigned whining (Mark Pizzolato) */ @@ -134,9 +136,11 @@ switch (op) { /* case on op */ case OP_SIO: /* start I/O */ *dvst = tt_tio_status (); /* get status */ - if ((*dvst & DVS_DST) == 0) { /* idle? */ + if (chan_chk_dvi (dva)) /* int pending? */ + *dvst |= (CC2 << DVT_V_CC); /* SIO fails */ + else if ((*dvst & DVS_DST) == 0) { /* idle? */ tt_cmd = TTS_INIT; /* start dev thread */ - sim_activate (&tt_unit[TTO], chan_ctl_time); + sim_activate (&tt_unit[TTO], 0); } break; diff --git a/sim_console.c b/sim_console.c index 312a5401b..86cd9e888 100644 --- a/sim_console.c +++ b/sim_console.c @@ -1,6 +1,6 @@ /* sim_console.c: simulator console I/O library - Copyright (c) 1993-2022, Robert M Supnik + Copyright (c) 1993-2024, 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,9 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 27-Mar-24 JDB Display connection port instead of socket for Telnet console + 13-Jun-23 RMS Silenced compiler warnings on system calls (Mark Pizzolato) + 07-Feb-22 RMS Silenced Mac compiler warnings (Ken Rector) 30-Nov-22 RMS Made definitions of sim_os_fd_isatty consistent (Dave Bryan) 27-Sep-22 RMS Removed MacOS "Classic" and OS/2 support Added sim_ttisatty @@ -418,6 +421,8 @@ return tmxr_close_master (&sim_con_tmxr); /* close master socket * t_stat sim_show_telnet (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, char *cptr) { +char *sockname, *peername, *portnum; + if (cptr && (*cptr != 0)) return SCPE_2MARG; if (sim_con_tmxr.master == 0) @@ -425,10 +430,23 @@ if (sim_con_tmxr.master == 0) else if (sim_con_ldsc.conn == 0) fprintf (st, "Listening on port %d\n", sim_con_tmxr.port); else { - fprintf (st, "Listening on port %d, connected to socket %d\n", - sim_con_tmxr.port, sim_con_ldsc.conn); - tmxr_fconns (st, &sim_con_ldsc, -1); - tmxr_fstats (st, &sim_con_ldsc, -1); + sim_getnames_sock (sim_con_ldsc.conn, &sockname, &peername); /* get the port names */ + + portnum = strchr (peername, (int) ']'); /* find the end of the host address */ + + if (portnum == NULL) /* if it is not there */ + portnum = peername; /* then use the entire connection port name */ + else /* otherwise */ + portnum = portnum + 2; /* use just the port number */ + + fprintf (st, "Listening on port %d, connected to port %s\n", + sim_con_tmxr.port, portnum); + + free (sockname); /* free the strings */ + free (peername); /* allocated for the names */ + + tmxr_fconns (st, &sim_con_ldsc, -1); /* report the connection time */ + tmxr_fstats (st, &sim_con_ldsc, -1); /* and I/O statistics */ } return SCPE_OK; } @@ -476,10 +494,10 @@ int32 c; c = sim_os_poll_kbd (); /* get character */ if ((c == SCPE_STOP) || (sim_con_tmxr.master == 0)) /* ^E or not Telnet? */ return c; /* in-window */ -if (sim_con_ldsc.conn == 0) /* no Telnet conn? */ +if (sim_con_ldsc.conn == 0) /* no Telnet conn? */ return SCPE_LOST; tmxr_poll_rx (&sim_con_tmxr); /* poll for input */ -if (c = tmxr_getc_ln (&sim_con_ldsc)) /* any char? */ +if ((c = tmxr_getc_ln (&sim_con_ldsc)) != 0) /* any char? */ return (c & (SCPE_BREAK | 0377)) | SCPE_KFLAG; return SCPE_OK; } @@ -769,11 +787,11 @@ static HANDLE std_input; static HANDLE std_output; static DWORD saved_mode; -/* Note: This routine catches all the potential events which some aspect - of the windows system can generate. The CTRL_C_EVENT won't be - generated by a user typing in a console session since that +/* Note: This routine catches all the potential events which some aspect + of the windows system can generate. The CTRL_C_EVENT won't be + generated by a user typing in a console session since that session is in RAW mode. In general, Ctrl-C on a simulator's - console terminal is a useful character to be passed to the + console terminal is a useful character to be passed to the simulator. This code does nothing to disable or affect that. */ static BOOL WINAPI @@ -784,7 +802,7 @@ ControlHandler(DWORD dwCtrlType) switch (dwCtrlType) { - case CTRL_BREAK_EVENT: // Use CTRL-Break or CTRL-C to simulate + case CTRL_BREAK_EVENT: // Use CTRL-Break or CTRL-C to simulate case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode int_handler(0); return TRUE; @@ -811,7 +829,7 @@ if ((std_input == INVALID_HANDLE_VALUE) || return SCPE_TTYERR; return SCPE_OK; } - + t_stat sim_ttrun (void) { if (!GetConsoleMode(std_input, &saved_mode) || @@ -941,13 +959,13 @@ if (ioctl (0, TIOCSETC, &runtchars) < 0) return SCPE_TTIERR; if (ioctl (0, TIOCSLTC, &runltchars) < 0) return SCPE_TTIERR; -nice (10); /* lower priority */ +(void) nice (10); /* lower priority */ return SCPE_OK; } t_stat sim_ttcmd (void) { -nice (-10); /* restore priority */ +(void) nice (-10); /* restore priority */ fcntl (0, F_SETFL, cmdfl); /* block mode */ if (ioctl (0, TIOCSETP, &cmdtty) < 0) return SCPE_TTIERR; @@ -985,7 +1003,7 @@ t_stat sim_os_putchar (int32 out) char c; c = out; -write (1, &c, 1); +(void) write (1, &c, 1); return SCPE_OK; } @@ -1050,7 +1068,7 @@ if (tcsetattr (0, TCSAFLUSH, &runtty) < 0) return SCPE_TTIERR; if (prior_norm) { /* at normal pri? */ errno = 0; - nice (10); /* try to lower pri */ + (void) nice (10); /* try to lower pri */ prior_norm = errno; /* if no error, done */ } return SCPE_OK; @@ -1062,7 +1080,7 @@ if (!isatty (fileno (stdin))) /* skip if !tty */ return SCPE_OK; if (!prior_norm) { /* priority down? */ errno = 0; - nice (-10); /* try to raise pri */ + (void) nice (-10); /* try to raise pri */ prior_norm = (errno == 0); /* if no error, done */ } if (tcsetattr (0, TCSAFLUSH, &cmdtty) < 0) @@ -1097,7 +1115,7 @@ t_stat sim_os_putchar (int32 out) char c; c = out; -write (1, &c, 1); +(void) write (1, &c, 1); return SCPE_OK; } diff --git a/sim_defs.h b/sim_defs.h index e97064b75..569e2d545 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -1,6 +1,6 @@ /* sim_defs.h: simulator definitions - Copyright (c) 1993-2022, Robert M Supnik + Copyright (c) 1993-2024, 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. + 05-May-22 RMS Added UNIT_V4XTND 06-Jun-22 RMS Deprecated UNIT_TEXT, deleted UNIT_RAW 10-Mar-22 JDB Modified REG macros to fix "stringizing" problem 12-Nov-21 JDB Added UNIT_EXTEND dynamic flag @@ -417,6 +418,7 @@ struct sim_unit { #define UNIT_ROABLE 001000 /* read only ok */ #define UNIT_DISABLE 002000 /* disable-able */ #define UNIT_DIS 004000 /* disabled */ +#define UNIT_V4XTND 010000 /* enabe V4 extensions */ #define UNIT_IDLE 040000 /* idle eligible */ /* Deleted or deprecated */ diff --git a/sim_rev.h b/sim_rev.h index 83637a2be..e45088fd2 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -1,6 +1,6 @@ /* sim_rev.h: simulator revisions and current rev level - Copyright (c) 1993-2021, Robert M Supnik + Copyright (c) 1993-2023, 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"), @@ -29,7 +29,7 @@ #define SIM_MAJOR 3 #define SIM_MINOR 12 -#define SIM_PATCH 3 +#define SIM_PATCH 5 #define SIM_DELTA 0 /* V3.12 revision history @@ -39,6 +39,12 @@ patch date module(s) and fix(es) + 5 16-July-2024 H316, Nova, PDP8, Sigma, SDS: bug fixes + PDP10, PDP11: bug fixes, Chaosnet support + + 4 28-May-2023 PDP8, PDP11, Sigma, SDS: bug fixes + SCP and libraries: silenced Mac compiler warnings + 3 12-Dec-2022 Mac "Classic" and OS/2 support has been removed PDP11: numerous 11/70 compatibility fixes Sigma: numerous bug fixes diff --git a/sim_sock.c b/sim_sock.c index f528bafe4..830a4b9c0 100644 --- a/sim_sock.c +++ b/sim_sock.c @@ -1,6 +1,6 @@ /* sim_sock.c: OS-dependent socket routines - Copyright (c) 2001-2010, Robert M Supnik + Copyright (c) 2001-2024, 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. + 23-Jan-24 RMS Cleaned up SD_BOTH guard for FreeBSD 15 (from Dave Bryan) 15-Oct-12 MP Added definitions needed to detect possible tcp connect failures 25-Sep-12 MP Reworked for RFC3493 interfaces supporting IPv6 and IPv4 @@ -63,7 +64,7 @@ extern "C" { #define WSAAPI #endif -#if defined(SHUT_RDWR) && !defined(SD_BOTH) +#if !defined(SD_BOTH) #define SD_BOTH SHUT_RDWR #endif diff --git a/sim_tape.c b/sim_tape.c index f6a241145..75a1d160d 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -1,6 +1,6 @@ /* sim_tape.c: simulator tape support library - Copyright (c) 1993-2021, Robert M Supnik + Copyright (c) 1993-2023, 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"), @@ -26,6 +26,7 @@ Ultimately, this will be a place to hide processing of various tape formats, as well as OS-specific direct hardware access. + 07-Feb-23 RMS Silenced Mac compiler warnings (Ken Rector) 15-Dec-21 JDB Added extended SIMH format support 10-Oct-21 JDB Improved tape_erase_fwd corrupt image error checking 06-Oct-21 JDB Added sim_tape_erase global, tape_erase internal functions @@ -505,8 +506,8 @@ else switch (f) { /* otherwise the read me if (sizeof_gap > 0 /* if gap detection is enabled */ && (runaway_counter <= 0 /* and a tape runaway occurred */ - || status == MTSE_EOM /* or EOM/EOF was seen */ - && runaway_counter < max_gap)) /* while a gap was being skipped */ + || (status == MTSE_EOM /* or EOM/EOF was seen */ + && runaway_counter < max_gap))) /* while a gap was being skipped */ status = MTSE_RUNAWAY; /* then report it */ break; /* end of case */ @@ -2224,7 +2225,7 @@ if (uptr == NULL) /* if the unit p else if (desc == NULL) /* otherwise if a validation set was not supplied */ if (val > 0 && val < (int32) BPI_COUNT) /* then if a valid density code was supplied */ - uptr->dynflags = uptr->dynflags & ~MTVF_DENS_MASK /* then insert the code */ + uptr->dynflags = (uptr->dynflags & ~MTVF_DENS_MASK) /* then insert the code */ | val << UNIT_V_DF_TAPE; /* in the unit flags */ else /* otherwise the code is invalid */ return SCPE_ARG; /* so report a bad argument */ @@ -2241,7 +2242,7 @@ else { /* otherwise a v else for (density = 0; density < BPI_COUNT; density++) /* otherwise validate the density */ if (new_bpi == bpi [density] /* if it matches a value in the list */ && ((1 << density) & *(int32 *) desc)) { /* and it's an allowed value */ - uptr->dynflags = uptr->dynflags & ~MTVF_DENS_MASK /* then store the index of the value */ + uptr->dynflags = (uptr->dynflags & ~MTVF_DENS_MASK) /* then store the index of the value */ | density << UNIT_V_DF_TAPE; /* in the unit flags */ return SCPE_OK; /* and return success */ } diff --git a/sim_tmxr.c b/sim_tmxr.c index f2d50db5d..0640ff193 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -1,6 +1,6 @@ /* sim_tmxr.c: Telnet terminal multiplexor library - Copyright (c) 2001-2021, Robert M Supnik + Copyright (c) 2001-2024, 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"), @@ -26,6 +26,9 @@ Based on the original DZ11 simulator by Thord Nilson, as updated by Arthur Krewat. + 19-Apr-24 RMS Merged CH11 changes (Lars Brinkhoff) + 27-Mar-24 JDB Dropped socket report from "tmxr_open_master" + 07-Feb-23 RMS Silenced Mac compiler warnings (Ken Rector) 31-Jan-21 JDB Added a cast in "tmxr_set_lnorder" from t_addr to uint32 26-Oct-20 JDB Line order now supports partial connection lists 23-Oct-20 JDB Added tmxr_table and tmxr_post_logs @@ -70,12 +73,15 @@ tmxr_poll_conn - poll for connection tmxr_reset_ln - reset line tmxr_getc_ln - get character for line + tmxr_get_packet_ln - get packet for line tmxr_poll_rx - poll receive tmxr_putc_ln - put character for line + tmxr_put packet_ln - put packet for line tmxr_poll_tx - poll transmit tmxr_set_modem_control_passthru - enable modem control on a multiplexer tmxr_set_get_modem_bits - set and/or get a line modem bits tmxr_open_master - open master connection + tmxr_open_master_xtnd - open master connection, extended options tmxr_close_master - close master connection tmxr_attach - attach terminal multiplexor tmxr_detach - detach terminal multiplexor @@ -382,6 +388,35 @@ if (lp->rxbpi == lp->rxbpr) /* empty? zero ptrs */ return val; } +/* Get UDP packet from line + + Inputs: + *lp = pointer to line descriptor + Outputs: + **pbuf = pointer to pointer to packet data + *psiz = pointer to size of packet + status = ok, or connection lost +*/ + +t_stat tmxr_get_packet_ln (TMLN *lp, const uint8 **pbuf, size_t *psize) +{ +int32 c; +static uint8 buf[TMXR_MAXBUF]; +int32 i = 0; + +*pbuf = NULL; +*psize = 0; +if (!lp->conn) + return SCPE_LOST; +while (TMXR_VALID & (c = tmxr_getc_ln (lp))) + buf[i++] = c; +if (i > 0) { + *pbuf = buf; + *psize = i; + } +return SCPE_OK; /* char sent */ +} + /* Poll for input Inputs: @@ -587,6 +622,29 @@ lp->xmte = 0; /* no room, dsbl line */ return SCPE_STALL; /* char not sent */ } +/* Store UDP packet in line buffer + + Inputs: + *lp = pointer to line descriptor + Outputs: + *buf = pointer to packet data + *size = size of packet + status = ok, or connection lost +*/ + +t_stat tmxr_put_packet_ln (TMLN *lp, const uint8 *buf, size_t size) +{ +size_t i; + +if (!lp->conn) + return SCPE_LOST; +for (i = 0; i < size; i++) + tmxr_putc_ln (lp, buf[i]); +tmxr_send_buffered_data (lp); +lp->txbpr = lp->txbpi = lp->txcnt = 0; /* clear the transmit indexes */ +return SCPE_OK; +} + /* Poll for output Inputs: @@ -673,7 +731,7 @@ if ((r != SCPE_OK) || (port == 0)) sock = sim_master_sock (cptr, &r); /* make master socket */ if (sock == INVALID_SOCKET) /* open error */ return SCPE_OPENERR; -sim_printf ("Listening on port %d (socket %d)\n", port, sock); +sim_printf ("Listening on port %d\n", port); mp->port = port; /* save port */ mp->master = sock; /* save master socket */ for (i = 0; i < mp->lines; i++) { /* initialize lines */ @@ -688,6 +746,76 @@ for (i = 0; i < mp->lines; i++) { /* initialize lines */ return SCPE_OK; } +/* Open master socket, extented options */ + +t_stat tmxr_open_master_xtnd (TMXR *mp, char *cptr) +{ +int32 i, port, line = -1; +SOCKET sock; +TMLN *lp; +t_stat r; +int flags = 0; +char *comma, *param, str[10]; +char *peer = NULL; + +do { + comma = strchr (cptr, ','); + if (comma) + *comma = 0; + if (isdigit(*cptr)) { + port = (int32) get_uint (cptr, 10, 65535, &r); /* get port */ + if ((r != SCPE_OK) || (port == 0)) + return SCPE_ARG; + } else { + param = strchr (cptr, '='); + if (param) + *param++ = 0; + if (strcasecmp (cptr, "buffer") == 0) { + ; + } else if (strcasecmp (cptr, "line") == 0) { + if (param == NULL) + return SCPE_ARG; + line = (int32) get_uint (param, 10, mp->lines-1, &r); + if (r) + return SCPE_ARG; + } else if (strcasecmp (cptr, "udp") == 0) { + flags |= SIM_SOCK_OPT_DATAGRAM; + flags |= SIM_SOCK_OPT_NODELAY; + } else if (strcasecmp (cptr, "connect") == 0) { + peer = param; + } + } + if (comma) + cptr = comma + 1; +} while (comma != NULL); +if (sim_switches & SWMASK ('U')) + flags |= SIM_SOCK_OPT_REUSEADDR; +snprintf(str, sizeof str, "%d", port); +if (flags & SIM_SOCK_OPT_DATAGRAM) + sock = sim_connect_sock_ex (str, peer, "localhost", NULL, flags); +else + sock = sim_master_sock_ex (str, &r, flags); /* make master socket */ +if (sock == INVALID_SOCKET) /* open error */ + return SCPE_OPENERR; +sim_printf("Listening on port %d\n", port); +mp->port = port; /* save port */ +if ((flags & SIM_SOCK_OPT_DATAGRAM) == 0) + mp->master = sock; /* save master socket */ +for (i = 0; i < mp->lines; i++) { /* initialize lines */ + lp = mp->ldsc + i; + + if (tmxr_is_extended == NULL /* if the line */ + || tmxr_is_extended (lp) == FALSE) { /* is not extended */ + tmxr_init_line (lp); /* then initialize the line */ + if ((flags & SIM_SOCK_OPT_DATAGRAM) && i == line) + lp->conn = sock; + else + lp->conn = 0; /* and clear the connection */ + } + } +return SCPE_OK; +} + /* Attach unit to master socket */ t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr) @@ -698,13 +826,16 @@ t_stat r; tptr = (char *) malloc (strlen (cptr) + 1); /* get string buf */ if (tptr == NULL) /* no more mem? */ return SCPE_MEM; -r = tmxr_open_master (mp, cptr); /* open master socket */ +strcpy (tptr, cptr); /* copy port */ +uptr->filename = tptr; /* save */ +if ((uptr->flags & UNIT_V4XTND) != 0) /* unit support xtnd? */ + r = tmxr_open_master_xtnd (mp, cptr); +else r = tmxr_open_master (mp, cptr); /* open master socket */ if (r != SCPE_OK) { /* error? */ free (tptr); /* release buf */ + uptr->filename = NULL; /* clear pointer */ return SCPE_OPENERR; } -strcpy (tptr, cptr); /* copy port */ -uptr->filename = tptr; /* save */ uptr->flags = uptr->flags | UNIT_ATT; /* no more errors */ if (mp->dptr == NULL) /* has device been set? */ @@ -967,12 +1098,13 @@ for (index = 0; index < TABLE_COUNT; index++) /* look through the desc line_count = mptr->lines; /* and the number of lines */ for (line = 0; line < line_count; line++, lptr++) /* for all lines in the array */ - if (lptr->txlog != NULL) /* if the current line's log is active */ + if (lptr->txlog != NULL) { /* if the current line's log is active */ if (close_logs) /* then if closing is requested */ tmxr_set_nolog (NULL, line, NULL, /* then close the log */ (void *) mptr); else /* otherwise */ fflush (lptr->txlog); /* flush the log and leave it open */ + } } return; @@ -1110,7 +1242,7 @@ idx = 0; /* initialize the index while (*cptr != '\0') { /* while characters remain in the command string */ if (strncmp (cptr, "ALL;", 4) == 0) { /* if the parameter is "ALL" */ - if (val != 0 || idx > 0 && idx <= max) /* then if some lines are restrictied or unspecified */ + if (val != 0 || (idx > 0 && idx <= max)) /* then if some lines are restrictied or unspecified */ for (line = (uint32) min; line <= max; line++) /* then fill them in sequentially */ if (set [line] == FALSE) /* setting each unspecified line */ list [idx++] = line; /* into the line order */ diff --git a/sim_tmxr.h b/sim_tmxr.h index b3956edb3..470205517 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -1,6 +1,6 @@ /* sim_tmxr.h: terminal multiplexor definitions - Copyright (c) 2001-2020, Robert M Supnik + Copyright (c) 2001-2024, 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"), @@ -26,6 +26,9 @@ Based on the original DZ11 simulator by Thord Nilson, as updated by Arthur Krewat. + 19-Apr-24 RMS Merged changes for CH11 (Lars Brinkhoff) + 04-Apr-24 JDB Added "sim_con_tmxr" and "sim_con_ldsc" global declarations + 12-Aug-23 JDB Added extension pointer to TMXR structure 23-Oct-20 JDB Added tmxr_post_logs global routine 19-Dec-19 JDB Added tmxr_is_extended global hook 19-Mar-19 JDB Added extension pointer to TMLN structure; @@ -55,7 +58,7 @@ #define TMXR_V_VALID 15 #define TMXR_VALID (1 << TMXR_V_VALID) -#define TMXR_MAXBUF 256 /* buffer size */ +#define TMXR_MAXBUF 512 /* buffer size */ #define TMXR_GUARD 12 /* buffer guard */ /* Modem Control Bits */ @@ -100,6 +103,7 @@ struct tmxr { TMLN *ldsc; /* line descriptors */ int32 *lnorder; /* line connection order */ DEVICE *dptr; /* multiplexer device */ + void *exptr; /* extension pointer */ }; typedef struct tmxr TMXR; @@ -107,10 +111,13 @@ typedef struct tmxr TMXR; int32 tmxr_poll_conn (TMXR *mp); void tmxr_reset_ln (TMLN *lp); int32 tmxr_getc_ln (TMLN *lp); +t_stat tmxr_get_packet_ln (TMLN *lp, const uint8 **pbuf, size_t *psize); void tmxr_poll_rx (TMXR *mp); t_stat tmxr_putc_ln (TMLN *lp, int32 chr); +t_stat tmxr_put_packet_ln (TMLN *lp, const uint8 *buf, size_t size); void tmxr_poll_tx (TMXR *mp); t_stat tmxr_open_master (TMXR *mp, char *cptr); +t_stat tmxr_open_master_xtnd (TMXR *mp, char *cptr); t_stat tmxr_close_master (TMXR *mp); t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr); t_stat tmxr_detach (TMXR *mp, UNIT *uptr); @@ -148,9 +155,13 @@ extern void (*tmxr_show) (TMLN *lp, FILE *stream); extern void (*tmxr_close) (TMLN *lp); extern t_bool (*tmxr_is_extended) (TMLN *lp); +/* Console Telnet support structures */ + +extern TMXR sim_con_tmxr; /* console multiplexer descriptor */ +extern TMLN sim_con_ldsc; /* console line descriptor */ + /* V4.X shims */ #define tmxr_set_console_units(rxuptr, txuptr) #endif -