diff --git a/altair_sys.c b/altair_sys.c index 04788be1..cfba428b 100644 --- a/altair_sys.c +++ b/altair_sys.c @@ -30,7 +30,6 @@ extern unsigned int32 get_uint (char *cptr, int32 radix, unsigned int32 max, sim_PC pointer to saved PC register descriptor sim_emax number of words needed for examine sim_devices array of pointers to simulated devices - sim_consoles array of pointers to consoles (if more than one) sim_stop_messages array of pointers to stop messages sim_load binary loader */ @@ -44,8 +43,6 @@ int32 sim_emax = 4; DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptr_dev, &ptp_dev, &dsk_dev, NULL }; -UNIT *sim_consoles = NULL; - const char *sim_stop_messages[] = { "Unknown error", "Unknown I/O Instruction", diff --git a/dec_dz.h b/dec_dz.h new file mode 100644 index 00000000..c6875548 --- /dev/null +++ b/dec_dz.h @@ -0,0 +1,438 @@ +/* dec_dz.c: DZ11 terminal multiplexor simulator + + Copyright (c) 2001, 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"), + 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. + + Based on the original DZ11 simulator by Thord Nilson, as updated by + Arthur Krewat. + + dz DZ11 terminal multiplexor + + 20-Oct-01 RMS Moved getchar from sim_tmxr, changed interrupt + logic to use tmxr_rqln + 06-Oct-01 RMS Fixed bug in carrier detect logic + 03-Oct-01 RMS Added support for BSD-style "ringless" modems + 27-Sep-01 RMS Fixed bug in xmte initialization + 17-Sep-01 RMS Added separate autodisconnect switch + 16-Sep-01 RMS Fixed modem control bit offsets + + This file is intended to be included in a shell routine that invokes + a simulator definition file: + + pdp11_dz.c = pdp11_defs.h + dec_dz.h + pdp10_dz.c = pdp10_defs.h + dec_dz.h + vax_dz.c = vax_defs.h + dec_dz.h +*/ + +#include "sim_sock.h" +#include "sim_tmxr.h" + +#define DZ_LNOMASK (DZ_LINES - 1) /* mask for lineno */ +#define DZ_LMASK ((1 << DZ_LINES) - 1) /* mask of lines */ +#define DZ_SILO_ALM 16 /* silo alarm level */ + +/* DZCSR - 160100 - control/status register */ + +#define CSR_MAINT 0000010 /* maint - NI */ +#define CSR_CLR 0000020 /* clear */ +#define CSR_MSE 0000040 /* master scan enb */ +#define CSR_RIE 0000100 /* rcv int enb */ +#define CSR_RDONE 0000200 /* rcv done - RO */ +#define CSR_V_TLINE 8 /* xmit line - RO */ +#define CSR_TLINE (DZ_LNOMASK << CSR_V_TLINE) +#define CSR_SAE 0010000 /* silo alm enb */ +#define CSR_SA 0020000 /* silo alm - RO */ +#define CSR_TIE 0040000 /* xmit int enb */ +#define CSR_TRDY 0100000 /* xmit rdy - RO */ +#define CSR_RW (CSR_MSE | CSR_RIE | CSR_SAE | CSR_TIE) +#define CSR_MBZ (0004003 | CSR_CLR | CSR_MAINT) + +#define CSR_GETTL(x) (((x) >> CSR_V_TLINE) & DZ_LNOMASK) +#define CSR_PUTTL(x,y) x = ((x) & ~CSR_TLINE) | (((y) & DZ_LNOMASK) << CSR_V_TLINE) + +/* DZRBUF - 160102 - receive buffer, read only */ + +#define RBUF_CHAR 0000377 /* rcv char */ +#define RBUF_V_RLINE 8 /* rcv line */ +#define RBUF_PARE 0010000 /* parity err - NI */ +#define RBUF_FRME 0020000 /* frame err - NI */ +#define RBUF_OVRE 0040000 /* overrun err - NI */ +#define RBUF_VALID 0100000 /* rcv valid */ +#define RBUF_MBZ 0004000 + +/* DZLPR - 160102 - line parameter register, write only, word access only */ + +#define LPR_V_LINE 0 /* line */ +#define LPR_LPAR 0007770 /* line pars - NI */ +#define LPR_RCVE 0010000 /* receive enb */ +#define LPR_GETLN(x) (((x) >> LPR_V_LINE) & DZ_LNOMASK) + +/* DZTCR - 160104 - transmission control register */ + +#define TCR_V_XMTE 0 /* xmit enables */ +#define TCR_V_DTR 8 /* DTRs */ + +/* DZMSR - 160106 - modem status register, read only */ + +#define MSR_V_RI 0 /* ring indicators */ +#define MSR_V_CD 8 /* carrier detect */ + +/* DZTDR - 160106 - transmit data, write only */ + +#define TDR_CHAR 0000377 /* xmit char */ +#define TDR_V_TBR 8 /* xmit break - NI */ + +extern int32 IREQ (HLVL); +extern int32 sim_switches; +extern FILE *sim_log; +extern int32 tmxr_poll; /* calibrated delay */ +int32 dz_csr = 0; /* csr */ +int32 dz_rbuf = 0; /* rcv buffer */ +int32 dz_lpr = 0; /* line param */ +int32 dz_tcr = 0; /* xmit control */ +int32 dz_msr = 0; /* modem status */ +int32 dz_tdr = 0; /* xmit data */ +int32 dz_mctl = 0; /* modem ctrl enabled */ +int32 dz_auto = 0; /* autodiscon enabled */ +int32 dz_sa_enb = 1; /* silo alarm enabled */ +int32 dz_enb = 1; /* device enable */ +TMLN dz_ldsc[DZ_LINES] = { /* line descriptors */ + { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 } }; +TMXR dz_desc = { /* mux descriptor */ + DZ_LINES, 0, + &dz_ldsc[0], &dz_ldsc[1], &dz_ldsc[2], &dz_ldsc[3], + &dz_ldsc[4], &dz_ldsc[5], &dz_ldsc[6], &dz_ldsc[7] }; + +t_stat dz_svc (UNIT *uptr); +t_stat dz_reset (DEVICE *dptr); +t_stat dz_attach (UNIT *uptr, char *cptr); +t_stat dz_detach (UNIT *uptr); +t_stat dz_clear (t_bool flag); +int32 dz_getchar (TMXR *mp); +void dz_update_rcvi (void); +void dz_update_xmti (void); +t_stat dz_status (UNIT *uptr, FILE *st); + +/* DZ data structures + + dz_dev DZ device descriptor + dz_unit DZ unit list + dz_reg DZ register list +*/ + +UNIT dz_unit = { UDATA (&dz_svc, UNIT_ATTABLE, 0) }; + +REG dz_reg[] = { + { ORDATA (CSR, dz_csr, 16) }, + { ORDATA (RBUF, dz_rbuf, 16) }, + { ORDATA (LPR, dz_lpr, 16) }, + { ORDATA (TCR, dz_tcr, 16) }, + { ORDATA (MSR, dz_msr, 16) }, + { ORDATA (TDR, dz_tdr, 16) }, + { FLDATA (SAENB, dz_sa_enb, 0) }, + { FLDATA (MDMCTL, dz_mctl, 0) }, + { FLDATA (AUTODS, dz_auto, 0) }, + { DRDATA (RPOS0, dz_ldsc[0].rxcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (TPOS0, dz_ldsc[0].txcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (RPOS1, dz_ldsc[1].rxcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (TPOS1, dz_ldsc[1].txcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (RPOS2, dz_ldsc[2].rxcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (TPOS2, dz_ldsc[2].txcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (RPOS3, dz_ldsc[3].rxcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (TPOS3, dz_ldsc[3].txcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (RPOS4, dz_ldsc[4].rxcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (TPOS4, dz_ldsc[4].txcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (RPOS5, dz_ldsc[5].rxcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (TPOS5, dz_ldsc[5].txcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (RPOS6, dz_ldsc[6].rxcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (TPOS6, dz_ldsc[6].txcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (RPOS7, dz_ldsc[7].rxcnt, 32), PV_LEFT+REG_RO }, + { DRDATA (TPOS7, dz_ldsc[7].txcnt, 32), PV_LEFT+REG_RO }, + { FLDATA (*DEVENB, dz_enb, 0) }, + { NULL } }; + +MTAB dz_mod[] = { + { UNIT_ATT, UNIT_ATT, "line status:", NULL, &dz_status }, + { 0 } }; + +DEVICE dz_dev = { + "DZ", &dz_unit, dz_reg, dz_mod, + 1, 8, 13, 1, 8, 8, + &tmxr_ex, &tmxr_dep, &dz_reset, + NULL, &dz_attach, &dz_detach }; + +/* IO dispatch routines, I/O addresses 17760100 - 17760107 */ + +t_stat dz_rd (int32 *data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 03) { /* case on PA<2:1> */ +case 00: /* CSR */ + *data = dz_csr = dz_csr & ~CSR_MBZ; + break; +case 01: /* RBUF */ + dz_csr = dz_csr & ~CSR_SA; /* clr silo alarm */ + if (dz_csr & CSR_MSE) { /* scanner on? */ + dz_rbuf = dz_getchar (&dz_desc); /* get top of silo */ + if (!dz_rbuf) dz_sa_enb = 1; /* empty? re-enable */ + tmxr_poll_rx (&dz_desc); /* poll input */ + dz_update_rcvi (); } /* update rx intr */ + else { dz_rbuf = 0; /* no data */ + dz_update_rcvi (); } /* no rx intr */ + *data = dz_rbuf; + break; +case 02: /* TCR */ + *data = dz_tcr; + break; +case 03: /* MSR */ + *data = dz_msr; + break; } +return SCPE_OK; +} + +t_stat dz_wr (int32 data, int32 PA, int32 access) +{ +int32 i, line; +TMLN *lp; + +switch ((PA >> 1) & 03) { /* case on PA<2:1> */ +case 00: /* CSR */ + if (access == WRITEB) data = (PA & 1)? + (dz_csr & 0377) | (data << 8): (dz_csr & ~0377) | data; + if (data & CSR_CLR) dz_clear (FALSE); + if (data & CSR_MSE) sim_activate (&dz_unit, tmxr_poll); + else { sim_cancel (&dz_unit); + dz_csr = dz_csr & ~(CSR_SA | CSR_RDONE | CSR_TRDY); } + if ((data & CSR_RIE) == 0) CLR_INT (DZRX); + else if (((dz_csr & CSR_IE) == 0) && /* RIE 0->1? */ + ((dz_csr & CSR_SAE)? (dz_csr & CSR_SA): (dz_csr & CSR_RDONE))) + SET_INT (DZRX); + if ((data & CSR_TIE) == 0) CLR_INT (DZTX); + else if (((dz_csr & CSR_TIE) == 0) && (dz_csr & CSR_TRDY)) + SET_INT (DZTX); + dz_csr = (dz_csr & ~CSR_RW) | (data & CSR_RW); + break; +case 01: /* LPR */ + dz_lpr = data; + line = LPR_GETLN (dz_lpr); /* get line */ + lp = dz_desc.ldsc[line]; /* get line desc */ + if (dz_lpr & LPR_RCVE) lp -> rcve = 1; /* rcv enb? on */ + else lp -> rcve = 0; /* else line off */ + tmxr_poll_rx (&dz_desc); /* poll input */ + dz_update_rcvi (); /* update rx intr */ + break; +case 02: /* TCR */ + if (access == WRITEB) data = (PA & 1)? + (dz_tcr & 0377) | (data << 8): (dz_tcr & ~0377) | data; + if (dz_mctl) { /* modem ctl? */ + dz_msr = dz_msr | ((data & 0177400) & /* dcd |= dtr & ring */ + ((dz_msr & DZ_LMASK) << MSR_V_CD)); + dz_msr = dz_msr & ~(data >> TCR_V_DTR); /* ring = ring & ~dtr */ + if (dz_auto) { /* auto disconnect? */ + int32 drop; + drop = (dz_tcr & ~data) >> TCR_V_DTR; /* drop = dtr & ~data */ + for (i = 0; i < DZ_LINES; i++) { /* drop hangups */ + lp = dz_desc.ldsc[i]; /* get line desc */ + if (lp -> conn && (drop & (1 << i))) { + tmxr_msg (lp -> conn, "\r\nLine hangup\r\n"); + tmxr_reset_ln (lp); /* reset line, cdet */ + dz_msr = dz_msr & ~(1 << (i + MSR_V_CD)); + } /* end if drop */ + } /* end for */ + } /* end if auto */ + } /* end if modem */ + dz_tcr = data; + tmxr_poll_tx (&dz_desc); /* poll output */ + dz_update_xmti (); /* update int */ + break; +case 03: /* TDR */ + if (PA & 1) { /* odd byte? */ + dz_tdr = (dz_tdr & 0377) | (data << 8); /* just save */ + break; } + dz_tdr = data; + if (dz_csr & CSR_MSE) { /* enabled? */ + line = CSR_GETTL (dz_csr); /* get xmit line */ + lp = dz_desc.ldsc[line]; /* get line desc */ + tmxr_putc_ln (lp, dz_tdr & 0177); /* store char */ + tmxr_poll_tx (&dz_desc); /* poll output */ + dz_update_xmti (); } /* update int */ + break; } +return SCPE_OK; +} + +/* Unit service routine + + The DZ11 polls to see if asynchronous activity has occurred and now + needs to be processed. The polling interval is controlled by the clock + simulator, so for most environments, it is calibrated to real time. + Typical polling intervals are 50-60 times per second. +*/ + +t_stat dz_svc (UNIT *uptr) +{ +int32 newln; + +if (dz_csr & CSR_MSE) { /* enabled? */ + newln = tmxr_poll_conn (&dz_desc, uptr); /* poll connect */ + if ((newln >= 0) && dz_mctl) { /* got a live one? */ + if (dz_tcr & (1 << (newln + TCR_V_DTR))) /* DTR set? */ + dz_msr = dz_msr | (1 << (newln + MSR_V_CD)); + else dz_msr = dz_msr | (1 << newln); } /* set ring */ + tmxr_poll_rx (&dz_desc); /* poll input */ + dz_update_rcvi (); /* upd rcv intr */ + tmxr_poll_tx (&dz_desc); /* poll output */ + dz_update_xmti (); /* upd xmt intr */ + sim_activate (uptr, tmxr_poll); } /* reactivate */ +return SCPE_OK; +} + +/* Get first available character, if any */ + +int32 dz_getchar (TMXR *mp) +{ +int32 i, val; + +for (i = val = 0; (i < mp -> lines) && (val == 0); i++) { /* loop thru lines */ + val = tmxr_getc_ln (mp -> ldsc[i]); /* test for input */ + if (val) val = val | (i << RBUF_V_RLINE); /* or in line # */ + } /* end for */ +return val; +} + +/* Update receive interrupts */ + +void dz_update_rcvi (void) +{ +int32 i, scnt; +TMLN *lp; + +for (i = scnt = 0; i < DZ_LINES; i++) { /* poll lines */ + lp = dz_desc.ldsc[i]; /* get line desc */ + scnt = scnt + tmxr_rqln (lp); /* sum buffers */ + if (dz_mctl && !lp -> conn) /* if disconn */ + dz_msr = dz_msr & ~(1 << (i + MSR_V_CD)); /* reset car det */ + } +if (scnt && (dz_csr & CSR_MSE)) { /* input & enabled? */ + dz_csr = dz_csr | CSR_RDONE; /* set done */ + if (dz_sa_enb && (scnt >= DZ_SILO_ALM)) { /* alm enb & cnt hi? */ + dz_csr = dz_csr | CSR_SA; /* set status */ + dz_sa_enb = 0; } } /* disable alarm */ +else dz_csr = dz_csr & ~CSR_RDONE; /* no, clear done */ +if ((dz_csr & CSR_RIE) && /* int enable */ + ((dz_csr & CSR_SAE)? (dz_csr & CSR_SA): (dz_csr & CSR_RDONE))) + SET_INT (DZRX); /* and alm/done? */ +else CLR_INT (DZRX); /* no, clear int */ +return; +} + +/* Update transmit interrupts */ + +void dz_update_xmti (void) +{ +int32 linemask, i, j; + +linemask = dz_tcr & DZ_LMASK; /* enabled lines */ +dz_csr = dz_csr & ~CSR_TRDY; /* assume not rdy */ +for (i = 0, j = CSR_GETTL (dz_csr); i < DZ_LINES; i++) { + j = (j + 1) & DZ_LNOMASK; + if ((linemask & (1 << j)) && dz_desc.ldsc[j] -> xmte) { + CSR_PUTTL (dz_csr, j); /* update CSR */ + dz_csr = dz_csr | CSR_TRDY; /* set xmt rdy */ + break; } } +if ((dz_csr & CSR_TIE) && (dz_csr & CSR_TRDY)) /* ready plus int? */ + SET_INT (DZTX); +else CLR_INT (DZTX); /* no int req */ +return; +} + +/* Device reset */ + +t_stat dz_clear (t_bool flag) +{ +int32 i; + +dz_csr = 0; /* clear CSR */ +dz_rbuf = 0; /* silo empty */ +dz_lpr = 0; /* no params */ +if (flag) dz_tcr = 0; /* INIT? clr all */ +else dz_tcr = dz_tcr & ~0377; /* else save dtr */ +dz_tdr = 0; +dz_sa_enb = 1; +CLR_INT (DZRX); +CLR_INT (DZTX); +sim_cancel (&dz_unit); /* no polling */ +for (i = 0; i < DZ_LINES; i++) { + if (!dz_desc.ldsc[i] -> conn) dz_desc.ldsc[i] -> xmte = 1; + dz_desc.ldsc[i] -> rcve = 0; } /* clr rcv enb */ +return SCPE_OK; +} + +t_stat dz_reset (DEVICE *dptr) +{ +return dz_clear (TRUE); +} + +/* Attach */ + +t_stat dz_attach (UNIT *uptr, char *cptr) +{ +t_stat r; +extern int32 sim_switches; + +dz_mctl = dz_auto = 0; /* modem ctl off */ +r = tmxr_attach (&dz_desc, uptr, cptr); /* attach mux */ +if (r != SCPE_OK) return r; /* error? */ +if (sim_switches & SWMASK ('M')) { /* modem control? */ + dz_mctl = 1; + printf ("Modem control activated\n"); + if (sim_log) fprintf (sim_log, "Modem control activated\n"); + if (sim_switches & SWMASK ('A')) { /* autodisconnect? */ + dz_auto = 1; + printf ("Auto disconnect activated\n"); + if (sim_log) fprintf (sim_log, "Auto disconnect activated\n"); + } + } +return SCPE_OK; +} + +/* Detach */ + +t_stat dz_detach (UNIT *uptr) +{ +return tmxr_detach (&dz_desc, uptr); +} + +/* Status */ + +t_stat dz_status (UNIT *uptr, FILE *st) +{ +int32 i; + +for (i = 0; (i < DZ_LINES) && (dz_desc.ldsc[i] -> conn == 0); i++) ; +if (i < DZ_LINES) { + for (i = 0; i < DZ_LINES; i++) { + if (dz_desc.ldsc[i] -> conn) + tmxr_fstatus (st, dz_desc.ldsc[i], i); } } +else fprintf (st, " all disconnected"); +return SCPE_OK; +} diff --git a/h316_stddev.c b/h316_stddev.c index c979acff..514eda6d 100644 --- a/h316_stddev.c +++ b/h316_stddev.c @@ -27,6 +27,8 @@ ptp 316/516-52 paper tape punch tty 316/516-33 teleprinter clk/options 316/516-12 real time clocks/internal options + + 07-Sep-01 RMS Moved function prototypes */ #include "h316_defs.h" @@ -54,9 +56,6 @@ t_stat tto_svc (UNIT *uptr); t_stat tty_reset (DEVICE *dptr); t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); -extern t_bool hp_setdev (UNIT *uptr, int32 val); /* PTR data structures diff --git a/h316_sys.c b/h316_sys.c index 2cc66e9b..9098cccf 100644 --- a/h316_sys.c +++ b/h316_sys.c @@ -22,6 +22,8 @@ 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. + + 17-Sep-01 RMS Removed multiconsole support */ #include "h316_defs.h" @@ -42,7 +44,6 @@ extern int32 sim_switches; sim_PC pointer to saved PC register descriptor sim_emax maximum number of words for examine/deposit sim_devices array of pointers to simulated devices - sim_consoles array of pointers to consoles (if more than one) sim_stop_messages array of pointers to stop messages sim_load binary loader */ @@ -59,8 +60,6 @@ DEVICE *sim_devices[] = { &cpu_dev, &clk_dev, NULL }; -UNIT *sim_consoles = NULL; - const char *sim_stop_messages[] = { "Unknown error", "Unimplemented instruction", diff --git a/hp2100_defs.h b/hp2100_defs.h index e70f13f6..21fa7b8f 100644 --- a/hp2100_defs.h +++ b/hp2100_defs.h @@ -175,3 +175,8 @@ struct hpdev { #define IOT_V_REASON 16 #define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ + +/* Function prototypes */ + +t_bool hp_setdev (UNIT *uptr, int32 val); +t_bool hp_setdev2 (UNIT *uptr, int32 val); diff --git a/hp2100_dp.c b/hp2100_dp.c index 28006852..577364df 100644 --- a/hp2100_dp.c +++ b/hp2100_dp.c @@ -25,6 +25,7 @@ dp 12557A cartridge disk system + 07-Sep-01 RMS Moved function prototypes 29-Nov-00 RMS Made variable names unique 21-Nov-00 RMS Fixed flag, buffer power up state */ @@ -125,7 +126,6 @@ t_stat dpc_detach (UNIT *uptr); t_stat dpd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat dpd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); void dp_go (int32 fnc, int32 drv, int32 time, int32 attdev); -extern t_bool hp_setdev2 (UNIT *uptr, int32 val); /* DPD data structures diff --git a/hp2100_lp.c b/hp2100_lp.c index faaed1d6..beffe6bb 100644 --- a/hp2100_lp.c +++ b/hp2100_lp.c @@ -25,6 +25,7 @@ lpt 12653A line printer + 07-Sep-01 RMS Moved function prototypes 21-Nov-00 RMS Fixed flag, fbf power up state Added command flop 15-Oct-00 RMS Added variable device number support @@ -42,7 +43,6 @@ int32 lpt_stopioe = 0; /* stop on error */ t_stat lpt_svc (UNIT *uptr); t_stat lpt_reset (DEVICE *dptr); extern struct hpdev infotab[]; -extern t_bool hp_setdev (UNIT *uptr, int32 val); /* LPT data structures diff --git a/hp2100_mt.c b/hp2100_mt.c index ddfd1b65..2ed0775a 100644 --- a/hp2100_mt.c +++ b/hp2100_mt.c @@ -25,6 +25,7 @@ mt 12559A nine track magnetic tape + 07-Sep-01 RMS Moved function prototypes 30-Nov-00 RMS Made variable names unique 04-Oct-98 RMS V2.4 magtape format @@ -101,7 +102,6 @@ t_stat mtc_attach (UNIT *uptr, char *cptr); t_stat mtc_detach (UNIT *uptr); t_stat mtd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat mtd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -extern t_bool hp_setdev2 (UNIT *uptr, int32 val); /* MTD data structures diff --git a/hp2100_stddev.c b/hp2100_stddev.c index daf43227..629ac797 100644 --- a/hp2100_stddev.c +++ b/hp2100_stddev.c @@ -28,6 +28,7 @@ tty 12531C buffered teleprinter interface clk 12539A/B/C time base generator + 07-Sep-01 RMS Moved function prototypes 21-Nov-00 RMS Fixed flag, buffer power up state Added status input for ptp, tty 15-Oct-00 RMS Added dynamic device number support @@ -71,9 +72,6 @@ t_stat tto_svc (UNIT *uptr); t_stat tty_reset (DEVICE *dptr); t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); -extern t_bool hp_setdev (UNIT *uptr, int32 val); /* PTR data structures diff --git a/hp2100_sys.c b/hp2100_sys.c index fdb20e0e..e0617a0f 100644 --- a/hp2100_sys.c +++ b/hp2100_sys.c @@ -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. + 17-Sep-01 RMS Removed multiconsole support 27-May-01 RMS Added multiconsole support 14-Mar-01 RMS Revised load/dump interface (again) 30-Oct-00 RMS Added examine to file support @@ -49,7 +50,6 @@ extern uint16 M[]; sim_PC pointer to saved PC register descriptor sim_emax maximum number of words for examine/deposit sim_devices array of pointers to simulated devices - sim_consoles array of pointers to consoles (if more than one) sim_stop_messages array of pointers to stop messages sim_load binary loader */ @@ -69,8 +69,6 @@ DEVICE *sim_devices[] = { &cpu_dev, &dpd_dev, &dpc_dev, NULL }; -UNIT *sim_consoles = NULL; - const char *sim_stop_messages[] = { "Unknown error", "Unimplemented instruction", diff --git a/i1401_iq.c b/i1401_iq.c index 3ef3c121..105f4e76 100644 --- a/i1401_iq.c +++ b/i1401_iq.c @@ -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. + 07-Sep-01 RMS Moved function prototypes 14-Apr-99 RMS Changed t_addr to unsigned */ @@ -38,8 +39,6 @@ int32 inq_char = 033; /* request inq */ t_stat inq_svc (UNIT *uptr); t_stat inq_reset (DEVICE *dptr); void puts_tty (char *cptr); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); /* INQ data structures diff --git a/i1401_sys.c b/i1401_sys.c index 2f707f10..a5ed5ad5 100644 --- a/i1401_sys.c +++ b/i1401_sys.c @@ -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. + 17-Sep-01 RMS Removed multiconsole support 13-Jul-01 RMS Fixed bug in symbolic output (found by Peter Schorn) 27-May-01 RMS Added multiconsole support 14-Mar-01 RMS Revised load/dump interface (again) @@ -52,7 +53,6 @@ extern int32 store_addr_u (int32 addr); sim_PC pointer to saved PC register descriptor sim_emax maximum number of words for examine/deposit sim_devices array of pointers to simulated devices - sim_consoles array of pointers to consoles (if more than one) sim_stop_messages array of pointers to stop messages sim_load binary loader */ @@ -67,8 +67,6 @@ DEVICE *sim_devices[] = { &cpu_dev, &inq_dev, &cdr_dev, &cdp_dev, &stack_dev, &lpt_dev, &mt_dev, NULL }; -UNIT *sim_consoles = NULL; - const char *sim_stop_messages[] = { "Unknown error", "Unimplemented instruction", diff --git a/id4_sys.c b/id4_sys.c index 257bac16..7ebaf25a 100644 --- a/id4_sys.c +++ b/id4_sys.c @@ -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. + 17-Sep-01 RMS Removed multiconsole support 17-Jul-01 RMS Fixed warning from VC++ 6.0 27-May-01 RMS Added multiconsole support 14-Mar-01 RMS Revised load/dump interface (again) @@ -46,7 +47,6 @@ extern int32 saved_PC; sim_PC pointer to saved PC register descriptor sim_emax number of words for examine sim_devices array of pointers to simulated devices - sim_consoles array of pointers to consoles (if more than one) sim_stop_messages array of pointers to stop messages sim_load binary loader */ @@ -61,8 +61,6 @@ DEVICE *sim_devices[] = { &cpu_dev, &pt_dev, &tt_dev, NULL }; -UNIT *sim_consoles = NULL; - const char *sim_stop_messages[] = { "Unknown error", "Reserved instruction", diff --git a/nova_clk.c b/nova_clk.c index 1db97245..7fd6e643 100644 --- a/nova_clk.c +++ b/nova_clk.c @@ -25,6 +25,7 @@ clk real-time clock + 17-Sep-01 RMS Added terminal multiplexor support 17-Mar-01 RMS Moved function prototype 05-Mar-01 RMS Added clock calibration 24-Sep-97 RMS Fixed bug in unit service (found by Charles Owen) @@ -36,6 +37,8 @@ extern int32 int_req, dev_busy, dev_done, dev_disable; int32 clk_sel = 0; /* selected freq */ int32 clk_time[4] = { 16000, 100000, 10000, 1000 }; /* freq table */ int32 clk_tps[4] = { 60, 10, 100, 1000 }; /* ticks per sec */ +int32 clk_adj[4] = { 1, -5, 2, 20 }; /* tmxr adjust */ +int32 tmxr_poll = 16000; /* tmxr poll */ t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); @@ -95,11 +98,16 @@ return 0; t_stat clk_svc (UNIT *uptr) { +int32 t; + dev_done = dev_done | INT_CLK; /* set done */ dev_busy = dev_busy & ~INT_CLK; /* clear busy */ int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); -sim_activate (&clk_unit, /* reactivate unit */ - sim_rtc_calb (clk_tps[clk_sel])); /* calibrate delay */ +t = sim_rtc_calb (clk_tps[clk_sel]); /* calibrate delay */ +sim_activate (&clk_unit, t); /* reactivate unit */ +if (clk_adj[clk_sel] > 0) /* clk >= 60Hz? */ + tmxr_poll = t * clk_adj[clk_sel]; /* poll is longer */ +else tmxr_poll = t / (-clk_adj[clk_sel]); /* poll is shorter */ return SCPE_OK; } @@ -112,5 +120,6 @@ dev_busy = dev_busy & ~INT_CLK; /* clear busy */ dev_done = dev_done & ~INT_CLK; /* clear done, int */ int_req = int_req & ~INT_CLK; sim_cancel (&clk_unit); /* deactivate unit */ +tmxr_poll = clk_time[0]; /* poll is default */ return SCPE_OK; } diff --git a/nova_sys.c b/nova_sys.c index c1c57ff1..4de0798c 100644 --- a/nova_sys.c +++ b/nova_sys.c @@ -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. + 17-Sep-01 RMS Removed multiconsole support 31-May-01 RMS Added multiconsole support 14-Mar-01 RMS Revised load/dump interface (again) 22-Dec-00 RMS Added second terminal support @@ -62,7 +63,6 @@ extern int32 saved_PC; sim_PC pointer to saved PC register descriptor sim_emax number of words needed for examine sim_devices array of pointers to simulated devices - sim_consoles array of pointers to consoles (if more than one) sim_stop_messages array of pointers to stop messages sim_load binary loader */ @@ -90,11 +90,6 @@ DEVICE *sim_devices[] = { &dkp_dev, &mta_dev, NULL }; -UNIT *sim_consoles[] = { - &tti_unit, &tto_unit, - &tti1_unit, &tto1_unit, - NULL }; - const char *sim_stop_messages[] = { "Unknown error", "Unknown I/O instruction", diff --git a/nova_tt.c b/nova_tt.c index 8d0b4ae2..1c60a52e 100644 --- a/nova_tt.c +++ b/nova_tt.c @@ -26,6 +26,8 @@ tti terminal input tto terminal output + 17-Sep-01 RMS Removed multiconsole support + 07-Sep-01 RMS Moved function prototypes 31-May-01 RMS Added multiconsole support */ @@ -39,9 +41,6 @@ t_stat tto_svc (UNIT *uptr); t_stat tti_reset (DEVICE *dptr); t_stat tto_reset (DEVICE *dptr); t_stat ttx_setmod (UNIT *uptr, int32 value); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); -static uint8 tto_consout[CONS_SIZE]; /* TTI data structures @@ -51,7 +50,7 @@ static uint8 tto_consout[CONS_SIZE]; ttx_mod TTI/TTO modifiers list */ -UNIT tti_unit = { UDATA (&tti_svc, UNIT_CONS, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; REG tti_reg[] = { { ORDATA (BUF, tti_unit.buf, 8) }, @@ -62,12 +61,9 @@ REG tti_reg[] = { { DRDATA (POS, tti_unit.pos, 31), PV_LEFT }, { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, { FLDATA (MODE, tti_unit.flags, UNIT_V_DASHER), REG_HRO }, - { FLDATA (CFLAG, tti_unit.flags, UNIT_V_CONS), REG_HRO }, { NULL } }; MTAB ttx_mod[] = { - { UNIT_CONS, 0, "inactive", NULL, NULL }, - { UNIT_CONS, UNIT_CONS, "active console", "CONSOLE", &set_console }, { UNIT_DASHER, 0, "ANSI", "ANSI", &ttx_setmod }, { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx_setmod }, { 0 } }; @@ -85,7 +81,7 @@ DEVICE tti_dev = { tto_reg TTO register list */ -UNIT tto_unit = { UDATA (&tto_svc, UNIT_CONS, 0), SERIAL_OUT_WAIT }; +UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { { ORDATA (BUF, tto_unit.buf, 8) }, @@ -96,8 +92,6 @@ REG tto_reg[] = { { DRDATA (POS, tto_unit.pos, 31), PV_LEFT }, { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, { FLDATA (MODE, tto_unit.flags, UNIT_V_DASHER), REG_HRO }, - { BRDATA (CONSOUT, tto_consout, 8, 8, CONS_SIZE), REG_HIDDEN }, - { FLDATA (CFLAG, tto_unit.flags, UNIT_V_CONS), REG_HRO }, { NULL } }; DEVICE tto_dev = { @@ -153,8 +147,7 @@ tti_unit.buf = 0; dev_busy = dev_busy & ~INT_TTI; /* clear busy */ dev_done = dev_done & ~INT_TTI; /* clear done, int */ int_req = int_req & ~INT_TTI; -if (tti_unit.flags & UNIT_CONS) /* if active console, */ - sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ +sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ return SCPE_OK; } @@ -190,7 +183,7 @@ dev_done = dev_done | INT_TTO; /* set done */ int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); c = tto_unit.buf & 0177; if ((tto_unit.flags & UNIT_DASHER) && (c == 031)) c = '\b'; -if ((temp = sim_putcons (c, uptr)) != SCPE_OK) return temp; +if ((temp = sim_putchar (c)) != SCPE_OK) return temp; tto_unit.pos = tto_unit.pos + 1; return SCPE_OK; } @@ -204,7 +197,6 @@ dev_busy = dev_busy & ~INT_TTO; /* clear busy */ dev_done = dev_done & ~INT_TTO; /* clear done, int */ int_req = int_req & ~INT_TTO; sim_cancel (&tto_unit); /* deactivate unit */ -tto_unit.filebuf = tto_consout; /* set buf pointer */ return SCPE_OK; } diff --git a/nova_tt1.c b/nova_tt1.c index 9435848e..b367e01a 100644 --- a/nova_tt1.c +++ b/nova_tt1.c @@ -27,23 +27,32 @@ tti1 second terminal input tto1 second terminal output + 17-Sep-01 RMS Changed to use terminal multiplexor library + 07-Sep-01 RMS Moved function prototypes 31-May-01 RMS Added multiconsole support 26-Apr-01 RMS Added device enable/disable support */ #include "nova_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" #define UNIT_V_DASHER (UNIT_V_UF + 0) /* Dasher mode */ #define UNIT_DASHER (1 << UNIT_V_DASHER) extern int32 int_req, dev_busy, dev_done, dev_disable, iot_enb; +extern int32 tmxr_poll; /* calibrated poll */ +TMLN tt1_ldsc = { 0 }; /* line descriptors */ +TMXR tt_desc = { 1, 0, &tt1_ldsc }; /* mux descriptor */ + t_stat tti1_svc (UNIT *uptr); t_stat tto1_svc (UNIT *uptr); t_stat tti1_reset (DEVICE *dptr); t_stat tto1_reset (DEVICE *dptr); t_stat ttx1_setmod (UNIT *uptr, int32 value); -extern t_stat sim_poll_kbd (void); -static uint8 tto1_consout[CONS_SIZE]; +t_stat tti1_attach (UNIT *uptr, char *cptr); +t_stat tti1_detach (UNIT *uptr); +t_stat tti1_status (UNIT *uptr, FILE *st); /* TTI1 data structures @@ -53,7 +62,7 @@ static uint8 tto1_consout[CONS_SIZE]; ttx1_mod TTI1/TTO1 modifiers list */ -UNIT tti1_unit = { UDATA (&tti1_svc, 0, 0), KBD_POLL_WAIT }; +UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT }; REG tti1_reg[] = { { ORDATA (BUF, tti1_unit.buf, 8) }, @@ -61,16 +70,14 @@ REG tti1_reg[] = { { FLDATA (DONE, dev_done, INT_V_TTI1) }, { FLDATA (DISABLE, dev_disable, INT_V_TTI1) }, { FLDATA (INT, int_req, INT_V_TTI1) }, - { DRDATA (POS, tti1_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tt1_ldsc.rxcnt, 31), PV_LEFT }, { DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT }, { FLDATA (MODE, tti1_unit.flags, UNIT_V_DASHER), REG_HRO }, - { FLDATA (CFLAG, tti1_unit.flags, UNIT_V_CONS), REG_HRO }, { FLDATA (*DEVENB, iot_enb, INT_V_TTI1), REG_HRO }, { NULL } }; MTAB ttx1_mod[] = { - { UNIT_CONS, 0, "inactive", NULL, NULL }, - { UNIT_CONS, UNIT_CONS, "active console", "CONSOLE", &set_console }, + { UNIT_ATT, UNIT_ATT, "line status:", NULL, &tti1_status }, { UNIT_DASHER, 0, "ANSI", "ANSI", &ttx1_setmod }, { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx1_setmod }, { 0 } }; @@ -78,8 +85,8 @@ MTAB ttx1_mod[] = { DEVICE tti1_dev = { "TTI1", &tti1_unit, tti1_reg, ttx1_mod, 1, 10, 31, 1, 8, 8, - NULL, NULL, &tti1_reset, - NULL, NULL, NULL }; + &tmxr_ex, &tmxr_dep, &tti1_reset, + NULL, &tti1_attach, &tti1_detach }; /* TTO1 data structures @@ -96,11 +103,9 @@ REG tto1_reg[] = { { FLDATA (DONE, dev_done, INT_V_TTO1) }, { FLDATA (DISABLE, dev_disable, INT_V_TTO1) }, { FLDATA (INT, int_req, INT_V_TTO1) }, - { DRDATA (POS, tto1_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tt1_ldsc.txcnt, 31), PV_LEFT }, { DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT }, { FLDATA (MODE, tto1_unit.flags, UNIT_V_DASHER), REG_HRO }, - { BRDATA (CONSOUT, tto1_consout, 8, 8, CONS_SIZE), REG_HIDDEN }, - { FLDATA (CFLAG, tto1_unit.flags, UNIT_V_CONS), REG_HRO }, { FLDATA (*DEVENB, iot_enb, INT_V_TTI1), REG_HRO }, { NULL } }; @@ -135,17 +140,25 @@ return iodata; t_stat tti1_svc (UNIT *uptr) { -int32 temp; +int32 temp, newln; -sim_activate (&tti1_unit, tti1_unit.wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ -tti1_unit.buf = temp & 0177; -if ((tti1_unit.flags & UNIT_DASHER) && (tti1_unit.buf == '\r')) - tti1_unit.buf = '\n'; /* Dasher: cr -> nl */ -dev_busy = dev_busy & ~INT_TTI1; /* clear busy */ -dev_done = dev_done | INT_TTI1; /* set done */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); -tti1_unit.pos = tti1_unit.pos + 1; +if (tt1_ldsc.conn) { /* connected? */ + tmxr_poll_rx (&tt_desc); /* poll for input */ + if (temp = tmxr_getc_ln (&tt1_ldsc)) { /* get char */ + uptr -> buf = temp & 0177; + if ((uptr -> flags & UNIT_DASHER) && + (uptr -> buf == '\r')) + uptr -> buf = '\n'; /* Dasher: cr -> nl */ + dev_busy = dev_busy & ~INT_TTI1; /* clear busy */ + dev_done = dev_done | INT_TTI1; /* set done */ + int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); } + sim_activate (uptr, uptr -> wait); } /* continue poll */ +if (uptr -> flags & UNIT_ATT) { /* attached? */ + newln = tmxr_poll_conn (&tt_desc, uptr); /* poll connect */ + if (newln >= 0) { /* got one? */ + sim_activate (&tti1_unit, tti1_unit.wait); + tt1_ldsc.rcve = 1; } /* rcv enabled */ + sim_activate (uptr, tmxr_poll); } /* sched poll */ return SCPE_OK; } @@ -157,8 +170,12 @@ tti1_unit.buf = 0; dev_busy = dev_busy & ~INT_TTI1; /* clear busy */ dev_done = dev_done & ~INT_TTI1; /* clear done, int */ int_req = int_req & ~INT_TTI1; -if (tti1_unit.flags & UNIT_CONS) /* active console? */ - sim_activate (&tti1_unit, tti1_unit.wait); +if (tt1_ldsc.conn) { /* if conn, */ + sim_activate (&tti1_unit, tti1_unit.wait); /* activate, */ + tt1_ldsc.rcve = 1; } /* enable */ +else if (tti1_unit.flags & UNIT_ATT) /* if attached, */ + sim_activate (&tti1_unit, tmxr_poll); /* activate */ +else sim_cancel (&tti1_unit); /* else stop */ return SCPE_OK; } @@ -187,15 +204,20 @@ return 0; t_stat tto1_svc (UNIT *uptr) { -int32 c, temp; +int32 c; dev_busy = dev_busy & ~INT_TTO1; /* clear busy */ dev_done = dev_done | INT_TTO1; /* set done */ int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); c = tto1_unit.buf & 0177; if ((tto1_unit.flags & UNIT_DASHER) && (c == 031)) c = '\b'; -if ((temp = sim_putcons (c, uptr)) != SCPE_OK) return temp; -tto1_unit.pos = tto1_unit.pos + 1; +if (tt1_ldsc.conn) { /* connected? */ + if (tt1_ldsc.xmte) { /* tx enabled? */ + tmxr_putc_ln (&tt1_ldsc, c); /* output char */ + tmxr_poll_tx (&tt_desc); } /* poll xmt */ + else { tmxr_poll_tx (&tt_desc); /* poll xmt */ + sim_activate (&tto1_unit, tmxr_poll); /* wait */ + return SCPE_OK; } } return SCPE_OK; } @@ -208,7 +230,6 @@ dev_busy = dev_busy & ~INT_TTO1; /* clear busy */ dev_done = dev_done & ~INT_TTO1; /* clear done, int */ int_req = int_req & ~INT_TTO1; sim_cancel (&tto1_unit); /* deactivate unit */ -tto1_unit.filebuf = tto1_consout; /* set buf pointer */ return SCPE_OK; } @@ -218,3 +239,35 @@ tti1_unit.flags = (tti1_unit.flags & ~UNIT_DASHER) | value; tto1_unit.flags = (tto1_unit.flags & ~UNIT_DASHER) | value; return SCPE_OK; } + +/* Attach routine */ + +t_stat tti1_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = tmxr_attach (&tt_desc, uptr, cptr); /* attach */ +if (r != SCPE_OK) return r; /* error */ +sim_activate (uptr, tmxr_poll); /* start poll */ +return SCPE_OK; +} + +/* Detach routine */ + +t_stat tti1_detach (UNIT *uptr) +{ +t_stat r; + +r = tmxr_detach (&tt_desc, uptr); /* detach */ +tt1_ldsc.rcve = 0; /* disable rcv */ +sim_cancel (uptr); /* stop poll */ +return r; +} + +/* Status routine */ + +t_stat tti1_status (UNIT *uptr, FILE *st) +{ +tmxr_fstatus (st, &tt1_ldsc, -1); +return SCPE_OK; +} \ No newline at end of file diff --git a/pdp10_cpu.c b/pdp10_cpu.c index 67deee66..f3bba9f5 100644 --- a/pdp10_cpu.c +++ b/pdp10_cpu.c @@ -25,6 +25,7 @@ cpu KS10 central processor + 31-Aug-01 RMS Changed int64 to t_int64 for Windoze 10-Aug-01 RMS Removed register in declarations 17-Jul-01 RMS Moved function prototype 19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug @@ -531,7 +532,7 @@ void ashc (int32 ac, a10 ea); void circ (int32 ac, a10 ea); void blt (int32 ac, a10 ea, int32 pflgs); void bltu (int32 ac, a10 ea, int32 pflgs, int dir); -a10 calc_ea (int64 inst, int32 prv); +a10 calc_ea (d10 inst, int32 prv); a10 calc_ioea (d10 inst, int32 prv); d10 calc_jrstfea (d10 inst, int32 pflgs); void pi_dismiss (void); diff --git a/pdp10_defs.h b/pdp10_defs.h index dd9e0648..b0b0f3cb 100644 --- a/pdp10_defs.h +++ b/pdp10_defs.h @@ -23,6 +23,11 @@ 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. + 23-Oct-01 RMS New IO page address constants + 19-Oct-01 RMS Added DZ definitions + 07-Sep-01 RMS Revised for PDP-11 multi-level interrupts + 31-Aug-01 RMS Changed int64 to t_int64 for Windoze + 29-Aug-01 RMS Corrected models and dates (found by Lars Brinkhoff) 01-Jun-01 RMS Updated DZ11 vector definitions 19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug */ @@ -35,9 +40,9 @@ PDP-6 0.25 Original 36b implementation, 1964 KA10 0.38 First PDP-10, flip chips, 1967 - KI10 0.72 First paging system, flip chip + MSI, 1969 - KL10 1.8 First ECL system, ECL 10K, 1972 - KL10X 1.8 Expanded addressing, ECL 10K, 1975 + KI10 0.72 First paging system, flip chip + MSI, 1972 + KL10 1.8 First ECL system, ECL 10K, 1975 + KL10B 1.8 Expanded addressing, ECL 10K, 1978 KS10 0.3 Last 36b system, 2901 based, 1979 In addition, it ran four major (incompatible) operating systems: @@ -69,8 +74,8 @@ /* Data types */ -typedef int32 a10; /* PDP-10 addr (30b) */ -typedef int64 d10; /* PDP-10 data (36b) */ +typedef int32 a10; /* PDP-10 addr (30b) */ +typedef t_int64 d10; /* PDP-10 data (36b) */ /* Abort codes, used to sort out longjmp's back to the main loop Codes > 0 are simulator stop codes @@ -162,7 +167,7 @@ typedef int64 d10; /* PDP-10 data (36b) */ #define BP_S 0007700000000 #define GET_P(x) ((int32) (((x) >> BP_V_P) & BP_M_P)) #define GET_S(x) ((int32) (((x) >> BP_V_S) & BP_M_S)) -#define PUT_P(b,x) (((b) & ~BP_P) | ((((int64) (x)) & BP_M_P) << BP_V_P)) +#define PUT_P(b,x) (((b) & ~BP_P) | ((((t_int64) (x)) & BP_M_P) << BP_V_P)) /* Flags (stored in their own halfword) */ @@ -567,17 +572,31 @@ typedef int64 d10; /* PDP-10 data (36b) */ #define IO_UBA3 (3 << IO_V_UBA) #define GET_IOUBA(x) (((x) >> IO_V_UBA) & IO_M_UBA) +/* DZ11 parameters */ + +#define DZ_MUXES 1 /* # of muxes */ +#define DZ_LINES 8 /* lines per mux */ + /* I/O page layout */ -#define IO_DZBASE 0760010 /* DZ11 base */ -#define IO_TCUBASE 0760770 /* TCU150 base */ -#define IO_UBMAP 0763000 /* Unibus map base */ -#define IO_UBCS 0763100 /* Unibus c/s reg */ -#define IO_UBMNT 0763101 /* Unibus maint reg */ -#define IO_TMBASE 0772440 /* RH11/tape base */ -#define IO_RHBASE 0776700 /* RH11/disk base */ -#define IO_LPBASE 0775400 /* LP20 base */ -#define IO_PTBASE 0777550 /* PC11 base */ +#define IOBA_DZ 0760010 /* DZ11 */ +#define IOLN_DZ (010 * DZ_MUXES) +#define IOBA_TCU 0760770 /* TCU150 */ +#define IOLN_TCU 006 +#define IOBA_UBMAP 0763000 /* Unibus map */ +#define IOLN_UBMAP 0100 +#define IOBA_UBCS 0763100 /* Unibus c/s reg */ +#define IOLN_UBCS 001 +#define IOBA_UBMNT 0763101 /* Unibus maint reg */ +#define IOLN_UBMNT 001 +#define IOBA_TU 0772440 /* RH11/tape */ +#define IOLN_TU 034 +#define IOBA_RP 0776700 /* RH11/disk */ +#define IOLN_RP 050 +#define IOBA_LP20 0775400 /* LP20 */ +#define IOLN_LP20 020 +#define IOBA_PT 0777550 /* PC11 */ +#define IOLN_PT 010 /* Common Unibus CSR flags */ @@ -603,20 +622,28 @@ typedef int64 d10; /* PDP-10 data (36b) */ #define INT_V_RP 6 /* RH11/RP,RM drives */ #define INT_V_TU 7 /* RH11/TM03/TU45 */ -#define INT_V_DZ0RX 16 /* DZ11 */ -#define INT_V_DZ0TX 17 +#define INT_V_DZRX 16 /* DZ11 */ +#define INT_V_DZTX 17 #define INT_V_PTR 24 /* PC11 */ #define INT_V_PTP 25 #define INT_V_LP20 26 /* LPT20 */ #define INT_RP (1u << INT_V_RP) #define INT_TU (1u << INT_V_TU) -#define INT_DZ0RX (1u << INT_V_DZ0RX) -#define INT_DZ0TX (1u << INT_V_DZ0TX) +#define INT_DZRX (1u << INT_V_DZRX) +#define INT_DZTX (1u << INT_V_DZTX) #define INT_PTR (1u << INT_V_PTR) #define INT_PTP (1u << INT_V_PTP) #define INT_LP20 (1u << INT_V_LP20) +#define IPL_RP 6 /* int levels */ +#define IPL_TU 6 +#define IPL_DZRX 5 +#define IPL_DZTX 5 +#define IPL_PTR 4 +#define IPL_PTP 4 +#define IPL_LP20 4 + #define INT_UB1 INT_RP /* on Unibus 1 */ #define INT_UB3 (0xFFFFFFFFu & ~INT_UB1) /* on Unibus 3 */ @@ -629,6 +656,10 @@ typedef int64 d10; /* PDP-10 data (36b) */ #define VEC_PTP 0074 #define VEC_TU 0224 #define VEC_RP 0254 -#define VEC_DZ0RX 0340 -#define VEC_DZ0TX 0344 +#define VEC_DZRX 0340 +#define VEC_DZTX 0344 #define VEC_LP20 0754 + +#define IREQ(dv) int_req +#define SET_INT(dv) IREQ(dv) = IREQ(dv) | (INT_##dv) +#define CLR_INT(dv) IREQ(dv) = IREQ(dv) & ~(INT_##dv) diff --git a/pdp10_dz.c b/pdp10_dz.c index d4f43ed0..fe09d12d 100644 --- a/pdp10_dz.c +++ b/pdp10_dz.c @@ -1,6 +1,6 @@ -/* pdp10_dz_stub.c: DZ11 terminal multiplexor simulator stub +/* pdp10_dz.c: DZ11 terminal multiplexor simulator - Copyright (c) 2001, Robert M Supnik + Copyright (c) 1993-2001, 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,168 +23,8 @@ 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. - dz DZ11 terminal multiplexor (stub) - - This version of the DZ11 is a stub to allow operating systems to play - with the device registers. It is required for ITS, and not harmful to - TOPS-10 or TOPS-20. + dz DZ11 terminal multiplexor */ #include "pdp10_defs.h" - -#define DZ_LINES 8 /* lines per DZ11 */ -#define DZ_LMASK (DZ_LINES - 1) -#define DZ_SILO_ALM 16 /* silo alarm level */ -#define MAXBUF 128 /* buffer size */ - -/* DZCSR - 160100 - control/status register */ - -#define CSR_MAINT 0000010 /* maint - NI */ -#define CSR_CLR 0000020 /* clear */ -#define CSR_MSE 0000040 /* master scan enb */ -#define CSR_RIE 0000100 /* rcv int enb */ -#define CSR_RDONE 0000200 /* rcv done - RO */ -#define CSR_V_TLINE 8 /* xmit line - RO */ -#define CSR_TLINE (DZ_LMASK << CSR_V_TLINE) -#define CSR_SAE 0010000 /* silo alm enb */ -#define CSR_SA 0020000 /* silo alm - RO */ -#define CSR_TIE 0040000 /* xmit int enb */ -#define CSR_TRDY 0100000 /* xmit rdy - RO */ -#define CSR_RW (CSR_MSE | CSR_RIE | CSR_SAE | CSR_TIE) -#define CSR_MBZ (0004003 | CSR_CLR | CSR_MAINT) - -#define CSR_GETTL(x) (((x) >> CSR_V_TLINE) & DZ_LMASK) -#define CSR_PUTTL(x,y) x = ((x) & ~CSR_TLINE) | (((y) & DZ_LMASK) << CSR_V_TLINE) - -/* DZRBUF - 160102 - receive buffer, read only */ - -#define RBUF_CHAR 0000377 /* rcv char */ -#define RBUF_V_RLINE 8 /* rcv line */ -#define RBUF_PARE 0010000 /* parity err - NI */ -#define RBUF_FRME 0020000 /* frame err - NI */ -#define RBUF_OVRE 0040000 /* overrun err - NI */ -#define RBUF_VALID 0100000 /* rcv valid */ -#define RBUF_MBZ 0004000 - -/* DZLPR - 160102 - line parameter register, write only, word access only */ - -#define LPR_V_LINE 0 /* line */ -#define LPR_LPAR 0007770 /* line pars - NI */ -#define LPR_RCVE 0010000 /* receive enb */ -#define LPR_GETLN(x) (((x) >> LPR_V_LINE) & DZ_LMASK) - -/* DZTCR - 160104 - transmission control register */ - -#define TCR_V_XMTE 0 /* xmit enables */ -#define TCR_V_DTR 7 /* DTRs */ - -/* DZMSR - 160106 - modem status register, read only */ - -#define MSR_V_RI 0 /* ring indicators */ -#define MSR_V_CD 7 /* carrier detect */ - -/* DZTDR - 160106 - transmit data, write only */ - -#define TDR_CHAR 0000377 /* xmit char */ -#define TDR_V_TBR 7 /* xmit break - NI */ - -extern int32 int_req, dev_enb; -int32 dz_csr = 0; /* csr */ -int32 dz_rbuf = 0; /* rcv buffer */ -int32 dz_lpr = 0; /* line param */ -int32 dz_tcr = 0; /* xmit control */ -int32 dz_msr = 0; /* modem status */ -int32 dz_tdr = 0; /* xmit data */ -int32 dz_mctl = 0; /* modem ctrl enab */ -int32 dz_sa_enb = 1; /* silo alarm enabled */ - -t_stat dz_reset (DEVICE *dptr); -t_stat dz_clear (t_bool flag); - -/* DZ data structures - - dz_dev DZ device descriptor - dz_unit DZ unit list - dz_reg DZ register list -*/ - -UNIT dz_unit = { UDATA (NULL, 0, 0) }; - -REG dz_reg[] = { - { ORDATA (CSR, dz_csr, 16) }, - { ORDATA (RBUF, dz_rbuf, 16) }, - { ORDATA (LPR, dz_lpr, 16) }, - { ORDATA (TCR, dz_tcr, 16) }, - { ORDATA (MSR, dz_msr, 16) }, - { ORDATA (TDR, dz_tdr, 16) }, - { FLDATA (MDMCTL, dz_mctl, 0) }, - { FLDATA (SAENB, dz_sa_enb, 0) }, - { FLDATA (*DEVENB, dev_enb, INT_V_DZ0RX), REG_HRO }, - { NULL } }; - -DEVICE dz_dev = { - "DZ", &dz_unit, dz_reg, NULL, - 1, 8, 13, 1, 8, 8, - NULL, NULL, &dz_reset, - NULL, NULL, NULL }; - -/* IO dispatch routines, I/O addresses 17760100 - 17760107 */ - -t_stat dz0_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 03) { /* case on PA<2:1> */ -case 00: /* CSR */ - *data = dz_csr = dz_csr & ~CSR_MBZ; - break; -case 01: /* RBUF */ - dz_csr = dz_csr & ~CSR_SA; /* clr silo alarm */ - *data = dz_rbuf; - break; -case 02: /* TCR */ - *data = dz_tcr; - break; -case 03: /* MSR */ - *data = dz_msr; - break; } -return SCPE_OK; -} - -t_stat dz0_wr (int32 data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 03) { /* case on PA<2:1> */ -case 00: /* CSR */ - if (access == WRITEB) data = (PA & 1)? - (dz_csr & 0377) | (data << 8): (dz_csr & ~0377) | data; - dz_csr = (dz_csr & ~CSR_RW) | (data & CSR_RW); - break; -case 01: /* LPR */ - dz_lpr = data; - break; -case 02: /* TCR */ - if (access == WRITEB) data = (PA & 1)? - (dz_tcr & 0377) | (data << 8): (dz_tcr & ~0377) | data; - dz_tcr = data; - break; -case 03: /* TDR */ - if (PA & 1) { /* odd byte? */ - dz_tdr = (dz_tdr & 0377) | (data << 8); /* just save */ - break; } - dz_tdr = data; - break; } -return SCPE_OK; -} - -/* Device reset */ - -t_stat dz_reset (DEVICE *dptr) -{ -dz_csr = 0; /* clear CSR */ -dz_rbuf = 0; /* silo empty */ -dz_lpr = 0; /* no params */ -dz_tcr = 0; /* clr all */ -dz_tdr = 0; -dz_sa_enb = 1; -int_req = int_req & ~(INT_DZ0RX | INT_DZ0TX); /* clear int */ -sim_cancel (&dz_unit); /* no polling */ -return SCPE_OK; -} +#include "dec_dz.h" diff --git a/pdp10_fe.c b/pdp10_fe.c index 71ec41ee..859a77f2 100644 --- a/pdp10_fe.c +++ b/pdp10_fe.c @@ -24,6 +24,9 @@ in this Software without prior written authorization from Robert M Supnik. fe KS10 console front end + + 23-Oct-01 RMS New IO page address constants + 07-Sep-01 RMS Moved function prototypes */ #include "pdp10_defs.h" @@ -36,8 +39,6 @@ t_stat feo_svc (UNIT *uptr); t_stat fe_reset (DEVICE *dptr); t_stat fe_stop_os (UNIT *uptr, int32 val); t_stat fe_ctrl_c (UNIT *uptr, int32 val); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); /* FE data structures @@ -147,7 +148,7 @@ return SCPE_OK; t_stat fe_stop_os (UNIT *uptr, int32 val) { -M[FE_SWITCH] = IO_RHBASE; /* tell OS to stop */ +M[FE_SWITCH] = IOBA_RP; /* tell OS to stop */ return SCPE_OK; } @@ -159,4 +160,4 @@ fei_unit.buf = 003; /* control-C */ M[FE_CTYIN] = fei_unit.buf | FE_CVALID; /* put char in mem */ apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */ return SCPE_OK; -} \ No newline at end of file +} diff --git a/pdp10_ksio.c b/pdp10_ksio.c index a15e296b..e7e70e24 100644 --- a/pdp10_ksio.c +++ b/pdp10_ksio.c @@ -25,6 +25,8 @@ uba Unibus adapters + 23-Sep-01 RMS New IO page address constants + 07-Sep-01 RMS Revised device disable mechanism 25-Aug-01 RMS Enabled DZ11 21-Aug-01 RMS Updated DZ11 disable 01-Jun-01 RMS Updated DZ11 vectors @@ -77,7 +79,6 @@ int32 ubcs[UBANUM] = { 0 }; /* status registers */ int32 ubmap[UBANUM][UMAP_MEMSIZE] = { 0 }; /* Unibus maps */ int32 int_req = 0; /* interrupt requests */ -int32 dev_enb = -1 & ~(INT_PTR | INT_PTP | INT_DZ0RX); /* device enables */ /* Map IO controller numbers to Unibus adapters: -1 = non-existent */ @@ -97,10 +98,12 @@ extern jmp_buf save_env; extern d10 Read (a10 ea); extern void pi_eval (); -extern t_stat dz0_rd (int32 *data, int32 addr, int32 access); -extern t_stat dz0_wr (int32 data, int32 addr, int32 access); +extern t_stat dz_rd (int32 *data, int32 addr, int32 access); +extern t_stat dz_wr (int32 data, int32 addr, int32 access); +extern int32 dz_enb; extern t_stat pt_rd (int32 *data, int32 addr, int32 access); extern t_stat pt_wr (int32 data, int32 addr, int32 access); +extern int32 pt_enb; extern t_stat lp20_rd (int32 *data, int32 addr, int32 access); extern t_stat lp20_wr (int32 data, int32 addr, int32 access); extern int32 lp20_inta (void); @@ -138,7 +141,6 @@ REG uba_reg[] = { { ORDATA (INTREQ, int_req, 32), REG_RO }, { ORDATA (UB1CS, ubcs[0], 18) }, { ORDATA (UB3CS, ubcs[1], 18) }, - { ORDATA (DEVENB, dev_enb, 32), REG_HRO }, { NULL } }; DEVICE uba_dev = { @@ -152,7 +154,7 @@ DEVICE uba_dev = { struct iolink { /* I/O page linkage */ int32 low; /* low I/O addr */ int32 high; /* high I/O addr */ - int32 enb; /* enable mask */ + int32 *enb; /* enable flag */ t_stat (*read)(); /* read routine */ t_stat (*write)(); }; /* write routine */ @@ -160,31 +162,31 @@ struct iolink { /* I/O page linkage */ The expected Unibus adapter number is included as the high 2 bits */ struct iolink iotable[] = { - { IO_UBA1+IO_RHBASE, IO_UBA1+IO_RHBASE+047, 0, - &rp_rd, &rp_wr }, /* disk */ - { IO_UBA3+IO_TMBASE, IO_UBA3+IO_TMBASE+033, 0, - &tu_rd, &tu_wr }, /* mag tape */ - { IO_UBA3+IO_DZBASE, IO_UBA3+IO_DZBASE+07, INT_DZ0RX, - &dz0_rd, &dz0_wr }, /* terminal mux */ - { IO_UBA3+IO_LPBASE, IO_UBA3+IO_LPBASE+017, 0, - &lp20_rd, &lp20_wr }, /* line printer */ - { IO_UBA3+IO_PTBASE, IO_UBA3+IO_PTBASE+07, INT_PTR, - &pt_rd, &pt_wr }, /* paper tape */ - { IO_UBA1+IO_UBMAP, IO_UBA1+IO_UBMAP+077, 0, - &ubmap_rd, &ubmap_wr }, /* Unibus 1 map */ - { IO_UBA3+IO_UBMAP, IO_UBA3+IO_UBMAP+077, 0, - &ubmap_rd, &ubmap_wr }, /* Unibus 3 map */ - { IO_UBA1+IO_UBCS, IO_UBA1+IO_UBCS, 0, - &ubs_rd, &ubs_wr }, /* Unibus 1 c/s */ - { IO_UBA3+IO_UBCS, IO_UBA3+IO_UBCS, 0, - &ubs_rd, &ubs_wr }, /* Unibus 3 c/s */ - { IO_UBA1+IO_UBMNT, IO_UBA1+IO_UBMNT, 0, - &rd_zro, &wr_nop }, /* Unibus 1 maint */ - { IO_UBA3+IO_UBMNT, IO_UBA3+IO_UBMNT, 0, - &rd_zro, &wr_nop }, /* Unibus 3 maint */ - { IO_UBA3+IO_TCUBASE, IO_UBA3+IO_TCUBASE+05, 0, - &tcu_rd, &wr_nop }, /* TCU150 */ - { 00100000, 00100000, 0, &rd_zro, &wr_nop }, /* Mem sys stat */ + { IO_UBA1+IOBA_RP, IO_UBA1+IOBA_RP+IOLN_RP, + NULL, &rp_rd, &rp_wr }, /* disk */ + { IO_UBA3+IOBA_TU, IO_UBA3+IOBA_TU+IOLN_TU, + NULL, &tu_rd, &tu_wr }, /* mag tape */ + { IO_UBA3+IOBA_DZ, IO_UBA3+IOBA_DZ+IOLN_DZ, + &dz_enb, &dz_rd, &dz_wr }, /* terminal mux */ + { IO_UBA3+IOBA_LP20, IO_UBA3+IOBA_LP20+IOLN_LP20, + NULL, &lp20_rd, &lp20_wr }, /* line printer */ + { IO_UBA3+IOBA_PT, IO_UBA3+IOBA_PT+IOLN_PT, + &pt_enb, &pt_rd, &pt_wr }, /* paper tape */ + { IO_UBA1+IOBA_UBMAP, IO_UBA1+IOBA_UBMAP+IOLN_UBMAP, + NULL, &ubmap_rd, &ubmap_wr }, /* Unibus 1 map */ + { IO_UBA3+IOBA_UBMAP, IO_UBA3+IOBA_UBMAP+IOLN_UBMAP, + NULL, &ubmap_rd, &ubmap_wr }, /* Unibus 3 map */ + { IO_UBA1+IOBA_UBCS, IO_UBA1+IOBA_UBCS+IOLN_UBCS, + NULL, &ubs_rd, &ubs_wr }, /* Unibus 1 c/s */ + { IO_UBA3+IOBA_UBCS, IO_UBA3+IOBA_UBCS+IOLN_UBCS, + NULL, &ubs_rd, &ubs_wr }, /* Unibus 3 c/s */ + { IO_UBA1+IOBA_UBMNT, IO_UBA1+IOBA_UBMNT+IOLN_UBMNT, + NULL, &rd_zro, &wr_nop }, /* Unibus 1 maint */ + { IO_UBA3+IOBA_UBMNT, IO_UBA3+IOBA_UBMNT+IOLN_UBMNT, + NULL, &rd_zro, &wr_nop }, /* Unibus 3 maint */ + { IO_UBA3+IOBA_TCU, IO_UBA3+IOBA_TCU+IOLN_TCU, + NULL, &tcu_rd, &wr_nop }, /* TCU150 */ + { 00100000, 00100000, NULL, &rd_zro, &wr_nop }, /* Mem sys stat */ { 0, 0, 0, NULL, NULL } }; /* Interrupt request to interrupt action map */ @@ -200,7 +202,7 @@ int32 (*int_ack[32])() = { /* int ack routines */ int32 int_vec[32] = { /* int req to vector */ 0, 0, 0, 0, 0, 0, VEC_RP, VEC_TU, 0, 0, 0, 0, 0, 0, 0, 0, - VEC_DZ0RX, VEC_DZ0TX, 0, 0, 0, 0, 0, 0, + VEC_DZRX, VEC_DZTX, 0, 0, 0, 0, 0, 0, VEC_PTR, VEC_PTP, VEC_LP20, 0, 0, 0, 0, 0 }; /* IO 710 (DEC) TIOE - test I/O word, skip if zero @@ -396,8 +398,8 @@ struct iolink *p; pa = (int32) ea; /* cvt addr to 32b */ for (p = &iotable[0]; p -> low != 0; p++ ) { - if ((pa >= p -> low) && (pa <= p -> high) && - ((p -> enb == 0) || (dev_enb & p -> enb))) { + if ((pa >= p -> low) && (pa < p -> high) && + ((p -> enb == NULL) || *p -> enb)) { p -> read (&val, pa, READ); pi_eval (); return ((d10) val); } } @@ -411,8 +413,8 @@ struct iolink *p; pa = (int32) ea; /* cvt addr to 32b */ for (p = &iotable[0]; p -> low != 0; p++ ) { - if ((pa >= p -> low) && (pa <= p -> high) && - ((p -> enb == 0) || (dev_enb & p -> enb))) { + if ((pa >= p -> low) && (pa < p -> high) && + ((p -> enb == NULL) || *p -> enb)) { p -> write ((int32) val, pa, mode); pi_eval (); return; } } diff --git a/pdp10_mdfp.c b/pdp10_mdfp.c index f90c3f86..cab690ad 100644 --- a/pdp10_mdfp.c +++ b/pdp10_mdfp.c @@ -91,6 +91,7 @@ format (so-called G floating). These instructions were not implemented in the KS10 and are treated as MUUO's. + 31-Aug-01 RMS Changed int64 to t_int64 for Windoze 10-Aug-01 RMS Removed register in declarations */ @@ -98,10 +99,10 @@ #include struct ufp { /* unpacked fp number */ - int32 sign; /* sign */ - int32 exp; /* exponent */ - uint64 fhi; /* fraction high */ - uint64 flo; }; /* for double prec */ + int32 sign; /* sign */ + int32 exp; /* exponent */ + t_uint64 fhi; /* fraction high */ + t_uint64 flo; }; /* for double prec */ typedef struct ufp UFP; @@ -154,7 +155,7 @@ extern d10 *ac_cur; /* current AC block */ extern int32 flags; /* flags */ void mul (d10 a, d10 b, d10 *rs); void funpack (d10 h, d10 l, UFP *r, t_bool sgn); -void fnorm (UFP *r, int64 rnd); +void fnorm (UFP *r, t_int64 rnd); d10 fpack (UFP *r, d10 *lo, t_bool fdvneg); /* Integer multiply - checked against KS-10 ucode */ @@ -197,9 +198,9 @@ return TRUE; void mul (d10 s1, d10 s2, d10 *rs) { -uint64 a = ABS (s1); -uint64 b = ABS (s2); -uint64 t, u, r; +t_uint64 a = ABS (s1); +t_uint64 b = ABS (s2); +t_uint64 t, u, r; if ((a == 0) || (b == 0)) { /* operand = 0? */ rs[0] = rs[1] = 0; /* result 0 */ @@ -232,7 +233,7 @@ t_bool divi (int32 ac, d10 b, d10 *rs) { int32 p1 = ADDAC (ac, 1); d10 dvr = ABS (b); /* make divr positive */ -int64 t; +t_int64 t; int32 i; d10 dvd[2]; @@ -373,7 +374,7 @@ else { funpack (op1, 0, &a, SFRC); /* unpack operands */ b = t; ediff = -ediff; } if (ediff > 63) ediff = 63; /* cap diff at 63 */ - if (ediff) b.fhi = (int64) b.fhi >> ediff; /* shift b (signed) */ + if (ediff) b.fhi = (t_int64) b.fhi >> ediff; /* shift b (signed) */ a.fhi = a.fhi + b.fhi; /* add fractions */ if (a.sign ^ b.sign) { /* add or subtract? */ if (a.fhi & FP_UCRY) { /* subtract, frac -? */ @@ -420,7 +421,7 @@ return fpack (&a, NULL, FALSE); t_bool fdv (d10 op1, d10 op2, d10 *rs, t_bool rnd) { UFP a, b; -uint64 savhi; +t_uint64 savhi; t_bool rem = FALSE; funpack (op1, 0, &a, AFRC); /* unpack operands */ @@ -479,7 +480,7 @@ return fpack (&a, NULL, FALSE); /* pack result */ void fix (int32 ac, d10 mb, t_bool rnd) { int32 sc; -uint64 so; +t_uint64 so; UFP a; funpack (mb, 0, &a, AFRC); /* unpack operand */ @@ -521,11 +522,11 @@ else { ediff = -ediff; } if (ediff > 127) ediff = 127; /* cap diff at 127 */ if (ediff > 63) { /* diff > 63? */ - a.flo = (int64) b.fhi >> (ediff - 64); /* b hi to a lo */ + a.flo = (t_int64) b.fhi >> (ediff - 64); /* b hi to a lo */ b.fhi = b.sign? FP_ONES: 0; } /* hi = all sign */ else if (ediff) { /* diff <= 63 */ a.flo = (b.flo >> ediff) | (b.fhi << (64 - ediff)); - b.fhi = (int64) b.fhi >> ediff; } /* shift b (signed) */ + b.fhi = (t_int64) b.fhi >> ediff; } /* shift b (signed) */ a.fhi = a.fhi + b.fhi; /* do add */ if (a.sign ^ b.sign) { /* add or subtract? */ if (a.fhi & FP_UCRY) { /* subtract, frac -? */ @@ -552,7 +553,7 @@ return; void dfmp (int32 ac, d10 *rs) { int32 p1 = ADDAC (ac, 1); -uint64 xh, xl, yh, yl, mid; +t_uint64 xh, xl, yh, yl, mid; UFP a, b; funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */ @@ -587,7 +588,7 @@ void dfdv (int32 ac, d10 *rs) { int32 p1 = ADDAC (ac, 1); int32 i; -uint64 qu = 0; +t_uint64 qu = 0; UFP a, b; funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */ @@ -636,10 +637,10 @@ return; /* Normalize and optionally round floating point operand */ -void fnorm (UFP *a, int64 rnd) +void fnorm (UFP *a, t_int64 rnd) { int32 i; -static uint64 normmask[6] = { +static t_uint64 normmask[6] = { 0x6000000000000000, 0x7800000000000000, 0x7F80000000000000, 0x7FFF800000000000, 0x7FFFFFFF80000000, 0x7FFFFFFFFFFFFFFF }; static int32 normtab[7] = { 1, 2, 4, 8, 16, 32, 63 }; diff --git a/pdp10_pt.c b/pdp10_pt.c index 69c998ba..0183b6b4 100644 --- a/pdp10_pt.c +++ b/pdp10_pt.c @@ -25,6 +25,8 @@ ptr paper tape reader ptp paper tape punch + + 07-Sep-01 RMS Revised disable mechanism */ #include "pdp10_defs.h" @@ -34,11 +36,12 @@ #define PTPCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* paper tape punch */ #define PTPCSR_RW (CSR_IE) -extern int32 int_req, dev_enb; +extern int32 int_req; int32 ptr_csr = 0; /* control/status */ int32 ptr_stopioe = 0; /* stop on error */ int32 ptp_csr = 0; /* control/status */ int32 ptp_stopioe = 0; /* stop on error */ +int32 pt_enb = 0; /* device enable */ t_stat ptr_svc (UNIT *uptr); t_stat ptp_svc (UNIT *uptr); t_stat ptr_reset (DEVICE *dptr); @@ -69,7 +72,7 @@ REG ptr_reg[] = { { DRDATA (POS, ptr_unit.pos, 31), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { FLDATA (*DEVENB, dev_enb, INT_V_PTR), REG_HRO }, + { FLDATA (*DEVENB, pt_enb, 0), REG_HRO }, { NULL } }; DEVICE ptr_dev = { @@ -98,7 +101,7 @@ REG ptp_reg[] = { { DRDATA (POS, ptp_unit.pos, 31), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { FLDATA (*DEVENB, dev_enb, INT_V_PTR), REG_HRO }, + { FLDATA (*DEVENB, pt_enb, 0), REG_HRO }, { NULL } }; DEVICE ptp_dev = { diff --git a/pdp10_rp.c b/pdp10_rp.c index 8c5c3c03..41e7eed2 100644 --- a/pdp10_rp.c +++ b/pdp10_rp.c @@ -25,8 +25,14 @@ rp RH/RP/RM moving head disks + 23-Oct-01 RMS Fixed bug in error interrupts + New IO page address constants + 05-Oct-01 RMS Rewrote interrupt handling from schematics + 02-Oct-01 RMS Revised CS1 write code + 30-Sep-01 RMS Moved CS1<5:0> into drives + 28-Sep-01 RMS Fixed interrupt handling for SC/ATA 23-Aug-01 RMS Added read/write header stubs for ITS - (found by Mirian Crzig Lennox) + (found by Mirian Crzig Lennox) 13-Jul-01 RMS Changed fread call to fxread (found by Peter Schorn) 14-May-01 RMS Added check for unattached drive @@ -35,13 +41,19 @@ 100% compatible) family of interfaces into the KS10 Unibus via the RH11 disk controller. - WARNING: This controller is somewhat abstract. It is intended to run - the operating system drivers for the PDP-10 operating systems and - nothing more. Most error and all diagnostic functions have been - omitted. In addition, the controller conflates the RP04/05/06 series - controllers with the RM02/03/05/80 series controllers and with the - RP07 controller. There are actually significant differences, which - have been highlighted where noticed. + WARNING: The interupt logic of the RH11/RH70 is unusual and must be + simulated with great precision. The RH11 has an internal interrupt + request flop, CSTB INTR, which is controlled as follows: + - Writing IE and DONE simultaneously sets CSTB INTR + - Controller clear, INIT, and interrupt acknowledge clear CSTB INTR + (and also clear IE) + - A transition of DONE from 0 to 1 sets CSTB from INTR + The output of INTR is OR'd with the AND of RPCS1 to + create the interrupt request signal. Thus, + - The DONE interrupt is edge sensitive, but the SC interrupt is + level sensitive. + - The DONE interrupt, once set, is not disabled if IE is cleared, + but the SC interrupt is. */ #include "pdp10_defs.h" @@ -89,6 +101,7 @@ #define FNC_PRESET 010 /* read-in preset */ #define FNC_PACK 011 /* pack acknowledge */ #define FNC_SEARCH 014 /* search */ +#define FNC_XFER 024 /* >=? data xfr */ #define FNC_WCHK 024 /* write check */ #define FNC_WRITE 030 /* write */ #define FNC_WRITEH 031 /* write w/ headers */ @@ -104,7 +117,7 @@ #define CS1_TRE 0040000 /* transfer err */ #define CS1_SC 0100000 /* special cond */ #define CS1_MBZ 0012000 -#define CS1_RW (CS1_FNC | CS1_IE | CS1_UAE) +#define CS1_DRV (CS1_FNC | CS1_GO) #define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) #define GET_UAE(x) (((x) & CS1_UAE) << (16 - CS1_V_UAE)) @@ -211,7 +224,7 @@ #define GET_DA(c,fs,d) ((((GET_CY (c) * drv_tab[d].surf) + \ GET_SF (fs)) * drv_tab[d].sect) + GET_SC (fs)) -/* RPCC - 176736 - current cylinder - unimplemented */ +/* RPCC - 176736 - current cylinder */ /* RPER2 - 176740 - error status 2 - drive unsafe conditions - unimplemented */ /* RPER3 - 176742 - error status 3 - more unsafe conditions - unimplemented */ /* RPEC1 - 176744 - ECC status 1 - unimplemented */ @@ -315,6 +328,7 @@ int32 rper2 = 0; /* error status 2 */ int32 rper3 = 0; /* error status 3 */ int32 rpec1 = 0; /* ECC correction 1 */ int32 rpec2 = 0; /* ECC correction 2 */ +int32 rpiff = 0; /* INTR flip/flop */ int32 rp_stopioe = 1; /* stop on error */ int32 rp_swait = 10; /* seek time */ int32 rp_rwait = 10; /* rotate time */ @@ -323,7 +337,7 @@ int reg_in_drive[32] = { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; void update_rpcs (int32 flags, int32 drv); -void rp_go (int32 drv); +void rp_go (int32 drv, int32 fnc); t_stat rp_set_size (UNIT *uptr, int32 value); t_stat rp_svc (UNIT *uptr); t_stat rp_reset (DEVICE *dptr); @@ -371,6 +385,7 @@ REG rp_reg[] = { { ORDATA (RPEC2, rpec2, 16) }, { ORDATA (RPMR, rpmr, 16) }, { ORDATA (RPDB, rpdb, 16) }, + { FLDATA (IFF, rpiff, 0) }, { FLDATA (INT, int_req, INT_V_RP) }, { FLDATA (SC, rpcs1, CSR_V_ERR) }, { FLDATA (DONE, rpcs1, CSR_V_DONE) }, @@ -393,6 +408,14 @@ REG rp_reg[] = { { ORDATA (RPDE5, rper1[5], 16) }, { ORDATA (RPDE6, rper1[6], 16) }, { ORDATA (RPDE7, rper1[7], 16) }, + { ORDATA (RPFN0, rp_unit[0].FUNC, 5), REG_HRO }, + { ORDATA (RPFN1, rp_unit[1].FUNC, 5), REG_HRO }, + { ORDATA (RPFN2, rp_unit[2].FUNC, 5), REG_HRO }, + { ORDATA (RPFN3, rp_unit[3].FUNC, 5), REG_HRO }, + { ORDATA (RPFN4, rp_unit[4].FUNC, 5), REG_HRO }, + { ORDATA (RPFN5, rp_unit[5].FUNC, 5), REG_HRO }, + { ORDATA (RPFN6, rp_unit[6].FUNC, 5), REG_HRO }, + { ORDATA (RPFN7, rp_unit[7].FUNC, 5), REG_HRO }, { GRDATA (FLG0, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), REG_HRO }, { GRDATA (FLG1, rp_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), @@ -550,9 +573,11 @@ return SCPE_OK; t_stat rp_wr (int32 data, int32 PA, int32 access) { int32 cs1f, drv, i, j; +UNIT *uptr; cs1f = 0; /* no int on cs1 upd */ drv = GET_UNIT (rpcs2); /* get current unit */ +uptr = rp_dev.units + drv; /* get unit */ j = (PA >> 1) & 037; /* get reg offset */ if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */ rpcs2 = rpcs2 | CS2_NED; /* set error flag */ @@ -566,17 +591,27 @@ if (reg_in_drive[j] && sim_is_active (&rp_unit[drv])) { /* unit busy? */ switch (j) { /* decode PA<5:1> */ case 000: /* RPCS1 */ if ((access == WRITEB) && (PA & 1)) data = data << 8; - else { if ((data & CS1_IE) == 0) int_req = int_req & ~INT_RP; - else if (data & CS1_DONE) int_req = int_req | INT_RP; } if (data & CS1_TRE) { /* error clear? */ rpcs1 = rpcs1 & ~CS1_TRE; /* clr CS1 */ rpcs2 = rpcs2 & ~CS2_ERR; } /* clr CS2<15:8> */ - if (access == WRITEB) data = (rpcs1 & /* merge data */ - ((PA & 1)? 0377: 0177400)) | data; - rpcs1 = (rpcs1 & ~CS1_RW) | (data & CS1_RW); - if (data & CS1_GO) { /* new command? */ - if (rpcs1 & CS1_DONE) rp_go (drv); /* start if not busy */ - else rpcs2 = rpcs2 | CS2_PGE; } /* else prog error */ + if ((access == WRITE) || (PA & 1)) { /* hi byte write? */ + if (rpcs1 & CS1_DONE) /* done set? */ + rpcs1 = (rpcs1 & ~CS1_UAE) | (data & CS1_UAE); } + if ((access == WRITE) || !(PA & 1)) { /* lo byte write? */ + if ((data & CS1_DONE) && (data & CS1_IE)) /* to DONE+IE? */ + rpiff = 1; /* set CSTB INTR */ + rpcs1 = (rpcs1 & ~CS1_IE) | (data & CS1_IE); + if (uptr -> flags & UNIT_DIS) { /* nx disk? */ + rpcs2 = rpcs2 | CS2_NED; /* set error flag */ + cs1f = CS1_SC; } /* req interrupt */ + else if (sim_is_active (uptr)) + rper1[drv] = rper1[drv] | ER1_RMR; /* won't write */ + else if (data & CS1_GO) { /* start op */ + uptr -> FUNC = GET_FNC (data); /* set func */ + if ((uptr -> FUNC >= FNC_XFER) && /* data xfer and */ + ((rpcs1 & CS1_DONE) == 0)) /* ~rdy? PGE */ + rpcs2 = rpcs2 | CS2_PGE; + else rp_go (drv, uptr -> FUNC); } } break; case 001: /* RPWC */ if (access == WRITEB) data = (PA & 1)? @@ -650,29 +685,23 @@ update_rpcs (cs1f, drv); /* update status */ return SCPE_OK; } -/* Initiate operation */ +/* Initiate operation - unit not busy, function set */ -void rp_go (int32 drv) +void rp_go (int32 drv, int32 fnc) { -int32 dc, dtype, fnc; +int32 dc, dtype, t; UNIT *uptr; -fnc = GET_FNC (rpcs1); /* get function */ uptr = rp_dev.units + drv; /* get unit */ if (uptr -> flags & UNIT_DIS) { /* nx unit? */ rpcs2 = rpcs2 | CS2_NED; /* set error flag */ update_rpcs (CS1_SC, drv); /* request intr */ return; } -if (fnc != FNC_DCLR) { /* not clear? */ - if ((rpds[drv] & DS_ERR) || /* error or */ - ((rpds[drv] & DS_RDY) == 0)) { /* not ready? */ - rpcs2 = rpcs2 | CS2_PGE; /* set error flag */ - update_rpcs (CS1_SC, drv); /* request intr */ - return; } - if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ - rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ - update_rpcs (CS1_SC, drv); /* request intr */ - return; } } +if ((fnc != FNC_DCLR) && (rpds[drv] & DS_ERR)) { /* err & ~clear? */ + rper1[drv] = rper1[drv] | ER1_ILF; /* not allowed */ + rpds[drv] = rpds[drv] | DS_ATA; /* set attention */ + update_rpcs (CS1_SC, drv); /* request intr */ + return; } dtype = GET_DTYPE (uptr -> flags); /* get drive type */ rpds[drv] = rpds[drv] & ~DS_ATA; /* clear attention */ dc = rpdc; /* assume seek, sch */ @@ -695,7 +724,9 @@ case FNC_PACK: /* pack acknowledge */ case FNC_OFFSET: /* offset mode */ case FNC_RETURN: - uptr -> FUNC = fnc; /* save function */ + if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ + rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ + break; } rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ sim_activate (uptr, rp_swait); /* time operation */ return; @@ -705,40 +736,46 @@ case FNC_RECAL: /* recalibrate */ dc = 0; /* seek to 0 */ case FNC_SEEK: /* seek */ case FNC_SEARCH: /* search */ + if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ + rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ + break; } if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ (GET_SF (rpda) >= drv_tab[dtype].surf) || /* bad surface */ (GET_SC (rpda) >= drv_tab[dtype].sect)) { /* or bad sector? */ rper1[drv] = rper1[drv] | ER1_IAE; break; } rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ - sim_activate (uptr, rp_swait * abs (dc - uptr -> CYL)); - uptr -> FUNC = fnc; /* save function */ + t = abs (dc - uptr -> CYL); /* cyl diff */ + if (t == 0) t = 1; /* min time */ + sim_activate (uptr, rp_swait * t); /* schedule */ uptr -> CYL = dc; /* save cylinder */ return; -case FNC_WRITEH: /* write headers */ +case FNC_WRITEH: /* write headers */ case FNC_WRITE: /* write */ case FNC_WCHK: /* write check */ case FNC_READ: /* read */ case FNC_READH: /* read headers */ + if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ + rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ + break; } rpcs2 = rpcs2 & ~CS2_ERR; /* clear errors */ rpcs1 = rpcs1 & ~(CS1_TRE | CS1_MCPE | CS1_DONE); if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ (GET_SF (rpda) >= drv_tab[dtype].surf) || /* bad surface */ (GET_SC (rpda) >= drv_tab[dtype].sect)) { /* or bad sector? */ rper1[drv] = rper1[drv] | ER1_IAE; - update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */ - return; } + break; } rpds[drv] = rpds[drv] & ~DS_RDY; /* clear drive rdy */ sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr -> CYL))); - uptr -> FUNC = fnc; /* save function */ uptr -> CYL = dc; /* save cylinder */ return; default: /* all others */ rper1[drv] = rper1[drv] | ER1_ILF; /* not supported */ break; } -update_rpcs (CS1_SC, drv); /* error, interrupt */ +rpds[drv] = rpds[drv] | DS_ATA; /* error, set attn */ +update_rpcs (CS1_SC, drv); /* req intr */ return; } @@ -870,21 +907,28 @@ case FNC_READH: /* read headers */ perror ("RP I/O error"); clearerr (uptr -> fileref); return SCPE_IOERR; } -case FNC_WRITEH: /* write headers stub */ +case FNC_WRITEH: /* write headers stub */ update_rpcs (CS1_DONE, drv); /* set done */ break; } /* end case func */ return SCPE_OK; } -/* Controller status update - First update drive status, then update RPCS1 - If optional argument, request interrupt +/* Controller status update + + Check for done transition + Update drive status + Update RPCS1 + Update interrupt request */ void update_rpcs (int32 flag, int32 drv) { int32 i; +UNIT *uptr; +if ((flag & ~rpcs1) & CS1_DONE) /* DONE 0 to 1? */ + rpiff = (rpcs1 & CS1_IE)? 1: 0; /* CSTB INTR <- IE */ +uptr = rp_dev.units + drv; /* get unit */ if (rp_unit[drv].flags & UNIT_DIS) rpds[drv] = rper1[drv] = 0; else rpds[drv] = (rpds[drv] | DS_DPR) & ~DS_PGM; if (rp_unit[drv].flags & UNIT_ATT) rpds[drv] = rpds[drv] | DS_MOL; @@ -892,13 +936,16 @@ else rpds[drv] = rpds[drv] & ~(DS_MOL | DS_VV | DS_RDY); if (rper1[drv] | rper2 | rper3) rpds[drv] = rpds[drv] | DS_ERR | DS_ATA; else rpds[drv] = rpds[drv] & ~DS_ERR; -rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ)) | CS1_DVA | flag; +rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ | CS1_DRV)) | CS1_DVA | flag; +rpcs1 = rpcs1 | (uptr -> FUNC << CS1_V_FNC); +if (sim_is_active (uptr)) rpcs1 = rpcs1 | CS1_GO; if (rpcs2 & CS2_ERR) rpcs1 = rpcs1 | CS1_TRE | CS1_SC; +else if (rpcs1 & CS1_TRE) rpcs1 = rpcs1 | CS1_SC; for (i = 0; i < RP_NUMDR; i++) if (rpds[i] & DS_ATA) rpcs1 = rpcs1 | CS1_SC; -if (((rpcs1 & CS1_IE) == 0) || ((rpcs1 & CS1_DONE) == 0)) - int_req = int_req & ~INT_RP; -else if (flag) int_req = int_req | INT_RP; +if (rpiff || ((rpcs1 & CS1_SC) && (rpcs1 & CS1_DONE) && (rpcs1 & CS1_IE))) + int_req = int_req | INT_RP; +else int_req = int_req & ~INT_RP; return; } @@ -907,6 +954,7 @@ return; int32 rp_inta (void) { rpcs1 = rpcs1 & ~CS1_IE; /* clear int enable */ +rpiff = 0; /* clear CSTB INTR */ return VEC_RP; /* acknowledge */ } @@ -923,7 +971,8 @@ rpba = rpda = 0; rpof = rpdc = 0; rper2 = rper3 = 0; rpec1 = rpec2 = 0; -int_req = int_req & ~INT_RP; +rpiff = 0; /* clear CSTB INTR */ +int_req = int_req & ~INT_RP; /* clear intr req */ for (i = 0; i < RP_NUMDR; i++) { uptr = rp_dev.units + i; sim_cancel (uptr); @@ -998,8 +1047,8 @@ return SCPE_OK; static const d10 boot_rom_dec[] = { 0515040000001, /* boot:hrlzi 1,1 ; uba # */ 0201000140001, /* movei 0,140001 ; vld,fst,pg 1 */ - 0713001000000+IO_UBMAP+1, /* wrio 0,763001(1); set ubmap */ - 0435040000000+IO_RHBASE, /* iori 1,776700 ; rh addr */ + 0713001000000+IOBA_UBMAP+1, /* wrio 0,763001(1); set ubmap */ + 0435040000000+IOBA_RP, /* iori 1,776700 ; rh addr */ 0202040000000+FE_RHBASE, /* movem 1,FE_RHBASE */ 0201000000040, /* movei 0,40 ; ctrl reset */ 0713001000010, /* wrio 0,10(1) ; ->RPCS2 */ @@ -1045,8 +1094,8 @@ static const d10 boot_rom_dec[] = { static const d10 boot_rom_its[] = { 0515040000001, /* boot:hrlzi 1,1 ; uba # */ 0201000140001, /* movei 0,140001 ; vld,fst,pg 1 */ - 0715000000000+IO_UBMAP+1, /* iowrq 0,763001 ; set ubmap */ - 0435040000000+IO_RHBASE, /* iori 1,776700 ; rh addr */ + 0715000000000+IOBA_UBMAP+1, /* iowrq 0,763001 ; set ubmap */ + 0435040000000+IOBA_RP, /* iori 1,776700 ; rh addr */ 0202040000000+FE_RHBASE, /* movem 1,FE_RHBASE */ 0201000000040, /* movei 0,40 ; ctrl reset */ 0715001000010, /* iowrq 0,10(1) ; ->RPCS2 */ diff --git a/pdp10_sys.c b/pdp10_sys.c index eca757dc..a8cc6f5f 100644 --- a/pdp10_sys.c +++ b/pdp10_sys.c @@ -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. + 17-Sep-01 RMS Removed multiconsole support 25-Aug-01 RMS Enabled DZ11 27-May-01 RMS Added multiconsole support 29-Apr-01 RMS Fixed format for RDPCST, WRPCST @@ -52,7 +53,6 @@ extern a10 saved_PC; sim_PC pointer to saved PC register descriptor sim_emax number of words for examine sim_devices array of pointers to simulated devices - sim_consoles array of pointers to consoles (if more than one) sim_stop_messages array of pointers to stop messages sim_load binary loader */ @@ -77,8 +77,6 @@ DEVICE *sim_devices[] = { &tu_dev, NULL }; -UNIT *sim_consoles = NULL; - const char *sim_stop_messages[] = { "Unknown error", "HALT instruction", diff --git a/pdp10_tim.c b/pdp10_tim.c index a6c50eef..6d23f21f 100644 --- a/pdp10_tim.c +++ b/pdp10_tim.c @@ -25,6 +25,7 @@ tim timer subsystem + 31-Aug-01 RMS Changed int64 to t_int64 for Windoze 17-Jul-01 RMS Moved function prototype 04-Jul-01 RMS Added DZ11 support */ @@ -45,12 +46,12 @@ extern int32 apr_flg, pi_act; extern UNIT cpu_unit; extern d10 pcst; extern a10 pager_PC; -int64 timebase = 0; /* 71b timebase */ +t_int64 timebase = 0; /* 71b timebase */ d10 ttg = 0; /* time to go */ d10 period = 0; /* period */ d10 quant = 0; /* ITS quantum */ int32 diagflg = 0; /* diagnostics? */ -int32 dz_poll = TIM_DELAY * DZ_MULT; /* DZ11 poll */ +int32 tmxr_poll = TIM_DELAY * DZ_MULT; /* term mux poll */ t_stat tim_svc (UNIT *uptr); t_stat tim_reset (DEVICE *dptr); @@ -132,7 +133,7 @@ int32 t; t = diagflg? tim_unit.wait: sim_rtc_calb (TIM_TPS); /* calibrate clock */ sim_activate (&tim_unit, t); /* reactivate unit */ -dz_poll = t * DZ_MULT; /* set DZ poll */ +tmxr_poll = t * DZ_MULT; /* set mux poll */ timebase = (timebase + 1) & TB_MASK; /* increment timebase */ ttg = ttg - TIM_HWRE; /* decrement timer */ if (ttg <= 0) { /* timeout? */ @@ -152,7 +153,7 @@ t_stat tim_reset (DEVICE *dptr) period = ttg = 0; /* clear timer */ apr_flg = apr_flg & ~APRF_TIM; /* clear interrupt */ sim_activate (&tim_unit, tim_unit.wait); /* activate unit */ -dz_poll = tim_unit.wait * DZ_MULT; /* set DZ poll */ +tmxr_poll = tim_unit.wait * DZ_MULT; /* set mux poll */ return SCPE_OK; } diff --git a/pdp10_tu.c b/pdp10_tu.c index 2ea54a5a..b2b9b2e6 100644 --- a/pdp10_tu.c +++ b/pdp10_tu.c @@ -25,6 +25,11 @@ tu RH11/TM03/TU45 magtape + 23-Oct-01 RMS Fixed bug in error interrupts + New IO page address constants + 05-Oct-01 RMS Rewrote interrupt handling from schematics + 30-Sep-01 RMS Fixed handling of non-existent formatters + 28-Sep-01 RMS Fixed interrupt handling for SC/ATA 4-May-01 RMS Fixed bug in odd address test 3-May-01 RMS Fixed drive reset to clear SSC @@ -42,6 +47,20 @@ 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. + + WARNING: The interupt logic of the RH11/RH70 is unusual and must be + simulated with great precision. The RH11 has an internal interrupt + request flop, CSTB INTR, which is controlled as follows: + - Writing IE and DONE simultaneously sets CSTB INTR + - Controller clear, INIT, and interrupt acknowledge clear CSTB INTR + (and also clear IE) + - A transition of DONE from 0 to 1 sets CSTB from INTR + The output of INTR is OR'd with the AND of RPCS1 to + create the interrupt request signal. Thus, + - The DONE interrupt is edge sensitive, but the SC interrupt is + level sensitive. + - The DONE interrupt, once set, is not disabled if IE is cleared, + but the SC interrupt is. */ #include "pdp10_defs.h" @@ -71,6 +90,7 @@ #define FNC_WREOF 013 /* write tape mark */ #define FNC_SPACEF 014 /* space forward */ #define FNC_SPACER 015 /* space reverse */ +#define FNC_XFER 024 /* >=? data xfr */ #define FNC_WCHKF 024 /* write check */ #define FNC_WCHKR 027 /* write check rev */ #define FNC_WRITE 030 /* write */ @@ -86,7 +106,7 @@ #define CS1_TRE 0040000 /* transfer err */ #define CS1_SC 0100000 /* special cond */ #define CS1_MBZ 0012000 -#define CS1_RW (CS1_FNC | CS1_IE | CS1_UAE | CS1_GO) +#define CS1_DRV (CS1_FNC | CS1_GO) #define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) #define GET_UAE(x) (((x) & CS1_UAE) << (16 - CS1_V_UAE)) @@ -224,6 +244,7 @@ (((b) & XBA_ODD) != ((od) << 1))) { \ tucs2 = tucs2 | CS2_NEM; \ ubcs[1] = ubcs[1] | UBCS_TMO; \ + tucs1 = tucs1 & ~CS1_GO; \ update_tucs (CS1_DONE, drv); \ return SCPE_OK; } #define NEWPAGE(v,m) (((v) & PAG_M_OFF) == (m)) @@ -257,6 +278,7 @@ int32 tucc = 0; /* check character */ int32 tudb = 0; /* data buffer */ int32 tumr = 0; /* maint register */ int32 tutc = 0; /* tape control */ +int32 tuiff = 0; /* INTR flip/flop */ int32 tu_time = 10; /* record latency */ int32 tu_stopioe = 1; /* stop on error */ int32 tu_log = 0; /* debug */ @@ -310,6 +332,7 @@ REG tu_reg[] = { { ORDATA (MTDB, tudb, 16) }, { ORDATA (MTMR, tumr, 16) }, { ORDATA (MTTC, tutc, 16) }, + { FLDATA (IFF, tuiff, 0) }, { FLDATA (INT, int_req, INT_V_TU) }, { FLDATA (DONE, tucs1, CSR_V_DONE) }, { FLDATA (IE, tucs1, CSR_V_IE) }, @@ -379,7 +402,8 @@ if (reg_in_fmtr[j] && (fmtr != 0)) { /* nx formatter */ update_tucs (0, drv); /* update status */ switch (j) { /* decode PA<4:1> */ case 000: /* MTCS1 */ - *data = tucs1; + if (fmtr != 0) *data = tucs1 & ~CS1_DRV; + else *data = tucs1; break; case 001: /* MTWC */ *data = tuwc; @@ -448,21 +472,24 @@ if (reg_in_fmtr1[j] && ((tucs1 & CS1_DONE) == 0)) { /* formatter busy? */ switch (j) { /* decode PA<4:1> */ case 000: /* MTCS1 */ if ((access == WRITEB) && (PA & 1)) data = data << 8; - else { if ((data & CS1_IE) == 0) int_req = int_req & ~INT_TU; - else if (data & CS1_DONE) int_req = int_req | INT_TU; } if (data & CS1_TRE) { /* error clear? */ tucs1 = tucs1 & ~CS1_TRE; /* clr CS1 */ tucs2 = tucs2 & ~CS2_ERR; } /* clr CS2<15:8> */ - if (access == WRITEB) data = (tucs1 & /* merge data */ - ((PA & 1)? 0377: 0177400)) | data; - tucs1 = (tucs1 & ~CS1_RW) | (data & CS1_RW); - if (data & CS1_GO) { /* new command? */ + if ((access == WRITE) || (PA & 1)) { /* hi byte write? */ + if (tucs1 & CS1_DONE) /* done set? */ + tucs1 = (tucs1 & ~CS1_UAE) | (data & CS1_UAE); } + if ((access == WRITE) || !(PA & 1)) { /* lo byte write? */ + if ((data & CS1_DONE) && (data & CS1_IE)) /* to DONE+IE? */ + tuiff = 1; /* set CSTB INTR */ + tucs1 = (tucs1 & ~CS1_IE) | (data & CS1_IE); if (fmtr != 0) { /* nx formatter? */ tucs2 = tucs2 | CS2_NEF; /* set error flag */ - update_tucs (CS1_SC, drv); /* request intr */ - return SCPE_OK; } - if (tucs1 & CS1_DONE) tu_go (drv); /* start if not busy */ - else tucs2 = tucs2 | CS2_PGE; } /* else prog error */ + cs1f = CS1_SC; } /* req interrupt */ + else if (tucs1 & CS1_GO) { /* busy? */ + if (tucs1 & CS1_DONE) tuer = tuer | ER_RMR; + else tucs2 = tucs2 | CS2_PGE; } + else { tucs1 = (tucs1 & ~CS1_DRV) | (data & CS1_DRV); + if (tucs1 & CS1_GO) tu_go (drv); } } break; case 001: /* MTWC */ if (access == WRITEB) data = (PA & 1)? @@ -533,8 +560,10 @@ fnc = GET_FNC (tucs1); /* get function */ den = GET_DEN (tutc); /* get density */ uptr = tu_dev.units + drv; /* get unit */ if ((fnc != FNC_FCLR) && /* not clear & err */ - ((tufs & FS_ERR) || sim_is_active (uptr))) { /* or in motion? */ - tucs2 = tucs2 | CS2_PGE; /* set error flag */ + ((tufs & FS_ERR) || sim_is_active (uptr))) { /* or in motion? */ + tuer = tuer | ER_ILF; /* set error flag */ + tufs = tufs | FS_ATA; /* exception */ + tucs1 = tucs1 & ~CS1_GO; /* clear go */ update_tucs (CS1_SC, drv); /* request intr */ return; } tufs = tufs & ~FS_ATA; /* clear attention */ @@ -621,9 +650,10 @@ DATA_XFER: /* tuer = tuer | ER_NXF; /* break; } */ uptr -> USTAT = 0; + tucs1 = tucs1 & ~CS1_DONE; /* clear done */ GO_XFER: tucs2 = tucs2 & ~CS2_ERR; /* clear errors */ - tucs1 = tucs1 & ~(CS1_TRE | CS1_MCPE | CS1_DONE); + tucs1 = tucs1 & ~(CS1_TRE | CS1_MCPE); tufs = tufs & ~(FS_TMK | FS_ID); /* clear eof, id */ sim_activate (uptr, tu_time); return; @@ -631,7 +661,9 @@ GO_XFER: default: /* all others */ tuer = tuer | ER_ILF; /* not supported */ break; } /* end case function */ -update_tucs (CS1_SC, drv); /* error, set intr */ +tucs1 = tucs1 & ~CS1_GO; /* clear go */ +tufs = tufs | FS_ATA; /* set attn */ +update_tucs (CS1_SC, drv); /* set intr */ return; } @@ -851,15 +883,20 @@ update_tucs (CS1_DONE, drv); return SCPE_OK; } -/* Controller status update - First update formatter status, then update MTCS1 - If optional argument, request interrupt +/* Controller status update + + Check for done transition + Update drive status + Update MTCS1 + Update interrupt request */ void update_tucs (int32 flag, int32 drv) { int32 act = sim_is_active (&tu_unit[drv]); +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].flags & UNIT_ATT) { @@ -871,10 +908,11 @@ if (GET_FMTR (tucs2) == 0) { /* formatter present? */ else tufs = 0; tucs1 = (tucs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ)) | CS1_DVA | flag; if (tucs2 & CS2_ERR) tucs1 = tucs1 | CS1_TRE | CS1_SC; +else if (tucs1 & CS1_TRE) tucs1 = tucs1 | CS1_SC; if (tufs & FS_ATA) tucs1 = tucs1 | CS1_SC; -if (((tucs1 & CS1_IE) == 0) || ((tucs1 & CS1_DONE) == 0)) - int_req = int_req & ~INT_TU; -else if (flag) int_req = int_req | INT_TU; +if (tuiff || ((tucs1 & CS1_SC) && (tucs1 & CS1_DONE) && (tucs1 & CS1_IE))) + int_req = int_req | INT_TU; +else int_req = int_req & ~INT_TU; if ((tucs1 & CS1_DONE) && tufs && !act) tufs = tufs | FS_RDY; return; } @@ -884,6 +922,7 @@ return; int32 tu_inta (void) { tucs1 = tucs1 & ~CS1_IE; /* clear int enable */ +tuiff = 0; /* clear CSTB INTR */ return VEC_TU; /* acknowledge */ } @@ -899,6 +938,7 @@ tucs2 = CS2_IR | CS2_OR; tuba = tufc = 0; tutc = tuer = 0; tufs = FS_FPR | FS_RDY; +tuiff = 0; /* clear CSTB INTR */ int_req = int_req & ~INT_TU; /* clear interrupt */ for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */ uptr = tu_dev.units + u; @@ -958,8 +998,8 @@ return SCPE_OK; static const d10 boot_rom_dec[] = { 0515040000003, /* boot:hrlzi 1,3 ; uba # */ 0201000040001, /* movei 0,40001 ; vld,pg 1 */ - 0713001000000+IO_UBMAP+1, /* wrio 0,763001(1); set ubmap */ - 0435040000000+IO_TMBASE, /* iori 1,772440 ; rh addr */ + 0713001000000+IOBA_UBMAP+1, /* wrio 0,763001(1); set ubmap */ + 0435040000000+IOBA_TU, /* iori 1,772440 ; rh addr */ 0202040000000+FE_RHBASE, /* movem 1,FE_RHBASE */ 0201000000040, /* movei 0,40 ; ctrl reset */ 0713001000010, /* wrio 0,10(1) ; ->MTFS */ @@ -996,8 +1036,8 @@ static const d10 boot_rom_dec[] = { static const d10 boot_rom_its[] = { 0515040000003, /* boot:hrlzi 1,3 ; uba # - not used */ 0201000040001, /* movei 0,40001 ; vld,pg 1 */ - 0714000000000+IO_UBMAP+1, /* iowri 0,763001 ; set ubmap */ - 0435040000000+IO_TMBASE, /* iori 1,772440 ; rh addr */ + 0714000000000+IOBA_UBMAP+1, /* iowri 0,763001 ; set ubmap */ + 0435040000000+IOBA_TU, /* iori 1,772440 ; rh addr */ 0202040000000+FE_RHBASE, /* movem 1,FE_RHBASE */ 0201000000040, /* movei 0,40 ; ctrl reset */ 0714001000010, /* iowri 0,10(1) ; ->MTFS */ diff --git a/pdp11_cpu.c b/pdp11_cpu.c index 228e15e6..cb5f76a4 100644 --- a/pdp11_cpu.c +++ b/pdp11_cpu.c @@ -25,9 +25,13 @@ cpu PDP-11 CPU (J-11 microprocessor) + 15-Oct-01 RMS Added debug logging + 08-Oct-01 RMS Fixed bug in revised interrupt logic + 07-Sep-01 RMS Revised device disable and interrupt mechanisms + 26-Aug-01 RMS Added DZ11 support 10-Aug-01 RMS Removed register from declarations 17-Jul-01 RMS Fixed warning from VC++ 6.0 - 01-Jun-01 RMS Added DZ11 support + 01-Jun-01 RMS Added DZ11 interrupts 23-Apr-01 RMS Added RK611 support 05-Apr-01 RMS Added TS11/TSV05 support 05-Mar-01 RMS Added clock calibration support @@ -151,8 +155,8 @@ lowest priority trap. Traps are processed by trap_vec and trap_clear, which provide the vector and subordinate traps to clear, respectively. - Variable int_req bit encodes all possible interrupts. It is masked - under the interrupt masks, int_mask[ipl]. If any interrupt request + Array int_req[0:7] bit encodes all possible interrupts. It is masked + under the interrupt priority level, ipl. If any interrupt request is not masked, the interrupt bit is set in trap_req. While most interrupts are handled centrally, a device can supply an interrupt acknowledge routine. @@ -176,8 +180,6 @@ #define calc_is(md) ((md) << VA_V_MODE) #define calc_ds(md) (calc_is((md)) | ((MMR3 & dsmask[(md)])? VA_DS: 0)) #define calc_MMR1(val) (MMR1 = MMR1? ((val) << 8) | MMR1: (val)) -#define calc_ints(lv,rq,tr) (((rq) & int_mask[(lv)])? \ - ((tr) | TRAP_INT) : ((tr) & ~TRAP_INT)) #define GET_SIGN_W(v) ((v) >> 15) #define GET_SIGN_B(v) ((v) >> 7) #define GET_Z(v) ((v) == 0) @@ -196,6 +198,8 @@ /* Global state */ +extern FILE *sim_log; + uint16 *M = NULL; /* address of memory */ int32 REGFILE[6][2] = { 0 }; /* R0-R5, two sets */ int32 STACKFILE[4] = { 0 }; /* SP, four modes */ @@ -210,7 +214,7 @@ int32 PSW = 0; /* PSW */ int32 N = 0, Z = 0, V = 0, C = 0; /* condition codes */ int32 wait_state = 0; /* wait state */ int32 trap_req = 0; /* trap requests */ -int32 int_req = 0; /* interrupt requests */ +int32 int_req[IPL_HLVL] = { 0 }; /* interrupt requests */ int32 PIRQ = 0; /* programmed int req */ int32 SR = 0; /* switch register */ int32 DR = 0; /* display register */ @@ -235,13 +239,13 @@ int32 stop_trap = 1; /* stop on trap */ int32 stop_vecabort = 1; /* stop on vec abort */ int32 stop_spabort = 1; /* stop on SP abort */ int32 wait_enable = 0; /* wait state enable */ +int32 pdp11_log = 0; /* logging */ int32 ibkpt_addr = ILL_ADR_FLAG | VAMASK; /* breakpoint addr */ int32 old_PC = 0; /* previous PC */ int32 dev_enb = (-1) & ~INT_TS; /* dev enables */ jmp_buf save_env; /* abort handler */ int32 dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS }; /* dspace enables */ -uint32 int_mask[8] = { INT_IPL0, INT_IPL1, INT_IPL2, /* interrupt masks */ - INT_IPL3, INT_IPL4, INT_IPL5, INT_IPL6, INT_IPL7 }; + extern int32 sim_int_char; /* Function declarations */ @@ -265,6 +269,7 @@ void PWriteW (int32 data, int32 addr); void PWriteB (int32 data, int32 addr); t_stat iopageR (int32 *data, int32 addr, int32 access); t_stat iopageW (int32 data, int32 addr, int32 access); +int32 calc_ints (int32 nipl, int32 trq); t_stat CPU_rd (int32 *data, int32 addr, int32 access); t_stat CPU_wr (int32 data, int32 addr, int32 access); @@ -278,64 +283,87 @@ extern t_stat std_rd (int32 *data, int32 addr, int32 access); extern t_stat std_wr (int32 data, int32 addr, int32 access); extern t_stat lpt_rd (int32 *data, int32 addr, int32 access); extern t_stat lpt_wr (int32 data, int32 addr, int32 access); +extern t_stat dz_rd (int32 *data, int32 addr, int32 access); +extern t_stat dz_wr (int32 data, int32 addr, int32 access); extern t_stat rk_rd (int32 *data, int32 addr, int32 access); extern t_stat rk_wr (int32 data, int32 addr, int32 access); extern int32 rk_inta (void); +extern int32 rk_enb; /* extern t_stat hk_rd (int32 *data, int32 addr, int32 access); extern t_stat hk_wr (int32 data, int32 addr, int32 access); -extern int32 hk_inta (void); */ +extern int32 hk_inta (void); +extern int32 hk_enb; */ extern t_stat rl_rd (int32 *data, int32 addr, int32 access); extern t_stat rl_wr (int32 data, int32 addr, int32 access); +extern int32 rl_enb; extern t_stat rp_rd (int32 *data, int32 addr, int32 access); extern t_stat rp_wr (int32 data, int32 addr, int32 access); extern int32 rp_inta (void); +extern int32 rp_enb; extern t_stat rx_rd (int32 *data, int32 addr, int32 access); extern t_stat rx_wr (int32 data, int32 addr, int32 access); +extern int32 rx_enb; extern t_stat dt_rd (int32 *data, int32 addr, int32 access); extern t_stat dt_wr (int32 data, int32 addr, int32 access); +extern int32 dt_enb; extern t_stat tm_rd (int32 *data, int32 addr, int32 access); extern t_stat tm_wr (int32 data, int32 addr, int32 access); +extern int32 tm_enb; extern t_stat ts_rd (int32 *data, int32 addr, int32 access); extern t_stat ts_wr (int32 data, int32 addr, int32 access); +extern int32 ts_enb; /* Auxiliary data structures */ struct iolink { /* I/O page linkage */ int32 low; /* low I/O addr */ int32 high; /* high I/O addr */ - int32 enb; /* enable mask */ + int32 *enb; /* enable flag */ t_stat (*read)(); /* read routine */ t_stat (*write)(); }; /* write routine */ struct iolink iotable[] = { - { 017777740, 017777777, 0, &CPU_rd, &CPU_wr }, - { 017777546, 017777567, 0, &std_rd, &std_wr }, - { 017777514, 017777517, 0, &lpt_rd, &lpt_wr }, - { 017777400, 017777417, INT_RK, &rk_rd, &rk_wr }, -/* { 017777440, 017777477, INT_HK, &hk_rd, &hk_wr }, */ - { 017774400, 017774411, INT_RL, &rl_rd, &rl_wr }, - { 017776700, 017776753, INT_RP, &rp_rd, &rp_wr }, - { 017777170, 017777173, INT_RX, &rx_rd, &rx_wr }, - { 017777340, 017777351, INT_DTA, &dt_rd, &dt_wr }, - { 017772520, 017772533, INT_TM, &tm_rd, &tm_wr }, - { 017772520, 017772523, INT_TS, &ts_rd, &ts_wr }, - { 017777600, 017777677, 0, &APR_rd, &APR_wr }, - { 017772200, 017772377, 0, &APR_rd, &APR_wr }, - { 017777570, 017777577, 0, &SR_MMR012_rd, &SR_MMR012_wr }, - { 017772516, 017772517, 0, &MMR3_rd, &MMR3_wr }, - { 0, 0, 0, NULL, NULL } }; + { 017777740, 017777777, NULL, &CPU_rd, &CPU_wr }, + { 017777546, 017777567, NULL, &std_rd, &std_wr }, + { 017777514, 017777517, NULL, &lpt_rd, &lpt_wr }, + { 017760100, 017760107, NULL, &dz_rd, &dz_wr }, + { 017777400, 017777417, &rk_enb, &rk_rd, &rk_wr }, +/* { 017777440, 017777477, &hk_enb, &hk_rd, &hk_wr }, */ + { 017774400, 017774411, &rl_enb, &rl_rd, &rl_wr }, + { 017776700, 017776753, &rp_enb, &rp_rd, &rp_wr }, + { 017777170, 017777173, &rx_enb, &rx_rd, &rx_wr }, + { 017777340, 017777351, &dt_enb, &dt_rd, &dt_wr }, + { 017772520, 017772533, &tm_enb, &tm_rd, &tm_wr }, + { 017772520, 017772523, &ts_enb, &ts_rd, &ts_wr }, + { 017777600, 017777677, NULL, &APR_rd, &APR_wr }, + { 017772200, 017772377, NULL, &APR_rd, &APR_wr }, + { 017777570, 017777577, NULL, &SR_MMR012_rd, &SR_MMR012_wr }, + { 017772516, 017772517, NULL, &MMR3_rd, &MMR3_wr }, + { 0, 0, NULL, NULL, NULL } }; -int32 int_vec[32] = { /* int req to vector */ - 0, 0, 0, VEC_PIRQ, VEC_CLK, VEC_DTA, 0, VEC_PIRQ, - VEC_RK, VEC_RL, VEC_RX, VEC_TM, VEC_RP, VEC_TS, VEC_HK, 0, - VEC_DZ0RX, VEC_DZ0TX, 0, VEC_PIRQ, VEC_TTI, VEC_TTO, VEC_PTR, VEC_PTP, - VEC_LPT, 0, 0, 0, VEC_PIRQ, VEC_PIRQ, VEC_PIRQ, VEC_PIRQ }; +int32 int_vec[IPL_HLVL][32] = { /* int req to vector */ + { 0 }, /* IPL 0 */ + { VEC_PIRQ }, /* IPL 1 */ + { VEC_PIRQ }, /* IPL 2 */ + { VEC_PIRQ }, /* IPL 3 */ + { VEC_TTI, VEC_TTO, VEC_PTR, VEC_PTP, /* IPL 4 */ + VEC_LPT, VEC_PIRQ }, + { VEC_RK, VEC_RL, VEC_RX, VEC_TM, /* IPL 5 */ + VEC_RP, VEC_TS, VEC_HK, VEC_DZRX, + VEC_DZTX, VEC_PIRQ }, + { VEC_CLK, VEC_DTA, VEC_PIRQ }, /* IPL 6 */ + { VEC_PIRQ } }; /* IPL 7 */ -int32 (*int_ack[32])() = { /* int ack routines */ - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &rk_inta, NULL, NULL, NULL, &rp_inta, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +int32 (*int_ack[IPL_HLVL][32])() = { /* int ack routines */ + { NULL }, /* IPL 0 */ + { NULL }, /* IPL 1 */ + { NULL }, /* IPL 2 */ + { NULL }, /* IPL 3 */ + { NULL }, /* IPL 4 */ + { &rk_inta, NULL, NULL, NULL, /* IPL 5 */ + &rp_inta, NULL, NULL, NULL }, + { NULL }, /* IPL 6 */ + { NULL } }; /* IPL 7 */ int32 trap_vec[TRAP_V_MAX] = { /* trap req to vector */ VEC_RED, VEC_ODD, VEC_MME, VEC_NXM, @@ -398,7 +426,7 @@ REG cpu_reg[] = { { ORDATA (MAINT, MAINT, 16) }, { ORDATA (HITMISS, HITMISS, 16) }, { ORDATA (CPUERR, CPUERR, 16) }, - { ORDATA (INT, int_req, 32), REG_RO }, + { BRDATA (IREQ, int_req, 8, 32, IPL_HLVL), REG_RO }, { ORDATA (TRAPS, trap_req, TRAP_V_MAX) }, { ORDATA (PIRQ, PIRQ, 16) }, { FLDATA (WAIT, wait_state, 0) }, @@ -406,6 +434,7 @@ REG cpu_reg[] = { { ORDATA (STOP_TRAPS, stop_trap, TRAP_V_MAX) }, { FLDATA (STOP_VECA, stop_vecabort, 0) }, { FLDATA (STOP_SPA, stop_spabort, 0) }, + { ORDATA (DBGLOG, pdp11_log, 16), REG_HIDDEN }, { ORDATA (FAC0H, FR[0].h, 32) }, { ORDATA (FAC0L, FR[0].l, 32) }, { ORDATA (FAC1H, FR[1].h, 32) }, @@ -568,7 +597,7 @@ extern UNIT *sim_clock_queue; extern UNIT clk_unit; int32 IR, srcspec, srcreg, dstspec, dstreg; int32 src, src2, dst; -int32 i, t, sign, oldrs, trapnum; +int32 i, j, t, sign, oldrs, trapnum; int32 abortval; volatile int32 trapea; t_stat reason; @@ -602,7 +631,7 @@ isenable = calc_is (cm); dsenable = calc_ds (cm); CPU_wr (PIRQ, 017777772, WRITE); /* rewrite PIRQ */ -trap_req = calc_ints (ipl, int_req, trap_req); +trap_req = calc_ints (ipl, trap_req); trapea = 0; reason = 0; sim_rtc_init (clk_unit.wait); /* init clock */ @@ -641,28 +670,38 @@ if (abortval != 0) { while (reason == 0) { if (sim_interval <= 0) { /* check clock queue */ reason = sim_process_event (); - trap_req = calc_ints (ipl, int_req, trap_req); + trap_req = calc_ints (ipl, trap_req); continue; } if (trap_req) { /* check traps, ints */ trapea = 0; /* assume srch fails */ if (t = trap_req & TRAP_ALL) { /* if a trap */ - for (trapnum = 0; trapnum < TRAP_V_MAX; trapnum++) { - if ((t >> trapnum) & 1) { - trapea = trap_vec[trapnum]; - trap_req = trap_req & ~trap_clear[trapnum]; - if ((stop_trap >> trapnum) & 1) - reason = trapnum + 1; - break; } } } - else if (t = int_req & int_mask[ipl]) { /* if an interrupt */ - for (i = 0; i < 32; i++) { - if ((t >> i) & 1) { - int_req = int_req & ~(1u << i); - if (int_ack[i]) trapea = int_ack[i](); - else trapea = int_vec[i]; - trapnum = TRAP_V_MAX; - break; } } } + for (trapnum = 0; trapnum < TRAP_V_MAX; trapnum++) { + if ((t >> trapnum) & 1) { + trapea = trap_vec[trapnum]; + trap_req = trap_req & ~trap_clear[trapnum]; + if ((stop_trap >> trapnum) & 1) + reason = trapnum + 1; + break; } /* end if t & 1 */ + } /* end for */ + } /* end if */ + else { + for (i = IPL_HLVL - 1; (trapea == 0) && (i > ipl); i--) { + t = int_req[i]; /* get level */ + for (j = 0; t && (j < 32); j++) { /* srch level */ + if ((t >> j) & 1) { /* irq found? */ + int_req[i] = int_req[i] & ~(1u << j); + if (int_ack[i][j]) trapea = int_ack[i][j](); + else trapea = int_vec[i][j]; + trapnum = TRAP_V_MAX; + if (DBG_LOG (LOG_CPU_I)) fprintf (sim_log, + ">>CPU, lvl=%d, flag=%d, vec=%o\n", + i, j, trapea); + break; } /* end if t & 1 */ + } /* end for j */ + } /* end for i */ + } /* end else */ if (trapea == 0) { /* nothing to do? */ - trap_req = calc_ints (ipl, int_req, 0); /* recalculate */ + trap_req = calc_ints (ipl, 0); /* recalculate */ continue; } /* back to fetch */ /* Process a trap or interrupt @@ -707,7 +746,7 @@ if (trap_req) { /* check traps, ints */ JMP_PC (src); isenable = calc_is (cm); dsenable = calc_ds (cm); - trap_req = calc_ints (ipl, int_req, trap_req); + trap_req = calc_ints (ipl, trap_req); if ((SP < STKLIM) && (cm == KERNEL) && (trapnum != TRAP_V_RED) && (trapnum != TRAP_V_YEL)) { setTRAP (TRAP_YEL); @@ -768,7 +807,8 @@ case 000: if (cm == KERNEL) { reset_all (1); PIRQ = 0; - int_req = 0; + for (i = 0; i < IPL_HLVL; i++) + int_req[i] = 0; MMR0 = MMR0 & ~(MMR0_MME | MMR0_FREEZE); MMR3 = 0; trap_req = trap_req & ~TRAP_INT; @@ -796,7 +836,7 @@ case 000: Z = (src2 >> PSW_V_Z) & 01; V = (src2 >> PSW_V_V) & 01; C = (src2 >> PSW_V_C) & 01; - trap_req = calc_ints (ipl, int_req, trap_req); + trap_req = calc_ints (ipl, trap_req); isenable = calc_is (cm); dsenable = calc_ds (cm); if (rs != oldrs) { @@ -830,7 +870,7 @@ case 000: break; } if (IR < 000240) { /* SPL */ if (cm == KERNEL) ipl = IR & 07; - trap_req = calc_ints (ipl, int_req, trap_req); + trap_req = calc_ints (ipl, trap_req); break; } /* end if SPL */ if (IR < 000260) { /* clear CC */ if (IR & 010) N = 0; @@ -1503,7 +1543,7 @@ case 010: dst = dstreg? R[dstspec]: ReadB (GeteaB (dstspec)); if (cm == KERNEL) { ipl = (dst >> PSW_V_IPL) & 07; - trap_req = calc_ints (ipl, int_req, trap_req); } + trap_req = calc_ints (ipl, trap_req); } N = (dst >> PSW_V_N) & 01; Z = (dst >> PSW_V_Z) & 01; V = (dst >> PSW_V_V) & 01; @@ -2068,9 +2108,9 @@ struct iolink *p; for (p = &iotable[0]; p -> low != 0; p++ ) { if ((pa >= p -> low) && (pa <= p -> high) && - ((p -> enb == 0) || (dev_enb & p -> enb))) { + ((p -> enb == NULL) || *p -> enb)) { stat = p -> read (data, pa, access); - trap_req = calc_ints (ipl, int_req, trap_req); + trap_req = calc_ints (ipl, trap_req); return stat; } } return SCPE_NXM; } @@ -2082,12 +2122,23 @@ struct iolink *p; for (p = &iotable[0]; p -> low != 0; p++ ) { if ((pa >= p -> low) && (pa <= p -> high) && - ((p -> enb == 0) || (dev_enb & p -> enb))) { + ((p -> enb == NULL) || *p -> enb)) { stat = p -> write (data, pa, access); - trap_req = calc_ints (ipl, int_req, trap_req); + trap_req = calc_ints (ipl, trap_req); return stat; } } return SCPE_NXM; } + +/* Calculate interrupt outstanding */ + +int32 calc_ints (int32 nipl, int32 trq) +{ +int32 i; + +for (i = IPL_HLVL - 1; i > nipl; i--) { + if (int_req[i]) return (trq | TRAP_INT); } +return (trq & ~TRAP_INT); +} /* I/O page routines for CPU registers @@ -2133,13 +2184,13 @@ default: /* MMR1, MMR2 */ return SCPE_OK; } /* end switch pa */ } -t_stat MMR3_rd (int32 *data, int32 pa, int32 access) /* MMR3 */ +t_stat MMR3_rd (int32 *data, int32 pa, int32 access) /* MMR3 */ { *data = MMR3 & MMR3_IMP; return SCPE_OK; } -t_stat MMR3_wr (int32 data, int32 pa, int32 access) /* MMR3 */ +t_stat MMR3_wr (int32 data, int32 pa, int32 access) /* MMR3 */ { if (pa & 1) return SCPE_OK; MMR3 = data & MMR3_RW; @@ -2267,17 +2318,22 @@ case 015: /* PIRQ */ if (access == WRITEB) { if (pa & 1) data = data << 8; else return SCPE_OK; } - int_req = int_req & ~(INT_PIR7 + INT_PIR6 + INT_PIR5 + INT_PIR4 + - INT_PIR3 + INT_PIR2 + INT_PIR1); PIRQ = data & PIRQ_RW; pl = 0; - if (PIRQ & PIRQ_PIR1) { int_req = int_req | INT_PIR1; pl = 0042; } - if (PIRQ & PIRQ_PIR2) { int_req = int_req | INT_PIR2; pl = 0104; } - if (PIRQ & PIRQ_PIR3) { int_req = int_req | INT_PIR3; pl = 0146; } - if (PIRQ & PIRQ_PIR4) { int_req = int_req | INT_PIR4; pl = 0210; } - if (PIRQ & PIRQ_PIR5) { int_req = int_req | INT_PIR5; pl = 0252; } - if (PIRQ & PIRQ_PIR6) { int_req = int_req | INT_PIR6; pl = 0314; } - if (PIRQ & PIRQ_PIR7) { int_req = int_req | INT_PIR7; pl = 0356; } + if (PIRQ & PIRQ_PIR1) { SET_INT (PIR1); pl = 0042; } + else CLR_INT (PIR1); + if (PIRQ & PIRQ_PIR2) { SET_INT (PIR2); pl = 0104; } + else CLR_INT (PIR2); + if (PIRQ & PIRQ_PIR3) { SET_INT (PIR3); pl = 0146; } + else CLR_INT (PIR3); + if (PIRQ & PIRQ_PIR4) { SET_INT (PIR4); pl = 0210; } + else CLR_INT (PIR4); + if (PIRQ & PIRQ_PIR5) { SET_INT (PIR5); pl = 0252; } + else CLR_INT (PIR5); + if (PIRQ & PIRQ_PIR6) { SET_INT (PIR6); pl = 0314; } + else CLR_INT (PIR6); + if (PIRQ & PIRQ_PIR7) { SET_INT (PIR7); pl = 0356; } + else CLR_INT (PIR7); PIRQ = PIRQ | pl; return SCPE_OK; diff --git a/pdp11_defs.h b/pdp11_defs.h index d85352dd..4e1a0464 100644 --- a/pdp11_defs.h +++ b/pdp11_defs.h @@ -26,6 +26,9 @@ The author gratefully acknowledges the help of Max Burnet, Megan Gentry, and John Wilson in resolving questions about the PDP-11 + 19-Oct-01 RMS Added DZ definitions + 15-Oct-01 RMS Added logging capabilities + 07-Sep-01 RMS Revised for multilevel interrupts 01-Jun-01 RMS Added DZ11 support 23-Apr-01 RMS Added RK611 support 05-Apr-01 RMS Added TS11/TSV05 support @@ -237,40 +240,42 @@ typedef struct fpac fpac_t; #define STOP_SPABORT TRAP_V_MAX + 5 /* abort trap push */ #define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */ -/* Interrupt assignments, priority is right to left +/* DZ11 parameters */ - <3:0> = BR7, <3> = PIR7 - <7:4> = BR6, <7> = PIR6 - <19:8> = BR5, <19> = PIR5 - <28:20> = BR4, <28> = PIR4 - <29> = PIR3 - <30> = PIR2 - <31> = PIR1 -*/ +#define DZ_MUXES 1 /* # of muxes */ +#define DZ_LINES 8 /* lines per mux */ -#define INT_V_PIR7 3 -#define INT_V_CLK 4 -#define INT_V_DTA 5 -#define INT_V_PIR6 7 -#define INT_V_RK 8 -#define INT_V_RL 9 -#define INT_V_RX 10 -#define INT_V_TM 11 -#define INT_V_RP 12 -#define INT_V_TS 13 -#define INT_V_HK 14 -#define INT_V_DZ0RX 16 -#define INT_V_DZ0TX 17 -#define INT_V_PIR5 19 -#define INT_V_TTI 20 -#define INT_V_TTO 21 -#define INT_V_PTR 22 -#define INT_V_PTP 23 -#define INT_V_LPT 24 -#define INT_V_PIR4 28 -#define INT_V_PIR3 29 -#define INT_V_PIR2 30 -#define INT_V_PIR1 31 +/* Interrupt assignments; within each level, priority is right to left */ + +#define IPL_HLVL 8 /* # int levels */ + +#define INT_V_PIR7 0 /* BR7 */ + +#define INT_V_CLK 0 /* BR6 */ +#define INT_V_DTA 1 +#define INT_V_PIR6 2 + +#define INT_V_RK 0 /* BR5 */ +#define INT_V_RL 1 +#define INT_V_RX 2 +#define INT_V_TM 3 +#define INT_V_RP 4 +#define INT_V_TS 5 +#define INT_V_HK 6 +#define INT_V_DZRX 7 +#define INT_V_DZTX 8 +#define INT_V_PIR5 9 + +#define INT_V_TTI 0 /* BR4 */ +#define INT_V_TTO 1 +#define INT_V_PTR 2 +#define INT_V_PTP 3 +#define INT_V_LPT 4 +#define INT_V_PIR4 5 + +#define INT_V_PIR3 0 /* BR3 */ +#define INT_V_PIR2 0 /* BR2 */ +#define INT_V_PIR1 0 /* BR1 */ #define INT_PIR7 (1u << INT_V_PIR7) #define INT_CLK (1u << INT_V_CLK) @@ -283,8 +288,8 @@ typedef struct fpac fpac_t; #define INT_RP (1u << INT_V_RP) #define INT_TS (1u << INT_V_TS) #define INT_HK (1u << INT_V_HK) -#define INT_DZ0RX (1u << INT_V_DZ0RX) -#define INT_DZ0TX (1u << INT_V_DZ0TX) +#define INT_DZRX (1u << INT_V_DZRX) +#define INT_DZTX (1u << INT_V_DZTX) #define INT_PIR5 (1u << INT_V_PIR5) #define INT_PTR (1u << INT_V_PTR) #define INT_PTP (1u << INT_V_PTP) @@ -296,14 +301,30 @@ typedef struct fpac fpac_t; #define INT_PIR2 (1u << INT_V_PIR2) #define INT_PIR1 (1u << INT_V_PIR1) -#define INT_IPL7 0x00000000 /* int level masks */ -#define INT_IPL6 0x0000000F -#define INT_IPL5 0x000000FF -#define INT_IPL4 0x000FFFFF -#define INT_IPL3 0x1FFFFFFF -#define INT_IPL2 0x3FFFFFFF -#define INT_IPL1 0x7FFFFFFF -#define INT_IPL0 0xFFFFFFFF +#define IPL_CLK 6 /* int pri levels */ +#define IPL_DTA 6 +#define IPL_RK 5 +#define IPL_RL 5 +#define IPL_RX 5 +#define IPL_TM 5 +#define IPL_RP 5 +#define IPL_TS 5 +#define IPL_HK 5 +#define IPL_DZRX 5 +#define IPL_DZTX 5 +#define IPL_PTR 4 +#define IPL_PTP 4 +#define IPL_TTI 4 +#define IPL_TTO 4 +#define IPL_LPT 4 + +#define IPL_PIR7 7 +#define IPL_PIR6 6 +#define IPL_PIR5 5 +#define IPL_PIR4 4 +#define IPL_PIR3 3 +#define IPL_PIR2 2 +#define IPL_PIR1 1 #define VEC_PIRQ 0240 /* interrupt vectors */ #define VEC_TTI 0060 @@ -320,8 +341,14 @@ typedef struct fpac fpac_t; #define VEC_TS 0224 #define VEC_RP 0254 #define VEC_RX 0264 -#define VEC_DZ0RX 0310 -#define VEC_DZ0TX 0314 +#define VEC_DZRX 0310 +#define VEC_DZTX 0314 + +/* Interrupt macros */ + +#define IREQ(dv) int_req[IPL_##dv] +#define SET_INT(dv) IREQ(dv) = IREQ(dv) | (INT_##dv) +#define CLR_INT(dv) IREQ(dv) = IREQ(dv) & ~(INT_##dv) /* CPU and FPU macros */ @@ -331,3 +358,15 @@ typedef struct fpac fpac_t; #define ABORT(val) longjmp (save_env, (val)) #define SP R[6] #define PC R[7] + +/* Logging */ + +#define LOG_CPU_I 00000001 +#define LOG_RP 00000010 +#define LOG_TS 00000020 +#define LOG_TC_MS 00000100 +#define LOG_TC_RW 00000200 +#define LOG_TC_RA 00000400 +#define LOG_TC_BL 00001000 + +#define DBG_LOG(x) (sim_log && (pdp11_log & (x))) diff --git a/pdp11_dz.c b/pdp11_dz.c new file mode 100644 index 00000000..0c7b449c --- /dev/null +++ b/pdp11_dz.c @@ -0,0 +1,30 @@ +/* pdp11_dz.c: DZ11 terminal multiplexor simulator + + Copyright (c) 1993-2001, 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"), + 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. + + dz DZ11 terminal multiplexor +*/ + +#include "pdp11_defs.h" +#include "dec_dz.h" diff --git a/pdp11_lp.c b/pdp11_lp.c index 2be16bd4..c11899ff 100644 --- a/pdp11_lp.c +++ b/pdp11_lp.c @@ -25,6 +25,7 @@ lpt LP11 line printer + 07-Sep-01 RMS Revised interrupt mechanism 30-Oct-00 RMS Standardized register naming */ @@ -33,7 +34,7 @@ #define LPTCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* implemented */ #define LPTCSR_RW (CSR_IE) /* read/write */ -extern int32 int_req; +extern int32 int_req[IPL_HLVL]; int32 lpt_csr = 0; /* control/status */ int32 lpt_stopioe = 0; /* stop on error */ t_stat lpt_svc (UNIT *uptr); @@ -54,7 +55,7 @@ UNIT lpt_unit = { REG lpt_reg[] = { { ORDATA (BUF, lpt_unit.buf, 8) }, { ORDATA (CSR, lpt_csr, 16) }, - { FLDATA (INT, int_req, INT_V_LPT) }, + { FLDATA (INT, IREQ (LPT), INT_V_LPT) }, { FLDATA (ERR, lpt_csr, CSR_V_ERR) }, { FLDATA (DONE, lpt_csr, CSR_V_DONE) }, { FLDATA (IE, lpt_csr, CSR_V_IE) }, @@ -90,13 +91,13 @@ t_stat lpt_wr (int32 data, int32 PA, int32 access) { if ((PA & 02) == 0) { /* csr */ if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) int_req = int_req & ~INT_LPT; + if ((data & CSR_IE) == 0) CLR_INT (LPT); else if ((lpt_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) - int_req = int_req | INT_LPT; + SET_INT (LPT); lpt_csr = (lpt_csr & ~LPTCSR_RW) | (data & LPTCSR_RW); } else { if ((PA & 1) == 0) lpt_unit.buf = data & 0177; /* buffer */ lpt_csr = lpt_csr & ~CSR_DONE; - int_req = int_req & ~INT_LPT; + CLR_INT (LPT); if ((lpt_unit.buf == 015) || (lpt_unit.buf == 014) || (lpt_unit.buf == 012)) sim_activate (&lpt_unit, lpt_unit.wait); else sim_activate (&lpt_unit, 0); } @@ -106,7 +107,7 @@ return SCPE_OK; t_stat lpt_svc (UNIT *uptr) { lpt_csr = lpt_csr | CSR_ERR | CSR_DONE; -if (lpt_csr & CSR_IE) int_req = int_req | INT_LPT; +if (lpt_csr & CSR_IE) SET_INT (LPT); if ((lpt_unit.flags & UNIT_ATT) == 0) return IORETURN (lpt_stopioe, SCPE_UNATT); if (putc (lpt_unit.buf & 0177, lpt_unit.fileref) == EOF) { @@ -123,7 +124,7 @@ t_stat lpt_reset (DEVICE *dptr) lpt_unit.buf = 0; lpt_csr = CSR_DONE; if ((lpt_unit.flags & UNIT_ATT) == 0) lpt_csr = lpt_csr | CSR_ERR; -int_req = int_req & ~INT_LPT; +CLR_INT (LPT); sim_cancel (&lpt_unit); /* deactivate unit */ return SCPE_OK; } diff --git a/pdp11_rk.c b/pdp11_rk.c index 60513124..865041cd 100644 --- a/pdp11_rk.c +++ b/pdp11_rk.c @@ -25,6 +25,7 @@ rk RK11/RK05 cartridge disk + 07-Sep-01 RMS Revised device disable and interrupt mechanisms 26-Apr-01 RMS Added device enable/disable support 25-Mar-01 RMS Fixed block fill calculation 15-Feb-01 RMS Corrected bootstrap string @@ -161,7 +162,7 @@ #define MAX(x,y) (((x) > (y))? (x): (y)) extern uint16 *M; /* memory */ -extern int32 int_req, dev_enb; +extern int32 int_req[IPL_HLVL]; extern UNIT cpu_unit; int32 rkcs = 0; /* control/status */ int32 rkds = 0; /* drive status */ @@ -174,6 +175,7 @@ int32 last_drv = 0; /* last r/w drive */ int32 rk_stopioe = 1; /* stop on error */ int32 rk_swait = 10; /* seek time */ int32 rk_rwait = 10; /* rotate time */ +int32 rk_enb = 1; /* device enable */ t_stat rk_svc (UNIT *uptr); t_stat rk_reset (DEVICE *dptr); void rk_go (void); @@ -208,7 +210,7 @@ REG rk_reg[] = { { ORDATA (RKER, rker, 16) }, { ORDATA (INTQ, rkintq, 9) }, { ORDATA (DRVN, last_drv, 3) }, - { FLDATA (INT, int_req, INT_V_RK) }, + { FLDATA (INT, IREQ (RK), INT_V_RK) }, { FLDATA (ERR, rkcs, CSR_V_ERR) }, { FLDATA (DONE, rkcs, CSR_V_DONE) }, { FLDATA (IE, rkcs, CSR_V_IE) }, @@ -231,7 +233,7 @@ REG rk_reg[] = { { GRDATA (FLG7, rk_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), REG_HRO }, { FLDATA (STOP_IOE, rk_stopioe, 0) }, - { FLDATA (*DEVENB, dev_enb, INT_V_RK), REG_HRO }, + { FLDATA (*DEVENB, rk_enb, 0), REG_HRO }, { NULL } }; MTAB rk_mod[] = { @@ -313,10 +315,10 @@ case 2: /* RKCS */ (rkcs & 0377) | (data << 8): (rkcs & ~0377) | data; if ((data & CSR_IE) == 0) { /* int disable? */ rkintq = 0; /* clr int queue */ - int_req = int_req & ~INT_RK; } /* clr int request */ + CLR_INT (RK); } /* clr int request */ else if ((rkcs & (CSR_DONE + CSR_IE)) == CSR_DONE) { rkintq = rkintq | RK_CTLI; /* queue ctrl int */ - int_req = int_req | INT_RK; } /* set int request */ + SET_INT (RK); } /* set int request */ rkcs = (rkcs & ~RKCS_RW) | (data & RKCS_RW); if ((rkcs & CSR_DONE) && (data & CSR_GO)) rk_go (); /* new function? */ return SCPE_OK; @@ -354,7 +356,7 @@ if (func == RKCS_CTLRESET) { /* control reset? */ rkba = 0; rkcs = CSR_DONE; rkintq = 0; /* clr int queue */ - int_req = int_req & ~INT_RK; /* clr int request */ + CLR_INT (RK); /* clr int request */ return; } rker = rker & ~RKER_SOFT; /* clear soft errors */ if (rker == 0) rkcs = rkcs & ~RKCS_ERR; /* redo summary */ @@ -420,9 +422,9 @@ if (uptr -> FUNC == RKCS_SEEK) { /* seek */ rkcs = rkcs | RKCS_SCP; /* set seek done */ if (rkcs & CSR_IE) { /* ints enabled? */ rkintq = rkintq | RK_SCPI (drv); /* queue request */ - if (rkcs & CSR_DONE) int_req = int_req | INT_RK; } + if (rkcs & CSR_DONE) SET_INT (RK); } else { rkintq = 0; /* clear queue */ - int_req = int_req & ~INT_RK; } /* clear interrupt */ + CLR_INT (RK); } /* clear interrupt */ return SCPE_OK; } if ((uptr -> flags & UNIT_ATT) == 0) { /* attached? */ @@ -499,9 +501,9 @@ void rk_set_done (int32 error) if (rker & RKER_HARD) rkcs = rkcs | RKCS_HERR; } if (rkcs & CSR_IE) { /* int enable? */ rkintq = rkintq | RK_CTLI; /* set ctrl int */ - int_req = int_req | INT_RK; } /* request int */ + SET_INT (RK); } /* request int */ else { rkintq = 0; /* clear queue */ - int_req = int_req & ~INT_RK; } + CLR_INT (RK); } return; } @@ -509,7 +511,7 @@ void rk_clr_done (void) { rkcs = rkcs & ~CSR_DONE; /* clear done */ rkintq = rkintq & ~RK_CTLI; /* clear ctl int */ - int_req = int_req & ~INT_RK; /* clear int req */ + CLR_INT (RK); /* clear int req */ return; } @@ -520,7 +522,7 @@ int32 i; for (i = 0; i <= RK_NUMDR; i++) { /* loop thru intq */ if (rkintq & (1u << i)) { /* bit i set? */ rkintq = rkintq & ~(1u << i); /* clear bit i */ - if (rkintq) int_req = int_req | INT_RK; /* queue next */ + if (rkintq) SET_INT (RK); /* queue next */ rkds = (rkds & ~RKDS_ID) | /* id drive */ (((i == 0)? last_drv: i - 1) << RKDS_V_ID); return VEC_RK; } } /* return vector */ @@ -538,7 +540,7 @@ UNIT *uptr; rkcs = CSR_DONE; rkda = rkba = rker = rkds = 0; rkintq = last_drv = 0; -int_req = int_req & ~INT_RK; +CLR_INT (RK); for (i = 0; i < RK_NUMDR; i++) { uptr = rk_dev.units + i; sim_cancel (uptr); @@ -549,8 +551,8 @@ return SCPE_OK; /* Device bootstrap */ -#define BOOT_START 02000 /* start */ -#define BOOT_UNIT 02006 /* where to store unit number */ +#define BOOT_START 02000 /* start */ +#define BOOT_UNIT 02006 /* unit number */ #define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) static const int32 boot_rom[] = { diff --git a/pdp11_rl.c b/pdp11_rl.c index 29f00f72..d82048a4 100644 --- a/pdp11_rl.c +++ b/pdp11_rl.c @@ -25,6 +25,7 @@ rl RL11(RLV12)/RL01/RL02 cartridge disk + 07-Sep-01 RMS Revised device disable and interrupt mechanisms 20-Aug-01 RMS Added bad block option in attach 17-Jul-01 RMS Fixed warning from VC++ 6.0 26-Apr-01 RMS Added device enable/disable support @@ -156,7 +157,7 @@ #define RLBAE_IMP 0000077 /* implemented */ extern uint16 *M; /* memory */ -extern int32 int_req, dev_enb; +extern int32 int_req[IPL_HLVL]; extern UNIT cpu_unit; int32 rlcs = 0; /* control/status */ int32 rlba = 0; /* memory address */ @@ -166,6 +167,7 @@ int32 rlmp = 0, rlmp1 = 0, rlmp2 = 0; /* mp register queue */ int32 rl_swait = 10; /* seek wait */ int32 rl_rwait = 10; /* rotate wait */ int32 rl_stopioe = 1; /* stop on error */ +int32 rl_enb = 1; /* device enable */ t_stat rl_svc (UNIT *uptr); t_stat rl_reset (DEVICE *dptr); void rl_set_done (int32 error); @@ -201,7 +203,7 @@ REG rl_reg[] = { { ORDATA (RLMP, rlmp, 16) }, { ORDATA (RLMP1, rlmp1, 16) }, { ORDATA (RLMP2, rlmp2, 16) }, - { FLDATA (INT, int_req, INT_V_RL) }, + { FLDATA (INT, IREQ (RL), INT_V_RL) }, { FLDATA (ERR, rlcs, CSR_V_ERR) }, { FLDATA (DONE, rlcs, CSR_V_DONE) }, { FLDATA (IE, rlcs, CSR_V_IE) }, @@ -220,7 +222,7 @@ REG rl_reg[] = { { DRDATA (CAPAC2, rl_unit[2].capac, 32), PV_LEFT + REG_HRO }, { DRDATA (CAPAC3, rl_unit[3].capac, 32), PV_LEFT + REG_HRO }, { FLDATA (STOP_IOE, rl_stopioe, 0) }, - { FLDATA (*DEVENB, dev_enb, INT_V_RL), REG_HRO }, + { FLDATA (*DEVENB, rl_enb, 0), REG_HRO }, { NULL } }; MTAB rl_mod[] = { @@ -300,12 +302,12 @@ case 0: /* RLCS */ rlcs = (rlcs & ~RLCS_RW) | (data & RLCS_RW); rlbae = (rlbae & ~RLCS_M_MEX) | ((rlcs >> RLCS_V_MEX) & RLCS_M_MEX); if (data & CSR_DONE) { /* ready set? */ - if ((data & CSR_IE) == 0) int_req = int_req & ~INT_RL; + if ((data & CSR_IE) == 0) CLR_INT (RL); else if ((rlcs & (CSR_DONE + CSR_IE)) == CSR_DONE) - int_req = int_req | INT_RL; + SET_INT (RL); return SCPE_OK; } - int_req = int_req & ~INT_RL; /* clear interrupt */ + CLR_INT (RL); /* clear interrupt */ rlcs = rlcs & ~RLCS_ALLERR; /* clear errors */ switch (GET_FUNC (rlcs)) { /* case on RLCS<3:1> */ case RLCS_NOP: /* nop */ @@ -459,8 +461,8 @@ return SCPE_OK; void rl_set_done (int32 status) { rlcs = rlcs | status | CSR_DONE; /* set done */ - if (rlcs & CSR_IE) int_req = int_req | INT_RL; - else int_req = int_req & ~INT_RL; + if (rlcs & CSR_IE) SET_INT (RL); + else CLR_INT (RL); return; } @@ -476,7 +478,7 @@ UNIT *uptr; rlcs = CSR_DONE; rlda = rlba = rlbae = rlmp = rlmp1 = rlmp2 = 0; -int_req = int_req & ~INT_RL; +CLR_INT (RL); for (i = 0; i < RL_NUMDR; i++) { uptr = rl_dev.units + i; sim_cancel (uptr); @@ -523,8 +525,8 @@ return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD); /* Device bootstrap */ -#define BOOT_START 02000 /* start */ -#define BOOT_UNIT 02006 /* where to store unit number */ +#define BOOT_START 02000 /* start */ +#define BOOT_UNIT 02006 /* unit number */ #define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) static const int32 boot_rom[] = { diff --git a/pdp11_rp.c b/pdp11_rp.c index 105585c8..32988437 100644 --- a/pdp11_rp.c +++ b/pdp11_rp.c @@ -25,6 +25,13 @@ rp RH/RP/RM moving head disks + 23-Oct-01 RMS Fixed bug in error interrupts + 15-Oct-01 RMS Added debug logging + 05-Oct-01 RMS Rewrote interrupt handling from schematics + 02-Oct-01 RMS Revised CS1 write code + 30-Sep-01 RMS Moved CS1<5:0> into drives + 28-Sep-01 RMS Fixed interrupt handling for SC/ATA + 07-Sep-01 RMS Revised device disable and interrupt mechanisms 20-Aug-01 RMS Added bad block option in attach 13-Jul-01 RMS Changed fread call to fxread (found by Peter Schorn) 14-May-01 RMS Added check for unattached drive @@ -46,13 +53,19 @@ systems, this was through many different third party controllers which emulated the Massbus interface. - WARNING: This controller is somewhat abstract. It is intended to run - the operating system drivers for the PDP-11 operating systems and - nothing more. Most error and all diagnostic functions have been - omitted. In addition, the controller conflates the RP04/05/06 series - controllers with the RM02/03/05/80 series controllers and with the - RP07 controller. There are actually significant differences, which - have been highlighted where noticed. + WARNING: The interupt logic of the RH11/RH70 is unusual and must be + simulated with great precision. The RH11 has an internal interrupt + request flop, CSTB INTR, which is controlled as follows: + - Writing IE and DONE simultaneously sets CSTB INTR + - Controller clear, INIT, and interrupt acknowledge clear CSTB INTR + (and also clear IE) + - A transition of DONE from 0 to 1 sets CSTB from INTR + The output of INTR is OR'd with the AND of RPCS1 to + create the interrupt request signal. Thus, + - The DONE interrupt is edge sensitive, but the SC interrupt is + level sensitive. + - The DONE interrupt, once set, is not disabled if IE is cleared, + but the SC interrupt is. */ #include "pdp11_defs.h" @@ -100,9 +113,12 @@ #define FNC_PRESET 010 /* read-in preset */ #define FNC_PACK 011 /* pack acknowledge */ #define FNC_SEARCH 014 /* search */ +#define FNC_XFER 024 /* >=? data xfr */ #define FNC_WCHK 024 /* write check */ #define FNC_WRITE 030 /* write */ +#define FNC_WRITEH 031 /* write w/ headers */ #define FNC_READ 034 /* read */ +#define FNC_READH 035 /* read w/ headers */ #define CS1_IE CSR_IE /* int enable */ #define CS1_DONE CSR_DONE /* ready */ #define CS1_V_UAE 8 /* Unibus addr ext */ @@ -113,7 +129,7 @@ #define CS1_TRE 0040000 /* transfer err */ #define CS1_SC 0100000 /* special cond */ #define CS1_MBZ 0012000 -#define CS1_RW (CS1_FNC | CS1_IE | CS1_UAE) +#define CS1_DRV (CS1_FNC | CS1_GO) #define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) /* RPWC - 176702 - word count */ @@ -219,7 +235,7 @@ #define GET_DA(c,fs,d) ((((GET_CY (c) * drv_tab[d].surf) + \ GET_SF (fs)) * drv_tab[d].sect) + GET_SC (fs)) -/* RPCC - 176736 - current cylinder - unimplemented */ +/* RPCC - 176736 - current cylinder */ /* RPER2 - 176740 - error status 2 - drive unsafe conditions - unimplemented */ /* RPER3 - 176742 - error status 3 - more unsafe conditions - unimplemented */ /* RPEC1 - 176744 - ECC status 1 - unimplemented */ @@ -312,8 +328,10 @@ struct drvtyp drv_tab[] = { { 0 } }; extern uint16 *M; /* memory */ -extern int32 int_req, dev_enb; +extern int32 int_req[IPL_HLVL]; extern UNIT cpu_unit; +extern int32 pdp11_log; +extern FILE *sim_log; int32 rpcs1 = 0; /* control/status 1 */ int32 rpwc = 0; /* word count */ int32 rpba = 0; /* bus address */ @@ -331,15 +349,17 @@ int32 rpec1 = 0; /* ECC correction 1 */ int32 rpec2 = 0; /* ECC correction 2 */ int32 rpbae = 0; /* bus address ext */ int32 rpcs3 = 0; /* control/status 3 */ +int32 rpiff = 0; /* INTR flip/flop */ int32 rp_stopioe = 1; /* stop on error */ int32 rp_swait = 10; /* seek time */ int32 rp_rwait = 10; /* rotate time */ +int32 rp_enb = 1; /* device enable */ int reg_in_drive[32] = { 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; void update_rpcs (int32 flags, int32 drv); -void rp_go (int32 drv); +void rp_go (int32 drv, int32 fnc); t_stat rp_set_size (UNIT *uptr, int32 value); t_stat rp_set_bad (UNIT *uptr, int32 value); t_stat rp_svc (UNIT *uptr); @@ -391,7 +411,8 @@ REG rp_reg[] = { { ORDATA (RPDB, rpdb, 16) }, { ORDATA (RPBAE, rpbae, 6) }, { ORDATA (RPCS3, rpcs3, 16) }, - { FLDATA (INT, int_req, INT_V_RP) }, + { FLDATA (IFF, rpiff, 0) }, + { FLDATA (INT, IREQ (RP), INT_V_RP) }, { FLDATA (SC, rpcs1, CSR_V_ERR) }, { FLDATA (DONE, rpcs1, CSR_V_DONE) }, { FLDATA (IE, rpcs1, CSR_V_IE) }, @@ -413,6 +434,14 @@ REG rp_reg[] = { { ORDATA (RPDE5, rper1[5], 16) }, { ORDATA (RPDE6, rper1[6], 16) }, { ORDATA (RPDE7, rper1[7], 16) }, + { ORDATA (RPFN0, rp_unit[0].FUNC, 5), REG_HRO }, + { ORDATA (RPFN1, rp_unit[1].FUNC, 5), REG_HRO }, + { ORDATA (RPFN2, rp_unit[2].FUNC, 5), REG_HRO }, + { ORDATA (RPFN3, rp_unit[3].FUNC, 5), REG_HRO }, + { ORDATA (RPFN4, rp_unit[4].FUNC, 5), REG_HRO }, + { ORDATA (RPFN5, rp_unit[5].FUNC, 5), REG_HRO }, + { ORDATA (RPFN6, rp_unit[6].FUNC, 5), REG_HRO }, + { ORDATA (RPFN7, rp_unit[7].FUNC, 5), REG_HRO }, { GRDATA (FLG0, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), REG_HRO }, { GRDATA (FLG1, rp_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), @@ -430,7 +459,7 @@ REG rp_reg[] = { { GRDATA (FLG7, rp_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), REG_HRO }, { FLDATA (STOP_IOE, rp_stopioe, 0) }, - { FLDATA (*DEVENB, dev_enb, INT_V_RP), REG_HRO }, + { FLDATA (*DEVENB, rp_enb, 0), REG_HRO }, { NULL } }; MTAB rp_mod[] = { @@ -578,9 +607,11 @@ return SCPE_OK; t_stat rp_wr (int32 data, int32 PA, int32 access) { int32 cs1f, drv, i, j; +UNIT *uptr; cs1f = 0; /* no int on cs1 upd */ drv = GET_UNIT (rpcs2); /* get current unit */ +uptr = rp_dev.units + drv; /* get unit */ j = (PA >> 1) & 037; /* get reg offset */ if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */ rpcs2 = rpcs2 | CS2_NED; /* set error flag */ @@ -594,19 +625,29 @@ if (reg_in_drive[j] && sim_is_active (&rp_unit[drv])) { /* unit busy? */ switch (j) { /* decode PA<5:1> */ case 000: /* RPCS1 */ if ((access == WRITEB) && (PA & 1)) data = data << 8; - else { if ((data & CS1_IE) == 0) int_req = int_req & ~INT_RP; - else if (data & CS1_DONE) int_req = int_req | INT_RP; } if (data & CS1_TRE) { /* error clear? */ rpcs1 = rpcs1 & ~CS1_TRE; /* clr CS1 */ rpcs2 = rpcs2 & ~CS2_ERR; } /* clr CS2<15:8> */ - if (access == WRITEB) data = (rpcs1 & /* merge data */ - ((PA & 1)? 0377: 0177400)) | data; - rpcs1 = (rpcs1 & ~CS1_RW) | (data & CS1_RW); - rpbae = (rpbae & ~CS1_M_UAE) | ((rpcs1 >> CS1_V_UAE) & CS1_M_UAE); + if ((access == WRITE) || (PA & 1)) { /* hi byte write? */ + if (rpcs1 & CS1_DONE) /* done set? */ + rpcs1 = (rpcs1 & ~CS1_UAE) | (data & CS1_UAE); } + if ((access == WRITE) || !(PA & 1)) { /* lo byte write? */ + if ((data & CS1_DONE) && (data & CS1_IE)) /* to DONE+IE? */ + rpiff = 1; /* set CSTB INTR */ + rpcs1 = (rpcs1 & ~CS1_IE) | (data & CS1_IE); + if (uptr -> flags & UNIT_DIS) { /* nx disk? */ + rpcs2 = rpcs2 | CS2_NED; /* set error flag */ + cs1f = CS1_SC; } /* req interrupt */ + else if (sim_is_active (uptr)) + rper1[drv] = rper1[drv] | ER1_RMR; /* won't write */ + else if (data & CS1_GO) { /* start op */ + uptr -> FUNC = GET_FNC (data); /* set func */ + if ((uptr -> FUNC >= FNC_XFER) && /* data xfer and */ + ((rpcs1 & CS1_DONE) == 0)) /* ~rdy? PGE */ + rpcs2 = rpcs2 | CS2_PGE; + else rp_go (drv, uptr -> FUNC); } } rpcs3 = (rpcs3 & ~CS1_IE) | (rpcs1 & CS1_IE); - if (data & CS1_GO) { /* new command? */ - if (rpcs1 & CS1_DONE) rp_go (drv); /* start if not busy */ - else rpcs2 = rpcs2 | CS2_PGE; } /* else prog error */ + rpbae = (rpbae & ~CS1_M_UAE) | ((rpcs1 >> CS1_V_UAE) & CS1_M_UAE); break; case 001: /* RPWC */ if (access == WRITEB) data = (PA & 1)? @@ -670,9 +711,6 @@ case 024: /* RPBAE */ case 025: /* RPCS3 */ if ((access == WRITEB) && (PA & 1)) break; rpcs3 = data & ~CS3_MBZ; - if ((data & CS1_IE) == 0) int_req = int_req & ~INT_RP; - else if (((rpcs1 & CS1_IE) == 0) && (rpcs1 & CS1_DONE)) - int_req = int_req | INT_RP; rpcs1 = (rpcs1 & ~CS1_IE) | (rpcs3 & CS1_IE); break; case 005: /* RPDS */ @@ -692,30 +730,27 @@ update_rpcs (cs1f, drv); /* update status */ return SCPE_OK; } -/* Initiate operation */ +/* Initiate operation - unit not busy, function set */ -void rp_go (int32 drv) +void rp_go (int32 drv, int32 fnc) { -int32 dc, dtype, fnc; +int32 dc, dtype, t; UNIT *uptr; -fnc = GET_FNC (rpcs1); /* get function */ +if (DBG_LOG (LOG_RP)) fprintf (sim_log, + ">>RP%d: fnc=%o, ds=%o, cyl=%o, da=%o, ba=%o, wc=%o\n", + drv, fnc, rpds[drv], rpdc, rpda, (rpbae << 16) | rpba, rpwc); uptr = rp_dev.units + drv; /* get unit */ if (uptr -> flags & UNIT_DIS) { /* nx unit? */ rpcs2 = rpcs2 | CS2_NED; /* set error flag */ update_rpcs (CS1_SC, drv); /* request intr */ return; } -if (fnc != FNC_DCLR) { /* not clear? */ - if ((rpds[drv] & DS_ERR) || /* error or */ - ((rpds[drv] & DS_RDY) == 0)) { /* not ready? */ - rpcs2 = rpcs2 | CS2_PGE; /* set error flag */ - update_rpcs (CS1_SC, drv); /* request intr */ - return; } - if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ - rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ - update_rpcs (CS1_SC, drv); /* request intr */ - return; } } +if ((fnc != FNC_DCLR) && (rpds[drv] & DS_ERR)) { /* err & ~clear? */ + rper1[drv] = rper1[drv] | ER1_ILF; /* not allowed */ + rpds[drv] = rpds[drv] | DS_ATA; /* set attention */ + update_rpcs (CS1_SC, drv); /* request intr */ + return; } dtype = GET_DTYPE (uptr -> flags); /* get drive type */ rpds[drv] = rpds[drv] & ~DS_ATA; /* clear attention */ dc = rpdc; /* assume seek, sch */ @@ -738,7 +773,9 @@ case FNC_PACK: /* pack acknowledge */ case FNC_OFFSET: /* offset mode */ case FNC_RETURN: - uptr -> FUNC = fnc; /* save function */ + if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ + rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ + break; } rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ sim_activate (uptr, rp_swait); /* time operation */ return; @@ -748,38 +785,47 @@ case FNC_RECAL: /* recalibrate */ dc = 0; /* seek to 0 */ case FNC_SEEK: /* seek */ case FNC_SEARCH: /* search */ + if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ + rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ + break; } if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ (GET_SF (rpda) >= drv_tab[dtype].surf) || /* bad surface */ (GET_SC (rpda) >= drv_tab[dtype].sect)) { /* or bad sector? */ rper1[drv] = rper1[drv] | ER1_IAE; break; } rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ - sim_activate (uptr, rp_swait * abs (dc - uptr -> CYL)); - uptr -> FUNC = fnc; /* save function */ + t = abs (dc - uptr -> CYL); /* cyl diff */ + if (t == 0) t = 1; /* min time */ + sim_activate (uptr, rp_swait * t); /* schedule */ uptr -> CYL = dc; /* save cylinder */ return; +case FNC_WRITEH: /* write headers */ case FNC_WRITE: /* write */ case FNC_WCHK: /* write check */ case FNC_READ: /* read */ +case FNC_READH: /* read headers */ + if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ + rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ + break; } rpcs2 = rpcs2 & ~CS2_ERR; /* clear errors */ rpcs1 = rpcs1 & ~(CS1_TRE | CS1_MCPE | CS1_DONE); if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ (GET_SF (rpda) >= drv_tab[dtype].surf) || /* bad surface */ (GET_SC (rpda) >= drv_tab[dtype].sect)) { /* or bad sector? */ rper1[drv] = rper1[drv] | ER1_IAE; - update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */ - return; } + break; } rpds[drv] = rpds[drv] & ~DS_RDY; /* clear drive rdy */ sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr -> CYL))); - uptr -> FUNC = fnc; /* save function */ uptr -> CYL = dc; /* save cylinder */ return; default: /* all others */ rper1[drv] = rper1[drv] | ER1_ILF; /* not supported */ + rpds[drv] = rpds[drv] | DS_ATA; /* set attention */ break; } -update_rpcs (CS1_SC, drv); /* error, req intr */ +rpds[drv] = rpds[drv] | DS_ATA; /* error, set attn */ +update_rpcs (CS1_SC, drv); /* req intr */ return; } @@ -826,6 +872,7 @@ case FNC_WRITE: /* write */ break; } case FNC_WCHK: /* write check */ case FNC_READ: /* read */ +case FNC_READH: /* read headers */ ba = (rpbae << 16) | rpba; /* get byte addr */ da = GET_DA (rpdc, rpda, dtype) * RP_NUMWD; /* get disk addr */ wc = 0200000 - rpwc; /* get true wc */ @@ -882,20 +929,28 @@ case FNC_READ: /* read */ perror ("RP I/O error"); clearerr (uptr -> fileref); return SCPE_IOERR; } +case FNC_WRITEH: /* write headers stub */ update_rpcs (CS1_DONE, drv); /* set done */ - break; } /* end case function */ + break; } /* end case func */ return SCPE_OK; } -/* Controller status update - First update drive status, then update RPCS1 - If optional argument, request interrupt +/* Controller status update + + Check for done transition + Update drive status + Update RPCS1 + Update interrupt request */ void update_rpcs (int32 flag, int32 drv) { int32 i; +UNIT *uptr; +if ((flag & ~rpcs1) & CS1_DONE) /* DONE 0 to 1? */ + rpiff = (rpcs1 & CS1_IE)? 1: 0; /* CSTB INTR <- IE */ +uptr = rp_dev.units + drv; /* get unit */ if (rp_unit[drv].flags & UNIT_DIS) rpds[drv] = rper1[drv] = 0; else rpds[drv] = (rpds[drv] | DS_DPR) & ~DS_PGM; if (rp_unit[drv].flags & UNIT_ATT) rpds[drv] = rpds[drv] | DS_MOL; @@ -903,13 +958,16 @@ else rpds[drv] = rpds[drv] & ~(DS_MOL | DS_VV | DS_RDY); if (rper1[drv] | rper2 | rper3) rpds[drv] = rpds[drv] | DS_ERR | DS_ATA; else rpds[drv] = rpds[drv] & ~DS_ERR; -rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ)) | CS1_DVA | flag; +rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ | CS1_DRV)) | CS1_DVA | flag; +rpcs1 = rpcs1 | (uptr -> FUNC << CS1_V_FNC); +if (sim_is_active (uptr)) rpcs1 = rpcs1 | CS1_GO; if (rpcs2 & CS2_ERR) rpcs1 = rpcs1 | CS1_TRE | CS1_SC; +else if (rpcs1 & CS1_TRE) rpcs1 = rpcs1 | CS1_SC; for (i = 0; i < RP_NUMDR; i++) if (rpds[i] & DS_ATA) rpcs1 = rpcs1 | CS1_SC; -if (((rpcs1 & CS1_IE) == 0) || ((rpcs1 & CS1_DONE) == 0)) - int_req = int_req & ~INT_RP; -else if (flag) int_req = int_req | INT_RP; +if (rpiff || ((rpcs1 & CS1_SC) && (rpcs1 & CS1_DONE) && (rpcs1 & CS1_IE))) + SET_INT (RP); +else CLR_INT (RP); return; } @@ -917,8 +975,9 @@ return; int32 rp_inta (void) { -/* rpcs1 = rpcs1 & ~CS1_IE; /* clear int enable */ -/* rpcs3 = rpcs3 & ~CS1_IE; /* in both registers */ +rpcs1 = rpcs1 & ~CS1_IE; /* clear int enable */ +rpcs3 = rpcs3 & ~CS1_IE; /* in both registers */ +rpiff = 0; /* clear CSTB INTR */ return VEC_RP; /* acknowledge */ } @@ -936,7 +995,8 @@ rpof = rpdc = 0; rper2 = rper3 = 0; rpec1 = rpec2 = 0; rpbae = rpcs3 = 0; -int_req = int_req & ~INT_RP; +rpiff = 0; /* clear CSTB INTR */ +CLR_INT (RP); /* clear intr req */ for (i = 0; i < RP_NUMDR; i++) { uptr = rp_dev.units + i; sim_cancel (uptr); @@ -1013,8 +1073,8 @@ return pdp11_bad_block (uptr, drv_tab[GET_DTYPE (uptr -> flags)].sect, RP_NUMWD) /* Device bootstrap */ -#define BOOT_START 02000 /* start */ -#define BOOT_UNIT 02006 /* where to store unit number */ +#define BOOT_START 02000 /* start */ +#define BOOT_UNIT 02006 /* unit number */ #define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) static const int32 boot_rom[] = { diff --git a/pdp11_rx.c b/pdp11_rx.c index 5b035caa..99642ce2 100644 --- a/pdp11_rx.c +++ b/pdp11_rx.c @@ -25,6 +25,7 @@ rx RX11/RX01 floppy disk + 07-Sep-01 RMS Revised device disable and interrupt mechanisms 17-Jul-01 RMS Fixed warning from VC++ 6.0 26-Apr-01 RMS Added device enable/disable support 13-Apr-01 RMS Revised for register arrays @@ -88,7 +89,7 @@ #define TRACK u3 /* current track */ #define CALC_DA(t,s) (((t) * RX_NUMSC) + ((s) - 1)) * RX_NUMBY -extern int32 int_req, dev_enb; +extern int32 int_req[IPL_HLVL]; int32 rx_csr = 0; /* control/status */ int32 rx_dbr = 0; /* data buffer */ int32 rx_esr = 0; /* error status */ @@ -102,6 +103,7 @@ int32 rx_swait = 10; /* seek, per track */ int32 rx_xwait = 1; /* tr set time */ unsigned int8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */ int32 bptr = 0; /* buffer pointer */ +int32 rx_enb = 1; /* device enable */ t_stat rx_svc (UNIT *uptr); t_stat rx_reset (DEVICE *dptr); t_stat rx_boot (int32 unitno); @@ -129,7 +131,7 @@ REG rx_reg[] = { { ORDATA (RXSA, rx_sector, 8) }, { ORDATA (STAPTR, rx_state, 3), REG_RO }, { ORDATA (BUFPTR, bptr, 7) }, - { FLDATA (INT, int_req, INT_V_RX) }, + { FLDATA (INT, IREQ (RX), INT_V_RX) }, { FLDATA (ERR, rx_csr, CSR_V_ERR) }, { FLDATA (TR, rx_csr, RXCS_V_TR) }, { FLDATA (IE, rx_csr, CSR_V_IE) }, @@ -141,7 +143,7 @@ REG rx_reg[] = { { FLDATA (FLG1, rx_unit[1].flags, UNIT_V_WLK), REG_HRO }, { FLDATA (STOP_IOE, rx_stopioe, 0) }, { BRDATA (SBUF, rx_buf, 8, 8, RX_NUMBY) }, - { FLDATA (*DEVENB, dev_enb, INT_V_RX), REG_HRO }, + { FLDATA (*DEVENB, rx_enb, 0), REG_HRO }, { NULL } }; MTAB rx_mod[] = { @@ -222,9 +224,9 @@ case 0: /* RXCS */ sim_activate (&rx_unit[drv], rx_cwait); break; } /* end switch func */ return SCPE_OK; } /* end if GO */ - if ((data & CSR_IE) == 0) int_req = int_req & ~INT_RX; + if ((data & CSR_IE) == 0) CLR_INT (RX); else if ((rx_csr & (RXCS_DONE + CSR_IE)) == RXCS_DONE) - int_req = int_req | INT_RX; + SET_INT (RX); rx_csr = (rx_csr & ~RXCS_RW) | (data & RXCS_RW); break; /* end case RXCS */ @@ -351,7 +353,7 @@ return IORETURN (rx_stopioe, rval); void rx_done (int32 new_dbr, int32 new_ecode) { rx_csr = rx_csr | RXCS_DONE; /* set done */ -if (rx_csr & CSR_IE) int_req = int_req | INT_RX; /* if ie, intr */ +if (rx_csr & CSR_IE) SET_INT (RX); /* if ie, intr */ rx_dbr = new_dbr; /* update RXDB */ if (new_ecode != 0) { /* test for error */ rx_ecode = new_ecode; @@ -368,7 +370,7 @@ t_stat rx_reset (DEVICE *dptr) { rx_csr = rx_dbr = 0; /* clear regs */ rx_esr = rx_ecode = 0; /* clear error */ -int_req = int_req & ~INT_RX; /* clear int req */ +CLR_INT (RX); /* clear int req */ sim_cancel (&rx_unit[1]); /* cancel drive 1 */ if (rx_unit[0].flags & UNIT_BUF) { /* attached? */ rx_state = INIT_COMPLETE; /* yes, sched init */ diff --git a/pdp11_stddev.c b/pdp11_stddev.c index 29fa226e..3fea03a4 100644 --- a/pdp11_stddev.c +++ b/pdp11_stddev.c @@ -27,6 +27,8 @@ tti,tto DL11 terminal input/output clk KW11L line frequency clock + 07-Oct-01 RMS Upgraded clock to full KW11L for RSTS/E autoconfigure + 07-Sep-01 RMS Moved function prototypes, revised interrupt mechanism 17-Jul-01 RMS Moved function prototype 04-Jul-01 RMS Added DZ11 support 05-Mar-01 RMS Added clock calibration support @@ -44,11 +46,11 @@ #define TTICSR_RW (CSR_IE) #define TTOCSR_IMP (CSR_DONE + CSR_IE) /* terminal output */ #define TTOCSR_RW (CSR_IE) -#define CLKCSR_IMP (CSR_IE) /* real-time clock */ -#define CLKCSR_RW (CSR_IE) +#define CLKCSR_IMP (CSR_DONE + CSR_IE) /* real-time clock */ +#define CLKCSR_RW (CSR_DONE + CSR_IE) #define CLK_DELAY 8000 -extern int32 int_req; +extern int32 int_req[IPL_HLVL]; int32 ptr_csr = 0; /* control/status */ int32 ptr_stopioe = 0; /* stop on error */ int32 ptp_csr = 0; /* control/status */ @@ -57,7 +59,7 @@ int32 tti_csr = 0; /* control/status */ int32 tto_csr = 0; /* control/status */ int32 clk_csr = 0; /* control/status */ int32 clk_tps = 60; /* ticks/second */ -int32 dz_poll = CLK_DELAY; /* DZ poll inteval */ +int32 tmxr_poll = CLK_DELAY; /* term mux poll */ t_stat ptr_svc (UNIT *uptr); t_stat ptp_svc (UNIT *uptr); @@ -73,8 +75,6 @@ t_stat ptr_attach (UNIT *uptr, char *ptr); t_stat ptr_detach (UNIT *uptr); t_stat ptp_attach (UNIT *uptr, char *ptr); t_stat ptp_detach (UNIT *uptr); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); /* PTR data structures @@ -89,7 +89,7 @@ UNIT ptr_unit = { REG ptr_reg[] = { { ORDATA (BUF, ptr_unit.buf, 8) }, { ORDATA (CSR, ptr_csr, 16) }, - { FLDATA (INT, int_req, INT_V_PTR) }, + { FLDATA (INT, IREQ (PTR), INT_V_PTR) }, { FLDATA (ERR, ptr_csr, CSR_V_ERR) }, { FLDATA (BUSY, ptr_csr, CSR_V_BUSY) }, { FLDATA (DONE, ptr_csr, CSR_V_DONE) }, @@ -118,7 +118,7 @@ UNIT ptp_unit = { REG ptp_reg[] = { { ORDATA (BUF, ptp_unit.buf, 8) }, { ORDATA (CSR, ptp_csr, 16) }, - { FLDATA (INT, int_req, INT_V_PTP) }, + { FLDATA (INT, IREQ (PTP), INT_V_PTP) }, { FLDATA (ERR, ptp_csr, CSR_V_ERR) }, { FLDATA (DONE, ptp_csr, CSR_V_DONE) }, { FLDATA (IE, ptp_csr, CSR_V_IE) }, @@ -145,7 +145,7 @@ UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; REG tti_reg[] = { { ORDATA (BUF, tti_unit.buf, 8) }, { ORDATA (CSR, tti_csr, 16) }, - { FLDATA (INT, int_req, INT_V_TTI) }, + { FLDATA (INT, IREQ (TTI), INT_V_TTI) }, { FLDATA (ERR, tti_csr, CSR_V_ERR) }, { FLDATA (DONE, tti_csr, CSR_V_DONE) }, { FLDATA (IE, tti_csr, CSR_V_IE) }, @@ -171,7 +171,7 @@ UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { { ORDATA (BUF, tto_unit.buf, 8) }, { ORDATA (CSR, tto_csr, 16) }, - { FLDATA (INT, int_req, INT_V_TTO) }, + { FLDATA (INT, IREQ (TTO), INT_V_TTO) }, { FLDATA (ERR, tto_csr, CSR_V_ERR) }, { FLDATA (DONE, tto_csr, CSR_V_DONE) }, { FLDATA (IE, tto_csr, CSR_V_IE) }, @@ -196,7 +196,7 @@ UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 8000 }; REG clk_reg[] = { { ORDATA (CSR, clk_csr, 16) }, - { FLDATA (INT, int_req, INT_V_CLK) }, + { FLDATA (INT, IREQ (CLK), INT_V_CLK) }, { FLDATA (DONE, clk_csr, CSR_V_DONE) }, { FLDATA (IE, clk_csr, CSR_V_IE) }, { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT }, @@ -236,7 +236,7 @@ case 04: /* ptr csr */ return SCPE_OK; case 05: /* ptr buf */ ptr_csr = ptr_csr & ~CSR_DONE; - int_req = int_req & ~INT_PTR; + CLR_INT (PTR); *data = ptr_unit.buf & 0377; return SCPE_OK; case 06: /* ptp csr */ @@ -250,7 +250,7 @@ case 010: /* tti csr */ return SCPE_OK; case 011: /* tti buf */ tti_csr = tti_csr & ~CSR_DONE; - int_req = int_req & ~INT_TTI; + CLR_INT (TTI); *data = tti_unit.buf & 0377; return SCPE_OK; case 012: /* tto csr */ @@ -267,17 +267,20 @@ t_stat std_wr (int32 data, int32 PA, int32 access) switch ((PA >> 1) & 017) { /* decode PA<4:1> */ case 03: /* clk csr */ if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) int_req = int_req & ~INT_CLK; + if (((data & CSR_IE) == 0) || /* clr IE, DONE? */ + ((data & CSR_DONE) == 0)) CLR_INT (CLK); /* clr intr */ + else if (((clk_csr & CSR_IE) == 0) || /* setting both */ + ((clk_csr & CSR_DONE) == 0)) SET_INT (CLK); /* if prv clr, intr */ clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW); return SCPE_OK; case 04: /* ptr csr */ if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) int_req = int_req & ~INT_PTR; + if ((data & CSR_IE) == 0) CLR_INT (PTR); else if (((ptr_csr & CSR_IE) == 0) && (ptr_csr & (CSR_ERR | CSR_DONE))) - int_req = int_req | INT_PTR; + SET_INT (PTR); if (data & CSR_GO) { ptr_csr = (ptr_csr & ~CSR_DONE) | CSR_BUSY; - int_req = int_req & ~INT_PTR; + CLR_INT (PTR); if (ptr_unit.flags & UNIT_ATT) /* data to read? */ sim_activate (&ptr_unit, ptr_unit.wait); else sim_activate (&ptr_unit, 0); } /* error if not */ @@ -287,39 +290,39 @@ case 05: /* ptr buf */ return SCPE_OK; case 06: /* ptp csr */ if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) int_req = int_req & ~INT_PTP; + if ((data & CSR_IE) == 0) CLR_INT (PTP); else if (((ptp_csr & CSR_IE) == 0) && (ptp_csr & (CSR_ERR | CSR_DONE))) - int_req = int_req | INT_PTP; + SET_INT (PTP); ptp_csr = (ptp_csr & ~PTPCSR_RW) | (data & PTPCSR_RW); return SCPE_OK; case 07: /* ptp buf */ if ((PA & 1) == 0) ptp_unit.buf = data & 0377; ptp_csr = ptp_csr & ~CSR_DONE; - int_req = int_req & ~INT_PTP; + CLR_INT (PTP); if (ptp_unit.flags & UNIT_ATT) /* file to write? */ sim_activate (&ptp_unit, ptp_unit.wait); else sim_activate (&ptp_unit, 0); /* error if not */ return SCPE_OK; case 010: /* tti csr */ if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) int_req = int_req & ~INT_TTI; + if ((data & CSR_IE) == 0) CLR_INT (TTI); else if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) - int_req = int_req | INT_TTI; + SET_INT (TTI); tti_csr = (tti_csr & ~TTICSR_RW) | (data & TTICSR_RW); return SCPE_OK; case 011: /* tti buf */ return SCPE_OK; case 012: /* tto csr */ if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) int_req = int_req & ~INT_TTO; + if ((data & CSR_IE) == 0) CLR_INT (TTO); else if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) - int_req = int_req | INT_TTO; + SET_INT (TTO); tto_csr = (tto_csr & ~TTOCSR_RW) | (data & TTOCSR_RW); return SCPE_OK; case 013: /* tto buf */ if ((PA & 1) == 0) tto_unit.buf = data & 0377; tto_csr = tto_csr & ~CSR_DONE; - int_req = int_req & ~INT_TTO; + CLR_INT (TTO); sim_activate (&tto_unit, tto_unit.wait); return SCPE_OK; } /* end switch PA */ return SCPE_NXM; @@ -338,7 +341,7 @@ t_stat ptr_svc (UNIT *uptr) int32 temp; ptr_csr = (ptr_csr | CSR_ERR) & ~CSR_BUSY; -if (ptr_csr & CSR_IE) int_req = int_req | INT_PTR; +if (ptr_csr & CSR_IE) SET_INT (PTR); if ((ptr_unit.flags & UNIT_ATT) == 0) return IORETURN (ptr_stopioe, SCPE_UNATT); if ((temp = getc (ptr_unit.fileref)) == EOF) { @@ -359,7 +362,7 @@ t_stat ptr_reset (DEVICE *dptr) ptr_unit.buf = 0; ptr_csr = 0; if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR; -int_req = int_req & ~INT_PTR; +CLR_INT (PTR); sim_cancel (&ptr_unit); return SCPE_OK; } @@ -391,7 +394,7 @@ return detach_unit (uptr); t_stat ptp_svc (UNIT *uptr) { ptp_csr = ptp_csr | CSR_ERR | CSR_DONE; -if (ptp_csr & CSR_IE) int_req = int_req | INT_PTP; +if (ptp_csr & CSR_IE) SET_INT (PTP); if ((ptp_unit.flags & UNIT_ATT) == 0) return IORETURN (ptp_stopioe, SCPE_UNATT); if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { @@ -408,7 +411,7 @@ t_stat ptp_reset (DEVICE *dptr) ptp_unit.buf = 0; ptp_csr = CSR_DONE; if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR; -int_req = int_req & ~INT_PTP; +CLR_INT (PTP); sim_cancel (&ptp_unit); /* deactivate unit */ return SCPE_OK; } @@ -444,7 +447,7 @@ if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ tti_unit.buf = temp & 0377; tti_unit.pos = tti_unit.pos + 1; tti_csr = tti_csr | CSR_DONE; -if (tti_csr & CSR_IE) int_req = int_req | INT_TTI; +if (tti_csr & CSR_IE) SET_INT (TTI); return SCPE_OK; } @@ -452,7 +455,7 @@ t_stat tti_reset (DEVICE *dptr) { tti_unit.buf = 0; tti_csr = 0; -int_req = int_req & ~INT_TTI; +CLR_INT (TTI); sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ return SCPE_OK; } @@ -468,7 +471,7 @@ t_stat tto_svc (UNIT *uptr) int32 temp; tto_csr = tto_csr | CSR_DONE; -if (tto_csr & CSR_IE) int_req = int_req | INT_TTO; +if (tto_csr & CSR_IE) SET_INT (TTO); if ((temp = sim_putchar (tto_unit.buf & 0177)) != SCPE_OK) return temp; tto_unit.pos = tto_unit.pos + 1; return SCPE_OK; @@ -478,7 +481,7 @@ t_stat tto_reset (DEVICE *dptr) { tto_unit.buf = 0; tto_csr = CSR_DONE; -int_req = int_req & ~INT_TTO; +CLR_INT (TTO); sim_cancel (&tto_unit); /* deactivate unit */ return SCPE_OK; } @@ -493,18 +496,19 @@ t_stat clk_svc (UNIT *uptr) { int32 t; -if (clk_csr & CSR_IE) int_req = int_req | INT_CLK; +clk_csr = clk_csr | CSR_DONE; /* set done */ +if (clk_csr & CSR_IE) SET_INT (CLK); t = sim_rtc_calb (clk_tps); /* calibrate clock */ sim_activate (&clk_unit, t); /* reactivate unit */ -dz_poll = t; /* set DZ poll */ +tmxr_poll = t; /* set mux poll */ return SCPE_OK; } t_stat clk_reset (DEVICE *dptr) { clk_csr = 0; -int_req = int_req & ~INT_CLK; +CLR_INT (CLK); sim_activate (&clk_unit, clk_unit.wait); /* activate unit */ -dz_poll = clk_unit.wait; /* set DZ poll */ +tmxr_poll = clk_unit.wait; /* set mux poll */ return SCPE_OK; } diff --git a/pdp11_sys.c b/pdp11_sys.c index 89546de2..0df7e8dc 100644 --- a/pdp11_sys.c +++ b/pdp11_sys.c @@ -23,6 +23,8 @@ 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. + 17-Sep-01 RMS Removed multiconsole support + 26-Aug-01 RMS Added DZ11 20-Aug-01 RMS Updated bad block inquiry 17-Jul-01 RMS Fixed warning from VC++ 6.0 27-May-01 RMS Added multiconsole support @@ -45,6 +47,7 @@ extern DEVICE cpu_dev; extern DEVICE ptr_dev, ptp_dev; extern DEVICE tti_dev, tto_dev; extern DEVICE lpt_dev, clk_dev; +extern DEVICE dz_dev; extern DEVICE rk_dev, rx_dev; extern DEVICE rl_dev, rp_dev; extern DEVICE dt_dev, tm_dev; @@ -61,7 +64,6 @@ extern int32 saved_PC; sim_PC pointer to saved PC register descriptor sim_emax number of words for examine sim_devices array of pointers to simulated devices - sim_consoles array of pointers to consoles (if more than one) sim_stop_messages array of pointers to stop messages sim_load binary loader */ @@ -77,14 +79,13 @@ DEVICE *sim_devices[] = { &ptr_dev, &ptp_dev, &tti_dev, &tto_dev, &lpt_dev, &clk_dev, + &dz_dev, &rk_dev, /* &hk_dev, */ &rl_dev, &rp_dev, &rx_dev, &dt_dev, &tm_dev, &ts_dev, NULL }; -UNIT *sim_consoles = NULL; - const char *sim_stop_messages[] = { "Unknown error", "Red stack trap", @@ -317,7 +318,7 @@ static const char *opcode[] = { "SOB", "BPL","BMI","BHI","BLOS", "BVC","BVS","BCC","BCS", -"BHIS","BLO", /* encode only */ +"BHIS","BLO", /* encode only */ "EMT","TRAP", "CLRB","COMB","INCB","DECB", "NEGB","ADCB","SBCB","TSTB", diff --git a/pdp11_tc.c b/pdp11_tc.c index bbfae487..f48a6fed 100644 --- a/pdp11_tc.c +++ b/pdp11_tc.c @@ -25,6 +25,10 @@ tc TC11/TU56 DECtape + 15-Sep-01 RMS Integrated debug logging + 27-Sep-01 RMS Fixed interrupt after stop for RSTS/E + 07-Sep-01 RMS Revised device disable and interrupt mechanisms + 29-Aug-01 RMS Added casts to PDP-8 unpack routine 17-Jul-01 RMS Moved function prototype 11-May-01 RMS Fixed bug in reset 26-Apr-01 RMS Added device enable/disable support @@ -228,27 +232,30 @@ #define LOG_BL 010 /* block # lblk */ #define DT_SETDONE tccm = tccm | CSR_DONE; \ - if (tccm & CSR_IE) int_req = int_req | INT_DTA + if (tccm & CSR_IE) SET_INT (DTA) #define DT_CLRDONE tccm = tccm & ~CSR_DONE; \ - int_req = int_req & ~INT_DTA + CLR_INT (DTA) #define ABS(x) (((x) < 0)? (-(x)): (x)) extern uint16 *M; /* memory */ -extern int32 int_req, dev_enb; +extern int32 int_req[IPL_HLVL]; extern UNIT cpu_unit; extern int32 sim_switches; +extern int32 pdp11_log; +extern FILE *sim_log; int32 tcst = 0; /* status */ int32 tccm = 0; /* command */ int32 tcwc = 0; /* word count */ int32 tcba = 0; /* bus address */ int32 tcdt = 0; /* data */ -int32 dt_ctime = 4; /* fast cmd time */ +int32 dt_ctime = 100; /* fast cmd time */ int32 dt_ltime = 12; /* interline time */ int32 dt_actime = 54000; /* accel time */ int32 dt_dctime = 72000; /* decel time */ int32 dt_substate = 0; -int32 dt_log = 0; int32 dt_logblk = 0; +int32 dt_enb = 1; /* device enable */ + t_stat dt_svc (UNIT *uptr); t_stat dt_svcdone (UNIT *uptr); t_stat dt_reset (DEVICE *dptr); @@ -294,7 +301,7 @@ REG dt_reg[] = { { ORDATA (TCWC, tcwc, 16) }, { ORDATA (TCBA, tcba, 16) }, { ORDATA (TCDT, tcdt, 16) }, - { FLDATA (INT, int_req, INT_V_DTA) }, + { FLDATA (INT, IREQ (DTA), INT_V_DTA) }, { FLDATA (ERR, tccm, CSR_V_ERR) }, { FLDATA (DONE, tccm, CSR_V_DONE) }, { FLDATA (IE, tccm, CSR_V_DONE) }, @@ -303,7 +310,6 @@ REG dt_reg[] = { { DRDATA (ACTIME, dt_actime, 31), REG_NZ }, { DRDATA (DCTIME, dt_dctime, 31), REG_NZ }, { ORDATA (SUBSTATE, dt_substate, 1) }, - { ORDATA (LOG, dt_log, 4), REG_HIDDEN }, { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, { DRDATA (POS0, dt_unit[0].pos, 31), PV_LEFT + REG_RO }, { DRDATA (POS1, dt_unit[1].pos, 31), PV_LEFT + REG_RO }, @@ -345,7 +351,7 @@ REG dt_reg[] = { REG_HRO }, { GRDATA (FLG7, dt_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), REG_HRO }, - { FLDATA (*DEVENB, dev_enb, INT_V_DTA), REG_HRO }, + { FLDATA (*DEVENB, dt_enb, 0), REG_HRO }, { NULL } }; MTAB dt_mod[] = { @@ -411,14 +417,14 @@ case 001: /* TCCM */ old_tccm = tccm; /* save prior */ if (access == WRITEB) data = (PA & 1)? (tccm & 0377) | (data << 8): (tccm & ~0377) | data; - if ((data & CSR_IE) == 0) int_req = int_req & ~INT_DTA; + if ((data & CSR_IE) == 0) CLR_INT (DTA); else if ((((tccm & CSR_IE) == 0) && (tccm & CSR_DONE)) || - (data & CSR_DONE)) int_req = int_req | INT_DTA; + (data & CSR_DONE)) SET_INT (DTA); tccm = (tccm & ~CSR_RW) | (data & CSR_RW); if ((data & CSR_GO) && (tccm & CSR_DONE)) { /* new cmd? */ tcst = tcst & ~STA_ALLERR; /* clear errors */ tccm = tccm & ~(CSR_ERR | CSR_DONE); /* clear done, err */ - int_req = int_req & ~INT_DTA; /* clear int */ + CLR_INT (DTA); /* clear int */ if ((old_tccm ^ tccm) & CSR_UNIT) dt_deselect (old_tccm); unum = CSR_GETUNIT (tccm); /* get drive */ fnc = CSR_GETFNC (tccm); /* get function */ @@ -581,8 +587,8 @@ case FNC_SRCH: /* search */ DTU_TSIZE (uptr): blk), uptr) - DT_BLKLN - DT_WSIZE; else newpos = DT_BLK2LN ((DT_QREZ (uptr)? 0: blk + 1), uptr) + DT_BLKLN + (DT_WSIZE - 1); - if (dt_log & LOG_MS) printf ("[DT%d: searching %s]\n", unum, - (dir? "backward": "forward")); + if (DBG_LOG (LOG_TC_MS)) fprintf (sim_log, ">>DT%d: searching %s\n", + unum, (dir? "backward": "forward")); break; case FNC_WRIT: /* write */ case FNC_READ: /* read */ @@ -599,8 +605,8 @@ case FNC_READ: /* read */ blk + 1: blk), uptr) - DT_HTLIN - DT_WSIZE; else newpos = DT_BLK2LN (((relpos < DT_HTLIN)? blk: blk + 1), uptr) + DT_HTLIN + (DT_WSIZE - 1); - if ((dt_log & LOG_RW) || ((dt_log & LOG_BL) && (blk == dt_logblk))) - printf ("[DT%d: %s block %d %s]\n", + if (DBG_LOG (LOG_TC_RW) || (DBG_LOG (LOG_TC_BL) && (blk == dt_logblk))) + fprintf (sim_log, ">>DT%d: %s block %d %s\n", unum, ((fnc == FNC_READ)? "read": "write"), blk, (dir? "backward": "forward")); break; @@ -618,8 +624,8 @@ case FNC_WALL: /* write all */ else newpos = DT_BLK2LN (blk, uptr) + DT_CSMLN + (DT_WSIZE - 1); } if (fnc == FNC_WALL) sim_activate /* write all? */ (&dt_dev.units[DT_TIMER], dt_ctime); /* sched done */ - if ((dt_log & LOG_RA) || ((dt_log & LOG_BL) && (blk == dt_logblk))) - printf ("[DT%d: read all block %d %s]\n", + if (DBG_LOG (LOG_TC_RW) || (DBG_LOG (LOG_TC_BL) && (blk == dt_logblk))) + fprintf (sim_log, ">>DT%d: read all block %d %s\n", unum, blk, (dir? "backward": "forward")); break; default: @@ -685,11 +691,11 @@ if ((uptr -> pos < 0) || return FALSE; } -/* Command timer service after stop - set done but not interrupt */ +/* Command timer service after stop - set done */ t_stat dt_svcdone (UNIT *uptr) { -tccm = tccm | CSR_DONE; +DT_SETDONE; return SCPE_OK; } @@ -932,7 +938,7 @@ int32 ba = blk * DTU_BSIZE (uptr); int32 i, csum, wrd; csum = 077; /* init csum */ -for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ +for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ wrd = bptr[ba + i] ^ 0777777; /* get ~word */ csum = csum ^ (wrd >> 12) ^ (wrd >> 6) ^ wrd; } return (csum & 077); @@ -974,14 +980,14 @@ for (i = 0; i < DT_NUMDR; i++) { /* stop all activity */ uptr -> LASTT = sim_grtime (); } } tcst = tcwc = tcba = tcdt = 0; /* clear reg */ tccm = CSR_DONE; -int_req = int_req & ~INT_DTA; /* clear int req */ +CLR_INT (DTA); /* clear int req */ return SCPE_OK; } /* Device bootstrap */ -#define BOOT_START 02000 /* start */ -#define BOOT_UNIT 02006 /* where to store unit number */ +#define BOOT_START 02000 /* start */ +#define BOOT_UNIT 02006 /* unit number */ #define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) static const int32 boot_rom[] = { @@ -1064,7 +1070,7 @@ uptr -> filebuf = calloc (uptr -> capac, sizeof (int32)); if (uptr -> filebuf == NULL) { /* can't alloc? */ detach_unit (uptr); return SCPE_MEM; } -printf ("%TC: buffering file in memory\n"); +printf ("TC: buffering file in memory\n"); rewind (uptr -> fileref); /* start of file */ if (uptr -> flags & UNIT_8FMT) { /* PDP-8? */ bptr = uptr -> filebuf; /* file buffer */ @@ -1073,10 +1079,10 @@ if (uptr -> flags & UNIT_8FMT) { /* PDP-8? */ if (k == 0) break; for ( ; k < D8_NBSIZE; k++) pdp8b[k] = 0; for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */ - bptr[ba] = ((pdp8b[k] & 07777) << 6) | - ((pdp8b[k + 1] >> 6) & 077); + bptr[ba] = ((uint32) (pdp8b[k] & 07777) << 6) | + ((uint32) (pdp8b[k + 1] >> 6) & 077); bptr[ba + 1] = ((pdp8b[k + 1] & 077) << 12) | - (pdp8b[k + 2] & 07777); + ((uint32) (pdp8b[k + 2] & 07777)); ba = ba + 2; } /* end blk loop */ } /* end file loop */ uptr -> hwmark = ba; } /* end if */ @@ -1109,7 +1115,7 @@ if (sim_is_active (uptr)) { /* active? cancel op */ if ((unum == CSR_GETUNIT (tccm)) && ((tccm & CSR_DONE) == 0)) { tcst = tcst | STA_SEL; tccm = tccm | CSR_ERR | CSR_DONE; - if (tccm & CSR_IE) int_req = int_req | INT_DTA; } + if (tccm & CSR_IE) SET_INT (DTA); } uptr -> STATE = uptr -> pos = 0; } if (uptr -> hwmark) { /* any data? */ printf ("TC: writing buffer to file\n"); diff --git a/pdp11_tm.c b/pdp11_tm.c index 804a6046..c400e5da 100644 --- a/pdp11_tm.c +++ b/pdp11_tm.c @@ -25,6 +25,8 @@ tm TM11/TU10 magtape + 18-Oct-01 RMS Added stub diagnostic register (found by Thord Nilson) + 07-Sep-01 RMS Revised device disable and interrupt mechanisms 26-Apr-01 RMS Added device enable/disable support 18-Apr-01 RMS Changed to rewind tape before boot 14-Apr-99 RMS Changed t_addr to unsigned @@ -124,17 +126,24 @@ #define STA_EFLGS (STA_ILL | STA_EOF | STA_CRC | STA_PAR | \ STA_DLT | STA_EOT | STA_RLE | STA_BAD | STA_NXM) /* set error */ + +/* Read lines - tm_rdl */ + +#define RDL_CLK 0100000 /* 10 Khz clock */ extern uint16 *M; /* memory */ -extern int32 int_req, dev_enb; +extern int32 int_req[IPL_HLVL]; extern UNIT cpu_unit; int32 tm_sta = 0; /* status register */ int32 tm_cmd = 0; /* command register */ int32 tm_ca = 0; /* current address */ int32 tm_bc = 0; /* byte count */ int32 tm_db = 0; /* data buffer */ +int32 tm_rdl = 0; /* read lines */ int32 tm_time = 10; /* record latency */ int32 tm_stopioe = 1; /* stop on error */ +int32 tm_enb = 1; /* device enable */ + t_stat tm_svc (UNIT *uptr); t_stat tm_reset (DEVICE *dptr); t_stat tm_attach (UNIT *uptr, char *cptr); @@ -169,7 +178,8 @@ REG tm_reg[] = { { ORDATA (MTBRC, tm_bc, 16) }, { ORDATA (MTCMA, tm_ca, 16) }, { ORDATA (MTD, tm_db, 8) }, - { FLDATA (INT, int_req, INT_V_TM) }, + { ORDATA (MTRD, tm_rdl, 16) }, + { FLDATA (INT, IREQ (TM), INT_V_TM) }, { FLDATA (ERR, tm_cmd, CSR_V_ERR) }, { FLDATA (DONE, tm_cmd, CSR_V_DONE) }, { FLDATA (IE, tm_cmd, CSR_V_IE) }, @@ -207,7 +217,7 @@ REG tm_reg[] = { REG_HRO }, { GRDATA (FLG7, tm_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), REG_HRO }, - { FLDATA (*DEVENB, dev_enb, INT_V_TM), REG_HRO }, + { FLDATA (*DEVENB, tm_enb, 0), REG_HRO }, { NULL } }; MTAB tm_mod[] = { @@ -229,7 +239,7 @@ DEVICE tm_dev = { 17772524 MTBRC read/write 17772526 MTCMA read/write 17772530 MTD read/write - 17772532 MTRD unimplemented + 17772532 MTRD read only */ t_stat tm_rd (int32 *data, int32 PA, int32 access) @@ -240,23 +250,28 @@ uptr = tm_dev.units + GET_UNIT (tm_cmd); /* get unit */ switch ((PA >> 1) & 07) { /* decode PA<3:1> */ case 0: /* MTS */ *data = tm_updcsta (uptr); /* update status */ - return SCPE_OK; + break; case 1: /* MTC */ tm_updcsta (uptr); /* update status */ *data = tm_cmd; /* return command */ - return SCPE_OK; + break; case 2: /* MTBRC */ *data = tm_bc; /* return byte count */ - return SCPE_OK; + break; case 3: /* MTCMA */ *data = tm_ca; /* return mem addr */ - return SCPE_OK; + break; case 4: /* MTD */ *data = tm_db; /* return data buffer */ - return SCPE_OK; + break; +case 5: /* MTRD */ + tm_rdl = tm_rdl ^ RDL_CLK; /* "clock" ticks */ + *data = tm_rdl; + break; default: /* unimplemented */ *data = 0; - return SCPE_OK; } + break; } +return SCPE_OK; } t_stat tm_wr (int32 data, int32 PA, int32 access) @@ -265,7 +280,7 @@ UNIT *uptr; switch ((PA >> 1) & 07) { /* decode PA<3:1> */ case 0: /* MTS: read only */ - return SCPE_OK; + break; case 1: /* MTC */ uptr = tm_dev.units + GET_UNIT (tm_cmd); /* select unit */ if ((tm_cmd & MTC_DONE) == 0) tm_sta = tm_sta | STA_ILL; @@ -276,30 +291,29 @@ case 1: /* MTC */ tm_reset (&tm_dev); /* reset device */ return SCPE_OK; } if ((data & MTC_IE) == 0) /* int disable? */ - int_req = int_req & ~INT_TM; /* clr int request */ + CLR_INT (TM); /* clr int request */ else if ((tm_cmd & (MTC_ERR + MTC_DONE)) && !(tm_cmd & MTC_IE)) - int_req = int_req | INT_TM; /* set int request */ + SET_INT (TM); /* set int request */ tm_cmd = (tm_cmd & ~MTC_RW) | (data & MTC_RW); uptr = tm_dev.units + GET_UNIT (tm_cmd); /* new unit */ if (data & MTC_GO) tm_go (uptr); } /* new function? */ tm_updcsta (uptr); /* update status */ - return SCPE_OK; + break; case 2: /* MTBRC */ if (access == WRITEB) data = (PA & 1)? (tm_bc & 0377) | (data << 8): (tm_bc & ~0377) | data; tm_bc = data; - return SCPE_OK; + break; case 3: /* MTCMA */ if (access == WRITEB) data = (PA & 1)? (tm_ca & 0377) | (data << 8): (tm_ca & ~0377) | data; tm_ca = data; - return SCPE_OK; + break; case 4: /* MTD */ if ((access == WRITEB) && (PA & 1)) return SCPE_OK; tm_db = data & 0377; - return SCPE_OK; -default: - return SCPE_OK; } /* end switch */ + break; } /* end switch */ +return SCPE_OK; } /* New magtape command */ @@ -325,7 +339,7 @@ else if (f == MTC_REWIND) /* rewind */ uptr -> USTAT = uptr -> USTAT | STA_REW; /* rewinding */ /* else /* uncomment this else if rewind/unload don't set done */ tm_cmd = tm_cmd & ~MTC_DONE; /* clear done */ -int_req = int_req & ~INT_TM; /* clear int */ +CLR_INT (TM); /* clear int */ sim_activate (uptr, tm_time); /* start io */ return; } @@ -501,7 +515,7 @@ if (sim_is_active (uptr)) tm_sta = tm_sta & ~STA_TUR; else tm_sta = tm_sta | STA_TUR; if (tm_sta & STA_EFLGS) tm_cmd = tm_cmd | MTC_ERR; else tm_cmd = tm_cmd & ~MTC_ERR; -if ((tm_cmd & MTC_IE) == 0) int_req = int_req & ~INT_TM; +if ((tm_cmd & MTC_IE) == 0) CLR_INT (TM); return tm_sta; } @@ -510,7 +524,7 @@ return tm_sta; void tm_set_done (void) { tm_cmd = tm_cmd | MTC_DONE; -if (tm_cmd & MTC_IE) int_req = int_req | INT_TM; +if (tm_cmd & MTC_IE) SET_INT (TM); return; } @@ -520,11 +534,12 @@ t_stat tm_reset (DEVICE *dptr) { int32 u; UNIT *uptr; +extern int32 ts_enb; -if (dev_enb & INT_TM) dev_enb = dev_enb & ~INT_TS; /* TM or TS */ +if (tm_enb) ts_enb = 0; /* TM or TS */ tm_cmd = MTC_DONE; /* set done */ -tm_bc = tm_ca = tm_db = tm_sta = 0; -int_req = int_req & ~INT_TM; /* clear interrupt */ +tm_bc = tm_ca = tm_db = tm_sta = tm_rdl = 0; +CLR_INT (TM); /* clear interrupt */ for (u = 0; u < TM_NUMDR; u++) { /* loop thru units */ uptr = tm_dev.units + u; uptr -> UNUM = u; /* init drive number */ diff --git a/pdp11_ts.c b/pdp11_ts.c index d899e8f0..bbe9ffb1 100644 --- a/pdp11_ts.c +++ b/pdp11_ts.c @@ -25,6 +25,12 @@ ts TS11/TSV05 magtape + 15-Oct-01 RMS Integrated debug logging across simulator + 27-Sep-01 RMS Implemented extended characteristics and status + Fixed bug in write characteristics status return + 19-Sep-01 RMS Fixed bug in bootstrap + 15-Sep-01 RMS Fixed bug in NXM test + 07-Sep-01 RMS Revised device disable and interrupt mechanism 13-Jul-01 RMS Fixed bug in space reverse (found by Peter Schorn) Magnetic tapes are represented as a series of variable 8b records @@ -171,24 +177,28 @@ /* Extended status register 1 - none of these errors are ever set */ -/* Extended status register 2 - none of these errors are ever set */ +/* Extended status register 2 */ + +#define XS2_XTF 0000200 /* ext features */ /* Extended status register 3 */ -#define XS3_XTF 0000200 /* ext features */ #define XS3_OPI 0000100 /* op incomplete */ #define XS3_REV 0000040 /* reverse */ #define XS3_RIB 0000001 /* reverse to BOT */ -/* Extended status register 4 - none of these errors are ever set */ +/* Extended status register 4 */ + +#define XS4_HDS 0100000 /* high density */ /* Write characteristics packet offsets */ -#define WCH_PLNT 4 /* packet length */ +#define WCH_PLNT 5 /* packet length */ #define wchadl tswchp[0] /* address low */ #define wchadh tswchp[1] /* address high */ #define wchlnt tswchp[2] /* length */ #define wchopt tswchp[3] /* options */ +#define wchxopt tswchp[4] /* ext options */ /* Write characteristics options */ @@ -197,6 +207,10 @@ #define WCH_EAI 0000040 /* enb attn int */ #define WCH_ERI 0000020 /* enb mrls int */ +/* Write characteristics extended options */ + +#define WCHX_HDS 0000040 /* high density */ + #define MAX(a,b) (((a) >= (b))? (a): (b)) #define READ_BYTE(p) ((M[(p) >> 1] >> (((p) & 1)? 8: 0)) & 0377) #define WRITE_BYTE(d,p) M[(p) >> 1] = (p & 1)? \ @@ -204,8 +218,10 @@ ((M[(p) >> 1] & ~0377) | (d)) extern uint16 *M; /* memory */ -extern int32 int_req, dev_enb; +extern int32 int_req[IPL_HLVL]; extern UNIT cpu_unit; +extern FILE *sim_log; +extern int32 pdp11_log; int32 tssr = 0; /* status register */ int32 tsba = 0; /* mem addr */ int32 tsdbx = 0; /* data buf ext */ @@ -217,7 +233,7 @@ int32 ts_ownm = 0; /* tape owns msg */ int32 ts_qatn = 0; /* queued attn */ int32 ts_bcmd = 0; /* boot cmd */ int32 ts_time = 10; /* record latency */ -int32 ts_log = 0; +int32 ts_enb = 0; /* device enable */ static uint8 dbuf[DBSIZE]; t_stat ts_svc (UNIT *uptr); @@ -259,6 +275,8 @@ REG ts_reg[] = { { ORDATA (WADH, wchadh, 16) }, { ORDATA (WLNT, wchlnt, 16) }, { ORDATA (WOPT, wchopt, 16) }, + { ORDATA (WXOPT, wchxopt, 16) }, + { FLDATA (INT, IREQ (TS), INT_V_TS) }, { FLDATA (ATTN, ts_qatn, 0) }, { FLDATA (BOOT, ts_bcmd, 0) }, { FLDATA (OWNC, ts_ownc, 0) }, @@ -266,8 +284,7 @@ REG ts_reg[] = { { DRDATA (TIME, ts_time, 24), PV_LEFT + REG_NZ }, { DRDATA (POS, ts_unit.pos, 31), PV_LEFT + REG_RO }, { FLDATA (WLK, ts_unit.flags, UNIT_V_WLK), REG_HRO }, - { FLDATA (LOG, ts_log, 0), REG_HIDDEN }, - { FLDATA (*DEVENB, dev_enb, INT_V_TS), REG_HRO }, + { FLDATA (*DEVENB, ts_enb, 0), REG_HRO }, { NULL } }; MTAB ts_mod[] = { @@ -314,10 +331,10 @@ case 0: /* TSDB */ tssr = ts_updtssr (tssr & TSSR_NBA); /* clr ssr, err */ msgxs0 = ts_updxs0 (msgxs0 & ~XS0_ALLERR); /* clr err, upd xs0 */ msgrfc = msgxs1 = msgxs2 = msgxs3 = msgxs4 = 0; /* clr status */ - int_req = int_req & ~INT_TS; /* clr int req */ + CLR_INT (TS); /* clr int req */ for (i = 0; i < CMD_PLNT; i++) { /* get cmd pkt */ if (ADDR_IS_MEM (tsba)) tscmdp[i] = M[(tsba >> 1)]; - else { ts_endcmd (TSSR_NXM + TC3, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL); + else { ts_endcmd (TSSR_NXM + TC5, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL); return SCPE_OK; } tsba = tsba + 2; } /* incr tsba */ ts_ownc = ts_ownm = 1; /* tape owns all */ @@ -574,12 +591,12 @@ if (ts_bcmd) { /* boot? */ ts_readf (uptr, 512); /* read blk */ tssr = ts_updtssr (tssr | TSSR_SSR); } else tssr = ts_updtssr (tssr | TSSR_SSR | TC3); - if (cmdhdr & CMD_IE) int_req = int_req | INT_TS; + if (cmdhdr & CMD_IE) SET_INT (TS); return SCPE_OK; } if (!(cmdhdr & CMD_ACK)) { /* no acknowledge? */ tssr = ts_updtssr (tssr | TSSR_SSR); /* set rdy, int */ - if (cmdhdr & CMD_IE) int_req = int_req | INT_TS; + if (cmdhdr & CMD_IE) SET_INT (TS); ts_ownc = ts_ownm = 0; /* CPU owns all */ return SCPE_OK; } fnc = GET_FNC (cmdhdr); /* get fnc+mode */ @@ -589,7 +606,7 @@ if ((fnc != FNC_WCHR) && (tssr & TSSR_NBA)) { /* ~wr chr & nba? */ return SCPE_OK; } if (ts_qatn && (wchopt & WCH_EAI)) { /* attn pending? */ ts_endcmd (TC1, 0, MSG_MATN | MSG_CATN); /* send attn msg */ - int_req = int_req | INT_TS; /* set interrupt */ + SET_INT (TS); /* set interrupt */ ts_qatn = 0; /* not pending */ return SCPE_OK; } if (cmdhdr & CMD_CVC) /* cvc? clr vck */ @@ -628,13 +645,13 @@ case FNC_WCHR: /* write char */ break; } tsba = (cmdadh << 16) | cmdadl; for (i = 0; (i < WCH_PLNT) && (i < (cmdlnt / 2)); i++) { - if (ADDR_IS_MEM (cmdadl)) tswchp[i] = M[tsba >> 1]; - else { ts_endcmd (TSSR_NBA | TSSR_NXM | TC3, 0, 0); + if (ADDR_IS_MEM (tsba)) tswchp[i] = M[tsba >> 1]; + else { ts_endcmd (TSSR_NBA | TSSR_NXM | TC5, 0, 0); return SCPE_OK; } tsba = tsba + 2; } if ((wchlnt < ((MSG_PLNT - 1) * 2)) || (wchadh & 0177700) || (wchadl & 1)) ts_endcmd (TSSR_NBA | TC3, 0, 0); - else { msgxs3 = msgxs3 | XS3_XTF | 1; + else { msgxs2 = msgxs2 | XS2_XTF | 1; tssr = ts_updtssr (tssr & ~TSSR_NBA); ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); } return SCPE_OK; @@ -642,7 +659,7 @@ case FNC_CTL: /* control */ switch (mod) { /* case mode */ case 00: /* msg buf rls */ tssr = ts_updtssr (tssr | TSSR_SSR); /* set SSR */ - if (wchopt & WCH_ERI) int_req = int_req | INT_TS; + if (wchopt & WCH_ERI) SET_INT (TS); ts_ownc = 0; ts_ownm = 1; /* keep msg */ break; case 01: /* clean */ @@ -728,7 +745,8 @@ case FNC_POS: break; } ts_cmpendcmd (st0, 0); break; } -if (ts_log) printf ("Cmd=%o, mod=%o, buf=%o, lnt=%o, sta = %o, tc=%o, pos=%d\n", +if (DBG_LOG (LOG_TS)) + fprintf (sim_log, ">>TS: cmd=%o, mod=%o, buf=%o, lnt=%o, sta = %o, tc=%o, pos=%d\n", fnc, mod, cmdadl, cmdlnt, msgxs0, (tssr & TSSR_TC) >> 1, ts_unit.pos); return SCPE_OK; } @@ -776,6 +794,7 @@ void ts_endcmd (int32 tc, int32 xs0, int32 msg) int32 i; msgxs0 = ts_updxs0 (msgxs0 | xs0); /* update XS0 */ +if (wchxopt & WCHX_HDS) msgxs4 = msgxs4 | XS4_HDS; /* update XS4 */ if (msg && !(tssr & TSSR_NBA)) { /* send end pkt */ msghdr = msg; msglnt = wchlnt - 4; /* exclude hdr, bc */ @@ -787,7 +806,7 @@ if (msg && !(tssr & TSSR_NBA)) { /* send end pkt */ break; } tsba = tsba + 2; } } tssr = ts_updtssr (tssr | tc | TSSR_SSR | (tc? TSSR_SC: 0)); -if (cmdhdr & CMD_IE) int_req = int_req | INT_TS; +if (cmdhdr & CMD_IE) SET_INT (TS); ts_ownm = 0; ts_ownc = 0; return; } @@ -797,8 +816,9 @@ return; t_stat ts_reset (DEVICE *dptr) { int32 i; +extern int32 tm_enb; -if (dev_enb & INT_TS) dev_enb = dev_enb & ~INT_TM; /* TM or TS */ +if (ts_enb) tm_enb = 0; /* TM or TS */ ts_unit.pos = 0; tsba = tsdbx = 0; ts_ownc = ts_ownm = 0; @@ -809,7 +829,7 @@ for (i = 0; i < CMD_PLNT; i++) tscmdp[i] = 0; for (i = 0; i < WCH_PLNT; i++) tswchp[i] = 0; for (i = 0; i < MSG_PLNT; i++) tsmsgp[i] = 0; msgxs0 = ts_updxs0 (XS0_VCK); -int_req = int_req & ~INT_TS; +CLR_INT (TS); return SCPE_OK; } @@ -825,7 +845,7 @@ tssr = tssr & ~TSSR_OFL; /* clr offline */ if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) return r; /* attn msg? */ if (ts_ownm) { /* own msg buf? */ ts_endcmd (TC1, 0, MSG_MATN | MSG_CATN); /* send attn */ - int_req = int_req | INT_TS; /* set interrupt */ + SET_INT (TS); /* set interrupt */ ts_qatn = 0; } /* don't queue */ else ts_qatn = 1; /* else queue */ return r; @@ -843,7 +863,7 @@ tssr = tssr | TSSR_OFL; /* set offline */ if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) return r; /* attn msg? */ if (ts_ownm) { /* own msg buf? */ ts_endcmd (TC1, 0, MSG_MATN | MSG_CATN); /* send attn */ - int_req = int_req | INT_TS; /* set interrupt */ + SET_INT (TS); /* set interrupt */ ts_qatn = 0; } /* don't queue */ else ts_qatn = 1; /* else queue */ return r; @@ -861,13 +881,13 @@ static const int32 boot_rom[] = { 0005011, /* clr (r1) ; init, rew */ 0105711, /* tstb (r1) ; wait */ 0100376, /* bpl .-2 */ - 0012710, 0001064, /* mov #pkt1, (r0) ; set char */ + 0012710, 0001070, /* mov #pkt1, (r0) ; set char */ 0105711, /* tstb (r1) ; wait */ 0100376, /* bpl .-2 */ - 0012710, 0001104, /* mov #pkt2, (r0) ; read, skip */ + 0012710, 0001110, /* mov #pkt2, (r0) ; read, skip */ 0105711, /* tstb (r1) ; wait */ 0100376, /* bpl .-2 */ - 0012710, 0001104, /* mov #pkt2, (r0) ; read */ + 0012710, 0001110, /* mov #pkt2, (r0) ; read */ 0105711, /* tstb (r1) ; wait */ 0100376, /* bpl .-2 */ 0005711, /* tst (r1) ; err? */ @@ -877,10 +897,10 @@ static const int32 boot_rom[] = { 0005007, /* clr r7 */ 0046523, /* pad */ 0140004, /* pkt1: 140004, wcpk, 0, 8. */ - 0001074, + 0001100, 0000000, 0000010, - 0001116, /* wcpk: msg, 0, 14., 0 */ + 0001122, /* wcpk: msg, 0, 14., 0 */ 0000000, 0000016, 0000000, @@ -889,6 +909,7 @@ static const int32 boot_rom[] = { 0000000, 0001000, 0000000 /* hlt: halt */ + /* msg: .blk 4 */ }; t_stat ts_boot (int32 unitno) diff --git a/pdp18b_cpu.c b/pdp18b_cpu.c index fd06a756..01dedddf 100644 --- a/pdp18b_cpu.c +++ b/pdp18b_cpu.c @@ -25,6 +25,8 @@ cpu PDP-4/7/9/15 central processor + 19-Sep-01 RMS Fixed bug in EAE (found by Dave Conroy) + 17-Sep-01 RMS Fixed typo in conditional 10-Aug-01 RMS Removed register from declarations 17-Jul-01 RMS Moved function prototype 27-May-01 RMS Added second Teletype support, fixed bug in API @@ -256,7 +258,7 @@ #else #define EAE_DFLT 0 #endif -#if defined (PDP4) || (PDP7) +#if defined (PDP4) || defined (PDP7) #define API_DFLT UNIT_NOAPI #else #define API_DFLT UNIT_NOAPI /* for now */ @@ -612,7 +614,7 @@ api_cycle = 0; /* not API cycle */ /* Main instruction fetch/decode loop: check trap and interrupt */ while (reason == 0) { /* loop until halted */ -int32 IR, MA, t, xct_count; +int32 IR, MA, esc, t, xct_count; int32 link_init, fill; if (sim_interval <= 0) { /* check clock queue */ @@ -1086,6 +1088,7 @@ case 033: case 032: /* EAE */ if (IR & 0001000) LAC = LAC & 01000000; /* IR<8>? clear AC */ link_init = LAC & 01000000; /* link temporary */ fill = link_init? 0777777: 0; /* fill = link */ + esc = (IR & 077)? IR & 077: 0100; /* get eff SC */ switch ((IR >> 6) & 07) { /* case on IR<9:11> */ case 0: /* setup */ @@ -1100,7 +1103,7 @@ case 033: case 032: /* EAE */ PC = INCR_ADDR (PC); /* increment PC */ if (eae_ac_sign) MQ = MQ ^ 0777777; /* EAE AC sign? ~MQ */ LAC = LAC & 0777777; /* clear link */ - for (SC = IR & 077; SC != 0; SC--) { /* loop per step cnt */ + for (SC = esc; SC != 0; SC--) { /* loop per step cnt */ if (MQ & 1) LAC = LAC + MA; /* MQ<17>? add */ MQ = (MQ >> 1) | ((LAC & 1) << 17); LAC = LAC >> 1; } /* shift AC'MQ right */ @@ -1130,7 +1133,7 @@ case 033: case 032: /* EAE */ break; } LAC = LAC & 0777777; /* clear link */ t = 0; /* init loop */ - for (SC = IR & 077; SC != 0; SC--) { + for (SC = esc; SC != 0; SC--) { /* loop per step cnt */ if (t) LAC = (LAC + MA) & 01777777; else LAC = (LAC - MA) & 01777777; t = (LAC >> 18) & 1; /* quotient bit */ @@ -1153,40 +1156,38 @@ case 033: case 032: /* EAE */ #if defined (PDP15) if (!usmd) ion_defer = 2; /* free cycles */ #endif - for (SC = IR & 077; ((LAC & 0400000) == - ((LAC << 1) & 0400000)) && (SC != 0); SC--) { + for (SC = esc; (SC != 0) && ((LAC & 0400000) == + ((LAC << 1) & 0400000)); SC--) { LAC = (LAC << 1) | ((MQ >> 17) & 1); MQ = (MQ << 1) | (link_init >> 18); } LAC = link_init | (LAC & 0777777); /* trim AC, restore L */ MQ = MQ & 0777777; /* trim MQ */ + SC = SC & 077; /* trim SC */ break; case 5: /* long right shift */ - t = IR & 077; /* get shift count */ - if (t < 18) { - MQ = ((LAC << (18 - t)) | (MQ >> t)) & 0777777; - LAC = ((fill << (18 - t)) | (LAC >> t)) & 01777777; } - else { if (t < 36) MQ = - ((fill << (36 - t)) | (LAC >> (t - 18))) & 0777777; + if (esc < 18) { + MQ = ((LAC << (18 - esc)) | (MQ >> esc)) & 0777777; + LAC = ((fill << (18 - esc)) | (LAC >> esc)) & 01777777; } + else { if (esc < 36) MQ = + ((fill << (36 - esc)) | (LAC >> (esc - 18))) & 0777777; else MQ = fill; LAC = link_init | fill; } SC = 0; /* clear step count */ break; case 6: /* long left shift */ - t = IR & 077; /* get shift count */ - if (t < 18) { + if (esc < 18) { LAC = link_init | - (((LAC << t) | (MQ >> (18 - t))) & 0777777); - MQ = ((MQ << t) | (fill >> (18 - t))) & 0777777; } - else { if (t < 36) LAC = link_init | - (((MQ << (t - 18)) | (fill >> (36 - t))) & 0777777); + (((LAC << esc) | (MQ >> (18 - esc))) & 0777777); + MQ = ((MQ << esc) | (fill >> (18 - esc))) & 0777777; } + else { if (esc < 36) LAC = link_init | + (((MQ << (esc - 18)) | (fill >> (36 - esc))) & 0777777); else LAC = link_init | fill; MQ = fill; } SC = 0; /* clear step count */ break; case 7: /* AC left shift */ - t = IR & 077; /* get shift count */ - if (t < 18) LAC = link_init | - (((LAC << t) | (fill >> (18 - t))) & 0777777); + if (esc < 18) LAC = link_init | + (((LAC << esc) | (fill >> (18 - esc))) & 0777777); else LAC = link_init | fill; SC = 0; /* clear step count */ break; } /* end switch IR */ diff --git a/pdp18b_dt.c b/pdp18b_dt.c index 1d0b4fd7..db0e96ff 100644 --- a/pdp18b_dt.c +++ b/pdp18b_dt.c @@ -26,6 +26,7 @@ dt (PDP-9) TC02/TU55 DECtape (PDP-15) TC15/TU56 DECtape + 29-Aug-01 RMS Added casts to PDP-8 unpack routine 17-Jul-01 RMS Moved function prototype 11-May-01 RMS Fixed bug in reset 26-Apr-01 RMS Added device enable/disable support @@ -1008,10 +1009,10 @@ if (uptr -> flags & UNIT_8FMT) { /* PDP-8? */ if (k == 0) break; for ( ; k < D8_NBSIZE; k++) pdp8b[k] = 0; for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */ - bptr[ba] = ((pdp8b[k] & 07777) << 6) | - ((pdp8b[k + 1] >> 6) & 077); + bptr[ba] = ((uint32) (pdp8b[k] & 07777) << 6) | + ((uint32) (pdp8b[k + 1] >> 6) & 077); bptr[ba + 1] = ((pdp8b[k + 1] & 077) << 12) | - (pdp8b[k + 2] & 07777); + ((uint32) (pdp8b[k + 2] & 07777)); ba = ba + 2; } /* end blk loop */ } /* end file loop */ uptr -> hwmark = ba; } /* end if */ diff --git a/pdp18b_lp.c b/pdp18b_lp.c index 689d0948..4ed9f950 100644 --- a/pdp18b_lp.c +++ b/pdp18b_lp.c @@ -27,6 +27,7 @@ (PDP-7,9) Type 647 line printer (PDP-15) LP15 line printer + 19-Sep-01 RMS Fixed bug in 647 13-Feb-01 RMS Revised for register arrays 15-Feb-01 RMS Fixed 3 cycle data break sequence 30-Oct-00 RMS Standardized register naming @@ -234,7 +235,7 @@ int32 lpt65 (int32 pulse, int32 AC) { int32 i; -if (pulse == 001) return (int_req & INT_LPT)? IOT_SKP + AC: AC; /* LPSF */ +if (pulse == 001) return (lpt_done? IOT_SKP + AC: AC); /* LPSF */ if (pulse & 002) { /* pulse 02 */ lpt_done = 0; /* clear done */ int_req = int_req & ~INT_LPT; } /* clear int req */ @@ -265,7 +266,7 @@ return AC; int32 lpt66 (int32 pulse, int32 AC) { -if (pulse == 001) return lpt_err? IOT_SKP + AC: AC; /* LPSE */ +if (pulse == 001) return (lpt_err? IOT_SKP + AC: AC); /* LPSE */ if (pulse & 002) { /* LPCF */ lpt_done = 0; /* clear done, int */ int_req = int_req & ~INT_LPT; } diff --git a/pdp18b_stddev.c b/pdp18b_stddev.c index dd9568de..908b75da 100644 --- a/pdp18b_stddev.c +++ b/pdp18b_stddev.c @@ -29,6 +29,8 @@ tto teleprinter clk clock + 17-Sep-01 RMS Removed multiconsole support + 07-Sep-01 RMS Added terminal multiplexor support 17-Jul-01 RMS Moved function prototype 10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware 27-May-01 RMS Added multiconsole support @@ -52,10 +54,8 @@ int32 ptr_err = 0, ptr_stopioe = 0, ptr_state = 0; int32 ptp_err = 0, ptp_stopioe = 0; int32 tti_state = 0; int32 tto_state = 0; -int32 clk_tps = 60; -#if defined (TTY1) -static uint8 tto_consout[CONS_SIZE]; -#endif +int32 clk_tps = 60; /* ticks/second */ +int32 tmxr_poll = 16000; /* term mux poll */ t_stat clk_svc (UNIT *uptr); t_stat ptr_svc (UNIT *uptr); @@ -72,8 +72,6 @@ t_stat ptp_attach (UNIT *uptr, char *cptr); t_stat ptr_detach (UNIT *uptr); t_stat ptp_detach (UNIT *uptr); t_stat ptr_boot (int32 unitno); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); /* CLK data structures @@ -200,9 +198,9 @@ static const int32 tti_trans[128] = { #define UNIT_HDX (1 << UNIT_V_HDX) #if defined (PDP4) || defined (PDP7) -UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC+UNIT_CONS, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT }; #else -UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC+UNIT_HDX+UNIT_CONS, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC+UNIT_HDX, 0), KBD_POLL_WAIT }; #endif REG tti_reg[] = { @@ -217,16 +215,9 @@ REG tti_reg[] = { #endif { DRDATA (POS, tti_unit.pos, 31), PV_LEFT }, { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, -#if defined (TTY1) - { FLDATA (CFLAG, tti_unit.flags, UNIT_V_CONS), REG_HRO }, -#endif { NULL } }; MTAB tti_mod[] = { -#if defined (TTY1) - { UNIT_CONS, 0, "inactive", NULL, NULL }, - { UNIT_CONS, UNIT_CONS, "active console", "CONSOLE", &set_console }, -#endif #if !defined (KSR28) { UNIT_UC, 0, "lower case", "LC", NULL }, { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, @@ -269,7 +260,7 @@ static const char tto_trans[64] = { #define TTO_MASK ((1 << TTO_WIDTH) - 1) -UNIT tto_unit = { UDATA (&tto_svc, UNIT_UC+UNIT_CONS, 0), SERIAL_OUT_WAIT }; +UNIT tto_unit = { UDATA (&tto_svc, UNIT_UC, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { { ORDATA (BUF, tto_unit.buf, TTO_WIDTH) }, @@ -280,17 +271,9 @@ REG tto_reg[] = { #endif { DRDATA (POS, tto_unit.pos, 31), PV_LEFT }, { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, -#if defined (TTY1) - { BRDATA (CONSOUT, tto_consout, 8, 8, CONS_SIZE), REG_HIDDEN }, - { FLDATA (CFLAG, tto_unit.flags, UNIT_V_CONS), REG_HRO }, -#endif { NULL } }; MTAB tto_mod[] = { -#if defined (TTY1) - { UNIT_CONS, 0, "inactive", NULL, NULL }, - { UNIT_CONS, UNIT_CONS, "active console", "CONSOLE", &set_console }, -#endif #if !defined (KSR28) { UNIT_UC, 0, "lower case", "LC", NULL }, { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, @@ -324,11 +307,14 @@ return AC; t_stat clk_svc (UNIT *uptr) { +int32 t; + if (clk_state) { /* clock on? */ M[7] = (M[7] + 1) & 0777777; /* incr counter */ if (M[7] == 0) int_req = int_req | INT_CLK; /* ovrflo? set flag */ - sim_activate (&clk_unit, /* reactivate unit */ - sim_rtc_calb (clk_tps)); } /* calibr delay */ + t = sim_rtc_calb (clk_tps); /* calibrate clock */ + sim_activate (&clk_unit, t); /* reactivate unit */ + tmxr_poll = t; } /* set mux poll */ return SCPE_OK; } @@ -339,6 +325,7 @@ t_stat clk_reset (DEVICE *dptr) int_req = int_req & ~INT_CLK; /* clear flag */ clk_state = 0; /* clock off */ sim_cancel (&clk_unit); /* stop clock */ +tmxr_poll = clk_unit.wait; /* set mux poll */ return SCPE_OK; } @@ -346,7 +333,7 @@ return SCPE_OK; int32 std_iors (void) { -return ((int_req & INT_CLK)? IOS_CLK: 0) | +return ((int_req & INT_CLK)? IOS_CLK: 0) | ((int_req & INT_PTR)? IOS_PTR: 0) | ((int_req & INT_PTP)? IOS_PTP: 0) | ((int_req & INT_TTI)? IOS_TTI: 0) | @@ -714,7 +701,7 @@ if ((tti_unit.flags & UNIT_UC) && islower (temp)) temp = toupper (temp); if ((tti_unit.flags & UNIT_HDX) && (!(tto_unit.flags & UNIT_UC) || ((temp >= 007) && (temp <= 0137)))) { - sim_putcons (temp, uptr); + sim_putchar (temp); tto_unit.pos = tto_unit.pos + 1; } tti_unit.buf = temp | 0200; /* got char */ #endif @@ -730,9 +717,6 @@ t_stat tti_reset (DEVICE *dptr) tti_unit.buf = 0; /* clear buffer */ tti_state = 0; /* clear state */ int_req = int_req & ~INT_TTI; /* clear flag */ -#if defined (TTY1) -if (tti_unit.flags & UNIT_CONS) /* if active cons */ -#endif sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ return SCPE_OK; } @@ -770,7 +754,7 @@ out = tto_unit.buf & 0177; /* ASCII... */ #endif if (!(tto_unit.flags & UNIT_UC) || ((out >= 007) && (out <= 0137))) { - temp = sim_putcons (out, uptr); + temp = sim_putchar (out); if (temp != SCPE_OK) return temp; tto_unit.pos = tto_unit.pos + 1; } return SCPE_OK; @@ -784,8 +768,5 @@ tto_unit.buf = 0; /* clear buffer */ tto_state = 0; /* clear state */ int_req = int_req & ~INT_TTO; /* clear flag */ sim_cancel (&tto_unit); /* deactivate unit */ -#if defined (TTY1) -tto_unit.filebuf = tto_consout; -#endif return SCPE_OK; } diff --git a/pdp18b_sys.c b/pdp18b_sys.c index 798670bc..6bae4a5a 100644 --- a/pdp18b_sys.c +++ b/pdp18b_sys.c @@ -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. + 17-Sep-01 RMS Removed multiconsole support 27-May-01 RMS Added second Teletype support 18-May-01 RMS Added PDP-9,-15 API IOT's 12-May-01 RMS Fixed bug in RIM loaders @@ -117,15 +118,6 @@ DEVICE *sim_devices[] = { &cpu_dev, #endif NULL }; -#if defined (TTY1) -UNIT *sim_consoles[] = { - &tti_unit, &tto_unit, - &tti1_unit, &tto1_unit, - NULL }; -#else -UNIT *sim_consoles = NULL; -#endif - const char *sim_stop_messages[] = { "Unknown error", "Undefined instruction", diff --git a/pdp18b_tt1.c b/pdp18b_tt1.c index a55bd0da..ba8625ba 100644 --- a/pdp18b_tt1.c +++ b/pdp18b_tt1.c @@ -26,23 +26,32 @@ tti1 keyboard tto1 teleprinter + 19-Sep-01 RMS Fixed typo + 17-Sep-01 RMS Changed to use terminal multiplexor library + 07-Sep-01 RMS Moved function prototypes 10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware */ #include "pdp18b_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" #include #define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ #define UNIT_UC (1 << UNIT_V_UC) extern int32 int_req, saved_PC; +extern int32 tmxr_poll; /* calibrated poll */ +TMLN tt1_ldsc = { 0 }; /* line descriptors */ +TMXR tt_desc = { 1, 0, &tt1_ldsc }; /* mux descriptor */ + t_stat tti1_svc (UNIT *uptr); t_stat tto1_svc (UNIT *uptr); t_stat tti1_reset (DEVICE *dptr); t_stat tto1_reset (DEVICE *dptr); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); -static uint8 tto1_consout[CONS_SIZE]; +t_stat tti1_attach (UNIT *uptr, char *cptr); +t_stat tti1_detach (UNIT *uptr); +t_stat tti1_status (UNIT *uptr, FILE *st); /* TTI1 data structures @@ -52,30 +61,28 @@ static uint8 tto1_consout[CONS_SIZE]; tti1_reg TTI1 register list */ -UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_UC, 0), KBD_POLL_WAIT }; +UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_ATTABLE+UNIT_UC, 0), KBD_POLL_WAIT }; REG tti1_reg[] = { { ORDATA (BUF, tti1_unit.buf, 8) }, { FLDATA (INT, int_req, INT_V_TTI1) }, { FLDATA (DONE, int_req, INT_V_TTI1) }, { FLDATA (UC, tti1_unit.flags, UNIT_V_UC), REG_HRO }, - { DRDATA (POS, tti1_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tt1_ldsc.rxcnt, 31), PV_LEFT }, { DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (CFLAG, tti1_unit.flags, UNIT_V_CONS), REG_HRO }, { NULL } }; -MTAB tti1_mod[] = { - { UNIT_CONS, 0, "inactive", NULL, NULL }, - { UNIT_CONS, UNIT_CONS, "active console", "CONSOLE", &set_console }, +MTAB ttx1_mod[] = { + { UNIT_ATT, UNIT_ATT, "line status:", NULL, &tti1_status }, { UNIT_UC, 0, "lower case", "LC", NULL }, { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, { 0 } }; DEVICE tti1_dev = { - "TTI1", &tti1_unit, tti1_reg, tti1_mod, + "TTI1", &tti1_unit, tti1_reg, ttx1_mod, 1, 10, 31, 1, 8, 8, - NULL, NULL, &tti1_reset, - NULL, NULL, NULL }; + &tmxr_ex, &tmxr_dep, &tti1_reset, + NULL, &tti1_attach, &tti1_detach }; /* TTO1 data structures @@ -91,21 +98,12 @@ REG tto1_reg[] = { { ORDATA (BUF, tto1_unit.buf, 8) }, { FLDATA (INT, int_req, INT_V_TTO1) }, { FLDATA (DONE, int_req, INT_V_TTO1) }, - { DRDATA (POS, tto1_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tt1_ldsc.txcnt, 31), PV_LEFT }, { DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT }, - { BRDATA (CONSOUT, tto1_consout, 8, 8, CONS_SIZE), REG_HIDDEN }, - { FLDATA (CFLAG, tto1_unit.flags, UNIT_V_CONS), REG_HRO }, { NULL } }; -MTAB tto1_mod[] = { - { UNIT_CONS, 0, "inactive", NULL, NULL }, - { UNIT_CONS, UNIT_CONS, "active console", "CONSOLE", &set_console }, - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, - { 0 } }; - DEVICE tto1_dev = { - "TTO1", &tto1_unit, tto1_reg, tto1_mod, + "TTO1", &tto1_unit, tto1_reg, ttx1_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto1_reset, NULL, NULL, NULL }; @@ -126,15 +124,23 @@ return AC; t_stat tti1_svc (UNIT *uptr) { -int32 temp; +int32 temp, newln; -sim_activate (&tti1_unit, tti1_unit.wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ -temp = temp & 0177; -if ((tti1_unit.flags & UNIT_UC) && islower (temp)) temp = toupper (temp); -tti1_unit.buf = temp | 0200; /* got char */ -int_req = int_req | INT_TTI1; /* set flag */ -tti1_unit.pos = tti1_unit.pos + 1; +if (tt1_ldsc.conn) { /* connected? */ + tmxr_poll_rx (&tt_desc); /* poll for input */ + if (temp = tmxr_getc_ln (&tt1_ldsc)) { /* get char */ + temp = temp & 0177; + if ((uptr -> flags & UNIT_UC) && + islower (temp)) temp = toupper (temp); + uptr -> buf = temp | 0200; /* got char */ + int_req = int_req | INT_TTI1; } /* set flag */ + sim_activate (uptr, uptr -> wait); } /* continue poll */ +if (uptr -> flags & UNIT_ATT) { /* attached? */ + newln = tmxr_poll_conn (&tt_desc, uptr); /* poll connect */ + if (newln >= 0) { /* got one? */ + sim_activate (&tti1_unit, tti1_unit.wait); + tt1_ldsc.rcve = 1; } /* rcv enabled */ + sim_activate (uptr, tmxr_poll); } /* sched poll */ return SCPE_OK; } @@ -143,9 +149,13 @@ return SCPE_OK; t_stat tti1_reset (DEVICE *dptr) { tti1_unit.buf = 0; /* clear buffer */ -int_req = int_req & ~INT_TTI; /* clear flag */ -if (tti1_unit.flags & UNIT_CONS) /* if active console */ - sim_activate (&tti1_unit, tti1_unit.wait); /* activate unit */ +int_req = int_req & ~INT_TTI1; /* clear flag */ +if (tt1_ldsc.conn) { /* if conn, */ + sim_activate (&tti1_unit, tti1_unit.wait); /* activate, */ + tt1_ldsc.rcve = 1; } /* enable */ +else if (tti1_unit.flags & UNIT_ATT) /* if attached, */ + sim_activate (&tti1_unit, tmxr_poll); /* activate */ +else sim_cancel (&tti1_unit); /* else stop */ return SCPE_OK; } @@ -166,15 +176,19 @@ return AC; t_stat tto1_svc (UNIT *uptr) { -int32 out, temp; +int32 out; int_req = int_req | INT_TTO1; /* set flag */ out = tto1_unit.buf & 0177; -if (!(tto1_unit.flags & UNIT_UC) || - ((out >= 007) && (out <= 0137))) { - temp = sim_putcons (out, uptr); - if (temp != SCPE_OK) return temp; - tto1_unit.pos = tto1_unit.pos + 1; } +if (tt1_ldsc.conn) { /* connected? */ + if (tt1_ldsc.xmte) { /* tx enabled? */ + if (!(tto1_unit.flags & UNIT_UC) || + ((out >= 007) && (out <= 0137))) + tmxr_putc_ln (&tt1_ldsc, out); /* output char */ + tmxr_poll_tx (&tt_desc); } /* poll xmt */ + else { tmxr_poll_tx (&tt_desc); /* poll xmt */ + sim_activate (&tto1_unit, tmxr_poll); /* wait */ + return SCPE_OK; } } return SCPE_OK; } @@ -185,6 +199,37 @@ t_stat tto1_reset (DEVICE *dptr) tto1_unit.buf = 0; /* clear buffer */ int_req = int_req & ~INT_TTO1; /* clear flag */ sim_cancel (&tto1_unit); /* deactivate unit */ -tto1_unit.filebuf = tto1_consout; /* set buf pointer */ +return SCPE_OK; +} + +/* Attach routine */ + +t_stat tti1_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = tmxr_attach (&tt_desc, uptr, cptr); /* attach */ +if (r != SCPE_OK) return r; /* error */ +sim_activate (uptr, tmxr_poll); /* start poll */ +return SCPE_OK; +} + +/* Detach routine */ + +t_stat tti1_detach (UNIT *uptr) +{ +t_stat r; + +r = tmxr_detach (&tt_desc, uptr); /* detach */ +tt1_ldsc.rcve = 0; /* disable rcv */ +sim_cancel (uptr); /* stop poll */ +return r; +} + +/* Status routine */ + +t_stat tti1_status (UNIT *uptr, FILE *st) +{ +tmxr_fstatus (st, &tt1_ldsc, -1); return SCPE_OK; } diff --git a/pdp1_stddev.c b/pdp1_stddev.c index 844c6039..7c19dbfa 100644 --- a/pdp1_stddev.c +++ b/pdp1_stddev.c @@ -28,6 +28,7 @@ tti keyboard tto teleprinter + 07-Sep-01 RMS Moved function prototypes 10-Jun-01 RMS Fixed comment 30-Oct-00 RMS Standardized device naming */ @@ -55,8 +56,6 @@ t_stat ptp_reset (DEVICE *dptr); t_stat tti_reset (DEVICE *dptr); t_stat tto_reset (DEVICE *dptr); t_stat ptr_boot (int32 unitno); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); /* Character translation tables */ diff --git a/pdp1_sys.c b/pdp1_sys.c index b228e173..7a5ee31d 100644 --- a/pdp1_sys.c +++ b/pdp1_sys.c @@ -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. + 17-Sep-01 RMS Removed multiconsole support 13-Jul-01 RMS Fixed RIM loader format 27-May-01 RMS Added multiconsole support 14-Mar-01 RMS Revised load/dump interface (again) @@ -52,7 +53,6 @@ extern int32 sc_map[]; sim_PC pointer to saved PC register descriptor sim_emax number of words for examine sim_devices array of pointers to simulated devices - sim_consoles array of pointers to consoles (if more than one) sim_stop_messages array of pointers to stop messages sim_load binary loader */ @@ -67,8 +67,6 @@ DEVICE *sim_devices[] = { &cpu_dev, &ptr_dev, &ptp_dev, &tti_dev, &tto_dev, &lpt_dev, NULL }; -UNIT *sim_consoles = NULL; - const char *sim_stop_messages[] = { "Unknown error", "Undefined instruction", diff --git a/pdp8_clk.c b/pdp8_clk.c index 845d7738..cb16228c 100644 --- a/pdp8_clk.c +++ b/pdp8_clk.c @@ -25,6 +25,7 @@ clk real time clock + 05-Sep-01 RMS Added terminal multiplexor support 17-Jul-01 RMS Moved function prototype 05-Mar-01 RMS Added clock calibration support @@ -36,7 +37,8 @@ extern int32 int_req, int_enable, dev_done, stop_inst; t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); -int32 clk_tps = 60; +int32 clk_tps = 60; /* ticks/second */ +int32 tmxr_poll = 16000; /* term mux poll */ /* CLK data structures @@ -103,9 +105,13 @@ default: t_stat clk_svc (UNIT *uptr) { +int32 t; + dev_done = dev_done | INT_CLK; /* set done */ int_req = INT_UPDATE; /* update interrupts */ -sim_activate (&clk_unit, sim_rtc_calb (clk_tps)); /* reactivate unit */ +t = sim_rtc_calb (clk_tps); /* calibrate clock */ +sim_activate (&clk_unit, t); /* reactivate unit */ +tmxr_poll = t; /* set mux poll */ return SCPE_OK; } @@ -117,5 +123,6 @@ dev_done = dev_done & ~INT_CLK; /* clear done, int */ int_req = int_req & ~INT_CLK; int_enable = int_enable & ~INT_CLK; /* clear enable */ sim_activate (&clk_unit, clk_unit.wait); /* activate unit */ +tmxr_poll = clk_unit.wait; /* set mux poll */ return SCPE_OK; } diff --git a/pdp8_cpu.c b/pdp8_cpu.c index 92ff6d0f..e029e4b6 100644 --- a/pdp8_cpu.c +++ b/pdp8_cpu.c @@ -25,6 +25,7 @@ cpu central processor + 16-Sep-01 RMS Fixed bug in reset routine, added KL8A support 10-Aug-01 RMS Removed register from declarations 17-Jul-01 RMS Moved function prototype 07-Jun-01 RMS Fixed bug in JMS to non-existent memory @@ -284,6 +285,8 @@ extern int32 ptr (int32 pulse, int32 AC); extern int32 ptp (int32 pulse, int32 AC); extern int32 clk (int32 pulse, int32 AC); extern int32 lpt (int32 pulse, int32 AC); +extern int32 ttix (int32 inst, int32 AC); +extern int32 ttox (int32 inst, int32 AC); extern int32 rk (int32 pulse, int32 AC); extern int32 rx (int32 pulse, int32 AC); extern int32 df60 (int32 pulse, int32 AC); @@ -1018,6 +1021,12 @@ case 030:case 031:case 032:case 033: /* IOT */ case 013: /* CLK */ iot_data = clk (pulse, iot_data); break; + case 040: case 042: case 044: case 046: /* KL8A in */ + iot_data = ttix (IR, iot_data); + break; + case 041: case 043: case 045: case 047: /* KL8A out */ + iot_data = ttox (IR, iot_data); + break; case 060: /* DF32/RF08 */ if (dev_enb & INT_DF) iot_data = df60 (pulse, iot_data); else if (dev_enb & INT_RF) iot_data = rf60 (pulse, iot_data); @@ -1087,7 +1096,7 @@ return reason; t_stat cpu_reset (DEVICE *dptr) { int_req = (int_req & ~INT_ION) | INT_NO_CIF_PENDING; -saved_DF = IB = (saved_PC >> 12) & 03; +saved_DF = IB = saved_PC & 070000; UF = UB = gtf = emode = 0; return cpu_svc (&cpu_unit); } diff --git a/pdp8_defs.h b/pdp8_defs.h index 68206c1a..25acc4df 100644 --- a/pdp8_defs.h +++ b/pdp8_defs.h @@ -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. + 16-Sep-01 RMS Added multiple KL support 18-Mar-01 RMS Added DF32 support 15-Feb-01 RMS Added DECtape support 14-Apr-99 RMS Changed t_addr to unsigned @@ -73,6 +74,9 @@ Because the PDP-8 does not have priority interrupts, the order of devices within groups does not matter. + + Note: all extra KL input and output interrupts must be assigned + to contiguous bits. */ #define INT_V_START 0 /* enable start */ @@ -82,7 +86,15 @@ #define INT_V_TTO (INT_V_START+3) /* terminal */ #define INT_V_TTI (INT_V_START+4) /* keyboard */ #define INT_V_CLK (INT_V_START+5) /* clock */ -#define INT_V_DIRECT (INT_V_START+6) /* direct start */ +#define INT_V_TTO1 (INT_V_START+6) /* tto1 */ +#define INT_V_TTO2 (INT_V_START+7) /* tto2 */ +#define INT_V_TTO3 (INT_V_START+8) /* tto3 */ +#define INT_V_TTO4 (INT_V_START+9) /* tto4 */ +#define INT_V_TTI1 (INT_V_START+10) /* tti1 */ +#define INT_V_TTI2 (INT_V_START+11) /* tti2 */ +#define INT_V_TTI3 (INT_V_START+12) /* tti3 */ +#define INT_V_TTI4 (INT_V_START+13) /* tti4 */ +#define INT_V_DIRECT (INT_V_START+14) /* direct start */ #define INT_V_RX (INT_V_DIRECT+0) /* RX8E */ #define INT_V_RK (INT_V_DIRECT+1) /* RK8E */ #define INT_V_RF (INT_V_DIRECT+2) /* RF08 */ @@ -102,6 +114,14 @@ #define INT_TTO (1 << INT_V_TTO) #define INT_TTI (1 << INT_V_TTI) #define INT_CLK (1 << INT_V_CLK) +#define INT_TTO1 (1 << INT_V_TTO1) +#define INT_TTO2 (1 << INT_V_TTO2) +#define INT_TTO3 (1 << INT_V_TTO3) +#define INT_TTO4 (1 << INT_V_TTO4) +#define INT_TTI1 (1 << INT_V_TTI1) +#define INT_TTI2 (1 << INT_V_TTI2) +#define INT_TTI3 (1 << INT_V_TTI3) +#define INT_TTI4 (1 << INT_V_TTI4) #define INT_RX (1 << INT_V_RX) #define INT_RK (1 << INT_V_RK) #define INT_RF (1 << INT_V_RF) diff --git a/pdp8_dt.c b/pdp8_dt.c index cbf3465f..c92822b5 100644 --- a/pdp8_dt.c +++ b/pdp8_dt.c @@ -25,6 +25,7 @@ dt TC08/TU56 DECtape + 29-Aug-01 RMS Added casts to PDP-18b packup routine 17-Jul-01 RMS Moved function prototype 11-May-01 RMS Fixed bug in reset 25-Apr-01 RMS Added device enable/disable support @@ -1130,10 +1131,10 @@ if (uptr -> hwmark) { /* any data? */ else { /* PDP9/11/15 */ for (ba = 0; ba < uptr -> hwmark; ) { /* loop thru buf */ for (k = 0; k < D18_NBSIZE; k = k + 2) { - pdp18b[k] = ((bptr[ba] & 07777) << 6) | - ((bptr[ba + 1] >> 6) & 077); - pdp18b[k + 1] = ((bptr[ba + 1] & 077) << 12) | - (bptr[ba + 2] & 07777); + pdp18b[k] = ((uint32) (bptr[ba] & 07777) << 6) | + ((uint32) (bptr[ba + 1] >> 6) & 077); + pdp18b[k + 1] = ((uint32) (bptr[ba + 1] & 077) << 12) | + ((uint32) (bptr[ba + 2] & 07777)); ba = ba + 3; } /* end loop blk */ fxwrite (pdp18b, sizeof (int32), D18_NBSIZE, uptr -> fileref); diff --git a/pdp8_sys.c b/pdp8_sys.c index fefa1ba3..ed4297da 100644 --- a/pdp8_sys.c +++ b/pdp8_sys.c @@ -23,6 +23,8 @@ 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. + 17-Sep-01 RMS Removed multiconsole support + 16-Sep-01 RMS Added TSS/8 packed char support, added KL8A support 27-May-01 RMS Added multiconsole support 18-Mar-01 RMS Added DF32 support 14-Mar-01 RMS Added extension detection of RIM binary tapes @@ -44,6 +46,10 @@ extern DEVICE clk_dev, lpt_dev; extern DEVICE rk_dev, rx_dev; extern DEVICE df_dev, rf_dev; extern DEVICE dt_dev, mt_dev; +extern DEVICE tti1_dev, tto1_dev; +extern DEVICE tti2_dev, tto2_dev; +extern DEVICE tti3_dev, tto3_dev; +extern DEVICE tti4_dev, tto4_dev; extern REG cpu_reg[]; extern uint16 M[]; extern int32 sim_switches; @@ -69,14 +75,16 @@ DEVICE *sim_devices[] = { &cpu_dev, &ptr_dev, &ptp_dev, &tti_dev, &tto_dev, + &tti1_dev, &tto1_dev, + &tti2_dev, &tto2_dev, + &tti3_dev, &tto3_dev, + &tti4_dev, &tto4_dev, &clk_dev, &lpt_dev, &rk_dev, &rx_dev, &df_dev, &rf_dev, &dt_dev, &mt_dev, NULL }; -UNIT *sim_consoles = NULL; - const char *sim_stop_messages[] = { "Unknown error", "Unimplemented instruction", @@ -333,6 +341,7 @@ return sp; #define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x) #define SIXTOASC(x) (((x) >= 040)? (x): (x) + 0100) +#define TSSTOASC(x) ((x) + 040) t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) @@ -350,6 +359,10 @@ if (sw & SWMASK ('C')) { /* characters? */ fprintf (of, "%c", SIXTOASC ((inst >> 6) & 077)); fprintf (of, "%c", SIXTOASC (inst & 077)); return SCPE_OK; } +if (sw & SWMASK ('T')) { /* TSS8 packed? */ + fprintf (of, "%c", TSSTOASC ((inst >> 6) & 077)); + fprintf (of, "%c", TSSTOASC (inst & 077)); + return SCPE_OK; } if (!(sw & SWMASK ('M'))) return SCPE_ARG; /* Instruction decode */ @@ -423,6 +436,11 @@ if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */ val[0] = (((t_value) cptr[0] & 077) << 6) | ((t_value) cptr[1] & 077); return SCPE_OK; } +if ((sw & SWMASK ('T')) || ((*cptr == '"') && cptr++)) { /* TSS8 string? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = (((t_value) (cptr[0] - 040) & 077) << 6) | + ((t_value) (cptr[1] - 040) & 077); + return SCPE_OK; } /* Instruction parse */ diff --git a/pdp8_tt.c b/pdp8_tt.c index 73d74ee8..3dc05940 100644 --- a/pdp8_tt.c +++ b/pdp8_tt.c @@ -24,6 +24,8 @@ in this Software without prior written authorization from Robert M Supnik. tti,tto KL8E terminal input/output + + 07-Sep-01 RMS Moved function prototypes */ #include "pdp8_defs.h" @@ -36,8 +38,6 @@ t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); t_stat tti_reset (DEVICE *dptr); t_stat tto_reset (DEVICE *dptr); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); /* TTI data structures diff --git a/pdp8_ttx.c b/pdp8_ttx.c new file mode 100644 index 00000000..91a692ab --- /dev/null +++ b/pdp8_ttx.c @@ -0,0 +1,423 @@ +/* pdp8_ttx.c: PDP-8 additional terminals simulator + + Copyright (c) 1993-2001, 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"), + 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. + + ttix,ttox PT08/KL8JA terminal input/output + + This module implements four individual serial interfaces similar in function + to the console. These interfaces are mapped to Telnet based connections as + though they were the four lines of a terminal multiplexor. The connection + polling mechanism is superimposed onto the keyboard of the first interface. +*/ + +#include "pdp8_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" +#include + +#define TTX_LINES 4 +#define TTX_MASK (TTX_LINES - 1) +#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ +#define UNIT_UC (1 << UNIT_V_UC) +#define TTX_GETLN(x) (((x) >> 4) & TTX_MASK) + +extern int32 int_req, int_enable, dev_done, stop_inst; +extern int32 tmxr_poll; /* calibrated poll */ +TMLN tt1_ldsc = { 0 }; /* line descriptors */ +TMLN tt2_ldsc = { 0 }; /* line descriptors */ +TMLN tt3_ldsc = { 0 }; /* line descriptors */ +TMLN tt4_ldsc = { 0 }; /* line descriptors */ + +TMXR ttx_desc = { /* mux descriptor */ + TTX_LINES, 0, &tt1_ldsc, &tt2_ldsc, &tt3_ldsc, &tt4_ldsc }; + +t_stat ttix_svc (UNIT *uptr); +t_stat ttix_reset (DEVICE *dptr); +t_stat ttox_svc (UNIT *uptr); +t_stat ttox_reset (DEVICE *dptr); +t_stat ttx_attach (UNIT *uptr, char *cptr); +t_stat ttx_detach (UNIT *uptr); +t_stat ttx_status (UNIT *uptr, FILE *st); + +/* TTIx data structures + + ttix_dev TTIx device descriptor + ttix_unit TTIx unit descriptor + ttix_reg TTIx register list + ttix_mod TTIx modifiers list +*/ + +MTAB ttix_mod[] = { + { UNIT_UC, 0, "lower case", "LC", NULL }, + { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { UNIT_ATT, UNIT_ATT, "line status:", NULL, &ttx_status }, + { 0 } }; + +UNIT ttix_unit[] = { + { UDATA (&ttix_svc, UNIT_ATTABLE+UNIT_UC, 0), KBD_POLL_WAIT }, + { UDATA (&ttix_svc, UNIT_UC, 0), KBD_POLL_WAIT }, + { UDATA (&ttix_svc, UNIT_UC, 0), KBD_POLL_WAIT }, + { UDATA (&ttix_svc, UNIT_UC, 0), KBD_POLL_WAIT } }; + +#define tti1_unit ttix_unit[0] +#define tti2_unit ttix_unit[1] +#define tti3_unit ttix_unit[2] +#define tti4_unit ttix_unit[3] + +REG tti1_reg[] = { + { ORDATA (BUF, tti1_unit.buf, 8) }, + { FLDATA (DONE, dev_done, INT_V_TTI1) }, + { FLDATA (ENABLE, int_enable, INT_V_TTI1) }, + { FLDATA (INT, int_req, INT_V_TTI1) }, + { DRDATA (POS, tt1_ldsc.rxcnt, 32), PV_LEFT }, + { DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT }, + { FLDATA (UC, tti1_unit.flags, UNIT_V_UC), REG_HRO }, + { NULL } }; + +DEVICE tti1_dev = { + "TTI1", &tti1_unit, tti1_reg, ttix_mod, + 1, 10, 31, 1, 8, 8, + &tmxr_ex, &tmxr_dep, &ttix_reset, + NULL, &ttx_attach, &ttx_detach }; + +REG tti2_reg[] = { + { ORDATA (BUF, tti2_unit.buf, 8) }, + { FLDATA (DONE, dev_done, INT_V_TTI2) }, + { FLDATA (ENABLE, int_enable, INT_V_TTI2) }, + { FLDATA (INT, int_req, INT_V_TTI2) }, + { DRDATA (POS, tt2_ldsc.rxcnt, 32), PV_LEFT }, + { DRDATA (TIME, tti2_unit.wait, 24), REG_NZ + PV_LEFT }, + { FLDATA (UC, tti2_unit.flags, UNIT_V_UC), REG_HRO }, + { NULL } }; + +DEVICE tti2_dev = { + "TTI2", &tti2_unit, tti2_reg, ttix_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ttix_reset, + NULL, NULL, NULL }; + +REG tti3_reg[] = { + { ORDATA (BUF, tti3_unit.buf, 8) }, + { FLDATA (DONE, dev_done, INT_V_TTI3) }, + { FLDATA (ENABLE, int_enable, INT_V_TTI3) }, + { FLDATA (INT, int_req, INT_V_TTI3) }, + { DRDATA (POS, tt3_ldsc.rxcnt, 32), PV_LEFT }, + { DRDATA (TIME, tti3_unit.wait, 24), REG_NZ + PV_LEFT }, + { FLDATA (UC, tti3_unit.flags, UNIT_V_UC), REG_HRO }, + { NULL } }; + +DEVICE tti3_dev = { + "TTI3", &tti3_unit, tti3_reg, ttix_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ttix_reset, + NULL, NULL, NULL }; + +REG tti4_reg[] = { + { ORDATA (BUF, tti4_unit.buf, 8) }, + { FLDATA (DONE, dev_done, INT_V_TTI4) }, + { FLDATA (ENABLE, int_enable, INT_V_TTI4) }, + { FLDATA (INT, int_req, INT_V_TTI4) }, + { DRDATA (POS, tt4_ldsc.rxcnt, 32), PV_LEFT }, + { DRDATA (TIME, tti4_unit.wait, 24), REG_NZ + PV_LEFT }, + { FLDATA (UC, tti4_unit.flags, UNIT_V_UC), REG_HRO }, + { NULL } }; + +DEVICE tti4_dev = { + "TTI4", &tti4_unit, tti4_reg, ttix_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ttix_reset, + NULL, NULL, NULL }; + +/* TTOx data structures + + ttox_dev TTOx device descriptor + ttox_unit TTOx unit descriptor + ttox_reg TTOx register list +*/ + +UNIT ttox_unit[] = { + { UDATA (&ttox_svc, 0, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, 0, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, 0, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, 0, 0), SERIAL_OUT_WAIT } }; + +#define tto1_unit ttox_unit[0] +#define tto2_unit ttox_unit[0] +#define tto3_unit ttox_unit[0] +#define tto4_unit ttox_unit[0] + +REG tto1_reg[] = { + { ORDATA (BUF, tto1_unit.buf, 8) }, + { FLDATA (DONE, dev_done, INT_V_TTO1) }, + { FLDATA (ENABLE, int_enable, INT_V_TTO1) }, + { FLDATA (INT, int_req, INT_V_TTO1) }, + { DRDATA (POS, tt1_ldsc.txcnt, 32), PV_LEFT }, + { DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT }, + { NULL } }; + +DEVICE tto1_dev = { + "TTO1", &tto1_unit, tto1_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ttox_reset, + NULL, NULL, NULL }; + +REG tto2_reg[] = { + { ORDATA (BUF, tto2_unit.buf, 8) }, + { FLDATA (DONE, dev_done, INT_V_TTO2) }, + { FLDATA (ENABLE, int_enable, INT_V_TTO2) }, + { FLDATA (INT, int_req, INT_V_TTO2) }, + { DRDATA (POS, tt2_ldsc.txcnt, 32), PV_LEFT }, + { DRDATA (TIME, tto2_unit.wait, 24), PV_LEFT }, + { NULL } }; + +DEVICE tto2_dev = { + "TTO2", &tto2_unit, tto2_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ttox_reset, + NULL, NULL, NULL }; + +REG tto3_reg[] = { + { ORDATA (BUF, tto3_unit.buf, 8) }, + { FLDATA (DONE, dev_done, INT_V_TTO3) }, + { FLDATA (ENABLE, int_enable, INT_V_TTO3) }, + { FLDATA (INT, int_req, INT_V_TTO3) }, + { DRDATA (POS, tt3_ldsc.txcnt, 32), PV_LEFT }, + { DRDATA (TIME, tto3_unit.wait, 24), PV_LEFT }, + { NULL } }; + +DEVICE tto3_dev = { + "TTO3", &tto3_unit, tto3_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ttox_reset, + NULL, NULL, NULL }; + +REG tto4_reg[] = { + { ORDATA (BUF, tto4_unit.buf, 8) }, + { FLDATA (DONE, dev_done, INT_V_TTO4) }, + { FLDATA (ENABLE, int_enable, INT_V_TTO4) }, + { FLDATA (INT, int_req, INT_V_TTO4) }, + { DRDATA (POS, tt4_ldsc.txcnt, 32), PV_LEFT }, + { DRDATA (TIME, tto4_unit.wait, 24), PV_LEFT }, + { NULL } }; + +DEVICE tto4_dev = { + "TTO4", &tto4_unit, tto4_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ttox_reset, + NULL, NULL, NULL }; + +/* Terminal input: IOT routine */ + +int32 ttix (int32 inst, int32 AC) +{ +int32 pulse = inst & 07; /* IOT pulse */ +int32 ln = TTX_GETLN (inst); /* line # */ +int32 itti = (INT_TTI1 << ln); /* rx intr */ +int32 itto = (INT_TTO1 << ln); /* tx intr */ + +switch (pulse) { /* case IR<9:11> */ +case 0: /* KCF */ + dev_done = dev_done & ~itti; /* clear flag */ + int_req = int_req & ~itti; + break; +case 1: /* KSF */ + return (dev_done & itti)? IOT_SKP + AC: AC; +case 2: /* KCC */ + dev_done = dev_done & ~itti; /* clear flag */ + int_req = int_req & ~itti; + return 0; /* clear AC */ +case 4: /* KRS */ + return (AC | ttix_unit[ln].buf); /* return buf */ +case 5: /* KIE */ + if (AC & 1) int_enable = int_enable | (itti + itto); + else int_enable = int_enable & ~(itti + itto); + int_req = INT_UPDATE; /* update intr */ + break; +case 6: /* KRB */ + dev_done = dev_done & ~itti; /* clear flag */ + int_req = int_req & ~itti; + return ttix_unit[ln].buf; /* return buf */ +default: + return (stop_inst << IOT_V_REASON) + AC; } /* end switch */ +return AC; +} + +/* Unit service */ + +t_stat ttix_svc (UNIT *uptr) +{ +int32 temp, newln; +int32 ln = uptr - ttix_unit; /* line # */ +int32 itti = (INT_TTI1 << ln); /* rx intr */ + +if (ttx_desc.ldsc[ln] -> conn) { /* connected? */ + tmxr_poll_rx (&ttx_desc); /* poll for input */ + if (temp = tmxr_getc_ln (ttx_desc.ldsc[ln])) { /* get char */ + temp = temp & 0177; /* mask to 7b */ + if ((uptr -> flags & UNIT_UC) && islower (temp)) + temp = toupper (temp); + uptr -> buf = temp | 0200; /* Teletype code */ + dev_done = dev_done | itti; /* set done */ + int_req = INT_UPDATE; } /* update intr */ + sim_activate (uptr, uptr -> wait); } /* continue poll */ +if (uptr -> flags & UNIT_ATT) { /* attached? */ + newln = tmxr_poll_conn (&ttx_desc, uptr); /* poll connect */ + if (newln >= 0) { /* got one? */ + sim_activate (&ttix_unit[newln], ttix_unit[newln].wait); + ttx_desc.ldsc[newln] -> rcve = 1; } /* rcv enabled */ + sim_activate (uptr, tmxr_poll); } /* sched poll */ +return SCPE_OK; +} + +/* Reset routine */ + +t_stat ttix_reset (DEVICE *dptr) +{ +UNIT *uptr = dptr -> units; /* unit */ +int32 ln = uptr - ttix_unit; /* line # */ +int32 itti = (INT_TTI1 << ln); /* rx intr */ + +uptr -> buf = 0; /* clr buf */ +dev_done = dev_done & ~itti; /* clr done, int */ +int_req = int_req & ~itti; +int_enable = int_enable | itti; /* set enable */ +if (ttx_desc.ldsc[ln] -> conn) { /* if conn, */ + sim_activate (uptr, uptr -> wait); /* activate, */ + ttx_desc.ldsc[ln] -> rcve = 1; } /* enable */ +else if (uptr -> flags & UNIT_ATT) /* if attached, */ + sim_activate (uptr, tmxr_poll); /* activate */ +else sim_cancel (uptr); /* else stop */ +return SCPE_OK; +} + +/* Terminal output: IOT routine */ + +int32 ttox (int32 inst, int32 AC) +{ +int32 pulse = inst & 07; /* pulse */ +int32 ln = TTX_GETLN (inst); /* line # */ +int32 itti = (INT_TTI1 << ln); /* rx intr */ +int32 itto = (INT_TTO1 << ln); /* tx intr */ + +switch (pulse) { /* case IR<9:11> */ +case 0: /* TLF */ + dev_done = dev_done | itto; /* set flag */ + int_req = INT_UPDATE; /* update intr */ + break; +case 1: /* TSF */ + return (dev_done & itto)? IOT_SKP + AC: AC; +case 2: /* TCF */ + dev_done = dev_done & ~itto; /* clear flag */ + int_req = int_req & ~itto; /* clear intr */ + break; +case 5: /* SPI */ + return (int_req & (itti | itto))? IOT_SKP + AC: AC; +case 6: /* TLS */ + dev_done = dev_done & ~itto; /* clear flag */ + int_req = int_req & ~itto; /* clear int req */ +case 4: /* TPC */ + sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate */ + ttox_unit[ln].buf = AC & 0377; /* load buffer */ + break; +default: + return (stop_inst << IOT_V_REASON) + AC; } /* end switch */ +return AC; +} + +/* Unit service */ + +t_stat ttox_svc (UNIT *uptr) +{ +int32 ln = uptr - ttox_unit; /* line # */ +int32 itto = (INT_TTO1 << ln); /* tx intr */ + +if (ttx_desc.ldsc[ln] -> conn) { /* connected? */ + if (ttx_desc.ldsc[ln] -> xmte) { /* tx enabled? */ + TMLN *lp = ttx_desc.ldsc[ln]; /* get line */ + tmxr_putc_ln (lp, uptr -> buf & 0177); /* output char */ + tmxr_poll_tx (&ttx_desc); } /* poll xmt */ + else { tmxr_poll_tx (&ttx_desc); /* poll xmt */ + sim_activate (uptr, tmxr_poll); /* wait */ + return SCPE_OK; } } +dev_done = dev_done | itto; /* set done */ +int_req = INT_UPDATE; /* update intr */ +return SCPE_OK; +} + +/* Reset routine */ + +t_stat ttox_reset (DEVICE *dptr) +{ +UNIT *uptr = dptr -> units; /* unit */ +int32 ln = uptr - ttox_unit; /* line # */ +int32 itto = (INT_TTO1 << ln); /* tx intr */ + +uptr -> buf = 0; /* clr buf */ +dev_done = dev_done & ~itto; /* clr done, int */ +int_req = int_req & ~itto; +int_enable = int_enable | itto; /* set enable */ +sim_cancel (uptr); /* deactivate */ +return SCPE_OK; +} + +/* Attach master unit */ + +t_stat ttx_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = tmxr_attach (&ttx_desc, uptr, cptr); /* attach */ +if (r != SCPE_OK) return r; /* error */ +sim_activate (uptr, tmxr_poll); /* start poll */ +return SCPE_OK; +} + +/* Detach master unit */ + +t_stat ttx_detach (UNIT *uptr) +{ +int32 i; +t_stat r; + +r = tmxr_detach (&ttx_desc, uptr); /* detach */ +for (i = 0; i < TTX_LINES; i++) { /* all lines, */ + ttx_desc.ldsc[i] -> rcve = 0; /* disable rcv */ + sim_cancel (&ttix_unit[i]); } /* stop poll */ +return SCPE_OK; +} + +/* Status */ + +t_stat ttx_status (UNIT *uptr, FILE *st) +{ +int32 i; + +for (i = 0; (i < TTX_LINES) && (ttx_desc.ldsc[i] -> conn == 0); i++) ; +if (i < TTX_LINES) { + for (i = 0; i < TTX_LINES; i++) { + if (ttx_desc.ldsc[i] -> conn) + tmxr_fstatus (st, ttx_desc.ldsc[i], i); } } +else fprintf (st, " all disconnected"); +return SCPE_OK; +} diff --git a/scp.c b/scp.c index ac67f413..ffd9715c 100644 --- a/scp.c +++ b/scp.c @@ -23,6 +23,13 @@ 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. + 08-Oct-01 RMS Added SHOW VERSION + 30-Sep-01 RMS Relaxed attach test in BOOT + 27-Sep-01 RMS Added queue count routine, fixed typo in ex/mod + 17-Sep-01 RMS Removed multiple console support + 07-Sep-01 RMS Removed conditional externs on function prototypes + Added special modifier print + 31-Aug-01 RMS Changed int64 to t_int64 for Windoze (V2.7) 18-Jul-01 RMS Minor changes for Macintosh port 12-Jun-01 RMS Fixed bug in big-endian I/O (found by Dave Conroy) 27-May-01 RMS Added multiple console support @@ -56,8 +63,8 @@ 13-Apr-95 RMS Added symbolic printouts */ -#define SCP 1 /* defining module */ #include "sim_defs.h" +#include "sim_rev.h" #include #include #define EX_D 0 /* deposit */ @@ -87,7 +94,6 @@ extern char sim_name[]; extern DEVICE *sim_devices[]; -extern UNIT *sim_consoles[]; extern REG *sim_PC; extern char *sim_stop_messages[]; extern t_stat sim_instr (void); @@ -120,17 +126,17 @@ unsigned char sim_flip[FLIP_SIZE]; #define SZ_D(dp) (size_map[((dp) -> dwidth + CHAR_BIT - 1) / CHAR_BIT]) #define SZ_R(rp) \ (size_map[((rp) -> width + (rp) -> offset + CHAR_BIT - 1) / CHAR_BIT]) -#if defined (int64) +#if defined (t_int64) #define SZ_LOAD(sz,v,mb,j) \ if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + j); \ else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + j); \ else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + j); \ - else v = *(((uint64 *) mb) + j); + else v = *(((t_uint64 *) mb) + j); #define SZ_STORE(sz,v,mb,j) \ if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \ else if (sz == sizeof (uint16)) *(((uint16 *) mb) + j) = (uint16) v; \ else if (sz == sizeof (uint32)) *(((uint32 *) mb) + j) = (uint32) v; \ - else *(((uint64 *) mb) + j) = v; + else *(((t_uint64 *) mb) + j) = v; #else #define SZ_LOAD(sz,v,mb,j) \ if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + j); \ @@ -161,14 +167,13 @@ t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr); t_value strtotv (char *inptr, char **endptr, int radix); t_stat fprint_val (FILE *stream, t_value val, int rdx, int wid, int fmt); void fprint_stopped (FILE *stream, t_stat r); -void sim_chkcons (void); char *read_line (char *ptr, int size, FILE *stream); DEVICE *find_dev (char *ptr); DEVICE *find_unit (char *ptr, int32 *iptr); DEVICE *find_dev_from_unit (UNIT *uptr); REG *find_reg (char *ptr, char **optr, DEVICE *dptr); t_bool qdisable (DEVICE *dptr); -t_stat detach_all (int start_device); +t_stat detach_all (int32 start_device, t_bool shutdown); t_stat ex_reg (FILE *ofile, t_value val, int flag, REG *rptr, t_addr idx); t_stat dep_reg (int flag, char *cptr, REG *rptr, t_addr idx); t_stat ex_addr (FILE *ofile, int flag, t_addr addr, DEVICE *dptr, UNIT *uptr); @@ -179,6 +184,7 @@ char *get_range (char *cptr, t_addr *lo, t_addr *hi, int rdx, SCHTAB *get_search (char *cptr, DEVICE *dptr, SCHTAB *schptr); int test_search (t_value val, SCHTAB *schptr); t_stat step_svc (UNIT *ptr); +t_stat show_version (FILE *st, int flag); UNIT step_unit = { UDATA (&step_svc, 0, 0) }; const char save_vercur[] = "V2.6"; @@ -217,8 +223,8 @@ const char *scp_error_messages[] = { const size_t size_map[] = { sizeof (int8), sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32) -#if defined (int64) - , sizeof (int64), sizeof (int64), sizeof (int64), sizeof (int64) +#if defined (t_int64) + , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64) #endif }; @@ -231,7 +237,7 @@ const t_value width_mask[] = { 0, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF -#if defined (int64) +#if defined (t_int64) , 0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF, 0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF, 0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF, @@ -312,7 +318,8 @@ if ((stat = ttinit ()) != SCPE_OK) { printf ("Fatal terminal initialization error\n%s\n", scp_error_messages[stat - SCPE_BASE]); return 0; } -printf ("\n%s simulator V2.6b\n", sim_name); +printf ("\n"); +show_version (stdout, 0); end_test.i = 1; /* test endian-ness */ sim_end = end_test.c[0]; stop_cpu = 0; @@ -363,7 +370,7 @@ do { printf ("sim> "); /* prompt */ scp_error_messages[stat - SCPE_BASE]); } } while (stat != SCPE_EXIT); -detach_all (0); /* close files */ +detach_all (0, TRUE); /* close files */ nolog_cmd (0, NULL); /* close log */ ttclose (); /* close console */ return 0; @@ -400,9 +407,11 @@ fprintf (st, "exi{t}|q{uit}|by{e} exit from simulation\n"); fprintf (st, "set set unit parameter\n"); fprintf (st, "show show device parameters\n"); fprintf (st, "sh{ow} c{onfiguration} show configuration\n"); +fprintf (st, "sh{ow} d{evices} show devices\n"); fprintf (st, "sh{ow} m{odifiers} show modifiers\n"); fprintf (st, "sh{ow} q{ueue} show event queue\n"); fprintf (st, "sh{ow} t{ime} show simulated time\n"); +fprintf (st, "sh{ow} v{ersion} show simulator version\n"); fprintf (st, "en{able} enable device\n"); fprintf (st, "di{sable} disable device\n"); fprintf (st, "ad{d} add unit to configuration\n"); @@ -441,23 +450,24 @@ GET_SWITCHES (cptr, gbuf); /* test for switches */ cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ dptr = find_unit (gbuf, &unitno); /* find dev+unit */ if ((dptr == NULL) || (dptr -> units == NULL) || - (*cptr == 0)) return SCPE_ARG; /* argument? */ + (*cptr == 0)) return SCPE_ARG; /* argument? */ cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ -if (*cptr != 0) return SCPE_ARG; /* now eol? */ uptr = dptr -> units + unitno; if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ for (i = 0; set_table[i].name != NULL; i++) { /* check globals */ - if (MATCH_CMD (gbuf, set_table[i].name) == 0) - return set_table[i].action (dptr, set_table[i].arg); } + if (MATCH_CMD (gbuf, set_table[i].name) == 0) { + if (*cptr != 0) return SCPE_ARG; /* now eol? */ + return set_table[i].action (dptr, set_table[i].arg); } } if (dptr -> modifiers == NULL) return SCPE_NOPARAM; /* any modifiers? */ for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { if ((mptr -> mstring != NULL) && (MATCH_CMD (gbuf, mptr -> mstring) == 0)) { + if (*cptr != 0) return SCPE_ARG; /* now eol? */ if ((mptr -> valid != NULL) && ((r = mptr -> valid (uptr, mptr -> match)) != SCPE_OK)) return r; /* invalid? */ uptr -> flags = (uptr -> flags & ~(mptr -> mask)) | - (mptr -> match & mptr -> mask); /* set new value */ + (mptr -> match & mptr -> mask); /* set new value */ return SCPE_OK; } } return SCPE_ARG; /* no match */ } @@ -491,6 +501,7 @@ static CTAB show_table[] = { { "QUEUE", &show_queue, 0 }, { "TIME", &show_time, 0 }, { "MODIFIERS", &show_modifiers, 0 }, + { "VERSION", &show_version, 0 }, { NULL, NULL, 0 } }; GET_SWITCHES (cptr, gbuf); /* test for switches */ @@ -536,24 +547,34 @@ for (j = 0; j < dptr -> numunits; j++) { if (uptr -> flags & UNIT_DIS) continue; if (ucnt > 1) fprintf (st, " unit %d", j); if (uptr -> flags & UNIT_FIX) { - if (uptr -> capac < kval) - fprintf (st, ", %d%s", uptr -> capac, - ((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B"); - else fprintf (st, ", %dK%s", uptr -> capac / kval, - ((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B"); } + if (uptr -> capac < kval) + fprintf (st, ", %d%s", uptr -> capac, + ((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B"); + else fprintf (st, ", %dK%s", uptr -> capac / kval, + ((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B"); } if (uptr -> flags & UNIT_ATT) - fprintf (st, ", attached to %s", uptr -> filename); + fprintf (st, ", attached to %s", uptr -> filename); else if (uptr -> flags & UNIT_ATTABLE) - fprintf (st, ", not attached"); + fprintf (st, ", not attached"); if (dptr -> modifiers != NULL) { for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { - if ((mptr -> pstring != NULL) && - ((uptr -> flags & mptr -> mask) == mptr -> match)) - fprintf (st, ", %s", mptr -> pstring); } } + if ((mptr -> pstring != NULL) && + ((uptr -> flags & mptr -> mask) == mptr -> match)) { + fprintf (st, ", %s", mptr -> pstring); + if ((mptr -> mstring == NULL) && mptr -> valid) + mptr -> valid (uptr, st); } } } fprintf (st, "\n"); } return SCPE_OK; } +t_stat show_version (FILE *st, int flag) +{ +int32 vmaj = SIM_MAJOR, vmin = SIM_MINOR, vpat = SIM_PATCH; + +fprintf (st, "%s simulator V%d.%d-%d\n", sim_name, vmaj, vmin, vpat); +return SCPE_OK; +} + t_stat show_config (FILE *st, int flag) { int32 i; @@ -890,7 +911,7 @@ GET_SWITCHES (cptr, gbuf); /* test for switches */ if (*cptr == 0) return SCPE_ARG; cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ if (*cptr != 0) return SCPE_ARG; -if (strcmp (gbuf, "ALL") == 0) return (detach_all (0)); +if (strcmp (gbuf, "ALL") == 0) return (detach_all (0, FALSE)); dptr = find_unit (gbuf, &unitno); /* locate dev+unit# */ if ((dptr == NULL) || (dptr -> units == NULL)) return SCPE_ARG; uptr = (dptr -> units) + unitno; @@ -903,11 +924,12 @@ return detach_unit (uptr); Inputs: start = number of starting device + shutdown = TRUE if simulator shutting down Outputs: status = error status */ -t_stat detach_all (int start) +t_stat detach_all (int32 start, t_bool shutdown) { int32 i, j; t_stat reason; @@ -918,9 +940,10 @@ if ((start < 0) || (start > 1)) return SCPE_ARG; for (i = start; (dptr = sim_devices[i]) != NULL; i++) { for (j = 0; j < dptr -> numunits; j++) { uptr = (dptr -> units) + j; - if (dptr -> detach != NULL) reason = dptr -> detach (uptr); - else reason = detach_unit (uptr); - if (reason != SCPE_OK) return reason; } } + if ((uptr -> flags & UNIT_ATTABLE) || shutdown) { + if (dptr -> detach != NULL) reason = dptr -> detach (uptr); + else reason = detach_unit (uptr); + if (reason != SCPE_OK) return reason; } } } return SCPE_OK; } @@ -1201,8 +1224,8 @@ if (flag == RU_BOOT) { /* boot */ (dptr -> boot == NULL)) return SCPE_ARG; uptr = dptr -> units + unitno; if (uptr -> flags & UNIT_DIS) return SCPE_ARG; /* disabled? */ - if (!(uptr -> flags & UNIT_ATTABLE)) return SCPE_NOATT; - if (!(uptr -> flags & UNIT_ATT)) return SCPE_UNATT; + if ((uptr -> flags & UNIT_ATTABLE) && + !(uptr -> flags & UNIT_ATT)) return SCPE_UNATT; if ((r = dptr -> boot (unitno)) != SCPE_OK) return r; } if (*cptr != 0) return SCPE_ARG; @@ -1227,7 +1250,6 @@ if (ttrunstate () != SCPE_OK) { /* set console */ return SCPE_TTYERR; } if (step) sim_activate (&step_unit, step); /* set step timer */ sim_is_running = 1; /* flag running */ -sim_chkcons (); /* check console buffer */ r = sim_instr(); sim_is_running = 0; /* flag idle */ @@ -1400,7 +1422,7 @@ for (gptr = gbuf, reason = SCPE_OK; continue; } tptr = get_range (gptr, &low, &high, dptr -> aradix, - (((uptr -> capac == 0) | (flag == EX_E))? 0: + (((uptr -> capac == 0) || (flag == EX_E))? 0: uptr -> capac - dptr -> aincr), 0); if (tptr == NULL) return SCPE_ARG; if (*tptr && (*tptr++ != ',')) return SCPE_ARG; @@ -1517,12 +1539,12 @@ if ((rptr -> depth > 1) && (sz == sizeof (uint8))) val = *(((uint8 *) rptr -> loc) + idx); else if ((rptr -> depth > 1) && (sz == sizeof (uint16))) val = *(((uint16 *) rptr -> loc) + idx); -#if !defined (int64) +#if !defined (t_int64) else val = *(((uint32 *) rptr -> loc) + idx); #else else if (sz <= sizeof (uint32)) val = *(((uint32 *) rptr -> loc) + idx); -else val = *(((uint64 *) rptr -> loc) + idx); +else val = *(((t_uint64 *) rptr -> loc) + idx); #endif val = (val >> rptr -> offset) & width_mask[rptr -> width]; return val; @@ -1589,12 +1611,12 @@ if ((rptr -> depth > 1) && (sz == sizeof (uint8))) PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask); else if ((rptr -> depth > 1) && (sz == sizeof (uint16))) PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask); -#if !defined (int64) +#if !defined (t_int64) else PUT_RVAL (uint32, rptr, idx, val, mask); #else else if (sz <= sizeof (uint32)) PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask); -else PUT_RVAL (uint64, rptr, idx, val, mask); +else PUT_RVAL (t_uint64, rptr, idx, val, mask); #endif return; } @@ -2182,6 +2204,7 @@ return SCPE_OK; sim_is_active see if entry is on event queue sim_atime return absolute time for an entry sim_gtime return global time + sim_qcount return event queue entry count Asynchronous events are set up by queueing a unit data structure to the event queue with a timeout (in simulator units, relative @@ -2335,6 +2358,23 @@ if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); } else { UPDATE_SIM_TIME (sim_clock_queue -> time); } return sim_rtime; } + +/* sim_qcount - return queue entry count + + Inputs: none + Outputs: + count = number of entries on the queue +*/ + +int32 sim_qcount (void) +{ +int32 cnt; +UNIT *uptr; + +cnt = 0; +for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr -> next) cnt++; +return cnt; +} /* Endian independent binary I/O package @@ -2456,77 +2496,4 @@ rtc_currdelay = (int32) (((double) rtc_basedelay * (double) rtc_nextintv) / 1000.0); /* next delay */ return rtc_currdelay; } - -/* OS independent multiconsole package - - set_console make unit the active console - sim_putcons output character in a multiconsole simulator - sim_chkcons check for buffered output in a multiconsole simulator -*/ - -t_stat set_console (UNIT *uptr, int32 flag) -{ -int32 i; -DEVICE *idptr, *odptr; -UNIT *wuptr, *iuptr = NULL, *ouptr = NULL; - -if (sim_consoles == NULL) return SCPE_NOFNC; -for (i = 0; sim_consoles[i] != NULL; i++) { - if (uptr == sim_consoles[i]) { - iuptr = sim_consoles[i & ~1]; - ouptr = sim_consoles[i | 1]; } } -if ((iuptr == NULL) || (ouptr == NULL)) return SCPE_ARG; -idptr = find_dev_from_unit (iuptr); -odptr = find_dev_from_unit (ouptr); -if ((idptr == NULL) || (odptr == NULL)) return SCPE_ARG; -for (i = 0; sim_consoles[i] != NULL; i++) { - wuptr = sim_consoles[i]; - wuptr -> flags = wuptr -> flags & ~UNIT_CONS; - if (!(i & 1)) sim_cancel (wuptr); } -iuptr -> flags = iuptr -> flags | UNIT_CONS; -ouptr -> flags = ouptr -> flags | UNIT_CONS; -sim_activate (iuptr, iuptr -> wait); -if (idptr == odptr) { - printf ("Active console is %s\n", idptr -> name); - if (sim_log) fprintf (sim_log, "Active console is %s\n", idptr -> name); } -else { printf ("Active console is %s/%s\n", idptr -> name, odptr -> name); - if (sim_log) fprintf (sim_log, - "Active console is %s/%s\n", idptr -> name, odptr -> name); } -return SCPE_OK; -} - -t_stat sim_putcons (int32 out, UNIT *uptr) -{ -uint8 *consbuf; - -if ((uptr -> flags & UNIT_CONS) || (uptr -> filebuf == NULL)) - return sim_putchar (out); -if (uptr -> u4 < CONS_SIZE) { - consbuf = (uint8 *) uptr -> filebuf; - consbuf[uptr -> u4] = out; } -uptr -> u4 = uptr -> u4 + 1; -return SCPE_OK; -} - -void sim_chkcons (void) -{ -int32 i, j, limit; -uint8 *consbuf; -UNIT *uptr; - -if (sim_consoles == NULL) return; -for (i = 0; sim_consoles[i] != NULL; i++) { - uptr = sim_consoles[i]; - if ((i & 1) && (uptr -> flags & UNIT_CONS) && - (uptr -> filebuf) && (uptr -> u4)) { - consbuf = (uint8 *) uptr -> filebuf; - limit = (uptr -> u4 < CONS_SIZE)? uptr -> u4: CONS_SIZE; - for (j = 0; j < limit; j++) sim_putchar (consbuf[j]); - if (uptr -> u4 >= CONS_SIZE) { - printf ("\n[Buffered output lost]\n"); - if (sim_log) fprintf (sim_log, "\n[Buffered output lost]\n"); } - uptr -> u4 = 0; - return; } } -return; -} diff --git a/scp_tty.c b/scp_tty.c index 49f73c70..d46159cf 100644 --- a/scp_tty.c +++ b/scp_tty.c @@ -23,6 +23,8 @@ 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. + 19-Sep-01 RMS More Mac changes + 31-Aug-01 RMS Changed int64 to t_int64 for Windoze 20-Jul-01 RMS Added Macintosh support (from Louis Chretien, Peter Schorn, and Ben Supnik) 15-May-01 RMS Added logging support @@ -50,7 +52,6 @@ The POSIX UNIX version works with LINUX. */ -#undef USE_INT64 /* hack for Windows */ #include "sim_defs.h" int32 sim_int_char = 005; /* interrupt character */ extern FILE *sim_log; @@ -190,7 +191,7 @@ return quo; /* Win32 routines */ -#if defined (WIN32) +#if defined (_WIN32) #define __TTYROUTINES 0 #include #include @@ -326,6 +327,7 @@ return 0; #include #include #include +#include extern char sim_name[]; extern pSIOUXWin SIOUXTextWindow; @@ -339,7 +341,11 @@ static void updateCursor(void) { Point localMouse; GetPort(&savePort); SetPort(window); +#if !TARGET_API_MAC_CARBON + localMouse = LMGetMouseLocation(); +#else GetGlobalMouse(&localMouse); +#endif GlobalToLocal(&localMouse); if (PtInRect(localMouse, &(*SIOUXTextWindow->edit)->viewRect) && iBeamCursorH) { SetCursor(*iBeamCursorH); diff --git a/sim_defs.h b/sim_defs.h index 3d75f78c..42d58546 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -23,6 +23,10 @@ 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. + 27-Sep-01 RMS Added queue count prototype + 17-Sep-01 RMS Removed multiple console support + 07-Sep-01 RMS Removed conditional externs on function prototypes + 31-Aug-01 RMS Changed int64 to t_int64 for Windoze 17-Jul-01 RMS Added additional function prototypes 27-May-01 RMS Added multiple console support 15-May-01 RMS Increased string buffer size @@ -73,16 +77,18 @@ typedef int t_bool; /* boolean */ typedef unsigned int8 uint8; typedef unsigned int16 uint16; typedef unsigned int32 uint32, t_addr; /* address */ -#if defined (USE_INT64) && defined (WIN32) -#define int64 __int64 /* for Windows */ -#elif defined (USE_INT64) && defined (__digital__) && defined (__unix__) -#define int64 long /* for DUNIX */ +#if defined (USE_INT64) && defined (_WIN32) +#define t_int64 __int64 /* for Windows */ +#elif defined (USE_INT64) && defined (VMS) && defined (__ALPHA) +#define t_int64 __int64 /* for AVMS */ +#elif defined (USE_INT64) && defined (__ALPHA) && defined (__unix__) +#define t_int64 long /* for DUNIX */ #elif defined (USE_INT64) -#define int64 long long /* for GCC */ +#define t_int64 long long /* for GCC */ #endif -#if defined (int64) -typedef unsigned int64 uint64, t_value; /* value */ -typedef int64 t_svalue; /* signed value */ +#if defined (t_int64) +typedef unsigned t_int64 t_uint64, t_value; /* value */ +typedef t_int64 t_svalue; /* signed value */ #else typedef unsigned int32 t_value; typedef int32 t_svalue; @@ -221,8 +227,6 @@ struct unit { #define UNIT_BUF 000400 /* buffered */ #define UNIT_DISABLE 001000 /* disable-able */ #define UNIT_DIS 002000 /* disabled */ -#define UNIT_CONS 004000 /* active console */ -#define UNIT_V_CONS 11 #define UNIT_V_UF 12 /* device specific */ /* Register data structure */ @@ -254,8 +258,8 @@ struct ctab { /* Modifier table */ struct mtab { - int32 mask; /* mask */ - int32 match; /* match */ + int32 mask; /* mask or radix */ + int32 match; /* match or max */ char *pstring; /* print string */ char *mstring; /* match string */ t_stat (*valid)(); /* validation routine */ @@ -301,30 +305,24 @@ typedef struct schtab SCHTAB; /* Function prototypes */ -#if defined (SCP) /* defining routine? */ -#define EXTERN -#else /* referencing routine */ -#define EXTERN extern -#endif - -EXTERN t_stat sim_process_event (void); -EXTERN t_stat sim_activate (UNIT *uptr, int32 interval); -EXTERN t_stat sim_cancel (UNIT *uptr); -EXTERN int32 sim_is_active (UNIT *uptr); -EXTERN double sim_gtime (void); -EXTERN uint32 sim_grtime (void); -EXTERN t_stat attach_unit (UNIT *uptr, char *cptr); -EXTERN t_stat detach_unit (UNIT *uptr); -EXTERN t_stat reset_all (int start_device); -EXTERN size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr); -EXTERN size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr); -EXTERN t_stat get_yn (char *ques, t_stat deflt); -EXTERN char *get_glyph (char *iptr, char *optr, char mchar); -EXTERN char *get_glyph_nc (char *iptr, char *optr, char mchar); -EXTERN t_value get_uint (char *cptr, int radix, t_value max, t_stat *status); -EXTERN t_value strtotv (char *cptr, char **endptr, int radix); -EXTERN int32 sim_rtc_init (int32 time); -EXTERN int32 sim_rtc_calb (int32 ticksper); -EXTERN t_stat set_console (UNIT *uptr, int32 flag); -EXTERN t_stat sim_putcons (int32 out, UNIT *uptr); - +t_stat sim_process_event (void); +t_stat sim_activate (UNIT *uptr, int32 interval); +t_stat sim_cancel (UNIT *uptr); +int32 sim_is_active (UNIT *uptr); +double sim_gtime (void); +uint32 sim_grtime (void); +int32 sim_qcount (void); +t_stat attach_unit (UNIT *uptr, char *cptr); +t_stat detach_unit (UNIT *uptr); +t_stat reset_all (int start_device); +size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr); +size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr); +t_stat get_yn (char *ques, t_stat deflt); +char *get_glyph (char *iptr, char *optr, char mchar); +char *get_glyph_nc (char *iptr, char *optr, char mchar); +t_value get_uint (char *cptr, int radix, t_value max, t_stat *status); +t_value strtotv (char *cptr, char **endptr, int radix); +int32 sim_rtc_init (int32 time); +int32 sim_rtc_calb (int32 ticksper); +t_stat sim_poll_kbd (void); +t_stat sim_putchar (int32 out); diff --git a/sim_rev.h b/sim_rev.h new file mode 100644 index 00000000..61757a7b --- /dev/null +++ b/sim_rev.h @@ -0,0 +1,123 @@ +/* sim_rev.h: simulator revisions and current rev level + + Copyright (c) 1993-2001, 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"), + 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. +*/ + +#define SIM_MAJOR 2 +#define SIM_MINOR 7 +#define SIM_PATCH 15 + +/* SIMH detailed revision list, starting with V2.7 + +patch date module(s) and fix(es) + +15 23-Oct-01 pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: fixed bugs + error interrupt handling + + pdp10_defs.h, pdp10_ksio.c, pdp10_fe.c, pdp10_fe.c, + pdp10_rp.c, pdp10_tu.c: reworked I/O page interface + to use symbolic base addresses and lengths + +14 20-Oct-01 dec_dz.h, sim_tmxr_h, sim_tmxr.c: fixed bug in Telnet + state handling (found by Thord Nilson), removed + tmxr_getchar, added tmxr_rqln and tmxr_tqln + +13 18-Oct-01 pdp11_tm.c: added stub diagnostic register clock + for RSTS/E (found by Thord Nilson) + +12 15-Oct-01 pdp11_defs.h, pdp11_cpu.c, pdp11_tc.c, pdp11_ts.c, + pdp11_rp.c: added operations logging + +11 8-Oct-01 scp.c: added sim_rev.h include and version print + + pdp11_cpu.c: fixed bug in interrupt acknowledge, + multiple outstanding interrupts caused the lowest + rather than the highest to be acknowledged + +10 7-Oct-01 pdp11_stddev.c: added monitor bits (CSR<7>) for full + KW11L compatibility, needed for RSTS/E autoconfiguration + +9 6-Oct-01 pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: rewrote interrupt + logic from RH11/RH70 schematics, to mimic hardware quirks + + dec_dz.c: fixed bug in carrier detect logic, carrier + detect was being cleared on next modem poll + +8 4-Oct-01 pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: undid edit of + 28-Sep-01; real problem was level-sensitive nature of + CS1_SC, but CS1_SC can only trigger an interrupt if + DONE is set + +7 2-Oct-01 pdp11_rp.c, pdp10_rp.c: CS1_SC is evaluated as a level- + sensitive, rather than an edge-sensitive, input to + interrupt request + +6 30-Sep-01 pdp11_rp.c, pdp10_rp.c: separated out CS1<5:0> to per- + drive registers + + pdp10_tu.c: based on above, cleaned up handling of + non-existent formatters, fixed non-data transfer commands + clearing DONE + +5 28-Sep-01 pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: controller should + interrupt if ATA or SC sets when IE is set, was + interrupting only if DON = 1 as well + +4 27-Sep-01 pdp11_ts.c: + -- NXM errors should return TC4 or TC5; were returning TC3 + -- extended features is part of XS2; was returned in XS3 + -- extended characteristics (fifth) word needed for RSTS/E + + pdp11_tc.c: stop, stop all do cause an interrupt + + dec_dz.h: scanner should find a ready output line, even + if there are no connections; needed for RSTS/E autoconfigure + + scp.c: + -- added routine sim_qcount for 1130 + -- added "simulator exit" detach routine for 1130 + + sim_defs.h: added header for sim_qcount + +3 20-Sep-01 pdp11_ts.c: boot code binary was incorrect + +2 19-Sep-01 pdp18b_cpu.c: EAE should interpret initial count of 00 + as 100 + + scp.c: modified Macintosh support + +1 17-Sep-01 pdp8_ttx.c: new module for PDP-8 multi-terminal support + + pdp18b_tt1.c: modified to use sim_tmxr library + + nova_tt1.c: modified to use sim_tmxr library + + dec_dz.h: added autodisconnect support + + scp.c: removed old multiconsole support + + sim_tmxr.c: modified calling sequence for sim_putchar_ln + + sim_sock.c: added Macintosh sockets support +*/ \ No newline at end of file diff --git a/sim_sock.c b/sim_sock.c new file mode 100644 index 00000000..a515cae9 --- /dev/null +++ b/sim_sock.c @@ -0,0 +1,210 @@ +/* scp_sock.c: OS-dependent socket routines + + Copyright (c) 2001, 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"), + 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. + + 16-Sep-01 RMS Added Macintosh support from Peter Schorn + 02-Sep-01 RMS Fixed UNIX bugs found by Mirian Lennox and Tom Markson +*/ + +#include "sim_defs.h" +#include "sim_sock.h" +#include + +/* OS dependent routines + + sim_master_sock create master socket + sim_accept_conn accept connection + sim_read_sock read from socket + sim_write_sock write from socket + sim_close_sock close socket + sim_setnonblock set socket non-blocking + sim_msg_sock send message to socket +*/ + +/* First, all the non-implemented versions */ + +#if defined (VMS) || defined (__OS2__) + +SOCKET sim_master_sock (int32 port) +{ +return INVALID_SOCKET; +} + +SOCKET sim_accept_conn (SOCKET master, UNIT *uptr) +{ +return INVALID_SOCKET; +} + +int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes) +{ +return -1; +} + +int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes) +{ +return 0; +} + +void sim_close_sock (SOCKET sock) +{ +return; +} + +SOCKET sim_setnonblock (SOCKET sock) +{ +return SOCKET_ERROR; +} + +#else /* endif unimpl */ + +/* UNIX, Win32, Macintosh (Berkeley socket) routines */ + +SOCKET sim_master_sock (int32 port) +{ +SOCKET newsock; +struct sockaddr_in name; +int32 sta; + +#if defined (_WIN32) +WORD wVersionRequested; +WSADATA wsaData; +wVersionRequested = MAKEWORD(1, 1); + +sta = WSAStartup(wVersionRequested, &wsaData); /* start Winsock */ +if (sta != 0) { + printf ("Winsock: startup error %d\n", sta); + return sta; } +#endif /* endif Win32 */ + +newsock = socket (AF_INET, SOCK_STREAM, 0); /* create socket */ +if (newsock == INVALID_SOCKET) { /* socket error? */ + perror ("Sockets: socket error"); + return INVALID_SOCKET; } + +name.sin_family = AF_INET; /* name socket */ +name.sin_port = htons ((unsigned short) port); /* insert port */ +name.sin_addr.s_addr = htonl (INADDR_ANY); +sta = bind (newsock, (struct sockaddr *) &name, sizeof (name)); +if (sta == SOCKET_ERROR) { /* bind error? */ + perror ("Sockets: bind error"); + sim_close_sock (newsock, 1); + return INVALID_SOCKET; } + +sta = sim_setnonblock (newsock); /* set nonblocking */ +if (sta == SOCKET_ERROR) { /* fcntl error? */ + perror ("Sockets: fcntl error"); + sim_close_sock (newsock, 1); + return INVALID_SOCKET; } + +sta = listen (newsock, 1); /* listen on socket */ +if (sta == SOCKET_ERROR) { /* listen error? */ + perror ("Sockets: listen error"); + sim_close_sock (newsock, 1); + return INVALID_SOCKET; } +return newsock; /* got it! */ +} + +SOCKET sim_accept_conn (SOCKET master, UNIT *uptr, uint32 *ipaddr) +{ +int32 sta; +#if defined (macintosh) +socklen_t size; +#else +size_t size; +#endif +SOCKET newsock; +struct sockaddr_in clientname; + +if ((uptr -> flags & UNIT_ATT) == 0) /* not attached? */ + return INVALID_SOCKET; +size = sizeof (clientname); +newsock = accept (master, (struct sockaddr *) &clientname, &size); +if (newsock == INVALID_SOCKET) { /* error? */ + if (WSAGetLastError () != WSAEWOULDBLOCK) + perror ("Sockets: accept error"); + return INVALID_SOCKET; } +if (ipaddr != NULL) *ipaddr = ntohl (clientname.sin_addr.s_addr); + +sta = sim_setnonblock (newsock); /* set nonblocking */ +if (sta == SOCKET_ERROR) { /* fcntl error? */ + perror ("Sockets: fcntl error"); + sim_close_sock (newsock, 0); + return INVALID_SOCKET; } +return newsock; +} + +int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes) +{ +int32 rbytes; + +rbytes = recv (sock, buf, nbytes, 0); +if (rbytes == 0) return -1; /* disconnect */ +if (rbytes == SOCKET_ERROR) { + if (WSAGetLastError () == WSAEWOULDBLOCK) return 0; /* no data */ + perror("Sockets: read error"); + return -1; } +return rbytes; +} + +int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes) +{ +return send (sock, msg, nbytes, 0); +} + +void sim_close_sock (SOCKET sock, t_bool master) +{ +#if defined (_WIN32) +closesocket (sock); +if (master) WSACleanup (); +#else +close (sock); +#endif +return; +} + +#if defined (_WIN32) +SOCKET sim_setnonblock (SOCKET sock) +{ +unsigned long non_block = 1; + +return ioctlsocket (sock, FIONBIO, &non_block); /* set nonblocking */ +} +#else +int32 sim_setnonblock (SOCKET sock) +{ +int32 fl, sta; + +fl = fcntl (sock, F_GETFL,0); /* get flags */ +if (fl == -1) return SOCKET_ERROR; +sta = fcntl (sock, F_SETFL, fl | O_NONBLOCK); /* set nonblock */ +if (sta == -1) return SOCKET_ERROR; +#if !defined (macintosh) +sta = fcntl (sock, F_SETOWN, getpid()); /* set ownership */ +if (sta == -1) return SOCKET_ERROR; +#endif +return 0; +} +#endif /* endif Win32 */ + +#endif /* endif Win32/UNIX/Mac */ diff --git a/sim_sock.h b/sim_sock.h new file mode 100644 index 00000000..11e5ad40 --- /dev/null +++ b/sim_sock.h @@ -0,0 +1,64 @@ +/* scp_sock.h: OS-dependent socket routines header file + + Copyright (c) 2001, 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"), + 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. + + 16-Sep-01 RMS Added Macintosh support from Peter Schorn +*/ + +#if defined (WIN32) +#undef INT_PTR /* hack, hack */ +#include +#else +#define WSAGetLastError() errno +#if !defined (VMS) && !defined (__OS2__) +#include /* for fcntl, getpid */ +#include /* for sockets */ +#include +#include +#include /* for sockaddr_in */ +#include +#endif +#endif + +/* Code uses Windows-specific defs that are undefined for most systems */ + +#if !defined (SOCKET) +#define SOCKET int32 +#endif +#if !defined (WSAEWOULDBLOCK) +#define WSAEWOULDBLOCK EWOULDBLOCK +#endif +#if !defined (INVALID_SOCKET) +#define INVALID_SOCKET -1 +#endif +#if !defined (SOCKET_ERROR) +#define SOCKET_ERROR -1 +#endif + +SOCKET sim_master_sock (int32 port); +SOCKET sim_accept_conn (SOCKET master, UNIT *uptr, uint32 *ipaddr); +int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes); +int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes); +void sim_close_sock (SOCKET sock, t_bool master); +SOCKET sim_setnonblock (SOCKET sock); diff --git a/sim_tmxr.c b/sim_tmxr.c new file mode 100644 index 00000000..accfa3ab --- /dev/null +++ b/sim_tmxr.c @@ -0,0 +1,403 @@ +/* sim_tmxr.c: Telnet terminal multiplexor library + + Copyright (c) 2001, 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"), + 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. + + Based on the original DZ11 simulator by Thord Nilson, as updated by + Arthur Krewat. + + 20-Oct-01 RMS Fixed bugs in read logic (found by Thord Nilson). + added tmxr_rqln, tmxr_tqln +*/ + +#include "sim_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" + +/* Telnet protocol constants - negatives are for init'ing signed char data */ + +#define TN_IAC -1 /* protocol delim */ +#define TN_DONT -2 /* dont */ +#define TN_DO -3 /* do */ +#define TN_WONT -4 /* wont */ +#define TN_WILL -5 /* will */ +#define TN_BIN 0 /* bin */ +#define TN_ECHO 1 /* echo */ +#define TN_SGA 3 /* sga */ +#define TN_LINE 34 /* line mode */ +#define TN_CR 015 /* carriage return */ + +/* Telnet line states */ + +#define TNS_NORM 000 /* normal */ +#define TNS_IAC 001 /* IAC seen */ +#define TNS_WILL 002 /* WILL seen */ +#define TNS_WONT 003 /* WONT seen */ +#define TNS_SKIP 004 /* skip next */ + +void tmxr_rmvrc (TMLN *lp, int32 p); +extern int32 sim_switches; +extern char sim_name[]; +extern FILE *sim_log; +extern uint32 sim_os_msec (void); + +/* Poll for new connection + + Called from unit service routine to test for new connection + + Inputs: + *mp = pointer to terminal multiplexor descriptor + Outputs: + line number activated, -1 if none +*/ + +int32 tmxr_poll_conn (TMXR *mp, UNIT *uptr) +{ +SOCKET newsock; +TMLN *lp; +int32 i; +uint32 ipaddr; +static char mantra[] = { + TN_IAC, TN_WILL, TN_LINE, + TN_IAC, TN_WILL, TN_SGA, + TN_IAC, TN_WILL, TN_ECHO, + TN_IAC, TN_WILL, TN_BIN, + TN_IAC, TN_DO, TN_BIN }; + +newsock = sim_accept_conn (mp -> master, uptr, &ipaddr);/* poll connect */ +if (newsock != INVALID_SOCKET) { /* got a live one? */ + for (i = 0; i < mp -> lines; i++) { /* find avail line */ + lp = mp -> ldsc[i]; /* ptr to ln desc */ + if (lp -> conn == 0) break; } /* available? */ + if (i >= mp -> lines) { /* all busy? */ + tmxr_msg (newsock, "All connections busy... please try later\r\n"); + sim_close_sock (newsock, 0); } + else { lp = mp -> ldsc[i]; /* get line desc */ + lp -> conn = newsock; /* record connection */ + lp -> ipad = ipaddr; /* ip address */ + lp -> cnms = sim_os_msec (); /* time of conn */ + lp -> rxbpr = lp -> rxbpi = 0; /* init buf pointers */ + lp -> txbpr = lp -> txbpi = 0; + lp -> rxcnt = lp -> txcnt = 0; /* init counters */ + lp -> tsta = 0; /* init telnet state */ + lp -> xmte = 1; /* enable transmit */ + lp -> dstb = 0; /* default bin mode */ + sim_write_sock (newsock, mantra, 15); + tmxr_msg (newsock, "\n\r\nWelcome to the "); + tmxr_msg (newsock, sim_name); + tmxr_msg (newsock, " simulator\r\n\n"); + return i; } + } /* end if newsock */ +return -1; +} + +/* Reset line */ + +void tmxr_reset_ln (TMLN *lp) +{ +sim_close_sock (lp -> conn, 0); /* reset conn */ +lp -> conn = lp -> tsta = 0; /* reset state */ +lp -> rxbpr = lp -> rxbpi = 0; +lp -> txbpr = lp -> txbpi = 0; +lp -> xmte = 1; +lp -> dstb = 0; +return; +} + +/* Get character from specific line + + Inputs: + *lp = pointer to terminal line descriptor + Output: + valid + char, 0 if line +*/ + +int32 tmxr_getc_ln (TMLN *lp) +{ +int32 j, val = 0; +uint32 tmp; + +if (lp -> conn && lp -> rcve) { /* conn & enb? */ + j = lp -> rxbpi - lp -> rxbpr; /* # input chrs */ + if (j) { /* any? */ + tmp = lp -> rxb[lp -> rxbpr]; /* get char */ + lp -> rxbpr = lp -> rxbpr + 1; /* adv pointer */ + val = TMXR_VALID | (tmp & 0377); } /* valid + chr */ + } /* end if conn */ +if (lp -> rxbpi == lp -> rxbpr) /* empty? zero ptrs */ + lp -> rxbpi = lp -> rxbpr = 0; +return val; +} + +/* Poll for input + + Inputs: + *mp = pointer to terminal multiplexor descriptor + Outputs: none +*/ + +void tmxr_poll_rx (TMXR *mp) +{ +int32 i, nbytes, j; +TMLN *lp; + +for (i = 0; i < mp -> lines; i++) { /* loop thru lines */ + lp = mp -> ldsc[i]; /* get line desc */ + if (!lp -> conn || !lp -> rcve) continue; /* skip if !conn */ + + nbytes = 0; + if (lp -> rxbpi == 0) /* need input? */ + nbytes = sim_read_sock (lp -> conn, /* yes, read */ + &(lp -> rxb[lp -> rxbpi]), /* leave spc for */ + TMXR_MAXBUF - TMXR_GUARD); /* Telnet cruft */ + else if (lp -> tsta) /* in Telnet seq? */ + nbytes = sim_read_sock (lp -> conn, /* yes, read to end */ + &(lp -> rxb[lp -> rxbpi]), + TMXR_MAXBUF - lp -> rxbpi); + if (nbytes < 0) tmxr_reset_ln (lp); /* closed? reset ln */ + else if (nbytes > 0) { /* if data rcvd */ + j = lp -> rxbpi; /* start of data */ + lp -> rxbpi = lp -> rxbpi + nbytes; /* adv pointers */ + lp -> rxcnt = lp -> rxcnt + nbytes; + +/* Examine new data, remove TELNET cruft before making input available */ + + for (; j < lp -> rxbpi; ) { /* loop thru char */ + char tmp = lp -> rxb[j]; /* get char */ + switch (lp -> tsta) { /* case tlnt state */ + case TNS_NORM: /* normal */ + if (tmp == TN_IAC) { /* IAC? */ + lp -> tsta = TNS_IAC; /* change state */ + tmxr_rmvrc (lp, j); /* remove char */ + break; } + if ((tmp == TN_CR) && lp -> dstb) /* CR, no bin */ + lp -> tsta = TNS_SKIP; /* skip next */ + j = j + 1; /* advance j */ + break; + case TNS_IAC: /* IAC prev */ + if (tmp == TN_WILL) /* IAC + WILL? */ + lp -> tsta = TNS_WILL; + else if (tmp == TN_WONT) /* IAC + WONT? */ + lp -> tsta = TNS_WONT; + else lp -> tsta = TNS_SKIP; /* IAC + other */ + tmxr_rmvrc (lp, j); /* remove char */ + break; + case TNS_WILL: case TNS_WONT: /* IAC+WILL/WONT prev */ + if (tmp == TN_BIN) { /* BIN? */ + if (lp -> tsta == TNS_WILL) lp -> dstb = 0; + else lp -> dstb = 1; } + case TNS_SKIP: default: /* skip char */ + lp -> tsta = TNS_NORM; /* next normal */ + tmxr_rmvrc (lp, j); /* remove char */ + break; } /* end case state */ + } /* end for char */ + } /* end else nbytes */ + } /* end for lines */ +for (i = 0; i < mp -> lines; i++) { /* loop thru lines */ + lp = mp -> ldsc[i]; /* get line desc */ + if (lp -> rxbpi == lp -> rxbpr) /* if buf empty, */ + lp -> rxbpi = lp -> rxbpr = 0; /* reset pointers */ + } /* end for */ +return; +} + +/* Return count of available characters for line */ + +int32 tmxr_rqln (TMLN *lp) +{ +return (lp -> rxbpi - lp -> rxbpr); +} + +/* Remove character p from line l input buffer */ + +void tmxr_rmvrc (TMLN *lp, int32 p) +{ +for ( ; p < lp -> rxbpi; p++) lp -> rxb[p] = lp -> rxb[p + 1]; +lp -> rxbpi = lp -> rxbpi - 1; +return; +} + +/* Store character in line buffer + + Inputs: + *lp = pointer to line descriptor + chr = characters + Outputs: + none +*/ + +void tmxr_putc_ln (TMLN *lp, int32 chr) +{ +if (lp -> conn == 0) return; /* no conn? done */ +if (lp -> txbpi < TMXR_MAXBUF) { /* room for char? */ + lp -> txb[lp -> txbpi] = (char) chr; /* buffer char */ + lp -> txbpi = lp -> txbpi + 1; /* adv pointer */ + if (lp -> txbpi > (TMXR_MAXBUF - TMXR_GUARD)) /* near full? */ + lp -> xmte = 0; } /* disable line */ +else lp -> xmte = 0; /* disable line */ +return; +} + +/* Poll for output + + Inputs: + *mp = pointer to terminal multiplexor descriptor + Outputs: + none +*/ + +void tmxr_poll_tx (TMXR *mp) +{ +int32 i, nbytes, sbytes; +TMLN *lp; + +for (i = 0; i < mp -> lines; i++) { /* loop thru lines */ + lp = mp -> ldsc[i]; /* get line desc */ + if (lp -> conn == 0) continue; /* skip if !conn */ + nbytes = lp -> txbpi - lp -> txbpr; /* avail bytes */ + if (nbytes) { /* >0? write */ + sbytes = sim_write_sock (lp -> conn, + &(lp -> txb[lp -> txbpr]), nbytes); + if (sbytes != SOCKET_ERROR) { /* update ptrs */ + lp -> txbpr = lp -> txbpr + sbytes; + lp -> txcnt = lp -> txcnt + sbytes; + nbytes = nbytes - sbytes; } + } + if (nbytes == 0) { /* buf empty? */ + lp -> xmte = 1; /* enable this line */ + lp -> txbpr = lp -> txbpi = 0; } + } /* end for */ +return; +} + +/* Return count of buffered characters for line */ + +int32 tmxr_tqln (TMLN *lp) +{ +return (lp -> txbpi - lp -> txbpr); +} + +/* Attach */ + +t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr) +{ +char* tptr; +int32 i, port; +SOCKET sock; +TMLN *lp; +t_stat r; +extern int32 sim_switches; + +port = (int32) get_uint (cptr, 10, 65535, &r); /* get port */ +if ((r != SCPE_OK) || (port == 0)) return SCPE_ARG; +tptr = malloc (strlen (cptr) + 1); /* get string buf */ +if (tptr == NULL) return SCPE_MEM; /* no more mem? */ + +sock = sim_master_sock (port); /* make master socket */ +if (sock == INVALID_SOCKET) { /* open error */ + free (tptr); /* release buf */ + return SCPE_OPENERR; } +printf ("Listening on socket %d\n", sock); +if (sim_log) fprintf (sim_log, "Listening on socket %d\n", sock); +mp -> master = sock; /* save master socket */ +strcpy (tptr, cptr); /* copy port */ +uptr -> filename = tptr; /* save */ +uptr -> flags = uptr -> flags | UNIT_ATT; /* no more errors */ + +for (i = 0; i < mp -> lines; i++) { /* initialize lines */ + lp = mp -> ldsc[i]; + lp -> conn = lp -> tsta = 0; + lp -> rxbpi = lp -> rxbpr = 0; + lp -> txbpi = lp -> txbpr = 0; + lp -> rxcnt = lp -> txcnt = 0; + lp -> xmte = 1; + lp -> dstb = 0; } +return SCPE_OK; +} + +/* Detach */ + +t_stat tmxr_detach (TMXR *mp, UNIT *uptr) +{ +int32 i; +TMLN *lp; + +if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ +for (i = 0; i < mp -> lines; i++) { /* loop thru conn */ + lp = mp -> ldsc[i]; + if (lp -> conn) { + tmxr_msg (lp -> conn, "\r\n"); + tmxr_msg (lp -> conn, sim_name); + tmxr_msg (lp -> conn, " simulator shutting down... please come back later\r\n\n"); + tmxr_reset_ln (lp); } /* end if conn */ + } /* end for */ +sim_close_sock (mp -> master, 1); /* close master socket */ +mp -> master = 0; +free (uptr -> filename); /* free port string */ +uptr -> filename = NULL; +uptr -> flags = uptr -> flags & ~UNIT_ATT; /* not attached */ +return SCPE_OK; +} + +/* Stub examine and deposit */ + +t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +return SCPE_NOFNC; +} + +t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +return SCPE_NOFNC; +} + +/* Output message */ + +void tmxr_msg (SOCKET sock, char *msg) +{ +if (sock) sim_write_sock (sock, msg, strlen (msg)); +return; +} + +/* Print line status */ + +void tmxr_fstatus (FILE *st, TMLN *lp, int32 ln) +{ +if (ln >= 0) fprintf (st, "\n line %d", ln); +if (lp -> conn) { + int32 o1, o2, o3, o4, hr, mn, sc; + uint32 ctime; + + o1 = (lp -> ipad >> 24) & 0xFF; + o2 = (lp -> ipad >> 16) & 0xFF; + o3 = (lp -> ipad >> 8) & 0xFF; + o4 = (lp -> ipad) & 0xFF; + ctime = (sim_os_msec () - lp -> cnms) / 1000; + hr = ctime / 3600; + mn = (ctime / 60) % 60; + sc = ctime % 3600; + fprintf (st, ": IP address %d.%d.%d.%d", o1, o2, o3, o4); + if (ctime) fprintf (st, ", connected %02d:%02d:%02d", hr, mn, sc); } +else fprintf (st, ": disconnected"); +return; +} diff --git a/sim_tmxr.h b/sim_tmxr.h new file mode 100644 index 00000000..7501b663 --- /dev/null +++ b/sim_tmxr.h @@ -0,0 +1,81 @@ +/* sim_tmxr.h: terminal multiplexor definitions + + Copyright (c) 2001, 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"), + 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. + + Based on the original DZ11 simulator by Thord Nilson, as updated by + Arthur Krewat. + + 20-Oct-01 RMS Removed tmxr_getchar, formalized buffer guard, + added tmxr_rqln, tmxr_tqln +*/ + +#define TMXR_V_VALID 15 +#define TMXR_VALID (1 << TMXR_V_VALID) +#define TMXR_MAXBUF 128 /* buffer size */ +#define TMXR_GUARD 8 /* buffer guard */ +#define TMXR_MAXLIN 64 /* max lines */ + +struct tmln { + SOCKET conn; /* line conn */ + uint32 ipad; /* IP address */ + uint32 cnms; /* conn time */ + int32 tsta; /* Telnet state */ + int32 rcve; /* rcv enable */ + int32 xmte; /* xmt enable */ + int32 dstb; /* disable Tlnt bin */ + int32 rxbpr; /* rcv buf remove */ + int32 rxbpi; /* rcv buf insert */ + int32 rxcnt; /* rcv count */ + int32 txbpr; /* xmt buf remove */ + int32 txbpi; /* xmt buf insert */ + int32 txcnt; /* xmt count */ + char rxb[TMXR_MAXBUF]; /* rcv buffer */ + char txb[TMXR_MAXBUF]; /* xmt buffer */ + }; + +typedef struct tmln TMLN; + +struct tmxr { + int32 lines; /* # lines */ + SOCKET master; /* master socket */ + TMLN *ldsc[TMXR_MAXLIN]; /* line descriptors */ + }; + +typedef struct tmxr TMXR; + +int32 tmxr_poll_conn (TMXR *mp, UNIT *uptr); +void tmxr_reset_ln (TMLN *lp); +int32 tmxr_getc_ln (TMLN *lp); +void tmxr_poll_rx (TMXR *mp); +void tmxr_putc_ln (TMLN *lp, int32 chr); +void tmxr_poll_tx (TMXR *mp); +t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr); +t_stat tmxr_detach (TMXR *mp, UNIT *uptr); +t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +void tmxr_msg (SOCKET sock, char *msg); +void tmxr_fstatus (FILE *st, TMLN *lp, int32 ln); +int32 tmxr_rqln (TMLN *lp); +int32 tmxr_tqln (TMLN *lp); + diff --git a/simh.doc b/simh.doc index ebe8110b..9a868050 100644 --- a/simh.doc +++ b/simh.doc @@ -1,138 +1,193 @@ {\rtf1\ansi\ansicpg1252\uc1 \deff0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;} -{\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f14\fnil\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings;} -{\f28\froman\fcharset238\fprq2 Times New Roman CE;}{\f29\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f31\froman\fcharset161\fprq2 Times New Roman Greek;}{\f32\froman\fcharset162\fprq2 Times New Roman Tur;} -{\f33\froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f34\froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f35\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f36\fswiss\fcharset238\fprq2 Arial CE;}{\f37\fswiss\fcharset204\fprq2 Arial Cyr;} -{\f39\fswiss\fcharset161\fprq2 Arial Greek;}{\f40\fswiss\fcharset162\fprq2 Arial Tur;}{\f41\fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f42\fswiss\fcharset178\fprq2 Arial (Arabic);}{\f43\fswiss\fcharset186\fprq2 Arial Baltic;} -{\f44\fmodern\fcharset238\fprq1 Courier New CE;}{\f45\fmodern\fcharset204\fprq1 Courier New Cyr;}{\f47\fmodern\fcharset161\fprq1 Courier New Greek;}{\f48\fmodern\fcharset162\fprq1 Courier New Tur;}{\f49\fmodern\fcharset177\fprq1 Courier New (Hebrew);} -{\f50\fmodern\fcharset178\fprq1 Courier New (Arabic);}{\f51\fmodern\fcharset186\fprq1 Courier New Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0; -\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{ -\ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 Normal;}{\*\cs10 \additive Default Paragraph Font;}{\*\cs15 \additive \b \sbasedon10 Strong;}}{\*\listtable -{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 -\fi-360\li720\jclisttab\tx720 }{\listname ;}\listid22442644}{\list\listtemplateid1593215596\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689 -\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li720\jclisttab\tx720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext -\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li1440\jclisttab\tx1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0 -{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li2160\jclisttab\tx2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 -\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li2880\jclisttab\tx2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 -\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li3600\jclisttab\tx3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 -\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li4320\jclisttab\tx4320 }{\listlevel\levelnfc23\levelnfcn23 -\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li5040\jclisttab\tx5040 }{\listlevel -\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li5760\jclisttab\tx5760 } -{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li6480 -\jclisttab\tx6480 }{\listname ;}\listid56512481}{\list\listtemplateid-1866037950{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 -\chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\chbrdr\brdrnone\brdrcf1 -\chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\chbrdr -\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers -\'01\'03\'05\'07;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext -\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal -\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-1080\li1080 -\jclisttab\tx1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\chbrdr -\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext -\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listname ;}\listid155609463} -{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 -\fi-360\li720\jclisttab\tx720 }{\listname ;}\listid602111040}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3 -\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid621424954}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0 -\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid717362522}{\list\listtemplateid67698689\listsimple{\listlevel\levelnfc23\levelnfcn23 -\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid1064328194} -{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 -\fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1080104542}{\list\listtemplateid-5054418{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat2\levelspace0\levelindent0{\leveltext\'01\'00;}{\levelnumbers\'01;}\chbrdr -\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-435\li435\jclisttab\tx435 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\chbrdr -\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-435\li435\jclisttab\tx435 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat2\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\chbrdr -\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;} -\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers -\'01\'03\'05\'07\'09;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1 -\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\levelnfcn0\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-1440\li1440 -\jclisttab\tx1440 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\chbrdr -\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-1800\li1800\jclisttab\tx1800 }{\listname ;}\listid1262834005}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0 -\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1272592440}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23 -\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1339387548} -{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 -\fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1409111490}{\list\listtemplateid1666980492\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689 -\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li720\jclisttab\tx720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext -\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li1440\jclisttab\tx1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0 -{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li2160\jclisttab\tx2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 -\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li2880\jclisttab\tx2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 -\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li3600\jclisttab\tx3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 -\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li4320\jclisttab\tx4320 }{\listlevel\levelnfc23\levelnfcn23 -\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li5040\jclisttab\tx5040 }{\listlevel -\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li5760\jclisttab\tx5760 } -{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li6480 -\jclisttab\tx6480 }{\listname ;}\listid1484007768}{\list\listtemplateid230209238{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat3\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 -\chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\chbrdr\brdrnone\brdrcf1 -\chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\chbrdr -\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers -\'01\'03\'05\'07;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext -\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal -\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-1080\li1080 -\jclisttab\tx1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\chbrdr -\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext -\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listname ;}\listid1502426668} -{\list\listtemplateid355235766\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 -\chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\chbrdr -\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li1080\jclisttab\tx1080 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693 -\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li1800\jclisttab\tx1800 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext -\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li2520\jclisttab\tx2520 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360 -\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li3240\jclisttab\tx3240 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 -\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li3960\jclisttab\tx3960 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 -\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li4680\jclisttab\tx4680 }{\listlevel\levelnfc23\levelnfcn23 -\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li5400\jclisttab\tx5400 }{\listlevel\levelnfc23 -\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li6120\jclisttab\tx6120 } -{\listname ;}\listid1523011899}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 -\chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1645162521}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid2006126440}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 -\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid2076124660}{\list\listtemplateid1666980492 -\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 -\fi-360\li720\jclisttab\tx720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\chbrdr\brdrnone\brdrcf1 -\chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li1440\jclisttab\tx1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr -\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li2160\jclisttab\tx2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689 -\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li2880\jclisttab\tx2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext -\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li3600\jclisttab\tx3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0 -{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li4320\jclisttab\tx4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 -\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li5040\jclisttab\tx5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 -\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li5760\jclisttab\tx5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 -\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f14\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li6480\jclisttab\tx6480 }{\listname ;}\listid2112620548}} -{\*\listoverridetable{\listoverride\listid155609463\listoverridecount0\ls1}{\listoverride\listid1409111490\listoverridecount0\ls2}{\listoverride\listid1272592440\listoverridecount0\ls3}{\listoverride\listid2076124660\listoverridecount0\ls4} -{\listoverride\listid717362522\listoverridecount0\ls5}{\listoverride\listid1339387548\listoverridecount0\ls6}{\listoverride\listid621424954\listoverridecount0\ls7}{\listoverride\listid1080104542\listoverridecount0\ls8}{\listoverride\listid1262834005 -\listoverridecount0\ls9}{\listoverride\listid2006126440\listoverridecount0\ls10}{\listoverride\listid602111040\listoverridecount0\ls11}{\listoverride\listid22442644\listoverridecount0\ls12}{\listoverride\listid1502426668\listoverridecount0\ls13} -{\listoverride\listid1645162521\listoverridecount0\ls14}{\listoverride\listid1064328194\listoverridecount0\ls15}{\listoverride\listid2112620548\listoverridecount0\ls16}{\listoverride\listid1484007768\listoverridecount0\ls17}{\listoverride\listid1523011899 -\listoverridecount0\ls18}{\listoverride\listid56512481\listoverridecount0\ls19}}{\info{\title Writing a Simulator for the SIMH System}{\author Bob Supnik}{\operator bsupnik}{\creatim\yr1997\mo8\dy30\hr19}{\revtim\yr2001\mo5\dy29\hr18\min17}{\version18} -{\edmins454}{\nofpages16}{\nofwords5879}{\nofchars33514}{\*\company Digital Equipment Corporation}{\nofcharsws41157}{\vern8299}}\widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\formshade\horzdoc\dghspace120 -\dgvspace120\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind4\viewscale100\pgbrdrhead\pgbrdrfoot\nolnhtadjtbl \fet0\sectd \linex0\endnhere\sectdefaultcl {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2 -\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6 -\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang -{\pntxtb (}{\pntxta )}}\pard\plain \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Writing a Simulator for the SIMH System -\par Revised 30-Jun-01 for V2.6a +{\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f4\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Times;} +{\f5\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Helvetica;}{\f6\fmodern\fcharset0\fprq1{\*\panose 00000000000000000000}Courier;}{\f7\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Geneva;} +{\f8\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Tms Rmn;}{\f9\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Helv;}{\f10\froman\fcharset0\fprq2{\*\panose 00000000000000000000}MS Serif;} +{\f11\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}MS Sans Serif;}{\f12\froman\fcharset0\fprq2{\*\panose 00000000000000000000}New York;}{\f13\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}System;} +{\f14\fnil\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings;}{\f15\fswiss\fcharset0\fprq2{\*\panose 020b0604030504040204}Tahoma;}{\f16\froman\fcharset177\fprq2{\*\panose 00000000000000000000}Times New Roman (Hebrew);} +{\f17\froman\fcharset178\fprq2{\*\panose 00000000000000000000}Times New Roman (Arabic);}{\f18\fswiss\fcharset177\fprq2{\*\panose 00000000000000000000}Arial (Hebrew);}{\f19\fswiss\fcharset178\fprq2{\*\panose 00000000000000000000}Arial (Arabic);} +{\f20\fmodern\fcharset177\fprq1{\*\panose 00000000000000000000}Courier New (Hebrew);}{\f21\fmodern\fcharset178\fprq1{\*\panose 00000000000000000000}Courier New (Arabic);}{\f22\fswiss\fcharset177\fprq2{\*\panose 00000000000000000000}Tahoma (Hebrew);} +{\f23\fswiss\fcharset178\fprq2{\*\panose 00000000000000000000}Tahoma (Arabic);}{\f24\froman\fcharset238\fprq2 Times New Roman CE;}{\f25\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f27\froman\fcharset161\fprq2 Times New Roman Greek;} +{\f28\froman\fcharset162\fprq2 Times New Roman Tur;}{\f29\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f30\fswiss\fcharset238\fprq2 Arial CE;}{\f31\fswiss\fcharset204\fprq2 Arial Cyr;}{\f33\fswiss\fcharset161\fprq2 Arial Greek;} +{\f34\fswiss\fcharset162\fprq2 Arial Tur;}{\f35\fswiss\fcharset186\fprq2 Arial Baltic;}{\f36\fmodern\fcharset238\fprq1 Courier New CE;}{\f37\fmodern\fcharset204\fprq1 Courier New Cyr;}{\f39\fmodern\fcharset161\fprq1 Courier New Greek;} +{\f40\fmodern\fcharset162\fprq1 Courier New Tur;}{\f41\fmodern\fcharset186\fprq1 Courier New Baltic;}{\f114\fswiss\fcharset238\fprq2 Tahoma CE;}{\f115\fswiss\fcharset204\fprq2 Tahoma Cyr;}{\f117\fswiss\fcharset161\fprq2 Tahoma Greek;} +{\f118\fswiss\fcharset162\fprq2 Tahoma Tur;}{\f119\fswiss\fcharset186\fprq2 Tahoma Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0; +\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{\widctlpar\adjustright +\fs20\cgrid \snext0 Normal;}{\s1\fi-360\li360\sb240\sa60\keepn\widctlpar\jclisttab\tx360\ls1\outlinelevel0\adjustright \b\f1\fs28\kerning28\cgrid \sbasedon0 \snext0 heading 1;}{\s2\fi-390\li390\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid \sbasedon0 \snext0 heading 2;}{\s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid \sbasedon0 \snext0 heading 3;}{\*\cs10 \additive +Default Paragraph Font;}{\*\cs15 \additive \b \sbasedon10 Strong;}{\s16\widctlpar\adjustright \b\f1\fs20\cgrid \sbasedon0 \snext16 Body Text;}{\s17\li720\widctlpar\adjustright \f1\fs20\cgrid \sbasedon0 \snext17 Body Text 2;}{ +\s18\sb120\widctlpar\adjustright \b\i\cgrid \sbasedon0 \snext0 \sautoupd toc 1;}{\s19\li200\sb120\widctlpar\adjustright \b\fs22\cgrid \sbasedon0 \snext0 \sautoupd toc 2;}{\s20\li400\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 3;}{ +\s21\li600\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 4;}{\s22\li800\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 5;}{\s23\li1000\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 6;}{ +\s24\li1200\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 7;}{\s25\li1400\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 8;}{\s26\li1600\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 9;}{ +\s27\widctlpar\adjustright \cbpat9 \f15\fs20\cgrid \sbasedon0 \snext27 Document Map;}}{\*\listtable{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid22442644}{\list\listtemplateid1593215596{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440 }{\listlevel +\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li2160\jclisttab\tx2160 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0 +{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600 } +{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li4320\jclisttab\tx4320 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360 +\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760 +\jclisttab\tx5760 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li6480\jclisttab\tx6480 }{\listname ;}\listid56512481}{\list\listtemplateid-332364684 +{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\fbias0 \s1\fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0 +\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\fbias0 \s2\fi-390\li390\jclisttab\tx390 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers +\'01\'03\'05;}\fbias0 \s3\fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\fbias0 \fi-1080\li1080 +\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0 +\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0 +\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal +\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\fbias0 \fi-1800\li1800\jclisttab\tx1800 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0 +\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fbias0 \fi-1800\li1800\jclisttab\tx1800 }{\listname ;}\listid155609463}{\list\listtemplateid1706078190\listsimple{\listlevel +\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid602111040}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23 +\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid621424954}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0 +\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid717362522}{\list\listtemplateid67698689\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid1064328194}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1 +\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1080104542}{\list\listtemplateid-5054418{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat2\levelspace0\levelindent0 +{\leveltext\'01\'00;}{\levelnumbers\'01;}\fbias0 \fi-435\li435\jclisttab\tx435 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\fbias0 \fi-435\li435\jclisttab\tx435 } +{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat2\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0 +\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers +\'01\'03\'05\'07\'09\'0b;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\fbias0 +\fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\fbias0 \fi-1440\li1440 +\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fbias0 \fi-1800\li1800\jclisttab\tx1800 +}{\listname ;}\listid1262834005}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname +;}\listid1272592440}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname +;}\listid1339387548}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname +;}\listid1409111490}{\list\listtemplateid1666980492{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listlevel\levelnfc23\leveljc0 +\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li2160\jclisttab\tx2160 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880 } +{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0 +{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li4320\jclisttab\tx4320 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040 +\jclisttab\tx5040 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360 +\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li6480\jclisttab\tx6480 }{\listname ;}\listid1484007768}{\list\listtemplateid230209238{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat3\levelspace0\levelindent0{\leveltext +\'02\'00.;}{\levelnumbers\'01;}\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\fbias0 \fi-360\li360\jclisttab\tx360 } +{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1 +\levellegal\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext +\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext +\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext +\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext +\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext +\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listname ;}\listid1502426668}{\list\listtemplateid355235766{\listlevel\levelnfc23\leveljc0\levelfollow0 +\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 +\fi-360\li1080\jclisttab\tx1080 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li1800\jclisttab\tx1800 }{\listlevel\levelnfc23\leveljc0\levelfollow0 +\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2520\jclisttab\tx2520 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;} +\f2\fbias0 \fi-360\li3240\jclisttab\tx3240 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li3960\jclisttab\tx3960 }{\listlevel\levelnfc23\leveljc0 +\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li4680\jclisttab\tx4680 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5400\jclisttab\tx5400 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li6120\jclisttab\tx6120 }{\listname +;}\listid1523011899}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname +;}\listid1645162521}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname +;}\listid2006126440}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname +;}\listid2076124660}{\list\listtemplateid1666980492{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li720\jclisttab\tx720 }{\listlevel\levelnfc23\leveljc0 +\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li2160\jclisttab\tx2160 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880 } +{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0 +{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li4320\jclisttab\tx4320 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040 +\jclisttab\tx5040 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360 +\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li6480\jclisttab\tx6480 }{\listname ;}\listid2112620548}}{\*\listoverridetable{\listoverride\listid155609463\listoverridecount0\ls1}{\listoverride\listid1409111490 +\listoverridecount0\ls2}{\listoverride\listid1272592440\listoverridecount0\ls3}{\listoverride\listid2076124660\listoverridecount0\ls4}{\listoverride\listid717362522\listoverridecount0\ls5}{\listoverride\listid1339387548\listoverridecount0\ls6} +{\listoverride\listid621424954\listoverridecount0\ls7}{\listoverride\listid1080104542\listoverridecount0\ls8}{\listoverride\listid1262834005\listoverridecount0\ls9}{\listoverride\listid2006126440\listoverridecount0\ls10}{\listoverride\listid602111040 +\listoverridecount0\ls11}{\listoverride\listid22442644\listoverridecount0\ls12}{\listoverride\listid1502426668\listoverridecount0\ls13}{\listoverride\listid1645162521\listoverridecount0\ls14}{\listoverride\listid1064328194\listoverridecount0\ls15} +{\listoverride\listid2112620548\listoverridecount0\ls16}{\listoverride\listid1484007768\listoverridecount0\ls17}{\listoverride\listid1523011899\listoverridecount0\ls18}{\listoverride\listid56512481\listoverridecount0\ls19}}{\info +{\title Writing a Simulator for the SIMH System}{\author Bob Supnik}{\operator Bob Supnik}{\creatim\yr1997\mo8\dy30\hr19}{\revtim\yr2001\mo10\dy20\hr10\min58}{\version29}{\edmins519}{\nofpages19}{\nofwords6533}{\nofchars-32766} +{\*\company Digital Equipment Corporation}{\nofcharsws0}{\vern113}}\widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\formshade\viewkind4\viewscale100\pgbrdrhead\pgbrdrfoot \fet0\sectd +\linex0\endnhere\sectdefaultcl {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4 +\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (} +{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \widctlpar\outlinelevel0\adjustright \fs20\cgrid {\f1 +Writing a Simulator for the SIMH System +\par }\pard \widctlpar\adjustright {\f1 Revised 20-Oct-01 for V2.7-14 \par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 1.\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\adjustright\rin0\lin360\itap0 {\f1 Overview -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par SIMH (history simulators) is a set of portable programs, written in C, which simulate various historically interesting computers. This document describes how to design, write, -and check out a new simulator for SIMH. It is not an introduction to either the philosophy or external operation of SIMH, and the reader should be familiar with both of those topics before proceeding. Nor is it a guide to the internal design or operatio -n - of SIMH, except insofar as those areas interact with simulator design. Instead, this manual presents and explains the form, meaning, and operation of the interfaces between simulators and the SIMH simulator control package. It also offers some suggesti -ons for utilizing the services SIMH offers and explains the constraints that all simulators operating within SIMH will experience. +\par }\pard\plain \s18\sb120\widctlpar\tx400\tqr\tldot\tx8630\adjustright \b\i\cgrid {\field\fldedit{\*\fldinst {\f1 TOC \\o }}{\fldrslt {\lang1024 1.\tab Overview\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228037 \\h }{\fs20\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003500320036003200320038003000330037000000000000001e006f}}}{\fldrslt {\lang1024 1}}}{\lang1024 +\par 2.\tab Data Types\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228038 \\h }{\fs20\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300033003800000000016f00000000}}}{\fldrslt { +\lang1024 2}}}{\lang1024 +\par 3.\tab VM Organization\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228039 \\h }{\fs20\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300033003900000000010000001e00}} +}{\fldrslt {\lang1024 2}}}{\lang1024 +\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 3.1\tab CPU Organization\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228040 \\h }{\fs20\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300034003000000000020100000004}}}{\fldrslt {\lang1024 3}}}{\lang1024 +\par }\pard\plain \s20\li400\widctlpar\tx1200\tqr\tldot\tx8630\adjustright \fs20\cgrid {\lang1024 3.1.1\tab Time Base\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228041 \\h }{\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300034003100000000001e0000001e}}}{\fldrslt {\lang1024 4}}}{\lang1024 +\par 3.1.2\tab Memory Organization\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228042 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300034003200000000000000006f00}} +}{\fldrslt {\lang1024 4}}}{\lang1024 +\par 3.1.3\tab Interrupt Organization\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228043 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f00630035003200360032003200380030003400330000000001fe00000000}} +}{\fldrslt {\lang1024 4}}}{\lang1024 +\par 3.1.4\tab I/O Dispatching\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228044 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300034003400000000000000eb0280}}}{\fldrslt +{\lang1024 5}}}{\lang1024 +\par 3.1.5\tab Instruction Execution\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228045 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003500320036003200320038003000340035000000000080000201ff}} +}{\fldrslt {\lang1024 5}}}{\lang1024 +\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 3.2\tab Peripheral Device Organization\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228046 \\h }{\fs20\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300034003600000000640100006401}}}{\fldrslt {\lang1024 6}}}{\lang1024 +\par }\pard\plain \s20\li400\widctlpar\tx1200\tqr\tldot\tx8630\adjustright \fs20\cgrid {\lang1024 3.2.1\tab Device Timing\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228047 \\h }{\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f00630035003200360032003200380030003400370000000000000001fe00}}}{\fldrslt {\lang1024 7}}}{\lang1024 +\par 3.2.2\tab Clock Calibration\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228048 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003500320036003200320038003000340038000000000000008002e2}} +}{\fldrslt {\lang1024 8}}}{\lang1024 +\par 3.2.3\tab Data I/O\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228049 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300034003900000000000000000000}}}{\fldrslt { +\lang1024 9}}}{\lang1024 +\par }\pard\plain \s18\sb120\widctlpar\tx400\tqr\tldot\tx8630\adjustright \b\i\cgrid {\lang1024 4.\tab Data Structures\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228050 \\h }{\fs20\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003000000000000000000000}}}{\fldrslt {\lang1024 10}}}{\lang1024 +\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 4.1\tab device Structure\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228051 \\h }{\fs20\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003100000000000000000000}}}{\fldrslt {\lang1024 10}}}{\lang1024 +\par }\pard\plain \s20\li400\widctlpar\tx1200\tqr\tldot\tx8630\adjustright \fs20\cgrid {\lang1024 4.1.1\tab Examine and Deposit Routines\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228052 \\h }{\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003200000000000000000000}}}{\fldrslt {\lang1024 11}}}{\lang1024 +\par 4.1.2\tab Reset Routine\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228053 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003300000000000000000000}}}{\fldrslt { +\lang1024 11}}}{\lang1024 +\par 4.1.3\tab Boot Routine\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228054 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003400000000000000000000}}}{\fldrslt { +\lang1024 11}}}{\lang1024 +\par 4.1.4\tab Attach and Detach Routines\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228055 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003500000000000000000000}} +}{\fldrslt {\lang1024 11}}}{\lang1024 +\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 4.2\tab unit Structure\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228056 \\h }{\fs20\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003600000000000000000000}}}{\fldrslt {\lang1024 12}}}{\lang1024 +\par }\pard\plain \s20\li400\widctlpar\tx1200\tqr\tldot\tx8630\adjustright \fs20\cgrid {\lang1024 4.2.1\tab Unit Flags\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228057 \\h }{\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003700000000000000000000}}}{\fldrslt {\lang1024 13}}}{\lang1024 +\par 4.2.2\tab Service Routine\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228058 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003800000000000000000000}}}{\fldrslt +{\lang1024 13}}}{\lang1024 +\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 4.3\tab reg Structure\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228059 \\h }{\fs20\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003900000000000000000000}}}{\fldrslt {\lang1024 13}}}{\lang1024 +\par }\pard\plain \s20\li400\widctlpar\tx1200\tqr\tldot\tx8630\adjustright \fs20\cgrid {\lang1024 4.3.1\tab Register Flags\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228060 \\h }{\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003000000000000000000000}}}{\fldrslt {\lang1024 14}}}{\lang1024 +\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 4.4\tab mtab Structure\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228061 \\h }{\fs20\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003100000000000000000000}}}{\fldrslt {\lang1024 15}}}{\lang1024 +\par }\pard\plain \s20\li400\widctlpar\tx1200\tqr\tldot\tx8630\adjustright \fs20\cgrid {\lang1024 4.4.1\tab Validation/Display Routine\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228062 \\h }{\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003200000000000000000000}}}{\fldrslt {\lang1024 15}}}{\lang1024 +\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 4.5\tab Other Data Structures\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228063 \\h }{\fs20\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003300000000000000000000}}}{\fldrslt {\lang1024 15}}}{\lang1024 +\par }\pard\plain \s18\sb120\widctlpar\tx400\tqr\tldot\tx8630\adjustright \b\i\cgrid {\lang1024 5.\tab VM Provided Routines\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228064 \\h }{\fs20\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003400000000000000000000}}}{\fldrslt {\lang1024 16}}}{\lang1024 +\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 5.1\tab Instruction Execution\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228065 \\h }{\fs20\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003500000000000000000000}}}{\fldrslt {\lang1024 16}}}{\lang1024 +\par 5.2\tab Binary Load and Dump\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228066 \\h }{\fs20\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003600000000000000000000}} +}{\fldrslt {\lang1024 16}}}{\lang1024 +\par 5.3\tab Symbolic Examination and Deposit\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228067 \\h }{\fs20\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003700000000000000000000}}}{\fldrslt {\lang1024 16}}}{\lang1024 +\par 5.4\tab Multi-Terminal Support (Telnet)\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228068 \\h }{\fs20\lang1024 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003800000000000000000000}}}{\fldrslt {\lang1024 17}}}{\lang1024 +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid }}\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 +\par {\*\bkmkstart _Toc526228037}{\listtext\pard\plain\s1 \b\f1\fs28\kerning28\cgrid \hich\af1\dbch\af0\loch\f1 1.\tab}}\pard\plain \s1\fi-360\li360\sb240\sa60\keepn\widctlpar\jclisttab\tx360\ls1\outlinelevel0\adjustright \b\f1\fs28\kerning28\cgrid {Overview +{\*\bkmkend _Toc526228037} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 +\par SIMH (history simulators) is a set of portab +le programs, written in C, which simulate various historically interesting computers. This document describes how to design, write, and check out a new simulator for SIMH. It is not an introduction to either the philosophy or external operation of SIMH, + +and the reader should be familiar with both of those topics before proceeding. Nor is it a guide to the internal design or operation of SIMH, except insofar as those areas interact with simulator design. Instead, this manual presents and explains the fo +r +m, meaning, and operation of the interfaces between simulators and the SIMH simulator control package. It also offers some suggestions for utilizing the services SIMH offers and explains the constraints that all simulators operating within SIMH will expe +rience. \par \par Some terminology: Each simulator consists of a standard }{\i\f1 simulator control package}{\f1 (SCP), which provides a control framework and utility routines for a simulator; and a unique }{\i\f1 virtual machine}{\f1 (VM), which implements the simulated processor and selected peripherals. A VM consists of multiple }{\i\f1 devices}{\f1 , such as the CPU, paper tape reader, disk controller, etc. Each controller consists of a named state space (called }{\i\f1 registers}{\f1 ) and one or more }{\i\f1 units}{\f1 . Each unit consists of a numbered state space (called a }{\i\f1 data set}{\f1 ). }{\i\f1 }{\f1 The }{\i\f1 host computer}{\f1 is the system on which SIMH runs; the }{\i\f1 target computer}{\f1 is the system being simulated. \par -\par SIMH is unabashedly based on the MIMIC simulation system, designed in the late 1960\rquote s by Len Fehskens, Mike McCarthy, and Bob Supnik. This document is based on MIMIC\rquote s published interface specification, \'93 -How to Write a Virtual Machine for the MIMIC Simulation System\'94, by Len Fehskens and Bob Supnik. +\par SIMH is unabashedly based on the MIMIC simulation system, designed in the late 1960\rquote s by Len Fehskens, Mike McCarthy, and Bob Supnik. This document is based on MIMIC\rquote s published interface specification, \ldblquote +How to Write a Virtual Machine for the MIMIC Simulation System\rdblquote , by Len Fehskens and Bob Supnik. \par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 2.\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\adjustright\rin0\lin360\itap0 {\f1 Data Types -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par SIMH is written in C. The host system must support (at least) 32-bit data types (64-bit data types for the PDP-10 and other large-word target systems). To cope with the vagaries of C data types, SIMH defines so -me unambiguous data types for its interfaces: +\par {\*\bkmkstart _Toc526228038}{\listtext\pard\plain\s1 \b\f1\fs28\kerning28\cgrid \hich\af1\dbch\af0\loch\f1 2.\tab}}\pard\plain \s1\fi-360\li360\sb240\sa60\keepn\widctlpar\jclisttab\tx360\ls1\outlinelevel0\adjustright \b\f1\fs28\kerning28\cgrid {Data Types +{\*\bkmkend _Toc526228038} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 +\par SIMH is written in C. The host system must support (at least) 32-bit data types (64-bit data types for the PDP-10 and other large-word target systems). To cope with the vagaries of C data types, SIMH defines some unambiguous data types for its inter +faces: \par \par \tab SIMH data type\tab \tab \tab interpretation in typical 32-bit C \par \par \tab int8, uint8\tab \tab \tab char, unsigned char \par \tab int16, uint16\tab \tab \tab short, unsigned short \par \tab int32, uint32\tab \tab \tab int, unsigned int -\par \tab int64, uint64\tab \tab \tab long long, _int64 (system specific) +\par \tab t_int64, t_uint64\tab \tab \tab long long, _int64 (system specific) \par \tab t_addr\tab \tab \tab \tab simulated address, int32 \par \tab t_value\tab \tab \tab \tab simulated value, unsigned int32 or int64 \par \tab t_svalue\tab \tab \tab simulated signed value, int32 or int64 @@ -140,15 +195,18 @@ me unambiguous data types for its interfaces: \par \tab t_stat\tab \tab \tab \tab status code, int \par \tab t_bool\tab \tab \tab \tab true/false value, int \par -\par In addition, SIMH defines structures for each of its major data elements +\par [The inconsistency in naming t_int64 and t_uint64 is due to VC++, which uses int64 as a structure name member in the master Windows definitions file.] \par +\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 In addition, SIMH defines structures for each of its major data elements +\par }\pard \widctlpar\adjustright {\f1 \par \tab }{\b\f1 DEVICE}{\f1 \tab \tab \tab device definition structure \par \tab }{\b\f1 UNIT}{\f1 \tab \tab \tab \tab unit definition structure \par \tab }{\b\f1 REG}{\f1 \tab \tab \tab \tab register definition structure \par \tab }{\b\f1 MTAB}{\f1 \tab \tab \tab \tab modifier definition structure \par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 3.\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\adjustright\rin0\lin360\itap0 {\f1 VM Organization -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par {\*\bkmkstart _Toc526228039}{\listtext\pard\plain\s1 \b\f1\fs28\kerning28\cgrid \hich\af1\dbch\af0\loch\f1 3.\tab}}\pard\plain \s1\fi-360\li360\sb240\sa60\keepn\widctlpar\jclisttab\tx360\ls1\outlinelevel0\adjustright \b\f1\fs28\kerning28\cgrid { +VM Organization{\*\bkmkend _Toc526228039} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par A virtual machine (VM) is a collection of devices bound together through their internal logic. Each device is named and corresponds more or less to a hunk of hardware on the real machine; for example: \par \par \tab VM device\tab \tab \tab Real machine hardware @@ -159,8 +217,8 @@ me unambiguous data types for its interfaces: \par \tab TTO\tab \tab \tab \tab console output \par \tab DKP\tab \tab \tab \tab disk pack controller and drives \par -\par There may be more than one device per physical hardware entity, as for the console; but for each user- -accessible device there must be at least one. One of these devices will have the pre-eminent responsibility for directing simulated operations. Normally, this is the CPU, but it could be a higher-level entity, such as a bus master. +\par There may be more than one device per physical hardware entity, as for the console; but for each user-accessible device there +must be at least one. One of these devices will have the pre-eminent responsibility for directing simulated operations. Normally, this is the CPU, but it could be a higher-level entity, such as a bus master. \par \par The VM actually runs as a subroutine of the simulator control package (SCP). It provides a master routine for running simulated programs and other routines and data structures to implement SCP\rquote s command and control functions. The interfaces between a VM and SCP are relatively few: @@ -181,52 +239,48 @@ s command and control functions. The interfaces between a VM and SCP are relati \par There is no required organization for VM code. The following convention has been used so far. Let name be the }{\i\f1 name}{\f1 of the real system (i1401 for the IBM 1401; pdp1 for the PDP-1; pdp18b for the other 18-bit PDP\rquote s; pdp8 for the PDP-8; pdp11 for the PDP-11; nova for Nova; hp2100 for the HP 21XX; id4 for the Interdata 4; pdp10 for the PDP-10): \par -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls2\adjustright\rin0\lin720\itap0 { -\i\f1 name}{\f1 .h contains definitions for the particular simulator -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls2\adjustright\rin0\lin720\itap0 { -\i\f1 name}{\f1 _sys.c contains all the SCP interfaces except the instruction simulator -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls2\adjustright\rin0\lin720\itap0 { -\i\f1 name}{\f1 _cpu.c contains the instruction simulator and CPU data structures -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls2\adjustright\rin0\lin720\itap0 { -\i\f1 name}{\f1 _stddev.c contains the peripherals which were standard with the real system. -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls2\adjustright\rin0\lin720\itap0 { -\i\f1 name}{\f1 _lp.c contains the line printer. -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls2\adjustright\rin0\lin720\itap0 { -\i\f1 name}{\f1 _mt.c contains the mag tape controller and drives, etc. -\par }\pard \ql \fi1440\li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 The SIMH standard definitions are in sim_defs.h, the simulator control package in scp.c, and the operating-system dependent routines in scp_tty.c. -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 3.1\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\ilvl1\adjustright\rin0\lin360\itap0 {\f1 CPU Organization -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 +.h contains definitions for the particular simulator +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 +_sys.c contains all the SCP interfaces except the instruction simulator +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 +_cpu.c contains the instruction simulator and CPU data structures +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 +_stddev.c contains the peripherals which were standard with the real system. +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 _lp.c contains th +e line printer. +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 +_mt.c contains the mag tape controller and drives, etc. +\par }\pard \fi1440\widctlpar\adjustright {\f1 +\par }\pard \widctlpar\adjustright {\f1 The SIMH standard definitions are in sim_defs.h, the simulator control package in scp.c, and the operating-system dependent terminal routines in scp_tty.c. Additional librarie +s include sim_tmxr.c (header file sim_tmxr.h) for terminal multiplexors, and sim_sock.c (header file sim_sock.h) for network processing. +\par {\*\bkmkstart _Toc526228040}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 3.1\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {CPU Organization +{\*\bkmkend _Toc526228040} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par Most CPU\rquote s perform at least the following functions: \par -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls3\adjustright\rin0\lin720\itap0 {\f1 -Time keeping -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls3\adjustright\rin0\lin720\itap0 {\f1 -Instruction fetching -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls3\adjustright\rin0\lin720\itap0 {\f1 -Address decoding -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls3\adjustright\rin0\lin720\itap0 {\f1 -Execution of non-I/O instructions -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls3\adjustright\rin0\lin720\itap0 {\f1 -I/O command processing -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls3\adjustright\rin0\lin720\itap0 {\f1 -Interrupt processing -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls3\adjustright {\f1 Time keeping +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls3\adjustright {\f1 Instruction fetching +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls3\adjustright {\f1 Address decoding +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls3\adjustright {\f1 Execution of non-I/O instructions + +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls3\adjustright {\f1 I/O command processing +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls3\adjustright {\f1 Interrupt processing +\par }\pard \widctlpar\adjustright {\f1 \par Instruction execution is actually the least complicated part of the design; memory and I/O organization should be tackled first. -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 3.1.1\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Time Base -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par In order to simulate asynchronous events, such as I/O completion, the VM must define and keep a time base. This can be accurate (for example, nanoseconds of execution) or arbitrary (for exam -ple, number of instructions executed), but it must be consistently used throughout the VM. All existing VM\rquote s count time in instructions. +\par {\*\bkmkstart _Toc526228041}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.1.1\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Time Base{\*\bkmkend _Toc526228041} + +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 +\par In order to simulate asynchronous events, such as I/O completion, the VM must define and keep a time base. This can be accurate (for example, nanoseconds of execution) or arbitrary (for example, number of ins +tructions executed), but it must be consistently used throughout the VM. All existing VM\rquote s count time in instructions. \par \par The CPU is responsible for counting down the event counter }{\b\f1 sim_interval}{\f1 and calling the asynchronous event controller }{\b\f1 sim_process_event}{\f1 . The record keeping for timing is done by SCP. -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 3.1.2\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Memory Organization -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par The criterion for memory layout is very simple: use the SIMH data type that is as large as (or if necessary, larger than), the word length of the real machine. Note t -hat the criterion is word length, not addressability: the PDP-11 has byte addressable memory, but it is a 16-bit machine, and its memory is defined as uint16 M[]. It may seem tempting to define memory as a union of int8 and int16 data types, but this wou -ld make the resulting VM endian-dependent. Instead, the VM should be based on the underlying word size of the real machine, and byte manipulation should be done explicitly. Examples: +\par {\*\bkmkstart _Toc526228042}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.1.2\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Memory Organization +{\*\bkmkend _Toc526228042} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 +\par The criterion for memory layout is very simple: use the SIMH data type that is as large as (or if necessary, larger than), the word length of the real mac +hine. Note that the criterion is word length, not addressability: the PDP-11 has byte addressable memory, but it is a 16-bit machine, and its memory is defined as uint16 M[]. It may seem tempting to define memory as a union of int8 and int16 data types, + but this would make the resulting VM endian-dependent. Instead, the VM should be based on the underlying word size of the real machine, and byte manipulation should be done explicitly. Examples: \par \par \tab Simulator\tab \tab memory size\tab \tab memory declaration \par @@ -235,17 +289,18 @@ ld make the resulting VM endian-dependent. Instead, the VM should be based on t \par \tab PDP-11, Nova\tab \tab 16-bit\tab \tab \tab uint16 \par \tab PDP-1\tab \tab \tab 18-bit\tab \tab \tab uint32 \par \tab PDP-10\tab \tab \tab 36-bit\tab \tab \tab uint64 -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 3.1.3\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Interrupt Organization -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par {\*\bkmkstart _Toc526228043}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.1.3\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Interrupt Organization +{\*\bkmkend _Toc526228043} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par The design of the VM\rquote s interrupt structure is a complex interaction between efficiency and fidelity to the hardware. If the VM\rquote -s interrupt structure is too abstract, interrupt driven software may not run. On the other hand, if it follows the hardware too literally, it may significantly reduce simulation speed. One rule I can offer is to minimize the fetch-phase cost of interr -upts, even if this complicates the (much less frequent) evaluation of the interrupt system following an I/O operation or asynchronous event. Another is not to over-generalize; even if the real hardware could support 64 or 256 interrupting devices, the si -mulators will be running much smaller configurations. I\rquote ll start with a simple interrupt structure and then offer suggestions for generalization. +s interrupt structure is too abstract, interrupt driven software may not run. On the other hand, if it follows the hardware too literally, it may si +gnificantly reduce simulation speed. One rule I can offer is to minimize the fetch-phase cost of interrupts, even if this complicates the (much less frequent) evaluation of the interrupt system following an I/O operation or asynchronous event. Another i +s not to over-generalize; even if the real hardware could support 64 or 256 interrupting devices, the simulators will be running much smaller configurations. I\rquote +ll start with a simple interrupt structure and then offer suggestions for generalization. \par -\par In the simplest structure, interrupt requests correspond to device flags and are kept in an interrupt request - variable, with one flag per bit. The fetch-phase evaluation of interrupts consists of two steps: are interrupts enabled, and is there an interrupt outstanding? If all the interrupt requests are kept as single-bit flags in a variable, the fetch-phase te -st is very fast: +\par In th +e simplest structure, interrupt requests correspond to device flags and are kept in an interrupt request variable, with one flag per bit. The fetch-phase evaluation of interrupts consists of two steps: are interrupts enabled, and is there an interrupt ou +tstanding? If all the interrupt requests are kept as single-bit flags in a variable, the fetch-phase test is very fast: \par \par \tab if (int_enable && int_requests) \{ \'85process interrupt\'85 \} \par @@ -258,95 +313,90 @@ st is very fast: \par \tab set: \tab int_requests = int_requests | DEVICE_FLAG; \par \tab clear:\tab int_requests = int_requests & ~DEVICE_FLAG; \par -\par At a slightly higher complexity, interrupt requests d -o not correspond directly to device flags but are based on masking the device flags with an enable (or disable) mask. There are now three parallel variables: interrupt requests, device flags, and interrupt enable mask. The fetch-phase test does not chan -ge; however, the evaluation of whether an interrupt is pending now requires an extra step: +\par At a slightly higher complexity, interrupt requests do not correspond directly to device flags but are based on masking the device flags with an enable (or disable) mask. There are now three parallel vari +ables: interrupt requests, device flags, and interrupt enable mask. The fetch-phase test does not change; however, the evaluation of whether an interrupt is pending now requires an extra step: \par \par \tab enable:\tab int_requests = device_flags & int_enables; \par \tab disable:\tab int_requests = device_flags & ~int_disables; \par -\par If required for interrupt processing, the highest priorit -y interrupting device can be determined by scanning the interrupt request variable from high priority to low until a set bit is found. The bit position can then be back-mapped through a table to determine the address or interrupt vector of the interrupti -ng device. +\par If required for interrupt processing, the highest priority interrupting device can be determined by scanning the interrupt request variable from high priority to low until a set bit is found. The bit position + can then be back-mapped through a table to determine the address or interrupt vector of the interrupting device. \par -\par At yet higher complexity, the interrupt system may be too complex or too large to evaluate during the fetch-phase. In this case, an interrupt pending flag is created, and it is evaluated by subroutine call whenever a change could occur (start o -f execution, I/O instruction issued, device time out occurs). This makes fetch-phase evaluation simple and isolates interrupt evaluation to a common subroutine. -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 3.1.4\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 I/O Dispatching -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par At yet higher complexity, the interrupt system may be too complex or too large to evaluate during the fetch-phase. In this case, an interrup +t pending flag is created, and it is evaluated by subroutine call whenever a change could occur (start of execution, I/O instruction issued, device time out occurs). This makes fetch-phase evaluation simple and isolates interrupt evaluation to a common s +ubroutine. +\par {\*\bkmkstart _Toc526228044}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.1.4\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {I/O Dispatching +{\*\bkmkend _Toc526228044} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par I/O dispatching consists of four steps: \par -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls14\adjustright\rin0\lin720\itap0 { -\f1 Identify the I/O command and analyze for the device address. -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls14\adjustright\rin0\lin720\itap0 { -\f1 Locate the selected device. -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls14\adjustright\rin0\lin720\itap0 { -\f1 Break down the I/O command into standard fields. -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls14\adjustright\rin0\lin720\itap0 { -\f1 Call the device processor. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par Analyzing an I/O command is usually easy. Most systems have one or more explicit I/O instructions containing an I/O command -and a device address. Memory mapped I/O is more complicated; the identification of a reference to I/O space becomes part of memory addressing. This usually requires centralizing memory reads and writes into subroutines, rather than as inline code. +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls14\adjustright {\f1 +Identify the I/O command and analyze for the device address. +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls14\adjustright {\f1 Locate the selected device. +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls14\adjustright {\f1 +Break down the I/O command into standard fields. +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls14\adjustright {\f1 Call the device processor. +\par }\pard \widctlpar\adjustright {\f1 +\par Analyzing an I/O command is usually easy. Most systems have one or more explicit I/O instructions containing an I/O command and a device address. Memory mapped I/O is more complicated; the identification of a reference to I/O +space becomes part of memory addressing. This usually requires centralizing memory reads and writes into subroutines, rather than as inline code. \par -\par Once -an I/O command has been analyzed, the CPU must locate the device subroutine. The simplest way is a large switch statement with hardwired subroutine calls. Slightly more modular is to call through a dispatch table, with NULL entries representing non-exis -tent devices. Before calling the device routine, the CPU usually breaks down the I/O command into standard fields. This simplifies writing the peripheral simulator. -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 3.1.5\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Instruction Execution -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par Once an I/O command has been analyzed, the CPU must locate the device subroutine. The simplest way is a lar +ge switch statement with hardwired subroutine calls. Slightly more modular is to call through a dispatch table, with NULL entries representing non-existent devices. Before calling the device routine, the CPU usually breaks down the I/O command into stan +dard fields. This simplifies writing the peripheral simulator. +\par {\*\bkmkstart _Toc526228045}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.1.5\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Instruction Execution +{\*\bkmkend _Toc526228045} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par Instruction execution is the responsibility of VM subroutine }{\b\f1 sim_instr}{\f1 . It is called from SCP as a result of a RUN, GO, CONT, or BOOT command. It begins executing instructions at the current PC (}{\b\f1 sim_PC}{\f1 points to its register description block) and continues until halted by an error or an external event. \par -\par When called, t -he CPU needs to account for any state changes that the user made. For example, it may need to re-evaluate whether an interrupt is pending, or restore frequently used state to local register variables for efficiency. The actual instruction fetch and exec -ute cycle is usually structured as a loop controlled by an error variable, e.g., +\par When called, the CPU needs to account for any state changes that the user made. For e +xample, it may need to re-evaluate whether an interrupt is pending, or restore frequently used state to local register variables for efficiency. The actual instruction fetch and execute cycle is usually structured as a loop controlled by an error variabl +e, e.g., \par \par \tab reason = 0; \par \tab do \{ \'85 \} while (reason == 0);\tab or\tab while (reason == 0) \{ \'85 \} \par \par Within this loop, the usual order of events is: \par -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls4\adjustright\rin0\lin720\itap0 {\f1 -If the event timer }{\b\f1 sim_interval}{\f1 has reached zero, process any timed events. This is done by SCP subroutine }{\b\f1 sim_process_event}{\f1 -. Because this is the polling mechanism for user-generated processor halts (^E), errors must be recognized immediately: -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par }\pard \ql \li1440\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin1440\itap0 {\f1 if (sim_interval <= 0) \{ -\par }\pard \ql \fi720\li1440\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin1440\itap0 {\f1 if (reason = sim_process_event ()) break; \} -\par }\pard \ql \fi2160\li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls4\adjustright\rin0\lin720\itap0 {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls4\adjustright {\f1 If the event timer }{\b\f1 +sim_interval}{\f1 has reached zero, process any timed events. This is done by SCP subroutine }{\b\f1 sim_process_event}{\f1 . Because this is the polling mechanism for user-generated processor halts (^E), errors must be recognized immediately: +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par }\pard \li1440\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 if (sim_interval <= 0) \{ +\par }\pard \fi720\li1440\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 if (reason = sim_process_event ()) break; \} +\par }\pard \fi2160\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls4\adjustright {\f1 Check for outstanding interrupts and process if required. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls4\adjustright\rin0\lin720\itap0 {\f1 +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls4\adjustright {\f1 Check for other processor-unique events, such as wait-state outstanding or traps outstanding. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls4\adjustright\rin0\lin720\itap0 {\f1 +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls4\adjustright {\f1 Check for an instruction breakpoint. SCP has no breakpoint facility, but it is customary to implement a single instruction breakpoint to help with processor code. All the existing CPU\rquote s use the same mechanism, see the sources for details. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls4\adjustright\rin0\lin720\itap0 {\f1 -Fetch the next instruction, increment the PC, optionally decode the address, and dispatch (via a switch statement) for execution. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls4\adjustright {\f1 Fetch the n +ext instruction, increment the PC, optionally decode the address, and dispatch (via a switch statement) for execution. +\par }\pard \widctlpar\adjustright {\f1 \par A few guidelines for implementation: \par -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls5\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls5\adjustright\rin0\lin720\itap0 {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls5\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls5\adjustright {\f1 In general, code should reflect the hardware being simulated. This is usually simplest and easiest to debug. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls5\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls5\adjustright\rin0\lin720\itap0 {\f1 -The VM should provide some debugging aids. The existing CPU\rquote s all provide an instruction breakpoint, an OLDPC register, and error stops on invalid instructions or operations. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 3.2\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\ilvl1\adjustright\rin0\lin360\itap0 {\f1 Peripheral Device Organization -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par The basic elements of a VM are devices, each corresponding roughly to a real chunk of hardware. A device consists of register-b -ased state and one or more units. Thus, a multi-drive disk subsystem is a single device (representing the hardware of the real controller) and one or more units (each representing a single disk drive). Sometimes the device and its unit are the same enti -ty as, for example, in the case of a paper tape reader. However, a single physical device, such as the console, may be broken up for convenience into separate input and output devices. +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls5\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls5\adjustright {\f1 +The VM should provide some debugging aids. The existing CPU\rquote s all provide an instruction breakpoint, an OLDPC register, and error stops on invalid instructions or operations. +\par {\*\bkmkstart _Toc526228046}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 3.2\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid { +Peripheral Device Organization{\*\bkmkend _Toc526228046} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 +\par The basic elements of a VM are devices, each corresponding roughly to a real chunk of hardware. A device consists of register-based state and one or more units. Thus, a multi-drive disk subsystem is a single device (representing the hardware of the real + controller) and one or more units (each representing a single disk drive). Sometimes the device and its unit are the same entity as, for example, in the case of a paper tape reader. However, a single physical device, such as the console, may be broken +up for convenience into separate input and output devices. \par -\par In general, units correspond to individual sources of input or output -(one tape transport, one A-to-D channel). Units are the basic medium for both device timing and device I/O. Except for the console, all I/O devices are simulated as host-resident files. SCP allows the user to make an explicit association between a host --resident file and a simulated hardware entity. +\par In general, units correspond to individual sources of input or output (one tape transport, one A-to-D channel). Units are the basic medium for both device timing and device I/O. Except for the co +nsole, all I/O devices are simulated as host-resident files. SCP allows the user to make an explicit association between a host-resident file and a simulated hardware entity. \par -\par Both devices and units have state. Devices operate on }{\i\f1 registers}{\f1 , which contain information about the state of the device, and indirectly, about the state of the units. Units operate on }{\i\f1 data sets}{\f1 , which may -be thought of as individual instances of input or output, such as a disk pack or a punched paper tape. In a typical multi-unit device, all units are the same, and the device performs similar operations on all of them, depending on which one has been sele -cted by the program being simulated. +\par Both devices and units have state. Devices operate on }{\i\f1 registers}{\f1 , which contain information about the state of the device, and indirectly, about the state of the units. Units operate on }{\i\f1 data sets}{\f1 +, which may be thought of as individual instances of input or output, such as a disk pack or a punched paper tape. In a typical multi-unit + device, all units are the same, and the device performs similar operations on all of them, depending on which one has been selected by the program being simulated. \par \par (Note: SIMH, like MIMIC, restricts registers to devices. This requires replicated registers, for example, disk drive current state, to have unique names in the device name space.) \par @@ -355,23 +405,21 @@ cted by the program being simulated. \par \par The primary functions of a peripheral are: \par -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls6\adjustright\rin0\lin720\itap0 {\f1 -command decoding and execution -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls6\adjustright\rin0\lin720\itap0 {\f1 -device timing -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls6\adjustright\rin0\lin720\itap0 {\f1 -data transmission. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par Command decoding is fairly obvious. At least one section of the peripheral code module will be devoted to processing directives issued by the CPU. Typically, the command decoder will -be responsible for register and flag manipulation, and for issuing or canceling I/O requests. The former is easy, but the later requires a thorough understanding of device timing. -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 3.2.1\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Device Timing -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par The principal problem in I/O device simulation is imitating - asynchronous operations in a sequential simulation environment. Fortunately, the timing characteristics of most I/O devices do not vary with external circumstances. The distinction between devices whose timing is externally generated (e.g., console key -b -oard) and those whose timing is externally generated (disk, paper tape reader) is crucial. With an externally timed device, there is no way to know when an in-progress operation will begin or end; with an internally timed device, given the time when an o -peration starts, the end time can be calculated. +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls6\adjustright {\f1 command decoding and execution + +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls6\adjustright {\f1 device timing +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls6\adjustright {\f1 data transmission. +\par }\pard \widctlpar\adjustright {\f1 +\par Command decoding is fairly obvious. At least one section of the peripheral code module will be devoted to processing directives issued by the CPU. Typically, the command decoder will be responsible for register and flag manipulation, and for issuing or +canceling I/O requests. The former is easy, but the later requires a thorough understanding of device timing. +\par {\*\bkmkstart _Toc526228047}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.2.1\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Device Timing +{\*\bkmkend _Toc526228047} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 +\par The principal problem in I/O device simulation is imitating asynchronous operations in a sequential + simulation environment. Fortunately, the timing characteristics of most I/O devices do not vary with external circumstances. The distinction between devices whose timing is externally generated (e.g., console keyboard) and those whose timing is externa +l +ly generated (disk, paper tape reader) is crucial. With an externally timed device, there is no way to know when an in-progress operation will begin or end; with an internally timed device, given the time when an operation starts, the end time can be cal +culated. \par \par For an internally timed device, the elapsed time between the start and conclusion of an operation is called the wait time. Some typical internally timed devices and their wait times include: \par @@ -382,48 +430,51 @@ peration starts, the end time can be calculated. \par \par Mass storage devices, such as disks and tapes, do not have a fixed response time, but a start-to-finish time can be calculated based on current versus desired position, state of motion, etc. \par -\par For an externally timed device, there is no portable mechanism by which a VM can be notified of an external event. Because the only important externally timed device is the console keyboard, all current VM\rquote s poll -for keyboard input, thus converting the externally timed keyboard to a pseudo-internally timed device. +\par For an externally timed device, there is no portable mechanism by which a VM can be notified of an external event. Because the only important externally timed device is the console keyboard, all current VM\rquote +s poll for keyboard input, thus converting the externally timed keyboard to a pseudo-internally timed device. \par \par SCP provides the supporting routines for device timing. SCP maintains a list of devices (called }{\i\f1 active devices}{\f1 ) which are in the process of timing out. It also provides routines for querying or manipulating this list (called the }{\i\f1 active queue}{\f1 ). Lastly, it provides a routine for checking for timed-out units and executing a VM-specified action when a time-out occurs. \par -\par Device timing is done with the UNIT s -tructure, described in section 3. To set up a timed operation, the peripheral calculates a waiting period for a unit and places that unit on the active queue. The CPU counts down the waiting period. When the waiting period has expired, }{\b\f1 -sim_process_event}{\f1 removes the unit from the active queue and calls a device subroutine. A device may also cancel an outstanding timed operation and query the state of the queue. The timing subroutines are: +\par Device timing is done with the UNIT structure, described in section 3. To se +t up a timed operation, the peripheral calculates a waiting period for a unit and places that unit on the active queue. The CPU counts down the waiting period. When the waiting period has expired, }{\b\f1 sim_process_event}{\f1 + removes the unit from the active queue and calls a device subroutine. A device may also cancel an outstanding timed operation and query the state of the queue. The timing subroutines are: \par -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\f1 -t_stat }{\b\f1 sim_activate}{\f1 (UNIT *uptr, int32 wait). This routine plac -es the specified unit on the active queue with the specified waiting period. A waiting period of 0 is legal; negative waits cause an error. If the unit is already active, the active queue is not changed, and no error occurs. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\f1 -t_stat }{\b\f1 sim_cancel}{\f1 (UNIT *uptr). This routine removes the specified unit from the active queue. If the unit is not on the queue, no error occurs. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\f1 -int32 }{\b\f1 sim_is_active}{\f1 (UNIT *uptr). This routine tests whether a unit is in the active queue. If it is, the routine returns the time (+1) remaining; if it is not, the routine returns 0. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\f1 -double }{\b\f1 sim_gtime}{\f1 (void). This routine returns the time elapsed since the last RUN or BOOT command. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\f1 -uint32 }{\b\f1 sim_grtime}{\f1 (void). This routine returns the low-order 32b of the time elapsed since the last RUN or BOOT command. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\f1 -t_stat }{\b\f1 sim_process_event}{\f1 (void). This routine removes all timed out units from the active queue and calls the appropriate device subroutine to service the time-out. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\f1 -int32 }{\b\f1 sim_interval}{\f1 . This variable counts down the first outstanding timed event. If there are no timed events outstanding, SCP counts down a \'93null interval\'94 of 10,000 time units. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 3.2.2\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Clock Calibration -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 t_stat }{\b\f1 sim_activate}{\f1 + (UNIT *uptr, int32 wait). This routine places the specified unit on the active q +ueue with the specified waiting period. A waiting period of 0 is legal; negative waits cause an error. If the unit is already active, the active queue is not changed, and no error occurs. +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 t_stat }{\b\f1 sim_cancel}{\f1 + (UNIT *uptr). This routine removes the specified unit from the active queue. If the unit is not on the queue, no error occurs. +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 int32 }{\b\f1 sim_is_active}{\f1 + (UNIT *uptr). This routine tests whether a unit is in the active queue. If it is, the routine returns the time (+1) remaining; if it is not, the routine returns 0. +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 double }{\b\f1 sim_gtime}{\f1 + (void). This routine returns the time elapsed since the last RUN or BOOT command. +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 uint32 }{\b\f1 sim_grtime}{\f1 + (void). This routine returns the low-order 32b of the time elapsed since the last RUN or BOOT command. +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 int32 }{\b\f1 sim_qcount}{\f1 + (void). This routine returns the number of entries on the clock queue. +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 t_stat }{\b\f1 sim_process_event}{ +\f1 (void). This routine removes all timed out units from the active queue and calls the appropriate device subroutine to service the time-out. +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 int32 }{\b\f1 sim_interval}{\f1 +. This variable counts down the first outstanding timed event. If there are no timed events outstanding, SCP counts down a \ldblquote null interval\rdblquote of 10,000 time units. +\par {\*\bkmkstart _Toc526228048}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.2.2\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Clock Calibration +{\*\bkmkend _Toc526228048} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par The timing mechanism described in the previous section is approximate. Devices, such as real-time clocks, which track wall time will be inaccurate. SCP provides routines to synchronize a simulated real-time clock to wall time. \par -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360{\*\pn \pnlvlblt\ilvl0\ls15\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls15\adjustright\rin0\lin360\itap0 { -\f1 int32 }{\b\f1 sim_rtc_init}{\f1 (int32 clock_interval). This routine initializes the clock calibration mechanism. The argument is returned as the result. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360{\*\pn \pnlvlblt\ilvl0\ls15\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls15\adjustright\rin0\lin360\itap0 { -\f1 int32 }{\b\f1 sim_rtc_calb}{\f1 (int32 tickspersecond). This routine calibrates the real-time clock. The argument is the number of clock ticks expected per second. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360{\*\pn \pnlvlblt\ilvl0\ls15\pnrnot0\pnf3\pnstart1\pnindent360\pnhang{\pntxtb \'b7}}\ls15\adjustright {\f1 int32 }{\b\f1 sim_rtc_init}{\f1 + (int32 clock_interval). This routine initializes the clock calibration mechanism. The argument is returned as the result. +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360{\*\pn \pnlvlblt\ilvl0\ls15\pnrnot0\pnf3\pnstart1\pnindent360\pnhang{\pntxtb \'b7}}\ls15\adjustright {\f1 int32 }{\b\f1 sim_rtc_calb}{\f1 + (int32 tickspersecond). This routine calibrates the real-time clock. The argument is the number of clock ticks expected per second. +\par }\pard \widctlpar\adjustright {\f1 \par The simulator calls }{\b\f1 sim_rtc_init}{\f1 in the prolog of }{\b\f1 sim_instr}{\f1 , before instruction execution starts, and whenever the real-time clock is started. The simulator calls }{\b\f1 sim_rtc_calb}{\f1 to calculate the actual interval delay when the real-time clock is serviced: \par @@ -435,66 +486,65 @@ int32 }{\b\f1 sim_interval}{\f1 . This variable counts down the first outstandi \par \tab /* clock service */ \par \par \tab sim_activate (&clk_unit, sim_rtc_calb (clk_ticks_per_second); -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 3.2.3\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Data I/O -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par For most devices, timing is half the battle (for clocks it is the entire war); the other half is I/O. Except for the console, all I/O devices are simulated a -s files on the host file system in little-endian format. SCP provides facilities for associating files with units (ATTACH command) and for reading and writing data from and to devices in a endian- and size-independent way. +\par {\*\bkmkstart _Toc526228049}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.2.3\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Data I/O{\*\bkmkend _Toc526228049} + +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 +\par For most devices, timing is half the battle (for clocks it is the entire war); the other half is I/O. Except for the console, all I/O devices are simulated as files on the host file system in little-endian format. SCP provides facilities for associating + files with units (ATTACH command) and for reading and writing data from and to devices in a endian- and size-independent way. \par \par For most devices, the VM designer does not have to be concerned about the formatting of simulated device files. I/O occurs in 1, 2, or 4 byte quantities; SCP automatically chooses the correct data size and corrects for byte ordering. Specific issues: \par -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls8\adjustright\rin0\lin720\itap0 {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1 Line printers should write data as 7-bit ASCII, with newlines replacing carriage-return/line-feed sequences. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls8\adjustright\rin0\lin720\itap0 {\f1 -Disks should be viewed as linear data sets, from sector 0 of surface 0 of cylinder 0 to the last sector on the disk. This allows easy transcription of real disks to files usable by the simulator. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls8\adjustright\rin0\lin720\itap0 {\f1 -Magtapes, by convention, use a record based format. Each record consists of a leading 32-bit record length, the record data (padded with a byte of 0 if the record length is odd), and a trailing 32-bit record length. File marks are reco -rded as one record length of 0. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls8\adjustright\rin0\lin720\itap0 {\f1 +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1 Disks should be + viewed as linear data sets, from sector 0 of surface 0 of cylinder 0 to the last sector on the disk. This allows easy transcription of real disks to files usable by the simulator. +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1 +Magtapes, by convention, use a record based format. Each record consi +sts of a leading 32-bit record length, the record data (padded with a byte of 0 if the record length is odd), and a trailing 32-bit record length. File marks are recorded as one record length of 0. +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1 Cards have 12 bits of data per column, but the data is most conveniently viewed as (ASCII) characters. Existing card reader simulators do not support binary operation. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par Data I/O varies between fixed and variable capacity d -evices, and between buffered and non-buffered devices. A fixed capacity device differs from a variable capacity device in that the file attached to the former has a maximum size, while the file attached to the latter may expand indefinitely. A buffered -d -evice differs from a non-buffered device in that the former buffers its data set in host memory, while the latter maintains it as a file. Most variable capacity devices (such as the paper tape reader and punch) are sequential; all buffered devices are fi -xed capacity. +\par }\pard \widctlpar\adjustright {\f1 +\par Data I/O varies between fixed and variable capacity devices, and between buffered and non-buffered devices. A fixed capacity device differ +s from a variable capacity device in that the file attached to the former has a maximum size, while the file attached to the latter may expand indefinitely. A buffered device differs from a non-buffered device in that the former buffers its data set in h +ost memory, while the latter maintains it as a file. Most variable capacity devices (such as the paper tape reader and punch) are sequential; all buffered devices are fixed capacity. \par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 3.2.3.1\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl3\adjustright\rin0\lin720\itap0 {\f1 Reading and Writing Data -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par The ATTACH command creates an association between a host file and an I/O unit. For non-buffered devices, ATTACH stores the file pointer for the host file in the }{\b\f1 fileref}{\f1 field of the UNIT structure. For buffered dev -ices, ATTACH reads the entire host file into an allocated buffer pointed to by the }{\b\f1 filebuf }{\f1 field of the UNIT structure. +\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2.3.1\tab}}\pard \fi-1080\li1080\widctlpar\jclisttab\tx1080\ls1\ilvl3\adjustright {\f1 Reading and Writing Data +\par }\pard \widctlpar\adjustright {\f1 +\par The ATTACH command creates an association between a host file and an I/O unit. For non-buffered devices, ATTACH stores the file pointer for the host file in the }{\b\f1 fileref}{\f1 + field of the UNIT structure. For buffered devices, ATTACH reads the entire host file into an allocated buffer pointed to by the }{\b\f1 filebuf }{\f1 field of the UNIT structure. \par -\par For non-buffered devices, I/O is done with standard C subroutines plus the SCP routines }{\b\f1 fxread}{\f1 and }{\b\f1 fxwrite}{\f1 . }{\b\f1 fxread}{\f1 and }{\b\f1 fxwrite}{\f1 are ide -ntical in calling sequence and function to fread and fwrite, respectively, but will correct for endian dependencies. For buffered devices, I/O is done by copying data to or from the allocated buffer. The device code must maintain the number (+1) of the -highest address modified in the }{\b\f1 hwmark}{\f1 field of the UNIT structure. For both the non-buffered and buffered cases, the device must perform all address calculations and positioning operations. +\par For non-buffered devices, I/O is done with standard C subroutines plus the SCP routines }{\b\f1 fxread}{\f1 and }{\b\f1 fxwrite}{\f1 . }{\b\f1 fxread}{\f1 and }{\b\f1 fxwrite}{\f1 + are identical in calling sequence and function to fread and fwrite, respectively, but + will correct for endian dependencies. For buffered devices, I/O is done by copying data to or from the allocated buffer. The device code must maintain the number (+1) of the highest address modified in the }{\b\f1 hwmark}{\f1 + field of the UNIT structure. For both the non-buffered and buffered cases, the device must perform all address calculations and positioning operations. \par \par The DETACH command breaks the association between a host file and an I/O unit. For buffered devices, DETACH writes the allocated buffer back to the host file. \par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 3.2.3.2\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl3\adjustright\rin0\lin720\itap0 {\f1 Console I/O -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par SCP provides two routines for console I/O. -\par -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls10\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls10\adjustright\rin0\lin720\itap0 { -\f1 t_stat }{\b\f1 sim_poll_char }{\f1 (void). This routine polls for keyboard input. If there is a character, it retu -rns SCPE_KFLAG + the character. If the user typed the interrupt character (^E), it returns SCPE_STOP. If there is no input, it returns SCPE_OK. -\par }\pard \ql \li0\ri0\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls10\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}}\faauto\ls10\adjustright\rin0\lin720\itap0 { -\f1 t_stat }{\b\f1 sim_putchar}{\f1 (int32 char). This routine types the specified ASCII character on the console. There are no errors. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\adjustright\rin0\lin360\itap0 {\f1 Data Structures -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2.3.2\tab}}\pard \fi-1080\li1080\widctlpar\jclisttab\tx1080\ls1\ilvl3\adjustright {\f1 Console I/O +\par }\pard \widctlpar\adjustright {\f1 +\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 SCP provides two routines for console I/O. +\par }\pard \widctlpar\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls10\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls10\adjustright {\f1 t_stat }{\b\f1 sim_poll_char }{ +\f1 (void). This routine polls for keyboard input. If there is a character, it returns SCPE_KFLAG + the character. If the user typed the interrupt character (^E), it returns SCPE_STOP. If there is no input, it returns SCPE_OK. +\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 +\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls10\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls10\adjustright {\f1 t_stat }{\b\f1 sim_putchar}{\f1 + (int32 char). This routine types the specified ASCII character on the console. There are no errors. +\par }\pard \widctlpar\adjustright {\f1 +\par {\*\bkmkstart _Toc526228050}{\listtext\pard\plain\s1 \b\f1\fs28\kerning28\cgrid \hich\af1\dbch\af0\loch\f1 4.\tab}}\pard\plain \s1\fi-360\li360\sb240\sa60\keepn\widctlpar\jclisttab\tx360\ls1\outlinelevel0\adjustright \b\f1\fs28\kerning28\cgrid { +Data Structures{\*\bkmkend _Toc526228050} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par The devices, units, and registers which make up a VM are formally described through a set of data structures which interface the VM to the control portions of SCP. The devices themselves are pointed to by the device list array }{\b\f1 sim_devices[]}{\f1 . Within a device, both units and registers are allocated contiguously as arrays of structures. In addition, many devices allow the user to set or clear options via a modifications table. +\par {\*\bkmkstart _Toc526228051}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 4.1\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {device Structure +{\*\bkmkend _Toc526228051} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 +\par Devices are defined by the }{\b\f1 device}{\f1 structure (typedef }{\b\f1 DEVICE}{\f1 ): \par -\par {\listtext\pard\plain\b\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.1\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\ilvl1\adjustright\rin0\lin360\itap0 {\b\f1 device}{\f1 Structure -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par Devices are defined by the }{\b\f1 device}{\f1 structure (typedef }{\b\f1 DEVICE}{\f1 ), which has the following fields: -\par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 struct device \{ +\par }\pard \li720\widctlpar\adjustright {\f1 struct device \{ \par \tab char\tab \tab *name;\tab \tab \tab \tab /* name */ \par \tab struct unit \tab *units;\tab \tab \tab \tab /* units */ \par \tab struct reg\tab *registers;\tab \tab \tab /* registers */ @@ -512,18 +562,18 @@ rns SCPE_KFLAG + the character. If the user typed the interrupt character (^E), \par \tab t_stat\tab \tab (*attach)();\tab \tab \tab /* attach routine */ \par \tab t_stat\tab \tab (*detach)();\tab \tab \tab /* detach routine */ \par \}; -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par }\pard \widctlpar\adjustright {\f1 \par The fields are the following: \par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\b\f1 name}{\f1 \tab \tab device name, string of all capital alphanumeric characters. +\par }\pard \li720\widctlpar\adjustright {\b\f1 name}{\f1 \tab \tab device name, string of all capital alphanumeric characters. \par }{\b\f1 units}{\f1 \tab \tab pointer to array of }{\b\f1 unit}{\f1 structures, or NULL if none. \par }{\b\f1 registers}{\f1 \tab pointer to array of }{\b\f1 reg}{\f1 structures, or NULL if none. \par }{\b\f1 modifiers}{\f1 \tab pointer to array of }{\b\f1 mtab}{\f1 structures, or NULL if none. \par }{\b\f1 numunits}{\f1 \tab number of units in this device. \par }{\b\f1 aradix}{\f1 \tab \tab radix for input and display of device addresses, 2 to 16 inclusive. \par }{\b\f1 awidth}{\f1 \tab \tab width in bits of a device address, 1 to 31 inclusive. -\par }\pard \ql \fi-1440\li2160\ri0\widctlpar\faauto\adjustright\rin0\lin2160\itap0 {\b\f1 aincr}{\f1 \tab increment between device addresses, normally 1; however, byte addressed devices with 16-bit words specify 2, with 32-bit words 4. -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\b\f1 dradix}{\f1 \tab \tab radix for input and display of device data, 2 to 16 inclusive. +\par }\pard \fi-1440\li2160\widctlpar\adjustright {\b\f1 aincr}{\f1 \tab increment between device addresses, normally 1; however, byte addressed devices with 16-bit words specify 2, with 32-bit words 4. +\par }\pard \li720\widctlpar\adjustright {\b\f1 dradix}{\f1 \tab \tab radix for input and display of device data, 2 to 16 inclusive. \par }{\b\f1 dwidth}{\f1 \tab \tab width in bits of device data, 1 to 32 inclusive. \par }{\b\f1 examine}{\f1 \tab address of special device data read routine, or NULL if none is required. \par }{\b\f1 deposit}{\f1 \tab \tab address of special device data write routine, or NULL if none is required. @@ -531,61 +581,65 @@ rns SCPE_KFLAG + the character. If the user typed the interrupt character (^E), \par }{\b\f1 boot}{\f1 \tab \tab address of device bootstrap routine, or NULL if none is required. \par }{\b\f1 attach}{\f1 \tab \tab address of special device attach routine, or NULL if none is required. \par }{\b\f1 detach}{\f1 \tab \tab address of special device detach routine, or NULL if none is required. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.1.1\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Examine and Deposit Routines -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par For devices which maintain their data sets as host files, SCP implements the examine and deposit data functions. - However, devices which maintain their data sets as private state (typically just the CPU) must supply special examine and deposit routines. The calling sequences are: +\par {\*\bkmkstart _Toc526228052}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.1.1\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Examine and Deposit Routines +{\*\bkmkend _Toc526228052} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 +\par For devices which maintain their data sets as host files, SCP implements the examine and deposit data functions. However, devices which maintain their data sets as private state (typically just the C +PU) must supply special examine and deposit routines. The calling sequences are: \par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 t_stat }{\i\f1 examine_routine}{\f1 (t_val *eval_array, t_addr addr, UNIT *uptr, int32 switches) \endash Copy }{\b\f1 sim_emax}{\f1 consecutive addresses for unit }{\i\f1 uptr}{ -\f1 , starting at }{\i\f1 addr}{\f1 , into }{\i\f1 eval_array}{\f1 . The }{\i\f1 switch}{\f1 variable has bit set if the n\rquote th letter was specified as a switch to the examine command. +\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\i\f1 examine_routine}{\f1 (t_val *eval_array, t_addr addr, UNIT *uptr, int32 switches) \endash Copy }{\b\f1 sim_emax}{\f1 consecutive addresses for unit }{\i\f1 uptr}{\f1 , starting at }{\i\f1 addr}{ +\f1 , into }{\i\f1 eval_array}{\f1 . The }{\i\f1 switch}{\f1 variable has bit set if the n\rquote th letter was specified as a switch to the examine command. \par \par t_stat }{\i\f1 deposit_routine}{\f1 (t_val value, t_addr addr, UNIT *uptr, int32 switches) \endash Store the specified }{\i\f1 value}{\f1 in the specified }{\i\f1 addr}{\f1 for unit }{\i\f1 uptr}{\f1 . The }{\i\f1 switch}{\f1 variable is the same as for the examine routine. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.1.2\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Reset Routine -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par {\*\bkmkstart _Toc526228053}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.1.2\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Reset Routine +{\*\bkmkend _Toc526228053} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par The reset routine implements the device reset function for the RESET, RUN, and BOOT commands. Its calling sequence is: \par \par \tab t_stat }{\i\f1 reset_routine}{\f1 (DEVICE *dptr) \endash Reset the specified device to its initial state. \par -\par A typical reset routine clears all device flags and cancels any outstanding timing operations. -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.1.3\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Boot Routine -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 A typical reset routine clears all device flags and cancels any outstanding timing operations. +\par {\*\bkmkstart _Toc526228054}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.1.3\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Boot Routine +{\*\bkmkend _Toc526228054} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par If a device responds to a BOOT command, the boot routine implements the bootstrapping function. Its calling sequence is: \par \par \tab t_stat }{\i\f1 boot_routine}{\f1 (int32 unit_number) \endash Bootstrap the specified unit. \par \par A typical bootstrap routine copies a bootstrap loader into main memory and sets the PC to the starting address of the loader. SCP then starts simulation at the specified address. -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.1.4\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Attach and Detach Routines -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par {\*\bkmkstart _Toc526228055}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.1.4\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Attach and Detach Routines +{\*\bkmkend _Toc526228055} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par Normally, the ATTACH and DETACH commands are handled by SCP. However, devices which need to pre- or post-process these commands must supply special attach and detach routines. The calling sequences are: \par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 t_stat }{\i\f1 attach_routine }{\f1 (UNIT *uptr, char *file) \endash Attach the specified }{\i\f1 file}{\f1 to the unit }{\i\f1 uptr}{\f1 . +\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\i\f1 attach_routine }{\f1 (UNIT *uptr, char *file) \endash Attach the specified }{\i\f1 file}{\f1 to the unit }{\i\f1 uptr}{\f1 . \par \par t_stat }{\i\f1 detach_routine}{\f1 (UNIT *uptr) \endash Detach unit }{\i\f1 uptr}{\f1 . -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par }\pard \widctlpar\adjustright {\f1 \par In practice, these routines always invoke the standard SCP routines, }{\b\f1 attach_unit}{\f1 and }{\b\f1 detach_unit}{\f1 , respectively. For example, here are special attach and detach routines to update line printer error state: \par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 t_stat lpt_attach (UNIT *uptr, char *cptr) \{ -\par }\pard \ql \fi720\li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 t_stat r; +\par }\pard \li720\widctlpar\adjustright {\f1 t_stat lpt_attach (UNIT *uptr, char *cptr) \{ +\par }\pard \fi720\li720\widctlpar\adjustright {\f1 t_stat r; \par if ((r = attach_unit (uptr, cptr)) != SCPE_OK) return r; \par lpt_error = 0; \par return SCPE_OK; -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 \} +\par }\pard \li720\widctlpar\adjustright {\f1 \} \par \par t_stat lpt_detach (UNIT *uptr) \{ \par \tab lpt_error = 1; \par \tab return detach_unit (uptr); \par \} -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\listtext\pard\plain\b\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.2\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\ilvl1\adjustright\rin0\lin360\itap0 {\b\f1 unit}{\f1 Structure -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\b\f1 -\par }{\f1 Units are allocated as contiguous array. Each unit is defined with a }{\b\f1 unit}{\f1 structure (typedef }{\b\f1 UNIT}{\f1 ), which has the following fields: +\par }\pard \widctlpar\adjustright {\f1 +\par SCP executes a DETACH ALL command as part of simulator exit. Normally, DETACH ALL only calls a unit\rquote s detach routine if the unit\rquote +s UNIT_ATTABLE flag is set. During simulator exit, the detach routine is called unconditionally. This allows the detach routine of a non-attachable unit to function as a simulator-specific cleanup routine for the unit, device, or entire simulator. + +\par {\*\bkmkstart _Toc526228056}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 4.2\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {unit Structure +{\*\bkmkend _Toc526228056} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\b\f1 +\par }{\f1 Units are allocated as contiguous array. Each unit is defined with a }{\b\f1 unit}{\f1 structure (typedef }{\b\f1 UNIT}{\f1 ): \par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 struct unit \{ +\par }\pard \li720\widctlpar\adjustright {\f1 struct unit \{ \par \tab struct unit\tab *next;\tab \tab \tab \tab /* next active */ \par \tab t_stat\tab \tab (*action)();\tab \tab \tab /* action routine */ \par \tab char\tab \tab *filename;\tab \tab \tab /* open file name */ @@ -601,10 +655,10 @@ rns SCPE_KFLAG + the character. If the user typed the interrupt character (^E), \par \tab int32\tab \tab u3;\tab \tab \tab \tab /* device specific */ \par \tab int32\tab \tab u4;\tab \tab \tab \tab /* device specific */ \par \}; -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par The fields are the following +\par }\pard \widctlpar\adjustright {\f1 +\par The fields are the following: \par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\b\f1 next}{\f1 \tab \tab pointer to next unit in active queue, NULL if none. +\par }\pard \li720\widctlpar\adjustright {\b\f1 next}{\f1 \tab \tab pointer to next unit in active queue, NULL if none. \par }{\b\f1 action}{\f1 \tab \tab address of unit time-out service routine. \par }{\b\f1 filename}{\f1 \tab pointer to name of attached file, NULL if none. \par }{\b\f1 fileref}{\f1 \tab \tab pointer to FILE structure of attached file, NULL if none. @@ -617,24 +671,24 @@ rns SCPE_KFLAG + the character. If the user typed the interrupt character (^E), \par }{\b\f1 wait}{\f1 \tab \tab by convention, the unit wait time, but can be used for other purposes. \par }{\b\f1 u3}{\f1 \tab \tab user-defined. \par }{\b\f1 u4}{\f1 \tab \tab user-defined. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\b\f1 +\par }\pard \widctlpar\adjustright {\b\f1 \par buf, wait, u3, u4}{\f1 are all saved and restored by the SAVE and RESTORE commands and thus can be used for unit state which must be preserved. \par -\par Macro }{\b\f1 UDATA}{\f1 is available to fill in the common fields of a UNIT. It is invoked by -\par +\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 Macro }{\b\f1 UDATA}{\f1 is available to fill in the common fields of a UNIT. It is invoked by +\par }\pard \widctlpar\adjustright {\f1 \par \tab UDATA\tab \tab (action_routine, flags, capacity) \par -\par Fields after }{\b\f1 buf}{\f1 can be filled in manually, e.g, -\par -\par \tab UNIT lpt_unit = \{ UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), 500 \}; -\par +\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 Fields after }{\b\f1 buf}{\f1 can be filled in manually, e.g, +\par }\pard \widctlpar\adjustright {\f1 +\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 \tab UNIT lpt_unit = \{ UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), 500 \}; +\par }\pard \widctlpar\adjustright {\f1 \par defines the line printer as a sequential unit with a wait time of 500. -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.2.1\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Unit Flags -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par {\*\bkmkstart _Toc526228057}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.2.1\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Unit Flags{\*\bkmkend _Toc526228057 +} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par The }{\b\f1 flags }{\f1 field contains indicators of current unit status. SIMH defines 11 flags: \par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 flag name\tab \tab meaning if set +\par }\pard \li720\widctlpar\adjustright {\f1 flag name\tab \tab meaning if set \par \par UNIT_DISABLE\tab \tab the unit responds to ENABLE and DISABLE. \par UNIT_DIS\tab \tab the unit is currently disabled. @@ -646,24 +700,24 @@ rns SCPE_KFLAG + the character. If the user typed the interrupt character (^E), \par UNIT_RO\tab \tab the unit is read only. \par UNIT_SEQ\tab \tab the unit is sequential. \par UNIX_FIX\tab \tab the unit is fixed capacity. -\par UNIT_BINK\tab \tab the unit measures \'93K\'94 as 1024, rather than 1000. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par Starting at bit position UNIT_V_UF, the remaining flags are device-specific. Device-specific flags are set and cleared with the SET and CLEAR commands, which -reference the MTAB array (see below). Device-specific flags and UNIT_DIS are not automatically saved and restored; the device must supply a register covering these bits. -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.2.2\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Service Routine -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par UNIT_BINK\tab \tab the unit measures \ldblquote K\rdblquote as 1024, rather than 1000. +\par }\pard \widctlpar\adjustright {\f1 +\par Starting at bit position UNIT_V_UF, the remaining flags are device-specific. Device-specific flags are set and cleared with the SET and CLEAR commands, which reference the MTAB array (see be +low). Device-specific flags and UNIT_DIS are not automatically saved and restored; the device must supply a register covering these bits. +\par {\*\bkmkstart _Toc526228058}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.2.2\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Service Routine +{\*\bkmkend _Toc526228058} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par This routine is called by }{\b\f1 sim_process_event}{\f1 when a unit times out. Its calling sequence is: \par -\par }\pard \ql \fi720\li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 t_stat }{\i\f1 service_routine}{\f1 (UNIT *uptr) -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par The status returned by the service routine is passed by }{\b\f1 sim_process_event}{\f1 back to the CPU. +\par }\pard \fi720\widctlpar\adjustright {\f1 t_stat }{\i\f1 service_routine}{\f1 (UNIT *uptr) +\par }\pard \widctlpar\adjustright {\f1 +\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 The status returned by the service routine is passed by }{\b\f1 sim_process_event}{\f1 back to the CPU. +\par {\*\bkmkstart _Toc526228059}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 4.3\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {reg Structure +{\*\bkmkend _Toc526228059} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\b\f1 +\par }{\f1 Registers are allocated as contiguous array, with a NULL register at the end. Each register is defined with a }{\b\f1 reg}{\f1 structure (typedef }{\b\f1 REG}{\f1 ): \par -\par {\listtext\pard\plain\b\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.3\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\ilvl1\adjustright\rin0\lin360\itap0 {\b\f1 reg}{\f1 Structure -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\b\f1 -\par }{\f1 Registers are allocated as contiguous array, with a NULL register at the end. Each register is defined with a }{\b\f1 reg}{\f1 structure (typedef }{\b\f1 REG}{\f1 ), which has the following fields: -\par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 struct reg \{ +\par }\pard \li720\widctlpar\adjustright {\f1 struct reg \{ \par \tab char\tab \tab *name;\tab \tab \tab \tab /* name */ \par \tab void\tab \tab *loc;\tab \tab \tab \tab /* location */ \par \tab int\tab \tab radix;\tab \tab \tab \tab /* radix */ @@ -672,19 +726,19 @@ reference the MTAB array (see below). Device-specific flags and UNIT_DIS are no \par \tab int\tab \tab depth;\tab \tab \tab \tab /* save depth */ \par \tab int32\tab \tab flags;\tab \tab \tab \tab /* flags */ \par \}; -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par }\pard \widctlpar\adjustright {\f1 \par The fields are the following: \par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\b\f1 name}{\f1 \tab \tab device name, string of all capital alphanumeric characters. +\par }\pard \li720\widctlpar\adjustright {\b\f1 name}{\f1 \tab \tab device name, string of all capital alphanumeric characters. \par }{\b\f1 loc}{\f1 \tab \tab pointer to location of the register value. \par }{\b\f1 radix}{\f1 \tab \tab radix for input and display of data, 2 to 16 inclusive. \par }{\b\f1 width}{\f1 \tab \tab width in bits of data, 1 to 32 inclusive. \par }{\b\f1 width\tab }{\f1 \tab bit offset (from right end of data). \par }{\b\f1 depth\tab }{\f1 \tab size of data array (normally 1). \par }{\b\f1 flags}{\f1 \tab \tab flags and formatting information. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par The }{\b\f1 depth}{\f1 field is only used with special \'93arrayed registers\'94, lik -e the data buffer in the PDP floppy disk controller. Arrayed registers cannot be examined or deposited, but all the values in the array will be saved and restored by SAVE and RESTORE. +\par }\pard \widctlpar\adjustright {\f1 +\par The }{\b\f1 depth}{\f1 field is only used with special \ldblquote arrayed registers\rdblquote +, like the data buffer in the PDP floppy disk controller. Arrayed registers cannot be examined or deposited, but all the values in the array will be saved and restored by SAVE and RESTORE. \par \par Macros }{\b\f1 ORDATA}{\f1 , }{\b\f1 DRDATA}{\f1 , and }{\b\f1 HRDATA}{\f1 define right-justified octal, decimal, and hexidecimal registers, respectively. They are invoked by: \par @@ -702,16 +756,16 @@ e the data buffer in the PDP floppy disk controller. Arrayed registers cannot b \par \par \tab BRDATA\tab (name, location, radix, width, depth) \par -\par The }{\b\f1 flag}{\f1 field can be filled in manually, e.g., -\par -\par \tab REG lpt_reg = \{ -\par \tab \tab \{ DRDATA\tab (POS, lpt_unit.pos, 31), PV_LFT \}, \'85 \} -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.3.1\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Register Flags -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par The }{\b\f1 flags }{\f1 field contains indicators that control register examination and deposit. -\par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 flag name\tab \tab meaning if specified +\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 The }{\b\f1 flag}{\f1 field can be filled in manually, e.g., +\par }\pard \widctlpar\adjustright {\f1 +\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 \tab REG lpt_reg = \{ +\par }\pard \widctlpar\adjustright {\f1 \tab \tab \{ DRDATA\tab (POS, lpt_unit.pos, 31), PV_LFT \}, \'85 \} +\par {\*\bkmkstart _Toc526228060}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.3.1\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Register Flags +{\*\bkmkend _Toc526228060} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 +\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 The }{\b\f1 flags }{\f1 field contains indicators that control register examination and deposit. +\par }\pard \widctlpar\adjustright {\f1 +\par }\pard \li720\widctlpar\adjustright {\f1 flag name\tab \tab meaning if specified \par \par PV_RZRO\tab \tab print register right justified with leading zeroes. \par PV_RSPC\tab \tab print register right justified with leading spaces. @@ -720,83 +774,93 @@ e the data buffer in the PDP floppy disk controller. Arrayed registers cannot b \par REG_HIDDEN\tab \tab register is hidden (will not appear in EXAMINE STATE). \par REG_HRO\tab \tab register is read only and hidden. \par REG_NZ\tab \tab new register values must be non-zero. -\par -\par {\listtext\pard\plain\b\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.4\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\ilvl1\adjustright\rin0\lin360\itap0 {\b\f1 mtab}{\f1 Structure -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\b\f1 +\par {\*\bkmkstart _Toc526228061}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 4.4\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {mtab Structure +{\*\bkmkend _Toc526228061} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\b\f1 \par }{\f1 Device-specific SHOW and SET commands are processed using the modifications array, which is allocated as contiguous array, with a NULL at the end. Each possible modification is defined with a }{\b\f1 mtab}{\f1 structure (synonym }{\b\f1 MTAB}{\f1 ), which has the following fields: \par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 struct mtab \{ +\par }\pard \li720\widctlpar\adjustright {\f1 struct mtab \{ \par \tab int32\tab \tab mask;\tab \tab \tab \tab /* mask */ \par \tab int32\tab \tab match;\tab \tab \tab \tab /* match */ \par \tab char\tab \tab *pstring;\tab \tab \tab /* print string */ \par \tab char\tab \tab *mstring;\tab \tab \tab /* match string */ \par \tab t_stat\tab \tab (*valid)();\tab \tab \tab /* validation routine */ \par \}; -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par }\pard \widctlpar\adjustright {\f1 \par The fields are the following: \par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\b\f1 mask}{\f1 \tab \tab bit mask for testing the unit.}{\b\f1 flags}{\f1 field -\par }\pard \ql \fi-1440\li2160\ri0\widctlpar\faauto\adjustright\rin0\lin2160\itap0 {\b\f1 match}{\f1 \tab (SHOW) if the masked bits equal this value, }{\b\f1 pstring}{\f1 is printed +\par }\pard \li720\widctlpar\adjustright {\b\f1 mask}{\f1 \tab \tab bit mask for testing the unit.}{\b\f1 flags}{\f1 field +\par }\pard \fi-1440\li2160\widctlpar\adjustright {\b\f1 match}{\f1 \tab (SHOW) if the masked bits equal this value, }{\b\f1 pstring}{\f1 is printed \par }{\b\f1 \tab }{\f1 (SET) if }{\b\f1 mstring}{\f1 is matched, the masked bits are set to this value -\par }{\b\f1 pstring}{\f1 \tab pointer to character string printed on a match (SHOW) -\par }{\b\f1 mstring}{\f1 \tab pointer to character string to be matched (SET, CLEAR) -\par }{\b\f1 valid}{\f1 \tab address of validation routine, or NULL if none required -\par }\pard \ql \fi-1440\li1440\ri0\widctlpar\faauto\adjustright\rin0\lin1440\itap0 {\f1 -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.4.1\tab}}\pard \ql \fi-720\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls1\ilvl2\adjustright\rin0\lin720\itap0 {\f1 Validation Routine -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par }{\b\f1 pstring}{\f1 \tab pointer to character string printed on a match (SHOW), or NULL +\par }{\b\f1 mstring}{\f1 \tab pointer to character string to be matched (SET), or NULL +\par }{\b\f1 valid}{\f1 \tab address of validation/display routine, or NULL if none required +\par {\*\bkmkstart _Toc526228062}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.4.1\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Validation/Display Routine +{\*\bkmkend _Toc526228062} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 +\par The validation/display routine can be used to validate input during SET processing, or to display device-specific output during SHOW processing, but not both. If }{\b\f1 mstring}{\f1 is not NULL, then the routine is a validation routine. If }{\b\f1 +mstring}{\f1 is NULL, and }{\b\f1 pstring}{\f1 is not NULL, then the routine is a display routine. +\par \par The validation routine is called during SET processing to make sure that the proposed modification is valid. It can make other state changes required by the modification or initiate additional dialogs needed by the modifier. Its calling sequence is: \par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 t_stat }{\i\f1 validation_routine}{\f1 (UNIT *uptr, int32 value) \endash test that }{\i\f1 uptr}{\f1 .}{\b\f1 flags}{\f1 can be set to }{\i\f1 value}{\f1 . -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 4.5\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\ilvl1\adjustright\rin0\lin360\itap0 {\f1 Other Data Structures -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\i\f1 validation_routine}{\f1 (UNIT *uptr, int32 value) \endash test that }{\i\f1 uptr}{\f1 .}{\b\f1 flags}{\f1 can be set to }{\i\f1 value}{\f1 . +\par }\pard \widctlpar\adjustright {\f1 +\par The display routine is called during SHOW processing to display device- or unit-specific state. Its calling sequence is: +\par +\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\i\f1 display_routine}{\f1 (UNIT *uptr, FILE *st) \endash output device- or unit-specific state for }{\i\f1 uptr}{\f1 to stream }{\i\f1 st}{\f1 . +\par }\pard \widctlpar\adjustright {\f1 +\par When the display routine is called, SHOW has output the }{\b\f1 pstring}{\f1 argument but has not appended a newline. SHOW will append a final newline after the display routine returns. +\par {\*\bkmkstart _Toc526228063}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 4.5\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {Other Data Structures +{\*\bkmkend _Toc526228063} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par char }{\b\f1 sim_name[]}{\f1 is a character array containing the VM name. \par \par int32 }{\b\f1 sim_emax}{\f1 contains the maximum number of words needed to hold the largest instruction or data item in the VM. Examine and deposit will process up to }{\b\f1 sim_emax}{\f1 words. \par \par DEVICE *}{\b\f1 sim_devices[]}{\f1 is an array of pointers to all the devices in the VM. It is terminated by a NULL. By convention, the CPU is always the first device in the array. \par -\par UNIT }{\b\f1 *sim_consoles[]}{\f1 is an array of pointers -to the units of simulated consoles, alternating input and output. (If a console has only an input unit, the output slot should also point to the input unit.) This structure is only used for multi-console support. If the VM has only one console, the poi -nter should be NULL. +\par UNIT }{\b\f1 *sim_consoles[]}{\f1 is an array of pointers to the units of simulate +d consoles, alternating input and output. (If a console has only an input unit, the output slot should also point to the input unit.) This structure is only used for multi-console support. If the VM has only one console, the pointer should be NULL. + \par \par REG *}{\b\f1 sim_PC}{\f1 points to the }{\b\f1 reg}{\f1 structure for the program counter. By convention, the PC is always the first register in the CPU\rquote s register array. \par \par char *}{\b\f1 sim_stop_messages[]}{\f1 is an array of pointers to character strings, corresponding to error status returns greater than zero. If }{\b\f1 sim_instr}{\f1 returns status code n > 0, then }{\b\f1 sim_stop_message[n]}{\f1 is printed by SCP. \par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 5.\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\adjustright\rin0\lin360\itap0 {\f1 VM Provided Routines -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 5.1\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\ilvl1\adjustright\rin0\lin360\itap0 {\f1 Instruction Execution -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par {\*\bkmkstart _Toc526228064}{\listtext\pard\plain\s1 \b\f1\fs28\kerning28\cgrid \hich\af1\dbch\af0\loch\f1 5.\tab}}\pard\plain \s1\fi-360\li360\sb240\sa60\keepn\widctlpar\jclisttab\tx360\ls1\outlinelevel0\adjustright \b\f1\fs28\kerning28\cgrid { +VM Provided Routines{\*\bkmkend _Toc526228064} +\par {\*\bkmkstart _Toc526228065}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 5.1\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {Instruction Execution +{\*\bkmkend _Toc526228065} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par Instruction execution is performed by routine }{\b\f1 sim_instr}{\f1 . Its calling sequence is: \par \par t_stat }{\b\f1 sim_instr}{\f1 (void) \endash Execute from current PC until error or halt. -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 5.2\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\ilvl1\adjustright\rin0\lin360\itap0 {\f1 Binary Load and Dump -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par {\*\bkmkstart _Toc526228066}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 5.2\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {Binary Load and Dump +{\*\bkmkend _Toc526228066} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par If the VM responds to the LOAD (or DUMP) command, the loader (dumper) is implemented by routine }{\b\f1 sim_load}{\f1 . Its calling sequence is: \par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 t_stat }{\b\f1 sim_load}{\f1 (FILE *fptr, char *buf, char *fnam, t_bool flag) - If }{\i\f1 flag}{\f1 = 0, load data from binary file }{\i\f1 fptr}{\f1 . If }{\i\f1 flag}{\f1 - = 1, dump data to binary file }{\i\f1 fptr}{\f1 . For either command, }{\i\f1 buf}{\f1 contains any VM-specific arguments, and }{\i\f1 fnam}{\f1 contains the file name. -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\b\f1 sim_load}{\f1 (FILE *fptr, char *buf, char *fnam, t_bool flag) - If }{\i\f1 flag}{\f1 = 0, load data from binary file }{\i\f1 fptr}{\f1 . If }{\i\f1 flag}{\f1 = 1, dump data to binary file }{ +\i\f1 fptr}{\f1 . For either command, }{\i\f1 buf}{\f1 contains any VM-specific arguments, and }{\i\f1 fnam}{\f1 contains the file name. +\par }\pard \widctlpar\adjustright {\f1 \par If LOAD or DUMP is not implemented, }{\b\f1 sim_load}{\f1 should simply return SCPE_ARG. The LOAD and DUMP commands open and close the specified file for }{\b\f1 sim_load}{\f1 . -\par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 5.3\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\ilvl1\adjustright\rin0\lin360\itap0 {\f1 Symbolic Examination and Deposit -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 +\par {\*\bkmkstart _Toc526228067}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 5.3\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid { +Symbolic Examination and Deposit{\*\bkmkend _Toc526228067} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 \par If the VM provides symbolic examination and deposit of data, it must provide two routines, }{\b\f1 fprint_sym}{\f1 for output and }{\b\f1 parse_sym}{\f1 for input. Their calling sequences are: \par -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 t_stat }{\b\f1 fprint_sym}{\f1 (FILE *ofile, t_addr addr, t_value *val, UNIT *uptr, int32 switch) \endash Based on the }{\i\f1 switch}{\f1 - variable, symbolically output to stream }{\i\f1 ofile}{\f1 the data in array }{\i\f1 val}{\f1 at the specified }{\i\f1 addr}{\f1 in unit }{\i\f1 uptr}{\f1 . +\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\b\f1 fprint_sym}{\f1 (FILE *ofile, t_addr addr, t_value *val, UNIT *uptr, int32 switch) \endash Based on the }{\i\f1 switch}{\f1 variable, symbolically output to stream }{\i\f1 ofile}{\f1 + the data in array }{\i\f1 val}{\f1 at the specified }{\i\f1 addr}{\f1 in unit }{\i\f1 uptr}{\f1 . \par \par t_stat }{\b\f1 parse_sym}{\f1 (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 switch) \endash Based on the }{\i\f1 switch}{\f1 variable, parse character string }{\i\f1 cptr}{\f1 for a symbolic value }{\i\f1 val}{\f1 at the specified }{ \i\f1 addr}{\f1 in unit }{\i\f1 uptr}{\f1 . -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par If symbolic processing is - not implemented, or the output value or input string cannot be parsed, these routines should return SCPE_ARG. If the processing was successful and consumed more than a single word, then these routines should return extra number of words (not bytes) cons -umed as a }{\b\f1 negative}{\f1 number. If the processing was successful and consumed a single word, then these routines should return SCPE_OK. For example, PDP-11 }{\b\f1 parse_sym}{\f1 would respond as follows to various inputs: +\par }\pard \widctlpar\adjustright {\f1 +\par If symbolic processing is not implemented, or the output value or input string cannot be parsed, these routines should return SCPE_ARG. If the processing +was successful and consumed more than a single word, then these routines should return extra number of words (not bytes) consumed as a }{\b\f1 negative}{\f1 + number. If the processing was successful and consumed a single word, then these routines should return SCPE_OK. For example, PDP-11 }{\b\f1 parse_sym}{\f1 would respond as follows to various inputs: \par \par \tab input\tab \tab \tab \tab return value \par @@ -813,59 +877,98 @@ umed as a }{\b\f1 negative}{\f1 number. If the processing was successful and c \par \tab -c\tab \tab \tab \tab character string \par \tab -m\tab \tab \tab \tab instruction mnemonic \par -\par In addition, on input, a leading \lquote (apostrophe) is interpreted to mean a single character, and a leading \'93 (double quote) is interpreted to mean a character string. +\par In addition, on input, a leading \lquote (apostrophe) is interpreted to mean a single character, and a leading \ldblquote (double quote) is interpreted to mean a character string. +\par {\*\bkmkstart _Toc526228068}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 5.4\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid { +Multi-Terminal Support (Telnet){\*\bkmkend _Toc526228068} +\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 +\par SIMH supports the use of multiple terminals. All terminals except the console are accessed via Telnet. SIMH provides two supporting +libraries for implementing multiple terminals: sim_tmxr.c (and its header file, sim_tmxr.h), which provide OS-independent support routines for terminal multiplexors; and sim_sock.c (and its header file, sim_sock.h), which provide OS-dependent socket routi +nes. Sim_sock.c is presently implemented only under Windows and UNIX. \par -\par {\listtext\pard\plain\f1\fs20 \hich\af1\dbch\af0\loch\f1 5.4\tab}}\pard \ql \fi-360\li360\ri0\widctlpar\jclisttab\tx360\faauto\ls1\ilvl1\adjustright\rin0\lin360\itap0 {\f1 Multi-console Support -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par At the moment, SIMH does not provide concurrent support for multiple con -soles in a VM. To facilitate use of software systems that require multiple consoles, SIMH does provide serialized support for multiple consoles; that is, the use of the controlling keyboard and screen can be moved from one console to another. This allow -s the user to interact with each of the consoles sequentially. This serialized support will (I hope) eventually be replaced by true concurrent support. The console with control of the keyboard and screen is the active console; the others are inactive. - +\par Two basic data structures define the multiple terminals. Individual lines are defined by the }{\b\f1 tmln}{\f1 structure (typedef }{\b\f1 TMLN}{\f1 ): \par -\par The list of consoles in a multi-console VM is pointed to by UNIT }{\b\f1 *sim_consoles[]}{\f1 . Even entries in }{\b\f1 sim_consoles[]}{\f1 - point to the input units, odd entries to the output units. (If a console has only an input unit, the output slot also points to the input unit.) Each console simulator must support the following additional features: +\par }\pard \li720\widctlpar\adjustright {\f1 struct tmln \{ +\par \tab SOCKET\tab conn;\tab \tab \tab \tab /* line conn */ +\par \tab uint32\tab \tab ipad;\tab \tab \tab \tab /* IP address */ +\par \tab uint32\tab \tab cnms;\tab \tab \tab \tab /* connect time ms */ +\par \tab int32\tab \tab tsta;\tab \tab \tab \tab /* Telnet state */ +\par \tab int32\tab \tab rcve;\tab \tab \tab \tab /* rcv enable */ +\par \tab int32\tab \tab xmte;\tab \tab \tab \tab /* xmt enable */ +\par \tab int32\tab \tab dstb;\tab \tab \tab \tab /* disable Tlnt bin */ +\par \tab int32\tab \tab rxbpr;\tab \tab \tab \tab /* rcv buf remove */ +\par \tab int32\tab \tab rxbpi;\tab \tab \tab \tab /* rcv buf insert */ +\par \tab int32\tab \tab rxcnt;\tab \tab \tab \tab /* rcv count */ +\par \tab int32\tab \tab txbpr;\tab \tab \tab \tab /* xmt buf remove */ +\par \tab int32\tab \tab txbpi;\tab \tab \tab \tab /* xmt buf insert */ +\par \tab int32\tab \tab txcnt;\tab \tab \tab \tab /* xmt count */ +\par \tab uint8\tab \tab rxb[TMXR_MAXBUF];\tab \tab /* rcv buffer */ +\par \tab uint8\tab \tab txb[TMXR_MAXBUF];\tab \tab /* xmt buffer */ +\par \tab \}; +\par }\pard \widctlpar\adjustright {\f1 +\par The fields are the following: \par -\par {\listtext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls17\adjustright\rin0\lin720\itap0 {\f1 The initial console must have flag UNIT_CONS set in both the input and output units: - -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par }\pard \ql \fi720\li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 UNIT tti_unit = \{ UDATA (&tti_svc, UNIT_CONS, 0), SERIAL_IN_WAIT \}; -\par : -\par UNIT tto_unit = \{ UDATA (&tto_svc, UNIT_CONS, 0), SERIAL_OUT_WAIT \}; +\par \tab }{\b\f1 conn}{\f1 \tab \tab connection socket (0 = disconnected) +\par \tab }{\b\f1 tsta}{\f1 \tab \tab Telnet state +\par \tab }{\b\f1 rcve}{\f1 \tab \tab receive enable flag (0 = disabled) +\par \tab }{\b\f1 xmte}{\f1 \tab \tab transmit flow control flag (0 = transmit disabled) +\par \tab }{\b\f1 dstb}{\f1 \tab \tab Telnet bin mode disabled +\par \tab }{\b\f1 rxbp}{\f1 r\tab \tab receive buffer remove pointer +\par \tab }{\b\f1 rxbpi}{\f1 \tab \tab receive buffer insert pointer +\par \tab }{\b\f1 rxcnt}{\f1 \tab \tab receive count +\par \tab }{\b\f1 txbpr}{\f1 \tab \tab transmit buffer remove pointer +\par \tab }{\b\f1 txbpi}{\f1 \tab \tab transmit buffer insert pointer +\par \tab }{\b\f1 txcnt}{\f1 \tab \tab transmit count +\par }\pard \fi720\widctlpar\adjustright {\b\f1 rxb}{\f1 \tab \tab receive buffer +\par }\pard \widctlpar\adjustright {\f1 \tab }{\b\f1 txb}{\f1 \tab \tab transmit buffer \par -\par {\listtext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls17\adjustright\rin0\lin720\itap0 {\f1 -Both the input unit and the output unit must have a modifier block that includes the CONSOLE modifier, with }{\b\f1 set_console}{\f1 as the verification routine: -\par }\pard \ql \li360\ri0\widctlpar\faauto\adjustright\rin0\lin360\itap0 {\f1 -\par }\pard \ql \fi360\li360\ri0\widctlpar\faauto\adjustright\rin0\lin360\itap0 {\f1 MTAB tti_mod[] = \{ -\par }\pard \ql \li360\ri0\widctlpar\faauto\adjustright\rin0\lin360\itap0 {\f1 \tab \tab \{ UNIT_CONS, 0, "inactive", NULL, NULL \}, -\par \tab \tab \{ UNIT_CONS, UNIT_CONS, "active console", "CONSOLE", &set_console \}, \'85 -\par \tab : -\par }\pard \ql \fi360\li360\ri0\widctlpar\faauto\adjustright\rin0\lin360\itap0 {\f1 MTAB tto_mod[] = \{ -\par }\pard \ql \li360\ri0\widctlpar\faauto\adjustright\rin0\lin360\itap0 {\f1 \tab \tab \{ UNIT_CONS, 0, "inactive", NULL, NULL \}, -\par \tab \tab \{ UNIT_CONS, UNIT_CONS, "active console", "CONSOLE", &set_console \}, \'85 +\par The overall set of extra terminals is defined by the }{\b\f1 tmxr}{\f1 structure (typedef }{\b\f1 TMXR}{\f1 ): \par -\par {\listtext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls17\adjustright\rin0\lin720\itap0 {\f1 The input and output unit \lquote UNIT_CONS\rquote f -lags must be defined as a hidden register flag, so their values are saved and restored properly: -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par \tab \{ FLDATA (CFLAG, tti_unit.flags, UNIT_V_CONS), REG_HRO \}, -\par \tab : -\par \tab \{ FLDATA (CFLAG, tto_unit.flags, UNIT_V_CONS), REG_HRO \}, +\par }\pard \li720\widctlpar\adjustright {\f1 struct tmxr \{ +\par \tab int32\tab \tab lines;\tab \tab \tab \tab /* # lines */ +\par \tab SOCKET\tab master;\tab \tab \tab \tab /* master socket */ +\par \tab TMLN\tab \tab *ldsc[TMXR_MAXLIN];\tab \tab /* line descriptors */ +\par \tab \}; +\par }\pard \widctlpar\adjustright {\f1 +\par The fields are the following: \par -\par {\listtext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls17\adjustright\rin0\lin720\itap0 {\f1 The input unit must initiate or continue polling only if its UNIT_CONS flag is set. - -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par {\listtext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls17\adjustright\rin0\lin720\itap0 {\f1 -The output unit must provide a CONS_SIZE character buffer to hold output when this console is inactive. This buffer must be defined as a hidden register array, so its contents are saved and restored properly. - Finally, the address of this buffer must be stored in the output unit\rquote s filebuf pointer: -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par }\pard \ql \fi720\li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 static uint8 tto_consout[CONS_SIZE];\tab \tab /* in data area */ -\par : -\par \{ BRDATA (CONSOUT, tto_consout, 8, 8, CONS_SIZE), REG_HIDDEN \}, -\par : -\par tto_unit.filebuf = tto_consout;\tab \tab \tab /* in reset: set buf pointer */ +\par \tab }{\b\f1 lines}{\f1 \tab \tab number of lines (constant) +\par \tab }{\b\f1 master}{\f1 \tab \tab master listening socket (specified by ATTACH command) +\par \tab }{\b\f1 ldsc}{\f1 \tab \tab array of line descriptors \par -\par {\listtext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\faauto\ls19\adjustright\rin0\lin720\itap0 {\f1 The output unit must use routine }{\b\f1 sim_putcons}{\f1 instead of }{\b\f1 -sim_putchar}{\f1 for output: -\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 -\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 t_stat }{\b\f1 sim_putcons}{\f1 (int32 out, UNIT }{\b\f1 uptr)\tab /}{\f1 * output to console, possibly buffered */ +\par Library sim_tmxr.c provides the following routines to support Telnet-based terminals: \par +\par }\pard \li720\widctlpar\adjustright {\f1 int32 }{\b\f1 tmxr_poll_conn}{\f1 (TMXR *mp, UNIT *uptr) \endash poll for a new connection to the terminals described by }{\i\f1 mp }{\f1 and unit }{\i\f1 uptr}{\f1 +. If there is a new connection, the routine resets all the line descriptor state (including receive enable) and returns the line number (index to line descriptor) for the new connection. If there isn\rquote t a new connection, the routine returns +\endash 1. +\par +\par void }{\b\f1 tmxr_reset_ln}{\f1 (TMLN *lp) \endash reset the line described by }{\i\f1 lp}{\f1 . The connection is closed and all line descriptor state is reset. +\par +\par int32 }{\b\f1 tmxr_getc_ln}{\f1 (TMLN *lp) \endash return the next available character from the line described by }{\i\f1 lp}{\f1 . If a character is available, the return variable is: +\par +\par \tab (1 << TMXR_V_VALID) | character +\par +\par If no character is available, the return variable is 0. +\par +\par void }{\b\f1 tmxr_poll_rx}{\f1 (TMXR *mp) \endash poll for input available on the terminals described by }{\i\f1 mp}{\f1 . +\par +\par void }{\b\f1 tmxr_rqln}{\f1 (TMLN *lp) \endash return the number of characters in the receive queue of the line described by }{\i\f1 lp}{\f1 . +\par +\par }\pard\plain \s17\li720\widctlpar\adjustright \f1\fs20\cgrid {void }{\b tmxr_putc_ln}{ (TMLN *lp, int32 chr) \endash output character }{\i chr }{to the line described by }{\i lp}{. +\par }\pard\plain \li720\widctlpar\adjustright \fs20\cgrid {\f1 +\par }\pard\plain \s17\li720\widctlpar\adjustright \f1\fs20\cgrid {void }{\b tmxr_poll_tx}{ (TMXR *mp) \endash poll for output complete on the terminals described by }{\i mp}{. +\par }\pard\plain \li720\widctlpar\adjustright \fs20\cgrid {\f1 +\par }{\f1 void }{\b\f1 tmxr_}{\b\f1 t}{\b\f1 qln}{\f1 (TMLN *lp) \endash return the number of characters in the }{\f1 transmit}{\f1 queue of the line described by }{\i\f1 lp}{\f1 . +\par +\par }{\f1 t_stat }{\b\f1 tmxr_attach}{\f1 (TMXR *mp, UNIT *uptr, char *cptr) \endash attach the port contained in character string }{\i\f1 cptr}{\f1 to the terminals described by }{\i\f1 mp}{\f1 and unit }{\i\f1 uptr}{\f1 . +\par +\par }\pard\plain \s17\li720\widctlpar\adjustright \f1\fs20\cgrid {t_stat }{\b tmxr_detach}{ (TMXR *mp, UNIT *uptr) \endash detach all connections for the terminals described by }{\i mp}{ and unit }{\i uptr}{. +\par }\pard\plain \li720\widctlpar\adjustright \fs20\cgrid {\f1 +\par t_stat }{\b\f1 tmxr_ex}{\f1 (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) \endash stub examine routine, needed because the extra terminals are marked as attached; always returns an error. +\par +\par t_stat }{\b\f1 tmxr_dep}{\f1 (t_value val, t_addr addr, UNIT *uptr, int32 sw) \endash stub deposit routine, needed because the extra terminals are marked as detached; always returns an error. +\par }\pard \li360\widctlpar\adjustright {\f1 +\par }\pard \fi360\li360\widctlpar\adjustright {\f1 void }{\b\f1 tmxr_msg}{\f1 (SOCKET sock, char *msg) \endash output character string }{\i\f1 msg}{\f1 to socket }{\i\f1 sock}{\f1 . +\par }\pard \widctlpar\adjustright {\f1 +\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 The OS-dependent socket routines should not need to be accessed by the terminal simulators. +\par }\pard \widctlpar\adjustright {\f1 \par }} \ No newline at end of file diff --git a/simh_doc.txt b/simh_doc.txt index 00b0bc99..ceefdd8b 100644 --- a/simh_doc.txt +++ b/simh_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik -Subj: Simulator Usage, V2.6b -Date: 15-Sep-01 +Subj: Simulator Usage, V2.7 +Date: 30-Sep-01 COPYRIGHT NOTICE @@ -54,30 +54,33 @@ in scp_tty.c and scp_sock.c. To compile the simulators on VMS, use these commands (note that separate compilations are required for each of the 18b PDP's): - $ cc pdp8_*.c,scp.c,scp_tty.c ! PDP-8 - $ link/exec=pdp8 pdp8_*.obj,scp.obj,scp_tty.obj + $ cc pdp8_*.c,scp.c,scp_tty.c,sim_*.c ! PDP-8 + $ link/exec=pdp8 pdp8_*.obj,scp.obj,scp_tty.obj,sim_*.obj - $ cc pdp11_*.c,scp.c,scp_tty.c ! PDP-11 - $ link/exec=pdp11 pdp11_*.obj,scp.obj,scp_tty.obj + $ cc pdp11_*.c,scp.c,scp_tty.c,sim_*.c ! PDP-11 + $ link/exec=pdp11 pdp11_*.obj,scp.obj,scp_tty.obj,sim_*.obj - $ cc nova_*.c,scp.c,scp_tty.c ! Nova - $ link/exec=nova nova_*.obj,scp.obj,scp_tty.obj + $ cc nova_*.c,scp.c,scp_tty.c,sim_*.c ! Nova + $ link/exec=nova nova_*.obj,scp.obj,scp_tty.obj,sim_*.obj - $ cc pdp1_*.c,scp.c,scp_tty.c ! PDP-1 + $ cc pdp1_*.c,scp.c,scp_tty.c ! PDP-1 $ link/exec=pdp1 pdp1_*.obj,scp.obj,scp_tty.obj - $ cc/define=PDP{4,7,9,15} pdp18b_*.c,scp.c,scp_tty.c - $ link/exec=pdp{4,7,9,15} pdp18b_*.obj,scp.obj,scp_tty.obj + $ cc/define=PDP{4,7,9,15} pdp18b_*.c,scp.c,scp_tty.c,sim_*.c + $ link/exec=pdp{4,7,9,15} pdp18b_*.obj,scp.obj,scp_tty.obj,sim_*.obj - $ cc i1401_*.c,scp.c,scp_tty.c ! IBM 1401 + $ cc i1401_*.c,scp.c,scp_tty.c ! IBM 1401 $ link/exec=i1401 i1401_*.obj,scp.obj,scp_tty.obj - $ cc hp2100_*.c,scp.c,scp_tty.c ! HP 2100 + $ cc hp2100_*.c,scp.c,scp_tty.c ! HP 2100 $ link/exec=hp2100 hp2100_*.obj,scp.obj,scp_tty.obj - $ cc id4_*.c,scp.c,scp_tty.c ! Interdata 4 + $ cc id4_*.c,scp.c,scp_tty.c ! Interdata 4 $ link/exec=id4 id4_*.obj,scp.obj,scp_tty.obj + $ cc h316_*.c,scp.c,scp_tty.c ! Honeywell 316 + $ link/exec=h316 h316_*.obj,scp.obj,scp_tty.obj + On version of VMS prior to 6.2, the simulators must then be defined as foreign commands so that they can be started by name. @@ -86,14 +89,15 @@ the POSIX compliant TERMIOS interface (including Linux and Mac OS X), use the following commands (note that separate compilations are required for each of the 18b PDP's): - % cc pdp8_*.c scp*.c -lm -o pdp8 - % cc pdp11_*.c scp*.c -lm -o pdp11 - % cc nova_*.c scp*.c -lm -o nova + % cc pdp8_*.c scp*.c sim_*.c -lm -o pdp8 + % cc pdp11_*.c scp*.c sim_*.c -lm -o pdp11 + % cc nova_*.c scp*.c sim_*.c -lm -o nova % cc pdp1_*.c scp*.c -o pdp1 - % cc -DPDP{4,7,9,15} pdp18b_*.c scp*.c -lm -o pdp{4,7,9,15} + % cc -DPDP{4,7,9,15} pdp18b_*.c scp*.c sim_*.c -lm -o pdp{4,7,9,15} % cc i1401_*.c scp*.c -o i1401 % cc hp2100_*.c scp*.c -o hp2100 % cc id4_*.c scp*.c -o id4 + % cc h316_*.c scp*.c -o h316 These commands should work with most UNIX variants. If your UNIX only supports the old BSD terminal interface, add -DBSDTTY to each command. @@ -104,7 +108,7 @@ The PDP-10 simulator requires 64b support in the simulator and in the simulator control package (SCP). To turn on 64b support, add the symbol USE_INT64 to the command line: - % cc -DUSE_INT64 pdp10_*.c,scp*.c -lm -o pdp10 + % cc -DUSE_INT64 pdp10_*.c scp*.c sim_*.c -lm -o pdp10 Since 64b integer declarations vary, sim_defs.h has conditional declarations for Windows (_int64) and Digital UNIX (long). The default @@ -115,12 +119,20 @@ To compile the simulators on Windows 9x/ME/NT/2000 and Visual C++, each simulator must be set up as a separate project. Under the VC++ file menu, select New, select Project Workspace, select Console Application, and type in the name of the simulator. In the project -files view, select Add Files To Project and add in all the files for -that simulator (e.g., all files beginning nova_ for the Nova), plus -sim_defs.h, scp.c, and scp_tty.c. If the project requires the DZ11, -also add in scp_sock.h and scp_sock.c. If the project requires a -command line switch, add the switches to the C/C++ tab of the -Configuration dialog. The simulator should then build properly. +files view, select Add Files To Project and add in the required files: + + - all simulators: sim_defs.h, sim_rev.h, scp.c, scp_tty + - all simulators: simulator specific files (e.g., all + files beginning with nova_* for the Nova) + - PDP-10, PDP-11: dec_dz.h + - PDP-8, PDP-10, PDP-11, PDP-18b, Nova: sim_sock.h, + sim_sock.c, sim_txmr.h, sim_txmr.c + +If the project requires 64b support, add the switch -DUSE_INT64 to +the C/C++ tab of the Configuration dialog. If the project includes +Telnet-based terminals, add the appropriate Winsock library to the +library search list (Wsock32.dll for VC++ V4.) The simulator should +then build properly. To start the simulator, simply type its name. The simulator takes one optional argument, a startup command file. If specified, this @@ -136,6 +148,7 @@ for example, disk sizes. % i1401 (cr) or % hp2100 (cr) or % id4 (cr) or + % h316 (cr) or % pdp10 (cr) The simulator types out its name and version, executes the commands @@ -234,8 +247,16 @@ unit. The ATTACH (abbreviation AT) command associates a unit and a file: If the file does not exist, it is created, and an appropriate message is printed. +For Telnet-based terminal emulators, the ATTACH command associates the +master unit with a TCP/IP port: + + sim> ATTACH (cr) + +The port is a decimal number between 1 and 65535 and should not used +by standard TCP/IP protocols. + The DETACH (abbreviation DET) command breaks the association between a -unit and a file and closes the file: +unit and a file, or between a unit and a port: sim> DETACH ALL(cr) -- detach all units sim> DETACH (cr) -- detach specified unit @@ -463,6 +484,7 @@ CPU PDP-8/E CPU with 32KW of memory - KM8E memory management and timeshare control PTR,PTP PC8E paper tape reader/punch TTI,TTO KL8E console terminal +TTI1-4,TTO1-4 KL8JA additional terminals LPT LE8E line printer CLK DK8E line frequency clock (also PDP-8/A compatible) RK RK8E/RK05 cartridge disk controller with four drives @@ -605,7 +627,7 @@ Error handling is as follows: 4.2.3 KL8E Terminal Input (TTI) -The terminal input (TTI) reads from the controling console port. The +The terminal input (TTI) polls the console keyboard for input. The input side has one option, UC; when set, it automatically converts lower case input to upper case. This is required by OS/8 and is on by default. @@ -622,7 +644,7 @@ The terminal input implements these registers: 4.2.4 KL8E Terminal Output (TTO) -The terminal output (TTO) writes to the controling console port. It +The terminal output (TTO) writes to the simulator console window. It implements these registers: name size comments @@ -676,6 +698,52 @@ The real-time clock (CLK) implements these registers: The real-time clock autocalibrates; the clock interval is adjusted up or down so that the clock tracks actual elapsed time. +4.2.7 KL8JA Additional Terminals (TTI1-4, TTO1-4) + +Each additional terminal consists of two independent devices, TTIn and +TTOn. The entire set is modelled as a terminal multiplexor, with TTI1 +as the master unit. The additional terminals perform input and output +through Telnet sessions connected to a user-specified port. The ATTACH +command specifies the port to be used: + + ATTACH TTI1 (cr) -- set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. + +Once TTI1 is attached and the simulator is running, the terminals listen +for connections on the specified port. They assume that the incoming +connections are Telnet connections. The connections remain open until +disconnected either by the Telnet client, or by a DETACH TTI1 command. + +The SHOW TTI1 command displays the current connections to the additional +terminals. + +The input devices (TTI1-4) implement these registers: + + name size comments + + BUF 8 last data item processed + DONE 1 device done flag + ENABLE 1 interrupt enable flag + INT 1 interrupt pending flag + POS 31 number of characters input + TIME 24 keyboard polling interval + +The output devices (TTO1-4) implement these registers: + + name size comments + + BUF 8 last data item processed + DONE 1 device done flag + ENABLE 1 interrupt enable flag + INT 1 interrupt pending flag + POS 31 number of characters output + TIME 24 time from I/O initiation to interrupt + +The additional terminals do not support save and restore. All open +connections are lost when the simulator shuts down or TTI1 is detached. + 4.3 RK8E Cartridge Disk (RK) RK8E options include the ability to make units write enabled or write locked: @@ -923,6 +991,7 @@ controlled by command line switches: -a display as ASCII character -c display as (sixbit) character string + -t display as (TSS/8 sixbit) character string -m display instruction mnemonics Input parsing is controlled by the first character typed in or by command @@ -930,6 +999,7 @@ line switches: ' or -a ASCII character " or -c two character sixbit string + # or -t two character TSS/8 sixbit string alphabetic instruction mnemonic numeric octal number @@ -985,6 +1055,7 @@ PTR,PTP PC11 paper tape reader/punch TTI,TTO DL11 console terminal LPT LP11 line printer CLK line frequency clock +DZ DZ11 8-line terminal multiplexor RK RK11/RK05 cartridge disk controller with eight drives RL RLV12/RL01(2) cartridge disk controller with four drives RP RM02/03/05/80, RP04/05/06/07 Massbus style controller @@ -994,9 +1065,9 @@ TC TC11/TU56 DECtape controller with eight drives TM TM11/TU10 magnetic tape controller with eight drives TS TS11/TSV05 magnetic tape controller with one drive -The RK, RL, RP, RX, TC, TM, and TS devices can be DISABLEd. The PDP-11 can -support either a TM11 or a TS11, but not both, since they use the same I/O -addresses. The simulator defaults to the TM11. To change the magtape, +The DZ, RK, RL, RP, RX, TC, TM, and TS devices can be DISABLEd. The PDP-11 +can support either a TM11 or a TS11, but not both, since they use the same +I/O addresses. The simulator defaults to the TM11. To change the magtape, ENABLE TM11 enable TM11 and disable TS11 ENABLE TS11 enable TS11 and disable TM11 @@ -1164,7 +1235,7 @@ Error handling is as follows: 5.2.3 KL11 Terminal Input (TTI) -The terminal input (TTI) reads from the controling console port. It +The terminal input (TTI) polls the console keyboard for input. It implements these registers: name size comments @@ -1180,7 +1251,7 @@ implements these registers: 5.2.4 KL11 Terminal Output (TTO) -The terminal output (TTO) writes to the controling console port. It +The terminal output (TTO) writes to the simulator console window. It implements these registers: name size comments @@ -1239,6 +1310,45 @@ The clock (CLK) implements these registers: The real-time clock autocalibrates; the clock interval is adjusted up or down so that the clock tracks actual elapsed time. +5.2.7 DZ11 Terminal Multiplexor (DZ) + +The DZ11 is an 8-line terminal multiplexor. The terminal lines perform +input and output through Telnet sessions connected to a user-specified +port. The ATTACH command specifies the port to be used: + + ATTACH {-am} DZ (cr) -- set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. The optional switch -m turns on the DZ11's +modem controls; the optional switch -a turns on active disconnects +(disconnect session if computer clears Data Terminal Ready). + +Once the DZ is attached and the simulator is running, the DZ will listen +for connections on the specified port. It assumes that the incoming +connections are Telnet connections. The connection remains open until +disconnected either by the simulated program or by the Telnet client. + +The SHOW DZ command displays the current connections to the DZ. + +The DZ11 implements these registers: + + name size comments + + CSR 16 control/status register + RBUF 16 receive buffer + LPR 16 line parameter register + TCR 16 transmission control register + MSR 16 modem status register + TDR 16 transmit data register + SAENB 1 silo alarm enabled + MDMTCL 1 modem control enabled + AUTODS 1 autodisconnect enabled + RPOS0..7 32 count of characters received + TPOS0..7 32 count of characters transmitted + +The DZ11 does not support save and restore. All open connections are +lost when the simulator shuts down or the DZ is detached. + 5.3 RK11/RK05 Cartridge Disk (RK) RK11 options include the ability to make units write enabled or write locked: @@ -1390,7 +1500,7 @@ a DEC standard 044 compliant bad block table on the last track: SET RPn RP06 set size to RP06 SET RPn RP07 set size to RP07 SET RPn AUTOSIZE set size based on file size at attach - SET RLn BADBLOCK write bad block table on last track + SET RPn BADBLOCK write bad block table on last track The size options can be used only when a unit is not attached to a file. The bad block option can be used only when a unit is attached to a file. Units @@ -1402,26 +1512,29 @@ The RP controller implements these registers: name size comments RPCS1 16 control/status 1 - RPCS2 16 control/status 2 - RPCS3 16 control/status 3 RPWC 16 word count RPBA 16 bus address - RPBAE 6 bus address extension RPDA 16 desired surface, sector - RPDC 8 desired cylinder + RPCS2 16 control/status 2 RPOF 16 offset - RPDS0..7 16 drive status, drives 0-7 - RPDE0..7 16 drive error, drives 0-7 + RPDC 8 desired cylinder RPER2 16 error status 2 RPER3 16 error status 3 - RPDB 16 data buffer + RPEC1 16 ECC syndrome 1 + RPEC2 16 ECC syndrome 2 RPMR 16 maintenance register + RPDB 16 data buffer + RPBAE 6 bus address extension + RPCS3 16 control/status 3 + RPIFF 1 transfer complete interrupt request flop INT 1 interrupt pending flag SC 1 special condition (CSR1<15>) DONE 1 device done flag (CSR1<7>) IE 1 interrupt enable flag (CSR1<6>) STIME 24 seek time, per cylinder RTIME 24 rotational delay + RPDS0..7 16 drive status, drives 0-7 + RPDE0..7 16 drive error, drives 0-7 STOP_IOE 1 stop on I/O error Error handling is as follows: @@ -1568,6 +1681,7 @@ The magnetic tape controller implements these registers: WADH 16 write char packet high address WLNT 16 write char packet length WOPT 16 write char packet options + WXOPT 16 write char packet extended options ATTN 1 attention message pending BOOT 1 boot request pending OWNC 1 if set, tape owns command buffer @@ -1732,22 +1846,6 @@ control registers for the interrupt system. 6.2 Programmed I/O Devices -The Nova can have two terminals (TTI/TTO, TTI1/TTO1). At any moment -only one terminal is active. It can receive input from the keyboard; -it can output to the simulator window. The inactive console cannot -receive input from the keyboard and outputs to an internal buffer -(maximum 4K characters). - -Control is switched among terminals with a SET TTI{n} CONSOLE or SET -TTO{n} CONSOLE command: - - At startup, active console is TTI/TTO - SET TTI1 CONSOLE Active console is now TTI1/TTO1 - SET TTO CONSOLE Active console is now TTI/TTO - -When control is switched to an inactive terminal, any buffered output -is printed when simulation resumes. - 6.2.1 Paper Tape Reader (PTR) The paper tape reader (PTR) reads data from a disk file. The POS @@ -1807,23 +1905,19 @@ Error handling is as follows: OS I/O error x report error and stop -6.2.3 Terminal Input (TTI, TTI1) +6.2.3 Terminal Input (TTI) -The active terminal input polls the console keyboard for input. The -inactive terminal input cannot receive characters. Terminal input -options include the ability to set limited Dasher compatibility mode -or ANSI standard mode: +The terminal input polls the console keyboard for input. Terminal +input options include the ability to set ANSI mode or limited Dasher +compatibility mode: SET TTI ANSI normal mode SET TTI DASHER Dasher mode - SET TTO ANSI normal mode - SET TTO DASHER Dasher mode -Setting either TTI (TTI1) or TTO (TTO1) changes both devices. In Dasher -mode, carriage return is changed to newline on input, and ^X is changed -to backspace. +Setting either TTI or TTO changes both devices. In Dasher mode, carriage +return is changed to newline on input, and ^X is changed to backspace. -The terminal inputs implement these registers: +The terminal input implements these registers: name size comments @@ -1835,22 +1929,19 @@ The terminal inputs implement these registers: POS 31 number of characters input TIME 24 keyboard polling interval -6.2.4 Terminal Output (TTO, TTO1) +6.2.4 Terminal Output (TTO) -The active terminal output writes to the simulator window. The inactive -terminal output buffers characters. Terminal output options include the -the ability to set limited Dasher compatibility mode or ANSI mode: +The terminal output writes to the simulator console window. Terminal +output options include the the ability to set ANSI mode or limited +Dasher compatibility mode: - SET TTI ANSI normal mode - SET TTI DASHER Dasher mode SET TTO ANSI normal mode SET TTO DASHER Dasher mode -Setting either TTI (TTI1) or TTO (TTO1) changes both devices. In Dasher -mode, carriage return is changed to newline on input, and ^X is changed -to backspace. +Setting either TTI or TTO changes both devices. In Dasher mode, carriage +return is changed to newline on input, and ^X is changed to backspace. -The terminal outputs implement these registers: +The terminal output implements these registers: name size comments @@ -1937,6 +2028,61 @@ Error handling is as follows: OS I/O error x report error and stop +6.2.8 Second Terminal (TTI1, TTO1) + +The second terminal consists of two independent devices, TTI1 and TTO1. +The additional terminal performs input and output through a Telnet session +connecting into a user-specified port. The ATTACH command specifies the +port to be used: + + ATTACH TTI1 (cr) -- set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. + +Once TTI1 is attached and the simulator is running, the terminal listens +for a connection on the specified port. It assumes that the incoming +connection is a Telnet connection. The connection remain opens until +disconnected by the Telnet client, or by a DETACH TTI1 command. + +The second terminal has two options, recognized on both devices, for +setting limited Dasher-compatibility mode or ANSI mode: + + SET TTI1 ANSI normal mode + SET TTI1 DASHER Dasher mode + SET TTO1 ANSI normal mode + SET TTO1 DASHER Dasher mode + +Setting either TTI1 or TTO1 changes both devices. In Dasher mode, carriage +return is changed to newline on input, and ^X is changed to backspace. + +The SHOW TTI1 command displays the current connection to the second +terminal. + +The second terminal input implements these registers: + + name size comments + + BUF 8 last data item processed + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 interrupt disable flag + INT 1 interrupt pending flag + POS 31 number of characters input + TIME 24 keyboard polling interval + +The second terminal output implements these registers: + + name size comments + + BUF 8 last data item processed + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 interrupt disable flag + INT 1 interrupt pending flag + POS 31 number of characters output + TIME 24 time from I/O initiation to interrupt + 6.3 Fixed Head Disk (DK) The fixed head disk controller implements these registers: @@ -2261,8 +2407,8 @@ Error handling is as follows: 7.2.3 Terminal Input (TTI) -The terminal input (TTO) reads from the controling console port. -It implements these registers: +The terminal input (TTI) polls the console keyboard for input. It +implements these registers: name size comments @@ -2273,7 +2419,7 @@ It implements these registers: 7.2.4 Terminal Output (TTO) -The terminal output (TTO) writes to the controling console port. +The terminal output (TTO) writes to the simulator console window. It implements these registers: name size comments @@ -2629,22 +2775,6 @@ the PDP-7 and PDP-9, 17b for the PDP-15). 8.2 Programmed I/O Devices -The PDP-9 and PDP-15 have two terminals (TTI/TTO, TTI1/TTO1). At any -moment, only one terminal is active. It can receive input from the -keyboard; it can output to the simulator window. The inactive console -cannot receive input from the keyboard and outputs to an internal buffer -(maximum 4K characters). - -Control is switched among terminals with a SET TTI{n} CONSOLE or SET -TTO{n} CONSOLE command: - - At startup, active console is TTI/TTO - SET TTI1 CONSOLE Active console is now TTI1/TTO1 - SET TTO CONSOLE Active console is now TTI/TTO - -When control is switched to an inactive terminal, any buffered output -is printed when simulation resumes. - 8.2.1 Paper Tape Reader (PTR) The paper tape reader (PTR) reads data from a disk file. The POS @@ -2707,20 +2837,19 @@ Error handling is as follows: OS I/O error x report error and stop -8.2.3 Terminal Input (TTI, TTI1) +8.2.3 Terminal Input (TTI) -The active terminal input polls the console keyboard for input. The -inactive terminal input cannot receive characters. The terminal inputs -have one option, UC; when set, it automatically converts lower case input -to upper case. +The terminal input (TTI) polls the console keyboard for input. The +input side has one option, UC; when set, it automatically converts lower +case input to upper case. -The PDP-9 and PDP-15 operated the primary terminal (TTI/TTO), by default, -as half-duplex. For backward compatibility, on the PDP-9 and PDP-15 +The PDP-9 and PDP-15 operate the console terminal (TTI/TTO), by default, +as half duplex. For backward compatibility, on the PDP-9 and PDP-15 the first terminal input has a second option, FDX; when set, it operates the terminal input in full-duplex mode. The second terminal is always full duplex. -The terminal inputs implement these registers: +The terminal input implements these registers: name size comments @@ -2730,14 +2859,13 @@ The terminal inputs implement these registers: POS 31 number of characters input TIME 24 keyboard polling interval -8.2.4 Terminal Output (TTO, TTO1) +8.2.4 Terminal Output (TTO) -The active terminal output writes to the simulator window. The inactive -terminal output buffers characters. The terminal outputs have one option, -UC; when set, it suppresses lower case output (so that ALTMODE is not -echoed as }). +The terminal output (TTO) writes to the simulator console window. The +terminal output has one option, UC; when set, it suppresses lower case +output (so that ALTMODE is not echoed as }). -The terminal outputs implement these registers: +The terminal output implements these registers: name size comments @@ -2822,6 +2950,51 @@ The real-time clock (CLK) implements these registers: The real-time clock autocalibrates; the clock interval is adjusted up or down so that the clock tracks actual elapsed time. +8.2.7 Second Terminal (TTI1, TTO1) + +The second terminal consists of two independent devices, TTI1 and TTO1. +The second terminal performs input and output through a Telnet session +connected to a user-specified port. The ATTACH command specifies the +port to be used: + + ATTACH TTI1 (cr) -- set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. + +Once TTI1 is attached and the simulator is running, the terminal listens +for a connection on the specified port. It assumes that the incoming +connection is a Telnet connection. The connection remain opens until +disconnected by the Telnet client, or by a DETACH TTI1 command. + +The second terminal input has one option, UC; when set, it automatically +converts lower case input to upper case. The second terminal output also +has one option, UC; when set, it suppresses lower case output (so that +ALTMODE is not echoed as }). + +The SHOW TTI1 command displays the current connection to the second +terminal. + +The second terminal input implements these registers: + + name size comments + + BUF 8 last data item processed + INT 1 interrupt pending flag + DONE 1 device done flag + POS 31 number of characters input + TIME 24 keyboard polling interval + +The second terminal output implements these registers: + + name size comments + + BUF 8 last data item processed + INT 1 interrupt pending flag + DONE 1 device done flag + POS 31 number of chararacters output + TIME 24 time from I/O initiation to interrupt + 8.3 RP15/RP02 Disk Pack (RP) RP15 options include the ability to make units write enabled or write locked: @@ -3384,8 +3557,8 @@ Error handling is as follows: 9.4 1407 Inquiry Terminal (INQ) The IBM 1407 inquiry terminal (INQ) is a half-duplex console. It polls -the controling keyboard of the simulator periodically for inquiry requests. -The inquiry terminal registers are: +the console keyboard periodically for inquiry requests. The inquiry +terminal registers are: name size comments @@ -3725,11 +3898,11 @@ Error handling is as follows: 10.4.3 12631C Buffered Teleprinter (TTY) The console teleprinter has three units: keyboard (unit 0), printer -(unit 1), and punch (unit 2). The keyboard reads from, and the -printer writes to, the controlling console port. The punch writes -to a disk file. The keyboard has one option, UC; when set, it -automatically converts lower case input to upper case. This is on -by default. +(unit 1), and punch (unit 2). The keyboard reads from the console +keyboard; the printer writes to the simulator console window. The +punch writes to a disk file. The keyboard has one option, UC; when +set, it automatically converts lower case input to upper case. This +is on by default. The terminal implements these registers: @@ -4076,9 +4249,10 @@ Error handling is as follows: 11.3 Teletype (TT) -The teletype reads and writes to the controlling console port. The -keyboard has one option, UC; when set, it automatically converts lower -case input to upper case. This is on by default. +The teletype keyboard reads from the console keyboard; the teletype +printer writes to the simulator console window. The keyboard has +one option, UC; when set, it automatically converts lower case +input to upper case. This is on by default. name size comments @@ -4158,12 +4332,13 @@ UBA Unibus adapters (translation maps) FE console TIM timer PTR,PTP PC11 paper tape reader/punch +DZ DZ11 8-line terminal multiplexor LP20 LP20 line printer RP RH11/RP04/RP05/RP06/RP07/RM03/RM05/RM80 controller with eight drives TU RH11/TM02/TU45 controller with eight drives -The PTR/PTP are initially DISABLEd. No other device can be DISABLEd. +The PTR/PTP are initially DISABLEd. The DZ11 can also be DISABLEd. The PDP-10 simulator implements several unique stop condition: @@ -4371,7 +4546,54 @@ Error handling is as follows: OS I/O error x report error and stop -12.8 RH11 Adapter, RM02/03/05/80, RP04/05/06/07 drives (RP) +12.8 DZ11 Terminal Multiplexor (DZ) + +The DZ11 is an 8-line terminal multiplexor. The terminal lines perform +input and output through Telnet sessions connected to a user-specified +port. The ATTACH command specifies the port to be used: + + ATTACH {-am} DZ (cr) -- set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. The optional switch -m turns on the DZ11's +modem controls; the optional switch -a turns on active disconnects +(disconnect session if computer clears Data Terminal Ready). + + + ATTACH {-m} DZ (cr) -- set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. The optional switch -m turns on the DZ11's +modem controls; the optional switch -a turns on active disconnects +(disconnect session if computer clears Data Terminal Ready). + +Once the DZ is attached and the simulator is running, the DZ will listen +for connections on the specified port. It assumes that the incoming +connections are Telnet connections. The connection remains open until +disconnected either by the simulated program or by the Telnet client. + +The SHOW DZ command displays the current connections to the DZ. + +The DZ11 implements these registers: + + name size comments + + CSR 16 control/status register + RBUF 16 receive buffer + LPR 16 line parameter register + TCR 16 transmission control register + MSR 16 modem status register + TDR 16 transmit data register + SAENB 1 silo alarm enabled + MDMTCL 1 modem control enabled + AUTODS 1 autodisconnect enabled + RPOS0..7 32 count of characters received + TPOS0..7 32 count of characters transmitted + +The DZ11 does not support save and restore. All open connections are +lost when the simulator shuts down or the DZ is detached. + +12.9 RH11 Adapter, RM02/03/05/80, RP04/05/06/07 drives (RP) The RP controller implements the Massbus 18b (RH11) direct interface for large disk drives. It is more abstract than other device simulators, with @@ -4401,26 +4623,27 @@ The RP controller implements these registers: name size comments RPCS1 16 control/status 1 - RPCS2 16 control/status 2 - RPCS3 16 control/status 3 RPWC 16 word count RPBA 16 bus address - RPBAE 6 bus address extension RPDA 16 desired surface, sector - RPDC 8 desired cylinder + RPCS2 16 control/status 2 RPOF 16 offset - RPDS0..7 16 drive status, drives 0-7 - RPDE0..7 16 drive error, drives 0-7 + RPDC 8 desired cylinder RPER2 16 error status 2 RPER3 16 error status 3 - RPDB 16 data buffer + RPEC1 16 ECC syndrome 1 + RPEC2 16 ECC syndrome 2 RPMR 16 maintenance register + RPDB 16 data buffer + RPIFF 1 transfer complete interrupt request flop INT 1 interrupt pending flag SC 1 special condition (CSR1<15>) DONE 1 device done flag (CSR1<7>) IE 1 interrupt enable flag (CSR1<6>) STIME 24 seek time, per cylinder RTIME 24 rotational delay + RPDS0..7 16 drive status, drives 0-7 + RPDE0..7 16 drive error, drives 0-7 STOP_IOE 1 stop on I/O error Error handling is as follows: @@ -4434,11 +4657,11 @@ Error handling is as follows: OS I/O error x report error and stop -12.9 RH11/TM02/TU45 Magnetic Tape (TU) +12.10 RH11 Adapter, TM02 Formatter, TU45 Magnetic Tape (TU) The magnetic tape simulator simulates an RH11 Massbus adapter with one -TM02 formatter and up to eight TU45. Magnetic tape options include the -ability to make units write enabled or locked. +TM02 formatter and up to eight TU45 drives. Magnetic tape options include +the ability to make units write enabled or locked. SET TUn LOCKED set unit n write locked SET TUn ENABLED set unit n write enabled @@ -4479,7 +4702,7 @@ Error handling is as follows: OS I/O error report error and stop -12.10 LP20 DMA Line Printer (LP20) +12.11 LP20 DMA Line Printer (LP20) The LP20 is a DMA-based line printer controller. There is one line printer option to clear the vertical forms unit (VFU). @@ -4521,7 +4744,7 @@ Error handling is as follows: OS I/O error x report error and stop -12.11 Symbolic Display and Input +12.12 Symbolic Display and Input The PDP-10 simulator implements symbolic display and input. Display is controlled by command line switches: @@ -4701,9 +4924,10 @@ Error handling is as follows: 13.2.3 316/516-33 Console Teletype (TTY) -The terminal reads and writes to the controlling console port. It has -one option, UC; when set, it automatically converts lower case input -to upper case. This is on by default. +The terminal reads from the console keyboard and writes to the +simulator console window. The terminal has one option, UC; when +set, the terminal automatically converts lower case input to upper +case. This is on by default. The terminal these registers: @@ -4865,7 +5089,7 @@ use 578 blocks of 256 32b words. Each 32b word contains 18b (6 lines) of data. PDP-8 DECtapes use 1474 blocks of 129 16b words. Each 16b word contains 12b (4 lines) of data. Note that PDP-8 OS/8 does not use the 129th word of each block, and OS/8 DECtape dumps contain only 128 -words per block. A utility, DSOS8CVT.C, is provided to convert OS/8 +words per block. A utility, DTOS8CVT.C, is provided to convert OS/8 DECtape dumps to simulator format. A known problem in DECtape format is that when a block is recorded in @@ -4932,28 +5156,47 @@ legend: y = runs operating system or sample program Revision History (since Rev 1.1) -Rev 2.6b, Jul, 01 +Rev 2.7, Sep, 01 + Added DZ11 (from Thord Nilson and Art Krewat) + to PDP-11, PDP-10 + Added additional terminals to PDP-8 + Added TSS/8 packed character format to PDP-8 + Added sim_sock and sim_tmxr libraries + Added sim_qcount and simulator exit detach all facilities + Added Macintosh sim_sock support (from Peter Schorn) + Added simulator revision level, SHOW version + Changed int64/uint64 to t_int64/t_uint64 for Windoze + Fixed bug in PDP-11 interrupt acknowledge + Fixed bugs in PDP-11 TS NXM check, boot code, error status; + added extended characteristics and status + Fixed bug in PDP-11 TC stop, stop all functions + Fixed receive interrupt while disconnected bug in DZ11 + Fixed multi-unit operation bugs, interrupt bugs in + PDP-11 RP, PDP-10 RP, PDP-10 TU + Fixed carrier detect bug in PDP-11, PDP-10 DZ + Fixed bug in PDP-8 reset routine + Fixed conditional in PDP-18b CPU + Fixed SC = 0 bug in PDP-18b EAE + Fixed bug in PDP-7 LPT + Upgraded Nova second terminal to use sim_tmxr + Upgraded PDP-18b second terminal to use sim_tmxr + Upgraded PDP-11 LTC to full KW11-L + Removed hack multiple console support + +Rev 2.6b, Aug, 01 Added H316/516 simulator Added Macintosh support from Louis Chrétien, Peter Schorn, and Ben Supnik Added bad block table option to PDP-11 RL, RP + Removed register in declarations Fixed bugs found by Peter Schorn - Endian error in PDP-10, PDP-11 RP - Space reverse error in PDP-11 TS - Symbolic input in 1401 + -- endian error in PDP-10, PDP-11 RP + -- space reverse error in PDP-11 TS + -- symbolic input in 1401 Fixed bug in PDP-1 RIM loader found by Derek Peschel Fixed bug in Nova fixed head disk - Removed register in declarations Rev 2.6a, Jun, 01 - Fixed bug (found by Dave Conroy) in big-endian I/O - Fixed DECtape reset in PDP-8, PDP-11, PDP-9/15 - Fixed RIM loader PC handling in PDP-9/15 - Fixed indirect pointers in PDP-10 paging - Fixed SSC handling in PDP-10 TM02/TU45 - Fixed JMS to non-existent memory in PDP-8 - Fixed error handling on command file - Increased size of string buffers for long path names Added PDP-9, PDP-15 API option Added PDP-9, PDP-15 second terminal Added PDP-10 option for TOPS-20 V4.1 bug fix @@ -4961,6 +5204,14 @@ Rev 2.6a, Jun, 01 Added console logging Added multiple console support Added comment recognition + Increased size of string buffers for long path names + Fixed bug in big-endian I/O found by Dave Conroy + Fixed DECtape reset in PDP-8, PDP-11, PDP-9/15 + Fixed RIM loader PC handling in PDP-9/15 + Fixed indirect pointers in PDP-10 paging + Fixed SSC handling in PDP-10 TM02/TU45 + Fixed JMS to non-existent memory in PDP-8 + Fixed error handling on command file Rev 2.6, May, 01 Added ENABLE/DISABLE devices @@ -4989,31 +5240,31 @@ Rev 2.6, May, 01 Updated copyright notices, fixed comments Rev 2.5a, Dec, 00 - Fixed SCP handling of devices without units - Fixed FLG, FBF initialization in many HP peripherals Added CMD flop to HP paper tape and line printer Added status input for HP paper tape punch and TTY + Added Dutch Owens' 1401 mag tape boot routine + Added Bruce Ray's Nova plotter and second terminal modules + Added Charles Owen's Eclipse CPU support + Added PDP-9/PDP-15 RIM/BIN loader support + Added PDP-9/PDP-15 extend/bank initial state registers + Added PDP-9/PDP-15 half/full duplex support + Moved software documentation to a separate file + Fixed SCP handling of devices without units + Fixed FLG, FBF initialization in many HP peripherals Fixed 1401 bugs found by Dutch Owens -- 4, 7 char NOPs are legal -- 1 char B is chained BCE -- MCE moves whole character, not digit, after first - Added Dutch Owens' 1401 mag tape boot routine Fixed Nova bugs found by Bruce Ray -- traps implemented on Nova 3 as well as Nova 4 -- DIV and DIVS 0/0 set carry -- RETN sets SP from FP at outset -- IORST does not clear carry -- Nova 4 implements two undocumented instructions - Added Bruce Ray's Nova plotter and second terminal modules - Added Charles Owen's Eclipse CPU support Fixed bugs in 18b PDP's -- XCT indirect address calculation -- missing index instructions in PDP-15 -- bank mode handling in PDP-15 - Added PDP-9/PDP-15 RIM/BIN loader support - Added PDP-9/PDP-15 extend/bank initial state registers - Added PDP-9/PDP-15 half/full duplex support - Moved software documentation to a separate file Rev 2.5, Nov, 00 Removed Digital and Compaq from copyrights, as @@ -5072,6 +5323,8 @@ Rev 2.3a, Nov, 97 Fixed endian dependence in 18b PDP RIM loader Rev 2.3, Mar, 97 + Added PDP-11 RP + Added PDP-1 Changed UNIX terminal I/O to TERMIOS Changed magtape format to double ended Changed PDP-8 current page mnemonic from T to C @@ -5085,8 +5338,6 @@ Rev 2.3, Mar, 97 Fixed bug in 18b PDP paper tape reader Fixed bug in PDP-4 console Fixed bug in PDP-4,7 line printer - Added PDP-11 RP - Added PDP-1 Rev 2.2d, Dec, 96 Added ADD/REMOVE commands @@ -5171,9 +5422,11 @@ Jay Jaeger IBM 1401 information Doug Jones PDP-8 information, simulator, and software Al Kossow HP 21xx, Varian 620, TI 990, DEC documentation and software Arthur Krewat DZ11 update for the PDP-10 +Mirian Crzig Lennox ITS and DZ11 debugging Don Lewine Nova documentation and legal permissions Tim Litt PDP-10 hardware documentation and schematics, tape images, and software sources +Tim Markson DZ11 debugging Scott McGregor PDP-11 UNIX legal permissions Jeff Moffatt HP 2100 information, documentation, and software Alec Muffett Solaris port testing @@ -5209,6 +5462,7 @@ David Waks PDP-8 ESI-X and PDP-7 SIM8 software Tom West Nova documentation Adrian Wise H316 simulator, documentation, and software John Wilson PDP-11 simulator and software +Joe Young RP debugging on Ultrix-11 and BSD In addition, the following companies have graciously licensed their software at no cost for hobbyist use: diff --git a/simh_swre.txt b/simh_swre.txt index 748acee4..d3cb2342 100644 --- a/simh_swre.txt +++ b/simh_swre.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: Sample Software Packages -Date: 31-May-01 +Date: 30-Sep-01 This memorandum documents the sample software packages available to run with the SIMH simulators. Many of these packages are available under @@ -88,6 +88,75 @@ Note that OS/8 only recognizes upper case characters. The first disk (drive 0) is the system disk; it also includes BASIC. The second disk (drive 1) includes FORTRAN. +1.4 PDP-8 TSS/8 + +TSS/8 is the PDP-8's timesharing system. It provides a program development +and execution environment for assembler, BASIC, and FORTRAN programs. TSS/8 +is provided as is, without fee, by Digital Equipment Corporation, for non- +commercial use only. My thanks to John Wilson of Dbit Inc, who provided +the disk image and the initialization tape source. + +Loading TSS/8 +------------- + +Note: your environment must have a functioning second Teletype; that is, you cannot +at present run Foreground/Background if your host system is VMS or OS/2. + +- Load the paper-tape bootstrap: + + sim> load tss8_init.bin + +- Mount the TSS/8 disk image of the RF08: + + sim> attach rf tss8_rf.dsk + +- Assign a TCP/IP port to the Telnet listener for the extra terminals: + + sim> attach tti1 -- 4000 typically works + +- Run the bootstrap: + + sim> run 24200 + +- TSS/8 will boot and go through its startup dialog + + LOAD, DUMP, START, ETC? START + MONTH-DAY-YEAR: mm:dd:yy -- numeric, yy in range [74:85] + HR:MIN - hh:mm -- numeric, 24 hour format + (type cr to get attention) + + . + + and is now ready for login. The list of accounts and passwords: + + PPN Password + [0,1] VH3M + [0,2] LXHE + [0,3] SHUG + [77,77] + [1,10] WBCN + [20,1] DT + [20,2] PT + [20,3] TSS8 + [20,4] EDIT + [20,5] 4TH + [1,50] JERK + +- Login using one of the existing accounts. The login command won't echo: + + .LOGIN 2 LXHE -- privileged library account + + TSS/8.24 JOB 01 [00,02] K00 23:23:06 + + SYSTEM IS DOWN, INC. + +- The system is now ready for commands. To get a directory listing: + + .R CAT + +- Other users can log in by connecting, from a Telnet client, to localhost + on the port specified in the attach tti1 command. + 2. PDP-11 2.1 UNIX V5, V6, V7 @@ -301,6 +370,69 @@ execution capabilities. To load and run ADSS/KM-15: 4.0000 * +6.3 Advanced Software System/Foreground Background + +Foreground/Background System +---------------------------- + +Note: your environment must have a functioning second Teletype; that is, you cannot +at present run Foreground/Background if your host system is VMS or OS/2. + +- Load the paper-tape bootstrap into upper memory: + + sim> load dec-15u.rim 77637 + + You specify the load address. + +- Verify that the bootstrap loaded correctly: + + sim> ex pc + PC: 077646 + +- Mount the Advanced Software System DECtape image on DECtape unit 0: + + sim> attach dt fb15_32k.dtp + +- Turn on the API option: + + sim> set cpu api + +- Assign a TCP/IP port to the Telnet listener for the second terminal: + + sim> assign tti1 -- 4000 typically works + +- Start a Telnet client to act as the second terminal and connect to + localhost on the specified port. + +- Run the bootstrap: + + sim> run + +- The DECtape will boot and print out + + F9/15 V4A + $ + + and is now ready for commands. Recognized commands include: + + D 0 list system device directory + R list device assignments + +- To activate the background, load IDLE into the foreground: + + $A DTA0 -4 + $GLOAD + FGLOAD V2A + >_IDLE + + Background terminal responds with + + B9/15 V4A + $ + + and is now ready for commands. + + 7. IBM 1401 7.1 Single Card "Koans"