diff --git a/PDP10/ks10_cty.c b/PDP10/ks10_cty.c new file mode 100644 index 0000000..32f11ed --- /dev/null +++ b/PDP10/ks10_cty.c @@ -0,0 +1,268 @@ +/* ks10_cty.c: KS-10 front end (console terminal) simulator + + Copyright (c) 2021, Richard Cornwell + + 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 + RICHARD CORNWELL 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 Richard Cornwell shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Richard Cornwell + +*/ + +#include "kx10_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" +#include + +#if KS +#define UNIT_DUMMY (1 << UNIT_V_UF) + +#define STATUS 031 +#define CTY_IN 032 +#define CTY_OUT 033 +#define KLINK_IN 034 +#define KLINK_OUT 035 +#define BOOT_ADDR 036 +#define BOOT_DRIVE 037 +#define MAG_FMT 040 + +#define KA_FAIL 0000000000001 /* Keep Alive failed to change */ +#define FORCE_RELOAD 0000000000002 /* Force reload */ +#define PWR_FAIL1 0000000000004 /* Power failure */ +#define BOOT_SW 0000000000010 /* Boot switch */ +#define KEEP_ALIVE 0000000077400 /* Keep alive */ +#define TRAPS_ENB 0000400000000 /* Traps enabled */ +#define ONE_MS 0001000000000 /* 1ms enabled */ +#define CACHE_ENB 0002000000000 /* Cache enable */ +#define DP_PAR_ENB 0004000000000 /* DP parity error enable */ +#define CRAM_PAR_ENB 0010000000000 /* CRAM parity error enable */ +#define PAR_ENB 0020000000000 /* Parity error detect enable */ +#define KLINK_ENB 0040000000000 /* Klink active */ +#define EX_KEEP_ALV 0100000000000 /* Examine Keep Alive */ +#define RELOAD 0200000000000 /* Reload */ + +#define CTY_CHAR 0000000000400 /* Character pending */ +#define KLINK_CHAR 0000000000400 /* Character pending */ +#define KLINK_ACT 0000000001000 /* KLINK ACTIVE */ +#define KLINK_HANG 0000000001400 /* KLINK HANGUP */ + +extern int32 tmxr_poll; +t_stat ctyi_svc (UNIT *uptr); +t_stat ctyo_svc (UNIT *uptr); +t_stat ctyrtc_srv(UNIT * uptr); +t_stat cty_reset (DEVICE *dptr); +t_stat cty_stop_os (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +const char *cty_description (DEVICE *dptr); + +static int32 rtc_tps = 1; + +struct _buffer { + int in_ptr; /* Insert pointer */ + int out_ptr; /* Remove pointer */ + char buff[32]; /* Buffer */ +} cty_in, cty_out; + +#define full(q) ((((q)->in_ptr + 1) & 0x1f) == (q)->out_ptr) +#define empty(q) ((q)->in_ptr == (q)->out_ptr) +#define not_empty(q) ((q)->in_ptr != (q)->out_ptr) +#define inco(q) (q)->out_ptr = ((q)->out_ptr + 1) & 0x1f +#define inci(q) (q)->in_ptr = ((q)->in_ptr + 1) & 0x1f + +MTAB cty_mod[] = { + { UNIT_DUMMY, 0, NULL, "STOP", &cty_stop_os }, + { TT_MODE, TT_MODE_UC, "UC", "UC", &tty_set_mode }, + { TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode }, + { TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode }, + { TT_MODE, TT_MODE_7P, "7p", "7P", &tty_set_mode }, + { 0 } + }; + +UNIT cty_unit[] = { + { UDATA (&ctyo_svc, TT_MODE_7B, 0), 100}, + { UDATA (&ctyi_svc, TT_MODE_7B|UNIT_DIS, 0), 1000 }, + { UDATA (&ctyrtc_srv, UNIT_IDLE|UNIT_DIS, 0), 1000 } + }; + +REG cty_reg[] = { + {SAVEDATA(IN, cty_in) }, + {SAVEDATA(OUT, cty_out) }, + {HRDATAD(WRU, sim_int_char, 8, "interrupt character") }, + { 0 }, + }; + + +DEVICE cty_dev = { + "CTY", cty_unit, cty_reg, cty_mod, + 3, 10, 31, 1, 8, 8, + NULL, NULL, &cty_reset, + NULL, NULL, NULL, NULL, DEV_DEBUG, 0, dev_debug, + NULL, NULL, &cty_help, NULL, NULL, &cty_description + }; + +void +cty_wakeup() +{ + sim_debug(DEBUG_EXP, &cty_dev, "CTY wakeup\n"); + sim_activate(&cty_unit[0], cty_unit[0].wait); +} + + +/* Check for input from CTY and put on queue. */ +t_stat ctyi_svc (UNIT *uptr) +{ + uint64 buffer; + int32 ch; + + sim_clock_coschedule (uptr, tmxr_poll); + + /* If we have room see if any new lines */ + while (!full(&cty_in)) { + ch = sim_poll_kbd (); + if (ch & SCPE_KFLAG) { + ch = 0177 & sim_tt_inpcvt(ch, TT_GET_MODE (uptr->flags)); + cty_in.buff[cty_in.in_ptr] =ch & 0377; + inci(&cty_in); + sim_debug(DEBUG_DETAIL, &cty_dev, "CTY char %o '%c'\n", ch, + ((ch > 040 && ch < 0177)? ch: '.')); + } else + break; + } + + if (not_empty(&cty_in)) { + if (Mem_read_word(CTY_IN, &buffer, 0)) + return SCPE_OK; + if (buffer & CTY_CHAR) + return SCPE_OK; + sim_debug(DEBUG_DETAIL, &cty_dev, "CTY Read %012llo\n", buffer); + ch = cty_in.buff[cty_in.out_ptr]; + if (ch != 0) { + buffer = (uint64)(ch) | CTY_CHAR; + if (Mem_write_word(CTY_IN, &buffer, 0)) + return SCPE_OK; + inco(&cty_in); + cty_interrupt(); + } else { + inco(&cty_in); + } + } + return SCPE_OK; +} + +/* Handle output of characters to CTY. Started whenever there is output pending */ +t_stat ctyo_svc (UNIT *uptr) +{ + uint64 buffer; + /* Check if any input pending? */ + if (Mem_read_word(CTY_OUT, &buffer, 0)) + return SCPE_OK; + sim_debug(DEBUG_DETAIL, &cty_dev, "CTY Write %012llo\n", buffer); + if (buffer & CTY_CHAR) { + if (!full(&cty_out)) { + cty_out.buff[cty_out.in_ptr] = (uint8)(buffer & 0377); + buffer = 0; + if (Mem_write_word(CTY_OUT, &buffer, 0) == 0) { + inci(&cty_out); + cty_interrupt(); + } + } else { + sim_activate(uptr, uptr->wait); + } + } + + /* Flush out any pending CTY output */ + while(not_empty(&cty_out)) { + char ch = cty_out.buff[cty_out.out_ptr]; + if (ch != 0) { + if (sim_putchar_s(ch) != SCPE_OK) { + sim_activate(uptr, uptr->wait); + return SCPE_OK; + } + } + inco(&cty_out); + sim_debug(DEBUG_DETAIL, &cty_dev, "CTY outch %o '%c'\n", ch, + ((ch > 040 && ch < 0177)? ch: '.')); + } + + return SCPE_OK; +} + + +/* Handle FE timer interrupts. And keepalive counts */ +t_stat +ctyrtc_srv(UNIT * uptr) +{ + + sim_activate_after(uptr, 1000000/rtc_tps); + /* Check if clock requested */ + return SCPE_OK; +} + + +t_stat cty_reset (DEVICE *dptr) +{ + cty_in.in_ptr = cty_in.out_ptr = 0; + cty_out.in_ptr = cty_out.out_ptr = 0; + sim_activate(&cty_unit[1], cty_unit[1].wait); + sim_activate(&cty_unit[2], cty_unit[2].wait); + return SCPE_OK; +} + +t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + cty_unit[0].flags = (cty_unit[0].flags & ~TT_MODE) | val; + return SCPE_OK; +} + +/* Stop operating system */ + +t_stat cty_stop_os (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + M[CTY_SWITCH] = 1; /* tell OS to stop */ + return SCPE_OK; +} + + +t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ +fprintf (st, "To stop the cpu use the command:\n\n"); +fprintf (st, " sim> SET CTY STOP\n\n"); +fprintf (st, "This will write a 1 to location %03o, causing TOPS10 to stop\n\n", CTY_SWITCH); +fprintf (st, "The additional terminals can be set to one of four modes: UC, 7P, 7B, or 8B.\n\n"); +fprintf (st, " mode input characters output characters\n\n"); +fprintf (st, " UC lower case converted lower case converted to upper case,\n"); +fprintf (st, " to upper case, high-order bit cleared,\n"); +fprintf (st, " high-order bit cleared non-printing characters suppressed\n"); +fprintf (st, " 7P high-order bit cleared high-order bit cleared,\n"); +fprintf (st, " non-printing characters suppressed\n"); +fprintf (st, " 7B high-order bit cleared high-order bit cleared\n"); +fprintf (st, " 8B no changes no changes\n\n"); +fprintf (st, "The default mode is 7P. In addition, each line can be configured to\n"); +fprintf (st, "behave as though it was attached to a dataset, or hardwired to a terminal:\n\n"); +fprint_reg_help (st, &cty_dev); +return SCPE_OK; +} + +const char *cty_description (DEVICE *dptr) +{ + return "Console TTY Line"; +} + +#endif diff --git a/PDP10/ks10_rp.c b/PDP10/ks10_rp.c new file mode 100644 index 0000000..6db6020 --- /dev/null +++ b/PDP10/ks10_rp.c @@ -0,0 +1,1103 @@ +/* ks10_rp.c: DEC Massbus RP04/5/6 + + Copyright (c) 2021, Richard Cornwell + + 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 + RICHARD CORNWELL 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. + +*/ + +#include "kx10_defs.h" +#include "kx10_disk.h" + +#ifndef NUM_DEVS_RP +#define NUM_DEVS_RP 0 +#endif + +#if (NUM_DEVS_RP > 0) +#define BUF_EMPTY(u) (u->hwmark == 0xFFFFFFFF) +#define CLR_BUF(u) u->hwmark = 0xFFFFFFFF + +#define RP_NUMWD 128 /* 36bit words/sec */ +#define NUM_UNITS_RP 8 + +/* Flags in the unit flags word */ + +#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */ +#define UNIT_M_DTYPE 7 +#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) +#define DTYPE(x) (((x) & UNIT_M_DTYPE) << UNIT_V_DTYPE) +#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) + +/* Parameters in the unit descriptor */ +#define CMD u3 +/* u3 low */ +/* RPC - 176700 - control */ + +#define CS1_GO 1 /* go */ +#define CS1_V_FNC 1 /* function pos */ +#define CS1_M_FNC 037 /* function mask */ +#define CS1_FNC (CS1_M_FNC << CS1_V_FNC) +#define FNC_NOP 000 /* no operation */ +#define FNC_UNLOAD 001 /* unload */ +#define FNC_SEEK 002 /* seek */ +#define FNC_RECAL 003 /* recalibrate */ +#define FNC_DCLR 004 /* drive clear */ +#define FNC_RELEASE 005 /* port release */ +#define FNC_OFFSET 006 /* offset */ +#define FNC_RETURN 007 /* return to center */ +#define FNC_PRESET 010 /* read-in preset */ +#define FNC_PACK 011 /* pack acknowledge */ +#define FNC_SEARCH 014 /* search */ +#define FNC_XFER 024 /* >=? data xfr */ +#define FNC_WCHK 024 /* write check */ +#define FNC_WCHKH 025 /* write check headers */ +#define FNC_WRITE 030 /* write */ +#define FNC_WRITEH 031 /* write w/ headers */ +#define FNC_READ 034 /* read */ +#define FNC_READH 035 /* read w/ headers */ +#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) +#define CS1_IE 0000100 /* Enable interrupts */ +#define CS1_RDY 0000200 /* Drive ready */ +#define CS1_UBA 0001400 /* High order UBA bits */ +#define CS1_PSEL 0002000 /* */ +#define CS1_DVA 0004000 /* drive avail NI */ +#define CS1_MCPE 0020000 /* */ +#define CS1_TRE 0040000 /* */ +#define CS1_SC 0100000 /* */ + + +/* RPWC - 176702 - word count */ + +/* RPBA - 176704 - base address */ + +#define DA u4 +/* u4 high */ +/* RPDC - 176706 - desired sector */ + +#define DA_V_SC 16 /* sector pos */ +#define DA_M_SC 077 /* sector mask */ +#define DA_V_SF 24 /* track pos */ +#define DA_M_SF 077 /* track mask */ +#define DA_MBZ 0140300 +#define GET_SC(x) (((x) >> DA_V_SC) & DA_M_SC) +#define GET_SF(x) (((x) >> DA_V_SF) & DA_M_SF) + +/* RPCS2 - 176710 - control/status 2 */ + +#define CS2_V_UNIT 0 /* unit pos */ +#define CS2_M_UNIT 07 /* unit mask */ +#define CS2_UNIT (CS2_M_UNIT << CS2_V_UNIT) +#define CS2_UAI 0000010 /* addr inhibit */ +#define CS2_PAT 0000020 /* parity test NI */ +#define CS2_CLR 0000040 /* controller clear */ +#define CS2_IR 0000100 /* input ready */ +#define CS2_OR 0000200 /* output ready */ +#define CS2_MDPE 0000400 /* Mbus par err NI */ +#define CS2_MXF 0001000 /* missed xfer NI */ +#define CS2_PGE 0002000 /* program err */ +#define CS2_NEM 0004000 /* nx mem err */ +#define CS2_NED 0010000 /* nx drive err */ +#define CS2_PE 0020000 /* parity err NI */ +#define CS2_WCE 0040000 /* write check err */ +#define CS2_DLT 0100000 /* data late NI */ + +/* u3 low */ +/* RPDS - 176712 - drive status */ + +#define DS_OFF 0000001 /* offset mode */ +#define DS_VV 0000100 /* volume valid */ +#define DS_DRY 0000200 /* drive ready */ +#define DS_DPR 0000400 /* drive present */ +#define DS_PGM 0001000 /* programable NI */ +#define DS_LST 0002000 /* last sector */ +#define DS_WRL 0004000 /* write locked */ +#define DS_MOL 0010000 /* medium online */ +#define DS_PIP 0020000 /* pos in progress */ +#define DS_ERR 0040000 /* error */ +#define DS_ATA 0100000 /* attention active */ +#define DS_MBZ 0000076 + +/* u3 high */ +/* RPER1 - 176714 - error status 1 */ + +#define ER1_ILF 0000001 /* illegal func */ +#define ER1_ILR 0000002 /* illegal register */ +#define ER1_RMR 0000004 /* reg mod refused */ +#define ER1_PAR 0000010 /* parity err */ +#define ER1_FER 0000020 /* format err NI */ +#define ER1_WCF 0000040 /* write clk fail NI */ +#define ER1_ECH 0000100 /* ECC hard err NI */ +#define ER1_HCE 0000200 /* hdr comp err NI */ +#define ER1_HCR 0000400 /* hdr CRC err NI */ +#define ER1_AOE 0001000 /* addr ovflo err */ +#define ER1_IAE 0002000 /* invalid addr err */ +#define ER1_WLE 0004000 /* write lock err */ +#define ER1_DTE 0010000 /* drive time err NI */ +#define ER1_OPI 0020000 /* op incomplete */ +#define ER1_UNS 0040000 /* drive unsafe */ +#define ER1_DCK 0100000 /* data check NI */ + +/* RPAS - 176716 - attention summary */ + +#define AS_U0 0000001 /* unit 0 flag */ + +/* RPLA - 176720 - look ahead register */ +#define LA_REG us9 +#define LA_V_SC 6 /* sector pos */ + +/* RPDB - 176722 - data buffer */ + +#define OF_HCI 0002000 /* hdr cmp inh NI */ +#define OF_ECI 0004000 /* ECC inhibit NI */ +#define OF_F22 0010000 /* format NI */ +#define OF_MBZ 0161400 + +/* RPMR - 176724 - maintenace register */ + +/* RPDT - 176726 - drive type */ + + +/* RPSN - 176730 - serial number */ + +/* us10 */ +/* RPOF - 176732 - offset register */ + +/* u4 low */ +/* RPDC - 176734 - desired cylinder */ +#define DC_V_CY 0 /* cylinder pos */ +#define DC_M_CY 01777 /* cylinder mask */ +#define DC_MBZ 0176000 +#define GET_CY(x) (((x) >> DC_V_CY) & DC_M_CY) +#define GET_DA(c,d) ((((GET_CY (c) * rp_drv_tab[d].surf) + GET_SF (c)) \ + * rp_drv_tab[d].sect) + GET_SC (c)) +#define CCYL u5 +/* u5 low */ +/* RPCC - 176736 - current cylinder */ + +/* RPER2 - 176740 - error status 2 - drive unsafe conditions */ +/* RPER3 - 176742 - error status 3 - more unsafe conditions - unimplemented */ +#define ERR2 us9 +/* us9 */ +#define ERR3 us10 + + +#define DATAPTR u6 +/* RPEC1 - 176744 - ECC status 1 - unimplemented */ +/* RPEC2 - 176746 - ECC status 2 - unimplemented */ + + +/* This controller supports many different disk drive types. These drives + are operated in 576 bytes/sector (128 36b words/sector) mode, which gives + them somewhat different geometry from the PDP-11 variants: + + type #sectors/ #surfaces/ #cylinders/ + surface cylinder drive + + RP04/5 20 19 411 =88MB + RP06 20 19 815 =176MB + RP07 43 32 630 =516MB + + In theory, each drive can be a different type. The size field in + each unit selects the drive capacity for each drive and thus the + drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE. + + The RP07, despite its name, uses an RM-style controller. +*/ + +#define RP04_DTYPE 0 +#define RP04_SECT 20 +#define RP04_SURF 19 +#define RP04_CYL 411 +#define RP04_DEV 020020 +#define RP04_SIZE (RP04_SECT * RP04_SURF * RP04_CYL * RP_NUMWD) + +#define RP06_DTYPE 1 +#define RP06_SECT 20 +#define RP06_SURF 19 +#define RP06_CYL 815 +#define RP06_DEV 020022 +#define RP06_SIZE (RP06_SECT * RP06_SURF * RP06_CYL * RP_NUMWD) + +#define RP07_DTYPE 2 +#define RP07_SECT 43 +#define RP07_SURF 32 +#define RP07_CYL 630 +#define RP07_DEV 020042 +#define RP07_SIZE (RP07_SECT * RP07_SURF * RP07_CYL * RP_NUMWD) + +struct drvtyp { + int32 sect; /* sectors */ + int32 surf; /* surfaces */ + int32 cyl; /* cylinders */ + int32 size; /* #blocks */ + int32 devtype; /* device type */ + }; + +struct drvtyp rp_drv_tab[] = { + { RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV }, + { RP06_SECT, RP06_SURF, RP06_CYL, RP06_SIZE, RP06_DEV }, + { RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV }, + { 0 } + }; + + +int rp_write(t_addr addr, uint16 data, int32 access); +int rp_read(t_addr addr, uint16 *data, int32 access); +t_stat rp_svc(UNIT *); +t_stat rp_boot(int32, DEVICE *); +void rp_ini(UNIT *, t_bool); +t_stat rp_reset(DEVICE *); +t_stat rp_attach(UNIT *, CONST char *); +t_stat rp_detach(UNIT *); +t_stat rp_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat rp_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, + const char *cptr); +const char *rp_description (DEVICE *dptr); +uint64 rp_buf[RP_NUMWD]; +uint16 rp_wc; +uint16 rp_db; +t_addr rp_ba; +uint8 rp_attn; +int rp_unit; +uint8 rp_ie; + + +UNIT rpa_unit[] = { +/* Controller 1 */ + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+DTYPE(RP06_DTYPE), RP06_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+DTYPE(RP06_DTYPE), RP06_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+DTYPE(RP06_DTYPE), RP06_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+DTYPE(RP06_DTYPE), RP06_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+DTYPE(RP06_DTYPE), RP06_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+DTYPE(RP06_DTYPE), RP06_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+DTYPE(RP06_DTYPE), RP06_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+DTYPE(RP06_DTYPE), RP06_SIZE) }, +}; + +DIB rpa_dib = {0776700, 077, 0254, 6, 1, &rp_read, &rp_write, 0}; + + +MTAB rp_mod[] = { + {UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL}, + {UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL}, + {UNIT_DTYPE, (RP07_DTYPE << UNIT_V_DTYPE), "RP07", "RP07", &rp_set_type }, + {UNIT_DTYPE, (RP06_DTYPE << UNIT_V_DTYPE), "RP06", "RP06", &rp_set_type }, + {UNIT_DTYPE, (RP04_DTYPE << UNIT_V_DTYPE), "RP04", "RP04", &rp_set_type }, + {MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", NULL, &disk_show_fmt }, + {MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "addr", "addr", &uba_set_addr, uba_show_addr, + NULL, "Sets address of RH11" }, + {MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "vect", "vect", &uba_set_vect, uba_show_vect, + NULL, "Sets vect of RH11" }, + {MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "br", "br", &uba_set_br, uba_show_br, + NULL, "Sets br of RH11" }, + {MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "ctl", "ctl", &uba_set_ctl, uba_show_ctl, + NULL, "Sets br of RH11" }, + {0} +}; + +REG rpa_reg[] = { + {ORDATA(WC, rp_wc, 16)}, + {ORDATA(BA, rp_ba, 18)}, + {ORDATA(ATTN, rp_attn, 8)}, + {ORDATA(UNIT, rp_unit, 3)}, + {ORDATA(IE, rp_ie, 8), REG_HRO}, + {BRDATA(BUFF, rp_buf, 16, 64, RP_NUMWD), REG_HRO}, + {0} +}; + +DEVICE rpa_dev = { + "RP", rpa_unit, rpa_reg, rp_mod, + NUM_UNITS_RP, 8, 18, 1, 8, 36, + NULL, NULL, &rp_reset, &rp_boot, &rp_attach, &rp_detach, + &rpa_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug, + NULL, NULL, &rp_help, NULL, NULL, &rp_description +}; + +int +rp_write(t_addr addr, uint16 data, int32 access) { + int i; + UNIT *uptr = &rpa_unit[rp_unit]; + int dtype = GET_DTYPE(uptr->flags); + + if (access == BYTE && addr & 1) + data <<= 8; + + switch(addr & 076) { +/* u3 low */ + case 000: /* RPC - 176700 - control */ + if (access == BYTE && addr & 1) + return 0; + + sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o Status=%06o\n", rp_unit, uptr->CMD); + /* Set if drive not writable */ + if (uptr->flags & UNIT_WLK) + uptr->CMD |= DS_WRL; + /* If drive not ready don't do anything */ + if ((uptr->CMD & DS_DRY) == 0) { + uptr->CMD |= (ER1_RMR << 16)|DS_ERR; + sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o not ready\n", rp_unit); + return 0; + } + rp_ba = ((data << 7) & 0600000) | (rp_ba & 0177777); + rp_ie = data & CS1_IE; + /* Check if GO bit set */ + if ((data & 1) == 0) { + uptr->CMD &= ~076; + uptr->CMD |= data & 076; + sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o no go\n", rp_unit); + return 0; /* No, nop */ + } + uptr->CMD &= DS_ATA|DS_VV|DS_DPR|DS_MOL|DS_WRL; + uptr->CMD |= data & 076; + switch (GET_FNC(data)) { + case FNC_NOP: + uptr->CMD |= DS_DRY; + break; + + case FNC_RECAL: /* recalibrate */ + uptr->DA &= ~0177777; + /* Fall through */ + + case FNC_RETURN: /* return to center */ + case FNC_OFFSET: /* offset */ + case FNC_UNLOAD: /* unload */ + uptr->CMD &= ~DS_OFF; + /* Fall through */ + + case FNC_SEARCH: /* search */ + case FNC_SEEK: /* seek */ + case FNC_WCHK: /* write check */ + case FNC_WRITE: /* write */ + case FNC_WRITEH: /* write w/ headers */ + case FNC_READ: /* read */ + case FNC_READH: /* read w/ headers */ + uptr->CMD |= DS_PIP; + + if (GET_CY(uptr->DA) >= rp_drv_tab[dtype].cyl || + GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect || + GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) { + rp_attn &= ~(1<CMD |= (ER1_IAE << 16)|DS_ERR|DS_DRY|DS_ATA; + uptr->CMD &= ~DS_PIP; + break; + } + + uptr->CMD |= CS1_GO; + CLR_BUF(uptr); + uptr->DATAPTR = 0; + break; + + + case FNC_DCLR: /* drive clear */ + uptr->CMD |= DS_DRY; + uptr->CMD &= ~(DS_ATA|CS1_GO); + uptr->DA &= 003400177777; + uptr->CCYL &= 0177777; + uptr->ERR2 = 0; + uptr->ERR3 = 0; + rp_ie = 0; + rp_attn &= ~(1<DA = 0; + uptr->CCYL &= 0177777; + uptr->CMD &= ~DS_OFF; + /* Fall through */ + + case FNC_RELEASE: /* port release */ + case FNC_PACK: /* pack acknowledge */ + if ((uptr->flags & UNIT_ATT) != 0) + uptr->CMD |= DS_VV; + uptr->CMD |= DS_DRY; + break; + + default: + uptr->CMD |= DS_DRY|DS_ERR|DS_ATA; + uptr->CMD |= (ER1_ILF << 16); + rp_attn |= (1<CMD & CS1_GO) + sim_activate(uptr, 1000); + sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o AStatus=%06o\n", rp_unit, uptr->CMD); + return 0; + case 002: /* RPWC - 176702 - word count */ + if (access == BYTE) { + if (addr & 1) + data = data | (rp_wc & 0377); + else + data = (rp_wc & 0177600) | data; + } + rp_wc = data; + break; + case 004: /* RPBA - 176704 - base address */ + if (access == BYTE) { + if (addr & 1) + data = data | (rp_ba & 0377); + else + data = (rp_ba & 0177600) | data; + } + rp_ba = (rp_ba & 0600000) | (data & 0177776); + break; + case 006: /* RPDC - 176706 - desired sector */ + if (access == BYTE) { + if (addr & 1) + data = data | ((uptr->DA >> 16) & 0377); + else + data = ((uptr->DA >> 16) & 0177600) | data; + } + uptr->DA &= 0177777; + uptr->DA |= data << 16; + break; + + case 010: /* RPCS2 - 176710 - Control and Status register 2 */ + if (access == BYTE) { + if (addr & 1) + data = data | rp_unit; + } + rp_unit = data & 07; + if (data & 040) { + rp_reset(&rpa_dev); + } + break; + + case 012: /* RPDS - 176712 - drive status */ + break; + + case 014: /* RPER1 - 176714 - error status 1 */ + if (access == BYTE) { + if (addr & 1) + data = data | ((uptr->CMD >> 16) & 0377); + else + data = ((uptr->CMD >> 16) & 0177600) | data; + } + uptr->CMD &= 0177777; + uptr->CMD |= data << 16; + uptr->CMD &= ~DS_ERR; + if ((((uptr->CMD >> 16) & 0177777) | uptr->ERR2 | uptr->ERR3) != 0) + uptr->CMD |= DS_ERR; + break; + + case 016: /* RPAS - 176716 - attention summary */ + for (i = 0; i < 8; i++) { + if (data & (1<CMD &= ~DS_ATA; + rp_attn &= ~(1<CCYL &= 0177777; + uptr->CCYL |= data << 16; + break; + case 034: /* RPDC - 176734 - desired cylinder */ + if (access == BYTE) { + if (addr & 1) + data = data | (uptr->DA & 0377); + else + data = (uptr->DA & 0177600) | data; + } + uptr->DA &= ~0177777; + uptr->DA |= data; + break; + case 040: /* RPER2 - 176740 - error status 2 - drive unsafe conditions */ + uptr->ERR2 = data; + uptr->CMD &= ~DS_ERR; + if ((((uptr->CMD >> 16) & 0177777) | uptr->ERR2 | uptr->ERR3) != 0) + uptr->CMD |= DS_ERR; + break; + case 042: /* RPER3 - 176742 - error status 3 - more unsafe conditions */ + uptr->ERR3 = data; + uptr->CMD &= ~DS_ERR; + if ((((uptr->CMD >> 16) & 0177777) | uptr->ERR2 | uptr->ERR3) != 0) + uptr->CMD |= DS_ERR; + break; + case 030: /* RPSN - 176730 - serial number */ + case 036: /* RPCC - 176736 - current cylinder */ + case 044: /* RPEC1 - 176744 - ECC status 1 - unimplemented */ + case 046: /* RPEC2 - 176746 - ECC status 2 - unimplemented */ + break; + } + sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o write %02o %06o\n", rp_unit, + addr & 076, data); + return 0; +} + +int +rp_read(t_addr addr, uint16 *data, int32 access) { + UNIT *uptr = &rpa_unit[rp_unit]; + uint16 temp = 0; + int i; + +/* RPDB - 176722 - data buffer */ + switch(addr & 076) { + case 000: /* RPC - 176700 - control */ + temp = uptr->CMD & (DS_DRY|076); + temp |= (uint16)rp_ie; + temp |= (rp_ba & 0600000) >> 7; + if (uptr->flags & UNIT_ATT) + temp |= CS1_DVA; + if (uptr->CMD & CS1_GO) + temp |= CS1_GO; + else if (GET_FNC(uptr->CMD) < FNC_XFER) + temp |= CS1_RDY; + break; + case 002: /* RPWC - 176702 - word count */ + temp = rp_wc; + break; + case 004: /* RPBA - 176704 - base address */ + temp = (uint16)(rp_ba & 0177776); + break; + case 006: /* RPDC - 176706 - desired sector */ + temp = (uptr->DA >> 16) & 0177777; + break; + case 010: /* RPCS2 - 176710 - control/status 2 */ + temp = rp_unit; + if (uptr->flags & UNIT_DIS) + temp |= CS2_NED; + break; + case 012: /* RPDS - 176712 - drive status */ + temp = uptr->CMD & 0177600; + if ((uptr->flags & UNIT_ATT) != 0) + temp |= DS_VV; + break; + case 014: /* RPER1 - 176714 - error status 1 */ + temp = (uptr->CMD >> 16) & 0177777; + break; + case 016: /* RPAS - 176716 - attention summary */ + for (i = 0; i < 8; i++) { + UNIT *u = &rpa_unit[i]; + if (u->CMD & DS_ATA) { + temp |= 1 << i; + } + } + break; + case 020: /* RPLA - 176720 - look ahead register */ + uptr->LA_REG += 0100; + uptr->LA_REG &= 07700; + temp = uptr->LA_REG; + break; + case 022: /* RPDB - 176722 - data buffer */ + temp = rp_db; + break; + case 024: /* RPMR - 176724 - maintenace register */ + break; + case 026: /* RPDT - 176726 - drive type */ + temp = rp_drv_tab[GET_DTYPE(uptr->flags)].devtype; + break; + case 030: /* RPSN - 176730 - serial number */ + temp = (rp_unit + 1); + break; + case 032: /* RPOF - 176732 - offset register */ + temp = (uptr->CCYL >> 16) & 0177777; + break; + case 034: /* RPDC - 176734 - desired cylinder */ + temp = uptr->DA & 0177777; + break; + case 036: /* RPCC - 176736 - current cylinder */ + temp = uptr->CCYL & 0177777; + break; + case 040: /* RPER2 - 176740 - error status 2 - drive unsafe conditions */ + temp = uptr->ERR2; + break; + case 042: /* RPER3 - 176742 - error status 3 - more unsafe conditions */ + temp = uptr->ERR3; + break; + case 044: /* RPEC1 - 176744 - ECC status 1 - unimplemented */ + case 046: /* RPEC2 - 176746 - ECC status 2 - unimplemented */ + break; + } + *data = temp; + sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o read %02o %06o\n", rp_unit, + addr & 076, temp); + return 0; +} + + +/* Set the attention flag for a unit */ +void rp_setattn(int unit) +{ + rp_attn |= 1<flags); + int cyl = GET_CY(uptr->DA); + DIB *dibp; + int unit; + DEVICE *dptr; + int diff, da; + int sts; + uint64 buf; + + dptr = uptr->dptr; + unit = uptr - dptr->units; + if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + uptr->CMD |= (ER1_UNS << 16) | DS_ATA|DS_ERR; /* set drive error */ + if (GET_FNC(uptr->CMD) >= FNC_XFER) { /* xfr? set done */ + if (rp_ie) + uba_set_irq(&rpa_dib); + } else { + rp_setattn(unit); + } + return (SCPE_OK); + } + + /* Check if seeking */ + if (uptr->CMD & DS_PIP) { + sim_debug(DEBUG_DETAIL, dptr, "%s%o seek %d %d\n", dptr->name, unit, cyl, uptr->CCYL); + if (cyl >= rp_drv_tab[dtype].cyl) { + uptr->CMD &= ~DS_PIP; + uptr->CMD |= (ER1_IAE << 16)|DS_ERR|DS_DRY|DS_ATA; + rp_setattn(unit); + } + diff = cyl - (uptr->CCYL & 01777); + if (diff < 0) { + if (diff < -50) { + uptr->CCYL -= 50; + sim_activate(uptr, 500); + } else if (diff < -10) { + uptr->CCYL -= 10; + sim_activate(uptr, 200); + } else { + uptr->CCYL -= 1; + sim_activate(uptr, 100); + } + return SCPE_OK; + } else if (diff > 0) { + if (diff > 50) { + uptr->CCYL += 50; + sim_activate(uptr, 500); + } else if (diff > 10) { + uptr->CCYL += 10; + sim_activate(uptr, 200); + } else { + uptr->CCYL += 1; + sim_activate(uptr, 100); + } + return SCPE_OK; + } else { + uptr->CMD &= ~DS_PIP; + uptr->DATAPTR = 0; + } + } + + switch (GET_FNC(uptr->CMD)) { + case FNC_NOP: + case FNC_DCLR: /* drive clear */ + case FNC_RELEASE: /* port release */ + case FNC_PACK: /* pack acknowledge */ + break; + case FNC_UNLOAD: /* unload */ + rp_detach(uptr); + /* Fall through */ + case FNC_OFFSET: /* offset */ + uptr->CMD |= DS_OFF; + /* Fall through */ + case FNC_RETURN: /* return to center */ + case FNC_PRESET: /* read-in preset */ + case FNC_RECAL: /* recalibrate */ + case FNC_SEEK: /* seek */ + if (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect || + GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) + uptr->CMD |= (ER1_IAE << 16)|DS_ERR; + uptr->CMD |= DS_DRY|DS_ATA; + uptr->CMD &= ~CS1_GO; + rp_setattn(unit); + sim_debug(DEBUG_DETAIL, dptr, "%s%o seekdone %d %o\n", dptr->name, unit, cyl, uptr->CMD); + break; + + case FNC_SEARCH: /* search */ + if (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect || + GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) + uptr->CMD |= (ER1_IAE << 16)|DS_ERR; + uptr->CMD |= DS_DRY|DS_ATA; + uptr->CMD &= ~CS1_GO; + rp_setattn(unit); + sim_debug(DEBUG_DETAIL, dptr, "%s%o searchdone %d %o\n", dptr->name, unit, cyl, uptr->CMD); + break; + + case FNC_READ: /* read */ + case FNC_READH: /* read w/ headers */ + case FNC_WCHK: /* write check */ + if (uptr->CMD & DS_ERR) { + sim_debug(DEBUG_DETAIL, dptr, "%s%o read error\n", dptr->name, unit); + goto rd_end; + } + + if (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect || + GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) { + uptr->CMD |= (ER1_IAE << 16)|DS_ERR|DS_DRY|DS_ATA; + uptr->CMD &= ~CS1_GO; + if (uptr->CMD & CS1_IE) + uba_set_irq(&rpa_dib); + sim_debug(DEBUG_DETAIL, dptr, "%s%o readx done\n", dptr->name, unit); + return SCPE_OK; + } + sim_debug(DEBUG_DETAIL, dptr, "%s%o read (%d,%d,%d)\n", dptr->name, unit, cyl, + GET_SF(uptr->DA), GET_SC(uptr->DA)); + da = GET_DA(uptr->DA, dtype); + (void)disk_read(uptr, &rp_buf[0], da, RP_NUMWD); + uptr->hwmark = RP_NUMWD; + uptr->DATAPTR = 0; + sts = 1; + /* On read headers, transfer 2 words to start */ + if (GET_FNC(uptr->CMD) == FNC_READH) { + buf = (((uint64)cyl) << 18) | + ((uint64)((GET_SF(uptr->DA) << 8) | GET_SF(uptr->DA))); + sim_debug(DEBUG_DATA, dptr, "%s%o read word h1 %012llo %09o %06o\n", + dptr->name, unit, buf, rp_ba, rp_wc); + if ((sts = uba_write_npr(rp_ba, rpa_dib.uba_ctl, buf)) == 0) + goto rd_end; + rp_ba += 4; + rp_wc = (rp_wc + 2) & 0177777; + if (rp_wc == 0) { + sts = 0; + goto rd_end; + } + buf = (((uint64)(unit + 1)) << 18) | (uint64)(unit); + sim_debug(DEBUG_DATA, dptr, "%s%o read word h2 %012llo %09o %06o\n", + dptr->name, unit, buf, rp_ba, rp_wc); + if ((sts = uba_write_npr(rp_ba, rpa_dib.uba_ctl, buf)) == 0) + goto rd_end; + rp_ba += 4; + rp_wc = (rp_wc + 2) & 0177777; + if (rp_wc == 0) { + sts = 0; + goto rd_end; + } + } + + while (uptr->DATAPTR < RP_NUMWD && sts != 0) { + buf = rp_buf[uptr->DATAPTR++]; + sim_debug(DEBUG_DATA, dptr, "%s%o read word %d %012llo %09o %06o\n", + dptr->name, unit, uptr->DATAPTR, buf, rp_ba, rp_wc); + sts = uba_write_npr(rp_ba, rpa_dib.uba_ctl, buf); + rp_ba += 4; + rp_wc = (rp_wc + 2) & 0177777; + if (rp_wc == 0) { + sts = 0; + goto rd_end; + } + } + + if (sts) { + /* Increment to next sector. Set Last Sector */ + uptr->DATAPTR = 0; + CLR_BUF(uptr); + uptr->DA += 1 << DA_V_SC; + if (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect) { + uptr->DA &= (DA_M_SF << DA_V_SF) | (DC_M_CY << DC_V_CY); + uptr->DA += 1 << DA_V_SF; + if (GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) { + uptr->DA &= (DC_M_CY << DC_V_CY); + uptr->DA += 1 << DC_V_CY; + uptr->CMD |= DS_PIP; + } + } + sim_activate(uptr, 10); + return SCPE_OK; + } +rd_end: + sim_debug(DEBUG_DETAIL, dptr, "%s%o read done\n", dptr->name, unit); + uptr->CMD |= DS_DRY; + uptr->CMD &= ~CS1_GO; + if (rp_ie) + uba_set_irq(&rpa_dib); + return SCPE_OK; + + case FNC_WRITE: /* write */ + case FNC_WRITEH: /* write w/ headers */ + if (uptr->CMD & DS_ERR) { + sim_debug(DEBUG_DETAIL, dptr, "%s%o read error\n", dptr->name, unit); + goto wr_end; + } + + if (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect || + GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) { + uptr->CMD |= (ER1_IAE << 16)|DS_ERR|DS_DRY|DS_ATA; + uptr->CMD &= ~CS1_GO; + uba_set_irq(&rpa_dib); + sim_debug(DEBUG_DETAIL, dptr, "%s%o writex done\n", dptr->name, unit); + return SCPE_OK; + } + sts = 1; + /* On Write headers, transfer 2 words to start */ + if (GET_FNC(uptr->CMD) == FNC_WRITEH) { + if (uba_read_npr(rp_ba, rpa_dib.uba_ctl, &buf) == 0) + goto wr_end; + rp_ba += 4; + rp_wc = (rp_wc + 2) & 0177777; + if (rp_wc == 0) { + sts = 0; + goto wr_end; + } + sim_debug(DEBUG_DATA, dptr, "%s%o write word h1 %012llo %07o\n", + dptr->name, unit, buf, rp_wc); + if (uba_read_npr(rp_ba, rpa_dib.uba_ctl, &buf) == 0) + goto wr_end; + rp_ba += 4; + rp_wc = (rp_wc + 2) & 0177777; + if (rp_wc == 0) { + sts = 0; + goto wr_end; + } + sim_debug(DEBUG_DATA, dptr, "%s%o write word h2 %012llo %07o\n", + dptr->name, unit, buf, rp_wc); + } + uptr->DATAPTR = 0; + uptr->hwmark = 0; + buf = 0; + while (uptr->DATAPTR < RP_NUMWD && + (sts = uba_read_npr(rp_ba, rpa_dib.uba_ctl, &buf)) != 0) { + rp_buf[uptr->DATAPTR++] = buf; + sim_debug(DEBUG_DATA, dptr, "%s%o write word %d %012llo %07o %06o\n", + dptr->name, unit, uptr->DATAPTR, buf, rp_ba, rp_wc); + rp_ba += 4; + rp_wc = (rp_wc + 2) & 0177777; + if (rp_wc == 0) { + sts = 0; + goto wr_end; + } + } + rp_buf[uptr->DATAPTR++] = buf; + while (uptr->DATAPTR < RP_NUMWD) { + rp_buf[uptr->DATAPTR++] = 0; + } +wr_done: + sim_debug(DEBUG_DETAIL, dptr, "%s%o write (%d,%d,%d)\n", dptr->name, + unit, cyl, GET_SF(uptr->DA), GET_SC(uptr->DA)); + da = GET_DA(uptr->DA, dtype); + (void)disk_write(uptr, &rp_buf[0], da, RP_NUMWD); + uptr->DATAPTR = 0; + CLR_BUF(uptr); + uptr->DA += 1 << DA_V_SC; + if (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect) { + uptr->DA &= (DA_M_SF << DA_V_SF) | (DC_M_CY << DC_V_CY); + uptr->DA += 1 << DA_V_SF; + if (GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) { + uptr->DA &= (DC_M_CY << DC_V_CY); + uptr->DA += 1 << DC_V_CY; + uptr->CMD |= DS_PIP; + } + } + + if (sts) { + sim_activate(uptr, 10); + } else { +wr_end: + sim_debug(DEBUG_DETAIL, dptr, "RP%o write done\n", unit); + uptr->CMD |= DS_DRY; + uptr->CMD &= ~CS1_GO; + if (rp_ie) + uba_set_irq(&rpa_dib); + } + return SCPE_OK; + } + return SCPE_OK; +} + + +t_stat +rp_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + int i; + + if (uptr == NULL) return SCPE_IERR; + uptr->flags &= ~(UNIT_DTYPE); + uptr->flags |= val; + i = GET_DTYPE(val); + uptr->capac = rp_drv_tab[i].size; + return SCPE_OK; +} + + +t_stat +rp_reset(DEVICE * rptr) +{ + int i; + rp_attn = 0; + rp_ba = 0; + rp_wc = 0177777; + for (i = 0; i < 8; i++) { + UNIT *u = &rpa_unit[i]; + u->CMD &= DS_VV|DS_DRY|DS_DPR|DS_MOL; + rp_attn &= ~(1<ERR2 = u->ERR3 = 0; + } + return SCPE_OK; +} + +/* Boot from given device */ +t_stat +rp_boot(int32 unit_num, DEVICE * rptr) +{ + UNIT *uptr = &rptr->units[unit_num]; + int dtype = GET_DTYPE(uptr->flags); + DEVICE *dptr = uptr->dptr; + uint32 addr; + uint32 ptr = 0; + uint64 len; + int wc; + int i; + uint64 word; + int da; + /* Read in block 1 and see if it is a home block */ + disk_read(uptr, &rp_buf[0], 1, RP_NUMWD); + if (rp_buf[0] != 0505755000000LL) { + /* Try blocks 10 and 12 if fail */ + disk_read(uptr, &rp_buf[0], 010, RP_NUMWD); + if (rp_buf[0] != 0505755000000LL) { + disk_read(uptr, &rp_buf[0], 012, RP_NUMWD); + if (rp_buf[0] != 0505755000000LL) + return SCPE_IERR; + } + } + + /* Word 103 and 102 contain pointer to SMFILE block */ + uptr->DA = ((rp_buf[0103] & 077) << DA_V_SC) | + (((rp_buf[0103] >> 8) & 077) << DA_V_SF) | + ((rp_buf[0103] >> 24) << DC_V_CY); + len = rp_buf[0102]; + da = GET_DA(uptr->DA, dtype); + disk_read(uptr, &rp_buf[0], da, RP_NUMWD); + /* For diagnostics use locations 6 and 7 */ + if (sim_switches & SWMASK ('D')) { + sim_messagef(SCPE_OK, "Diags boot\n"); + uptr->DA = ((rp_buf[06] & 077) << DA_V_SC) | + (((rp_buf[06] >> 8) & 077) << DA_V_SF) | + ((rp_buf[06] >> 24) << DC_V_CY); + len = (rp_buf[07] & 077) * 4; + } else { + /* Normal is at 4 and 5*/ + uptr->DA = ((rp_buf[04] & 077) << DA_V_SC) | + (((rp_buf[04] >> 8) & 077) << DA_V_SF) | + ((rp_buf[04] >> 24) << DC_V_CY); + len = (rp_buf[05] & 077) * 4; + } + + /* Read len sectors into address 1000 */ + addr = 01000; + for (; len > 0; len--) { + da = GET_DA(uptr->DA, dtype); + disk_read(uptr, &rp_buf[0], da, RP_NUMWD); + for (i = 0; i < RP_NUMWD; i++) { + M[addr++] = rp_buf[i]; + } + uptr->DA += 1 << DA_V_SC; + if (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect) { + uptr->DA &= (DA_M_SF << DA_V_SF) | (DC_M_CY << DC_V_CY); + uptr->DA += 1 << DA_V_SF; + if (GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) { + uptr->DA &= (DC_M_CY << DC_V_CY); + uptr->DA += 1 << DC_V_CY; + } + } + } + /* Start location, and set up load infor */ + PC = 01000; + M[036] = rpa_dib.uba_addr | (rpa_dib.uba_ctl << 18); + M[037] = unit_num; + return SCPE_OK; +} + +/* Device attach */ + +t_stat rp_attach (UNIT *uptr, CONST char *cptr) +{ + t_stat r; + DEVICE *rptr; + DIB *dib; + + uptr->capac = rp_drv_tab[GET_DTYPE (uptr->flags)].size; + r = disk_attach (uptr, cptr); + if (r != SCPE_OK) + return r; + rptr = find_dev_from_unit(uptr); + if (rptr == 0) + return SCPE_OK; + dib = (DIB *) rptr->ctxt; + if (uptr->flags & UNIT_WLK) + uptr->CMD |= DS_WRL; + if (sim_switches & SIM_SW_REST) + return SCPE_OK; + uptr->DA = 0; + uptr->CMD &= ~DS_VV; + uptr->CMD |= DS_DPR|DS_MOL|DS_DRY; + rp_setattn(uptr - &rpa_unit[0]); + return SCPE_OK; +} + +/* Device detach */ + +t_stat rp_detach (UNIT *uptr) +{ + if (!(uptr->flags & UNIT_ATT)) /* attached? */ + return SCPE_OK; + if (sim_is_active (uptr)) /* unit active? */ + sim_cancel (uptr); /* cancel operation */ + uptr->CMD &= ~(DS_VV|DS_WRL|DS_DPR|DS_DRY); + return disk_detach (uptr); +} + +t_stat rp_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ +fprintf (st, "RP04/05/06/07 Disk Pack Drives (RP)\n\n"); +fprintf (st, "The RP controller implements the Massbus family of large disk drives. RP\n"); +fprintf (st, "options include the ability to set units write enabled or write locked, to\n"); +fprintf (st, "set the drive type to one of six disk types or autosize, and to write a DEC\n"); +fprintf (st, "standard 044 compliant bad block table on the last track.\n\n"); +disk_attach_help(st, dptr, uptr, flag, cptr); +fprint_set_help (st, dptr); +fprint_show_help (st, dptr); +fprintf (st, "\nThe type options can be used only when a unit is not attached to a file.\n"); +fprintf (st, "The RP device supports the BOOT command.\n"); +fprint_reg_help (st, dptr); +return SCPE_OK; +} + +const char *rp_description (DEVICE *dptr) +{ + return "RP04/05/06/07 Massbus disk controller"; +} + + +#endif diff --git a/PDP10/ks10_tu.c b/PDP10/ks10_tu.c new file mode 100644 index 0000000..2c1eb2f --- /dev/null +++ b/PDP10/ks10_tu.c @@ -0,0 +1,975 @@ +/* ks10_tu.c: DEC Massbus TM03/TU10 tape controller + + Copyright (c) 2021, Richard Cornwell + + 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 PUTUOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + RICHARD CORNWELL 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. + +*/ + +#include "kx10_defs.h" +#include "sim_tape.h" + +#ifndef NUM_DEVS_TU +#define NUM_DEVS_TU 0 +#endif + +#if (NUM_DEVS_TU > 0) + +#define NUM_UNITS_TU 8 +#define TU_NUMFR (64*1024) + +#define BUF_EMPTY(u) (u->hwmark == 0xFFFFFFFF) +#define CLR_BUF(u) u->hwmark = 0xFFFFFFFF + +/* Flags in the unit flags word */ + +#define TU_UNIT UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE + +#define CMD u3 +/* u3 low */ +/* TUC - 772440 - control */ + +#define CS1_GO 1 /* go */ +#define CS1_V_FNC 1 /* function pos */ +#define CS1_M_FNC 037 /* function mask */ +#define CS1_FNC (CS1_M_FNC << CS1_V_FNC) +#define FNC_NOP 000 /* no operation */ +#define FNC_UNLOAD 001 /* unload */ +#define FNC_REWIND 003 /* rewind */ +#define FNC_DCLR 004 /* drive clear */ +#define FNC_PRESET 010 /* read-in preset */ +#define FNC_ERASE 012 /* Erase */ +#define FNC_WTM 013 /* Write Tape Mark */ +#define FNC_SPACEF 014 /* Space record forward */ +#define FNC_SPACEB 015 /* Space record backward */ +#define FNC_XFER 024 /* >=? data xfr */ +#define FNC_WCHK 024 /* write check */ +#define FNC_WCHKREV 027 /* write check reverse */ +#define FNC_WRITE 030 /* write */ +#define FNC_READ 034 /* read */ +#define FNC_READREV 037 /* read reverse */ +#define CS1_IE 0000100 /* Enable interrupts */ +#define CS1_RDY 0000200 /* Drive ready */ +#define CS1_UBA 0001400 /* High order UBA bits */ +#define CS1_PSEL 0002000 /* */ +#define CS1_DVA 0004000 /* drive avail NI */ +#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) +#define CS1_MCPE 0020000 /* */ +#define CS1_TRE 0040000 /* */ +#define CS1_SC 0100000 /* */ + +/* TUWC - 772442 - word count. */ + +/* TUBA - 772444 - bus address */ + +/* TUFC - 772446 - Frame count */ + +/* TUCS2 -772450 - Control Status 2 */ +#define CS2_V_UNIT 0 /* unit pos */ +#define CS2_M_UNIT 07 /* unit mask */ +#define CS2_UNIT (CS2_M_UNIT << CS2_V_UNIT) +#define CS2_UAI 0000010 /* addr inhibit */ +#define CS2_PAT 0000020 /* parity test NI */ +#define CS2_CLR 0000040 /* controller clear */ +#define CS2_IR 0000100 /* input ready */ +#define CS2_OR 0000200 /* output ready */ +#define CS2_MDPE 0000400 /* Mbus par err NI set TRE*/ +#define CS2_MXF 0001000 /* missed xfer NI set TRE*/ +#define CS2_PGE 0002000 /* program err set TRE*/ +#define CS2_NEM 0004000 /* nx mem err set TRE*/ +#define CS2_NED 0010000 /* nx drive err set TRE */ +#define CS2_PE 0020000 /* parity err NI set TRE */ +#define CS2_WCE 0040000 /* write check err set TRE */ +#define CS2_DLT 0100000 /* data late NI set TRE */ + +#define STATUS u5 +/* u5 low */ +/* TUDS - 772452 - drive status */ + +#define DS_SLA 0000001 /* Drive has become ready */ +#define DS_BOT 0000002 /* Beginning of tape */ +#define DS_TM 0000004 /* Tape mark */ +#define DS_IDB 0000010 /* Identification burst */ +#define DS_SDWN 0000020 /* Tape stoped */ +#define DS_PES 0000040 /* Phase Encoding */ +#define DS_SSC 0000100 /* Status change */ +#define DS_DRY 0000200 /* drive ready */ +#define DS_DPR 0000400 /* drive present */ +#define DS_PGM 0001000 /* programable NI */ +#define DS_EOT 0002000 /* end of tape */ +#define DS_WRL 0004000 /* write locked */ +#define DS_MOL 0010000 /* medium online */ +#define DS_PIP 0020000 /* pos in progress */ +#define DS_ERR 0040000 /* error */ +#define DS_ATA 0100000 /* attention active */ + +/* u5 high */ +/* TUER1 - 772454 - error status 1 */ + +#define ER1_ILF 0000001 /* illegal func */ +#define ER1_ILR 0000002 /* illegal register */ +#define ER1_RMR 0000004 /* reg mod refused */ +#define ER1_CPAR 0000010 /* control parity err NI */ +#define ER1_FMT 0000020 /* format err */ +#define ER1_DPAR 0000040 /* data parity error */ +#define ER1_INC 0000100 /* Incorrectable data */ +#define ER1_PEF 0000200 /* format error */ +#define ER1_NSG 0000400 /* Nonstandard gap NI */ +#define ER1_FCE 0001000 /* Frame count error */ +#define ER1_ITM 0002000 /* Illegal tape mark */ +#define ER1_NEF 0004000 /* Non executable function */ +#define ER1_DTE 0010000 /* drive time err NI */ +#define ER1_OPI 0020000 /* op incomplete */ +#define ER1_UNS 0040000 /* drive unsafe */ +#define ER1_DCK 0100000 /* data check NI */ + +/* TUDB - 772462 - Data buffer */ + +/* TUMR - 772464 - maintenace register */ + +/* TUAS - 772456 - attention summary */ + +#define AS_U0 0000001 /* unit 0 flag */ + +/* TUDT - 772466 - drive type */ + +/* TULA - 772460 - Check Character */ + +/* TUSN - 772470 - serial number */ + +/* TUTC - 772472 - Tape control register */ +#define TC_SS 0000007 /* Slave select mask */ +#define TC_EVPAR 0000010 /* Even parity */ +#define TC_FMTSEL 0000360 /* Format select */ +#define TC_10CORE 000 /* PDP 10 Core */ + /* 4 8 bit chars + 1 4 bit char */ +#define TC_15CORE 001 /* PDP 15 core */ + /* 3 6 bit chars per word */ +#define TC_10NORM 003 /* PDP 10 Compatible */ + /* 4 8 bit chars per word */ +#define TC_11NORM 014 /* PDP 11 Normal */ + /* 2 8 bit chars per word */ +#define TC_11CORE 015 /* PDP 11 Core */ + /* 4 4 bit chars per word */ +#define TC_15NORM 016 /* PDP 15 Normal */ + /* 2 8 bit chars per word */ +#define TC_DENS 0003400 /* Density (ignored) */ +#define TC_800 0001400 /* 800 BPI */ +#define TC_1600 0002000 /* 1600 BPI */ +#define TC_EAODTE 0010000 /* Enable abort */ +#define TC_SAC 0020000 /* Slave address change */ +#define TC_FCS 0040000 /* Frame count status */ +#define TC_ACCL 0100000 /* Acceleration */ + + +/* TUER3 - 15 - error status 3 - more unsafe conditions - unimplemented */ + +#define CPOS u4 +#define DATAPTR u6 + +uint8 tu_buf[TU_NUMFR]; +uint64 tu_cbuf; +uint16 tu_frame; +uint16 tu_tcr; +uint16 tu_wc; +uint16 tu_db; +uint16 tu_cs2; +t_addr tu_ba; +uint8 tu_attn; +uint8 tu_ie; +uint16 tu_mr; +static uint64 tu_boot_buffer; + +int tu_write(t_addr addr, uint16 data, int32 access); +int tu_read(t_addr addr, uint16 *data, int32 access); +void tu_rst(DEVICE *dptr); +t_stat tu_srv(UNIT *); +t_stat tu_boot(int32, DEVICE *); +void tu_ini(UNIT *, t_bool); +t_stat tu_reset(DEVICE *); +t_stat tu_attach(UNIT *, CONST char *); +t_stat tu_detach(UNIT *); +t_stat tu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, + const char *cptr); +const char *tu_description (DEVICE *dptr); + + +UNIT tua_unit[] = { +/* Controller 1 */ + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, +}; + +DIB tua_dib = {0772440, 037, 0224, 6, 3, &tu_read, &tu_write, 0}; + +MTAB tu_mod[] = { + {MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL}, + {MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL}, + {MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", + &sim_tape_set_fmt, &sim_tape_show_fmt, NULL}, + {MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "LENGTH", "LENGTH", + &sim_tape_set_capac, &sim_tape_show_capac, NULL}, + {MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "DENSITY", "DENSITY", + &sim_tape_set_dens, &sim_tape_show_dens, NULL}, + {MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "addr", "addr", &uba_set_addr, uba_show_addr, + NULL, "Sets address of RH11" }, + {MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "vect", "vect", &uba_set_vect, uba_show_vect, + NULL, "Sets vect of RH11" }, + {MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "br", "br", &uba_set_br, uba_show_br, + NULL, "Sets br of RH11" }, + {MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "ctl", "ctl", &uba_set_ctl, uba_show_ctl, + NULL, "Sets br of RH11" }, + {0} +}; + +REG tua_reg[] = { + {ORDATA(WC, tu_wc, 16)}, + {ORDATA(BA, tu_ba, 18)}, + {ORDATA(ATTN, tu_attn, 8)}, + {ORDATA(UNIT, tu_cs2, 8)}, + {ORDATA(IE, tu_ie, 8), REG_HRO}, + {ORDATA(FRAME, tu_frame, 16)}, + {ORDATA(TCR, tu_tcr, 16)}, + {BRDATA(BUFF, tu_buf, 16, 8, TU_NUMFR), REG_HRO}, + {0} +}; + +DEVICE tua_dev = { + "TU", tua_unit, tua_reg, tu_mod, + NUM_UNITS_TU, 8, 18, 1, 8, 36, + NULL, NULL, &tu_reset, &tu_boot, &tu_attach, &tu_detach, + &tua_dib, DEV_DISABLE | DEV_DEBUG | DEV_TAPE, 0, dev_debug, + NULL, NULL, &tu_help, NULL, NULL, &tu_description +}; + +int +tu_write(t_addr addr, uint16 data, int32 access) { + int i; + int unit = tu_tcr & 07; + UNIT *uptr = &tua_unit[unit]; + + if (access == BYTE && addr & 1) + data <<= 8; + + if (uptr->CMD & CS1_GO) { + uptr->STATUS |= (ER1_RMR << 16); + return 0; + } + + switch(addr & 036) { + case 000: /* TUCS - control */ + sim_debug(DEBUG_DETAIL, &tua_dev, "TU %d Status=%06o\n", unit, uptr->STATUS); + if (access == BYTE && addr & 1) + return 0; + + sim_debug(DEBUG_DETAIL, &tua_dev, "TU %d Status=%06o\n", unit, uptr->CMD); + tu_ba = ((data << 7) & 0600000) | (tu_ba & 0177777); + tu_ie = data & CS1_IE; + uptr->CMD = data & 076; + + if ((data & 01) != 0 && (uptr->flags & UNIT_ATT) != 0) { + switch (GET_FNC(data)) { + case FNC_NOP: + break; + + case FNC_PRESET: /* read-in preset */ + case FNC_READ: /* read */ + case FNC_READREV: /* read w/ headers */ + tu_frame = 0; + tu_tcr |= TC_FCS; + /* Fall through */ + + case FNC_WRITE: /* write */ + case FNC_SPACEF: /* Space forward */ + case FNC_SPACEB: /* Space backward */ + if ((tu_tcr & TC_FCS) == 0) { + uptr->STATUS |= ER1_NEF << 16; + break; + } + /* Fall through */ + + case FNC_ERASE: /* Erase gap */ + case FNC_WTM: /* Write tape mark */ + case FNC_WCHK: /* write check */ + case FNC_REWIND: /* rewind */ + case FNC_UNLOAD: /* unload */ + case FNC_WCHKREV: /* write w/ headers */ + uptr->CMD |= CS1_GO; + uptr->STATUS |= DS_PIP; + tu_attn = 0; + for (i = 0; i < 8; i++) { + if (tua_unit[i].STATUS & DS_ATA) + tu_attn = 1; + } + CLR_BUF(uptr); + uptr->DATAPTR = 0; + sim_activate(uptr, 100); + break; + + case FNC_DCLR: /* drive clear */ + uptr->CMD &= ~(CS1_GO); + uptr->STATUS = 0; + tu_ie = 0; + tu_attn = 0; + for (i = 0; i < 8; i++) { + if (tua_unit[i].STATUS & DS_ATA) + tu_attn = 1; + } + break; + default: + uptr->STATUS |= (ER1_ILF << 16) | DS_ATA; + tu_attn = 1; + } + sim_debug(DEBUG_DETAIL, &tua_dev, "TU %o AStatus=%06o\n", unit, uptr->CMD); + } + break; + case 002: /* TUWC - 172442 - word count */ + if (access == BYTE) { + if (addr & 1) + data = data | (tu_wc & 0377); + else + data = (tu_wc & 0177600) | data; + } + tu_wc = data; + break; + case 004: /* TUBA - 172444 - base address */ + if (access == BYTE) { + if (addr & 1) + data = data | (tu_ba & 0377); + else + data = (tu_ba & 0177600) | data; + } + tu_ba = (tu_ba & 0600000) | (data & 0177776); + break; + + case 006: /* 772446 frame count */ + tu_frame = data; + tu_tcr |= TC_FCS; + break; + + case 010: /* 772450 CS2 */ + if (access == BYTE) { + if (addr & 1) + data = data | tu_cs2; + } + if (data & 040) { + tu_reset(&tua_dev); + } + tu_cs2 = data & (CS2_PAT|CS2_UAI|CS2_UNIT); + break; + + + case 012: /* 772452 status */ + break; + + case 014: /* 772454 error register 1 */ + uptr->STATUS &= 0177777; + uptr->STATUS |= (uint32)data << 16; + break; + case 016: /* 772456 atten summary */ + tu_attn = 0; + if (data & 1) { + for (i = 0; i < 8; i++) + tua_unit[i].STATUS &= ~DS_ATA; + } + break; + + case 020: /* 772460 TCK maintenance */ + break; + case 022: /* 772462 Data buffer */ + tu_db = data; + tu_cs2 |= CS2_OR; + break; + case 024: /* 772464 Maintenance register */ + tu_mr = data; + break; + case 026: /* 772466 drive type */ + break; + case 032: /* 772472 tape control register */ + tu_tcr = data; + break; + } + sim_debug(DEBUG_DETAIL, &tua_dev, "TU %o write %02o %06o\n", tu_tcr & 7, + addr & 036, data); + return 0; +} + +int +tu_read(t_addr addr, uint16 *data, int32 access) +{ + UNIT *uptr = &tua_unit[tu_tcr & 07]; + int tu_drive = tu_tcr & 07; + uint16 temp = 0; + int i; + + + switch(addr & 036) { + case 000: /* 772440 control */ + temp = uptr->CMD & 076; + temp |= CS1_DVA; + temp |= (uint16)tu_ie; + temp |= (tu_ba & 0600000) << 7; + if (uptr->CMD & CS1_GO) + temp |= CS1_GO; + else if ((uptr->STATUS & DS_PIP) == 0) + temp |= CS1_RDY; + if ((tu_cs2 & 07) != 0 || (uptr->STATUS & (ER1_RMR << 16)) != 0) + temp |= CS1_TRE; + if (tu_attn || temp & CS1_TRE) + temp |= CS1_SC; + break; + case 002: /* 772442 - word count */ + temp = tu_wc; + break; + case 004: /* 772444 - base addresss */ + temp = (uint16)(tu_ba & 0177776); + break; + case 006: /* 772446 - frame count */ + temp = tu_frame; + break; + case 010: /* 772450 - CS2 */ + temp = tu_cs2; + if ((tu_cs2 & 07) != 0) + temp |= CS2_NED; + break; + case 012: /* 772452 - status */ + temp = uptr->STATUS & 0177777; + if (((uptr->STATUS >> 16) & 0177777) != 0) + temp |= DS_ERR; + if ((uptr->flags & UNIT_ATT) != 0) { + temp |= DS_MOL; + if (uptr->flags & MTUF_WLK) + temp |= DS_WRL; + if ((uptr->CMD & CS1_GO) == 0 && (uptr->STATUS & DS_PIP) == 0) + temp |= DS_DRY; + if (sim_tape_bot(uptr)) + temp |= DS_BOT; + if (sim_tape_eot(uptr)) + temp |= DS_EOT; + } + break; + case 014: /* 772454 - error register 1 */ + temp = (uptr->STATUS >> 16) & 0177777; + break; + case 016: /* 772456 - atten summary */ + for (i = 0; i < 8; i++) { + if (tua_unit[i].STATUS & DS_ATA) + temp |= 1; + } + break; + case 022: /* 772462 Data buffer */ + temp = tu_db; + tu_cs2 &= ~CS2_OR; + break; + case 020: /* 772460 - character check */ + break; + case 024: /* 772464 - maintenance */ + temp = tu_mr; + break; + case 026: /* 772466 - drive type */ + if ((uptr->flags & UNIT_DIS) == 0) + temp = 042054; + break; + case 030: /* 772470 - serial no */ + temp = 020 + (tu_drive + 1); + break; + case 032: /* 772472 - tape control register */ + temp = tu_tcr; + break; + default: + uptr->STATUS |= (ER1_ILR << 16); + uptr->STATUS |= DS_ATA; + tu_attn = 1; + } + *data = temp; + sim_debug(DEBUG_DETAIL, &tua_dev, "TU %o read %02o %06o\n", tu_tcr & 7, + addr & 036, *data); + return 0; +} + + +/* Map simH errors into machine errors */ +void tu_error(UNIT * uptr, t_stat r) +{ + DEVICE *dptr = uptr->dptr; + + switch (r) { + case MTSE_OK: /* no error */ + break; + + case MTSE_TMK: /* tape mark */ + uptr->STATUS |= DS_TM; + break; + + case MTSE_WRP: /* write protected */ + uptr->STATUS |= (ER1_NEF << 16) | DS_ATA; + break; + + case MTSE_UNATT: /* unattached */ + case MTSE_BOT: /* beginning of tape */ + case MTSE_EOM: /* end of medium */ + break; + + case MTSE_IOERR: /* IO error */ + case MTSE_FMT: /* invalid format */ + uptr->STATUS |= (ER1_PEF << 16) | DS_ATA; + break; + + case MTSE_RECE: /* error in record */ + uptr->STATUS |= (ER1_DPAR << 16) | DS_ATA; + break; + + case MTSE_INVRL: /* invalid rec lnt */ + uptr->STATUS |= (ER1_FCE << 16) | DS_ATA; + break; + + } + if (uptr->STATUS & DS_ATA) + tu_attn = 1; + uptr->CMD &= ~(CS1_GO); + uptr->STATUS &= ~DS_PIP; + sim_debug(DEBUG_EXP, dptr, "Setting status %d\n", r); + if (tu_ie) + uba_set_irq(&tua_dib); +} + +/* Handle processing of tape requests. */ +t_stat tu_srv(UNIT * uptr) +{ + int unit; + DEVICE *dptr; + t_stat r; + t_mtrlnt reclen; + uint8 ch; + int cc; + int cc_max; + + /* Find dptr, and df10 */ + dptr = uptr->dptr; + unit = uptr - dptr->units; + cc_max = (4 + ((tu_tcr & TC_FMTSEL) == 0)); + if ((uptr->flags & UNIT_ATT) == 0) { + tu_error(uptr, MTSE_UNATT); /* attached? */ + return SCPE_OK; + } + switch (GET_FNC(uptr->CMD)) { + case FNC_NOP: + case FNC_DCLR: + sim_debug(DEBUG_DETAIL, dptr, "%s%o nop\n", dptr->name, unit); + tu_error(uptr, MTSE_OK); /* Nop */ + tu_attn = 1; + return SCPE_OK; + + case FNC_REWIND: + sim_debug(DEBUG_DETAIL, dptr, "%s%o rewind\n", dptr->name, unit); + if (uptr->CMD & CS1_GO) { + sim_activate(uptr,40000); + uptr->CMD &= ~(CS1_GO); + } else { + uptr->STATUS |= DS_SSC|DS_ATA; + uptr->STATUS &= ~DS_PIP; + tu_attn = 1; + if (tu_ie) + uba_set_irq(&tua_dib); + (void)sim_tape_rewind(uptr); + } + return SCPE_OK; + + case FNC_UNLOAD: + sim_debug(DEBUG_DETAIL, dptr, "%s%o unload\n", dptr->name, unit); + uptr->CMD &= ~(CS1_GO); + uptr->STATUS &= ~(DS_PIP); + uptr->STATUS |= DS_SSC|DS_ATA; + tu_error(uptr, sim_tape_detach(uptr)); + return SCPE_OK; + + case FNC_WCHKREV: + case FNC_READREV: + if (BUF_EMPTY(uptr)) { + if ((r = sim_tape_rdrecr(uptr, &tu_buf[0], &reclen, + TU_NUMFR)) != MTSE_OK) { + sim_debug(DEBUG_DETAIL, dptr, "%s%o read error %d\n", dptr->name, unit, r); + if (r == MTSE_BOT) + uptr->STATUS |= ER1_NEF << 16; + tu_error(uptr, r); + } else { + sim_debug(DEBUG_DETAIL, dptr, "%s%o read %d\n", dptr->name, unit, reclen); + uptr->hwmark = reclen; + uptr->DATAPTR = uptr->hwmark-1; + uptr->CPOS = cc_max; + tu_cbuf = 0; + sim_activate(uptr, 120); + } + return SCPE_OK; + } + if (uptr->DATAPTR >= 0) { + tu_frame++; + cc = (8 * (3 - uptr->CPOS)) + 4; + ch = tu_buf[uptr->DATAPTR]; + if (cc < 0) + tu_cbuf |= (uint64)(ch & 0x0f); + else + tu_cbuf |= (uint64)(ch & 0xff) << cc; + uptr->DATAPTR--; + uptr->CPOS--; + if (uptr->CPOS == 0) { + uptr->CPOS = cc_max; + if (GET_FNC(uptr->CMD) == FNC_READREV && + uba_write_npr(tu_ba, tua_dib.uba_ctl, tu_cbuf) == 0) { + tu_error(uptr, MTSE_OK); + return SCPE_OK; + } + sim_debug(DEBUG_DATA, dptr, "%s%o readrev %012llo\n", + dptr->name, unit, tu_cbuf); + tu_cbuf = 0; + if ((tu_cs2 & CS2_UAI) == 0) + tu_ba -= 4; + tu_wc = (tu_wc + 2) & 0177777; + if (tu_wc == 0) { + tu_error(uptr, MTSE_OK); + return SCPE_OK; + } + } + } else { + if (uptr->CPOS != cc_max) + uba_write_npr(tu_ba, tua_dib.uba_ctl, tu_cbuf); + tu_error(uptr, MTSE_OK); + return SCPE_OK; + } + break; + + case FNC_WCHK: + case FNC_READ: + if (BUF_EMPTY(uptr)) { + if ((r = sim_tape_rdrecf(uptr, &tu_buf[0], &reclen, + TU_NUMFR)) != MTSE_OK) { + sim_debug(DEBUG_DETAIL, dptr, "%s%o read error %d\n", dptr->name, unit, r); + if (r == MTSE_TMK) + uptr->STATUS |= ER1_FCE << 16; + tu_error(uptr, r); + } else { + sim_debug(DEBUG_DETAIL, dptr, "%s%o read %d %d\n", dptr->name, unit, reclen, uptr->pos); + uptr->hwmark = reclen; + uptr->DATAPTR = 0; + uptr->CPOS = 0; + tu_cbuf = 0; + sim_activate(uptr, 120); + } + return SCPE_OK; + } + if ((uint32)uptr->DATAPTR < uptr->hwmark) { + tu_frame++; + cc = (8 * (3 - uptr->CPOS)) + 4; + ch = tu_buf[uptr->DATAPTR]; + if (cc < 0) + tu_cbuf |= (uint64)(ch & 0x0f); + else + tu_cbuf |= (uint64)(ch & 0xff) << cc; + uptr->DATAPTR++; + uptr->CPOS++; + if (uptr->CPOS == cc_max) { + uptr->CPOS = 0; + if (GET_FNC(uptr->CMD) == FNC_READ && + uba_write_npr(tu_ba, tua_dib.uba_ctl, tu_cbuf) == 0) { + if ((uint32)uptr->DATAPTR == uptr->hwmark) + goto rd_end; + tu_error(uptr, MTSE_OK); + return SCPE_OK; + } + sim_debug(DEBUG_DATA, dptr, "%s%o read %012llo %d\n", + dptr->name, unit, tu_cbuf, uptr->DATAPTR); + tu_cbuf = 0; + tu_cbuf = 0; + if ((tu_cs2 & CS2_UAI) == 0) + tu_ba += 4; + tu_wc = (tu_wc + 2) & 0177777; + if (tu_wc == 0) + goto rd_end; + } + } else { + if (uptr->CPOS != 0) { + sim_debug(DEBUG_DATA, dptr, "%s%o readf %012llo\n", + dptr->name, unit, tu_cbuf); + uba_write_npr(tu_ba, tua_dib.uba_ctl, tu_cbuf); + } +rd_end: + if (tu_frame != 0) + uptr->STATUS |= ER1_FCE << 16; + tu_error(uptr, MTSE_OK); + return SCPE_OK; + } + break; + + case FNC_WRITE: + if (BUF_EMPTY(uptr)) { + if (tu_frame == 0) { + uptr->STATUS |= ER1_NEF << 16; + uptr->CMD |= DS_ATA; + tu_error(uptr, MTSE_OK); + return SCPE_OK; + } + if ((uptr->flags & MTUF_WLK) != 0) { + tu_error(uptr, MTSE_WRP); + return SCPE_OK; + } + sim_debug(DEBUG_EXP, dptr, "%s%o Init write\n", dptr->name, unit); + uptr->hwmark = 0; + uptr->CPOS = 0; + uptr->DATAPTR = 0; + tu_cbuf = 0; + } + if (tu_frame != 0 && uptr->CPOS == 0) { + if (uba_read_npr(tu_ba, tua_dib.uba_ctl, &tu_cbuf) == 0) { + uptr->CPOS = 010; + goto wr_end; + } else { + if ((tu_cs2 & CS2_UAI) == 0) + tu_ba += 4; + tu_wc = (tu_wc + 2) & 0177777; + } + } + + if (uptr->CPOS == 0) + sim_debug(DEBUG_DATA, dptr, "%s%o write %012llo\n", + dptr->name, unit, tu_cbuf); + /* Write next char out */ + cc = (8 * (3 - (uptr->CPOS & 07))) + 4; + if (cc < 0) + ch = tu_cbuf & 0x0f; + else + ch = (tu_cbuf >> cc) & 0xff; + tu_buf[uptr->DATAPTR] = ch; + uptr->DATAPTR++; + uptr->hwmark = uptr->DATAPTR; + uptr->CPOS = (uptr->CPOS & 010) | ((uptr->CPOS & 07) + 1); + if ((uptr->CPOS & 7) == cc_max) { + uptr->CPOS &= 010; + } + tu_frame = 0177777 & (tu_frame + 1); + if (tu_wc == 0) + uptr->CPOS = 010; + else if (tu_frame == 0) { + uptr->CPOS = 010; + tu_tcr &= ~(TC_FCS); + } +wr_end: + if (uptr->CPOS & 010) { + /* Write out the block */ + reclen = uptr->hwmark; + r = sim_tape_wrrecf(uptr, &tu_buf[0], reclen); + sim_debug(DEBUG_DETAIL, dptr, "%s%o Write %d %d\n", + dptr->name, unit, reclen, uptr->CPOS); + uptr->DATAPTR = 0; + uptr->hwmark = 0; + tu_error(uptr, r); /* Record errors */ + return SCPE_OK; + } + break; + + case FNC_WTM: + uptr->CMD |= DS_ATA; + if ((uptr->flags & MTUF_WLK) != 0) { + tu_error(uptr, MTSE_WRP); + } else { + tu_error(uptr, sim_tape_wrtmk(uptr)); + } + sim_debug(DEBUG_DETAIL, dptr, "%s%o WTM\n", dptr->name, unit); + return SCPE_OK; + + case FNC_ERASE: + uptr->STATUS |= DS_ATA; + if ((uptr->flags & MTUF_WLK) != 0) { + tu_error(uptr, MTSE_WRP); + } else { + tu_error(uptr, sim_tape_wrgap(uptr, 35)); + } + sim_debug(DEBUG_DETAIL, dptr, "%s%o ERG\n", dptr->name, unit); + return SCPE_OK; + + case FNC_SPACEF: + case FNC_SPACEB: + sim_debug(DEBUG_DETAIL, dptr, "%s%o space %o\n", dptr->name, unit, GET_FNC(uptr->CMD)); + /* Always skip at least one record */ + if (GET_FNC(uptr->CMD) == FNC_SPACEF) + r = sim_tape_sprecf(uptr, &reclen); + else + r = sim_tape_sprecr(uptr, &reclen); + switch (r) { + case MTSE_OK: /* no error */ + tu_frame = 0177777 & (tu_frame + 1); + break; + + case MTSE_BOT: /* beginning of tape */ + uptr->STATUS |= ER1_NEF << 16; + /* Fall Through */ + + case MTSE_TMK: /* tape mark */ + case MTSE_EOM: /* end of medium */ + if (tu_frame != 0) + uptr->STATUS |= ER1_FCE << 16; + else + tu_tcr &= ~(TC_FCS); + uptr->STATUS |= DS_ATA; + /* Stop motion if we recieve any of these */ + tu_error(uptr, r); + return SCPE_OK; + } + if (tu_frame == 0) { + uptr->STATUS |= DS_ATA; + tu_error(uptr, MTSE_OK); + return SCPE_OK; + } else { + tu_tcr &= ~(TC_FCS); + sim_activate(uptr, reclen * 100); + } + return SCPE_OK; + } + sim_activate(uptr, 50); + return SCPE_OK; +} + + + +t_stat +tu_reset(DEVICE * dptr) +{ + int i; + + tu_attn = 0; + tu_ba = tu_frame = tu_tcr = 0; + tu_wc = 0177777; + tu_cs2 = 0; + for (i = 0; i < 8; i++) { + tua_unit[i].STATUS = 0; + } + return SCPE_OK; +} + +void tu_read_word(UNIT *uptr) { + int i, cc, ch; + + tu_cbuf = 0; + for(i = 0; i <= 4; i++) { + cc = (8 * (3 - i)) + 4; + ch = tu_buf[uptr->DATAPTR]; + if (cc < 0) + tu_cbuf |= (uint64)(ch & 0x0f); + else + tu_cbuf |= (uint64)(ch & 0xff) << cc; + uptr->DATAPTR++; + } +} + +/* Boot from given device */ +t_stat +tu_boot(int32 unit_num, DEVICE * dptr) +{ + UNIT *uptr = &dptr->units[unit_num]; + t_mtrlnt reclen; + t_stat r; + uint32 addr; + + if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_UNATT; /* attached? */ + + tu_tcr = unit_num; + r = sim_tape_rewind(uptr); + if (r != MTSE_OK) + return r; + /* Skip first file, which is micro code */ + while (r == MTSE_OK) + r = sim_tape_rdrecf(uptr, &tu_buf[0], &reclen, TU_NUMFR); + + if (r != MTSE_TMK) + return r; + /* Next read in the boot block */ + r = sim_tape_rdrecf(uptr, &tu_buf[0], &reclen, TU_NUMFR); + if (r != MTSE_OK) + return r; + uptr->DATAPTR = 0; + uptr->hwmark = reclen; + + addr = 01000; + while ((uint32)uptr->DATAPTR < uptr->hwmark) { + tu_read_word(uptr); + M[addr] = tu_cbuf; + addr ++; + } + M[036] = tua_dib.uba_addr | (tua_dib.uba_ctl << 18); + M[037] = unit_num; + M[040] = tu_tcr; + PC = 01000; + return SCPE_OK; +} + + +t_stat +tu_attach(UNIT * uptr, CONST char *file) +{ t_stat r; + + uptr->CMD = 0; + uptr->STATUS = 0; + r = sim_tape_attach_ex(uptr, file, 0, 0); + if (r == SCPE_OK && (sim_switches & SIM_SW_REST) == 0) { + uptr->STATUS = DS_ATA|DS_SSC; + tu_attn = 1; + if (tu_ie) + uba_set_irq(&tua_dib); + } + return r; +} + +t_stat +tu_detach(UNIT * uptr) +{ + uptr->STATUS = DS_ATA|DS_SSC; + tu_attn = 1; + if (tu_ie) + uba_set_irq(&tua_dib); + return sim_tape_detach(uptr); +} + + + +t_stat tu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ +fprintf (st, "TU Tape Drives with TM03 formatter. (TU)\n\n"); +fprintf (st, "The TU controller implements the Massbus tape formatter the TM03. TU\n"); +fprintf (st, "options include the ability to set units write enabled or write locked\n\n"); +fprint_set_help (st, dptr); +fprint_show_help (st, dptr); +fprintf (st, "\nThe type options can be used only when a unit is not attached to a file.\n"); +fprintf (st, "The TU device supports the BOOT command.\n"); +sim_tape_attach_help (st, dptr, uptr, flag, cptr); +fprint_reg_help (st, dptr); +return SCPE_OK; +} + +const char *tu_description (DEVICE *dptr) +{ + return "TU04/05/06/07 Massbus disk controller"; +} + + +#endif diff --git a/PDP10/ks10_uba.c b/PDP10/ks10_uba.c new file mode 100644 index 0000000..0bd25af --- /dev/null +++ b/PDP10/ks10_uba.c @@ -0,0 +1,452 @@ +/* ks10_uba.c: KS10 Unibus interface + + Copyright (c) 2021, Richard Cornwell + + 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 + RICHARD CORNWELL 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. + +*/ + +#include "kx10_defs.h" + +/* UBA Map as stored */ +#define PAGE_MASK 000003777000 /* Page mask bits, bits 25-36 on load */ +#define MAP_RPV 000400000000 /* Ram parity valid bit */ +#define MAP_VALID 001000000000 /* Page valid */ +#define MAP_FME 002000000000 /* Fast Mode enable */ +#define MAP_EN16 004000000000 /* Disable upper 2 bits UBA */ +#define MAP_RPW 010000000000 /* For Read Pause Write */ +#define MAP_RAMP 020000000000 /* Parity error in RAM */ + +/* UBA Stats register */ +#define UBST_PIL 000000000007 /* Low level PIA */ +#define UBST_PIH 000000000070 /* High level PIA */ +#define UBST_INIT 000000000100 /* Initialize UBA */ +#define UBST_DXFR 000000000200 /* Disable transfer on uncorrectable */ +#define UBST_PWRL 000000001000 /* Power low */ +#define UBST_INTL 000000002000 /* Interrupt on Br5 or Br4 */ +#define UBST_INTH 000000004000 /* INterrupt on Br7 or Br6 */ +#define UBST_NED 000000040000 /* Non-existant device */ +#define UBST_PAR 000000100000 /* Parity error */ +#define UBST_BAD 000000200000 /* Bad mem transfer */ +#define UBST_TIM 000000400000 /* UBA Timout */ + +uint32 uba_map[2][64]; +uint32 uba_status[2]; +int uba_device[16] = { -1, 0, -1, 1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; + +int +uba_read(t_addr addr, int ctl, uint64 *data, int access) +{ + DEVICE *dptr; + int i; + int ubm = uba_device[ctl]; + + if (ubm == -1) { + uba_status[ubm] |= UBST_TIM | UBST_NED; + return 1; + } + + /* Check if in UBA map */ + if ((addr & 0777600) == 0763000) { + if ((addr & 0100) == 0) { + *data = (uint64)uba_map[ubm][addr & 077]; + return 0; + } else if ((addr & 077) == 0) { + *data = (uint64)uba_status[ubm]; + return 0; + } else if ((addr & 077) == 1) { + return 0; + } + uba_status[ubm] |= UBST_TIM | UBST_NED; + return 1; + } + + /* Look for device */ + for(i = 0; (dptr = sim_devices[i]) != NULL; i++) { + DIB *dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + continue; + if (ctl == dibp->uba_ctl && dibp->uba_addr == (addr & (~dibp->uba_mask))) { + uint16 buf; + int r = dibp->rd_io(addr, &buf, access); + *data = (uint64)buf; + return r; + } + } + uba_status[ubm] |= UBST_TIM | UBST_NED; + return 1; +} + +int +uba_write(t_addr addr, int ctl, uint64 data, int access) +{ + DEVICE *dptr; + int i; + int ubm = uba_device[ctl]; + + if (ubm == -1) { + uba_status[ubm] |= UBST_TIM | UBST_NED; + return 1; + } + + + /* Check if in UBA map */ + if ((addr & 0777400) == 0763000) { + if ((addr & 0100) == 0) { + uint32 map = (uint32)(data & 03777) << 9; + map |= (uint32)(data & 0740000) << 13; + uba_map[ubm][addr & 077] = map; +//fprintf(stderr, "Wr MAP %02o %012llo %06o\n\r", addr & 077, data, map); + return 0; + } else if ((addr & 077) == 0) { + uba_status[ubm] &= (uint32)(074000 ^ data) | 0746000; + uba_status[ubm] |= (uint32)(0277 & data); + if (data & 0100) { + for(i = 0; (dptr = sim_devices[i]) != NULL; i++) { + DIB *dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + continue; + if (ctl == dibp->uba_ctl && dptr->reset != NULL) + (void)(dptr->reset)(dptr); + if (ctl == dibp->uba_ctl) + dibp->uba_irq_pend = 0; + } + clr_interrupt(ctl); + } + return 0; + } else if ((addr & 077) == 1) { + return 0; + } + uba_status[ubm] |= UBST_TIM | UBST_NED; + return 1; + } + + /* Look for device */ + for(i = 0; (dptr = sim_devices[i]) != NULL; i++) { + DIB *dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + continue; + if (ctl == dibp->uba_ctl && dibp->uba_addr == (addr & (~dibp->uba_mask))) { + uint16 buf = (uint16)(data & 0177777); + return dibp->wr_io(addr, buf, access); + } + } + uba_status[ubm] |= UBST_TIM | UBST_NED; + return 1; +} + +int +uba_read_npr(t_addr addr, uint16 ctl, uint64 *data) +{ + int ubm = uba_device[ctl]; + uint32 map = uba_map[ubm][(077) & (addr >> 11)]; + if ((addr & 0400000) != 0) + return 0; + if ((map & MAP_VALID) == 0) + return 0; + map |= (addr >> 2) & 0777; + addr = (map & (PAGE_MASK|0777)); + *data = M[addr]; + if (map & MAP_EN16) + *data &= 0177777177777; + return 1; +} + +int +uba_write_npr(t_addr addr, uint16 ctl, uint64 data) +{ + int ubm = uba_device[ctl]; +t_addr oaddr = addr; + uint32 map = uba_map[ubm][(077) & (addr >> 11)]; + if ((addr & 0400000) != 0) + return 0; + if ((map & MAP_VALID) == 0) + return 0; + map |= (addr >> 2) & 0777; + addr = (map & (PAGE_MASK|0777)); + if (map & MAP_EN16) + data &= 0177777177777; +//fprintf(stderr, "Wr NPR %08o %08o %012llo\n\r", oaddr, addr, data); + M[addr] = data; + return 1; +} + +int +uba_read_npr_byte(t_addr addr, uint16 ctl, uint16 *data) +{ + int ubm = uba_device[ctl]; +} + +int +uba_write_npr_byte(t_addr addr, uint16 ctl, uint16 data) +{ + int ubm = uba_device[ctl]; +} + +int +uba_read_npr_word(t_addr addr, uint16 ctl, uint16 *data) +{ + int ubm = uba_device[ctl]; +} + +int +uba_write_npr_word(t_addr addr, uint16 ctl, uint16 data) +{ + int ubm = uba_device[ctl]; +} + +void +uba_set_irq(DIB *dibp) +{ + int ubm = uba_device[dibp->uba_ctl]; + int pi; + + if (ubm < 0) + return; + if (dibp->uba_br > 5) { + pi = uba_status[ubm] >> 3; + uba_status[ubm] |= UBST_INTH; + } else { + pi = uba_status[ubm]; + uba_status[ubm] |= UBST_INTL; + } + dibp->uba_irq_pend |= 0200 >> pi; + set_interrupt(dibp->uba_ctl, pi); +} + +t_addr +uba_get_vect(t_addr addr, int lvl) +{ + DEVICE *dptr; + DIB *idev = NULL; + uint64 buffer; + int i; + int ctl = 17; + int msk[16] = {0}; + int pi; + + /* Look for device */ + for(i = 0; (dptr = sim_devices[i]) != NULL; i++) { + DIB *dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + continue; + if ((dibp->uba_irq_pend & lvl) != 0) { + if (dibp->uba_ctl < ctl) + ctl = dibp->uba_ctl; + idev = dibp; + continue; + } + msk[dibp->uba_ctl] |= dibp->uba_irq_pend; + } + if (idev != NULL) { + if (idev->uba_br > 5) { + pi = uba_status[idev->uba_ctl] >> 3; + uba_status[idev->uba_ctl] &= ~UBST_INTH; + if (msk[idev->uba_ctl] & (0200 >> pi)) + uba_status[idev->uba_ctl] |= UBST_INTH; + } else { + pi = uba_status[idev->uba_ctl]; + uba_status[idev->uba_ctl] &= ~UBST_INTL; + if (msk[idev->uba_ctl] & (0200 >> pi)) + uba_status[idev->uba_ctl] |= UBST_INTL; + } + idev->uba_irq_pend &= ~(0200 >> pi); + if (msk[idev->uba_ctl] & (0200 >> pi)) + set_interrupt(idev->uba_ctl, pi); + else + clr_interrupt(idev->uba_ctl); + if (Mem_read_word(0100 | idev->uba_ctl, &buffer, 1)) + return addr; + addr = (buffer & RMASK) + (idev->uba_vect >> 2); + } + return addr; +} + +t_stat +uba_set_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + DEVICE *dptr; + DIB *dibp; + t_value newaddr; + t_stat r; + + if (dibp == NULL) + return SCPE_IERR; + if (cptr == NULL) + return SCPE_ARG; + if (uptr == NULL) + return SCPE_IERR; + dptr = find_dev_from_unit(uptr); + if (dptr == NULL) + return SCPE_IERR; + + dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + return SCPE_IERR; + + newaddr = get_uint (cptr, 18, 0777777, &r); + + if (r != SCPE_OK) + return r; + dibp->uba_addr = newaddr; + return SCPE_OK; +} + +t_stat +uba_show_addr (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + DEVICE *dptr = find_dev_from_unit(uptr); + DIB *dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + return SCPE_IERR; + fprintf(st, "addr=%07o", dibp->uba_addr); + return SCPE_OK; +} + +t_stat +uba_set_br(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + DEVICE *dptr; + DIB *dibp; + t_value br; + t_stat r; + + if (dibp == NULL) + return SCPE_IERR; + if (cptr == NULL) + return SCPE_ARG; + if (uptr == NULL) + return SCPE_IERR; + dptr = find_dev_from_unit(uptr); + if (dptr == NULL) + return SCPE_IERR; + + dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + return SCPE_IERR; + + br = get_uint (cptr, 3, 07, &r); + + if (r != SCPE_OK) + return r; + + if (br < 4 || br > 7) + return SCPE_ARG; + dibp->uba_br = br; + return SCPE_OK; +} + +t_stat +uba_show_br (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + DEVICE *dptr = find_dev_from_unit(uptr); + DIB *dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + return SCPE_IERR; + fprintf(st, "br=%o", dibp->uba_br); + return SCPE_OK; +} + +t_stat +uba_set_vect(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + DEVICE *dptr; + DIB *dibp; + t_value vect; + t_stat r; + + if (dibp == NULL) + return SCPE_IERR; + if (cptr == NULL) + return SCPE_ARG; + if (uptr == NULL) + return SCPE_IERR; + dptr = find_dev_from_unit(uptr); + if (dptr == NULL) + return SCPE_IERR; + + dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + return SCPE_IERR; + + vect = get_uint (cptr, 8, 0377, &r); + + if (r != SCPE_OK) + return r; + + dibp->uba_vect = vect; + return SCPE_OK; +} + +t_stat +uba_show_vect (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + DEVICE *dptr = find_dev_from_unit(uptr); + DIB *dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + return SCPE_IERR; + fprintf(st, "vect=%03o", dibp->uba_vect); + return SCPE_OK; +} + +t_stat +uba_set_ctl(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + DEVICE *dptr; + DIB *dibp; + t_value ctl; + t_stat r; + + if (dibp == NULL) + return SCPE_IERR; + if (cptr == NULL) + return SCPE_ARG; + if (uptr == NULL) + return SCPE_IERR; + dptr = find_dev_from_unit(uptr); + if (dptr == NULL) + return SCPE_IERR; + + dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + return SCPE_IERR; + + ctl = get_uint (cptr, 4, 017, &r); + + if (r != SCPE_OK) + return r; + + if (ctl != 1 || ctl != 3) + return SCPE_ARG; + dibp->uba_ctl = ctl; + return SCPE_OK; +} + +t_stat +uba_show_ctl (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + DEVICE *dptr = find_dev_from_unit(uptr); + DIB *dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + return SCPE_IERR; + fprintf(st, "uba%o", dibp->uba_ctl); + return SCPE_OK; +} + + diff --git a/PDP10/kx10_cpu.c b/PDP10/kx10_cpu.c index 5cbf0be..263f91a 100644 --- a/PDP10/kx10_cpu.c +++ b/PDP10/kx10_cpu.c @@ -107,7 +107,7 @@ uint64 M[MAXMEMSIZE]; /* Memory */ -#if KL +#if KL | KS uint64 FM[128]; /* Fast memory register */ #elif KI uint64 FM[64]; /* Fast memory register */ @@ -131,6 +131,7 @@ int uuo_cycle; /* Uuo cycle in progress */ int SC; /* Shift count */ int SCAD; /* Shift count extension */ int FE; /* Exponent */ +int max_dev; /* Max dev number */ #if KA | PDP6 t_addr Pl, Ph, Rl, Rh, Pflag; /* Protection registers */ int push_ovf; /* Push stack overflow */ @@ -161,7 +162,7 @@ int pi_restore; /* Restore previous level */ int pi_hold; /* Hold onto interrupt */ int modify; /* Modify cycle */ int xct_flag; /* XCT flags */ -#if KI | KL +#if KI | KL | KS uint64 ARX; /* Extension to AR */ uint64 BRX; /* Extension to BR */ uint64 ADX; /* Extension to AD */ @@ -170,7 +171,19 @@ t_addr eb_ptr; /* Executive base pointer */ uint8 fm_sel; /* User fast memory block */ int32 apr_serial = -1; /* CPU Serial number */ int inout_fail; /* In out fail flag */ -#if KL +#if KS +int ext_ac; /* Extended instruction AC */ +uint8 prev_ctx; /* Previous AC context */ +uint16 irq_enable; /* Apr IRQ enable bits */ +uint16 irq_flags; /* Apr IRQ bits */ +uint64 tim_low; /* Low order timer word */ +uint64 tim_high; /* High order timer word */ +uint64 int_val; /* Interval timer */ +uint64 int_cur; /* Current interval */ +int t20_page; /* Tops 20 paging selected */ +int ptr_flg; /* Access to pointer value */ +int extend = 0; /* Process extended instruction */ +#elif KL int pi_vect; /* Last pi location used for IRQ */ int ext_ac; /* Extended instruction AC */ uint8 prev_ctx; /* Previous AC context */ @@ -192,12 +205,12 @@ int cur_sect; /* Current section */ int prev_sect; /* Previous section */ int pc_sect; /* Program counter section */ int glb_sect; /* Global section access */ -#else +#elif KI int small_user; /* Small user flag */ #endif int user_addr_cmp; /* User address compare flag */ #endif -#if KI | KL | ITS | BBN +#if KI | KL | ITS | BBN | KS uint32 e_tlb[512]; /* Executive TLB */ uint32 u_tlb[546]; /* User TLB */ int page_enable; /* Enable paging */ @@ -242,6 +255,27 @@ int MAGIC = 1; /* Magic switch. */ #define mar brk_addr; #endif +#if KL +#define spt FM[(06<<4)|3] +#define cst FM[(06<<4)|2] +#define cst_msk FM[(06<<4)|0] +#define cst_dat FM[(06<<4)|1] +#endif + +#if KS +uint64 spt; +uint64 cst; +uint64 cst_msk; +uint64 cst_dat; +#endif + +#if KS_ITS +#define dbr1 spt +#define dbr2 cst +#define dbr3 cst_dat +#define dbr4 cst_msk +#endif + int watch_stop; /* Stop at memory watch point */ int maoff = 0; /* Offset for traps */ @@ -249,7 +283,11 @@ uint16 dev_irq[128]; /* Pending irq by device */ t_stat (*dev_tab[128])(uint32 dev, uint64 *data); t_addr (*dev_irqv[128])(uint32 dev, t_addr addr); t_stat rtc_srv(UNIT * uptr); +#if KS +int32 rtc_tps = 100; +#else int32 rtc_tps = 60; +#endif #if ITS t_stat qua_srv(UNIT * uptr); int32 qua_tps = 125000; @@ -264,7 +302,7 @@ int32 tmxr_poll = 10000; /* Physical address range for auxiliary PDP-6. */ #define AUXCPURANGE(addr) ((addr) >= auxcpu_base && (addr) < (auxcpu_base + 040000)) - +#if KA | KI | KL /* List of RH10 & RH20 devices */ DEVICE *rh_devs[] = { #if (NUM_DEVS_RS > 0) @@ -294,6 +332,7 @@ DEVICE *rh_devs[] = { int rh_nums[] = { 0270, 0274, 0360, 0364, 0370, 0374, 0}; /* Maps RH10 & RH20 device number to DEVICE structure */ struct rh_dev rh[8]; +#endif typedef struct { uint32 pc; @@ -312,7 +351,7 @@ InstHistory *hst = NULL; /* instruction history */ /* Forward and external declarations */ -#if KL +#if KL | KS int do_extend(uint32 IA); #endif t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); @@ -321,7 +360,7 @@ t_stat cpu_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc); -#if KI | KL +#if KI | KL | KS t_stat cpu_set_serial (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat cpu_show_serial (FILE *st, UNIT *uptr, int32 val, CONST void *desc); #endif @@ -375,7 +414,7 @@ REG cpu_reg[] = { { ORDATA (FM15, FM[015], 36) }, { ORDATA (FM16, FM[016], 36) }, { ORDATA (FM17, FM[017], 36) }, -#if KL +#if KL | KS { BRDATA (FM, FM, 8, 36, 128)}, #elif KI { BRDATA (FM, FM, 8, 36, 64)}, @@ -427,11 +466,11 @@ REG cpu_reg[] = { { ORDATAD (UB, ub_ptr, 18, "User Base Pointer") }, { ORDATAD (EB, eb_ptr, 18, "Executive Base Pointer") }, #endif -#if KL +#if KL | KS { ORDATAD (UB, ub_ptr, 22, "User Base Pointer") }, { ORDATAD (EB, eb_ptr, 22, "Executive Base Pointer") }, #endif -#if KI | KL +#if KI | KL | KS { ORDATAD (FMSEL, fm_sel, 8, "Register set select") }, { ORDATAD (SERIAL, apr_serial, 10, "System Serial Number") }, { FLDATA (INOUT, inout_fail, 0), REG_RO}, @@ -440,14 +479,14 @@ REG cpu_reg[] = { #endif { FLDATA (ADRCMP, user_addr_cmp, 0), REG_HRO}, #endif -#if KL | KI | ITS | BBN +#if KL | KI | ITS | BBN | KS { FLDATAD (PAGE_ENABLE, page_enable, 0, "Paging enabled")}, { FLDATAD (PAGE_FAULT, page_fault, 0, "Page fault"), REG_RO}, { ORDATAD (AC_STACK, ac_stack, 18, "AC Stack"), REG_RO}, { ORDATAD (PAGE_RELOAD, pag_reload, 18, "Page reload"), REG_HRO}, { ORDATAD (FAULT_DATA, fault_data, 36, "Page fault data"), REG_RO}, { FLDATAD (TRP_FLG, trap_flag, 0, "Trap flag"), REG_HRO}, -#if !KL +#if !(KL | KS) { ORDATAD (LST_PAGE, last_page, 9, "Last page"), REG_HRO}, #endif #endif @@ -473,6 +512,17 @@ REG cpu_reg[] = { { ORDATAD (MAGIC, MAGIC, 1, "Magic switch"), REG_FIT}, #endif /* MAGIC_SWITCH */ #endif /* ITS */ +#if KS + { ORDATAD (EXT_AC, ext_ac, 4, "Extended Instruction AC"), REG_HRO}, + { ORDATAD (PREV_CTX, prev_ctx, 5, "Previous context"), REG_HRO}, + { ORDATAD (ITQ_EN, irq_enable, 16, "Interrupt enable"), REG_HRO}, + { ORDATAD (ITQ_FLGS, irq_flags, 16, "Interrupt Flags"), REG_HRO}, + { ORDATAD (T20_PAGE, t20_page, 1, "TOPS20 paging"), REG_HRO}, + { ORDATAD (PTR_FLG, ptr_flg, 1, "Accessing pointer"), REG_HRO}, + { ORDATAD (EXTEND, extend, 1, "Execute Extend"), REG_HRO}, + { ORDATAD (SPT, spt, 18, "Special Page table"),}, + { ORDATAD (CST, cst, 18, "Memory status table"),}, +#endif #if KL { ORDATAD (EXT_AC, ext_ac, 4, "Extended Instruction AC"), REG_HRO}, { ORDATAD (PREV_CTX, prev_ctx, 5, "Previous context"), REG_HRO}, @@ -513,7 +563,7 @@ MTAB cpu_mod[] = { { UNIT_MSIZE, 8, "128K", "128K", &cpu_set_size }, { UNIT_MSIZE, 12, "196K", "196K", &cpu_set_size }, { UNIT_MSIZE, 16, "256K", "256K", &cpu_set_size }, -#if KI_22BIT|KI|ITS +#if KI_22BIT|KI|ITS|KS { UNIT_MSIZE, 32, "512K", "512K", &cpu_set_size }, { UNIT_MSIZE, 48, "768K", "768K", &cpu_set_size }, { UNIT_MSIZE, 64, "1024K", "1024K", &cpu_set_size }, @@ -522,7 +572,7 @@ MTAB cpu_mod[] = { { UNIT_MSIZE, 128, "2048K", "2048K", &cpu_set_size }, { UNIT_MSIZE, 256, "4096K", "4096K", &cpu_set_size }, #endif -#if KI|KL +#if KI|KL|KS { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "SERIAL", "SERIAL", &cpu_set_serial, &cpu_show_serial, NULL, "CPU Serial Number" }, #if KL @@ -538,7 +588,7 @@ MTAB cpu_mod[] = { { UNIT_M_PAGE, UNIT_TWOSEG, "TWOSEG", "TWOSEG", NULL, NULL, NULL, "Two Relocation Registers"}, #endif -#if ITS | KL_ITS +#if ITS | KL_ITS | KS_ITS { UNIT_M_PAGE, UNIT_ITSPAGE, "ITS", "ITS", NULL, NULL, NULL, "Paging hardware for ITS"}, #endif @@ -886,7 +936,7 @@ int opflags[] = { #define SMEAR_SIGN(x) x = ((x) & SMASK) ? (x) | EXPO : (x) & MANT #define GET_EXPO(x) ((((x) & SMASK) ? 0377 : 0 ) \ ^ (((x) >> 27) & 0377)) -#if KI | KL +#if KI | KL | KS #define AOB(x) ((x + 1) & RMASK) | ((x + 01000000LL) & (C1|LMASK)) #define SOB(x) ((x + RMASK) & RMASK) | ((x + LMASK) & (C1|LMASK)); #else @@ -898,7 +948,7 @@ int opflags[] = { #define QTEN11 (ten11_unit[0].flags & UNIT_ATT) #define QAUXCPU (auxcpu_unit[0].flags & UNIT_ATT) #else -#if KL_ITS +#if KL_ITS | KS_ITS #define QITS (cpu_unit[0].flags & UNIT_ITSPAGE) #else #define QITS 0 @@ -1054,64 +1104,66 @@ void clr_interrupt(int dev) { * else set pi_enc to highest level and return 1. */ int check_irq_level() { - int i, lvl; - int pi_req; + DEVICE *dptr; + int i, lvl; + int pi_req; - /* If PXCT don't check for interrupts */ - if (xct_flag != 0) - return 0; - check_apr_irq(); + /* If PXCT don't check for interrupts */ + if (xct_flag != 0) + return 0; - /* If not enabled, check if any pending Processor IRQ */ - if (pi_enable == 0) { + /* If not enabled, check if any pending Processor IRQ */ + if (pi_enable == 0) { #if !PDP6 - if (PIR != 0) { - pi_enc = 1; - for(lvl = 0100; lvl != 0; lvl >>= 1) { - if (lvl & PIH) - break; - if (PIR & lvl) - return 1; - pi_enc++; + if (PIR != 0) { + pi_enc = 1; + for(lvl = 0100; lvl != 0; lvl >>= 1) { + if (lvl & PIH) + break; + if (PIR & lvl) + return 1; + pi_enc++; + } + } +#endif + return 0; + } + + /* Scan all devices */ + for(i = lvl = 0; i <= max_dev; i++) + lvl |= dev_irq[i]; + if (lvl == 0) + pi_pending = 0; + pi_req = (lvl & PIE) | PIR; +#if MPX_DEV + /* Check if interrupt on PI channel 1 */ + if (mpx_enable && cpu_unit[0].flags & UNIT_MPX && + (pi_req & 0100) && (PIH & 0100) == 0) { + pi_enc = 010; + for(i = lvl = 0; i <= max_dev; i++) { + if (dev_irq[i] & 0100) { + int l = dev_irq[i] >> 8; + if (l != 0 && l < pi_enc) + pi_enc = l; } } + if (pi_enc != 010) { + pi_enc += 010; + return 1; + } + } #endif - return 0; - } - - /* Scan all devices */ - for(i = lvl = 0; i < 128; i++) - lvl |= dev_irq[i]; - if (lvl == 0) - pi_pending = 0; - pi_req = (lvl & PIE) | PIR; -#if MPX_DEV - /* Check if interrupt on PI channel 1 */ - if (mpx_enable && cpu_unit[0].flags & UNIT_MPX && - (pi_req & 0100) && (PIH & 0100) == 0) { - pi_enc = 010; - for(i = lvl = 0; i < 128; i++) { - int l = dev_irq[i] >> 8; - if (dev_irq[i] & 0100 && l != 0 && l < pi_enc) - pi_enc = l; - } - if (pi_enc != 010) { - pi_enc += 010; - return 1; - } - } -#endif - /* Handle held interrupt requests */ - i = 1; - for(lvl = 0100; lvl != 0; lvl >>= 1, i++) { - if (lvl & PIH) - break; - if (pi_req & lvl) { - pi_enc = i; - return 1; - } - } - return 0; + /* Handle held interrupt requests */ + i = 1; + for(lvl = 0100; lvl != 0; lvl >>= 1, i++) { + if (lvl & PIH) + break; + if (pi_req & lvl) { + pi_enc = i; + return 1; + } + } + return 0; } /* @@ -1148,8 +1200,9 @@ void set_pi_hold() { PIH |= (0200 >> pi); } +#if !KS /* - * PI device for KA and KI + * PI device for KA and KI and KL */ t_stat dev_pi(uint32 dev, uint64 *data) { uint64 res = 0; @@ -1272,6 +1325,7 @@ t_stat null_dev(uint32 dev, uint64 *data) { } return SCPE_OK; } +#endif #if KL void @@ -1463,33 +1517,9 @@ t_stat dev_apr(uint32 dev, uint64 *data) { break; case DATAI: - if (dev & 040) { - /* APRID */ - AR = SMASK| (500LL << 18); /* MC level 500 */ - /* Bit 0 for TOPS-20 paging */ - /* Bit 1 for extended addressing */ - /* Bit 2 Exotic microcode */ - /* Bit 3 KL10B */ - /* Bit 4 PMOVE/PMOVEM or ITS Style Paging */ - /* Bit 5 Tops-20 R5 microcode */ -#if KL_ITS - if (QITS) - AR |= 00020000000000LL; -#endif - /* Bit 18 50hz */ - /* Bit 19 Cache */ - /* Bit 20 Channel? */ - /* Bit 21 Extended KL10 */ - /* Bit 22 Master Osc */ - if (QKLB) - AR |= BIT1|BIT4|040000; - AR |= (uint64)((apr_serial == -1) ? DEF_SERIAL : apr_serial); - sim_debug(DEBUG_DATAIO, &cpu_dev, "APRID BLKI %012llo\n", MB); - } else { - *data = ((uint64)brk_flags) << 23; - *data |= (uint64)brk_addr; - sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAI APR %012llo\n", *data); - } + *data = ((uint64)brk_flags) << 23; + *data |= (uint64)brk_addr; + sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAI APR %012llo\n", *data); break; } return SCPE_OK; @@ -1536,39 +1566,6 @@ t_stat dev_mtr(uint32 dev, uint64 *data) { break; case DATAI: - if (dev & 040) { - /* RDMACT */ - /* Read memory accounting */ - if (page_enable) { - sim_interval--; - res = M[ub_ptr + 0507]; - sim_interval--; - BR = (M[ub_ptr + 0506] & CMASK); - } else { - res = 0 << 12; - BR = 0; - } - sim_debug(DEBUG_DATAIO, &cpu_dev, "BLKI MTR %012llo\n", *data); - } else { - /* RDEACT */ - /* Read executive accounting */ - int t; - double us = sim_activate_time_usecs (&cpu_unit[0]); - t = rtc_tim - ((int)us); - update_times(t); - rtc_tim = ((int)us); - if (page_enable) { - sim_interval--; - res = M[ub_ptr + 0505]; - sim_interval--; - BR = (M[ub_ptr + 0504] & CMASK); - } else { - res = 0; - BR = t << 12; - } - sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAI MTR %012llo\n", *data); - } - *data = res; break; } return SCPE_OK; @@ -1617,53 +1614,9 @@ t_stat dev_tim(uint32 dev, uint64 *data) { break; case DATAO: - if (dev & 040) { - /* WRPAE */ - /* Write performance enables */ - sim_debug(DEBUG_DATAIO, &cpu_dev, "BLKO TIM %012llo\n", *data); - } else { - sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAO TIM %012llo\n", *data); - } return SCPE_OK; case DATAI: - if (dev & 040) { - /* RDPERF */ - /* Read process execution time */ - int t; - us = sim_activate_time_usecs (&cpu_unit[0]); - t = rtc_tim - ((int)us); - update_times(t); - rtc_tim = ((int)us); - if (page_enable) { - sim_interval--; - res = (M[ub_ptr + 0505]); - sim_interval--; - BR = M[ub_ptr + 0504]; - } else { - res = 0 << 12; - BR = t; - } - sim_debug(DEBUG_DATAIO, &cpu_dev, "BLKI TIM %012llo\n", *data); - } else { - /* RDTIME */ - int t; - us = sim_activate_time_usecs (&cpu_unit[0]); - t = rtc_tim - ((int)us); - update_times(t); - rtc_tim = ((int)us); - if (page_enable) { - sim_interval--; - res = (M[eb_ptr + 0510]); - sim_interval--; - BR = M[eb_ptr + 0511]; - } else { - res = 0; - BR = t << 12; - } - sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAI TIM %012llo\n", *data); - } - *data = res; return SCPE_OK; } /* If timer is on, figure out when it will go off */ @@ -1923,7 +1876,6 @@ void check_apr_irq() { } } - /* * APR Device for KA10. */ @@ -2028,6 +1980,500 @@ sim_debug(DEBUG_DATAIO, &cpu_dev, "Rl=%06o Pl=%06o, Rh=%06o, Ph=%06o\n", Rl, Pl, } #endif +#if KS + +/* + * Check if the last operation caused a APR IRQ to be generated. + */ +void check_apr_irq() { + if (pi_enable && apr_irq) { + int flg = 0; + clr_interrupt(0); + flg = irq_enable & irq_flags; + if (flg) + set_interrupt(0, apr_irq); + } +} + +/* + * Set interrupt from CTY. + */ +void cty_interrupt() +{ + irq_flags |= CON_IRQ; + check_apr_irq(); +} + +int +load_tlb(int uf, int page, int wr) +{ + uint64 data; + +#if KS_ITS + if (QITS && t20_page) { + uint64 dbr; + int pg; + + dbr = (uf)? ((page & 0400) ? dbr2 : dbr1) : + ((page & 0400) ? dbr3 : dbr4) ; + pg = (page & 0377) >> 2; /* 2 1024 word page entries */ + sim_interval--; + data = M[dbr + pg]; + if ((page & 02) == 0) + data &= ~0160000000000LL; + else + data &= ~0160000LL; + M[dbr + pg] = data; + if ((page & 02) == 0) + data >>= 18; + data &= RMASK; + pg = 0; + switch(data >> 16) { + case 0: + fault_data = 033LL << 30; + page_fault = 1; + return 0; /* No access */ + case 1: /* Read Only */ + case 2: /* R/W First */ + if (wr) { + fault_data = 024LL << 30; + page_fault = 1; + return 0; + } + pg = KL_PAG_A; + break; + case 3: pg = KL_PAG_A|KL_PAG_W; break; /* R/W */ + } + pg |= (data & 003777) << 1; + /* Create 2 page table entries. */ + if (uf) { + u_tlb[page & 0776] = pg; + u_tlb[(page & 0776)|1] = pg|1; + data = u_tlb[page]; + } else { + e_tlb[page & 0776] = pg; + e_tlb[(page & 0776)|1] = pg|1; + data = e_tlb[page]; + } + } else +#endif +#define PG_PUB 0040000 +#define PG_WRT 0020000 +#define PG_KEP 0010000 +#define PG_CAC 0004000 +#define PG_STG (0000077LL << 18) +#define PG_IDX 0000777 + +#define PG_MASK 0000003777777LL +#define PG_AGE 0770000000000LL +#define PG_PAG 0003777 + if (t20_page) { /* Start with full access */ + int acc_bits = PG_PUB|PG_WRT|PG_KEP|PG_CAC; + uint64 cst_val = 0; + int index; + int pg; + + /* Get segment pointer */ + /* And save it */ + sim_interval--; + if (uf) + data = M[ub_ptr + 0540]; + else + data = M[eb_ptr + 0540]; + /* Find correct page table */ +sect_loop: + switch ((data >> 33) & 07) { + default: /* Invalid page */ + fault_data = 0; + page_fault = 1; + return 0; + case 1: /* Direct page */ + /* Bit 4 = execute */ + /* Bit 3 = Write */ + /* Bit 2 = Read */ + acc_bits &= (data >> 18) & RMASK; + break; + + case 2: /* Shared page */ + acc_bits &= (data >> 18) & RMASK; + sim_interval--; + index = data & RMASK; + data = M[index + (spt & PG_MASK)]; + break; + + case 3: /* Indirect page */ + acc_bits &= (data >> 18) & RMASK; + index = (data >> 18) & PG_IDX; + if ((index & 077) != 0) { + fault_data = 037LL << 30 | (data & PG_STG) | BIT8; + fault_data |= (data & RMASK) + (spt & PG_MASK); + page_fault = 1; + return 0; + } + sim_interval--; + data = M[(data & RMASK) + (spt & PG_MASK)]; + if ((data & PG_STG) != 0) { + fault_data = 0; + page_fault = 1; + return 0; + } + pg = data & PG_PAG; + sim_interval--; + data = M[(pg << 9) | index]; + goto sect_loop; + } + if ((data & PG_STG) != 0) { + fault_data = 0; + page_fault = 1; + return 0; + } + pg = data & PG_PAG; + + /* Update CST entry if needed */ + if ((cst & PG_MASK)) { + sim_interval--; + cst_val = M[(cst & PG_MASK) + pg]; + if ((cst_val & PG_AGE) == 0) { + fault_data = 0; + page_fault = 1; + return 0; + } + M[(cst & PG_MASK) + pg] = (cst_val & cst_msk) | cst_dat; + } + + /* Get address of page */ + sim_interval--; + data = M[(pg << 9) | page]; +pg_loop: + + /* Decode map pointer */ + switch ((data >> 33) & 07) { + default: /* Invalid page */ + fault_data = 0; + page_fault = 1; + return 0; + case 1: /* Direct page */ + /* Bit 4 = execute */ + /* Bit 3 = Write */ + /* Bit 2 = Read */ + acc_bits &= (data >> 18) & RMASK; + break; + + case 2: /* Shared page */ + acc_bits &= (data >> 18) & RMASK; + sim_interval--; + index = data & RMASK; + data = M[index + (spt & PG_MASK)]; + break; + + case 3: /* Indirect page */ + acc_bits &= (data >> 18) & RMASK; + index = (data >> 18) & PG_IDX; + sim_interval--; + data = M[(data & RMASK) + (spt & PG_MASK)]; + if ((data & PG_STG) != 0) { + fault_data = 0; + page_fault = 1; + return 0; + } + pg = data & RMASK; + sim_interval--; + data = M[(pg << 9) | index]; + goto pg_loop; + } + + /* Now have final page */ + if ((data & PG_STG) != 0) { + fault_data = 0; + page_fault = 1; + return 0; + } + pg = data & PG_PAG; + /* Check outside of memory */ + /* Update CST entry if needed */ + if ((cst & PG_MASK)) { + sim_interval--; + cst_val = M[(cst & PG_MASK) + pg]; + if ((cst_val & PG_AGE) == 0) { + fault_data = 0; + page_fault = 1; + return 0; + } + if (acc_bits & PG_WRT) { + if (wr) + cst_val |= 1; + } else if (wr) { /* Trying to write and not writable */ + fault_data = 0 /* Write fault */; + page_fault = 1; + return 0; + } + M[(cst & PG_MASK) + pg] = (cst_val & cst_msk) | cst_dat; + } else { + if (acc_bits & PG_WRT) { + cst_val = 1; + } + } + /* Now construct a TBL entry */ + /* A = accessable */ + /* P = public */ + /* W = writable */ + /* S = user */ + /* C = cache */ + data = pg | KL_PAG_A; +// if (acc_bits & PG_PUB) + // data |= KL_PAG_P; /* P */ + if (acc_bits & PG_WRT) { + if (cst_val & 1) + data |= KL_PAG_W; /* Set Modified page */ + data |= KL_PAG_S; /* Set Writeable bit */ + } + if (acc_bits & PG_CAC) + data |= KL_PAG_C; + /* And save it */ + if (uf) + u_tlb[page] = data & (SECTM|RMASK); + else + e_tlb[page] = data & (SECTM|RMASK); + } else { + + /* Map the page */ + sim_interval--; + if (uf) { + data = M[ub_ptr + (page >> 1)]; + u_tlb[page & 01776] = (uint32)(RMASK & (data >> 18)); + u_tlb[page | 1] = (uint32)(RMASK & data); + data = u_tlb[page]; + } else { + if (page & 0400) + data = M[eb_ptr + (page >> 1)]; + else + data = M[eb_ptr + (page >> 1) + 0600]; + e_tlb[page & 01776] = (uint32)(RMASK & (data >> 18)); + e_tlb[page | 1] = (uint32)(RMASK & data); + data = e_tlb[page]; + } + } + return (int)(data); +} + +/* + * Handle page lookup on KS10 + * + * addr is address to look up. + * flag is set for pi cycle and user overide. + * loc is final address. + * wr indicates whether cycle is read or write. + * cur_context is set when access should ignore xct_flag + * fetch is set for instruction fetches. + */ +int page_lookup(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, int fetch) { + int data; + int page = (RMASK & addr) >> 9; + int uf = (FLAGS & USER) != 0; + int pub = (FLAGS & PUBLIC) != 0; + int upmp = 0; + + /* If paging is not enabled, address is direct */ + if (!page_enable) { + *loc = addr; + return 1; + } + +// /* If this is modify instruction use write access */ +// wr |= modify; + + /* Figure out if this is a user space access */ + + /* AC = 1 use BYF5 */ + /* AC = 2 use ptr_flg */ + /* AC = 4 all general access */ + /* AC = 8 only in cur_context EA calculations */ + if (flag) { + uf = 0; + } else if (xct_flag != 0 && !fetch) { + if (((xct_flag & 8) != 0 && cur_context && !ptr_flg) || + ((xct_flag & 4) != 0 && !cur_context && !BYF5 && !ptr_flg) || + ((xct_flag & 2) != 0 && !cur_context && ptr_flg) || + ((xct_flag & 1) != 0 && !cur_context && BYF5 )) { + uf = (FLAGS & USERIO) != 0; + } + } + + /* Handle KI paging odditiy */ + if (!uf && !t20_page && (page & 0740) == 0340) { + /* Pages 340-377 via UBT */ + page += 01000 - 0340; + upmp = 1; + } + + /* Map the page */ + if (uf || upmp) + data = u_tlb[page]; + else + data = e_tlb[page]; + + /* If not valid, go refill it */ + if (data == 0) { + data = load_tlb(uf | upmp, page, wr); + if (data == 0 && page_fault) { + if (fault_data != 0) + return 0; + fault_data |= ((uint64)addr); + if (uf) /* U */ + fault_data |= SMASK; +#if KS_ITS + if (QITS) + return 0; +#endif + fault_data |= BIT8; + if (fault_data & BIT1) + return 0; + if (wr) /* T */ + fault_data |= BIT5; /* BIT5 */ + return 0; + } + } + + /* Check if we need to modify TLB entry for TOPS 20 */ + if (t20_page && (data & KL_PAG_A) && (wr & ((data & KL_PAG_W) == 0)) && (data & KL_PAG_S)) { + /* Update CST entry if needed */ + if ((cst & PG_MASK)) { + uint64 cst_val; + int pg = data & 017777; + sim_interval--; + cst_val = M[(cst & PG_MASK) + pg]; + M[(cst & PG_MASK) + pg] = (cst_msk & cst_val) | cst_dat | 1; + } + data |= KL_PAG_W; + /* Map the page */ + if (uf || upmp) + u_tlb[page] = data; + else + e_tlb[page] = data; + } + + /* create location. */ + *loc = ((data & 017777) << 9) + (addr & 0777); + + + /* Check for access error */ + if ((data & KL_PAG_A) == 0 || (wr & ((data & KL_PAG_W) == 0))) { +#if KS_ITS + if (QITS) { + /* Remap the flag bits */ + if (uf) { /* U */ + u_tlb[page] = 0; + } else { + e_tlb[page] = 0; + } + if ((data & KL_PAG_A) == 0) { + fault_data = ((uint64)addr) | 033LL << 30 |((uf)?SMASK:0); + } else { + fault_data = ((uint64)addr) | 024LL << 30 |((uf)?SMASK:0); + } + page_fault = 1; + return 0; + } +#endif + fault_data = BIT8 | (uint64)addr; + /* Remap the flag bits */ + if (uf) { /* U */ + fault_data |= SMASK; /* BIT0 */ + u_tlb[page] = 0; + } else { + e_tlb[page] = 0; + } +// if (data & KL_PAG_C) /* C */ +// fault_data |= BIT7; /* BIT7 */ +// if (data & KL_PAG_P) /* P */ + // fault_data |= BIT6; /* BIT6 */ + if (wr) /* T */ + fault_data |= BIT5; /* BIT5 */ +// if (data & KL_PAG_W) /* W */ +// fault_data |= BIT3; /* BIT3 */ + if (data & KL_PAG_A) { /* A */ + fault_data |= BIT2; /* BIT2 */ + if (data & KL_PAG_S) /* S */ + fault_data |= BIT4; /* BIT4 */ + } + page_fault = 1; + return 0; + } + + return 1; +} + +/* + * Register access on KS 10 + */ +uint64 get_reg(int reg) { + return FM[fm_sel|(reg & 017)]; +} + +void set_reg(int reg, uint64 value) { + FM[fm_sel|(reg & 017)] = value; +} + +int Mem_read(int flag, int cur_context, int fetch) { + t_addr addr; + + if (AB < 020) { + if (xct_flag != 0 && !fetch) { + if (((xct_flag & 8) != 0 && cur_context && !ptr_flg) || + ((xct_flag & 4) != 0 && !cur_context && !BYF5 && !ptr_flg) || + ((xct_flag & 2) != 0 && !cur_context && ptr_flg) || + ((xct_flag & 1) != 0 && !cur_context && BYF5 )) { + MB = FM[prev_ctx|AB]; + return 0; + } + } + /* Check if invalid section */ + MB = get_reg(AB); + } else { + if (!page_lookup(AB, flag, &addr, 0, cur_context, fetch)) + return 1; + if (addr >= MEMSIZE) { + irq_flags |= 02000; + return 1; + } + if (sim_brk_summ && sim_brk_test(AB, SWMASK('R'))) + watch_stop = 1; + sim_interval--; + MB = M[addr]; + } + return 0; +} + +int Mem_write(int flag, int cur_context) { + t_addr addr; + + if (AB < 020) { + if (xct_flag != 0) { + if (((xct_flag & 8) != 0 && cur_context && !ptr_flg) || + ((xct_flag & 4) != 0 && !cur_context && !BYF5 && !ptr_flg) || + ((xct_flag & 2) != 0 && !cur_context && ptr_flg) || + ((xct_flag & 1) != 0 && !cur_context && BYF5 )) { + FM[prev_ctx|AB] = MB; + return 0; + } + } + set_reg(AB, MB); + } else { + if (!page_lookup(AB, flag, &addr, 1, cur_context, 0)) + return 1; + if (addr >= MEMSIZE) { + irq_flags |= 02000; + return 1; + } + if (sim_brk_summ && sim_brk_test(AB, SWMASK('W'))) + watch_stop = 1; + sim_interval--; + M[addr] = MB; + } + return 0; +} +#endif + #if KL int load_tlb(int uf, int page, int wr) @@ -2094,10 +2540,6 @@ load_tlb(int uf, int page, int wr) #define PG_PAG 0017777 if (t20_page) { /* Start with full access */ int acc_bits = PG_PUB|PG_WRT|PG_KEP|PG_CAC; - uint64 spt = FM[(06<<4)|3] & PG_MASK; - uint64 cst = FM[(06<<4)|2] & PG_MASK; - uint64 cst_msk = FM[(06<<4)|0]; - uint64 cst_dat = FM[(06<<4)|1]; uint64 cst_val = 0; int index; int pg; @@ -2134,14 +2576,14 @@ sect_loop: acc_bits &= (data >> 18) & RMASK; sim_interval--; index = data & RMASK; - data = M[index + spt]; + data = M[index + (spt & PG_MASK)]; break; case 3: /* Indirect page */ acc_bits &= (data >> 18) & RMASK; index = (data >> 18) & PG_IDX; sim_interval--; - data = M[(data & RMASK) + spt]; + data = M[(data & RMASK) + (spt & PG_MASK)]; if ((data & PG_STG) != 0) { fault_data = 0; page_fault = 1; @@ -2160,15 +2602,15 @@ sect_loop: pg = data & PG_PAG; /* Update CST entry if needed */ - if (cst) { + if ((cst & PG_MASK)) { sim_interval--; - cst_val = M[cst + pg]; + cst_val = M[(cst & PG_MASK) + pg]; if ((cst_val & PG_AGE) == 0) { fault_data = 0; page_fault = 1; return 0; } - M[cst + pg] = (cst_val & cst_msk) | cst_dat; + M[(cst & PG_MASK) + pg] = (cst_val & cst_msk) | cst_dat; } /* Get address of page */ @@ -2193,14 +2635,14 @@ pg_loop: acc_bits &= (data >> 18) & RMASK; sim_interval--; index = data & RMASK; - data = M[index + spt]; + data = M[index + (spt & PG_MASK)]; break; case 3: /* Indirect page */ acc_bits &= (data >> 18) & RMASK; index = (data >> 18) & PG_IDX; sim_interval--; - data = M[(data & RMASK) + spt]; + data = M[(data & RMASK) + (spt & PG_MASK)]; if ((data & PG_STG) != 0) { fault_data = 0; page_fault = 1; @@ -2221,9 +2663,9 @@ pg_loop: pg = data & PG_PAG; /* Check outside of memory */ /* Update CST entry if needed */ - if (cst) { + if ((cst & PG_MASK)) { sim_interval--; - cst_val = M[cst + pg]; + cst_val = M[(cst & PG_MASK) + pg]; if ((cst_val & PG_AGE) == 0) { fault_data = 0; page_fault = 1; @@ -2237,7 +2679,7 @@ pg_loop: page_fault = 1; return 0; } - M[cst + pg] = (cst_val & cst_msk) | cst_dat; + M[(cst & PG_MASK) + pg] = (cst_val & cst_msk) | cst_dat; } else { if (acc_bits & PG_WRT) { cst_val = 1; @@ -2397,16 +2839,13 @@ int page_lookup(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, int /* Check if we need to modify TLB entry for TOPS 20 */ if (t20_page && (data & KL_PAG_A) && (wr & ((data & KL_PAG_W) == 0)) && (data & KL_PAG_S)) { - uint64 cst = FM[(06<<4)|2] & PG_MASK; - uint64 cst_msk = FM[(06<<4)|0]; - uint64 cst_dat = FM[(06<<4)|1]; /* Update CST entry if needed */ - if (cst) { + if ((cst & PG_MASK)) { uint64 cst_val; int pg = data & 017777; sim_interval--; - cst_val = M[cst + pg]; - M[cst + pg] = (cst_msk & cst_val) | cst_dat | 1; + cst_val = M[(cst & PG_MASK) + pg]; + M[(cst & PG_MASK) + pg] = (cst_msk & cst_val) | cst_dat | 1; } data |= KL_PAG_W; /* Map the page */ @@ -2810,11 +3249,9 @@ int page_lookup(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, int } /* If fetching byte data, use write access */ - if (BYF5 && (IR & 06) == 6) - wr = 1; +// if (BYF5 && (IR & 06) == 6) + // wr = 1; - /* If this is modify instruction use write access */ - wr |= modify; /* Figure out if this is a user space access */ if (flag) @@ -2827,6 +3264,9 @@ int page_lookup(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, int } } + /* If this is modify instruction use write access */ + wr |= modify; + /* If user, check if small user enabled */ if (uf) { if (small_user && (page & 0340) != 0) { @@ -2923,6 +3363,7 @@ read: return 1; if (addr >= MEMSIZE) { nxm_flag = 1; + check_apr_irq(); return 1; } if (sim_brk_summ && sim_brk_test(AB, SWMASK('R'))) @@ -2962,6 +3403,7 @@ write: return 1; if (addr >= MEMSIZE) { nxm_flag = 1; + check_apr_irq(); return 1; } if (sim_brk_summ && sim_brk_test(AB, SWMASK('W'))) @@ -2994,6 +3436,7 @@ int its_load_tlb(uint32 reg, int page, uint32 *tlb) { if (entry >= MEMSIZE) { nxm_flag = 1; fault_data |= 0400; + check_apr_irq(); return 1; } sim_interval--; @@ -3032,11 +3475,8 @@ int page_lookup_its(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, } /* If fetching byte data, use write access */ - if (BYF5 && (IR & 06) == 6) - wr = 1; - - /* If this is modify instruction use write access */ - wr |= modify; +// if (BYF5 && (IR & 06) == 6) + // wr = 1; /* Figure out if this is a user space access */ if (flag) @@ -3048,6 +3488,9 @@ int page_lookup_its(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, } } + /* If this is modify instruction use write access */ + wr |= modify; + /* AC & 1 = ??? */ /* AC & 2 = Read User */ /* AC & 4 = Write User */ @@ -3060,6 +3503,7 @@ int page_lookup_its(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, case 1: if (fetch) { mem_prot = 1; fault_data |= 2; + check_apr_irq(); } break; case 2: if (!wr) @@ -3067,6 +3511,7 @@ int page_lookup_its(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, /* Fall through */ case 3: mem_prot = 1; fault_data |= 2; + check_apr_irq(); break; } } @@ -3140,6 +3585,7 @@ fault: } else { PC = (PC + 1) & RMASK; } + check_apr_irq(); return 0; } @@ -3164,6 +3610,7 @@ int Mem_read_its(int flag, int cur_context, int fetch) { if (T11RANGE(addr) && QTEN11) { if (ten11_read (addr, &MB)) { nxm_flag = 1; + check_apr_irq(); return 1; } return 0; @@ -3173,12 +3620,14 @@ int Mem_read_its(int flag, int cur_context, int fetch) { if (AUXCPURANGE(addr) && QAUXCPU) { if (auxcpu_read (addr, &MB)) { nxm_flag = 1; + check_apr_irq(); return 1; } } #endif if (addr >= MEMSIZE) { nxm_flag = 1; + check_apr_irq(); return 1; } if (sim_brk_summ && sim_brk_test(AB, SWMASK('R'))) @@ -3210,6 +3659,7 @@ int Mem_write_its(int flag, int cur_context) { if (T11RANGE(addr) && QTEN11) { if (ten11_write (addr, MB)) { nxm_flag = 1; + check_apr_irq(); return 1; } return 0; @@ -3219,12 +3669,14 @@ int Mem_write_its(int flag, int cur_context) { if (AUXCPURANGE(addr) && QAUXCPU) { if (auxcpu_write (addr, MB)) { nxm_flag = 1; + check_apr_irq(); return 1; } } #endif if (addr >= MEMSIZE) { nxm_flag = 1; + check_apr_irq(); return 1; } if (sim_brk_summ && sim_brk_test(AB, SWMASK('W'))) @@ -3513,6 +3965,7 @@ int Mem_read_bbn(int flag, int cur_context, int fetch) { } if (addr >= MEMSIZE) { nxm_flag = 1; + check_apr_irq(); return 1; } if (sim_brk_summ && sim_brk_test(AB, SWMASK('R'))) @@ -3543,6 +3996,7 @@ int Mem_write_bbn(int flag, int cur_context) { } if (addr >= MEMSIZE) { nxm_flag = 1; + check_apr_irq(); return 1; } if (sim_brk_summ && sim_brk_test(AB, SWMASK('W'))) @@ -3584,6 +4038,7 @@ int page_lookup_waits(t_addr addr, int flag, t_addr *loc, int wr, int cur_contex } } mem_prot = 1; + check_apr_irq(); return 0; } else { *loc = addr; @@ -3602,6 +4057,7 @@ int Mem_read_waits(int flag, int cur_context, int fetch) { return 1; if (addr >= MEMSIZE) { nxm_flag = 1; + check_apr_irq(); return 1; } if (sim_brk_summ && sim_brk_test(AB, SWMASK('R'))) @@ -3629,6 +4085,7 @@ int Mem_write_waits(int flag, int cur_context) { return 1; if (addr >= MEMSIZE) { nxm_flag = 1; + check_apr_irq(); return 1; } if (sim_brk_summ && sim_brk_test(AB, SWMASK('W'))) @@ -3653,6 +4110,7 @@ int page_lookup_ka(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, } } mem_prot = 1; + check_apr_irq(); return 0; } else { *loc = addr; @@ -3670,6 +4128,7 @@ int Mem_read_ka(int flag, int cur_context, int fetch) { return 1; if (addr >= MEMSIZE) { nxm_flag = 1; + check_apr_irq(); return 1; } if (sim_brk_summ && sim_brk_test(AB, SWMASK('R'))) @@ -3696,6 +4155,7 @@ int Mem_write_ka(int flag, int cur_context) { return 1; if (addr >= MEMSIZE) { nxm_flag = 1; + check_apr_irq(); return 1; } if (sim_brk_summ && sim_brk_test(AB, SWMASK('W'))) @@ -3923,7 +4383,7 @@ int Mem_write_nopage() { */ int Mem_read_word(t_addr addr, uint64 *data, int ept) { -#if KL | KI +#if KL | KI | KS if (ept) addr += eb_ptr; #endif @@ -3935,7 +4395,7 @@ int Mem_read_word(t_addr addr, uint64 *data, int ept) int Mem_write_word(t_addr addr, uint64 *data, int ept) { -#if KL | KI +#if KL | KI | KS if (ept) addr += eb_ptr; #endif @@ -3980,7 +4440,7 @@ int flag1; int flag3; int instr_count = 0; /* Number of instructions to execute */ uint32 IA; /* Initial address of first fetch */ -#if ITS | KL_ITS +#if ITS | KL_ITS | KS_ITS char one_p_arm = 0; /* One proceed arm */ #endif @@ -3989,10 +4449,13 @@ if (sim_step != 0) { sim_cancel_step(); } +#if KS +reason = SCPE_OK; +#else /* Build device table */ if ((reason = build_dev_tab ()) != SCPE_OK) /* build, chk dib_tab */ return reason; - +#endif /* Main instruction fetch/decode loop: check clock queue, intr, trap, bkpt */ f_load_pc = 1; @@ -4050,19 +4513,21 @@ if ((reason = build_dev_tab ()) != SCPE_OK) /* build, chk dib_tab */ } #endif /* MAGIC_SWITCH */ - check_apr_irq(); +// check_apr_irq(); /* Normal instruction */ if (f_load_pc) { modify = 0; xct_flag = 0; -#if KI | KL +#if KI | KL | KS trap_flag = 0; -#if KL - sect = cur_sect = pc_sect; - glb_sect = 0; +#endif +#if KL | KS extend = 0; ptr_flg = 0; #endif +#if KL + sect = cur_sect = pc_sect; + glb_sect = 0; #endif AB = PC; uuo_cycle = 0; @@ -4070,7 +4535,7 @@ if ((reason = build_dev_tab ()) != SCPE_OK) /* build, chk dib_tab */ } if (f_inst_fetch) { -#if !(KI | KL) +#if !(KI|KL) fetch: #endif #if ITS @@ -4107,11 +4572,11 @@ no_fetch: BYF5 = 0; } -#if KI | KL +#if KI | KL | KS /* Handle page fault and traps */ if (page_enable && trap_flag == 0 && (FLAGS & (TRP1|TRP2))) { if (FLAGS & ADRFLT) { -#if KL_ITS +#if KL_ITS | KS_ITS if (QITS && (FLAGS & (TRP1|TRP2|ADRFLT)) == (TRP1|TRP2|ADRFLT)) one_p_arm = 1; #endif @@ -4150,26 +4615,27 @@ no_fetch: } #endif + if ((!pi_cycle) & pi_pending +#if KI | KL | KS + & (!trap_flag) +#endif + ) { + pi_rq = check_irq_level(); + } /* Handle indirection repeat until no longer indirect */ do { - if ((!pi_cycle) & pi_pending -#if KI | KL - & (!trap_flag) -#endif - ) { - pi_rq = check_irq_level(); - } ind = TST_IND(MB) != 0; AR = MB; AB = MB & RMASK; ix = GET_XR(MB); if (ix) { -#if KL +#if KL | KS if (((xct_flag & 8) != 0 && !ptr_flg) || ((xct_flag & 2) != 0 && ptr_flg)) AR = FM[prev_ctx|ix]; else AR = get_reg(ix); +#if KL /* Check if extended indexing */ if (QKLB && t20_page && cur_sect != 0 && (AR & SMASK) == 0 && (AR & SECTM) != 0) { AR = (AR + ((AB & RSIGN) ? SECTM|((uint64)AB): (uint64)AB)) & (SECTM|RMASK); @@ -4179,9 +4645,10 @@ no_fetch: } else glb_sect = 0; /* For KL */ +#endif AR = MB = (AB + AR) & FMASK; #else - /* For KA & KI */ + /* For KA & KI & PDP6 */ AR = MB = (AB + get_reg(ix)) & FMASK; #endif AB = MB & RMASK; @@ -4255,16 +4722,32 @@ in_loop: goto in_loop; } #endif - } - /* Handle events during a indirect loop */ - AIO_CHECK_EVENT; /* queue async events */ - if (--sim_interval <= 0) { - if ((reason = sim_process_event()) != SCPE_OK) { - return reason; - } + /* Handle events during a indirect loop */ + AIO_CHECK_EVENT; /* queue async events */ + if (--sim_interval <= 0) { + if ((reason = sim_process_event()) != SCPE_OK) { + return reason; + } + if ((!pi_cycle) & pi_pending +#if KI | KL | KS + & (!trap_flag) +#endif + ) { + pi_rq = check_irq_level(); + } + } +#if KS + if ((IR & 0700) == 0700) { + AB = AR = MB; + ind = 0; + } +#endif } } while (ind & !pi_rq); +#if KS + if ((IR & 0700) != 0700) +#endif /* If not a JRST clear the upper half of AR. */ if (IR != 0254) { AR &= RMASK; @@ -4273,6 +4756,9 @@ in_loop: /* If there is a interrupt handle it. */ if (pi_rq) { +#if KI | KL | KS + int pi_mask = (0200 >> pi_enc); +#endif #if KA | PDP6 st_pi: #endif @@ -4284,19 +4770,24 @@ st_pi: pi_ov = 0; AB = 040 | (pi_enc << 1) | maoff; xct_flag = 0; -#if KI | KL -#if KL - sect = cur_sect = 0; - extend = 0; +#if KS + if ((dev_irq[0] & pi_mask) == 0) { + AB |= eb_ptr; + AB = uba_get_vect(AB, pi_enc); + sim_debug(DEBUG_IRQ, &cpu_dev, "vect irq %o %06o\n", pi_enc, AB); + } else + AB |= eb_ptr; + Mem_read_nopage(); + goto no_fetch; #endif +#if KI | KL /* * Scan through the devices and allow KI devices to have first * hit at a given level. */ - for (f = 0; f < 128; f++) { - if (dev_irqv[f] != 0 && dev_irq[f] & (0200 >> pi_enc)) { + for (f = 0; f <= max_dev; f++) { + if (dev_irqv[f] != 0 && dev_irq[f] & pi_mask) { AB = dev_irqv[f](f << 2, AB); - if (dev_irqv[f] != 0) sim_debug(DEBUG_IRQ, &cpu_dev, "vect irq %o %03o %06o\n", pi_enc, dev_irq[f], AB); break; @@ -4307,6 +4798,8 @@ st_pi: else AB |= eb_ptr; #if KL + sect = cur_sect = 0; + extend = 0; pi_vect = AB; #endif Mem_read_nopage(); @@ -4317,7 +4810,7 @@ st_pi: } -#if KI | KL +#if KI | KL | KS if (page_enable && page_fault) { if (!f_pc_inh && !pi_cycle) PC = (PC + 1) & RMASK; @@ -4333,7 +4826,7 @@ st_pi: } /* Update history */ - if (hst_lnt && PC > 017) { + if (hst_lnt) { hst_p = hst_p + 1; if (hst_p >= hst_lnt) { hst_p = 0; @@ -4357,7 +4850,7 @@ st_pi: | ill_op #endif #endif -#if KL +#if KL | KS | (fm_sel >> 4) #endif @@ -4377,7 +4870,7 @@ st_pi: sac_inh = 0; modify = 0; f_pc_inh = 0; -#if KL +#if KL | KS if (extend) { if (IR == 0 || IR > 031 || AC != 0 || do_extend(IA)) { IR = 0123; @@ -4459,13 +4952,16 @@ muuo: /* MUUO */ -#if KI | KL +#if KI | KL | KS case 0100: /* UJEN */ - case 0101: case 0102: case 0103: + case 0101: +#if !KS_ITS + case 0102: case 0103: +#endif case 0104: /* JSYS */ case 0106: case 0107: -#if !KL_ITS +#if !(KL_ITS | KS_ITS) case 0247: /* UUO */ #endif unasign: @@ -4486,6 +4982,11 @@ unasign: MB |= (uint64)(prev_sect); } } else +#elif KS + if (t20_page) { + AR = (uint64)AB; /* Save address */ + MB = (((uint64)((IR << 9) | (AC << 5))) | ((uint64)(FLAGS) << 23)) & FMASK; + } else #endif MB = ((uint64)(IR) << 27) | ((uint64)(AC) << 23) | (uint64)(AB); AB = ub_ptr | 0424; @@ -4507,6 +5008,11 @@ unasign: MB |= (FLAGS & PRV_PUB) ? SMASK : 0; } } +#elif KS + if (t20_page) + MB = (PC + (trap_flag == 0)) & RMASK; + else + MB = (((uint64)(FLAGS) << 23) & LMASK) | ((PC + (trap_flag == 0)) & RMASK); #else MB = (((uint64)(FLAGS) << 23) & LMASK) | ((PC + (trap_flag == 0)) & RMASK); if ((FLAGS & USER) == 0) { @@ -4517,7 +5023,7 @@ unasign: Mem_write_nopage(); #if KL extend = 0; - if (QKLB && t20_page) { /* Save address */ + if (QKLB && t20_page) { /* Restore address */ if (pc_sect != 0 && glb_sect == 0 && AR < 020) AR |= BIT17; else @@ -4537,14 +5043,31 @@ unasign: prev_sect = pc_sect & 037; } Mem_write_nopage(); +#endif +#if KS + extend = 0; + if (t20_page) { /* Restore address */ + MB = AR; + AB ++; + Mem_write_nopage(); + /* Save context */ + AB ++; + MB = SMASK| + ((uint64)(fm_sel & 0160) << 23) | + ((uint64)(prev_ctx & 0160) << 20) | + (ub_ptr >> 9); + Mem_write_nopage(); + } #endif /* Read in new PC and flags */ FLAGS &= ~ (PRV_PUB|BYTI|ADRFLT|TRP1|TRP2); AB = ub_ptr | 0430; if (trap_flag != 0) AB |= 1; +#if !KS if (FLAGS & PUBLIC) AB |= 2; +#endif if (FLAGS & USER) AB |= 4; Mem_read_nopage(); @@ -4554,14 +5077,21 @@ unasign: pc_sect = (MB >> 18) & 00037; FLAGS = 0; } else +#endif +#if KS + if (t20_page) + FLAGS = 0; + else #endif FLAGS = (MB >> 23) & 017777; /* If transistioning from user to executive adjust flags */ if ((FLAGS & USER) == 0) { if ((AB & 4) != 0) FLAGS |= USERIO; +#if !KS if ((AB & 2 || (FLAGS & OVR) != 0)) FLAGS |= PRV_PUB|OVR; +#endif } PC = MB & RMASK; f_pc_inh = 1; @@ -4705,21 +5235,36 @@ unasign: } goto unasign; #endif +#if KS_ITS + case 0102: /* XCT */ + case 0103: /* XCTI */ + if (QITS && (FLAGS & USER) == 0) { + f_load_pc = 0; + f_pc_inh = 1; + xct_flag = 020|AC; + break; + } + goto unasign; +#endif -#if KI | KL -#if KL +#if KI | KL | KS +#if KL | KS case 0105: /* ADJSP */ BR = get_reg(AC); +#if KL if (QKLB && t20_page && pc_sect != 0 && (BR & SMASK) == 0 && (BR & SECTM) != 0) { AD = (((AR & RSIGN)?(LMASK|AR):AR) + BR) & (SECTM|RMASK); AD |= BR & ~(SECTM|RMASK); } else { +#endif AD = (BR + AR) & RMASK; AD |= (BR & LMASK) + ((AR << 18) & LMASK); +#if KL if (QKLB && pc_sect == 0 && ((BR ^ AD) & SMASK) != 0) FLAGS |= TRP2; } +#endif i_flags = SAC; AR = AD & FMASK; break; @@ -4921,7 +5466,7 @@ dpnorm: if ((AR & 0777) == 0777) AR &= (FPFMASK << 8); } -#if KL +#if KL | KS while (((AR & (FPSBIT|FPNBIT)) == (FPSBIT|FPNBIT)) || ((AR & (FPSBIT|FPNBIT)) == 0)) { #else @@ -4936,7 +5481,7 @@ dpnorm: MQ &= FMASK; nrf = 1; } -#if KL +#if KL | KS /* Handle special minus case */ if (AR == (FPHBIT|FPSBIT)) { SC += 1; @@ -4997,7 +5542,7 @@ dpnorm: SMEAR_SIGN(BR); BR <<= 35; BR |= MB & CMASK; -#if KL +#if KL | KS /* One extra bit for KL */ AR <<= 1; BR <<= 1; @@ -5049,7 +5594,7 @@ dpnorm: if (flag1) { AR = (AR ^ FPFMASK) + 1; } -#if KL +#if KL | KS else AR++; /* Round on KL */ AR = (AR & FPHBIT) | (AR >> 1); /* Remove extra bit */ @@ -5084,7 +5629,7 @@ dpnorm: set_reg(AC+1, MQ); break; -#if KL +#if KL | KS case 0114: /* DADD */ flag1 = flag3 = 0; /* AR,ARX = AC BR,BX = mem */ @@ -5115,7 +5660,6 @@ dpnorm: if (flag1 != flag3) { if (!pi_cycle) FLAGS |= OVR|TRP1; - check_apr_irq(); } ARX &= CMASK; ARX |= AR & SMASK; @@ -5153,7 +5697,6 @@ dpnorm: if (flag1 != flag3) { if (!pi_cycle) FLAGS |= OVR|TRP1; - check_apr_irq(); } ARX &= CMASK; ARX |= AR & SMASK; @@ -5375,7 +5918,7 @@ dpnorm: goto last; MQ = CCM(MB) + 1; /* Low */ /* High */ -#if KL +#if KL | KS flag1 = flag3 = 0; if ((CCM(AR) + ((MQ & SMASK) != 0)) & SMASK) { FLAGS |= CRY1; @@ -5384,14 +5927,13 @@ dpnorm: #endif AR = (CM(AR) + ((MQ & SMASK) != 0)); MQ &= CMASK; -#if KL +#if KL | KS if (AR & C1) { FLAGS |= CRY0; flag3 = 1; } if (flag1 != flag3 && !pi_cycle) { FLAGS |= OVR|TRP1; - check_apr_irq(); } if ((AR == SMASK && MQ == 0) && !pi_cycle) FLAGS |= TRP1; @@ -5402,7 +5944,7 @@ dpnorm: break; case 0123: /* Extend */ -#if KL +#if KL | KS /* Handle like xct */ f_load_pc = 0; f_pc_inh = 1; @@ -5418,9 +5960,22 @@ dpnorm: case 0124: /* DMOVEM */ AR = get_reg(AC); -#if KL +#if KL | KS MQ = get_reg(AC + 1); #endif +#if KS + BR = AB; + AB = (AB + 1) & RMASK; + MB = MQ; + if (Mem_write(0, 0)) + goto last; + FLAGS |= BYTI; + AB = BR; + MB = AR; + if (Mem_write(0, 0)) + goto last; + FLAGS &= ~BYTI; +#else /* Handle each half as seperate instruction */ if ((FLAGS & BYTI) == 0) { MB = AR; @@ -5428,7 +5983,7 @@ dpnorm: goto last; FLAGS |= BYTI; } -#if !KL +#if !(KL) MQ = get_reg(AC + 1); #endif if ((FLAGS & BYTI)) { @@ -5438,6 +5993,7 @@ dpnorm: if (Mem_write(0, 0)) goto last; } +#endif break; case 0125: /* DMOVNM */ @@ -5449,7 +6005,7 @@ dpnorm: BR = BR + 1; MQ = CCM(MQ) + 1; if (MQ & SMASK) { -#if KL +#if KL | KS flag1 = flag3 = 0; if ((CCM(get_reg(AC)) + 1) & SMASK) { FLAGS |= CRY1; @@ -5457,14 +6013,13 @@ dpnorm: } #endif AR = BR; -#if KL +#if KL | KS if (AR & C1) { FLAGS |= CRY0; flag3 = 1; } if (flag1 != flag3 && !pi_cycle) { FLAGS |= OVR|TRP1; - check_apr_irq(); } if ((AR == SMASK && MQ == 0) && !pi_cycle) FLAGS |= TRP1; @@ -5475,7 +6030,7 @@ dpnorm: if (Mem_write(0, 0)) goto last; FLAGS |= BYTI; -#if KL +#if KL | KS AB = (AB + 1) & RMASK; MB = MQ & CMASK; if (Mem_write(0, 0)) @@ -5667,10 +6222,8 @@ dpnorm: AR = get_reg(AC); MB = AR; if (Mem_write(0, 0)) { - IR = 0; goto last; } - IR = 0; break; } #endif @@ -5692,18 +6245,15 @@ dpnorm: #if BBN if (QBBN) { if (Mem_read(0, 0, 0)) { - IR = 0; goto last; } modify = 1; AR = MB; if (Mem_write(0, 0)) { - IR = 0; goto last; } if (AC != 0) set_reg(AC, AR); /* blank, I, B */ - IR = 0; break; } #endif @@ -5738,7 +6288,7 @@ dpnorm: goto unasign; case 0247: /* UUO or ITS CIRC instruction */ -#if ITS | KL_ITS +#if ITS | KL_ITS | KS_ITS if (QITS) { BR = AR; AR = get_reg(AC); @@ -5805,7 +6355,7 @@ unasign: #endif case 0133: /* IBP/ADJBP */ -#if KL +#if KL | KS if (AC != 0) { /* ADJBP */ if (Mem_read(0, 0, 0)) goto last; @@ -5816,6 +6366,7 @@ unasign: FE = (AR >> 30) & 077; /* P */ f = 0; +#if KL if (QKLB && t20_page && pc_sect != 0 && FE > 36) { if (FE == 077) goto muuo; @@ -5823,6 +6374,7 @@ unasign: SC = _byte_adj[(FE - 37)].s; FE = _byte_adj[(FE - 37)].p; } +#endif left = (36 - FE) / SC; /* Number bytes left (36 - P)/S */ bpw = left + (FE / SC); /* Bytes per word */ if (bpw == 0) { @@ -5843,6 +6395,7 @@ unasign: adjw--; } FE = 36 - (adjb * SC) - ((36 - FE) % SC); /* New P */ +#if KL if (f) { /* Short pointer */ for (f = 0; f < 28; f++) { @@ -5876,6 +6429,7 @@ unasign: set_reg(AC+1, BR); break; } +#endif AR = (((uint64)(FE & 077)) << 30) | /* Make new BP */ (AR & PMASK & LMASK) | /* S,IX,I */ ((AR + adjw) & RMASK); @@ -5887,13 +6441,13 @@ unasign: case 0134: /* ILDB */ case 0136: /* IDPB */ if ((FLAGS & BYTI) == 0) { /* BYF6 */ + modify = 1; #if KL if (Mem_read(0, 0, 0)) { #elif KI - modify = 1; if (Mem_read(0, 1, 0)) { #else - modify = 1; +// modify = 1; if (Mem_read(0, !QITS, 0)) { #endif #if PDP6 @@ -5924,6 +6478,7 @@ unasign: MB = AR; if (Mem_write(0, 0)) goto last; + modify = 0; if ((IR & 04) == 0) break; goto ld_ptr; @@ -5953,7 +6508,7 @@ unasign: AB = (AB - 1) & RMASK; } else AR = (AR & LMASK) | ((AR + 1) & RMASK); -#elif KI +#elif KI | KS AR = (AR & LMASK) | ((AR + 1) & RMASK); #else AR = (AR + 1) & FMASK; @@ -5962,7 +6517,7 @@ unasign: AR &= PMASK; AR |= (uint64)(SCAD & 077) << 30; MB = AR; -#if KL +#if KL | KS if (Mem_write(0, 0)) #elif KI if (Mem_write(0, 1)) @@ -5970,9 +6525,9 @@ unasign: if (Mem_write(0, !QITS)) #endif goto last; + modify = 0; if ((IR & 04) == 0) break; - modify = 0; goto ldb_ptr; } /* Fall through */ @@ -5980,7 +6535,7 @@ unasign: case 0135:/* LDB */ case 0137:/* DPB */ if ((FLAGS & BYTI) == 0 || !BYF5) { -#if KL +#if KL | KS if (Mem_read(0, 0, 0)) #elif KI if (Mem_read(0, 1, 0)) @@ -6010,7 +6565,7 @@ ldb_ptr: f_load_pc = 0; f_inst_fetch = 0; f_pc_inh = 1; -#if KL_ITS +#if KL_ITS | KS_ITS if (QITS && one_p_arm) { FLAGS |= ADRFLT; one_p_arm = 0; @@ -6037,10 +6592,9 @@ ldb_ptr: #if KL ptr_flg = 0; ld_exe: -#else +#endif if ((IR & 06) == 6) modify = 1; -#endif AB = AR & RMASK; MQ = (uint64)(1) << SC; MQ -= 1; @@ -6087,7 +6641,7 @@ ld_exe: case 0132:/* FSC */ SC = ((AB & RSIGN) ? 0400 : 0) | (AB & 0377); SCAD = GET_EXPO(AR); -#if KL +#if KL | KS SC |= (SC & 0400) ? 0777000 : 0; SCAD |= (SC & 0400) ? 0777000 : 0; SC = SCAD + SC; @@ -6173,7 +6727,7 @@ ufa: /* Get exponent */ SC = GET_EXPO(AR); -#if KL +#if KL | KS SC |= (SC & 0400) ? 0777000 : 0; /* Extend sign */ #endif /* Smear the signs */ @@ -6214,7 +6768,7 @@ fnorm: #if !PDP6 AR &= ~077; /* Save one extra bit */ #endif -#if !KL +#if !(KL|KS) if (((SC & 0400) != 0) ^ ((SC & 0200) != 0)) fxu_hold_set = 1; #endif @@ -6270,7 +6824,7 @@ fnormx: AR = MQ = 0; SC = 0; } -#if KL +#if KL | KS if (!pi_cycle && (SC & 0400) != 0) { FLAGS |= OVR|FLTOVR|TRP1; if ((SC & RSIGN) != 0) @@ -6285,7 +6839,9 @@ fnormx: MQ = 0; } #endif +#if PDP6 | KA check_apr_irq(); +#endif } #endif #if WAITS @@ -6346,7 +6902,7 @@ fnormx: SC = (((BR & SMASK) ? 0777 : 0) ^ (BR >> 27)) & 0777; SC += (((AR & SMASK) ? 0777 : 0) ^ (AR >> 27)) & 0777; SC += 0600; -#if KL +#if KL | KS SC |= (SC & 0400) ? 0777000 : 0; /* Extend sign */ #else SC &= 0777; @@ -6418,7 +6974,7 @@ fnormx: AR = CM(AR) + 1; flag1 = !flag1; } -#if KL +#if KL | KS SC = (SC + ((0777 ^ SCAD) + 1) + 0201); #else SC = (SC + ((0777 ^ SCAD) + 1) + 0201) & 0777; @@ -6428,9 +6984,12 @@ fnormx: BR &= MMASK; /* Check if we need to fix things */ if (BR >= (AR << 1)) { - if (!pi_cycle) + if (!pi_cycle) { FLAGS |= OVR|NODIV|FLTOVR|TRP1; - check_apr_irq(); +#if PDP6 | KA + check_apr_irq(); +#endif + } sac_inh = 1; break; /* Done */ } @@ -6522,9 +7081,11 @@ fnormx: if (!fxu_hold_set) { FLAGS |= FLTUND; } +#if PDP6 | KA check_apr_irq(); +#endif } -#if !PDP6 & !KL +#if !(PDP6 | KL | KS) if (flag1) { AR = ((AR ^ MMASK) + 1) & MMASK; AR |= SMASK; @@ -6637,7 +7198,9 @@ left: if (!fxu_hold_set) { FLAGS |= FLTUND; } +#if PDP6 | KA check_apr_irq(); +#endif } SCAD = SC ^ ((AR & SMASK) ? 0377 : 0); AR &= SMASK|MMASK; @@ -6667,9 +7230,12 @@ left: BR &= MMASK; /* Check if we need to fix things */ if (BR >= (AR << 1)) { - if (!pi_cycle) + if (!pi_cycle) { FLAGS |= OVR|NODIV|FLTOVR|TRP1; - check_apr_irq(); +#if PDP6 | KA + check_apr_irq(); +#endif + } sac_inh = 1; break; /* Done */ } @@ -6721,7 +7287,9 @@ left: if (!fxu_hold_set) { FLAGS |= FLTUND; } +#if PDP6 | KA check_apr_irq(); +#endif } SCAD = SC ^ ((AR & SMASK) ? 0377 : 0); AR &= SMASK|MMASK; @@ -6784,9 +7352,11 @@ left: } if (flag1 != flag3 && !pi_cycle) { FLAGS |= OVR|TRP1; +#if PDP6 | KA check_apr_irq(); +#endif } -#if KI | KL +#if KI | KL | KS if (AR == SMASK && !pi_cycle) FLAGS |= TRP1; #endif @@ -6828,7 +7398,12 @@ left: if ((IR & 4) == 0) { /* IMUL */ if (AR > (uint64)flag3 && !pi_cycle) { FLAGS |= OVR|TRP1; +#if PDP6 | KA check_apr_irq(); +#endif +#if KS + i_flags = 0; +#endif } if (flag3) { MQ ^= CMASK; @@ -6840,7 +7415,12 @@ left: } if ((AR & SMASK) != 0 && !pi_cycle) { FLAGS |= OVR|TRP1; +#if PDP6 | KA check_apr_irq(); +#endif +#if KS + i_flags = 0; +#endif } if (flag3) { AR ^= FMASK; @@ -6854,8 +7434,10 @@ left: AR &= FMASK; MQ = (MQ & ~SMASK) | (AR & SMASK); #if KA - if (BR == SMASK && (AR & SMASK)) /* Handle special case */ + if (BR == SMASK && (AR & SMASK)) { /* Handle special case */ FLAGS |= OVR; + check_apr_irq(); + } #endif break; @@ -6871,17 +7453,21 @@ left: } if (BR == 0) { /* Check for overflow */ - FLAGS |= OVR|NODIV; /* Overflow and No Divide */ - sac_inh=1; /* Don't touch AC */ + FLAGS |= OVR|NODIV|TRP1; /* Overflow and No Divide */ +#if PDP6 | KA check_apr_irq(); +#endif + sac_inh=1; /* Don't touch AC */ break; /* Done */ } #if !PDP6 if (AR == SMASK && BR == 1) { - FLAGS |= OVR|NODIV; /* Overflow and No Divide */ - sac_inh=1; /* Don't touch AC */ + FLAGS |= OVR|NODIV|TRP1; /* Overflow and No Divide */ +#if PDP6 | KA check_apr_irq(); +#endif + sac_inh=1; /* Don't touch AC */ break; /* Done */ } #else @@ -6933,8 +7519,10 @@ left: if ((AD & SMASK) == 0) { FLAGS |= OVR|NODIV|TRP1; /* Overflow and No Divide */ i_flags = 0; - sac_inh=1; +#if PDP6 | KA check_apr_irq(); +#endif + sac_inh=1; break; /* Done */ } @@ -6991,7 +7579,9 @@ left: } else { if (((AD << SC) & ~CMASK) != ((AR << SC) & ~CMASK)) { FLAGS |= OVR|TRP1; +#if PDP6 | KA check_apr_irq(); +#endif } AR = ((AR << SC) & CMASK) | (AR & SMASK); } @@ -7063,7 +7653,9 @@ left: #if !PDP6 if (((AD << SC) & ~CMASK) != ((AR << SC) & ~CMASK)) { FLAGS |= OVR|TRP1; +#if KA check_apr_irq(); +#endif } #endif AR = (AD & SMASK) | ((MQ << (SC - 35)) & CMASK); @@ -7071,7 +7663,9 @@ left: } else { if ((((AD & CMASK) << SC) & ~CMASK) != ((AR << SC) & ~CMASK)) { FLAGS |= OVR|TRP1; +#if PDP6 | KA check_apr_irq(); +#endif } AR = (AD & SMASK) | ((AR << SC) & CMASK) | (MQ >> (35 - SC)); @@ -7162,11 +7756,11 @@ left: } } AB = (AR >> 18) & RMASK; -#if KL +#if KL | KS BYF5 = 1; #endif if (Mem_read(0, 0, 0)) { -#if KL +#if KL | KS BYF5 = 0; #endif #if ITS @@ -7190,7 +7784,7 @@ left: goto last; } AB = (AR & RMASK); -#if KL +#if KL | KS BYF5 = 0; set_reg(AC, AOB(AR)); #endif @@ -7218,6 +7812,9 @@ left: AD = (AR & RMASK) + CM(BR) + 1; AR = AOB(AR); } while ((AD & C1) == 0); +#if KS + set_reg(AC, AR); +#endif break; case 0252: /* AOBJP */ @@ -7249,8 +7846,8 @@ left: break; case 0254: /* JRST */ /* AR Frm PC */ -#if KL -#if KL_ITS +#if KL | KS +#if KL_ITS | KS_ITS if (uuo_cycle | pi_cycle) { if (QITS && one_p_arm) { FLAGS |= ADRFLT; @@ -7273,19 +7870,26 @@ xjrstf: if (Mem_read(0, 0, 0)) goto last; AR = MB; /* Get PC. */ +#if KL if (QKLB && t20_page) { pc_sect = (AR >> 18) & 07777; if (AC != 07 && (FLAGS & USER) == 0 && ((BR >> 23) & USER) == 0) prev_sect = BR & 037; } +#endif BR = BR >> 23; /* Move flags into position */ goto jrstf; case 006: /* XJEN */ case 012: /* JEN */ +#if KL /* Restore interrupt level. */ if ((FLAGS & (USER|USERIO)) == USER || (FLAGS & (USER|PUBLIC)) == PUBLIC) { +#else + /* Restore interrupt level. */ + if ((FLAGS & (USER|USERIO)) == USER) { +#endif goto muuo; } else { pi_restore = 1; @@ -7297,7 +7901,7 @@ xjrstf: case 002: /* JRSTF */ BR = AR >> 23; /* Move into position */ jrstf: -#if KL_ITS +#if KL_ITS | KS_ITS if (QITS) f = FLAGS & (TRP1|TRP2); #endif @@ -7314,15 +7918,14 @@ jrstf: if ((FLAGS & USER) == 0) { FLAGS |= (BR & OVR) ? PRV_PUB : 0; } -#if KL_ITS +#if KL_ITS | KS_ITS if (QITS) FLAGS |= f; #endif - check_apr_irq(); break; case 017: /* Invalid */ -#if KL_ITS +#if KL_ITS | KS_ITS if (QITS) { BR = AR >> 23; /* Move into position */ pi_enable = 1; @@ -7337,19 +7940,25 @@ jrstf: if ((FLAGS & USER) == 0) { MB &= ~SMASK; MB |= (FLAGS & PRV_PUB) ? SMASK : 0; +#if KL if (QKLB && t20_page) MB |= (uint64)(prev_sect & 037); +#endif } if (uuo_cycle | pi_cycle) { FLAGS &= ~(USER|PUBLIC); /* Clear USER */ +#if KL sect = 0; /* Force section zero on IRQ */ +#endif } if (Mem_write(0, 0)) goto last; AB = (AB + 1) & RMASK; +#if KL if (QKLB && t20_page) MB = (((((uint64)pc_sect) << 18) | PC) + !pi_cycle) & (SECTM|RMASK); else +#endif MB = (PC + !pi_cycle) & (RMASK); if (Mem_write(0, 0)) goto last; @@ -7360,9 +7969,11 @@ jrstf: if (Mem_read(0, 0, 0)) goto last; AR = MB; /* Get PC. */ +#if KL if (QKLB && t20_page) { pc_sect = (AR >> 18) & 07777; } +#endif break; case 014: /* SFM */ @@ -7370,8 +7981,10 @@ jrstf: if ((FLAGS & USER) == 0) { MB &= ~SMASK; MB |= (FLAGS & PRV_PUB) ? SMASK : 0; +#if KL if (QKLB && t20_page) MB |= (uint64)(prev_sect & 037); +#endif } (void)Mem_write(0, 0); goto last; @@ -7383,17 +7996,28 @@ jrstf: goto muuo; case 004: /* HALT */ +#if KL + /* Restore interrupt level. */ if ((FLAGS & (USER|USERIO)) == USER || (FLAGS & (USER|PUBLIC)) == PUBLIC) { +#else + /* Restore interrupt level. */ + if ((FLAGS & (USER|USERIO)) == USER) { +#endif goto muuo; } else { reason = STOP_HALT; } break; case 010: /* JEN */ +#if KL /* Restore interrupt level. */ if ((FLAGS & (USER|USERIO)) == USER || (FLAGS & (USER|PUBLIC)) == PUBLIC) { +#else + /* Restore interrupt level. */ + if ((FLAGS & (USER|USERIO)) == USER) { +#endif goto muuo; } else { pi_restore = 1; @@ -7406,8 +8030,10 @@ jrstf: } #endif PC = AR & RMASK; +#if KL if (QKLB && t20_page && glb_sect) pc_sect = (AR >> 18) & 07777; +#endif #else if (uuo_cycle | pi_cycle) { FLAGS &= ~USER; /* Clear USER */ @@ -7511,7 +8137,7 @@ jrstf: if (QBBN && (FLAGS & USER) == 0) xct_flag = AC; #endif -#if KI | KL +#if KI | KL | KS if ((FLAGS & USER) == 0) xct_flag = AC; #endif @@ -7525,7 +8151,7 @@ jrstf: one_p_arm = 0; } #endif -#if KL_ITS +#if KL_ITS | KS_ITS if (QITS && one_p_arm) { FLAGS |= ADRFLT; one_p_arm = 0; @@ -7534,11 +8160,11 @@ jrstf: break; case 0257: /* MAP */ -#if KI | KL +#if KI | KL | KS f = AB >> 9; flag1 = (FLAGS & USER) != 0; flag3 = 0; -#if KL +#if KL /* Invalid in user unless USERIO set, or not in supervisor mode */ if ((FLAGS & (USER|USERIO)) == USER || (FLAGS & (USER|PUBLIC)) == PUBLIC) goto muuo; @@ -7548,7 +8174,8 @@ jrstf: flag1 = (FLAGS & USERIO) != 0; sect = prev_sect; } - +#endif +#if KL | KS /* Check if Paging Enabled */ if (!page_enable) { AR = AB; /* direct map */ @@ -7560,6 +8187,7 @@ jrstf: } /* Check if access to register */ +#if KL if (AB < 020 && ((QKLB && (glb_sect == 0 || sect == 0 || (glb_sect && sect == 1))) || !QKLB)) { AR = AB; /* direct map */ @@ -7569,6 +8197,7 @@ jrstf: set_reg(AC, AR); break; } +#endif /* Handle KI paging odditiy */ if (!flag1 && !t20_page && (f & 0740) == 0340) { @@ -7589,12 +8218,18 @@ jrstf: BR = AR; /* Remap the flag bits */ if (BR & KL_PAG_A) { /* A */ +#if KL AR = ((AR & 017777LL) << 9) + (AB & 0777); +#else + AR = ((AR & 003777LL) << 9) + (AB & 0777); +#endif if (flag1) /* U */ AR |= SMASK; /* BIT0 */ AR |= BIT2; /* BIT2 */ +#if KL if (BR & KL_PAG_P) /* P */ AR |= BIT6; /* BIT6 */ +#endif if (BR & KL_PAG_W) /* W */ AR |= BIT3; /* BIT3 */ if (BR & KL_PAG_S) /* S */ @@ -7602,7 +8237,11 @@ jrstf: if (BR & KL_PAG_C) /* C */ AR |= BIT7; /* BIT7 */ } else +#if KS + AR = AB; +#else AR = (f & 01740) ? 0 : 0377777LL; +#endif AR |= BIT8; #else /* Check if Paging Enabled */ @@ -7673,7 +8312,7 @@ jrstf: AR = AOB(AR); FLAGS &= ~ (BYTI|ADRFLT|TRP1|TRP2); if (AR & C1) { -#if KI | KL +#if KI | KL | KS if (!pi_cycle) FLAGS |= TRP2; #else @@ -7725,7 +8364,7 @@ jrstf: #endif AR = AOB(AR); if (AR & C1) { -#if KI | KL +#if KI | KL | KS if (!pi_cycle) FLAGS |= TRP2; #else @@ -7804,13 +8443,13 @@ jrstf: } } #endif -#if PDP6 | KL +#if PDP6 | KL | KS /* This has to before the check for KL10 B extended check */ AR = SOB(AR); set_reg(AC, AR & FMASK); #endif if ((AR & C1) == 0) { -#if KI | KL +#if KI | KL | KS if (!pi_cycle) FLAGS |= TRP2; #else @@ -7863,7 +8502,7 @@ jrstf: } #endif if ((AR & C1) == 0) { -#if KI | KL +#if KI | KL | KS if (!pi_cycle) FLAGS |= TRP2; #else @@ -8012,9 +8651,12 @@ jrstf: flag3 = 1; } if (flag1 != flag3) { - if (!pi_cycle) + if (!pi_cycle) { FLAGS |= OVR|TRP1; - check_apr_irq(); +#if PDP6 | KA + check_apr_irq(); +#endif + } } break; @@ -8034,9 +8676,12 @@ jrstf: flag3 = 1; } if (flag1 != flag3) { - if (!pi_cycle) + if (!pi_cycle) { FLAGS |= OVR|TRP1; - check_apr_irq(); +#if PDP6 | KA + check_apr_irq(); +#endif + } } break; @@ -8132,7 +8777,9 @@ jrstf: } if (flag1 != flag3 && !pi_cycle) { FLAGS |= OVR|TRP1; +#if PDP6 | KA check_apr_irq(); +#endif } f = ((AD & SMASK) != 0); jump_op: @@ -8183,7 +8830,9 @@ jump_op: } if (flag1 != flag3 && !pi_cycle) { FLAGS |= OVR|TRP1; +#if PDP6 | KA check_apr_irq(); +#endif } f = ((AD & SMASK) != 0); skip_op: @@ -8546,41 +9195,743 @@ test_op: /* User and not User I/O */ goto muuo; } else { +#if KS + int ctl = (int)((AR >> 18) & 017); + double us; + AR &= RMASK; + + switch (IR & 077) { + case 000: /* APR0 */ + switch (AC) { + /* 7000 */ + case 000: /* APRID */ + /* APRID */ + MB = SMASK | BIT4 | BIT5 | (270LL << 18); /* MC level 270 */ + /* Bit 0 Inhibit CST Update available */ + /* Bit 1 No CST at all */ + /* Bit 2 Exotic microcode */ + /* Bit 3 UBABLT Instructions present */ + /* Bit 4 KI style paging */ + /* Bit 5 for TOPS-20 paging */ +#if KS_ITS + if (QITS) + MB |= 00020000000000LL; +#endif + MB |= (uint64)((apr_serial == -1) ? DEF_SERIAL : apr_serial); + sim_debug(DEBUG_DATAIO, &cpu_dev, "APRID %012llo\n", MB); + if (Mem_write(0, 0)) + goto last; + break; + + /* 70020 */ + case 004: /* WRAPR */ + /* Set trap conditions */ + /* Bit 20 100000 Enable interrupts */ + /* Bit 21 040000 Disable interrupts */ + /* Bit 22 020000 Clear pending */ + /* Bit 23 010000 Set irq */ + /* Bit 24 004000 Flag 24 */ + /* Bit 25 002000 Wake up front end */ + /* Bit 26 001000 Power fail interrupt */ + /* Bit 27 000400 NXM */ + /* Bit 28 000200 Hard memory error */ + /* Bit 29 000100 Soft memory error */ + /* Bit 30 000040 Timer interrupt */ + /* Bit 31 000020 Interrupt from Front end */ + /* Bit 32 000010 Generate interrupt request */ + /* 000007 PIA */ + apr_irq = AR & 07; + clr_interrupt(0); + if (AR & 0100000) { /* Enable interrupts */ + irq_enable |= 07760 & AR; + } + if (AR & 0040000) { /* Disable interrupts */ + irq_enable &= ~(07760 & AR); + } + if (AR & 0020000) { /* Clear interrupt */ + irq_flags &= ~(05760 & AR); + } + if (AR & 0010000) { /* Set interrupt */ + irq_flags |= (05760 & AR); + if (AR & 02000) + cty_wakeup(); + } + check_apr_irq(); + sim_debug(DEBUG_CONO, &cpu_dev, "WRAPR %012llo\n", AR); + break; + + /* 70024 */ + case 005: /* RDAPR */ + /* Read trap conditions */ + MB = irq_flags | apr_irq; + MB |= ((uint64)irq_enable) << 18; + if (irq_flags & irq_enable) + MB |= 010; + if (Mem_write(0, 0)) + goto last; + sim_debug(DEBUG_CONI, &cpu_dev, "RDAPR %012llo\n", MB); + break; + + /* 70030 */ + case 006: /* CONSZ APR */ + /* Read trap conditions */ + AR = irq_flags | apr_irq; + AR |= ((uint64)irq_enable) << 18; + if (irq_flags & irq_enable) + AR |= 010; + AR &= AB; + if (AR == 0) + PC = (PC + 1) & RMASK; + sim_debug(DEBUG_CONI, &cpu_dev, "CONSZ %012llo\n", AR); + break; + + /* 70034 */ + case 007: /* CONSO APR */ + /* Read trap conditions */ + AR = irq_flags | apr_irq; + AR |= ((uint64)irq_enable) << 18; + if (irq_flags & irq_enable) + AR |= 010; + AR &= AB; + if (AR != 0) + PC = (PC + 1) & RMASK; + sim_debug(DEBUG_CONI, &cpu_dev, "CONSO %012llo\n", AR); + break; + + /* 70060 */ + case 014: /* WRPI */ + /* Set PI flags */ + if (AR & 010000) { /* Bit 23 */ + PIR = PIH = PIE = 0; + pi_enable = 0; + parity_irq = 0; + } + if (AR & 0200) { /* Bit 28 */ + pi_enable = 1; + } + if (AR & 0400) /* Bit 27 */ + pi_enable = 0; + if (AR & 01000) { /* Bit 26 */ + PIE &= ~(AR & 0177); + } + if (AR & 02000) /* Bit 25 */ + PIE |= (AR & 0177); + if (AR & 04000) { /* Bit 24 */ + PIR |= (AR & 0177); + pi_pending = 1; + } + if (AR & 020000) { /* Bit 22 */ + PIR &= ~(AR & 0177); + } + check_apr_irq(); + sim_debug(DEBUG_CONO, &cpu_dev, "WRPI %012llo\n", AR); + break; + + /* 70064 */ + case 015: /* RDPI */ + MB = PIE; + MB |= (pi_enable << 7); + MB |= (PIH << 8); + MB |= ((uint64)(PIR) << 18); + MB |= (parity_irq << 15); + sim_debug(DEBUG_CONI, &cpu_dev, "RDPI %012llo\n", MB); + if (Mem_write(0, 0)) + goto last; + break; + + /* 70070 */ + case 016: /* CONSZ PI */ + /* Read PI conditions */ + AR = PIE; + AR |= (pi_enable << 7); + AR |= (PIH << 8); + AR &= AB; + if (AR == 0) + PC = (PC + 1) & RMASK; + sim_debug(DEBUG_CONI, &cpu_dev, "CONSZ PI %012llo\n", AR); + break; + + /* 70074 */ + case 017: /* CONSO PI */ + /* Read PI conditions */ + AR = PIE; + AR |= (pi_enable << 7); + AR |= (PIH << 8); + AR &= AB; + if (AR != 0) + PC = (PC + 1) & RMASK; + sim_debug(DEBUG_CONI, &cpu_dev, "CONSO PI %012llo\n", AR); + break; + + default: + goto muuo; + } + break; + + case 001: /* APR1 */ + switch (AC) { + case 000: /* CLRSCH */ + break; + + /* 70104 */ + case 001: /* RDUBR */ + MB = (ub_ptr >> 9); + /* Set previous section */ + MB |= ((uint64)(prev_ctx & 0160)) << 20; + MB |= ((uint64)(fm_sel & 0160)) << 23; + MB |= SMASK|BIT2; + sim_debug(DEBUG_DATAIO, &cpu_dev, "RDUBR %012llo\n", MB); + if (Mem_write(0, 0)) + goto last; + break; + + /* 70110 */ + case 002: /* CLRPT */ + f = (RMASK & AB) >> 9; + + /* Map the page */ + u_tlb[f] = 0; + e_tlb[f] = 0; + /* If not user do exec mappping */ + if (!t20_page && (f & 0740) == 0340) { + /* Pages 340-377 via UBT */ + f += 01000 - 0340; + u_tlb[f] = 0; + } + break; + + /* 70114 */ + case 003: /* WRUBR */ + if (Mem_read(0, 0, 0)) + goto last; + if (MB & SMASK) { + fm_sel = (uint8)(MB >> 23) & 0160; + prev_ctx = (uint8)(MB >> 20) & 0160; + } + if (MB & BIT2) { + ub_ptr = (MB & 03777) << 9; + for (f = 0; f < 512; f++) { + u_tlb[f] = 0; + e_tlb[f] = 0; + } + for (;f < 546; f++) + u_tlb[f] = 0; + } + sim_debug(DEBUG_DATAIO, &cpu_dev, + "WRUBR %012llo ebr=%06o ubr=%06o\n", + MB, eb_ptr, ub_ptr); + break; + + /* 70120 */ + case 004: /* WREBR */ + eb_ptr = (AR & 03777) << 9; + for (f = 0; f < 512; f++) { + e_tlb[f] = 0; + u_tlb[f] = 0; + } + for (;f < 546; f++) + u_tlb[f] = 0; + page_enable = (AR & 020000) != 0; + t20_page = (AR & 040000) != 0; + page_fault = 0; + sim_debug(DEBUG_CONO, &cpu_dev, "WREBR %012llo\n", AR); + break; + + /* 70124 */ + case 005: /* RDEBR */ + MB = (eb_ptr >> 9); + if (page_enable) + MB |= 020000; + if (t20_page) + MB |= 040000; + sim_debug(DEBUG_CONI, &cpu_dev, "RDEBR %012llo\n", MB); + if (Mem_write(0, 0)) + goto last; + break; + + default: + goto muuo; + } + break; + + case 002: /* APR2 */ + switch (AC) { + /* 70200 */ + case 000: /* RDSPB */ /* ITS SDBR1 */ + sim_debug(DEBUG_CONI, &cpu_dev, "RDSPD %012llo\n", spt); + MB = spt; + if (Mem_write(0, 0)) + goto last; + break; + + /* 70204 */ + case 001: /* RDCSB */ /* ITS SDBR2 */ + sim_debug(DEBUG_CONI, &cpu_dev, "RDSPD %012llo\n", cst); + MB = cst; + if (Mem_write(0, 0)) + goto last; + break; + + /* 70250 */ + case 002: /* RDPUR */ /* ITS SDBR3 */ + sim_debug(DEBUG_CONI, &cpu_dev, "RDSPD %012llo\n", cst_dat); + MB = cst_dat; + if (Mem_write(0, 0)) + goto last; + break; + + /* 70214 */ + case 003: /* RDCSTM */ /* ITS SDBR4 */ + sim_debug(DEBUG_CONI, &cpu_dev, "RDSPD %012llo\n", cst_msk); + MB = cst_msk; + if (Mem_write(0, 0)) + goto last; + break; + + /* 70220 */ + case 004: /* RDTIME */ + us = sim_activate_time_usecs (&cpu_unit[0]); + f = 10000 - ((int)us); + MB = tim_low | (f << 2); + sim_debug(DEBUG_CONI, &cpu_dev, "RDTIME %012llo %012llo\n", MB, tim_high); + if (Mem_write(0, 0)) + goto last; + AB = (AB + 1) & RMASK; + MB = tim_high; + if (Mem_write(0, 0)) + goto last; + break; + + /* 70224 */ + case 005: /* RDINT */ + MB = int_val; + sim_debug(DEBUG_CONI, &cpu_dev, "RDINT %012llo\n", MB); + if (Mem_write(0, 0)) + goto last; + break; + + /* 70230 */ + case 006: /* RDHSB */ + + /* 70234 */ + case 007: /* ITS SPM */ + if (QITS) { + MB = dbr1; + if (Mem_write(0, 0)) + goto last; + AB = (AB + 1) & RMASK; + MB = dbr2; + if (Mem_write(0, 0)) + goto last; + AB = (AB + 1) & RMASK; + } + break; + + /* 70240 */ + case 010: /* WRSPB */ /* ITS LDBR1 */ + if (Mem_read(0, 0, 0)) + goto last; + spt = MB; + sim_debug(DEBUG_CONI, &cpu_dev, "WRSPD %012llo\n", spt); + break; + + /* 70244 */ + case 011: /* WRCSB */ /* ITS LDBR2 */ + if (Mem_read(0, 0, 0)) + goto last; + cst = MB; + sim_debug(DEBUG_CONI, &cpu_dev, "WRSPD %012llo\n", cst); + break; + + /* 70250 */ + case 012: /* WRPUR */ /* ITS LDBR3 */ + if (Mem_read(0, 0, 0)) + goto last; + cst_dat = MB; + sim_debug(DEBUG_CONI, &cpu_dev, "WRSPD %012llo\n", cst_dat); + break; + + /* 70254 */ + case 013: /* WRCSTM */ /* ITS LDBR4 */ + if (Mem_read(0, 0, 0)) + goto last; + cst_msk = MB; + sim_debug(DEBUG_CONI, &cpu_dev, "WRSPD %012llo\n", cst_msk); + break; + + /* 70264 */ + case 015: /* WRINT */ + if (Mem_read(0, 0, 0)) + goto last; + int_val = MB & ~07777; + sim_debug(DEBUG_DATAIO, &cpu_dev, "WRINT %012llo\n", int_val); + break; + + /* 70260 */ + case 014: /* WRTIME */ + if (Mem_read(0, 0, 0)) + goto last; + tim_low = MB & ~07777; + sim_debug(DEBUG_CONI, &cpu_dev, "RDTIME %012llo %012llo\n", MB, tim_high); + AB = (AB + 1) & RMASK; + if (Mem_read(0, 0, 0)) + goto last; + tim_high = MB; + break; + /* 70270 */ + case 016: /* WRHSB */ + break; + + /* 70274 */ + case 017: /* ITS LPMR */ +#if KS_ITS + if (QITS) { + if (Mem_read(0, 0, 0)) + goto last; + dbr1 = MB; + AB = (AB + 1) & RMASK; + if (Mem_read(0, 0, 0)) + goto last; + dbr2 = MB; + AB = (AB + 1) & RMASK; + } +#endif + break; + default: + goto muuo; + } + break; + + case 004: /* UMOVE */ + xct_flag = 4; + if (Mem_read(pi_cycle, 0, 0)) + goto last; + set_reg(AC, MB); + xct_flag = 0; + break; + + case 005: /* UMOVEM */ + MB = get_reg(AC); + xct_flag = 4; + if (Mem_write(pi_cycle, 0)) + goto last; + xct_flag = 0; + break; + + case 010: /* TIOE */ +#if KS_ITS + if (QITS) { + ctl = 3; + goto its_rd; + } +#endif + BR = get_reg(AC); + if (uba_read(AR, ctl, &MB, WORD)) { +io_fault: + fault_data = (020LL << 30) | BIT8 | BIT10 | AR; + fault_data |= (uint64)((020 & IR) << 18); + page_fault = 1; + goto last; + } + if ((BR & MB) == 0) + PC = (PC + 1) & RMASK; + break; + + case 011: /* TION */ +#if KS_ITS + if (QITS) { + ctl = 1; + goto its_rd; + } +#endif + BR = get_reg(AC); + if (uba_read(AR, ctl, &MB, WORD)) + goto io_fault; + if ((BR & MB) != 0) + PC = (PC + 1) & RMASK; + break; + + case 012: /* RDIO */ +#if KS_ITS +its_rd: +#endif + if (uba_read(AR, ctl, &AR, WORD)) + goto io_fault; + i_flags = SAC; + break; + + case 013: /* WRIO */ +#if KS_ITS +its_wr: +#endif + MB = get_reg(AC); + if (uba_write(AR, ctl, MB, WORD)) + goto io_fault; + break; + + case 014: /* BSIO */ +#if KS_ITS + if (QITS) { + ctl = 3; + goto its_wr; + } +#endif + BR = get_reg(AC); + if (uba_read(AR, ctl, &MB, WORD)) + goto io_fault; + MB |= BR; + if (uba_write(AR, ctl, MB, WORD)) + goto io_fault; + break; + + case 015: /* BCIO */ +#if KS_ITS + if (QITS) { + ctl = 1; + goto its_wr; + } +#endif + BR = get_reg(AC); + if (uba_read(AR, ctl, &MB, WORD)) + goto io_fault; + MB &= ~BR; + if (uba_write(AR, ctl, MB, WORD)) + goto io_fault; + break; + + case 020: /* TIOEB */ + BR = get_reg(AC); + if (uba_read(AR, ctl, &MB, BYTE)) + goto io_fault; + if ((BR & MB) == 0) + PC = (PC + 1) & RMASK; + break; + + case 021: /* TIONB */ + BR = get_reg(AC); + if (uba_read(AR, ctl, &MB, BYTE)) + goto io_fault; + if ((BR & MB) != 0) + PC = (PC + 1) & RMASK; + break; + + case 022: /* RDIOB */ + if (uba_read(AR, ctl, &AR, BYTE)) + goto io_fault; + i_flags = SAC; + break; + + case 023: /* WRIOB */ + MB = get_reg(AC); + if (uba_write(AR, ctl, MB, BYTE)) + goto io_fault; + break; + + case 024: /* BSIOB */ + BR = get_reg(AC); + if (uba_read(AR, ctl, &MB, BYTE)) + goto io_fault; + MB |= BR; + if (uba_write(AR, ctl, MB, BYTE)) + goto io_fault; + break; + + case 025: /* BCIOB */ + BR = get_reg(AC); + if (uba_read(AR, ctl, &MB, BYTE)) + goto io_fault; + MB &= ~BR; + if (uba_write(AR, ctl, MB, BYTE)) + goto io_fault; + break; + + default: + goto muuo; + } +#else int d = ((IR & 077) << 1) | ((AC & 010) != 0); #if KL if (d == 3) { - irq_flags |= 020; + irq_flags |= SWP_DONE; goto last; } #endif fetch_opr: switch(AC & 07) { case 0: /* 00 BLKI */ - case 2: /* 10 BLKO */ #if KL - /* For KL10 special devices treat like DATAI/DATAO */ + /* For KL10 special devices */ if (d <= 05) { - if (AC & 02) { - if (d == 1 || d == 4) { - if (Mem_read(pi_cycle, 0, 0)) - goto last; - AR = MB; - } - dev_tab[d](040|DATAO|(d<<2), &AR); - } else { - dev_tab[d](040|DATAI|(d<<2), &AR); + double us; + switch (d) { + case 0: /* APR */ + /* BLKI APRID */ + AR = SMASK| (500LL << 18); /* MC level 500 */ + /* Bit 0 for TOPS-20 paging */ + /* Bit 1 for extended addressing */ + /* Bit 2 Exotic microcode */ + /* Bit 3 KL10B */ + /* Bit 4 PMOVE/PMOVEM or ITS Style Paging */ + /* Bit 5 Tops-20 R5 microcode */ +#if KL_ITS + if (QITS) + AR |= BIT4; +#endif + /* Bit 18 50hz */ + /* Bit 19 Cache */ + /* Bit 20 Channel? */ + /* Bit 21 Extended KL10 */ + /* Bit 22 Master Osc */ + if (QKLB) + AR |= BIT1|BIT4|040000; + AR |= (uint64)((apr_serial == -1) ? DEF_SERIAL : apr_serial); + sim_debug(DEBUG_DATAIO, &cpu_dev, "APRID BLKI %012llo\n", MB); MB = AR; if (Mem_write(pi_cycle, 0)) goto last; - if (d == 4 || d == 5) { - AB = (AB + 1) & RMASK; - MB = BR; - if (Mem_write(pi_cycle, 0)) - goto last; + break; + + case 1: /* PI */ + /* BLKI RDERA */ + case 2: /* PAG */ + case 3: /* CCA */ + break; + + case 4: /* TIM */ + /* BLKI RDPERF */ + /* Read process execution time */ + us = sim_activate_time_usecs (&cpu_unit[0]); + f = rtc_tim - ((int)us); + update_times(f); + rtc_tim = ((int)us); + if (page_enable) { + AR = (M[ub_ptr + 0505]); + BR = M[ub_ptr + 0504]; + } else { + AR = 0 << 12; + BR = f; } + sim_debug(DEBUG_DATAIO, &cpu_dev, "RDPERF %012llo %012llo\n", AR, BR); + MB = AR; + if (Mem_write(pi_cycle, 0)) + goto last; + AB = (AB + 1) & RMASK; + MB = BR; + if (Mem_write(pi_cycle, 0)) + goto last; + break; + case 5: /* MTR */ + /* BLKI RDMACT */ + /* RDMACT */ + /* Read memory accounting */ + if (page_enable) { + AR = M[ub_ptr + 0507]; + BR = (M[ub_ptr + 0506] & CMASK); + } else { + AR = 0 << 12; + BR = 0; + } + sim_debug(DEBUG_DATAIO, &cpu_dev, "RDMACT %012llo %012llo\n", AR, BR); + MB = AR; + if (Mem_write(pi_cycle, 0)) + goto last; + AB = (AB + 1) & RMASK; + MB = BR; + if (Mem_write(pi_cycle, 0)) + goto last; + MB = AR; + break; } break; } + /* Fall through */ +#endif + + case 2: /* 10 BLKO */ + +#if KL + /* For special KL devices */ + if (d <= 05) { + int ctl; + int fcn; + int page; + + switch (d) { + case 0: /* APR */ + /* BLKO WRFIL */ + break; + + case 1: /* PI */ + /* BLKO SBDIAG */ + if (Mem_read(pi_cycle, 0, 0)) + goto last; + AB = (AB + 1) & RMASK; + ctl = MB >> 31; + fcn = MB & 037; + if (ctl >= 010 && ctl < 030) { + int mc = MEMSIZE / (512 * 1024); + int c = (ctl - 010); + int s = 0; + if (c < mc) { + switch(fcn) { + case 0: MB = 06000000000LL; break; + case 1: MB = 00500000000LL; break; + case 2: switch ((MB >> 21) & 077) { + case 000: /* yyyyWWWW */ + case 001: /* ww###### */ + case 002: /* #####ppA */ + MB = (ctl << 3) + 06; + break; + case 003: /* bNNSSmmm */ + MB = 0; + break; + } + break; + case 012: + s = ((int)(0176000 & MB)) / 8192; + MB = 0; + if (s > mc || c != s) + MB = 010000000LL; + break; + default: MB = 0; break; + } + } else { + MB = 0; + } + if (Mem_write(pi_cycle, 0)) + goto last; + } + break; + + case 2: /* PAG */ + /* BLKO CLRPT */ + page = (RMASK & AB) >> 9; + + page &= ~7; + /* Map the page */ + for(f = 0; f < 8; f++) { + u_tlb[page+f] = 0; + e_tlb[page+f] = 0; + } + /* If not user do exec mappping */ + if (!t20_page && (page & 0740) == 0340) { + /* Pages 340-377 via UBT */ + page += 01000 - 0340; + for(f = 0; f < 8; f++) + u_tlb[page+f] = 0; + } + break; + + case 3: /* CCA */ + /* BLKO SWPVA */ + case 4: /* TIM */ + /* BLKO WRPAE */ + case 5: /* MTR */ + break; + } + break; + } + #endif if (Mem_read(pi_cycle, 0, 0)) goto last; @@ -8603,18 +9954,61 @@ fetch_opr: goto fetch_opr; case 1: /* 04 DATAI */ - dev_tab[d](DATAI|(d<<2), &AR); - MB = AR; - if (Mem_write(pi_cycle, 0)) - goto last; #if KL - if (d == 4 || d == 5) { /* DATAI TIM, MTR is two words */ + /* For KL10 special devices */ + if (d == 4) { /* DATAI TIM is two words */ + /* DATAI RDTIME */ + double us = sim_activate_time_usecs (&cpu_unit[0]); + f = rtc_tim - ((int)us); + update_times(f); + rtc_tim = ((int)us); + if (page_enable) { + AR = (M[eb_ptr + 0510]); + BR = M[eb_ptr + 0511]; + } else { + AR = 0; + BR = f << 12; + } + sim_debug(DEBUG_DATAIO, &cpu_dev, "RDTIM %012llo, %012llo\n", AR, BR); + MB = AR; + if (Mem_write(pi_cycle, 0)) + goto last; AB = (AB + 1) & RMASK; MB = BR; if (Mem_write(pi_cycle, 0)) goto last; + break; + } + if (d == 5) { /* DATAI MTR is two words */ + /* RDEACT */ + /* Read executive accounting */ + double us = sim_activate_time_usecs (&cpu_unit[0]); + f = rtc_tim - ((int)us); + update_times(f); + rtc_tim = ((int)us); + if (page_enable) { + AR = M[ub_ptr + 0505]; + BR = (M[ub_ptr + 0504] & CMASK); + } else { + AR = 0; + BR = f << 12; + } + sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAI MTR %012llo %012llo\n", AR, BR); + MB = AR; + if (Mem_write(pi_cycle, 0)) + goto last; + AB = (AB + 1) & RMASK; + MB = BR; + if (Mem_write(pi_cycle, 0)) + goto last; + break; } #endif + + dev_tab[d](DATAI|(d<<2), &AR); + MB = AR; + if (Mem_write(pi_cycle, 0)) + goto last; break; case 3: /* 14 DATAO */ if (Mem_read(pi_cycle, 0, 0)) @@ -8644,10 +10038,12 @@ fetch_opr: PC = (PC + 1) & RMASK; break; } - } - break; +#endif + } + break; } + AR &= FMASK; if (!sac_inh && (i_flags & (SCE|FCEPSE))) { MB = AR; @@ -8677,6 +10073,63 @@ last: goto fetch; } #endif +#if KS + /* Handle page fault and traps */ + if (page_enable && page_fault) { + if (hst_lnt) { + hst_p = hst_p + 1; + if (hst_p >= hst_lnt) { + hst_p = 0; + } + } + page_fault = 0; + BYF5 = 0; +#if KS_ITS + if (QITS) { + AB = eb_ptr | 0500; + FM[(6<<4)|0] = fault_data; + } else +#endif + AB = ub_ptr | 0500; + MB = fault_data; + Mem_write_nopage(); + AB++; + /* If fault on trap, kill the pi_cycle flag */ + if (trap_flag) + pi_cycle = 0; + FLAGS |= trap_flag & (TRP1|TRP2); + trap_flag = (TRP1|TRP2); + MB = (((uint64)(FLAGS) << 23) & LMASK); + Mem_write_nopage(); + AB++; + MB = (PC & RMASK); + Mem_write_nopage(); + AB++; + flag1 = flag3 = 0; + if (FLAGS & USER) + flag1 = 1; + Mem_read_nopage(); + if (t20_page) + FLAGS = 0; + else + FLAGS = (MB >> 23) & 017777; + /* If transistioning from user to executive adjust flags */ + if ((FLAGS & USER) == 0) { + if (flag1) + FLAGS |= USERIO; + } + PC = MB & RMASK; + xct_flag = 0; + f_load_pc = 1; + f_pc_inh = 1; + if (pi_cycle) { + pi_cycle = 0; + irq_flags |= 01000; + FM[(7 << 4) | 2] = fault_data; + pi_enable = 0; + } + } +#endif #if KL /* Handle page fault and traps */ if (page_enable && page_fault) { @@ -8749,7 +10202,7 @@ last: pi_cycle = 0; irq_flags |= 01000; FM[(7 << 4) | 2] = fault_data; - pi_enable = 0; + pi_enable = 0; } } #endif @@ -8773,7 +10226,7 @@ last: } #endif -#if KI | KL +#if KI | KL | KS if (!f_pc_inh && (trap_flag == 0) && !pi_cycle) { FLAGS &= ~ADRFLT; #else @@ -8787,12 +10240,13 @@ last: fault_data |= 02000; mem_prot = 1; one_p_arm = 0; + check_apr_irq(); } #endif /* Dismiss an interrupt */ if (pi_cycle) { -#if KI | KL +#if KI | KL | KS if (trap_flag != 0) { pi_hold = pi_ov = 0; f_pc_inh = 0; @@ -8811,6 +10265,8 @@ last: #endif #if KI | KL Mem_read_nopage(); +#elif KS + Mem_read_word(AB, &MB, 1); #else Mem_read(1, 0, 1); #endif @@ -8829,12 +10285,14 @@ last: pi_hold = 0; #if KI | KL Mem_read_nopage(); +#elif KS + Mem_read_word(AB, &MB, 1); #else Mem_read(1, 0, 1); #endif goto no_fetch; } else { -#if KI | KL +#if KI | KL | KS if (f_pc_inh && trap_flag == 0) set_pi_hold(); /* Hold off all lower interrupts */ #else @@ -8874,7 +10332,7 @@ if (QITS) return reason; } -#if KL +#if KL | KS /* Handle indirection for extended byte instructions */ int @@ -8897,6 +10355,7 @@ do_byte_setup(int n, int wr, int *pos, int *sz) p = (val1 >> 30) & 077; np = (p + (0777 ^ s) + 1) & 0777; /* Advance pointer */ +#if KL if (QKLB && t20_page && pc_sect != 0) { if (p > 36) { /* Extended pointer */ int i = p - 37; @@ -8953,6 +10412,7 @@ do_byte_setup(int n, int wr, int *pos, int *sz) glb_sect = 0; } } else { +#endif if (np & 0400) { np = p = ((0777 ^ s) + 044 + 1) & 0777; val1 = (val1 & LMASK) | ((val1 + 1) & RMASK); @@ -8960,15 +10420,18 @@ do_byte_setup(int n, int wr, int *pos, int *sz) ix = GET_XR(val1); ind = TST_IND(val1) != 0; MB = (val1 & RMASK) | ((val1 & RSIGN)? LMASK:0); +#if KL sect = cur_sect; glb_sect = 0; } +#endif *pos = np & 077; AB = MB & RMASK; if (ix) { temp = get_reg(ix); /* Check if extended indexing */ +#if KL if (QKLB && t20_page && glb_sect != 0 && (temp & SMASK) == 0 && (temp & SECTM) != 0) { temp = (temp + MB) & (SECTM|RMASK); sect = (temp >> 18) & 07777; @@ -8976,13 +10439,15 @@ do_byte_setup(int n, int wr, int *pos, int *sz) glb_sect = 1; } else glb_sect = 0; +#endif temp = MB = (MB + temp) & FMASK; AB = MB & RMASK; } - while (ind & !check_irq_level()) { + while (ind && pi_pending && !check_irq_level()) { if (Mem_read(0, 1, 0)) { return 1; } +#if KL /* Check if extended indexing */ if (QKLB && sect != 0) { if (MB & SMASK) { /* Instruction format IFIW */ @@ -9029,11 +10494,13 @@ do_byte_setup(int n, int wr, int *pos, int *sz) glb_sect = 1; } } else { +#endif ix = GET_XR(MB); ind = TST_IND(MB) != 0; AB = MB & RMASK; if (ix) { temp = get_reg(ix); +#if KL /* Check if extended indexing */ if (QKLB && sect != 0 && (temp & SMASK) == 0 && (temp & SECTM) != 0) { temp = (temp + ((AB & RSIGN) ? @@ -9044,10 +10511,13 @@ do_byte_setup(int n, int wr, int *pos, int *sz) AB = 0; } else glb_sect = 0; +#endif temp = MB = (MB + temp) & FMASK; AB = MB & RMASK; } +#if KL } +#endif }; /* Update pointer */ val1 &= PMASK; @@ -9178,6 +10648,7 @@ adj_byte(int n) p = (val1 >> 30) & 077; /* Advance pointer */ np = (p + (0777 ^ s) + 1) & 0777; +#if KL if (QKLB && t20_page && pc_sect != 0) { if (p > 36) { /* Extended pointer */ int i = p - 37; @@ -9197,9 +10668,12 @@ adj_byte(int n) val1 = (val1 & LMASK) | ((val1 + 1) & RMASK); } } else { +#endif if (np & 0400) val1 = (val1 & LMASK) | ((val1 + 1) & RMASK); +#if KL } +#endif if ((np & 0400) == 0) return; /* Update pointer */ @@ -9235,6 +10709,7 @@ adv_byte(int n) p = (val1 >> 30) & 077; /* Advance pointer */ np = (p + (0777 ^ s) + 1) & 0777; +#if KL if (QKLB && t20_page && pc_sect != 0) { if (p > 36) { /* Extended pointer */ int i = p - 37; @@ -9259,11 +10734,14 @@ adv_byte(int n) } } } else { +#endif if (np & 0400) { np = ((0777 ^ s) + 044 + 1) & 0777; val1 = (val1 & LMASK) | ((val1 + 1) & RMASK); } +#if KL } +#endif np &= 077; /* Update pointer */ val1 &= PMASK; @@ -9452,10 +10930,12 @@ do_extend(uint32 ia) case 004: /* EDIT */ val2 = MB; /* Save address of translate table */ +#if KL if (QKLB && pc_sect != 0 && glb_sect) xlat_sect = (val2 >> 18) & 07777; else xlat_sect = cur_sect; +#endif /* Fetch filler values */ AB = (ia + 1) & RMASK; if (Mem_read(0, 1, 0)) @@ -9473,6 +10953,7 @@ do_extend(uint32 ia) /* Read in pattern control */ reg = get_reg(ext_ac); AB = reg & RMASK; +#if KL if (QKLB && pc_sect != 0) { sect = (reg >> 18) & 07777; glb_sect = 1; @@ -9480,6 +10961,7 @@ do_extend(uint32 ia) sect = cur_sect; glb_sect = 0; } +#endif if (Mem_read(0, 0, 0)) return 0; i = (reg >> 30) & 03; @@ -9487,9 +10969,11 @@ do_extend(uint32 ia) val1 = (MB >> ((3 - i) * 9)) & 0777; i++; if (i > 3) { +#if KL if (QKLB && pc_sect != 0) reg = (reg & ~(SECTM|RMASK)) | ((reg + 1) & (SECTM|RMASK)); else +#endif reg = (reg & LMASK) | ((reg+1) & RMASK); i = 0; } @@ -9507,7 +10991,9 @@ do_extend(uint32 ia) return 0; a = 1; AB = (val2 + (val1 >> 1)) & RMASK; +#if KL sect = xlat_sect; +#endif if (Mem_read(0, 0, 0)) return 0; if ((val1 & 1) == 0) @@ -9538,6 +11024,7 @@ do_extend(uint32 ia) adj_byte(ext_ac+3); reg |= SMASK; AR = get_reg(ext_ac+3); +#if KL if (QKLB && pc_sect != 0) { sect = (AR >> 18) & 07777; glb_sect = 1; @@ -9545,10 +11032,12 @@ do_extend(uint32 ia) sect = cur_sect; glb_sect = 0; } +#endif AB = AR & RMASK; MB = get_reg(ext_ac+4); if (Mem_write(0, 0)) return 0; +#if KL if (QKLB && pc_sect != 0 && (MB & BIT12) != 0) { AB = (++AR) & RMASK; sect = (AR >> 18) & 07777; @@ -9556,6 +11045,7 @@ do_extend(uint32 ia) if (Mem_write(0,0)) return 0; } +#endif if (fill2 != 0) { if (!store_byte(ext_ac+3, fill1, 0)) { return 0; @@ -9579,6 +11069,7 @@ do_extend(uint32 ia) case 2: /* Set signifigance */ if ((reg & SMASK) == 0) { AR = get_reg(ext_ac+3); +#if KL if (QKLB && pc_sect != 0) { sect = (AR >> 18) & 07777; glb_sect = 1; @@ -9586,10 +11077,12 @@ do_extend(uint32 ia) sect = cur_sect; glb_sect = 0; } +#endif AB = AR & RMASK; MB = get_reg(ext_ac+4); if (Mem_write(0, 0)) return 0; +#if KL if (QKLB && pc_sect != 0 && (MB & BIT12) != 0) { AB = (++AR) & RMASK; sect = (AR >> 18) & 07777; @@ -9597,6 +11090,7 @@ do_extend(uint32 ia) if (Mem_write(0,0)) return 0; } +#endif if (fill2 != 0) { val1 = fill2; i = 1; @@ -9609,6 +11103,7 @@ do_extend(uint32 ia) break; case 4: /* Exchange Mark */ AR = get_reg(ext_ac+3); +#if KL if (QKLB && pc_sect != 0) { sect = (AR >> 18) & 07777; glb_sect = 1; @@ -9616,6 +11111,7 @@ do_extend(uint32 ia) sect = cur_sect; glb_sect = 0; } +#endif AB = AR & RMASK; if (Mem_read(0, 0, 0)) return 0; @@ -9626,6 +11122,7 @@ do_extend(uint32 ia) return 0; if (Mem_write(0, 0)) return 0; +#if KL if (QKLB && pc_sect != 0 && (BR & BIT12) != 0) { AB = (AR + 1) & RMASK; sect = ((AR + 1)>> 18) & 07777; @@ -9647,6 +11144,7 @@ do_extend(uint32 ia) } set_reg(ext_ac+5, AD); } +#endif set_reg(ext_ac+4, BR); break; case 5: @@ -9657,7 +11155,9 @@ do_extend(uint32 ia) case 1: /* Insert Message char */ if ((reg & SMASK) != 0) { AB = (ia + (val1 & 077) + 1) & RMASK; +#if KL sect = cur_sect; +#endif if (Mem_read(0, 0, 0)) return 0; i = 1; @@ -9700,10 +11200,12 @@ do_extend(uint32 ia) case 010: /* CVTDBO */ case 011: /* CVTDBT */ +#if KL if (QKLB && pc_sect != 0 && glb_sect) xlat_sect = (AR >> 18) & 07777; else xlat_sect = cur_sect; +#endif val2 = ((AR & RSIGN) ? LMASK : 0) | (AR & RMASK); /* Check if conversion started */ if ((get_reg(ext_ac) & SMASK) == 0) { @@ -9726,7 +11228,9 @@ do_extend(uint32 ia) if (IR == 010) { val1 = (val1 + val2) & FMASK; } else { +#if KL sect = xlat_sect; +#endif f = do_xlate((uint32)(val2 & RMASK), val1, 017); if (f < 0) break; @@ -9772,13 +11276,17 @@ do_extend(uint32 ia) /* Save E1 */ if (IR == 012) { val2 = ((AR & RSIGN) ? LMASK : 0) | (AR & RMASK); +#if KL xlat_sect = cur_sect; +#endif } else { val2 = AB; +#if KL if (QKLB && pc_sect != 0 && glb_sect) xlat_sect = (AR >> 18) & 07777; else xlat_sect = cur_sect; +#endif } /* Get fill */ AB = (ia + 1) & RMASK; @@ -9798,7 +11306,9 @@ do_extend(uint32 ia) /* Set N bit if non-zero number */ if ((AR | ARX) != 0) reg |= BIT1; +#if KL set_reg(ext_ac+3, reg); +#endif /* Compute number of digits needed for value */ for (f = 0; f < 22; f++) { BRX = ARX + CCM(pow10_tab[f][1]) + 1; @@ -9811,6 +11321,9 @@ do_extend(uint32 ia) /* Check if room to save it */ if (f > (int)(reg & MANT)) return 0; +#if KS + set_reg(ext_ac+3, reg); +#endif /* Fill out left justify */ /* If L, fill leading zeros with fill char */ while ((reg & SMASK) != 0 && (int)(reg & MANT) > f) { @@ -9833,7 +11346,9 @@ do_extend(uint32 ia) if (IR == 013) { /* Read first translation entry */ AB = (val1 + val2) & RMASK; +#if KL sect = xlat_sect; +#endif if (Mem_read(0, 0, 0)) { set_reg(ext_ac + 3, (reg & (SMASK|EXPO)) | (f+1)); return 0; @@ -9862,13 +11377,16 @@ do_extend(uint32 ia) case 015: /* MOVST */ case 016: /* MOVSLJ */ get_mask(ext_ac+3, &msk); +#if KL xlat_sect = cur_sect; +#endif if ((((get_reg(ext_ac) & (077LL << 26))| get_reg(ext_ac+3)) & EMASK) != 0) return 1; if (IR == 014) { val2 = ((AR & RSIGN) ? LMASK : 0) | (AR & RMASK); } else if (IR == 015) { AB = ia; +#if KL if (QKLB) { if (pc_sect != 0 && glb_sect) xlat_sect = (AR >> 18) & 07777; @@ -9876,6 +11394,7 @@ do_extend(uint32 ia) xlat_sect = cur_sect; } else xlat_sect = 0; +#endif if (Mem_read(0, 1, 0)) return 0; val2 = MB; @@ -9898,7 +11417,9 @@ do_extend(uint32 ia) if ((val1 & ~msk) != 0) return 0; } else if (IR == 015) { +#if KL sect = xlat_sect; +#endif f = do_xlate((uint32)(val2), val1, 07777); if (f < 0) return 0; @@ -9951,6 +11472,7 @@ do_extend(uint32 ia) break; case 020: /* XBLT */ +#if KL if (QKLB) { glb_sect = 1; reg = get_reg(ext_ac); @@ -10003,6 +11525,7 @@ xblt_done: set_reg(ext_ac + 2, val2); return 0; } +#endif case 021: /* GSNGL */ case 022: /* GDBLE */ case 023: /* GDFIX */ @@ -10032,8 +11555,19 @@ rtc_srv(UNIT * uptr) sim_debug(DEBUG_CONO, &cpu_dev, "CONO timmer\n"); set_interrupt(4, clk_irq); } -#endif -#if KL +#elif KS + int_cur -= 4096 * 10; + if (int_cur & C1) { + irq_flags |= INT_DONE; + int_cur = int_val; + check_apr_irq(); + } + tim_low += 4096 * 10; + if (tim_low & SMASK) { + tim_high += 1; + tim_low = 0; + } +#elif KL update_times(rtc_tim); rtc_tim = (1000000/rtc_tps); #endif @@ -10109,19 +11643,24 @@ pi_pending = pi_enc = apr_irq = 0; ov_irq =fov_irq =clk_en =clk_irq = 0; pi_restore = pi_hold = 0; FLAGS = 0; -#if KI | KL +#if KI | KL | KS ub_ptr = eb_ptr = 0; pag_reload = ac_stack = 0; #if KI fm_sel = small_user = user_addr_cmp = page_enable = 0; #else fm_sel = prev_ctx = user_addr_cmp = page_enable = t20_page = 0; +#if KL sect = cur_sect = pc_sect = 0; #endif #endif +#endif #if BBN exec_map = 0; #endif +#if KS +int_cur = int_val = 0; +#endif for(i=0; i < 128; dev_irq[i++] = 0); sim_brk_types = SWMASK('E') | SWMASK('W') | SWMASK('R'); @@ -10129,7 +11668,7 @@ sim_brk_dflt = SWMASK ('E'); sim_clock_precalibrate_commands = pdp10_clock_precalibrate_commands; sim_vm_initial_ips = 4 * SIM_INITIAL_IPS; sim_rtcn_init_unit (&cpu_unit[0], cpu_unit[0].wait, TMR_RTC); -sim_activate(&cpu_unit[0], 10000); +sim_activate(&cpu_unit[0], 1000); #if MPX_DEV mpx_enable = 0; #endif @@ -10150,12 +11689,12 @@ if (vptr == NULL) if (ea < 020) *vptr = FM[ea] & FMASK; else { -#if KL | KI +#if KL | KI | KS if (sw & SWMASK ('V')) { int uf = ((sw & SWMASK('U')) != 0); int page = ea >> 9; uint32 tlb; -#if KL +#if KL | KS if (!uf && !t20_page && (page & 0740) == 0340) { #else if (!uf && (page & 0740) == 0340) { @@ -10188,12 +11727,12 @@ t_stat cpu_dep (t_value val, t_addr ea, UNIT *uptr, int32 sw) if (ea < 020) FM[ea] = val & FMASK; else { -#if KL | KI +#if KL | KI | KS if (sw & SWMASK ('V')) { int uf = ((sw & SWMASK('U')) != 0); int page = ea >> 9; uint32 tlb; -#if KL +#if KL | KS if (!uf && !t20_page && (page & 0740) == 0340) { #else if (!uf && (page & 0740) == 0340) { @@ -10241,136 +11780,148 @@ cpu_unit[0].capac = (uint32)val; return SCPE_OK; } +#if !KS /* Build device dispatch table */ t_bool build_dev_tab (void) { -DEVICE *dptr; -DIB *dibp; -uint32 i, j, d; + DEVICE *dptr; + DIB *dibp; + uint32 i, j, d; #if KL -uint32 rh20; + uint32 rh20; #endif -int rh_idx; - -/* Set trap offset based on MAOFF flag */ -maoff = (cpu_unit[0].flags & UNIT_MAOFF)? 0100 : 0; - + int rh_idx; + + /* Set trap offset based on MAOFF flag */ + maoff = (cpu_unit[0].flags & UNIT_MAOFF)? 0100 : 0; + max_dev = 2; + #if KA -/* Set up memory access routines based on current CPU type. */ - -/* Default to KA */ -Mem_read = &Mem_read_ka; -Mem_write = &Mem_write_ka; + /* Set up memory access routines based on current CPU type. */ + + /* Default to KA */ + Mem_read = &Mem_read_ka; + Mem_write = &Mem_write_ka; #if ITS -if (QITS) { - Mem_read = &Mem_read_its; - Mem_write = &Mem_write_its; -} + if (QITS) { + Mem_read = &Mem_read_its; + Mem_write = &Mem_write_its; + } #endif #if BBN -if (QBBN) { - Mem_read = &Mem_read_bbn; - Mem_write = &Mem_write_bbn; -} + if (QBBN) { + Mem_read = &Mem_read_bbn; + Mem_write = &Mem_write_bbn; + } #endif #if WAITS /* Waits without BBN pager */ -if (QWAITS && !QBBN) { - Mem_read = &Mem_read_waits; - Mem_write = &Mem_write_waits; -} + if (QWAITS && !QBBN) { + Mem_read = &Mem_read_waits; + Mem_write = &Mem_write_waits; + } #endif #endif - -/* Clear device and interrupt table */ -for (i = 0; i < 128; i++) { - dev_tab[i] = &null_dev; - dev_irqv[i] = NULL; -} - -/* Set up basic devices. */ -dev_tab[0] = &dev_apr; -dev_tab[1] = &dev_pi; + + /* Clear device and interrupt table */ + for (i = 0; i < 128; i++) { + dev_tab[i] = &null_dev; + dev_irqv[i] = NULL; + } + + /* Set up basic devices. */ + dev_tab[0] = &dev_apr; + dev_tab[1] = &dev_pi; #if KI | KL -dev_tab[2] = &dev_pag; + dev_tab[2] = &dev_pag; + max_dev++; #if KL -dev_tab[3] = &dev_cca; -dev_tab[4] = &dev_tim; -dev_irqv[4] = &tim_irq; -dev_tab[5] = &dev_mtr; + dev_tab[3] = &dev_cca; + dev_tab[4] = &dev_tim; + dev_irqv[4] = &tim_irq; + dev_tab[5] = &dev_mtr; + max_dev+=4; #endif #endif #if BBN -if (QBBN) - dev_tab[024>>2] = &dev_pag; -#endif - - -/* Assign all RH10 & RH20 devices */ -#if KL -rh20 = 0540; -#endif -rh_idx = 0; -for (i = 0; (dptr = rh_devs[i]) != NULL; i++) { - dibp = (DIB *) dptr->ctxt; - if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */ - d = dibp->dev_num; /* Check type */ - if (d & RH10_DEV) { /* Skip RH10 devices */ - d = rh_nums[rh_idx]; - if (d == 0) { - sim_printf ("To many RH10 devices %s\n", sim_dname (dptr)); - return TRUE; - } -#if KL - } else if (d & RH20_DEV) { /* RH20, grab next device */ -#if NUM_DEVS_NIA > 0 - /* If NIA20 installed, skip this slot */ - if ((nia_dev.flags & DEV_DIS) == 0 && dptr != &nia_dev && - rh20 == (((DIB *)nia_dev.ctxt)->dev_num & 0777)) - rh20 += 4; - /* If NIA20, then assign it to it's requested address */ - if ((nia_dev.flags & DEV_DIS) == 0 && dptr == &nia_dev) - d = dibp->dev_num & 0777; - else -#endif - d = rh20; - rh20 += 4; -#endif - } - dev_tab[(d >> 2)] = dibp->io; - dev_irqv[(d >> 2)] = dibp->irq; - rh[rh_idx].dev_num = d; - rh[rh_idx].dev = dptr; - rh[rh_idx].rh = dibp->rh; - dibp->rh->devnum = d; - rh_idx++; + if (QBBN) { + dev_tab[024>>2] = &dev_pag; + max_dev = 024>>2; + } +#endif + +#if !PDP6 + /* Assign all RH10 & RH20 devices */ +#if KL + rh20 = 0540; +#endif + rh_idx = 0; + for (i = 0; (dptr = rh_devs[i]) != NULL; i++) { + dibp = (DIB *) dptr->ctxt; + if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */ + d = dibp->dev_num; /* Check type */ + if (d & RH10_DEV) { /* Skip RH10 devices */ + d = rh_nums[rh_idx]; + if (d == 0) { + sim_printf ("To many RH10 devices %s\n", sim_dname (dptr)); + return TRUE; + } +#if KL + } else if (d & RH20_DEV) { /* RH20, grab next device */ +#if NUM_DEVS_NIA > 0 + /* If NIA20 installed, skip this slot */ + if ((nia_dev.flags & DEV_DIS) == 0 && dptr != &nia_dev && + rh20 == (((DIB *)nia_dev.ctxt)->dev_num & 0777)) + rh20 += 4; + /* If NIA20, then assign it to it's requested address */ + if ((nia_dev.flags & DEV_DIS) == 0 && dptr == &nia_dev) + d = dibp->dev_num & 0777; + else +#endif + d = rh20; + rh20 += 4; +#endif + } + dev_tab[(d >> 2)] = dibp->io; + dev_irqv[(d >> 2)] = dibp->irq; + rh[rh_idx].dev_num = d; + rh[rh_idx].dev = dptr; + rh[rh_idx].rh = dibp->rh; + dibp->rh->devnum = d; + if ((d >> 2) > max_dev) + max_dev = d >> 2; + rh_idx++; + } + } +#endif + + /* Assign all remaining devices */ + for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { + dibp = (DIB *) dptr->ctxt; + if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */ + for (j = 0; j < dibp->num_devs; j++) { /* loop thru disp */ + if (dibp->io) { /* any dispatch? */ + d = dibp->dev_num; + if (d & (RH10_DEV|RH20_DEV)) /* Skip RH10 & RH20 devices */ + continue; + if (dev_tab[(d >> 2) + j] != &null_dev) { + /* already filled? */ + sim_printf ("%s device number conflict at %02o\n", + sim_dname (dptr), d + (j << 2)); + return TRUE; + } + dev_tab[(d >> 2) + j] = dibp->io; /* fill */ + dev_irqv[(d >> 2) + j] = dibp->irq; + if (((d >> 2) + j)> max_dev) + max_dev = (d >> 2) + j; + } + } + } } -} - -/* Assign all remaining devices */ -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { - dibp = (DIB *) dptr->ctxt; - if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */ - for (j = 0; j < dibp->num_devs; j++) { /* loop thru disp */ - if (dibp->io) { /* any dispatch? */ - d = dibp->dev_num; - if (d & (RH10_DEV|RH20_DEV)) /* Skip RH10 & RH20 devices */ - continue; - if (dev_tab[(d >> 2) + j] != &null_dev) { - /* already filled? */ - sim_printf ("%s device number conflict at %02o\n", - sim_dname (dptr), d + (j << 2)); - return TRUE; - } - dev_tab[(d >> 2) + j] = dibp->io; /* fill */ - dev_irqv[(d >> 2) + j] = dibp->irq; - } /* end if dsp */ - } /* end for j */ - } /* end if enb */ - } /* end for i */ return FALSE; } +#endif -#if KI | KL +#if KI | KL | KS /* Set serial */ t_stat cpu_set_serial (UNIT *uptr, int32 val, CONST char *cptr, void *desc) @@ -10473,7 +12024,12 @@ for (k = 0; k < lnt; k++) { /* print specified */ fprintf(st, "%08o ", h->ea & 0777777777); else #endif +#if KS + fprintf (st, "%c", (h->ea & 07000000) ? ((h->ea >> 18) & 07) + '0': ' '); + fprintf (st, "%06o ", h->ea & 0777777); +#else fprintf (st, "%06o ", h->ea); +#endif fputs (" ", st); fprint_val (st, h->mb, 8, 36, PV_RZRO); fputs (" ", st); @@ -10481,7 +12037,9 @@ for (k = 0; k < lnt; k++) { /* print specified */ fputs (" ", st); #if KI | KL fprintf (st, "%c%06o ", ((h->flags & (PRV_PUB << 5))? 'p':' '), h->flags & 0777777); +#if KL fprintf (st, "%02o ", h->prev_sect); +#endif #else fprintf (st, "%06o ", h->flags); #endif @@ -10518,6 +12076,9 @@ cpu_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) const char * cpu_description (DEVICE *dptr) { +#if KS + return "KS10 CPU"; +#endif #if KL return "KL10 CPU"; #endif diff --git a/PDP10/kx10_defs.h b/PDP10/kx10_defs.h index 7e90cc6..29e0056 100644 --- a/PDP10/kx10_defs.h +++ b/PDP10/kx10_defs.h @@ -50,11 +50,15 @@ #define KL 0 #endif +#ifndef KS +#define KS 0 +#endif + #if KL #define EPT440 0 /* Force KL10 to use as 440 section address */ #endif -#if (PDP6 + KA + KI + KL) != 1 +#if (PDP6 + KA + KI + KL + KS) != 1 #error "Please define only one type of CPU" #endif @@ -82,6 +86,11 @@ #define KL_ITS KL #endif +/* Support for ITS on KS */ +#ifndef KS_ITS +#define KS_ITS KS +#endif + #ifndef PDP6_DEV /* Include PDP6 devices */ #define PDP6_DEV PDP6|WAITS #endif @@ -196,6 +205,27 @@ extern DEBTAB crd_debug[]; #define FPRBIT2 00000000000100000000000LL #define FPRBIT1 00000000000200000000000LL +/* IRQ Flags in APR */ +#if KL +#define SWP_DONE 0000020 /* Cache sweep done */ +#define PWR_FAIL 0000040 /* Power failure */ +#define ADDR_PAR 0000100 /* Address Parity error */ +#define CACHE_DIR 0000200 /* Cache Parity error */ +#define MB_PAR 0000400 /* Memory parity error */ +#define INOUT_FAIL 0001000 /* Fault during IRQ */ +#define NXM_MEM 0002000 /* Non-existent memory */ +#define SBUS_ERR 0004000 /* SBus Error */ +#endif +#if KS +#define CON_IRQ 0000020 /* Interrupt from Console */ +#define INT_DONE 0000040 /* Interval timer complete */ +#define COR_MEM 0000100 /* Corrected memory error */ +#define MB_ERR 0000200 /* Uncorrectable memory error */ +#define NXM_MEM 0000400 /* No memory */ +#define PWR_FAIL 0001000 /* Power Failure */ +#define FLAG_24 0004000 /* Spare */ +#endif + #define CM(x) (FMASK ^ (x)) #define CCM(x) ((CMASK ^ (x)) & CMASK) @@ -231,12 +261,16 @@ extern DEBTAB crd_debug[]; #define NODIV 000001 /* 000040 */ #define FLTUND 000002 /* 000100 */ #endif -#if KI|KL +#if KI|KL|KS #define TRP1 000004 /* 000200 */ #define TRP2 000010 /* 000400 */ #define ADRFLT 000020 /* 001000 */ +#if KI | KL #define PUBLIC 000040 /* 002000 */ #else +#define PUBLIC 000000 /* 000000 */ +#endif +#else #define TRP1 000000 #define TRP2 000000 #define ADRFLT 000000 @@ -284,9 +318,13 @@ extern DEBTAB crd_debug[]; #if PDP6 #define MAXMEMSIZE 256 * 1024 #else +#if KS +#define MAXMEMSIZE 512 * 1024 +#else #define MAXMEMSIZE 1024 * 1024 #endif #endif +#endif #define MEMSIZE (cpu_unit[0].capac) #define ICWA 0000000000776 @@ -323,6 +361,10 @@ extern DEBTAB crd_debug[]; #define DEF_SERIAL 1025 /* Default DEC test machine */ #endif +#if KS +#define DEF_SERIAL 4097 /* Default DEC test machine */ +#endif + #if BBN #define BBN_PAGE 0000017777777LL #define BBN_TRPPG 0000017000000LL @@ -339,7 +381,7 @@ extern DEBTAB crd_debug[]; #define BBN_MERGE 0161740000000LL #endif -#if KL +#if KL|KS /* KL10 TLB paging bits */ #define KL_PAG_A 0400000 /* Access */ #define KL_PAG_P 0200000 /* Public */ @@ -367,7 +409,11 @@ extern DEBTAB crd_debug[]; #define UNIT_KL10B (1 << UNIT_V_PAGE) #define UNIT_TWOSEG (0) #else +#if KA #define UNIT_TWOSEG (1 << UNIT_V_PAGE) +#else +#define UNIT_TWOSEG (0) +#endif #endif #define UNIT_ITSPAGE (2 << UNIT_V_PAGE) #define UNIT_BBNPAGE (4 << UNIT_V_PAGE) @@ -471,6 +517,45 @@ extern DEVICE mtc_dev; extern DEVICE dsk_dev; extern DEVICE dcs_dev; +#if KS +/* Device context block */ +struct pdp_dib { + uint32 uba_addr; /* device address, includes adaptor */ + uint32 uba_mask; /* Compare mask */ + uint16 uba_vect; /* Floating IRQ vector */ + uint16 uba_br; /* Unibus IRQ level */ + uint16 uba_ctl; /* Unibus controller number */ + t_stat (*rd_io)(t_addr addr, uint16 *data, int32 access); + t_stat (*wr_io)(t_addr addr, uint16 data, int32 access); + uint8 uba_irq_pend; /* Device has pending */ +}; +typedef struct pdp_dib DIB; + +void cty_wakeup(); +void cty_interrupt(); + +#define WORD 0 +#define BYTE 1 +int uba_read(t_addr addr, int ctl, uint64 *data, int access); +int uba_write(t_addr addr, int ctl, uint64 data, int access); +int uba_read_npr(t_addr addr, uint16 ctl, uint64 *data); +int uba_write_npr(t_addr addr, uint16 ctl, uint64 data); +int uba_read_npr_byte(t_addr addr, uint16 ctl, uint16 *data); +int uba_write_npr_byte(t_addr addr, uint16 ctl, uint16 data); +int uba_read_npr_word(t_addr addr, uint16 ctl, uint16 *data); +int uba_write_npr_word(t_addr addr, uint16 ctl, uint16 data); +void uba_set_irq(DIB *dibp); +t_addr uba_get_vect(t_addr addr, int lvl); + +t_stat uba_set_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat uba_show_addr (FILE *st, UNIT *uptr, int32 val, CONST void *desc); +t_stat uba_set_br(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat uba_show_br (FILE *st, UNIT *uptr, int32 val, CONST void *desc); +t_stat uba_set_vect(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat uba_show_vect (FILE *st, UNIT *uptr, int32 val, CONST void *desc); +t_stat uba_set_ctl(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat uba_show_ctl (FILE *st, UNIT *uptr, int32 val, CONST void *desc); +#else extern t_stat (*dev_tab[128])(uint32 dev, t_uint64 *data); #define VEC_DEVMAX 8 /* max device vec */ @@ -573,15 +658,13 @@ extern void ka10_lights_init (void); extern void ka10_lights_main (t_uint64); extern void ka10_lights_set_aux (int); extern void ka10_lights_clear_aux (int); - +#endif /* I/O system parameters */ +#if !(PDP6 | KS) #define NUM_DEVS_LP 1 -#if KL -#define NUM_DEVS_PT 0 -#define NUM_DEVS_CR 0 -#define NUM_DEVS_CP 0 -#else +#endif +#if !(KL | KS) #define NUM_DEVS_PT 1 #define NUM_DEVS_CR 1 #define NUM_DEVS_CP 1 @@ -597,34 +680,40 @@ extern void ka10_lights_clear_aux (int); #define NUM_DEVS_DCS 1 #define NUM_DEVS_SLAVE PDP6 #endif -#if !PDP6 +#if !(PDP6 | KS) #define NUM_DEVS_DC 1 #define NUM_DEVS_MT 1 +#endif #if KL -#define NUM_DEVS_RC 0 -#define NUM_DEVS_DT 0 -#define NUM_DEVS_DK 0 -#define NUM_DEVS_DP 0 #define NUM_DEVS_LP20 1 #define NUM_DEVS_TTY 1 #define NUM_LINES_TTY 64 #define NUM_DEVS_NIA 1 -#else +#elif KS +#define NUM_DEVS_LP20 0 +#define NUM_DEVS_DZ 0 +#define NUM_LINES_DZ 8 * NUM_DEVS_DZ +#endif +#if KA | KI #define NUM_DEVS_RC 1 #define NUM_DEVS_DT 1 #define NUM_DEVS_DK 1 #define NUM_DEVS_DP 2 -#define NUM_DEVS_LP20 0 -#define NUM_DEVS_TTY 0 -#define NUM_DEVS_NIA 0 #endif +#if KS +#define NUM_DEVS_RP 1 +#elif KA | KI | KL #define NUM_DEVS_RP 4 #define NUM_DEVS_RS 1 +#endif +#if !(PDP6) #define NUM_DEVS_TU 1 +#endif +#if KA #define NUM_DEVS_PMP WAITS #define NUM_DEVS_DKB (WAITS * USE_DISPLAY) #define NUM_DEVS_III (WAITS * USE_DISPLAY) -#define NUM_DEVS_PD ITS | KL_ITS +#define NUM_DEVS_PD ITS #define NUM_DEVS_PCLK WAITS #define NUM_DEVS_IMX ITS #define NUM_DEVS_STK ITS @@ -632,11 +721,16 @@ extern void ka10_lights_clear_aux (int); #define NUM_DEVS_MTY ITS #define NUM_DEVS_TEN11 ITS #define NUM_DEVS_AUXCPU ITS -#define NUM_DEVS_IMP 1 -#define NUM_DEVS_CH10 ITS | KL_ITS +#define NUM_DEVS_IMP ITS +#define NUM_DEVS_CH10 ITS #define NUM_DEVS_DPK ITS #define NUM_DEVS_AI ITS #endif +#if KL_ITS +#define NUM_DEVS_PD KL_ITS +#define NUM_DEVS_IMP KL_ITS +#define NUM_DEVS_CH10 KL_ITS +#endif #if MAGIC_SWITCH && !KA && !ITS #error "Magic switch only valid on KA10 with ITS mods" #endif @@ -645,7 +739,9 @@ extern void ka10_lights_clear_aux (int); extern t_bool sim_idle_enab; +#if !KS extern struct rh_dev rh[]; +#endif extern t_uint64 M[MAXMEMSIZE]; extern t_uint64 FM[]; extern uint32 PC; diff --git a/PDP10/kx10_sys.c b/PDP10/kx10_sys.c index 2204e2b..03ad7cd 100644 --- a/PDP10/kx10_sys.c +++ b/PDP10/kx10_sys.c @@ -42,6 +42,9 @@ sim_load binary loader */ +#if KS +char sim_name[] = "KS-10"; +#endif #if KL char sim_name[] = "KL-10"; #endif @@ -62,7 +65,7 @@ int32 sim_emax = 1; DEVICE *sim_devices[] = { &cpu_dev, -#if PDP6 | KA | KI +#if PDP6 | KA | KI | KS &cty_dev, #endif #if KL @@ -902,7 +905,7 @@ static const char *opcode[] = { "SETSTS", "STATO", "STATUS", "GETSTS", "INBUF", "OUTBUF", "INPUT", "OUTPUT", "CLOSE", "RELEAS", "MTAPE", "UGETF", "USETI", "USETO", "LOOKUP", "ENTER", -#if KL +#if KL | KS "UJEN", "GFAD", "GFSB", "JSYS", "ADJSP", "GFMP", "GFDV ", "DFAD", "DFSB", "DFMP", "DFDV", "DADD", "DSUB", "DMUL", "DDIV", #else @@ -961,6 +964,19 @@ static const char *opcode[] = { "TRO", "TLO", "TROE", "TLOE", "TROA", "TLOA", "TRON", "TLON", "TDO", "TSO", "TDOE", "TSOE", "TDOA", "TSOA", "TDON", "TSON", +#if KS + "APRID", "CLRSCH", "RDUBR", "CLRPT", + "WRUBR", "WREBR", "RDEBR", + "RDSPB", "RDCSB", "RDPUR", "RDCSTM", + "RDTIME", "RDINT", "RDHSB", "SPM", + "WRSPB", "WRCSB", "WRPUR", "WRCSTM", + "WRINT", "WRTIME", "WRHSB", "LPMR", + "UMOVE", "UMOVEM", + "TIOE", "TION", "RDIO", "WRIO", + "BSIO", "BCIO", + "TIOEB", "TIONB", "RDIOB", "WRIOB", + "BSIOB", "BCIOB", +#endif "BLKI", "DATAI", "BLKO", "DATAO", /* classic I/O */ "CONO", "CONI", "CONSZ", "CONSO", @@ -1095,9 +1111,21 @@ static const t_int64 opc_val[] = { 0670000000000+I_AC, 0671000000000+I_AC, 0672000000000+I_AC, 0673000000000+I_AC, 0674000000000+I_AC, 0675000000000+I_AC, 0676000000000+I_AC, 0677000000000+I_AC, +#if KS + 0700000000000+I_OP, 0701000000000+I_OP, 0701040000000+I_OP, 0701100000000+I_OP, + 0701140000000+I_OP, 0701200000000+I_OP, 0701240000000+I_OP, + 0702000000000+I_OP, 0702040000000+I_OP, 0702100000000+I_OP, 0702140000000+I_OP, + 0702200000000+I_OP, 0702240000000+I_OP, 0702300000000+I_OP, 0702340000000+I_OP, + 0702400000000+I_OP, 0702440000000+I_OP, 0702500000000+I_OP, 0702540000000+I_OP, + 0702600000000+I_OP, 0702640000000+I_OP, 0702700000000+I_OP, 0702740000000+I_OP, + 0704000000000+I_AC, 0705000000000+I_AC, + 0710000000000+I_AC, 0711000000000+I_AC, 0712000000000+I_AC, 0713000000000+I_AC, + 0714000000000+I_AC, 0715000000000+I_AC, + 0720000000000+I_AC, 0721000000000+I_AC, 0722000000000+I_AC, 0723000000000+I_AC, + 0724000000000+I_AC, 0725000000000+I_AC, +#endif 0700000000000+I_IO, 0700040000000+I_IO, 0700100000000+I_IO, 0700140000000+I_IO, 0700200000000+I_IO, 0700240000000+I_IO, 0700300000000+I_IO, 0700340000000+I_IO, - -1 }; diff --git a/README.md b/README.md index feb79ce..f9a1402 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![Coverity Scan Build Status](https://scan.coverity.com/projects/12020/badge.svg)](https://scan.coverity.com/projects/rcornwell-sims) -This is a working copy of my Burroughs B5500, Dec PDP6, KA10, KI10, KL10, SEL32, IBM 360 +This is a working copy of my Burroughs B5500, Dec PDP6, KA10, KI10, KL10, KS10, SEL32, IBM 360 and IBM7000 series simulators for SimH. # Stable released simulators. @@ -95,11 +95,12 @@ The PDP6 runs TOPS 10 4.5 off Dectape. Type 340 graphics display. -# Dec KA10 & KI10 & KL10 +# Dec KA10 & KI10 & KL10 & KS10 The KA10 sim has successfully run Tops 10 4.5, 5.03 and 6.03, ITS and WAITS. The KI10 sim has successfully run Tops 10 6.03 with VMSER. The KL10 sim has successfully run Tops 10 6.03-7.03, ITS and Tops 20 V2-V7. +The KS10 is still in testing. Disk * RC10 RD10/RM10 @@ -138,6 +139,8 @@ The KL10 sim has successfully run Tops 10 6.03-7.03, ITS and Tops 20 V2-V7. The RP10 supports boot (actual hardware did not), by reading in Blocks 4-7 and transfering to the loaded value. RC10, RH10, TM10 support readin mode. + The KS10 supports RH11/RP and RH11/TM03 drives. + # ICL 1900 simulator. This is a new simulator. Will pass 1904E/1905E CPU diagnostics (FLIT). Will boot paper diff --git a/makefile b/makefile index d1c9a30..aae99ad 100644 --- a/makefile +++ b/makefile @@ -277,7 +277,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) OS_CCDEFS += -Wno-deprecated endif endif - ifeq (git-repo,$(shell if ${TEST} -d ./.git; then echo git-repo; fi)) + ifeq (git-repo,$(shell if ${TEST} -e ./.git; then echo git-repo; fi)) GIT_PATH=$(strip $(shell which git)) ifeq (,$(GIT_PATH)) $(error building using a git repository, but git is not available) @@ -1196,6 +1196,7 @@ else ifeq (Darwin,$(OSTYPE)) CFLAGS_O += -O4 -flto -fwhole-program else +# CFLAGS_O := -O2 -fprofile-arcs -ftest-coverage CFLAGS_O := -O2 endif endif @@ -2138,7 +2139,13 @@ KL10 = ${KL10D}/kx10_cpu.c ${KL10D}/kx10_sys.c ${KL10D}/kx10_df.c \ ${KL10D}/kx10_imp.c ${KL10D}/kl10_fe.c ${KL10D}/ka10_pd.c \ ${KL10D}/ka10_ch10.c ${KL10D}/kx10_lp.c ${KL10D}/kl10_nia.c \ ${KL10D}/kx10_disk.c -KL10_OPT = -DKL=1 -DUSE_INT64 -I $(KL10D) -DUSE_SIM_CARD ${NETWORK_OPT} +KL10_OPT = -DKL=1 -DUSE_INT64 -I $(KL10D) ${NETWORK_OPT} + +KS10D = ${SIMHD}/PDP10 +KS10 = ${KS10D}/kx10_cpu.c ${KS10D}/kx10_sys.c ${KS10D}/kx10_disk.c \ + ${KS10D}/ks10_cty.c ${KS10D}/ks10_uba.c ${KS10D}/ks10_rp.c \ + ${KS10D}/ks10_tu.c +KS10_OPT = -DKS=1 -DUSE_INT64 -I $(KS10D) ${NETWORK_OPT} ATT3B2D = ${SIMHD}/3B2 ATT3B2 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_mmu.c \ @@ -2214,7 +2221,7 @@ ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \ scelbi 3b2 i701 i704 i7010 i7070 i7080 i7090 \ sigma uc15 pdp10-ka pdp10-ki pdp6 -ALL = b5500 i701 i704 i7010 i7070 i7080 i7090 pdp10-ka pdp10-ki pdp10-kl pdp6 ibm360 ibm360_32 icl1900 sel32 +ALL = b5500 i701 i704 i7010 i7070 i7080 i7090 pdp10-ka pdp10-ki pdp10-kl pdp10-ks pdp6 ibm360 ibm360_32 icl1900 sel32 all : ${ALL} @@ -3057,6 +3064,15 @@ ifneq (,$(call find_test,${PDP10D},kl10)) $@ $(call find_test,${PDP10D},kl10) ${TEST_ARG} endif +pdp10-ks : ${BIN}pdp10-ks${EXE} + +${BIN}pdp10-ks${EXE} : ${KS10} ${SIM} + ${MKDIRBIN} + ${CC} ${KS10} ${SIM} ${KS10_OPT} ${CC_OUTSPEC} ${LDFLAGS} +ifneq (,$(call find_test,${PDP10D},ks10)) + $@ $(call find_test,${PDP10D},ks10) ${TEST_ARG} +endif + # Front Panel API Demo/Test program frontpaneltest : ${BIN}frontpaneltest${EXE}