From a7b623a1a81b3e159462f0a03bbabb5c9e6d20d2 Mon Sep 17 00:00:00 2001 From: Bob Supnik Date: Tue, 6 Nov 2001 20:54:00 -0800 Subject: [PATCH] simh v2.6a --- altair_sys.c | 3 + eclipse_cpu.c | 8 +- hp2100_sys.c | 4 + i1401_sys.c | 4 + id4_sys.c | 4 + nova_sys.c | 11 +- nova_tt.c | 18 +- nova_tt1.c | 61 +--- pdp10_cpu.c | 9 +- pdp10_defs.h | 34 +- pdp10_ksio.c | 13 +- pdp10_pag.c | 3 + pdp10_rp.c | 16 +- pdp10_sys.c | 4 + pdp11_cis.c | 19 +- pdp11_cpu.c | 3 +- pdp11_defs.h | 9 +- pdp11_fp.c | 4 +- pdp11_rk.c | 2 +- pdp11_rl.c | 6 +- pdp11_rp.c | 4 +- pdp11_sys.c | 14 +- pdp18b_cpu.c | 443 ++++++++++++++++---------- pdp18b_defs.h | 108 +++++-- pdp18b_drm.c | 15 +- pdp18b_rf.c | 2 +- pdp18b_stddev.c | 91 ++++-- pdp18b_sys.c | 79 +++-- pdp18b_tt1.c | 190 ++++++++++++ pdp1_stddev.c | 3 +- pdp1_sys.c | 8 +- pdp8_cpu.c | 17 +- pdp8_rf.c | 2 +- pdp8_sys.c | 4 + scp.c | 380 ++++++++++++++++------- scp_tty.c | 12 +- sim_defs.h | 17 +- simh.doc | 806 ++++++++++++++++++++++++++++-------------------- simh_doc.txt | 205 ++++++------ simh_swre.txt | 59 +++- 40 files changed, 1793 insertions(+), 901 deletions(-) create mode 100644 pdp18b_tt1.c diff --git a/altair_sys.c b/altair_sys.c index cfba428b..04788be1 100644 --- a/altair_sys.c +++ b/altair_sys.c @@ -30,6 +30,7 @@ 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 */ @@ -43,6 +44,8 @@ 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/eclipse_cpu.c b/eclipse_cpu.c index ae00be7a..c176b554 100644 --- a/eclipse_cpu.c +++ b/eclipse_cpu.c @@ -28,6 +28,7 @@ cpu Eclipse central processor + 01-Jun-01 RMS Added second terminal, plotter support 26-Apr-01 RMS Added device enable/disable support The register state for the Eclipse CPU is basically the same as @@ -436,7 +437,10 @@ extern int32 ptr (int32 pulse, int32 code, int32 AC); extern int32 ptp (int32 pulse, int32 code, int32 AC); extern int32 tti (int32 pulse, int32 code, int32 AC); extern int32 tto (int32 pulse, int32 code, int32 AC); +extern int32 tti1 (int32 pulse, int32 code, int32 AC); +extern int32 tto1 (int32 pulse, int32 code, int32 AC); extern int32 clk (int32 pulse, int32 code, int32 AC); +extern int32 plt (int32 pulse, int32 code, int32 AC); extern int32 lpt (int32 pulse, int32 code, int32 AC); extern int32 dsk (int32 pulse, int32 code, int32 AC); extern int32 dkp (int32 pulse, int32 code, int32 AC); @@ -455,7 +459,7 @@ struct ndev dev_table[64] = { { 0, 0, &nulldev }, { 0, 0, &nulldev }, { INT_TTI, PI_TTI, &tti }, { INT_TTO, PI_TTO, &tto }, /* 10 - 17 */ { INT_PTR, PI_PTR, &ptr }, { INT_PTP, PI_PTP, &ptp }, - { INT_CLK, PI_CLK, &clk }, { 0, 0, &nulldev }, + { INT_CLK, PI_CLK, &clk }, { INT_PLT, PI_PLT, &plt }, { 0, 0, &nulldev }, { INT_LPT, PI_LPT, &lpt }, { INT_DSK, PI_DSK, &dsk }, { 0, 0, &nulldev }, /* 20 - 27 */ { INT_MTA, PI_MTA, &mta }, { 0, 0, &nulldev }, @@ -469,7 +473,7 @@ struct ndev dev_table[64] = { { 0, 0, &nulldev }, { 0, 0, &nulldev }, { 0, 0, &nulldev }, { 0, 0, &nulldev }, { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, /* 50 - 57 */ + { INT_TTI1, PI_TTI1, &tti1 }, { INT_TTO1, PI_TTO1, &tto1 }, /* 50 - 57 */ { 0, 0, &nulldev }, { 0, 0, &nulldev }, { 0, 0, &nulldev }, { 0, 0, &nulldev }, { 0, 0, &nulldev }, { 0, 0, &nulldev }, diff --git a/hp2100_sys.c b/hp2100_sys.c index 1111b3e4..fdb20e0e 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. + 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 15-Oct-00 RMS Added dynamic device number support @@ -48,6 +49,7 @@ 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 */ @@ -67,6 +69,8 @@ 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_sys.c b/i1401_sys.c index 6b28dfc7..dec2b080 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. + 27-May-01 RMS Added multiconsole support 14-Mar-01 RMS Revised load/dump interface (again) 30-Oct-00 RMS Added support for examine to file 27-Oct-98 RMS V2.4 load interface @@ -50,6 +51,7 @@ 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 */ @@ -64,6 +66,8 @@ 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 091484bf..fd6ed257 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. + 27-May-01 RMS Added multiconsole support 14-Mar-01 RMS Revised load/dump interface (again) 30-Oct-00 RMS Added support for examine to file 27-Oct-98 RMS V2.4 load interface @@ -44,6 +45,7 @@ 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 */ @@ -58,6 +60,8 @@ 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_sys.c b/nova_sys.c index 35a25d14..c1c57ff1 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. + 31-May-01 RMS Added multiconsole support 14-Mar-01 RMS Revised load/dump interface (again) 22-Dec-00 RMS Added second terminal support 10-Dec-00 RMS Added Eclipse support @@ -31,7 +32,7 @@ 15-Oct-00 RMS Added stack, byte, trap instructions 14-Apr-99 RMS Changed t_addr to unsigned 27-Oct-98 RMS V2.4 load interface - 24-Sep-97 RMS Fixed bug in device name table (found by Dutch Owen) + 24-Sep-97 RMS Fixed bug in device name table (found by Charles Owen) */ #include "nova_defs.h" @@ -49,6 +50,8 @@ extern DEVICE tti1_dev, tto1_dev; extern DEVICE clk_dev, lpt_dev; extern DEVICE dkp_dev, dsk_dev; extern DEVICE mta_dev; +extern UNIT tti_unit, tto_unit; +extern UNIT tti1_unit, tto1_unit; extern REG cpu_reg[]; extern uint16 M[]; extern int32 saved_PC; @@ -59,6 +62,7 @@ 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 */ @@ -86,6 +90,11 @@ 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 c8143ecc..8d0b4ae2 100644 --- a/nova_tt.c +++ b/nova_tt.c @@ -25,6 +25,8 @@ tti terminal input tto terminal output + + 31-May-01 RMS Added multiconsole support */ #include "nova_defs.h" @@ -39,6 +41,7 @@ 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 @@ -48,7 +51,7 @@ extern t_stat sim_putchar (int32 out); ttx_mod TTI/TTO modifiers list */ -UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, UNIT_CONS, 0), KBD_POLL_WAIT }; REG tti_reg[] = { { ORDATA (BUF, tti_unit.buf, 8) }, @@ -59,9 +62,12 @@ 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 } }; @@ -79,7 +85,7 @@ DEVICE tti_dev = { tto_reg TTO register list */ -UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; +UNIT tto_unit = { UDATA (&tto_svc, UNIT_CONS, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { { ORDATA (BUF, tto_unit.buf, 8) }, @@ -90,6 +96,8 @@ 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 = { @@ -145,7 +153,8 @@ 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; -sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ +if (tti_unit.flags & UNIT_CONS) /* if active console, */ + sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ return SCPE_OK; } @@ -181,7 +190,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_putchar (c)) != SCPE_OK) return temp; +if ((temp = sim_putcons (c, uptr)) != SCPE_OK) return temp; tto_unit.pos = tto_unit.pos + 1; return SCPE_OK; } @@ -195,6 +204,7 @@ 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 3e6f9dda..9435848e 100644 --- a/nova_tt1.c +++ b/nova_tt1.c @@ -27,6 +27,7 @@ tti1 second terminal input tto1 second terminal output + 31-May-01 RMS Added multiconsole support 26-Apr-01 RMS Added device enable/disable support */ @@ -36,14 +37,13 @@ #define UNIT_DASHER (1 << UNIT_V_DASHER) extern int32 int_req, dev_busy, dev_done, dev_disable, iot_enb; -int32 tti1_stopioe = 0, tto1_stopioe = 0; /* stop on error */ 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 tti1_attach (UNIT *uptr, char *ptr); -t_stat tti1_detach (UNIT *uptr); t_stat ttx1_setmod (UNIT *uptr, int32 value); +extern t_stat sim_poll_kbd (void); +static uint8 tto1_consout[CONS_SIZE]; /* TTI1 data structures @@ -53,7 +53,7 @@ t_stat ttx1_setmod (UNIT *uptr, int32 value); ttx1_mod TTI1/TTO1 modifiers list */ -UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_SEQ+UNIT_ATTABLE, 0), KBD_POLL_WAIT }; +UNIT tti1_unit = { UDATA (&tti1_svc, 0, 0), KBD_POLL_WAIT }; REG tti1_reg[] = { { ORDATA (BUF, tti1_unit.buf, 8) }, @@ -63,12 +63,14 @@ REG tti1_reg[] = { { FLDATA (INT, int_req, INT_V_TTI1) }, { DRDATA (POS, tti1_unit.pos, 31), PV_LEFT }, { DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (STOP_IOE, tti1_stopioe, 0) }, { 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_DASHER, 0, "ANSI", "ANSI", &ttx1_setmod }, { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx1_setmod }, { 0 } }; @@ -77,7 +79,7 @@ DEVICE tti1_dev = { "TTI1", &tti1_unit, tti1_reg, ttx1_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tti1_reset, - NULL, &tti1_attach, &tti1_detach }; + NULL, NULL, NULL }; /* TTO1 data structures @@ -86,7 +88,7 @@ DEVICE tti1_dev = { tto1_reg TTO1 register list */ -UNIT tto1_unit = { UDATA (&tto1_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; +UNIT tto1_unit = { UDATA (&tto1_svc, 0, 0), SERIAL_OUT_WAIT }; REG tto1_reg[] = { { ORDATA (BUF, tto1_unit.buf, 8) }, @@ -96,8 +98,9 @@ REG tto1_reg[] = { { FLDATA (INT, int_req, INT_V_TTO1) }, { DRDATA (POS, tto1_unit.pos, 31), PV_LEFT }, { DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, tto1_stopioe, 0) }, { 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 } }; @@ -134,16 +137,8 @@ t_stat tti1_svc (UNIT *uptr) { int32 temp; -if ((tti1_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (tti1_stopioe, SCPE_UNATT); sim_activate (&tti1_unit, tti1_unit.wait); /* continue poll */ -if ((temp = getc (tti1_unit.fileref)) == EOF) { /* end of file? */ - if (feof (tti1_unit.fileref)) { - if (tti1_stopioe) printf ("TTI1 end of file\n"); - else return SCPE_OK; } - else perror ("TTI1 input error"); - clearerr (tti1_unit.fileref); - return SCPE_IOERR; } +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 */ @@ -162,30 +157,10 @@ 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_ATT) /* attached? */ +if (tti1_unit.flags & UNIT_CONS) /* active console? */ sim_activate (&tti1_unit, tti1_unit.wait); -else sim_cancel (&tti1_unit); return SCPE_OK; } - -/* Attach routine */ - -t_stat tti1_attach (UNIT *uptr, char *cptr) -{ -t_stat reason; - -reason = attach_unit (uptr, cptr); -if (reason == SCPE_OK) sim_activate (uptr, uptr -> wait); -return reason; -} - -/* Detach routine */ - -t_stat tti1_detach (UNIT *uptr) -{ -sim_cancel (uptr); -return detach_unit (uptr); -} /* Terminal output: IOT routine */ @@ -212,19 +187,14 @@ return 0; t_stat tto1_svc (UNIT *uptr) { -int32 c ; +int32 c, temp; 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); -if ((tto1_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (tto1_stopioe, SCPE_UNATT); c = tto1_unit.buf & 0177; if ((tto1_unit.flags & UNIT_DASHER) && (c == 031)) c = '\b'; -if (putc (c, tto1_unit.fileref) == EOF) { - perror ("TTO1 output error"); - clearerr (tto1_unit.fileref); - return SCPE_IOERR; } +if ((temp = sim_putcons (c, uptr)) != SCPE_OK) return temp; tto1_unit.pos = tto1_unit.pos + 1; return SCPE_OK; } @@ -238,6 +208,7 @@ 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; } diff --git a/pdp10_cpu.c b/pdp10_cpu.c index 1ed9b602..d799ceb7 100644 --- a/pdp10_cpu.c +++ b/pdp10_cpu.c @@ -25,6 +25,7 @@ cpu KS10 central processor + 19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug 29-Apr-01 RMS Fixed modifier naming conflict Fixed XCTR/XCTRI, UMOVE/UMOVEM, BLTUB/BLTBU for ITS Added CLRCSH for ITS @@ -115,7 +116,7 @@ #define ILL_ADR_FLAG (1 << VASIZE) #define save_ibkpt (cpu_unit.u3) -#define UNIT_V_MSIZE (UNIT_V_ITS + 1) /* dummy mask */ +#define UNIT_V_MSIZE (UNIT_V_T20V41 + 1) /* dummy mask */ #define UNIT_MSIZE (1 << UNIT_V_MSIZE) d10 *M = NULL; /* memory */ @@ -241,6 +242,7 @@ REG cpu_reg[] = { { DRDATA (INDMAX, ind_max, 8), PV_LEFT + REG_NZ }, { DRDATA (XCTMAX, xct_max, 8), PV_LEFT + REG_NZ }, { FLDATA (ITS, cpu_unit.flags, UNIT_V_ITS), REG_HRO }, + { FLDATA (T20V41, cpu_unit.flags, UNIT_V_T20V41), REG_HRO }, { ORDATA (BREAK, ibkpt_addr, VASIZE + 1) }, { ORDATA (WRU, sim_int_char, 8) }, { FLDATA (STOP_ILL, stop_op0, 0) }, @@ -248,8 +250,9 @@ REG cpu_reg[] = { { NULL } }; MTAB cpu_mod[] = { - { UNIT_ITS, 0, "Standard microcode", "STANDARD", NULL }, - { UNIT_ITS, UNIT_ITS, "ITS microcode", "ITS", NULL }, + { UNIT_ITS+UNIT_T20V41, 0, "Standard microcode", "STANDARD", NULL }, + { UNIT_ITS+UNIT_T20V41, UNIT_T20V41, "TOPS-20 V4.1", "TOPS20V41", NULL }, + { UNIT_ITS+UNIT_T20V41, UNIT_ITS, "ITS microcode", "ITS", NULL }, { 0 } }; DEVICE cpu_dev = { diff --git a/pdp10_defs.h b/pdp10_defs.h index 17ebaba1..dd9e0648 100644 --- a/pdp10_defs.h +++ b/pdp10_defs.h @@ -22,6 +22,9 @@ 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. + + 01-Jun-01 RMS Updated DZ11 vector definitions + 19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug */ #include "sim_defs.h" /* simulator defns */ @@ -103,6 +106,8 @@ typedef int64 d10; /* PDP-10 data (36b) */ #define UNIT_V_ITS (UNIT_V_UF) /* ITS */ #define UNIT_ITS (1 << UNIT_V_ITS) +#define UNIT_V_T20V41 (UNIT_V_UF + 1) /* TOPS-20 V4.1 */ +#define UNIT_T20V41 (1 << UNIT_V_T20V41) #define ITS (cpu_unit.flags & UNIT_ITS) /* Architectural constants */ @@ -590,22 +595,24 @@ typedef int64 d10; /* PDP-10 data (36b) */ /* I/O system definitions, lifted from the PDP-11 simulator Interrupt assignments, priority is right to left - <7:0> = BR7 - <15:8> = BR6 - <23:16> = BR5 - <30:24> = BR4 + <3:0> = BR7 + <7:4> = BR6 + <19:8> = BR5 + <30:20> = BR4 */ -#define INT_V_RP 8 /* RH11/RP,RM drives */ -#define INT_V_TU 9 /* RH11/TM03/TU45 */ -#define INT_V_DZ 16 /* DZ11 */ +#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_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_DZ (1u << INT_V_DZ) +#define INT_DZ0RX (1u << INT_V_DZ0RX) +#define INT_DZ0TX (1u << INT_V_DZ0TX) #define INT_PTR (1u << INT_V_PTR) #define INT_PTP (1u << INT_V_PTP) #define INT_LP20 (1u << INT_V_LP20) @@ -613,14 +620,15 @@ typedef int64 d10; /* PDP-10 data (36b) */ #define INT_UB1 INT_RP /* on Unibus 1 */ #define INT_UB3 (0xFFFFFFFFu & ~INT_UB1) /* on Unibus 3 */ -#define INT_IPL7 0x000000FF /* int level masks */ -#define INT_IPL6 0x0000FF00 -#define INT_IPL5 0x00FF0000 -#define INT_IPL4 0x3F000000 +#define INT_IPL7 0x0000000F /* int level masks */ +#define INT_IPL6 0x000000F0 +#define INT_IPL5 0x000FFF00 +#define INT_IPL4 0x3FF00000 #define VEC_PTR 0070 /* interrupt vectors */ #define VEC_PTP 0074 #define VEC_TU 0224 #define VEC_RP 0254 -#define VEC_DZ 0340 +#define VEC_DZ0RX 0340 +#define VEC_DZ0TX 0344 #define VEC_LP20 0754 diff --git a/pdp10_ksio.c b/pdp10_ksio.c index 19c23a79..c38ff0d2 100644 --- a/pdp10_ksio.c +++ b/pdp10_ksio.c @@ -25,6 +25,7 @@ uba Unibus adapters + 1-Jun-01 RMS Updated DZ11 vectors 12-May-01 RMS Fixed typo The KS10 uses the PDP-11 Unibus for its I/O, via adapters. While @@ -94,8 +95,8 @@ extern jmp_buf save_env; extern d10 Read (a10 ea); extern void pi_eval (); -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 dz0_rd (int32 *data, int32 addr, int32 access); +extern t_stat dz0_wr (int32 data, int32 addr, int32 access); extern t_stat pt_rd (int32 *data, int32 addr, int32 access); extern t_stat pt_wr (int32 data, int32 addr, int32 access); extern t_stat lp20_rd (int32 *data, int32 addr, int32 access); @@ -162,7 +163,7 @@ struct iolink iotable[] = { { 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_DZ, - &dz_rd, &dz_wr }, /* terminal mux */ + &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, @@ -187,17 +188,17 @@ struct iolink iotable[] = { /* Interrupt request to interrupt action map */ int32 (*int_ack[32])() = { /* int ack routines */ + NULL, NULL, NULL, NULL, NULL, NULL, &rp_inta, &tu_inta, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &rp_inta, &tu_inta, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &lp20_inta, NULL, NULL, NULL, NULL, NULL }; /* Interrupt request to vector map */ 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_RP, VEC_TU, 0, 0, 0, 0, 0, 0, - VEC_DZ, 0, 0, 0, 0, 0, 0, 0, + VEC_DZ0RX, VEC_DZ0TX, 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 diff --git a/pdp10_pag.c b/pdp10_pag.c index c85ab929..847a043f 100644 --- a/pdp10_pag.c +++ b/pdp10_pag.c @@ -25,6 +25,7 @@ pag KS10 pager + 19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug 03-May-01 RMS Fixed bug in indirect page table pointer processing 29-Apr-01 RMS Added CLRCSH for ITS, fixed LPMR @@ -659,6 +660,8 @@ return FALSE; t_bool wrcstm (a10 ea, int32 prv) { cstm = Read (ea, prv); +if ((cpu_unit.flags & UNIT_T20V41) && (ea == 040127)) + cstm = 0770000000000; return FALSE; } diff --git a/pdp10_rp.c b/pdp10_rp.c index b25613e7..a34b4bc2 100644 --- a/pdp10_rp.c +++ b/pdp10_rp.c @@ -335,21 +335,21 @@ t_stat rp_detach (UNIT *uptr); */ UNIT rp_unit[] = { - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) } }; REG rp_reg[] = { diff --git a/pdp10_sys.c b/pdp10_sys.c index c2f0e75f..9141bfe2 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. + 27-May-01 RMS Added multiconsole support 29-Apr-01 RMS Fixed format for RDPCST, WRPCST Added CLRCSH for ITS 03-Apr-01 RMS Added support for loading EXE files @@ -50,6 +51,7 @@ 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 */ @@ -69,6 +71,8 @@ DEVICE *sim_devices[] = { &rp_dev, &tu_dev, NULL }; +UNIT *sim_consoles = NULL; + const char *sim_stop_messages[] = { "Unknown error", "HALT instruction", diff --git a/pdp11_cis.c b/pdp11_cis.c index 9545b70c..436e0240 100644 --- a/pdp11_cis.c +++ b/pdp11_cis.c @@ -138,11 +138,11 @@ /* Condition code macros */ -#define GET_BIT(ir,n) (((ir) >> n) & 1) -#define GET_SIGN_L(ir) GET_BIT((ir), 31) -#define GET_SIGN_W(ir) GET_BIT((ir), 15) -#define GET_SIGN_B(ir) GET_BIT((ir), 7) -#define GET_Z(ir) (ir == 0) +#define GET_BIT(ir,n) (((ir) >> n) & 1) +#define GET_SIGN_L(ir) GET_BIT((ir), 31) +#define GET_SIGN_W(ir) GET_BIT((ir), 15) +#define GET_SIGN_B(ir) GET_BIT((ir), 7) +#define GET_Z(ir) (ir == 0) /* Decimal string structure */ @@ -416,7 +416,7 @@ case 030: case 032: case 0130: case 0132: Condition codes: NZVC = set from src.lnt - dst.lnt - Registers (MOVC, MOVTC only) + Registers (MOVRC only) R0 = max (0, src.len - dst.len) R1:R3 = 0 R4:R5 = unchanged @@ -432,7 +432,7 @@ case 031: case 0131: addr = A2ADR + A2LNT - mvlnt; for (i = 0; i < mvlnt; i++) { WriteB (movbuf[i], ((addr + i) & 0177777) | dsenable); } - fill = A3LNT & 0377; /* do fill, if any */ + fill = A3LNT & 0377; /* do fill, if any */ for (i = mvlnt, j = 0; i < A2LNT; i++, j++) { WriteB (fill, ((A2ADR + j) & 0177777) | dsenable); } t = A1LNT - A2LNT; /* src.lnt - dst.lnt */ @@ -509,7 +509,7 @@ case 042: case 043: case 0142: case 0143: for (; R[0] != 0; R[0]--) { /* loop */ t = ReadB (R[1] | dsenable); /* get char as index */ c = ReadB (((A1ADR + t) & 0177777) | dsenable); - if (((c & mask) != 0) ^ (op & 1)) break; /* != + SCN, = + SPN? */ + if (((c & mask) != 0) ^ (op & 1)) break; /* != + SCN, = + SPN? */ R[1] = (R[1] + 1) & 0177777; } N = GET_SIGN_W (R[0]); Z = GET_Z (R[0]); @@ -735,8 +735,7 @@ case 052: case 072: case 0152: case 0172: ReadDstr (A2, &src2, op); /* get source2 */ N = Z = V = C = 0; if (src1.sign != src2.sign) N = src1.sign; - else { - t = CmpDstr (&src1, &src2); /* compare strings */ + else { t = CmpDstr (&src1, &src2); /* compare strings */ if (t < 0) N = 1; else if (t == 0) Z = 1; } if ((op & INLINE) == 0) /* if reg, clr reg */ diff --git a/pdp11_cpu.c b/pdp11_cpu.c index b11fb40c..7b59a7ce 100644 --- a/pdp11_cpu.c +++ b/pdp11_cpu.c @@ -25,6 +25,7 @@ cpu PDP-11 CPU (J-11 microprocessor) + 01-Jun-01 RMS Added DZ11 support 23-Apr-01 RMS Added RK611 support 05-Apr-01 RMS Added TS11/TSV05 support 05-Mar-01 RMS Added clock calibration support @@ -325,7 +326,7 @@ struct iolink iotable[] = { 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, - 0, 0, 0, VEC_PIRQ, VEC_TTI, VEC_TTO, VEC_PTR, VEC_PTP, + 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_ack[32])() = { /* int ack routines */ diff --git a/pdp11_defs.h b/pdp11_defs.h index f15e7ff1..d85352dd 100644 --- a/pdp11_defs.h +++ b/pdp11_defs.h @@ -26,6 +26,7 @@ The author gratefully acknowledges the help of Max Burnet, Megan Gentry, and John Wilson in resolving questions about the PDP-11 + 01-Jun-01 RMS Added DZ11 support 23-Apr-01 RMS Added RK611 support 05-Apr-01 RMS Added TS11/TSV05 support 10-Feb-01 RMS Added DECtape support @@ -240,7 +241,7 @@ typedef struct fpac fpac_t; <3:0> = BR7, <3> = PIR7 <7:4> = BR6, <7> = PIR6 - <19:8> = BR5, <15> = PIR5 + <19:8> = BR5, <19> = PIR5 <28:20> = BR4, <28> = PIR4 <29> = PIR3 <30> = PIR2 @@ -258,6 +259,8 @@ typedef struct fpac fpac_t; #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 @@ -280,6 +283,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_PIR5 (1u << INT_V_PIR5) #define INT_PTR (1u << INT_V_PTR) #define INT_PTP (1u << INT_V_PTP) @@ -315,6 +320,8 @@ 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 /* CPU and FPU macros */ diff --git a/pdp11_fp.c b/pdp11_fp.c index bd0732dc..eb4e3561 100644 --- a/pdp11_fp.c +++ b/pdp11_fp.c @@ -27,8 +27,8 @@ 20-Apr-98 RMS Fixed bug in MODf integer truncation 17-Apr-98 RMS Fixed bug in STCfi range check 16-Apr-98 RMS Fixed bugs in STEXP, STCfi, round/pack - 9-Apr-98 RMS Fixed bug in LDEXP - 4-Apr-98 RMS Fixed bug in MODf condition codes + 09-Apr-98 RMS Fixed bug in LDEXP + 04-Apr-98 RMS Fixed bug in MODf condition codes This module simulates the PDP-11 floating point unit (FP11 series). It is called from the instruction decoder for opcodes 170000:177777. diff --git a/pdp11_rk.c b/pdp11_rk.c index 9be8d898..60513124 100644 --- a/pdp11_rk.c +++ b/pdp11_rk.c @@ -28,7 +28,7 @@ 26-Apr-01 RMS Added device enable/disable support 25-Mar-01 RMS Fixed block fill calculation 15-Feb-01 RMS Corrected bootstrap string - 29-Jun-96 RMS Added unit disable support. + 29-Jun-96 RMS Added unit disable support The RK11 is an eight drive cartridge disk subsystem. An RK05 drive consists of 203 cylinders, each with 2 surfaces containing 12 sectors diff --git a/pdp11_rl.c b/pdp11_rl.c index b07dd03b..1d585018 100644 --- a/pdp11_rl.c +++ b/pdp11_rl.c @@ -28,9 +28,9 @@ 26-Apr-01 RMS Added device enable/disable support 25-Mar-01 RMS Fixed block fill calculation 15-Feb-01 RMS Corrected bootstrap string - 12-Nov-97 RMS Added bad block table command. - 25-Nov-96 RMS Default units to autosize. - 29-Jun-96 RMS Added unit disable support. + 12-Nov-97 RMS Added bad block table command + 25-Nov-96 RMS Default units to autosize + 29-Jun-96 RMS Added unit disable support The RL11 is a four drive cartridge disk subsystem. An RL01 drive consists of 256 cylinders, each with 2 surfaces containing 40 sectors diff --git a/pdp11_rp.c b/pdp11_rp.c index daa84cee..8cdd707c 100644 --- a/pdp11_rp.c +++ b/pdp11_rp.c @@ -34,8 +34,8 @@ 14-Apr-99 RMS Changed t_addr to unsigned 05-Oct-98 RMS Fixed bug, failing to interrupt on go error 04-Oct-98 RMS Changed names to allow coexistence with RH/TU77 - 12-Nov-97 RMS Added bad block table command. - 10-Aug-97 RMS Fixed bugs in interrupt handling. + 12-Nov-97 RMS Added bad block table command + 10-Aug-97 RMS Fixed bugs in interrupt handling The "Massbus style" disks consisted of several different large capacity drives interfaced through a reasonably common (but not diff --git a/pdp11_sys.c b/pdp11_sys.c index 6e329279..6d5cce72 100644 --- a/pdp11_sys.c +++ b/pdp11_sys.c @@ -23,16 +23,17 @@ 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-May-01 RMS Added multiconsole support 05-Apr-01 RMS Added support for TS11/TSV05 14-Mar-01 RMS Revised load/dump interface (again) 11-Feb-01 RMS Added DECtape support 30-Oct-00 RMS Added support for examine to file 14-Apr-99 RMS Changed t_addr to unsigned - 09-Nov-98 RMS Fixed assignments of ROR/ROL (John Wilson). - 27-Oct-98 RMS V2.4 load interface. - 08-Oct-98 RMS Fixed bug in bad block routine. - 30-Mar-98 RMS Fixed bug in floating point display. - 12-Nov-97 RMS Added bad block table routine. + 09-Nov-98 RMS Fixed assignments of ROR/ROL (John Wilson) + 27-Oct-98 RMS V2.4 load interface + 08-Oct-98 RMS Fixed bug in bad block routine + 30-Mar-98 RMS Fixed bug in floating point display + 12-Nov-97 RMS Added bad block table routine */ #include "pdp11_defs.h" @@ -58,6 +59,7 @@ 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 */ @@ -79,6 +81,8 @@ DEVICE *sim_devices[] = { &tm_dev, &ts_dev, NULL }; +UNIT *sim_consoles = NULL; + const char *sim_stop_messages[] = { "Unknown error", "Red stack trap", diff --git a/pdp18b_cpu.c b/pdp18b_cpu.c index 79a33cb7..212fb393 100644 --- a/pdp18b_cpu.c +++ b/pdp18b_cpu.c @@ -25,6 +25,9 @@ cpu PDP-4/7/9/15 central processor + 27-May-01 RMS Added second Teletype support, fixed bug in API + 18-May-01 RMS Added PDP-9,-15 API option + 16-May-01 RMS Fixed bugs in protection checks 26-Apr-01 RMS Added device enable/disable support 25-Jan-01 RMS Added DECtape support 18-Dec-00 RMS Added PDP-9,-15 memm init register @@ -46,7 +49,7 @@ all IORS I/O status register PDP-7, PDP-9 EXTM extend mode PDP-15 BANKM bank mode - PDP-7 TRAPM trap mode + PDP-7 USMD trap mode PDP-9, PDP-15 USMD user mode PDP-9, PDP-15 BR bounds register PDP-15 XR index register @@ -241,22 +244,33 @@ #define save_ibkpt (cpu_unit.u3) #define UNIT_V_NOEAE (UNIT_V_UF) /* EAE absent */ #define UNIT_NOEAE (1 << UNIT_V_NOEAE) -#define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */ +#define UNIT_V_NOAPI (UNIT_V_UF+1) /* API absent */ +#define UNIT_NOAPI (1 << UNIT_V_NOAPI) +#define UNIT_V_MSIZE (UNIT_V_UF+2) /* dummy mask */ + #define UNIT_MSIZE (1 << UNIT_V_MSIZE) #if defined (PDP4) #define EAE_DFLT UNIT_NOEAE #else #define EAE_DFLT 0 #endif +#if defined (PDP4) || (PDP7) +#define API_DFLT UNIT_NOAPI +#else +#define API_DFLT UNIT_NOAPI /* for now */ +#endif int32 M[MAXMEMSIZE] = { 0 }; /* memory */ int32 saved_LAC = 0; /* link'AC */ int32 saved_MQ = 0; /* MQ */ int32 saved_PC = 0; /* PC */ -int32 int_req = 0; /* int requests */ int32 iors = 0; /* IORS */ int32 ion = 0; /* int on */ int32 ion_defer = 0; /* int defer */ +int32 int_req = 0; /* int requests */ +int32 api_enb = 0; /* API enable */ +int32 api_req = 0; /* API requests */ +int32 api_act = 0; /* API active */ int32 memm = 0; /* mem mode */ #if defined (PDP15) int32 memm_init = 1; /* mem init */ @@ -288,7 +302,31 @@ t_stat cpu_reset (DEVICE *dptr); t_stat cpu_svc (UNIT *uptr); t_stat cpu_set_size (UNIT *uptr, int32 value); int32 upd_iors (void); -extern t_stat sim_activate (UNIT *uptr, int32 delay); +int32 api_eval (void); + +static const int32 api_ffo[256] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +static const int32 api_vec[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, ACH_TTO1, ACH_TTI1, ACH_CLK, 0, 0, 0, 0, + 0, ACH_LPT, ACH_LPT, ACH_PTR, 0, 0, 0, ACH_RP, + ACH_RF, ACH_DRM, ACH_MTA, ACH_DTA, 0, 0, ACH_PWRFL, 0 }; /* CPU data structures @@ -298,7 +336,7 @@ extern t_stat sim_activate (UNIT *uptr, int32 delay); cpu_mod CPU modifier list */ -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK + EAE_DFLT, +UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK + EAE_DFLT + API_DFLT, MAXMEMSIZE) }; REG cpu_reg[] = { @@ -320,7 +358,11 @@ REG cpu_reg[] = { { FLDATA (TRAPP, trap_pending, 0) }, { FLDATA (EXTM, memm, 0) }, { FLDATA (EMIRP, emir_pending, 0) }, -#elif defined (PDP9) +#endif +#if defined (PDP9) + { FLDATA (APIENB, api_enb, 0) }, + { ORDATA (APIREQ, api_req, 8) }, + { ORDATA (APIACT, api_act, 8) }, { ORDATA (BR, BR, ADDRSIZE) }, { FLDATA (USMD, usmd, 0) }, { FLDATA (USMDBUF, usmdbuf, 0) }, @@ -332,7 +374,11 @@ REG cpu_reg[] = { { FLDATA (EMIRP, emir_pending, 0) }, { FLDATA (RESTP, rest_pending, 0) }, { FLDATA (PWRFL, int_req, INT_V_PWRFL) }, -#elif defined (PDP15) +#endif +#if defined (PDP15) + { FLDATA (APIENB, api_enb, 0) }, + { ORDATA (APIREQ, api_req, 8) }, + { ORDATA (APIACT, api_act, 8) }, { ORDATA (XR, XR, 18) }, { ORDATA (LR, LR, 18) }, { ORDATA (BR, BR, ADDRSIZE) }, @@ -349,6 +395,7 @@ REG cpu_reg[] = { { ORDATA (OLDPC, old_PC, ADDRSIZE), REG_RO }, { FLDATA (STOP_INST, stop_inst, 0) }, { FLDATA (NOEAE, cpu_unit.flags, UNIT_V_NOEAE), REG_HRO }, + { FLDATA (NOAPI, cpu_unit.flags, UNIT_V_NOAPI), REG_HRO }, { DRDATA (XCT_MAX, xct_max, 8), PV_LEFT + REG_NZ }, { ORDATA (BREAK, ibkpt_addr, ADDRSIZE + 1) }, { ORDATA (WRU, sim_int_char, 8) }, @@ -361,6 +408,10 @@ MTAB cpu_mod[] = { { UNIT_NOEAE, 0, "EAE", "EAE", NULL }, #else { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, +#endif +#if defined (PDP9) || defined (PDP15) + { UNIT_NOAPI, UNIT_NOAPI, "no API", "NOAPI", NULL }, + { UNIT_NOAPI, 0, "API", "API", NULL }, #endif { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, #if (MAXMEMSIZE > 8192) @@ -391,6 +442,7 @@ t_stat sim_instr (void) { extern int32 sim_interval; register int32 PC, LAC, MQ; +int32 api_int, api_cycle, skp; int32 iot_data, device, pulse; t_stat reason; extern UNIT clk_unit; @@ -422,94 +474,15 @@ extern int32 mt (int32 pulse, int32 AC); extern int32 dt75 (int32 pulse, int32 AC); extern int32 dt76 (int32 pulse, int32 AC); #endif +#if defined (TTY1) +extern int32 tti1 (int32 pulse, int32 AC); +extern int32 tto1 (int32 pulse, int32 AC); +#endif #define JMS_WORD(t) (((LAC & 01000000) >> 1) | ((memm & 1) << 16) | \ (((t) & 1) << 15) | ((PC) & 077777)) #define INCR_ADDR(x) (((x) & epcmask) | (((x) + 1) & damask)) #define SEXT(x) ((int) (((x) & 0400000)? (x) | ~0777777: (x) & 0777777)) - -/* Restore register state */ - -#if defined (PDP15) -register int32 epcmask, damask; - -damask = memm? 017777: 07777; /* set dir addr mask */ -epcmask = ADDRMASK & ~damask; /* extended PC mask */ - -#else -#define damask 017777 /* direct addr mask */ -#define epcmask (ADDRMASK & ~damask) /* extended PC mask */ -#endif - -PC = saved_PC & ADDRMASK; /* load local copies */ -LAC = saved_LAC & 01777777; -MQ = saved_MQ & 0777777; -reason = 0; -sim_rtc_init (clk_unit.wait); /* init calibration */ - -/* Main instruction fetch/decode loop: check trap and interrupt */ - -while (reason == 0) { /* loop until halted */ -register int32 IR, MA, t, xct_count; -register int32 link_init, fill; - -if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) break; } - -/* Protection traps work like interrupts, with these quirks: - - PDP-7 extend mode forced on, M[0] = PC, PC = 2 - PDP-9 extend mode ???, M[0/20] = PC, PC = 0/21 - PDP-15 bank mode unchanged, M[0/20] = PC, PC = 0/21 -*/ - -#if defined (PDP7) -if (trap_pending) { /* trap pending? */ - old_PC = PC; /* save old PC */ - M[0] = JMS_WORD (1); /* save state */ - PC = 2; /* fetch next from 2 */ - ion = 0; /* interrupts off */ - memm = 1; /* extend on */ - emir_pending = trap_pending = 0; /* emir, trap off */ - usmd = 0; } /* protect off */ -#elif defined (PDP9) -if (trap_pending) { /* trap pending? */ - old_PC = PC; /* save old PC */ - MA = ion? 0: 020; /* save in 0 or 20 */ - M[MA] = JMS_WORD (1); /* save state */ - PC = MA + 1; /* fetch next */ - ion = 0; /* interrupts off */ -/*??? memm = 0; /* extend off */ - emir_pending = rest_pending = trap_pending = 0; /* emir,rest,trap off */ - usmd = 0; } /* protect off */ -#elif defined (PDP15) -if (trap_pending) { /* trap pending? */ - old_PC = PC; /* save old PC */ - MA = ion? 0: 020; /* save in 0 or 20 */ - M[MA] = JMS_WORD (1); /* save state */ - PC = MA + 1; /* fetch next */ - ion = 0; /* interrupts off */ - emir_pending = rest_pending = trap_pending = 0; /* emir,rest,trap off */ - usmd = 0; } /* protect off */ -#endif - -if (ion && !ion_defer && int_req) { /* interrupt? */ - old_PC = PC; /* save old PC */ - M[0] = JMS_WORD (usmd); /* save state */ - PC = 1; /* fetch next from 1 */ - ion = 0; /* interrupts off */ -#if !defined (PDP15) /* except PDP-15, */ - memm = 0; /* extend off */ -#endif - emir_pending = rest_pending = 0; /* emir, restore off */ - usmd = 0; } /* protect off */ - -if (PC == ibkpt_addr) { /* breakpoint? */ - save_ibkpt = ibkpt_addr; /* save ibkpt */ - ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ - sim_activate (&cpu_unit, 1); /* sched re-enable */ - reason = STOP_IBKPT; /* stop simulation */ - break; } /* The following macros implement addressing. They account for autoincrement addressing, extended addressing, and memory protection, if it exists. @@ -563,7 +536,7 @@ if (PC == ibkpt_addr) { /* breakpoint? */ if (!MEM_ADDR_OK (x)) { \ nexm = prvn = trap_pending = 1; \ break; } \ - if ((x) >= BR) { \ + if ((x) < BR) { \ prvn = trap_pending = 1; \ break; } } \ if (!MEM_ADDR_OK (x)) nexm = 1 @@ -604,7 +577,7 @@ if (PC == ibkpt_addr) { /* breakpoint? */ if (!MEM_ADDR_OK (x)) { \ nexm = prvn = trap_pending = 1; \ break; } \ - if ((x) >= BR) { \ + if ((x) < BR) { \ prvn = trap_pending = 1; \ break; } } \ if (!MEM_ADDR_OK (x)) nexm = 1 @@ -613,20 +586,133 @@ if (PC == ibkpt_addr) { /* breakpoint? */ if (!MEM_ADDR_OK (x)) break #endif +/* Restore register state */ + +#if defined (PDP15) +register int32 epcmask, damask; + +damask = memm? 017777: 07777; /* set dir addr mask */ +epcmask = ADDRMASK & ~damask; /* extended PC mask */ + +#else +#define damask 017777 /* direct addr mask */ +#define epcmask (ADDRMASK & ~damask) /* extended PC mask */ +#endif + +PC = saved_PC & ADDRMASK; /* load local copies */ +LAC = saved_LAC & 01777777; +MQ = saved_MQ & 0777777; +reason = 0; +sim_rtc_init (clk_unit.wait); /* init calibration */ +if (cpu_unit.flags & UNIT_NOAPI) api_enb = api_req = api_act = 0; +api_int = api_eval (); /* eval API */ +api_cycle = 0; /* not API cycle */ + +/* Main instruction fetch/decode loop: check trap and interrupt */ + +while (reason == 0) { /* loop until halted */ +register int32 IR, MA, t, xct_count; +register int32 link_init, fill; + +if (sim_interval <= 0) { /* check clock queue */ + if (reason = sim_process_event ()) break; + api_int = api_eval (); } /* eval API */ + +/* Protection traps work like interrupts, with these quirks: + + PDP-7 extend mode forced on, M[0] = PC, PC = 2 + PDP-9 extend mode ???, M[0/20] = PC, PC = 0/21 + PDP-15 bank mode unchanged, M[0/20] = PC, PC = 0/21 +*/ + +#if defined (PDP7) +if (trap_pending) { /* trap pending? */ + old_PC = PC; /* save old PC */ + M[0] = JMS_WORD (1); /* save state */ + PC = 2; /* fetch next from 2 */ + ion = 0; /* interrupts off */ + memm = 1; /* extend on */ + emir_pending = trap_pending = 0; /* emir, trap off */ + usmd = 0; } /* protect off */ +#endif +#if defined (PDP9) || defined (PDP15) +if (trap_pending) { /* trap pending? */ + old_PC = PC; /* save old PC */ + MA = ion? 0: 020; /* save in 0 or 20 */ + M[MA] = JMS_WORD (1); /* save state */ + PC = MA + 1; /* fetch next */ + ion = 0; /* interrupts off */ + emir_pending = rest_pending = trap_pending = 0; /* emir,rest,trap off */ + usmd = 0; } /* protect off */ + +/* PDP-9 and PDP-15 automatic priority interrupt (API) */ + +if (api_int && !ion_defer) { /* API intr? */ + int32 i, lvl = api_int - 1; /* get req level */ + api_act = api_act | (0200 >> lvl); /* set level active */ + if (lvl >= 4) { /* software req? */ + MA = ACH_SWRE + lvl - 4; /* vec = 40:43 */ + api_req = api_req & ~(0200 >> lvl); } /* remove request */ + else { MA = 0; /* assume fails */ + for (i = 31; i >= 0; i--) { /* loop hi to lo */ + if ((int_req >> i) & 1) { /* int req set? */ + MA = api_vec[i]; /* get vector */ + break; } } } /* and stop */ + if (MA == 0) { /* bad channel? */ + reason = STOP_API; /* API error */ + break; } + api_int = api_eval (); /* no API int */ + api_cycle = 1; /* in API cycle */ + emir_pending = rest_pending = 0; /* emir, restore off */ + xct_count = 0; + goto xct_instr; } + +/* Standard program interrupt */ + +if (!(api_enb && api_act) && ion && !ion_defer && int_req) { +#else +if (ion && !ion_defer && int_req) { /* interrupt? */ +#endif + old_PC = PC; /* save old PC */ + M[0] = JMS_WORD (usmd); /* save state */ + PC = 1; /* fetch next from 1 */ + ion = 0; /* interrupts off */ +#if !defined (PDP15) /* except PDP-15, */ + memm = 0; /* extend off */ +#endif + emir_pending = rest_pending = 0; /* emir, restore off */ + usmd = 0; } /* protect off */ + +/* Breakpoint */ + +if (PC == ibkpt_addr) { /* breakpoint? */ + save_ibkpt = ibkpt_addr; /* save ibkpt */ + ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ + sim_activate (&cpu_unit, 1); /* sched re-enable */ + reason = STOP_IBKPT; /* stop simulation */ + break; } + /* Fetch, decode instruction */ -MA = PC; /* fetch at PC */ -CHECK_ADDR_R (MA); /* validate addr */ -IR = M[MA]; /* fetch instruction */ -PC = INCR_ADDR (PC); /* increment PC */ #if defined (PDP9) || defined (PDP15) +if (usmd) { /* user mode? */ + if (!MEM_ADDR_OK (PC)) { /* nxm? */ + nexm = prvn = trap_pending = 1; /* abort fetch */ + continue; } \ + if (PC < BR) { /* bounds viol? */ + prvn = trap_pending = 1; /* abort fetch */ + continue; } } +else if (!MEM_ADDR_OK (PC)) nexm = 1; /* flag nxm */ if (!ion_defer) usmd = usmdbuf; /* no IOT? load usmd */ #endif -if (ion_defer) ion_defer = ion_defer - 1; /* count down defer */ xct_count = 0; /* track nested XCT's */ -sim_interval = sim_interval - 1; +MA = PC; /* fetch at PC */ +PC = INCR_ADDR (PC); /* increment PC */ xct_instr: /* label for XCT */ +IR = M[MA]; /* fetch instruction */ +if (ion_defer) ion_defer = ion_defer - 1; /* count down defer */ +if (sim_interval) sim_interval = sim_interval - 1; MA = (MA & epcmask) | (IR & damask); /* effective address */ switch ((IR >> 13) & 037) { /* decode IR<0:4> */ @@ -752,13 +838,13 @@ case 020: /* XCT, dir */ #if defined (PDP9) ion_defer = 1; /* defer intr */ #endif - IR = M[MA]; /* get instruction */ goto xct_instr; /* go execute */ /* CAL: opcode 00 On the PDP-4 and PDP-7, CAL (I) is exactly the same as JMS (I) 20 - On the PDP-9, CAL clears user mode + On the PDP-9 and PDP-15, CAL clears user mode + On the PDP-9 and PDP-15 with API, CAL activates level 4 On the PDP-15, CAL goes to absolute 20, regardless of mode */ @@ -771,6 +857,9 @@ case 001: case 000: /* CAL */ #endif #if defined (PDP9) || defined (PDP15) usmd = 0; /* clear user mode */ + if ((cpu_unit.flags & UNIT_NOAPI) == 0) { /* if API, act lvl 4 */ + api_act = api_act | 010; + api_int = api_eval (); } #endif if (IR & 0020000) { INDIRECT; } /* indirect? */ CHECK_ADDR_W (MA); @@ -800,7 +889,7 @@ case 004: /* JMS, dir */ */ case 031: /* JMP, indir */ - CHECK_AUTO_INC; /* check auto inc */ +CHECK_AUTO_INC; /* check auto inc */ #if defined (PDP7) || defined (PDP9) if (emir_pending && (((M[MA] >> 16) & 1) == 0)) memm = 0; #endif @@ -825,55 +914,56 @@ case 037: /* OPR, indir */ break; case 036: /* OPR, dir */ + skp = 0; /* assume no skip */ switch ((IR >> 6) & 017) { /* decode IR<8:11> */ case 0: /* nop */ break; case 1: /* SMA */ - if ((LAC & 0400000) != 0) PC = INCR_ADDR (PC); + if ((LAC & 0400000) != 0) skp = 1; break; case 2: /* SZA */ - if ((LAC & 0777777) == 0) PC = INCR_ADDR (PC); + if ((LAC & 0777777) == 0) skp = 1; break; case 3: /* SZA | SMA */ if (((LAC & 0777777) == 0) || ((LAC & 0400000) != 0)) - PC = INCR_ADDR (PC); + skp = 1; break; case 4: /* SNL */ - if (LAC >= 01000000) PC = INCR_ADDR (PC); + if (LAC >= 01000000) skp = 1; break; case 5: /* SNL | SMA */ - if (LAC >= 0400000) PC = INCR_ADDR (PC); + if (LAC >= 0400000) skp = 1; break; case 6: /* SNL | SZA */ - if ((LAC >= 01000000) || (LAC == 0)) PC = INCR_ADDR (PC); + if ((LAC >= 01000000) || (LAC == 0)) skp = 1; break; case 7: /* SNL | SZA | SMA */ - if ((LAC >= 0400000) || (LAC == 0)) PC = INCR_ADDR (PC); + if ((LAC >= 0400000) || (LAC == 0)) skp = 1; break; case 010: /* SKP */ - PC = INCR_ADDR (PC); + skp = 1; break; case 011: /* SPA */ - if ((LAC & 0400000) == 0) PC = INCR_ADDR (PC); + if ((LAC & 0400000) == 0) skp = 1; break; case 012: /* SNA */ - if ((LAC & 0777777) != 0) PC = INCR_ADDR (PC); + if ((LAC & 0777777) != 0) skp = 1; break; case 013: /* SNA & SPA */ if (((LAC & 0777777) != 0) && ((LAC & 0400000) == 0)) - PC = INCR_ADDR (PC); + skp = 1; break; case 014: /* SZL */ - if (LAC < 01000000) PC = INCR_ADDR (PC); + if (LAC < 01000000) skp = 1; break; case 015: /* SZL & SPA */ - if (LAC < 0400000) PC = INCR_ADDR (PC); + if (LAC < 0400000) skp = 1; break; case 016: /* SZL & SNA */ - if ((LAC < 01000000) && (LAC != 0)) PC = INCR_ADDR (PC); + if ((LAC < 01000000) && (LAC != 0)) skp = 1; break; case 017: /* SZL & SNA & SPA */ - if ((LAC < 0400000) && (LAC != 0)) PC = INCR_ADDR (PC); + if ((LAC < 0400000) && (LAC != 0)) skp = 1; break; } /* end switch skips */ /* OPR, continued */ @@ -968,6 +1058,7 @@ case 036: /* OPR, dir */ if (IR & 0000040) { /* HLT */ if (usmd) prvn = trap_pending = 1; else reason = STOP_HALT; } + if (skp && !prvn) PC = INCR_ADDR (PC); /* if skip, inc PC */ break; /* end OPR */ /* EAE: opcode 64 @@ -1169,7 +1260,11 @@ case 035: /* index operates */ 703301 undefined TTS TTS TTS 703341 undefined SKP7 SKP7 SPCO 703302 undefined CAF CAF CAF + 703304 undefined undefined DBK DBK 703344 undefined undefined DBR DBR + 705501 undefined undefined SPI SPI + 705502 undefined undefined RPL RPL + 705504 undefined undefined ISA ISA 707701 undefined SEM SEM undefined 707741 undefined undefined undefined SKP15 707761 undefined undefined undefined SBA @@ -1203,10 +1298,11 @@ case 034: /* IOT */ else if (pulse == 042) ion = ion_defer = 1; /* ION */ else iot_data = clk (pulse, iot_data); break; +#endif /* PDP-7 system IOT's */ -#elif defined (PDP7) +#if defined (PDP7) switch (device) { /* decode IR<6:11> */ case 0: /* CPU and clock */ if (pulse == 002) ion = 0; /* IOF */ @@ -1226,10 +1322,11 @@ case 034: /* IOT */ memm = emir_pending = 1; /* ext on, restore */ else if (pulse == 004) memm = 0; /* LEM */ break; +#endif -/* PDP-9 system IOT's */ +/* PDP-9 and PDP-15 system IOT's */ -#elif defined (PDP9) +#if defined (PDP9) || defined (PDP15) ion_defer = 1; /* delay interrupts */ switch (device) { /* decode IR<6:11> */ case 000: /* CPU and clock */ @@ -1242,7 +1339,7 @@ case 034: /* IOT */ else if ((pulse == 041) && nexm) PC = INCR_ADDR (PC); else if (pulse == 002) prvn = 0; else if (pulse == 042) usmdbuf = 1; - else if (pulse == 004) BR = LAC & 076000; + else if (pulse == 004) BR = LAC & BRMASK; else if (pulse == 044) nexm = 0; break; case 032: /* power fail */ @@ -1252,8 +1349,27 @@ case 034: /* IOT */ case 033: /* CPU control */ if ((pulse == 001) || (pulse == 041)) PC = INCR_ADDR (PC); else if (pulse == 002) reset_all (0); /* CAF */ - else if (pulse == 044) rest_pending = 1; /* DBR */ + else if (pulse == 044) rest_pending = 1; /* DBR */ + if (((cpu_unit.flags & UNIT_NOAPI) == 0) && (pulse & 004)) { + int32 t = api_ffo[api_act & 0377]; + api_act = api_act & ~(0200 >> t); } break; + case 055: /* API control */ + if (cpu_unit.flags & UNIT_NOAPI) reason = stop_inst; + else if (pulse == 001) { /* SPI */ + if (((LAC & SIGN) && api_enb) || + ((LAC & 0377) > api_act)) + iot_data = iot_data | IOT_SKP; } + else if (pulse == 002) { /* RPL */ + iot_data = iot_data | (api_enb << 17) | + (api_req << 8) | api_act; } + else if (pulse == 004) { /* ISA */ + api_enb = (iot_data & SIGN)? 1: 0; + api_req = api_req | ((LAC >> 8) & 017); + api_act = api_act | (LAC & 0377); } + break; +#endif +#if defined (PDP9) case 077: /* extended memory */ if ((pulse == 001) && memm) PC = INCR_ADDR (PC); else if (pulse == 002) memm = 1; /* EEM */ @@ -1261,34 +1377,8 @@ case 034: /* IOT */ memm = emir_pending = 1; /* ext on, restore */ else if (pulse == 004) memm = 0; /* LEM */ break; - -/* PDP-15 system IOT's */ - -#elif defined (PDP15) - ion_defer = 1; /* delay interrupts */ - switch (device) { /* decode IR<6:11> */ - case 000: /* CPU and clock */ - if (pulse == 002) ion = 0; /* IOF */ - else if (pulse == 042) ion = 1; /* ION */ - else iot_data = clk (pulse, iot_data); - break; - case 017: /* mem protection */ - if ((pulse == 001) && prvn) PC = INCR_ADDR (PC); - else if ((pulse == 041) && nexm) PC = INCR_ADDR (PC); - else if (pulse == 002) prvn = 0; - else if (pulse == 042) usmdbuf = 1; - else if (pulse == 004) BR = LAC & 0377400; - else if (pulse == 044) nexm = 0; - break; - case 032: /* power fail */ - if ((pulse == 001) && (int_req & INT_PWRFL)) - PC = INCR_ADDR (PC); - break; - case 033: /* CPU control */ - if ((pulse == 001) || (pulse == 041)) PC = INCR_ADDR (PC); - else if (pulse == 002) reset_all (0); /* CAF */ - else if (pulse == 044) rest_pending = 1; /* DBR */ - break; +#endif +#if defined (PDP15) case 077: /* bank addressing */ if ((pulse == 041) || ((pulse == 061) && memm)) PC = INCR_ADDR (PC); /* SKP15, SBA */ @@ -1315,6 +1405,14 @@ case 034: /* IOT */ case 4: /* TTO */ iot_data = tto (pulse, iot_data); break; +#if defined (TTY1) + case 040: /* TTO1 */ + iot_data = tto1 (pulse, iot_data); + break; + case 041: /* TTI1 */ + iot_data = tti1 (pulse, iot_data); + break; +#endif #if defined (DRM) case 060: /* drum */ if (dev_enb & INT_DRM) iot_data = drm60 (pulse, iot_data); @@ -1377,8 +1475,13 @@ case 034: /* IOT */ LAC = LAC | (iot_data & 0777777); if (iot_data & IOT_SKP) PC = INCR_ADDR (PC); if (iot_data >= IOT_REASON) reason = iot_data >> IOT_V_REASON; + api_int = api_eval (); /* eval API */ break; /* end case IOT */ } /* end switch opcode */ +if (api_cycle) { /* API cycle? */ + api_cycle = 0; /* cycle over */ + usmd = 0; /* exit user mode */ + trap_pending = prvn = 0; } /* no priv viol */ } /* end while */ /* Simulation halted */ @@ -1390,20 +1493,21 @@ iors = upd_iors (); /* get IORS */ return reason; } -/* Reset routine */ +/* Evaluate API */ -t_stat cpu_reset (DEVICE *dptr) +int32 api_eval (void) { -SC = 0; -eae_ac_sign = 0; -ion = ion_defer = 0; -int_req = int_req & ~INT_PWRFL; -BR = 0; -usmd = usmdbuf = 0; -memm = memm_init; -nexm = prvn = trap_pending = 0; -emir_pending = rest_pending = 0; -return cpu_svc (&cpu_unit); +int32 i, hi; +static const uint32 api_mask[4] = { + API_L0, API_L1, API_L2, API_L3 }; + +if (api_enb == 0) return 0; /* off? no req */ +api_req = api_req & ~0360; /* clr req<0:3> */ +for (i = 0; i < 4; i++) { + if (int_req & api_mask[i]) api_req = api_req | (0200 >> i); } +hi = api_ffo[api_req & 0377]; /* find hi req */ +if (hi < api_ffo[api_act & 0377]) return (hi + 1); +return 0; } /* Process IORS instruction */ @@ -1441,6 +1545,23 @@ return (ion? IOS_ION: 0) | std_iors () | lpt_iors (); } +/* Reset routine */ + +t_stat cpu_reset (DEVICE *dptr) +{ +SC = 0; +eae_ac_sign = 0; +ion = ion_defer = 0; +int_req = int_req & ~INT_PWRFL; +api_enb = api_req = api_act = 0; +BR = 0; +usmd = usmdbuf = 0; +memm = memm_init; +nexm = prvn = trap_pending = 0; +emir_pending = rest_pending = 0; +return cpu_svc (&cpu_unit); +} + /* Memory examine */ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) diff --git a/pdp18b_defs.h b/pdp18b_defs.h index 8c950c8b..0eaf9408 100644 --- a/pdp18b_defs.h +++ b/pdp18b_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. + 27-May-01 RMS Added second Teletype support 21-Jan-01 RMS Added DECtape support 14-Apr-99 RMS Changed t_addr to unsigned 02-Jan-96 RMS Added fixed head and moving head disks @@ -54,21 +55,23 @@ Type 24 serial drum PDP9 32K KE09A EAE KSR-33 Teletype - KG09B mem extension PC09A paper tape reader and punch - KP09A power detection integral real time clock - KX09A mem protection Type 647D/E line printer (sixbit) - RF09/RS09 fixed head disk + KF09A auto pri intr PC09A paper tape reader and punch + KG09B mem extension integral real time clock + KP09A power detection Type 647D/E line printer (sixbit) + KX09A mem protection RF09/RS09 fixed head disk TC59 magnetic tape TC02/TU55 DECtape + LT09A second Teletype PDP15 128K KE15 EAE KSR-35 Teletype - KF15 power detection PC15 paper tape reader and punch - KM15 mem protection KW15 real time clock - ??KT15 mem relocation LP15 line printer - RP15 disk pack + KA15 auto pri intr PC15 paper tape reader and punch + KF15 power detection KW15 real time clock + KM15 mem protection LP15 line printer + ??KT15 mem relocation RP15 disk pack RF15/RF09 fixed head disk TC59D magnetic tape TC15/TU56 DECtape + LT15 second Teletype ??Indicates not implemented. The PDP-4 manual refers to both an EAE ??and a memory extension control; there is no documentation on either. @@ -84,6 +87,7 @@ #define STOP_HALT 2 /* HALT */ #define STOP_IBKPT 3 /* breakpoint */ #define STOP_XCT 4 /* nested XCT's */ +#define STOP_API 5 /* invalid API int */ /* Peripheral configuration */ @@ -101,6 +105,8 @@ #define RF 0 /* fixed head disk */ #define MTA 0 /* magtape */ #define DTA 0 /* DECtape */ +#define TTY1 0 /* second Teletype */ +#define BRMASK 0076000 /* bounds mask */ #elif defined (PDP15) #define ADDRSIZE 17 #define LP15 0 /* ASCII printer */ @@ -108,6 +114,8 @@ #define RP 0 /* disk pack */ #define MTA 0 /* magtape */ #define DTA 0 /* DECtape */ +#define TTY1 0 /* second Teletype */ +#define BRMASK 0377400 /* bounds mask */ #endif /* Memory */ @@ -125,6 +133,7 @@ #define LINK (DMASK + 1) /* link */ #define LACMASK (LINK | DMASK) /* link + data */ #define SIGN 0400000 /* sign bit */ +#define OP_JMS 0100000 /* JMS */ #define OP_JMP 0600000 /* JMP */ #define OP_HLT 0740040 /* HLT */ @@ -144,19 +153,55 @@ If flag based, API is hard to implement; if API based, IORS requires extra code for implementation. I've chosen an API based model. + API channel Device API priority Notes + + 00 software 4 4 + 01 software 5 5 + 02 software 6 6 + 03 software 7 7 + 04 TC02/TC15 1 + 05 TC59D 1 + 06 drum 1 PDP-9 only + 07 disk 1 PDP-9 only + 10 paper tape reader 2 + 11 real time clock 3 + 12 power fail 0 + 13 memory parity 0 + 14 display 2 + 15 card reader 2 + 16 line printer 2 + 17 A/D converter 0 + 20 interprocessor buffer 3 + 21 360 link 3 PDP-9 only + 22 data phone 2 PDP-15 only + 23 RF09/RF15 1 + 24 RP15 1 PDP-15 only + 25 plotter 1 PDP-15 only + 26 - + 27 - + 30 - + 31 - + 32 - + 33 - + 34 LT15 TTO 3 PDP-15 only + 35 LT15 TTI 3 PDP-15 only + 36 - + 37 - + Interrupt system, priority is left to right. <30:28> = priority 0 <27:20> = priority 1 - <19:14> = priority 2 - <13:10> = priority 3 - <9:4> = PI only - <3> = priority 4 (software) - <2> = priority 5 (software) - <1> = priority 6 (software) - <0> = priority 7 (software) + <19:12> = priority 2 + <11:8> = priority 3 + <7:0> = PI only */ +#define API_L0 0xF0000000 +#define API_L1 0x0FF00000 +#define API_L2 0x000FF000 +#define API_L3 0x00000F00 + #define INT_V_PWRFL 30 /* powerfail */ #define INT_V_DTA 27 /* DECtape */ #define INT_V_MTA 26 /* magtape */ @@ -166,14 +211,12 @@ #define INT_V_PTR 19 /* paper tape reader */ #define INT_V_LPT 18 /* line printer */ #define INT_V_LPTSPC 17 /* line printer spc */ -#define INT_V_CLK 13 /* clock */ -#define INT_V_TTI 9 /* keyboard */ -#define INT_V_TTO 8 /* terminal */ -#define INT_V_PTP 7 /* paper tape punch */ -#define INT_V_SW4 3 /* software 4 */ -#define INT_V_SW5 2 /* software 5 */ -#define INT_V_SW6 1 /* software 6 */ -#define INT_V_SW7 0 /* software 7 */ +#define INT_V_CLK 11 /* clock */ +#define INT_V_TTI1 10 /* LT15 keyboard */ +#define INT_V_TTO1 9 /* LT15 output */ +#define INT_V_TTI 7 /* console keyboard */ +#define INT_V_TTO 6 /* console output */ +#define INT_V_PTP 5 /* paper tape punch */ #define INT_PWRFL (1 << INT_V_PWRFL) #define INT_DTA (1 << INT_V_DTA) @@ -185,13 +228,24 @@ #define INT_LPT (1 << INT_V_LPT) #define INT_LPTSPC (1 << INT_V_LPTSPC) #define INT_CLK (1 << INT_V_CLK) +#define INT_TTI1 (1 << INT_V_TTI1) +#define INT_TTO1 (1 << INT_V_TTO1) #define INT_TTI (1 << INT_V_TTI) #define INT_TTO (1 << INT_V_TTO) #define INT_PTP (1 << INT_V_PTP) -#define INT_SW4 (1 << INT_V_SW4) -#define INT_SW5 (1 << INT_V_SW5) -#define INT_SW6 (1 << INT_V_SW6) -#define INT_SW7 (1 << INT_V_SW7) + +#define ACH_SWRE 040 /* API channels */ +#define ACH_PWRFL 052 +#define ACH_DTA 044 +#define ACH_MTA 045 +#define ACH_DRM 046 +#define ACH_RF 063 +#define ACH_RP 064 +#define ACH_PTR 050 +#define ACH_LPT 056 +#define ACH_CLK 051 +#define ACH_TTI1 075 +#define ACH_TTO1 074 /* I/O status flags for the IORS instruction diff --git a/pdp18b_drm.c b/pdp18b_drm.c index f2075784..29730f15 100644 --- a/pdp18b_drm.c +++ b/pdp18b_drm.c @@ -26,6 +26,7 @@ drm (PDP-7) Type 24 serial drum (PDP-9) RM09 serial drum + 10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware 26-Apr-01 RMS Added device enable/disable support 14-Apr-99 RMS Changed t_addr to unsigned */ @@ -108,14 +109,13 @@ int32 drm61 (int32 pulse, int32 AC) { int32 t; -if (pulse == 001) return (int_req & INT_DRM)? IOT_SKP + AC: AC; /* DRSF */ -if (pulse == 002) { /* DRCF */ +if (pulse & 001) { /* DRSF */ + if (int_req & INT_DRM) AC = AC | IOT_SKP; } +if (pulse & 002) { /* DRCF */ int_req = int_req & ~INT_DRM; /* clear done */ drm_err = 0; } /* clear error */ -if (pulse == 006) { /* DRSS */ +if (pulse & 004) { /* DRSS */ drm_da = AC & DRM_SMASK; /* load sector # */ - int_req = int_req & ~INT_DRM; /* clear done */ - drm_err = 0; /* clear error */ t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time); if (t < 0) t = t + DRM_NUMWDT; /* wrap around? */ sim_activate (&drm_unit, t * drm_time); } /* schedule op */ @@ -126,8 +126,9 @@ int32 drm62 (int32 pulse, int32 AC) { int32 t; -if (pulse == 001) return (drm_err)? AC: IOT_SKP + AC; /* DRSN */ -if (pulse == 004) { /* DRCS */ +if (pulse & 001) { /* DRSN */ + if (drm_err == 0) AC = AC | IOT_SKP; } +if (pulse & 004) { /* DRCS */ int_req = int_req & ~INT_DRM; /* clear done */ drm_err = 0; /* clear error */ t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time); diff --git a/pdp18b_rf.c b/pdp18b_rf.c index a3b643be..4626f70f 100644 --- a/pdp18b_rf.c +++ b/pdp18b_rf.c @@ -187,7 +187,7 @@ if (pulse == 042) { /* DSCD */ if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */ else rf_sta = 0; rf_updsta (0); } -if (pulse == 0062) { /* DSRS */ +if (pulse == 062) { /* DSRS */ if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */ return rf_updsta (0); } return AC; diff --git a/pdp18b_stddev.c b/pdp18b_stddev.c index b4d5ad4f..7730f43c 100644 --- a/pdp18b_stddev.c +++ b/pdp18b_stddev.c @@ -29,6 +29,8 @@ tto teleprinter clk clock + 10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware + 27-May-01 RMS Added multiconsole support 10-Mar-01 RMS Added funny format loader support 05-Mar-01 RMS Added clock calibration support 22-Dec-00 RMS Added PDP-9/15 half duplex support @@ -50,6 +52,10 @@ 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 + t_stat clk_svc (UNIT *uptr); t_stat ptr_svc (UNIT *uptr); t_stat ptp_svc (UNIT *uptr); @@ -195,9 +201,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, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC+UNIT_CONS, 0), KBD_POLL_WAIT }; #else -UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC + UNIT_HDX, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC+UNIT_HDX+UNIT_CONS, 0), KBD_POLL_WAIT }; #endif REG tti_reg[] = { @@ -212,9 +218,16 @@ 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 }, @@ -257,7 +270,7 @@ static const char tto_trans[64] = { #define TTO_MASK ((1 << TTO_WIDTH) - 1) -UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; +UNIT tto_unit = { UDATA (&tto_svc, UNIT_UC+UNIT_CONS, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { { ORDATA (BUF, tto_unit.buf, TTO_WIDTH) }, @@ -268,10 +281,25 @@ 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 }, +#endif + { 0 } }; + DEVICE tto_dev = { - "TTO", &tto_unit, tto_reg, NULL, + "TTO", &tto_unit, tto_reg, tto_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto_reset, NULL, NULL, NULL }; @@ -280,14 +308,16 @@ DEVICE tto_dev = { int32 clk (int32 pulse, int32 AC) { -if (pulse == 001) return (int_req & INT_CLK)? IOT_SKP + AC: AC; /* CLSF */ -if (pulse == 004) clk_reset (&clk_dev); /* CLOF */ -else if (pulse == 044) { /* CLON */ - int_req = int_req & ~INT_CLK; /* clear flag */ - clk_state = 1; /* clock on */ - if (!sim_is_active (&clk_unit)) /* already on? */ - sim_activate (&clk_unit, /* start */ - sim_rtc_init (clk_unit.wait)); } /* init calibr */ +if (pulse & 001) { /* CLSF */ + if (int_req & INT_CLK) AC = AC | IOT_SKP; } +if (pulse & 004) { /* CLON/CLOF */ + if (pulse & 040) { /* CLON */ + int_req = int_req & ~INT_CLK; /* clear flag */ + clk_state = 1; /* clock on */ + if (!sim_is_active (&clk_unit)) /* already on? */ + sim_activate (&clk_unit, /* start, calibr */ + sim_rtc_init (clk_unit.wait)); } + else clk_reset (&clk_dev); } /* CLOF */ return AC; } @@ -335,10 +365,11 @@ return ((int_req & INT_CLK)? IOS_CLK: 0) | int32 ptr (int32 pulse, int32 AC) { -if (pulse == 001) return (int_req & INT_PTR)? IOT_SKP + AC: AC; /* RSF */ +if (pulse & 001) { /* RSF */ + if (int_req & INT_PTR) AC = AC | IOT_SKP; } if (pulse & 002) { /* RRB, RCF */ int_req = int_req & ~INT_PTR; /* clear done */ - AC = ptr_unit.buf; } /* return buffer */ + AC = AC | ptr_unit.buf; } /* return buffer */ if (pulse & 004) { /* RSA, RSB */ ptr_state = (pulse & 040)? 18: 0; /* set mode */ int_req = int_req & ~INT_PTR; /* clear done */ @@ -587,7 +618,8 @@ return SCPE_ARG; int32 ptp (int32 pulse, int32 AC) { -if (pulse == 001) return (int_req & INT_PTP)? IOT_SKP + AC: AC; /* PSF */ +if (pulse & 001) { /* PSF */ + if (int_req & INT_PTP) AC = AC | IOT_SKP; } if (pulse & 002) int_req = int_req & ~INT_PTP; /* PCF */ if (pulse & 004) { /* PSA, PSB, PLS */ int_req = int_req & ~INT_PTP; /* clear flag */ @@ -648,10 +680,11 @@ return detach_unit (uptr); int32 tti (int32 pulse, int32 AC) { -if (pulse == 001) return (int_req & INT_TTI)? IOT_SKP + AC: AC; /* KSF */ -if (pulse == 002) { /* KRB */ +if (pulse & 001) { /* KSF */ + if (int_req & INT_TTI) AC = AC | IOT_SKP; } +if (pulse & 002) { /* KRB */ int_req = int_req & ~INT_TTI; /* clear flag */ - return tti_unit.buf & TTI_MASK; } /* return buffer */ + AC = AC | tti_unit.buf & TTI_MASK; } /* return buffer */ return AC; } @@ -679,7 +712,11 @@ else { if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ temp = temp & 0177; if ((tti_unit.flags & UNIT_UC) && islower (temp)) temp = toupper (temp); -if (tti_unit.flags & UNIT_HDX) sim_putchar (temp); +if ((tti_unit.flags & UNIT_HDX) && + (!(tto_unit.flags & UNIT_UC) || + ((temp >= 007) && (temp <= 0137)))) { + sim_putcons (temp, uptr); + tto_unit.pos = tto_unit.pos + 1; } tti_unit.buf = temp | 0200; /* got char */ #endif int_req = int_req | INT_TTI; /* set flag */ @@ -694,6 +731,9 @@ 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; } @@ -702,7 +742,8 @@ return SCPE_OK; int32 tto (int32 pulse, int32 AC) { -if (pulse == 001) return (int_req & INT_TTO)? IOT_SKP + AC: AC; /* TSF */ +if (pulse & 001) { /* TSF */ + if (int_req & INT_TTO) AC = AC | IOT_SKP; } if (pulse & 002) int_req = int_req & ~INT_TTO; /* clear flag */ if (pulse & 004) { /* load buffer */ sim_activate (&tto_unit, tto_unit.wait); /* activate unit */ @@ -728,8 +769,11 @@ out = tto_trans[tto_unit.buf + tto_state]; /* translate */ #else out = tto_unit.buf & 0177; /* ASCII... */ #endif -if ((temp = sim_putchar (out)) != SCPE_OK) return temp; -tto_unit.pos = tto_unit.pos + 1; +if (!(tto_unit.flags & UNIT_UC) || + ((out >= 007) && (out <= 0137))) { + temp = sim_putcons (out, uptr); + if (temp != SCPE_OK) return temp; + tto_unit.pos = tto_unit.pos + 1; } return SCPE_OK; } @@ -741,5 +785,8 @@ 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 5f642956..798670bc 100644 --- a/pdp18b_sys.c +++ b/pdp18b_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. + 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 14-Mar-01 RMS Added extension detection of RIM format tapes 21-Jan-01 RMS Added DECtape support @@ -39,6 +41,7 @@ extern DEVICE cpu_dev; extern DEVICE ptr_dev, ptp_dev; extern DEVICE tti_dev, tto_dev; +extern UNIT tti_unit, tto_unit; extern DEVICE clk_dev; extern DEVICE lpt_dev; #if defined (DRM) @@ -56,6 +59,10 @@ extern DEVICE mt_dev; #if defined (DTA) extern DEVICE dt_dev; #endif +#if defined (TTY1) +extern DEVICE tti1_dev, tto1_dev; +extern UNIT tti1_unit, tto1_unit; +#endif extern UNIT cpu_unit; extern REG cpu_reg[]; extern int32 M[]; @@ -87,7 +94,8 @@ REG *sim_PC = &cpu_reg[0]; int32 sim_emax = 3; DEVICE *sim_devices[] = { &cpu_dev, - &ptr_dev, &ptp_dev, &tti_dev, &tto_dev, + &ptr_dev, &ptp_dev, + &tti_dev, &tto_dev, &clk_dev, &lpt_dev, #if defined (DRM) &drm_dev, @@ -103,15 +111,28 @@ DEVICE *sim_devices[] = { &cpu_dev, #endif #if defined (MTA) &mt_dev, +#endif +#if defined (TTY1) + &tti1_dev, &tto1_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", "HALT instruction", "Breakpoint", - "Nested XCT's" }; + "Nested XCT's", + "Invalid API interrupt" }; /* Binary loader */ @@ -279,7 +300,7 @@ static const char *opcode[] = { "XCT", "ISZ", "AND", "SAD", "JMP", -#if defined (PDP15) /* mem ref ind */ +#if defined (PDP9) || defined (PDP15) /* mem ref ind */ "CAL*", "DAC*", "JMS*", "DZM*", /* normal */ "LAC*", "XOR*", "ADD*", "TAD*", "XCT*", "ISZ*", "AND*", "SAD*", @@ -346,26 +367,34 @@ static const char *opcode[] = { "MTTR", "MTCR", "MTSF", "MTRC", "MTAF", "MTRS", "MTGO", "MTCM", "MTLC", #endif -#if defined (DTA) +#if defined (DTA) /* TC02/TC15 */ "DTCA", "DTRA", "DTXA", "DTLA", "DTEF", "DTRB", "DTDF", #endif +#if defined (TTY1) + "KSF1", "KRB1", + "TSF1", "TCF1", "TLS1", "TCF1!TLS1", +#endif #if defined (PDP7) "ITON", "TTS", "SKP7", "CAF", "SEM", "EEM", "EMIR", "LEM", -#elif defined (PDP9) - "PFSF", "TTS", "SKP7", "CAF", - "DBR", "SEM", "EEM", "LEM", - "MPSK", "MPSNE", "MPCV", "MPEU", - "MPLD", "MPCNE", +#endif +#if defined (PDP9) + "SKP7", "SEM", "EEM", "LEM", "LPDI", "LPEI", -#elif defined (PDP15) - "PFSF", "TTS", "SPCO", "CAF", - "DBR", "SKP15", "RES", +#endif +#if defined (PDP15) + "SPCO", "SKP15", "RES", "SBA", "DBA", "EBA", "AAS", "PAX", "PAL", "AAC", "PXA", "AXS", "PXL", "PLA", "PLX", "CLAC","CLX", "CLLR", "AXR", +#endif +#if defined (PDP9) || defined (PDP15) + "MPSK", "MPSNE", "MPCV", "MPEU", + "MPLD", "MPCNE", "PFSF", + "TTS", "CAF", "DBK", "DBR", + "SPI", "RPL", "ISA", #endif "IOT", /* general */ @@ -493,22 +522,30 @@ static const int32 opc_val[] = { 0707541+I_NPI, 0707552+I_NPN, 0707544+I_NPI, 0707545+I_NPI, 0707561+I_NPI, 0707572+I_NPN, 0707601+I_NPI, #endif +#if defined (TTY1) + 0704101+I_NPI, 0704112+I_NPN, + 0704001+I_NPI, 0704002+I_NPI, 0704004+I_NPI, 0704006+I_NPI, +#endif #if defined (PDP7) 0703201+I_NPI, 0703301+I_NPI, 0703341+I_NPI, 0703302+I_NPI, 0707701+I_NPI, 0707702+I_NPI, 0707742+I_NPI, 0707704+I_NPI, -#elif defined (PDP9) - 0700062+I_NPI, 0703301+I_NPI, 0703341+I_NPI, 0703302+I_NPI, - 0703344+I_NPI, 0707701+I_NPI, 0707702+I_NPI, 0707704+I_NPI, - 0701701+I_NPI, 0701741+I_NPI, 0701702+I_NPI, 0701742+I_NPI, - 0701704+I_NPI, 0701644+I_NPI, +#endif +#if defined (PDP9) + 0703341+I_NPI, 0707701+I_NPI, 0707702+I_NPI, 0707704+I_NPI, 0706504+I_NPI, 0706604+I_NPI, -#elif defined (PDP15) - 0700062+I_NPI, 0703301+I_NPI, 0703341+I_NPI, 0703302+I_NPI, - 0703344+I_NPI, 0707741+I_NPI, 0707742+I_NPI, +#endif +#if defined (PDP15) + 0703341+I_NPI, 0707741+I_NPI, 0707742+I_NPI, 0707761+I_NPI, 0707762+I_NPI, 0707764+I_NPI, 0720000+I_XR9, 0721000+I_XR, 0722000+I_XR, 0723000+I_XR9, 0724000+I_XR, 0725000+I_XR9, 0726000+I_XR, 0730000+I_XR, 0731000+I_XR, 0734000+I_XR, 0735000+I_XR, 0736000+I_XR, 0737000+I_XR9, +#endif +#if defined (PDP9) || defined (PDP15) + 0701701+I_NPI, 0701741+I_NPI, 0701702+I_NPI, 0701742+I_NPI, + 0701704+I_NPI, 0701744+I_NPI, 0703201+I_NPI, + 0703301+I_NPI, 0703302+I_NPI, 0703304+I_NPI, 0703344+I_NPI, + 0705501+I_NPI, 0705512+I_NPN, 0705504+I_NPI, #endif 0700000+I_IOT, @@ -785,6 +822,8 @@ case I_V_MRF: /* mem ref */ #else dmask = 017777; cptr = get_glyph (cptr, gbuf, 0); /* get next field */ +#endif +#if defined (PDP4) || defined (PDP7) if (strcmp (gbuf, "I") == 0) { /* indirect? */ val[0] = val[0] | 020000; cptr = get_glyph (cptr, gbuf, 0); } diff --git a/pdp18b_tt1.c b/pdp18b_tt1.c new file mode 100644 index 00000000..a55bd0da --- /dev/null +++ b/pdp18b_tt1.c @@ -0,0 +1,190 @@ +/* pdp18b_tt1.c: 18b PDP's second Teletype + + 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. + + tti1 keyboard + tto1 teleprinter + + 10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware +*/ + +#include "pdp18b_defs.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; +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]; + +/* TTI1 data structures + + tti1_dev TTI1 device descriptor + tti1_unit TTI1 unit + tto1_mod TTI1 modifier list + tti1_reg TTI1 register list +*/ + +UNIT tti1_unit = { UDATA (&tti1_svc, 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 (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 }, + { 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, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &tti1_reset, + NULL, NULL, NULL }; + +/* TTO1 data structures + + tto1_dev TTO1 device descriptor + tto1_unit TTO1 unit + tto1_mod TTO1 modifier list + tto1_reg TTO1 register list +*/ + +UNIT tto1_unit = { UDATA (&tto1_svc, UNIT_UC, 0), SERIAL_OUT_WAIT }; + +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 (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, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &tto1_reset, + NULL, NULL, NULL }; + +/* Terminal input: IOT routine */ + +int32 tti1 (int32 pulse, int32 AC) +{ +if (pulse & 001) { /* KSF1 */ + if (int_req & INT_TTI1) AC = AC | IOT_SKP; } +if (pulse & 002) { /* KRB1 */ + int_req = int_req & ~INT_TTI1; /* clear flag */ + AC= AC | tti1_unit.buf; } /* return buffer */ +return AC; +} + +/* Unit service */ + +t_stat tti1_svc (UNIT *uptr) +{ +int32 temp; + +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; +return SCPE_OK; +} + +/* Reset routine */ + +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 */ +return SCPE_OK; +} + +/* Terminal output: IOT routine */ + +int32 tto1 (int32 pulse, int32 AC) +{ +if (pulse & 001) { /* TSF */ + if (int_req & INT_TTO1) AC = AC | IOT_SKP; } +if (pulse & 002) int_req = int_req & ~INT_TTO1; /* clear flag */ +if (pulse & 004) { /* load buffer */ + sim_activate (&tto1_unit, tto1_unit.wait); /* activate unit */ + tto1_unit.buf = AC & 0377; } /* load buffer */ +return AC; +} + +/* Unit service */ + +t_stat tto1_svc (UNIT *uptr) +{ +int32 out, temp; + +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; } +return SCPE_OK; +} + +/* Reset routine */ + +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; +} diff --git a/pdp1_stddev.c b/pdp1_stddev.c index d35843a3..844c6039 100644 --- a/pdp1_stddev.c +++ b/pdp1_stddev.c @@ -28,6 +28,7 @@ tti keyboard tto teleprinter + 10-Jun-01 RMS Fixed comment 30-Oct-00 RMS Standardized device naming */ @@ -260,7 +261,7 @@ static const int32 boot_rom[] = { 0327776, /* dio x */ 0107776, /* xct x */ 0730002, /* rpb + wait */ - 0760400, /* x, halt / + 0760400, /* x, halt */ 0607772 /* jmp r */ }; diff --git a/pdp1_sys.c b/pdp1_sys.c index fbc23590..86faac90 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. + 27-May-01 RMS Added multiconsole support 14-Mar-01 RMS Revised load/dump interface (again) 30-Oct-00 RMS Added support for examine to file 27-Oct-98 RMS V2.4 load interface @@ -50,6 +51,7 @@ 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 */ @@ -64,6 +66,8 @@ 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", @@ -98,11 +102,11 @@ int32 origin, val; if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; for (;;) { if ((val = getword (fileref)) < 0) return SCPE_FMT; - if ((val & 0770000) == 0240000) { /* DAC? */ + if ((val & 0770000) == 0240000) { /* DAC? */ origin = val & 07777; if ((val = getword (fileref)) < 0) return SCPE_FMT; if (MEM_ADDR_OK (origin)) M[origin++] = val; } - else if ((val & 0770000) == 0600000) { + else if ((val & 0770000) == 0600000) { /* JMP? */ PC = val & 007777; return SCPE_OK; } } return SCPE_FMT; /* error */ diff --git a/pdp8_cpu.c b/pdp8_cpu.c index af7b9a1d..ac393bf2 100644 --- a/pdp8_cpu.c +++ b/pdp8_cpu.c @@ -25,6 +25,7 @@ cpu central processor + 07-Jun-01 RMS Fixed bug in JMS to non-existent memory 25-Apr-01 RMS Added device enable/disable support 18-Mar-01 RMS Added DF32 support 05-Mar-01 RMS Added clock calibration support @@ -345,6 +346,10 @@ sim_interval = sim_interval - 1; jump calculations. Data calculations return a full 15b extended address, jump calculations a 12b field-relative address. + Autoindex calculations always occur within the same field as the + instruction fetch. The field must exist; otherwise, the instruction + fetched would be 0000, and indirect addressing could not occur. + Note that MA contains IF'PC. */ @@ -408,12 +413,12 @@ case 007: /* TAD, indir, curr */ case 010: /* ISZ, dir, zero */ ZERO_PAGE; - M[MA] = MB = (M[MA] + 1) & 07777; + M[MA] = MB = (M[MA] + 1) & 07777; /* field must exist */ if (MB == 0) PC = (PC + 1) & 07777; break; case 011: /* ISZ, dir, curr */ CURR_PAGE; - M[MA] = MB = (M[MA] + 1) & 07777; + M[MA] = MB = (M[MA] + 1) & 07777; /* field must exist */ if (MB == 0) PC = (PC + 1) & 07777; break; case 012: /* ISZ, indir, zero */ @@ -461,13 +466,17 @@ case 017: /* DCA, indir, curr */ case 020: /* JMS, dir, zero */ ZERO_PAGE_J; CHANGE_FIELD; - M[IF | MA] = old_PC = PC; + MA = IF | MA; + old_PC = PC; + if (MEM_ADDR_OK (MA)) M[MA] = PC; PC = (MA + 1) & 07777; break; case 021: /* JMS, dir, curr */ CURR_PAGE_J; CHANGE_FIELD; - M[IF | MA] = old_PC = PC; + MA = IF | MA; + old_PC = PC; + if (MEM_ADDR_OK (MA)) M[MA] = PC; PC = (MA + 1) & 07777; break; case 022: /* JMS, indir, zero */ diff --git a/pdp8_rf.c b/pdp8_rf.c index c952cde4..5bb8a3ac 100644 --- a/pdp8_rf.c +++ b/pdp8_rf.c @@ -29,7 +29,7 @@ 19-Mar-01 RMS Added disk monitor bootstrap, fixed IOT decoding 15-Feb-01 RMS Fixed 3 cycle data break sequence 14-Apr-99 RMS Changed t_addr to unsigned - 30-Mar-98 RMS Fixed bug in RF bootstrap. + 30-Mar-98 RMS Fixed bug in RF bootstrap The RF08 is a head-per-track disk. It uses the three cycle data break facility. To minimize overhead, the entire RF08 is buffered in memory. diff --git a/pdp8_sys.c b/pdp8_sys.c index f0682172..fefa1ba3 100644 --- a/pdp8_sys.c +++ b/pdp8_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. + 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 15-Feb-01 RMS Added DECtape support @@ -53,6 +54,7 @@ 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 */ @@ -73,6 +75,8 @@ DEVICE *sim_devices[] = { &dt_dev, &mt_dev, NULL }; +UNIT *sim_consoles = NULL; + const char *sim_stop_messages[] = { "Unknown error", "Unimplemented instruction", diff --git a/scp.c b/scp.c index d2ea2a69..c7474fed 100644 --- a/scp.c +++ b/scp.c @@ -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. + 12-Jun-01 RMS Fixed bug in big-endian I/O (found by Dave Conroy) + 27-May-01 RMS Added multiple console support + 16-May-01 RMS Added logging + 15-May-01 RMS Added features from Tim Litt 12-May-01 RMS Fixed missing return in disable_cmd 25-Mar-01 RMS Added ENABLE/DISABLE 14-Mar-01 RMS Revised LOAD/DUMP interface (again) @@ -53,7 +57,6 @@ #define SCP 1 /* defining module */ #include "sim_defs.h" -#include #include #include #define EX_D 0 /* deposit */ @@ -83,6 +86,7 @@ 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); @@ -96,6 +100,7 @@ extern t_stat ttinit (void); extern t_stat ttrunstate (void); extern t_stat ttcmdstate (void); extern t_stat ttclose (void); +extern t_stat sim_putchar (int32 out); extern uint32 sim_os_msec (void); UNIT *sim_clock_queue = NULL; int32 sim_interval = 0; @@ -106,7 +111,8 @@ static uint32 sim_rtime; static int32 noqueue_time; volatile int32 stop_cpu = 0; t_value *sim_eval = NULL; -int32 sim_end = 1; /* 1 = little, 0 = big */ +int32 sim_end = 1; /* 1 = little */ +FILE *sim_log = NULL; /* log file */ unsigned char sim_flip[FLIP_SIZE]; #define print_val(a,b,c,d) fprint_val (stdout, (a), (b), (c), (d)) @@ -153,6 +159,8 @@ void put_rval (REG *rptr, int idx, t_value val); 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); @@ -201,7 +209,9 @@ const char *scp_error_messages[] = { "Console terminal setup error", "Subscript out of range", "Command not allowed", - "Unit disabled" + "Unit disabled", + "Logging enabled", + "Logging disabled" }; const size_t size_map[] = { sizeof (int8), @@ -255,6 +265,8 @@ t_stat add_cmd (int flag, char *ptr); t_stat remove_cmd (int flag, char *ptr); t_stat enable_cmd (int flag, char *ptr); t_stat disable_cmd (int flag, char *ptr); +t_stat log_cmd (int flag, char *ptr); +t_stat nolog_cmd (int flag, char *ptr); t_stat help_cmd (int flag, char *ptr); static CTAB cmd_table[] = { @@ -284,12 +296,14 @@ static CTAB cmd_table[] = { { "DISABLE", &disable_cmd, 0 }, { "ADD", &add_cmd, 0 }, { "REMOVE", &remove_cmd, 0 }, + { "LOG", &log_cmd, 0 }, + { "NOLOG", &nolog_cmd, 0 }, { "HELP", &help_cmd, 0 }, { NULL, NULL, 0 } }; /* Main command loop */ -printf ("\n%s simulator V2.6\n", sim_name); +printf ("\n%s simulator V2.6a\n", sim_name); end_test.i = 1; /* test endian-ness */ sim_end = end_test.c[0]; if (sim_emax <= 0) sim_emax = 1; @@ -306,13 +320,14 @@ sim_time = sim_rtime = 0; noqueue_time = 0; sim_clock_queue = NULL; sim_is_running = 0; +sim_log = NULL; if ((stat = reset_all (0)) != SCPE_OK) { printf ("Fatal simulator initialization error\n%s\n", scp_error_messages[stat - SCPE_BASE]); return 0; } -if ((argc > 1) && (argv[1] != NULL) && - ((fpin = fopen (argv[1], "r")) != NULL)) { /* command file? */ +if ((argc > 1) && (argv[1] != NULL)) { /* cmd line arg? */ + if ((fpin = fopen (argv[1], "r")) != NULL) { /* cmd file open? */ do { cptr = read_line (cbuf, CBUFSIZE, fpin); if (cptr == NULL) break; /* exit on eof */ if (*cptr == 0) continue; /* ignore blank */ @@ -324,23 +339,28 @@ if ((argc > 1) && (argv[1] != NULL) && if (stat >= SCPE_BASE) printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); } while (stat != SCPE_EXIT); } /* end if cmd file */ + else printf ("Can't open file \"%s\"\n", argv[1]); } /* end if cmd arg */ do { printf ("sim> "); /* prompt */ cptr = read_line (cbuf, CBUFSIZE, stdin); /* read command line */ stat = SCPE_UNK; if (cptr == NULL) continue; /* ignore EOF */ if (*cptr == 0) continue; /* ignore blank */ + if (sim_log) fprintf (sim_log, "sim> %s\n", cbuf); /* log cmd */ cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ for (i = 0; cmd_table[i].name != NULL; i++) { if (MATCH_CMD (gbuf, cmd_table[i].name) == 0) { stat = cmd_table[i].action (cmd_table[i].arg, cptr); break; } } - if (stat >= SCPE_BASE) + if (stat >= SCPE_BASE) { /* error? */ printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); + if (sim_log) fprintf (sim_log, "%s\n", + scp_error_messages[stat - SCPE_BASE]); } } while (stat != SCPE_EXIT); -detach_all (0); -ttclose (); +detach_all (0); /* close files */ +nolog_cmd (0, NULL); /* close log */ +ttclose (); /* close console */ return 0; } @@ -353,36 +373,45 @@ return SCPE_EXIT; /* Help command */ +void fprint_help (FILE *st) +{ +fprintf (st, "r{eset} {ALL|} reset simulator\n"); +fprintf (st, "e{xamine} examine memory or registers\n"); +fprintf (st, "ie{xamine} interactive examine memory or registers\n"); +fprintf (st, "d{eposit} deposit in memory or registers\n"); +fprintf (st, "id{eposit} interactive deposit in memory or registers\n"); +fprintf (st, "l{oad} {} load binary file\n"); +fprintf (st, "du(mp) {} dump binary file\n"); +fprintf (st, "ru{n} {new PC} reset and start simulation\n"); +fprintf (st, "go {new PC} start simulation\n"); +fprintf (st, "c{ont} continue simulation\n"); +fprintf (st, "s{tep} {n} simulate n instructions\n"); +fprintf (st, "b{oot} | bootstrap device\n"); +fprintf (st, "at{tach} attach file to simulated unit\n"); +fprintf (st, "det{ach} detach file from simulated unit\n"); +fprintf (st, "sa{ve} save simulator to file\n"); +fprintf (st, "rest{ore}|ge{t} restore simulator from file\n"); +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} 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, "en{able} enable device\n"); +fprintf (st, "di{sable} disable device\n"); +fprintf (st, "ad{d} add unit to configuration\n"); +fprintf (st, "rem{ove} remove unit from configuration\n"); +fprintf (st, "log enable logging to file\n"); +fprintf (st, "nolog disable logging\n"); +fprintf (st, "h{elp} type this message\n"); +return; +} + t_stat help_cmd (int flag, char *cptr) { -printf ("r{eset} {ALL|} reset simulator\n"); -printf ("e{xamine} examine memory or registers\n"); -printf ("ie{xamine} interactive examine memory or registers\n"); -printf ("d{eposit} deposit in memory or registers\n"); -printf ("id{eposit} interactive deposit in memory or registers\n"); -printf ("l{oad} {} load binary file\n"); -printf ("du(mp) {} dump binary file\n"); -printf ("ru{n} {new PC} reset and start simulation\n"); -printf ("go {new PC} start simulation\n"); -printf ("c{ont} continue simulation\n"); -printf ("s{tep} {n} simulate n instructions\n"); -printf ("b{oot} | bootstrap device\n"); -printf ("at{tach} attach file to simulated unit\n"); -printf ("det{ach} detach file from simulated unit\n"); -printf ("sa{ve} save simulator to file\n"); -printf ("rest{ore}|ge{t} restore simulator from file\n"); -printf ("exi{t}|q{uit}|by{e} exit from simulation\n"); -printf ("set set unit parameter\n"); -printf ("show show device parameters\n"); -printf ("sh{ow} c{onfiguration} show configuration\n"); -printf ("sh{ow} m{odifiers} show modifiers\n"); -printf ("sh{ow} q{ueue} show event queue\n"); -printf ("sh{ow} t{ime} show simulated time\n"); -printf ("en{able} enable device\n"); -printf ("di{sable} disable device\n"); -printf ("ad{d} add unit to configuration\n"); -printf ("rem{ove} remove unit from configuration\n"); -printf ("h{elp} type this message\n"); +fprint_help (stdout); +if (sim_log) fprint_help (sim_log); return SCPE_OK; } @@ -441,13 +470,16 @@ return SCPE_OK; t_stat show_cmd (int flag, char *cptr) { int32 i; +t_stat r; char gbuf[CBUFSIZE]; DEVICE *dptr; -t_stat show_config (int flag); -t_stat show_queue (int flag); -t_stat show_time (int flag); -t_stat show_modifiers (int flag); -t_stat show_device (DEVICE *dptr, int flag); + +t_stat show_config (FILE *st, int flag); +t_stat show_queue (FILE *st, int flag); +t_stat show_time (FILE *st, int flag); +t_stat show_modifiers (FILE *st, int flag); +t_stat show_device (FILE *st, DEVICE *dptr, int flag); + static CTAB show_table[] = { { "CONFIGURATION", &show_config, 0 }, { "DEVICES", &show_config, 1 }, @@ -460,110 +492,118 @@ GET_SWITCHES (cptr, gbuf); /* test for switches */ cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ if (*cptr != 0) return SCPE_ARG; /* now eol? */ for (i = 0; show_table[i].name != NULL; i++) { /* find command */ - if (MATCH_CMD (gbuf, show_table[i].name) == 0) - return show_table[i].action (show_table[i].arg); } + if (MATCH_CMD (gbuf, show_table[i].name) == 0) { + r = show_table[i].action (stdout, show_table[i].arg); + if (sim_log) + show_table[i].action (sim_log, show_table[i].arg); + return r; } } dptr = find_dev (gbuf); /* locate device */ if (dptr == NULL) return SCPE_ARG; /* not found? */ -return show_device (dptr, 0); +r = show_device (stdout, dptr, 0); +if (sim_log) show_device (sim_log, dptr, 0); +return r; } /* Show processors */ -t_stat show_device (DEVICE *dptr, int flag) +t_stat show_device (FILE *st, DEVICE *dptr, int flag) { int32 j, ucnt; t_addr kval; UNIT *uptr; MTAB *mptr; -printf ("%s", dptr -> name); /* print dev name */ +fprintf (st, "%s", dptr -> name); /* print dev name */ if (qdisable (dptr)) { /* disabled? */ - printf (", disabled\n"); + fprintf (st, ", disabled\n"); return SCPE_OK; } for (j = ucnt = 0; j < dptr -> numunits; j++) { /* count units */ uptr = (dptr -> units) + j; if (!(uptr -> flags & UNIT_DIS)) ucnt++; } -if (dptr -> numunits == 0) printf ("\n"); -else { if (ucnt == 0) printf (", all units disabled\n"); - else if (ucnt > 1) printf (", %d units\n", ucnt); - else if (flag) printf ("\n"); } +if (dptr -> numunits == 0) fprintf (st, "\n"); +else { if (ucnt == 0) fprintf (st, ", all units disabled\n"); + else if (ucnt > 1) fprintf (st, ", %d units\n", ucnt); + else if (flag) fprintf (st, "\n"); } if (flag) return SCPE_OK; /* dev only? */ for (j = 0; j < dptr -> numunits; j++) { uptr = (dptr -> units) + j; kval = (uptr -> flags & UNIT_BINK)? 1024: 1000; if (uptr -> flags & UNIT_DIS) continue; - if (ucnt > 1) printf (" unit %d", j); + if (ucnt > 1) fprintf (st, " unit %d", j); if (uptr -> flags & UNIT_FIX) { if (uptr -> capac < kval) - printf (", %d%s", uptr -> capac, + fprintf (st, ", %d%s", uptr -> capac, ((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B"); - else printf (", %dK%s", uptr -> capac / kval, + else fprintf (st, ", %dK%s", uptr -> capac / kval, ((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B"); } if (uptr -> flags & UNIT_ATT) - printf (", attached to %s", uptr -> filename); - else if (uptr -> flags & UNIT_ATTABLE) printf (", not attached"); + fprintf (st, ", attached to %s", uptr -> filename); + else if (uptr -> flags & UNIT_ATTABLE) + 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)) - printf (", %s", mptr -> pstring); } } - printf ("\n"); } + fprintf (st, ", %s", mptr -> pstring); } } + fprintf (st, "\n"); } return SCPE_OK; } -t_stat show_config (int flag) +t_stat show_config (FILE *st, int flag) { int32 i; DEVICE *dptr; -printf ("%s simulator configuration\n\n", sim_name); +fprintf (st, "%s simulator configuration\n\n", sim_name); for (i = 0; (dptr = sim_devices[i]) != NULL; i++) - show_device (dptr, flag); + show_device (st, dptr, flag); return SCPE_OK; } -t_stat show_queue (int flag) +t_stat show_queue (FILE *st, int flag) { DEVICE *dptr; UNIT *uptr; int32 accum; if (sim_clock_queue == NULL) { - printf ("%s event queue empty, time = %-16.0f\n", sim_name, sim_time); + fprintf (st, "%s event queue empty, time = %-16.0f\n", + sim_name, sim_time); return SCPE_OK; } -printf ("%s event queue status, time = %-16.0f\n", sim_name, sim_time); +fprintf (st, "%s event queue status, time = %-16.0f\n", + sim_name, sim_time); accum = 0; for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr -> next) { - if (uptr == &step_unit) printf (" Step timer"); + if (uptr == &step_unit) fprintf (st, " Step timer"); else if ((dptr = find_dev_from_unit (uptr)) != NULL) { - printf (" %s", dptr -> name); - if (dptr -> numunits > 1) printf (" unit %d", + fprintf (st, " %s", dptr -> name); + if (dptr -> numunits > 1) fprintf (st, " unit %d", uptr - dptr -> units); } - else printf (" Unknown"); - printf (" at %d\n", accum + uptr -> time); + else fprintf (st, " Unknown"); + fprintf (st, " at %d\n", accum + uptr -> time); accum = accum + uptr -> time; } return SCPE_OK; } -t_stat show_time (int flag) +t_stat show_time (FILE *st, int flag) { -printf ("Time: %-16.0f\n", sim_time); +fprintf (st, "Time: %-16.0f\n", sim_time); return SCPE_OK; } -t_stat show_modifiers (int flag) +t_stat show_modifiers (FILE *st, int flag) { int i, any; DEVICE *dptr; MTAB *mptr; for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { - any = 0; - for (mptr = dptr -> modifiers; mptr && (mptr -> mask != 0); mptr++) { - if (mptr -> mstring) { - if (any++) printf (", %s", mptr -> mstring); - else printf ("%s %s", dptr -> name, mptr -> mstring); } } - if (any) printf ("\n"); } + any = 0; + for (mptr = dptr -> modifiers; mptr && (mptr -> mask != 0); mptr++) { + if (mptr -> mstring) { + if (any++) fprintf (st, ", %s", mptr -> mstring); + else fprintf (st, "%s %s", dptr -> name, mptr -> mstring); } } + if (any) fprintf (st, "\n"); } return SCPE_OK; } @@ -668,6 +708,43 @@ uptr -> flags = uptr -> flags | UNIT_DIS; /* disable it */ return SCPE_OK; } +/* Logging commands + + log filename open log file + nolog close log file +*/ + +t_stat log_cmd (int flag, char *cptr) +{ +char gbuf[CBUFSIZE]; + +GET_SWITCHES (cptr, gbuf); /* test for switches */ +if (*cptr == 0) return (sim_log? SCPE_LOGON: SCPE_LOGOFF); +cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ +if (*cptr != 0) return SCPE_ARG; /* end of line? */ +nolog_cmd (0, NULL); /* close cur log */ +sim_log = fopen (gbuf, "a"); /* open log */ +if (sim_log == NULL) return SCPE_OPENERR; /* error? */ +printf ("Logging to file \"%s\"\n", gbuf); /* start of log */ +fprintf (sim_log, "Logging to file \"%s\"\n", gbuf); +return SCPE_OK; +} + +t_stat nolog_cmd (int flag, char *cptr) +{ +char gbuf[CBUFSIZE]; + +if (cptr) { + GET_SWITCHES (cptr, gbuf); /* test for switches */ + if (*cptr != 0) return SCPE_ARG; } /* end of line? */ +if (sim_log == NULL) return SCPE_OK; /* no log? */ +printf ("Log file closed\n"); +fprintf (sim_log, "Log file closed\n"); /* close log */ +fclose (sim_log); +sim_log = NULL; +return SCPE_OK; +} + /* Reset command and routines re[set] reset all devices @@ -991,7 +1068,7 @@ else if (strcmp (buf, save_ver25) == 0) { /* version 2.5? */ if (strcmp (buf, sim_name)) { /* name match? */ printf ("Wrong system type: %s\n", buf); fclose (rfile); - return SCPE_OK; } + return SCPE_INCOMP; } READ_I (sim_time); /* sim time */ if (v26) { READ_I (sim_rtime); } /* sim relative time */ @@ -1095,8 +1172,6 @@ t_stat run_cmd (int flag, char *cptr) char gbuf[CBUFSIZE]; int32 i, j, step, unitno; t_stat r; -t_addr k; -t_value pcval; DEVICE *dptr; UNIT *uptr; void int_handler (int signal); @@ -1147,6 +1222,7 @@ 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 */ @@ -1159,11 +1235,26 @@ else { UPDATE_SIM_TIME (noqueue_time); } #if defined (VMS) printf ("\n"); #endif -if (r >= SCPE_BASE) printf ("\n%s, %s: ", scp_error_messages[r - SCPE_BASE], - sim_PC -> name); -else printf ("\n%s, %s: ", sim_stop_messages[r], sim_PC -> name); +fprint_stopped (stdout, r); /* print msg */ +if (sim_log) fprint_stopped (sim_log, r); /* log if enabled */ +return SCPE_OK; +} + +/* Print stopped message */ + +void fprint_stopped (FILE *stream, t_stat v) +{ +int32 i; +t_stat r; +t_addr k; +t_value pcval; +DEVICE *dptr; + +if (v >= SCPE_BASE) fprintf (stream, "\n%s, %s: ", + scp_error_messages[v - SCPE_BASE], sim_PC -> name); +else fprintf (stream, "\n%s, %s: ", sim_stop_messages[v], sim_PC -> name); pcval = get_rval (sim_PC, 0); -print_val (pcval, sim_PC -> radix, sim_PC -> width, +fprint_val (stream, pcval, sim_PC -> radix, sim_PC -> width, sim_PC -> flags & REG_FMT); if (((dptr = sim_devices[0]) != NULL) && (dptr -> examine != NULL)) { for (i = 0; i < sim_emax; i++) sim_eval[i] = 0; @@ -1171,16 +1262,14 @@ if (((dptr = sim_devices[0]) != NULL) && (dptr -> examine != NULL)) { if (r = dptr -> examine (&sim_eval[i], k, dptr -> units, SWMASK ('V')) != SCPE_OK) break; } if ((r == SCPE_OK) || (i > 0)) { - printf (" ("); - if (fprint_sym (stdout, (t_addr) pcval, sim_eval, NULL, SWMASK('M')) > 0) - fprint_val (stdout, sim_eval[0], dptr -> dradix, + fprintf (stream, " ("); + if (fprint_sym (stream, (t_addr) pcval, sim_eval, NULL, SWMASK('M')) > 0) + fprint_val (stream, sim_eval[0], dptr -> dradix, dptr -> dwidth, PV_RZRO); - printf (")"); } } -printf ("\n"); -return SCPE_OK; + fprintf (stream, ")"); } } +fprintf (stream, "\n"); +return; } - -/* Run time routines */ /* Unit service for step timeout, originally scheduled by STEP n command @@ -1227,7 +1316,7 @@ t_stat exdep_cmd (int flag, char *cptr) { char gbuf[CBUFSIZE], *gptr, *tptr; int32 unitno, t; -t_bool log; +t_bool exd2f; t_addr low, high; t_stat reason; DEVICE *dptr, *tdptr; @@ -1242,7 +1331,7 @@ t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int flag, char *ptr, if (*cptr == 0) return SCPE_ARG; /* err if no args */ ofile = NULL; /* no output file */ -log = FALSE; +exd2f = FALSE; sim_switches = 0; /* no switches */ schptr = NULL; /* no search */ stab.logic = SCH_OR; /* default search params */ @@ -1254,13 +1343,13 @@ for (;;) { /* loop through modifiers */ if (*cptr == 0) return SCPE_ARG; /* error if no arguments */ if (*cptr == '@') { /* output file spec? */ if (flag != EX_E) return SCPE_ARG; /* examine only */ - if (log) { /* already got one? */ + if (exd2f) { /* already got one? */ fclose (ofile); /* one per customer */ return SCPE_ARG; } cptr = get_glyph_nc (cptr + 1, gbuf, 0); ofile = fopen (gbuf, "a"); /* open for append */ if (ofile == NULL) return SCPE_OPENERR; - log = TRUE; + exd2f = TRUE; continue; } /* look for more */ cptr = get_glyph (cptr, gbuf, 0); if ((t = get_switches (gbuf)) != 0) { /* try for switches */ @@ -1313,7 +1402,7 @@ for (gptr = gbuf, reason = SCPE_OK; reason = exdep_addr_loop (ofile, schptr, flag, cptr, low, high, dptr, uptr); } /* end for */ -if (log) fclose (ofile); /* close output file */ +if (exd2f) fclose (ofile); /* close output file */ return reason; } @@ -1342,7 +1431,9 @@ for (rptr = lowr; rptr <= highr; rptr++) { if (schptr && !test_search (val, schptr)) continue; if (flag != EX_D) { reason = ex_reg (ofile, val, flag, rptr, idx); - if (reason != SCPE_OK) return reason; } + if (reason != SCPE_OK) return reason; + if (sim_log && (ofile == stdout)) + ex_reg (sim_log, val, flag, rptr, idx); } if (flag != EX_E) { reason = dep_reg (flag, cptr, rptr, idx); if (reason != SCPE_OK) return reason; } } } @@ -1365,7 +1456,9 @@ for (i = low; i <= high; i = i + (dptr -> aincr)) { if (schptr && !test_search (sim_eval[0], schptr)) continue; if (flag != EX_D) { reason = ex_addr (ofile, flag, i, dptr, uptr); - if (reason > SCPE_OK) return reason; } + if (reason > SCPE_OK) return reason; + if (sim_log && (ofile == stdout)) + ex_addr (sim_log, flag, i, dptr, uptr); } if (flag != EX_E) { reason = dep_addr (flag, cptr, i, dptr, uptr, reason); if (reason > SCPE_OK) return reason; } @@ -1452,6 +1545,7 @@ if ((cptr == NULL) || (rptr == NULL)) return SCPE_ARG; if (rptr -> flags & REG_RO) return SCPE_RO; if (flag & EX_I) { cptr = read_line (gbuf, CBUFSIZE, stdin); + if (sim_log) fprintf (sim_log, (cptr? "%s\n": "\n"), cptr); if (cptr == NULL) return 1; /* force exit */ if (*cptr == 0) return SCPE_OK; } /* success */ mask = width_mask[rptr -> width]; @@ -1606,6 +1700,7 @@ char gbuf[CBUFSIZE]; if (dptr == NULL) return SCPE_ARG; if (flag & EX_I) { cptr = read_line (gbuf, CBUFSIZE, stdin); + if (sim_log) fprintf (sim_log, (cptr? "%s\n": "\n"), cptr); if (cptr == NULL) return 1; /* force exit */ if (*cptr == 0) return dfltinc; } /* success */ mask = width_mask[dptr -> dwidth]; @@ -1661,6 +1756,7 @@ if (cptr == NULL) { for (tptr = cptr; tptr < (cptr + size); tptr++) /* remove cr */ if (*tptr == '\n') *tptr = 0; while (isspace (*cptr)) cptr++; /* absorb spaces */ +if (*cptr == ';') *cptr = 0; /* ignore comment */ return cptr; } @@ -2267,11 +2363,12 @@ lcnt = count % nelem; /* count in last buf */ if (lcnt) nbuf = nbuf + 1; else lcnt = nelem; total = 0; +dptr = bptr; /* init output ptr */ for (i = nbuf; i > 0; i--) { c = fread (sim_flip, size, (i == 1? lcnt: nelem), fptr); if (c == 0) return total; total = total + c; - for (j = 0, sptr = sim_flip, dptr = bptr; j < c; j++) { + for (j = 0, sptr = sim_flip; j < c; j++) { for (k = size - 1; k >= 0; k--) *(dptr + k) = *sptr++; dptr = dptr + size; } } return total; @@ -2292,11 +2389,11 @@ lcnt = count % nelem; /* count in last buf */ if (lcnt) nbuf = nbuf + 1; else lcnt = nelem; total = 0; +sptr = bptr; /* init input ptr */ for (i = nbuf; i > 0; i--) { c = (i == 1)? lcnt: nelem; - for (j = 0, sptr = bptr, dptr = sim_flip; j < c; j++) { - for (k = size - 1; k >= 0; k--) - *(dptr + k) = *sptr++; + for (j = 0, dptr = sim_flip; j < c; j++) { + for (k = size - 1; k >= 0; k--) *(dptr + k) = *sptr++; dptr = dptr + size; } c = fwrite (sim_flip, size, c, fptr); if (c == 0) return total; @@ -2354,4 +2451,77 @@ 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 ba528189..bdd968ae 100644 --- a/scp_tty.c +++ b/scp_tty.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. + 15-May-01 RMS Added logging support 05-Mar-01 RMS Added clock calibration support 08-Dec-00 BKR Added OS/2 support 18-Aug-98 RMS Added BeOS support @@ -50,6 +51,7 @@ #undef USE_INT64 /* hack for Windows */ #include "sim_defs.h" int32 sim_int_char = 005; /* interrupt character */ +extern FILE *sim_log; /* VMS routines */ @@ -151,6 +153,7 @@ IOSB iosb; c = out; status = sys$qiow (EFN, tty_chan, IO$_WRITELBLK | IO$M_NOFORMAT, &iosb, 0, 0, &c, 1, 0, 0, 0, 0); +if (sim_log) fputc (c, sim_log); if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTOERR; return SCPE_OK; } @@ -237,7 +240,9 @@ return c | SCPE_KFLAG; t_stat sim_putchar (int32 c) { -if (c != 0177) _putch (c); +if (c != 0177) { + _putch (c); + if (sim_log) fputc (c, sim_log); } return SCPE_OK; } @@ -291,7 +296,8 @@ t_stat sim_putchar (int32 c) { if (c != 0177) { putch (c); - fflush (stdout) ; } + fflush (stdout) ; + if (sim_log) fputc (c, sim_log); } return SCPE_OK; } @@ -381,6 +387,7 @@ char c; c = out; write (1, &c, 1); +if (sim_log) fputc (c, sim_log); return SCPE_OK; } @@ -480,6 +487,7 @@ char c; c = out; write (1, &c, 1); +if (sim_log) fputc (c, sim_log); return SCPE_OK; } diff --git a/sim_defs.h b/sim_defs.h index 9f6d0317..e3a92d2b 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -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. + 27-May-01 RMS Added multiple console support + 15-May-01 RMS Increased string buffer size 25-Feb-01 RMS Revisions for V2.6 15-Oct-00 RMS Editorial revisions for V2.5 11-Jul-99 RMS Added unsigned int data types @@ -53,6 +55,7 @@ #include #include #include +#include #ifndef TRUE #define TRUE 1 @@ -90,7 +93,11 @@ typedef int32 t_mtrlnt; /* magtape rec lnt */ #define MTRF(x) ((x) & (1u << 31)) /* record error flg */ #define MTRL(x) ((x) & ((1u << 31) - 1)) /* record length */ #define FLIP_SIZE (1 << 16) /* flip buf size */ -#define CBUFSIZE 128 /* string buf size */ +#if !defined (PATH_MAX) /* usually in limits */ +#define PATH_MAX 512 +#endif +#define CBUFSIZE (128 + PATH_MAX) /* string buf size */ +#define CONS_SIZE 4096 /* console buffer */ /* Simulator status codes @@ -128,6 +135,8 @@ typedef int32 t_mtrlnt; /* magtape rec lnt */ #define SCPE_SUB (SCPE_BASE + 24) /* subscript err */ #define SCPE_NOFNC (SCPE_BASE + 25) /* func not imp */ #define SCPE_UDIS (SCPE_BASE + 26) /* unit disabled */ +#define SCPE_LOGON (SCPE_BASE + 27) /* logging enabled */ +#define SCPE_LOGOFF (SCPE_BASE + 28) /* logging disabled */ #define SCPE_KFLAG 01000 /* tti data flag */ /* Print value format codes */ @@ -211,7 +220,9 @@ struct unit { #define UNIT_BUF 000400 /* buffered */ #define UNIT_DISABLE 001000 /* disable-able */ #define UNIT_DIS 002000 /* disabled */ -#define UNIT_V_UF 11 /* device specific */ +#define UNIT_CONS 004000 /* active console */ +#define UNIT_V_CONS 11 +#define UNIT_V_UF 12 /* device specific */ /* Register data structure */ @@ -310,3 +321,5 @@ 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 t_stat set_console (UNIT *uptr, int32 flag); +EXTERN t_stat sim_putcons (int32 out, UNIT *uptr); diff --git a/simh.doc b/simh.doc index 099a127b..ebe8110b 100644 --- a/simh.doc +++ b/simh.doc @@ -1,75 +1,131 @@ {\rtf1\ansi\ansicpg1252\uc1 \deff0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;} -{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f16\froman\fcharset238\fprq2 Times New Roman CE;}{\f17\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f19\froman\fcharset161\fprq2 Times New Roman Greek;} -{\f20\froman\fcharset162\fprq2 Times New Roman Tur;}{\f21\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f22\fswiss\fcharset238\fprq2 Arial CE;}{\f23\fswiss\fcharset204\fprq2 Arial Cyr;}{\f25\fswiss\fcharset161\fprq2 Arial Greek;} -{\f26\fswiss\fcharset162\fprq2 Arial Tur;}{\f27\fswiss\fcharset186\fprq2 Arial 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;}{\*\cs10 \additive Default Paragraph Font;}}{\*\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\listtemplateid-1866037950{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\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 ;}\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\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\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}}{\*\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}}{\info -{\title Writing a Simulator for the SIMH System}{\author Bob Supnik}{\operator Bob Supnik}{\creatim\yr1997\mo8\dy30\hr19}{\revtim\yr2001\mo4\dy14\hr22\min39}{\version16}{\edmins431}{\nofpages15}{\nofwords5229}{\nofchars29808} -{\*\company Digital Equipment Corporation}{\nofcharsws0}{\vern113}}\widowctrl\ftnbj\aenddoc\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\adjustright \fs20\cgrid {\f1 Writing a Simulator for the SIMH System -\par Revised 30-Apr-01 for V2.6 +{\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 \par -\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 1.\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\adjustright {\f1 Overview -\par }\pard \widctlpar\adjustright {\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 t -h -e 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. Inste -a -d, 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 suggestions for utilizing the services SIMH offers and explains the constraints which a -ll simulators operating within SIMH will experience. +\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 -\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 +\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 60\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 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 -\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 2.\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\adjustright {\f1 Data Types -\par }\pard \widctlpar\adjustright {\f1 -\par SIMH is written in C. The host s -ystem 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 interfaces: +\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 \par \tab SIMH data type\tab \tab \tab interpretation in typical 32-bit C \par @@ -91,8 +147,8 @@ ystem must support (at least) 32-bit data types (64-bit data types for the PDP-1 \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\cgrid \hich\af1\dbch\af0\loch\f1 3.\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\adjustright {\f1 VM Organization -\par }\pard \widctlpar\adjustright {\f1 +\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 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 @@ -103,8 +159,8 @@ ystem must support (at least) 32-bit data types (64-bit data types for the PDP-1 \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 h -ave 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: @@ -115,6 +171,7 @@ s command and control functions. The interfaces between a VM and SCP are relati \par \tab REG *}{\b\f1 sim_pc}{\f1 \tab \tab \tab pointer to simulated program counter \par \tab int32 }{\b\f1 sim_emax}{\f1 \tab \tab maximum number of words in an instruction \par \tab DEVICE *}{\b\f1 sim_devices[]}{\f1 \tab table of pointers to simulated devices, NULL terminated +\par \tab UNIT }{\b\f1 *sim_consoles[]}{\f1 \tab \tab table of pointers to simulated consoles \par \tab char *}{\b\f1 sim_stop_messages[]}{\f1 \tab table of pointers to error messages \par \tab t_stat }{\b\f1 sim_load}{\f1 (\'85)\tab \tab binary loader subroutine \par \tab t_stat }{\b\f1 sim_inst}{\f1 (void)\tab \tab instruction execution subroutine @@ -124,47 +181,52 @@ 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\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 the 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 routines in scp_tty.c. +\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\cgrid \hich\af1\dbch\af0\loch\f1 3.1\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\f1 CPU Organization -\par }\pard \widctlpar\adjustright {\f1 +\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 Most CPU\rquote s perform at least the following functions: \par -\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 {\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 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\cgrid \hich\af1\dbch\af0\loch\f1 3.1.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Time Base -\par }\pard \widctlpar\adjustright {\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 instructions executed), but it must be consistent -ly used throughout the VM. All existing VM\rquote s count time in instructions. +\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 \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\cgrid \hich\af1\dbch\af0\loch\f1 3.1.2\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Memory Organization -\par }\pard \widctlpar\adjustright {\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 that the crit -erion 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 {\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 \par \tab Simulator\tab \tab memory size\tab \tab memory declaration \par @@ -174,16 +236,16 @@ resulting VM endian-dependent. Instead, the VM should be based on the underlyin \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\cgrid \hich\af1\dbch\af0\loch\f1 3.1.3\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Interrupt Organization -\par }\pard \widctlpar\adjustright {\f1 +\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 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 inter -rupts, 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 s -imulators 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 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. \par -\par In the simplest structure, interrupt requests correspond to device flags and are kept in an interrupt reques -t 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 t -est is very fast: +\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 \par \tab if (int_enable && int_requests) \{ \'85process interrupt\'85 \} \par @@ -196,114 +258,120 @@ est 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 -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 variables: interrupt requests, device flags, and interrupt enable mask. The fetch-phase test does not cha -nge; however, the evaluation of whether an interrupt is pending now requires an extra step: +\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 \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 priori -ty 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 interrupt -ing device. +\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 -\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 -of execution, I/O instruction issued, device time out occurs). This makes fetch-phase evaluation simple and isolates interrupt evaluation to a common subroutine. +\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\cgrid \hich\af1\dbch\af0\loch\f1 3.1.4\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 I/O Dispatching -\par }\pard \widctlpar\adjustright {\f1 +\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 I/O dispatching consists of four steps: \par -\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 \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 -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 contain -ing 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-existent 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 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\cgrid \hich\af1\dbch\af0\loch\f1 3.1.5\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Instruction Execution -\par }\pard \widctlpar\adjustright {\f1 +\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 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, the 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. Th -e actual instruction fetch and execute cycle is usually structured as a loop controlled by an error variable, e.g., +\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 \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\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 +\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 Check for outstanding interrupts and process if required. -\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 +\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 Check for other processor-unique events, such as wait-state outstanding or traps outstanding. -\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 +\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 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 \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 +\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 \widctlpar\adjustright {\f1 +\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 \par A few guidelines for implementation: \par -\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 +\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 In general, code should reflect the hardware being simulated. This is usually simplest and easiest to debug. -\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 +\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 \widctlpar\adjustright {\f1 -\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\f1 Peripheral Device Organization -\par }\pard \widctlpar\adjustright {\f1 -\par The basic elements of a VM are devices, ea -ch 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 r -e -presenting 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 }\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 -\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 hos -t-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 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 -\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 de -vice performs similar operations on all of them, depending on which one has been selected 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 sele +cted 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 -\par For each structural level, SIMH defines, and the VM must supply, a corresponding data structure. }{\b\f1 device}{\f1 structures correspond to devices, }{\b\f1 reg}{\f1 structures to registers, and }{\b\f1 unit}{\f1 structures to units. These st -ructures are described in detail in section 4. +\par For each structural level, SIMH defines, and the VM must supply, a corresponding data structure. }{\b\f1 device}{\f1 structures correspond to devices, }{\b\f1 reg}{\f1 structures to registers, and }{\b\f1 unit}{\f1 + structures to units. These structures are described in detail in section 4. \par \par The primary functions of a peripheral are: \par -\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 wi -ll 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 understandi -ng of 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 +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\cgrid \hich\af1\dbch\af0\loch\f1 3.2.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Device Timing -\par }\pard \widctlpar\adjustright {\f1 -\par The principal problem in I/O device simulation is imitating asynchronous operations in a sequential simulation environment. Fortuna -tely, 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 externally generated (disk, paper tape r -eader) 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 calculated. +\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 \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 @@ -314,48 +382,48 @@ eader) is crucial. With an externally timed device, there is no way to know whe \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 structure, described in section 3. To set up a timed operation, the perip -heral 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 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 -\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 queue with the specified waiting p -eriod. 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 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 }\pard \widctlpar\adjustright {\f1 -\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2.2\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Clock Calibration -\par }\pard \widctlpar\adjustright {\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_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 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\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 {\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 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 @@ -368,65 +436,65 @@ eriod. A waiting period of 0 is legal; negative waits cause an error. If the u \par \par \tab sim_activate (&clk_unit, sim_rtc_calb (clk_ticks_per_second); \par -\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2.3\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Data I/O -\par }\pard \widctlpar\adjustright {\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 {\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 \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\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 +\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 Line printers should write data as 7-bit ASCII, with newlines replacing carriage-return/line-feed sequences. -\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 +\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 \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 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 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 +\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 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 \widctlpar\adjustright {\f1 -\par Data I/O v -aries between fixed and variable capacity devices, 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 l -a -tter may expand indefinitely. A buffered device 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 fixed capacity. +\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 -\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2.3.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\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 {\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 -\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 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 \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\cgrid \hich\af1\dbch\af0\loch\f1 3.2.3.2\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl3\adjustright {\f1 Console I/O -\par }\pard \widctlpar\adjustright {\f1 +\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\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 {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\adjustright {\f1 Data Structures -\par }\pard \widctlpar\adjustright {\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_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 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 -\par {\listtext\pard\plain\b\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.1\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\b\f1 device}{\f1 Structure -\par }\pard \widctlpar\adjustright {\f1 +\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 \li720\widctlpar\adjustright {\f1 struct device \{ +\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\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 */ @@ -444,18 +512,18 @@ are sequential; all buffered devices are fixed capacity. \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 \widctlpar\adjustright {\f1 +\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 \par The fields are the following: \par -\par }\pard \li720\widctlpar\adjustright {\b\f1 name}{\f1 \tab \tab device name, string of all capital alphanumeric characters. +\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 }{\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 \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 }\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 }{\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. @@ -463,61 +531,61 @@ are sequential; all buffered devices are fixed capacity. \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 \widctlpar\adjustright {\f1 -\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.1.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Examine and Deposit Routines -\par }\pard \widctlpar\adjustright {\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 s -pecial examine and deposit routines. The calling sequences are: +\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 -\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 }\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 \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 \widctlpar\adjustright {\f1 -\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.1.2\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Reset Routine -\par }\pard \widctlpar\adjustright {\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.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 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\cgrid \hich\af1\dbch\af0\loch\f1 4.1.3\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Boot Routine -\par }\pard \widctlpar\adjustright {\f1 +\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 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\cgrid \hich\af1\dbch\af0\loch\f1 4.1.4\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Attach and Detach Routines -\par }\pard \widctlpar\adjustright {\f1 +\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 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 \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 }\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 \par t_stat }{\i\f1 detach_routine}{\f1 (UNIT *uptr) \endash Detach unit }{\i\f1 uptr}{\f1 . -\par }\pard \widctlpar\adjustright {\f1 +\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\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 \li720\widctlpar\adjustright {\f1 t_stat lpt_attach (UNIT *uptr, char *cptr) \{ -\par }\pard \fi720\li720\widctlpar\adjustright {\f1 t_stat r; +\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 if ((r = attach_unit (uptr, cptr)) != SCPE_OK) return r; \par lpt_error = 0; \par return SCPE_OK; -\par }\pard \li720\widctlpar\adjustright {\f1 \} +\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\f1 \} \par \par t_stat lpt_detach (UNIT *uptr) \{ \par \tab lpt_error = 1; \par \tab return detach_unit (uptr); \par \} -\par }\pard \widctlpar\adjustright {\f1 -\par {\listtext\pard\plain\b\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.2\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\b\f1 unit}{\f1 Structure -\par }\pard \widctlpar\adjustright {\b\f1 +\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 -\par }\pard \li720\widctlpar\adjustright {\f1 struct unit \{ +\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\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 */ @@ -533,10 +601,10 @@ pecial examine and deposit routines. The calling sequences are: \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 \widctlpar\adjustright {\f1 +\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 \par The fields are the following \par -\par }\pard \li720\widctlpar\adjustright {\b\f1 next}{\f1 \tab \tab pointer to next unit in active queue, NULL if none. +\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 }{\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. @@ -549,7 +617,7 @@ pecial examine and deposit routines. The calling sequences are: \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 \widctlpar\adjustright {\b\f1 +\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\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 @@ -562,11 +630,11 @@ pecial examine and deposit routines. The calling sequences are: \par \par defines the line printer as a sequential unit with a wait time of 500. \par -\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.2.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Unit Flags -\par }\pard \widctlpar\adjustright {\f1 +\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 The }{\b\f1 flags }{\f1 field contains indicators of current unit status. SIMH defines 11 flags: \par -\par }\pard \li720\widctlpar\adjustright {\f1 flag name\tab \tab meaning if set +\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\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. @@ -578,24 +646,24 @@ pecial examine and deposit routines. The calling sequences are: \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 \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 below). Devi -ce-specific flags and UNIT_DIS are not automatically saved and restored; the device must supply a register covering these bits. +\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\cgrid \hich\af1\dbch\af0\loch\f1 4.2.2\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Service Routine -\par }\pard \widctlpar\adjustright {\f1 +\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 This routine is called by }{\b\f1 sim_process_event}{\f1 when a unit times out. Its calling sequence is: \par -\par }\pard \fi720\widctlpar\adjustright {\f1 t_stat }{\i\f1 service_routine}{\f1 (UNIT *uptr) -\par }\pard \widctlpar\adjustright {\f1 +\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 -\par {\listtext\pard\plain\b\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.3\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\b\f1 reg}{\f1 Structure -\par }\pard \widctlpar\adjustright {\b\f1 +\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 \li720\widctlpar\adjustright {\f1 struct reg \{ +\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\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 */ @@ -604,19 +672,19 @@ ce-specific flags and UNIT_DIS are not automatically saved and restored; the dev \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 \widctlpar\adjustright {\f1 +\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 \par The fields are the following: \par -\par }\pard \li720\widctlpar\adjustright {\b\f1 name}{\f1 \tab \tab device name, string of all capital alphanumeric characters. +\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 }{\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 \widctlpar\adjustright {\f1 -\par The }{\b\f1 depth}{\f1 field is only used with special \ldblquote arrayed registers\rdblquote , like the data buffer in t -he 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 \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 \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 @@ -639,11 +707,11 @@ he PDP floppy disk controller. Arrayed registers cannot be examined or deposite \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\cgrid \hich\af1\dbch\af0\loch\f1 4.3.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Register Flags -\par }\pard \widctlpar\adjustright {\f1 +\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 \li720\widctlpar\adjustright {\f1 flag name\tab \tab meaning if specified +\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\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. @@ -653,78 +721,82 @@ he PDP floppy disk controller. Arrayed registers cannot be examined or deposite \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\cgrid \hich\af1\dbch\af0\loch\f1 4.4\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\b\f1 mtab}{\f1 Structure -\par }\pard \widctlpar\adjustright {\b\f1 +\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 }{\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 \li720\widctlpar\adjustright {\f1 struct mtab \{ +\par }\pard \ql \li720\ri0\widctlpar\faauto\adjustright\rin0\lin720\itap0 {\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 \widctlpar\adjustright {\f1 +\par }\pard \ql \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\f1 \par The fields are the following: \par -\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 }\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 }{\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 \fi-1440\li1440\widctlpar\adjustright {\f1 -\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.4.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Validation Routine -\par }\pard \widctlpar\adjustright {\f1 +\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 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 \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 {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.5\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\f1 Other Data Structures -\par }\pard \widctlpar\adjustright {\f1 +\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 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 \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\cgrid \hich\af1\dbch\af0\loch\f1 5.\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\adjustright {\f1 VM Provided Routines -\par }\pard \widctlpar\adjustright {\f1 -\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 5.1\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\f1 Instruction Execution -\par }\pard \widctlpar\adjustright {\f1 +\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 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\cgrid \hich\af1\dbch\af0\loch\f1 5.2\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\f1 Binary Load and Dump -\par }\pard \widctlpar\adjustright {\f1 +\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 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 \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 }\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 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\cgrid \hich\af1\dbch\af0\loch\f1 5.3\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\f1 Symbolic Examination and Deposit -\par }\pard \widctlpar\adjustright {\f1 +\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 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 \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 }\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 \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 \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 }\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 \par \tab input\tab \tab \tab \tab return value \par @@ -741,5 +813,59 @@ he PDP floppy disk controller. Arrayed registers cannot be examined or deposite \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 \ldblquote (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 \'93 (double quote) is interpreted to mean a character string. +\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 +\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 +\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 +\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 +\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 +\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 +\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 \par }} \ No newline at end of file diff --git a/simh_doc.txt b/simh_doc.txt index 273fb9bb..0bab626a 100644 --- a/simh_doc.txt +++ b/simh_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik -Subj: Simulator Usage, V2.6 -Date: 3-May-01 +Subj: Simulator Usage, V2.6a +Date: 15-Jun-01 COPYRIGHT NOTICE @@ -161,6 +161,8 @@ Multiple switches may be specified separately or together: -abcd or -a -b -c -d are treated identically. Verbs, switches, and other input (except for file names) are case insensitive. +Any command beginning with semicolon (;) is considered a comment and ignored. + 3.1 Loading and Saving Programs The LOAD command (abbreviation LO) loads a file in binary paper-tape @@ -419,7 +421,20 @@ specified unit from the configuration. Once removed, a unit cannot be manipulated in any way until it is added back to the configuration. ADD adds back a unit that had been removed from the configuration. -3.11 Exiting The Simulator +3.11 Logging Console Output + +Output to the console can be logged simultaneously to a file. Logging is +enabled by the LOG command: + + sim> LOG -- log console output to file + +Logging is disabled by the NOLOG command: + + sim> NOLOG -- disable logging + +LOG with no argument displays whether logging is enabled or disabled. + +3.12 Exiting The Simulator EXIT (synonyms QUIT and BYE) returns control to the operating system. @@ -1704,6 +1719,22 @@ 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 @@ -1763,21 +1794,23 @@ Error handling is as follows: OS I/O error x report error and stop -6.2.3 Terminal Input (TTI) +6.2.3 Terminal Input (TTI, TTI1) -The terminal input reads from the controling console port. Terminal -options include the ability to set limited Dasher compatibility mode or -normal mode: +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: SET TTI ANSI normal mode SET TTI DASHER Dasher mode SET TTO ANSI normal mode SET TTO DASHER Dasher mode -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. +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. -The terminal input implements these registers: +The terminal inputs implement these registers: name size comments @@ -1789,21 +1822,22 @@ The terminal input implements these registers: POS 31 number of characters input TIME 24 keyboard polling interval -6.2.4 Terminal Output (TTO) +6.2.4 Terminal Output (TTO, TTO1) -The terminal output writes to the controling console port. Terminal -options include the ability to set limited Dasher compatibility mode or -normal mode: +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: SET TTI ANSI normal mode SET TTI DASHER Dasher mode SET TTO ANSI normal mode SET TTO DASHER Dasher mode -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. +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. -The terminal output implements these registers: +The terminal outputs implement these registers: name size comments @@ -1890,69 +1924,6 @@ Error handling is as follows: OS I/O error x report error and stop -6.2.8 Second Terminal Input (TTI1) - -The second terminal input (TTI1) reads data from a disk file. When a -file is attached, the second terminal input will read characters at -the interval specified by the TIME register. Detaching the file, or -reaching end of file, stops input. The POS register specifies the -number of the next data item to be read. Thus, by changing POS, the -user can backspace or advance the input stream. - -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 position in the input file - TIME 24 time from I/O initiation to interrupt - STOP_IOE 1 stop on I/O error - -Error handling is as follows: - - error STOP_IOE processed as - - not attached 1 report error and stop - 0 out of tape or paper - - end of file 1 report error and stop - 0 out of tape or paper - - OS I/O error x report error and stop - -6.2.9 Second Terminal Output (TTO1) - -The second terminal output (TTO1) writes data to a disk file. The -POS register specifies the number of the next data item to be written. -Thus, by changing POS, the user can backspace or advance the output -stream. - -The second terminal outpout 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 position in the output file - TIME 24 time from I/O initiation to interrupt - STOP_IOE 1 stop on I/O error - -Error handling is as follows: - - error STOP_IOE processed as - - not attached 1 report error and stop - 0 out of tape or paper - - OS I/O error x report error and stop - 6.3 Fixed Head Disk (DK) The fixed head disk controller implements these registers: @@ -2528,11 +2499,13 @@ PDP-7 CPU PDP-7 CPU with 32KW of memory PDP-9 CPU PDP-9 CPU with 32KW of memory - KE09A extended arithmetic element (EAE) + - KF09A automatic priority interrupt (API) - KG09B memory extension - KP09A power detection - KX09A memory protection PTR,PTP PC09A paper tape reader/punch TTI,TTO KSR 33 console terminal + TTI1,TTO1 LT09A second console terminal LPT Type 647E line printer CLK integral real-time clock RF RF09/RS09 fixed-head disk @@ -2541,10 +2514,12 @@ PDP-9 CPU PDP-9 CPU with 32KW of memory PDP-15 CPU PDP-15 CPU with 32KW of memory - KE15 extended arithmetic element (EAE) + - KA15 automatic priority interrupt (API) - KF15 power detection - KM15 memory protection PTR,PTP PC15 paper tape reader/punch TTI,TTO KSR 35 console terminal + TTI1,TTO1 LT15 second console terminal LPT LP15 line printer CLK integral real-time clock RP RP15/RP02 disk pack @@ -2569,10 +2544,13 @@ specified, the file is assumed to be BIN format. 8.1 CPU -The only CPU options are the presence of the EAE and the size of main memory. +The CPU options are the presence of the EAE, the presense of the API (for +the PDP-9 and PDP-15), and the size of main memory. SET CPU EAE enable EAE SET CPU NOEAE disable EAE + SET CPU API enable API + SET CPU NOAPI disable API SET CPU 4K set memory size = 4K SET CPU 8K set memory size = 8K SET CPU 12K set memory size = 12K @@ -2638,6 +2616,22 @@ 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 @@ -2700,18 +2694,20 @@ Error handling is as follows: OS I/O error x report error and stop -8.2.3 Terminal Input (TTI) +8.2.3 Terminal Input (TTI, TTI1) -The terminal input (TTI) reads from the controling console port. The -terminal input has one option, UC; when set, it automatically converts -lower case input to upper case. +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 PDP-9 and PDP-15 operated the terminal, by default, as half-duplex. -For backward compatibility, on the PDP-9 and PDP-15 the terminal input -has a second option, FDX; when set, it operates the terminal input in -full-duplex mode. +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 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 input implements these registers: +The terminal inputs implement these registers: name size comments @@ -2721,10 +2717,14 @@ The terminal input implements these registers: POS 31 number of characters input TIME 24 keyboard polling interval -8.2.4 Terminal Output (TTO)n backspace or advance these devices. +8.2.4 Terminal Output (TTO, TTO1) -The terminal output (TTO) writes to the controling console port. It -implements these registers: +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 outputs implement these registers: name size comments @@ -4172,9 +4172,12 @@ the file format to try to determine the file type. 12.1 CPU -The only CPU option is the choice of standard or ITS compatible microcode. +The CPU options allow the user to specify standard microcode, standard +microcode with a bug fix for a boostrap problem in TOPS-20 V4.1, or ITS +microcode SET CPU STANDARD Standard microcode + SET CPU TOPS20V41 Standard microcode with TOPS-20 V4.1 bug fix SET CPU ITS ITS compatible microcode CPU registers include the visible state of the processor as well as the @@ -4663,12 +4666,22 @@ legend: y = runs operating system or sample program Revision History (since Rev 1.1) -Rev 2.6a, Jul, 01 +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 - Added FE CTRL-C option for Windoze + 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 + Added PDP-10 FE CTRL-C option for Windoze + Added console logging + Added multiple console support + Added comment recognition Rev 2.6, May, 01 Added ENABLE/DISABLE devices diff --git a/simh_swre.txt b/simh_swre.txt index 1de967c6..748acee4 100644 --- a/simh_swre.txt +++ b/simh_swre.txt @@ -457,9 +457,62 @@ To load and run BASIC: RUN 1.41421 -9. PDP-10 TOPS-10 7.03 +9. PDP-9/PDP-15 Advanced Software System/Keyboard Monitor + +The Advanced Software System was a family of operating systems for the +PDP-9 and PDP-15, ranging from a paper-tape basic system, through the +DECtape or disk based Keyboard Monitor, through the Foreground/Background +Monitor, to DOS-15. To run ADSS/KM from simulated DECtape: + +- On the PDP-9 (only), initialize extend mode to on: + + sim> d extm_init 1 + +- Load the paper-tape bootstrap into upper memory: + + sim> load dec-15u.rim 77637 + +- 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 adss15_32k.dtp + +- Run the bootstrap: + + sim> run + +- The DECtape will boot and print out + + KMS9-15 V5B000 + $ + + and is now ready for commands. Recognized commands include: + + D list system device directory + I list available commands + R list device assignments + SCOM list systems communication region + +- To run Focal, assign unused DAT slot 10 and then load Focal + + $A LPA0 10 + $GLOAD + LOADER V5B000 + >_FOCAL + FOCAL V9A + *TYPE 2+2,! + 4.0000 + * + +10. PDP-10 TOPS-10 7.03, TOPS-20 V4.1 TOPS-10 was the primary time-shared operating system for the PDP-10. -Installation and distribution tapes for TOPS-10 7.03 are available at -http://pdp-10.trailing-edge.com. +TOPS-20 was a popular alternative derived from the BBN TENEX system. +Installation and distribution tapes for TOPS-10 7.03 and TOPS-20 4.1 +are available at http://pdp-10.trailing-edge.com. + [end simh_swre.txt]