diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index 43eb6ee8..be96c3cf 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -26,6 +26,7 @@ The author gratefully acknowledges the help of Max Burnet, Megan Gentry, and John Wilson in resolving questions about the PDP-11 + 02-Sep-13 RMS Added third Massbus adapter and RS drive 11-Dec-11 RMS Fixed priority of PIRQ vs IO; added INT_INTERNALn 22-May-10 RMS Added check for 64b definitions 19-Nov-08 RMS Moved I/O support routines to I/O library @@ -598,10 +599,11 @@ typedef struct pdp_dib DIB; #define INT_V_TU 15 #define INT_V_RF 16 #define INT_V_RC 17 -#define INT_V_DMCRX 18 -#define INT_V_DMCTX 19 -#define INT_V_DUPRX 20 -#define INT_V_DUPTX 21 +#define INT_V_RS 18 +#define INT_V_DMCRX 19 +#define INT_V_DMCTX 20 +#define INT_V_DUPRX 21 +#define INT_V_DUPTX 22 #define INT_V_PIR4 0 /* BR4 */ #define INT_V_TTI 1 @@ -645,6 +647,7 @@ typedef struct pdp_dib DIB; #define INT_TU (1u << INT_V_TU) #define INT_RF (1u << INT_V_RF) #define INT_RC (1u << INT_V_RC) +#define INT_RS (1u << INT_V_RS) #define INT_DMCRX (1u << INT_V_DMCRX) #define INT_DMCTX (1u << INT_V_DMCTX) #define INT_DUPRX (1u << INT_V_DUPRX) @@ -695,6 +698,7 @@ typedef struct pdp_dib DIB; #define IPL_TU 5 #define IPL_RF 5 #define IPL_RC 5 +#define IPL_RS 5 #define IPL_DMCRX 5 #define IPL_DMCTX 5 #define IPL_DUPRX 5 @@ -741,9 +745,10 @@ typedef struct pdp_dib DIB; /* Massbus definitions */ -#define MBA_NUM 2 /* number of MBA's */ +#define MBA_NUM 3 /* number of MBA's */ #define MBA_RP 0 /* MBA for RP */ #define MBA_TU 1 /* MBA for TU */ +#define MBA_RS 2 /* MBA for RS */ #define MBA_RMASK 037 /* max 32 reg */ #define MBE_NXD 1 /* nx drive */ #define MBE_NXR 2 /* nx reg */ diff --git a/PDP11/pdp11_io_lib.c b/PDP11/pdp11_io_lib.c index da6f638e..311adb01 100644 --- a/PDP11/pdp11_io_lib.c +++ b/PDP11/pdp11_io_lib.c @@ -451,8 +451,8 @@ AUTO_CON auto_tab[] = {/*c #v am vm fxa fxv */ {017300} }, /* KE11-A - fx CSR, no VEC */ { { "KG" }, 1, 0, 0, 0, {010700} }, /* KG11-A - fx CSR, no VEC */ - { { "RHA", "RHB" }, 1, 1, 0, 0, - {016700, 012440}, {0254, 0224} }, /* RH11/RH70 - fx CSR, fx VEC */ + { { "RHA", "RHB", "RHC" }, 1, 1, 0, 0, + {016700, 012440, 012040}, {0254, 0224, 0204} }, /* RH11/RH70 - fx CSR, fx VEC */ { { "CLK" }, 1, 1, 0, 0, {017546}, {0100} }, /* KW11L - fx CSR, fx VEC */ { { "PCLK" }, 1, 1, 0, 0, diff --git a/PDP11/pdp11_rh.c b/PDP11/pdp11_rh.c index 2141392e..ce334a74 100644 --- a/PDP11/pdp11_rh.c +++ b/PDP11/pdp11_rh.c @@ -1,6 +1,6 @@ /* pdp11_rh.c: PDP-11 Massbus adapter simulator - Copyright (c) 2005-2012, Robert M Supnik + Copyright (c) 2005-2013, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rha, rhb RH11/RH70 Massbus adapter + 02-Sep-13 RMS Added third Massbus adapter, debug printouts 19-Mar-12 RMS Fixed declaration of cpu_opt (Mark Pizzolato) 02-Feb-08 RMS Fixed DMA memory address limit test (John Dundas) 17-May-07 RMS Moved CS1 drive enable to devices @@ -172,6 +173,7 @@ t_stat mba_set_type (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat mba_show_type (FILE *st, UNIT *uptr, int32 val, void *desc); int32 mba0_inta (void); int32 mba1_inta (void); +int32 mba2_inta (void); void mba_set_int (uint32 mb); void mba_clr_int (uint32 mb); void mba_upd_cs1 (uint32 set, uint32 clr, uint32 mb); @@ -273,6 +275,41 @@ MTAB mba1_mod[] = { { 0 } }; +#define IOLN_RS 040 + +DIB mba2_dib = { + IOBA_AUTO, IOLN_RS, &mba_rd, &mba_wr, + 1, IVCL (RS), VEC_AUTO, { &mba2_inta } + }; + +UNIT mba2_unit = { UDATA (NULL, 0, 0) }; + +REG mba2_reg[] = { + { ORDATA (CS1, massbus[2].cs1, 16) }, + { ORDATA (WC, massbus[2].wc, 16) }, + { ORDATA (BA, massbus[2].ba, 16) }, + { ORDATA (CS2, massbus[2].cs2, 16) }, + { ORDATA (DB, massbus[2].db, 16) }, + { ORDATA (BAE, massbus[2].bae, 6) }, + { ORDATA (CS3, massbus[2].cs3, 16) }, + { FLDATA (IFF, massbus[2].iff, 0) }, + { FLDATA (INT, IREQ (TU), INT_V_TU) }, + { FLDATA (SC, massbus[2].cs1, CSR_V_ERR) }, + { FLDATA (DONE, massbus[2].cs1, CSR_V_DONE) }, + { FLDATA (IE, massbus[2].cs1, CSR_V_IE) }, + { ORDATA (DEVADDR, mba2_dib.ba, 32), REG_HRO }, + { ORDATA (DEVVEC, mba2_dib.vec, 16), REG_HRO }, + { NULL } + }; + +MTAB mba2_mod[] = { + { MTAB_XTD|MTAB_VDV, 0040, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, + { 0 } + }; + DEVICE mba_dev[] = { { "RHA", &mba0_unit, mba0_reg, mba0_mod, @@ -287,6 +324,13 @@ DEVICE mba_dev[] = { NULL, NULL, &mba_reset, NULL, NULL, NULL, &mba1_dib, DEV_DEBUG | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS + }, + { + "RHC", &mba2_unit, mba2_reg, mba2_mod, + 1, 0, 0, 0, 0, 0, + NULL, NULL, &mba_reset, + NULL, NULL, NULL, + &mba2_dib, DEV_DEBUG | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS } }; @@ -416,6 +460,9 @@ switch (ofs) { /* case on reg */ massbus[mb].cs1 &= ~(CS1_TRE | CS1_MCPE | CS1_DONE); massbus[mb].cs2 &= ~CS2_ERR; /* clear errors */ massbus[mb].cs3 &= ~(CS3_ERR | CS3_DBL); + if (DEBUG_PRS (mba_dev[mb])) + fprintf (sim_deb, ">>RH%d STRT: cs1=%o, cs2=%o,ba=%o, wc=%o\n", + mb, massbus[mb].cs1, massbus[mb].cs2, massbus[mb].ba, massbus[mb].wc); } } } @@ -624,6 +671,9 @@ return i; void mba_set_don (uint32 mb) { mba_upd_cs1 (CS1_DONE, 0, mb); +if (DEBUG_PRS (mba_dev[mb])) + fprintf (sim_deb, ">>RH%d DONE: cs1=%o, cs2=%o,ba=%o, wc=%o\n", + mb, massbus[mb].cs1, massbus[mb].cs2, massbus[mb].ba, massbus[mb].wc); return; } @@ -727,6 +777,14 @@ massbus[1].iff = 0; /* clear CSTB INTR */ return mba1_dib.vec; /* acknowledge */ } +int32 mba2_inta (void) +{ +massbus[2].cs1 &= ~CS1_IE; /* clear int enable */ +massbus[2].cs3 &= ~CS1_IE; /* in both registers */ +massbus[2].iff = 0; /* clear CSTB INTR */ +return mba2_dib.vec; /* acknowledge */ +} + /* Map physical address to Massbus number, offset */ uint32 mba_map_pa (int32 pa, int32 *ofs) @@ -784,11 +842,15 @@ return auto_config (0, 0); void mba_set_enbdis (uint32 mb, t_bool dis) { +t_bool orig; if (mb >= MBA_NUM) /* valid MBA? */ return; +orig = mba_dev[mb].flags & DEV_DIS; if (dis) mba_dev[mb].flags |= DEV_DIS; else mba_dev[mb].flags &= ~DEV_DIS; +if (orig ^ dis) + mba_reset (&mba_dev[mb]); /* reset on change */ return; } diff --git a/PDP11/pdp11_rp.c b/PDP11/pdp11_rp.c index d66391a7..9dbb9cfa 100644 --- a/PDP11/pdp11_rp.c +++ b/PDP11/pdp11_rp.c @@ -639,6 +639,8 @@ REG rp_reg[] = { }; MTAB rp_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "MASSBUS", NULL, + NULL, &mba_show_num, NULL, "Display Massbus number" }, { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL, NULL, NULL, "Write enable disk drive" }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", diff --git a/PDP11/pdp11_rs.c b/PDP11/pdp11_rs.c new file mode 100644 index 00000000..b699b60e --- /dev/null +++ b/PDP11/pdp11_rs.c @@ -0,0 +1,724 @@ +/* pdp11_rs.c - RS03/RS04 Massbus disk controller + + Copyright (c) 2013, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + rs RS03/RS04 fixed head disks +*/ + +#if defined (VM_PDP10) +#error "RS03/RS04 not supported on the PDP-10!" + +#elif defined (VM_PDP11) +#include "pdp11_defs.h" +#define DEV_RADIX 8 + +#elif defined (VM_VAX) +#error "RS03/RS04 not supported on the VAX!" +#endif + +#include + +#define RS_NUMDR 8 /* #drives */ +#define RS03_NUMWD 64 /* words/sector */ +#define RS04_NUMWD 128 /* words/sector */ +#define RS_NUMSC 64 /* sectors/track */ +#define RS_NUMTK 64 /* tracks/disk */ +#define RS_MAXFR (1 << 16) /* max transfer */ +#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \ + ((double) (RS03_NUMWD * RS_NUMSC)))) +#define RS03_ID 0 +#define RS04_ID 2 +#define RS03_SIZE (RS_NUMTK * RS_NUMSC * RS03_NUMWD) +#define RS04_SIZE (RS_NUMTK * RS_NUMSC * RS04_NUMWD) +#define RS_NUMWD(d) ((d)? RS04_NUMWD: RS03_NUMWD) +#define RS_SIZE(d) ((d)? RS04_SIZE: RS03_SIZE) + +/* Flags in the unit flags word */ + +#define UNIT_V_DTYPE (UNIT_V_UF + 0) /* disk type */ +#define RS03_DTYPE (0) +#define RS04_DTYPE (1) +#define UNIT_V_AUTO (UNIT_V_UF + 1) /* autosize */ +#define UNIT_V_WLK (UNIT_V_UF + 2) /* write lock */ +#define UNIT_DTYPE (1 << UNIT_V_DTYPE) +#define UNIT_AUTO (1 << UNIT_V_AUTO) +#define UNIT_WLK (1 << UNIT_V_WLK) +#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & 1) + +/* RSCS1 - control/status 1 - offset 0 */ + +#define RS_CS1_OF 0 +#define CS1_GO CSR_GO /* go */ +#define CS1_V_FNC 1 /* function pos */ +#define CS1_M_FNC 037 /* function mask */ +#define CS1_N_FNC (CS1_M_FNC + 1) +#define FNC_NOP 000 /* no operation */ +#define FNC_DCLR 004 /* drive clear */ +#define FNC_SEARCH 014 /* search */ +#define FNC_XFR 020 /* divide line for xfr */ +#define FNC_WCHK 024 /* write check */ +#define FNC_WRITE 030 /* write */ +#define FNC_READ 034 /* read */ +#define CS1_RW 076 +#define CS1_DVA 04000 /* drive avail */ +#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) + +/* RSDS - drive status - offset 1 */ + +#define RS_DS_OF 1 +#define DS_RDY 0000200 /* drive ready */ +#define DS_DPR 0000400 /* drive present */ +#define DS_LST 0002000 /* last sector */ +#define DS_WLK 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 0001177 + +/* RSER - error status - offset 2 */ + +#define RS_ER_OF 2 +#define ER_ILF 0000001 /* illegal func */ +#define ER_ILR 0000002 /* illegal register */ +#define ER_RMR 0000004 /* reg mod refused */ +#define ER_PAR 0000010 /* parity err */ +#define ER_AOE 0001000 /* addr ovflo err */ +#define ER_IAE 0002000 /* invalid addr err */ +#define ER_WLE 0004000 /* write lock err NI */ +#define ER_DTE 0010000 /* drive time err NI */ +#define ER_OPI 0020000 /* op incomplete */ +#define ER_UNS 0040000 /* drive unsafe */ +#define ER_DCK 0100000 /* data check NI */ +#define ER_MBZ 0000760 + +/* RSMR - maintenace register - offset 3 */ + +#define RS_MR_OF 3 + +/* RSAS - attention summary - offset 4 */ + +#define RS_AS_OF 4 +#define AS_U0 0000001 /* unit 0 flag */ + +/* RSDA - sector/track - offset 5 + All 16b are RW, but only <14:12> are tested for "invalid" address */ + +#define RS_DA_OF 5 +#define DA_V_SC 0 /* sector pos */ +#define DA_M_SC 077 /* sector mask */ +#define DA_V_TK 6 /* track pos */ +#define DA_M_TK 077 /* track mask */ +#define GET_SC(x) (((x) >> DA_V_SC) & DA_M_SC) +#define GET_TK(x) (((x) >> DA_V_TK) & DA_M_TK) +#define DA_INV 0070000 /* inv addr */ +#define DA_IGN 0100000 /* ignored */ + +/* RSDT - drive type - offset 6 */ + +#define RS_DT_OF 6 + +/* RSLA - look ahead register - offset 7 */ + +#define RS_LA_OF 7 + +/* This controller supports many two disk drive types: + + type #words/ #sectors/ #tracks/ + sector track drive + + RS03 64 64 64 =256KW + RS04 128 64 640 =512KW + + 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. +*/ + +uint16 rscs1[RS_NUMDR] = { 0 }; /* control/status 1 */ +uint16 rsda[RS_NUMDR] = { 0 }; /* track/sector */ +uint16 rsds[RS_NUMDR] = { 0 }; /* drive status */ +uint16 rser[RS_NUMDR] = { 0 }; /* error status */ +uint16 rsmr[RS_NUMDR] = { 0 }; /* maint register */ +uint8 rswlk[RS_NUMDR] = { 0 }; /* wlk switches */ +int32 rs_stopioe = 1; /* stop on error */ +int32 rs_wait = 10; /* rotate time */ +static const char *rs_fname[CS1_N_FNC] = { + "NOP", "01", "02", "03", "DCLR", "05", "06", "07", + "10", "11", "12", "13", "SCH", "15", "16", "17", + "20", "21", "22", "23", "WRCHK", "25", "26", "27", + "WRITE", "31", "32", "33", "READ", "35", "36", "37" + }; + +t_stat rs_mbrd (int32 *data, int32 ofs, int32 drv); +t_stat rs_mbwr (int32 data, int32 ofs, int32 drv); +t_stat rs_svc (UNIT *uptr); +t_stat rs_reset (DEVICE *dptr); +t_stat rs_attach (UNIT *uptr, char *cptr); +t_stat rs_detach (UNIT *uptr); +t_stat rs_boot (int32 unitno, DEVICE *dptr); +void rs_set_er (int32 flg, int32 drv); +void rs_clr_as (int32 mask); +void rs_update_ds (int32 flg, int32 drv); +t_stat rs_go (int32 drv); +t_stat rs_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +int32 rs_abort (void); +t_stat rs_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +char *rs_description (DEVICE *dptr); + +/* RS data structures + + rs_dev RS device descriptor + rs_unit RS unit list + rs_reg RS register list + rs_mod RS modifier list +*/ + +DIB rs_dib = { MBA_RS, 0, &rs_mbrd, &rs_mbwr, 0, 0, 0, { &rs_abort } }; + +UNIT rs_unit[] = { + { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ + UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, + { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ + UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, + { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ + UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, + { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ + UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, + { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ + UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, + { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ + UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, + { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ + UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, + { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ + UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) } + }; + +REG rs_reg[] = { + { BRDATAD (CS1, rscs1, DEV_RDX, 16, RS_NUMDR, "control/status 1") }, + { BRDATAD (DA, rsda, DEV_RDX, 16, RS_NUMDR, "track/sector") }, + { BRDATAD (DS, rsds, DEV_RDX, 16, RS_NUMDR, "drive status") }, + { BRDATAD (ER, rser, DEV_RDX, 16, RS_NUMDR, "error status") }, + { BRDATAD (MR, rsmr, DEV_RDX, 16, RS_NUMDR, "maint register") }, + { BRDATAD (WLKS, rswlk, DEV_RDX, 6, RS_NUMDR, "write lock switches") }, + { DRDATAD (TIME, rs_wait, 24, "rotate time"), REG_NZ + PV_LEFT }, + { URDATAD (CAPAC, rs_unit[0].capac, 10, T_ADDR_W, 0, + RS_NUMDR, PV_LEFT | REG_HRO, "Capacity") }, + { FLDATAD (STOP_IOE, rs_stopioe, 0, "stop on I/O error") }, + { NULL } + }; + +MTAB rs_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "MASSBUS", NULL, NULL, &mba_show_num, NULL, "Display Massbus Address" }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL, NULL, NULL, "Write enable disk drive" }, + { UNIT_WLK, UNIT_WLK, "write lockable", "LOCKED", NULL, NULL, NULL, "Write lock disk drive" }, + { (UNIT_DTYPE|UNIT_ATT), (RS03_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, + "RS03", NULL, NULL }, + { (UNIT_DTYPE|UNIT_ATT), (RS04_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, + "RS04", NULL, NULL }, + { (UNIT_AUTO|UNIT_DTYPE|UNIT_ATT), (RS03_DTYPE << UNIT_V_DTYPE), + "RS03", NULL, NULL }, + { (UNIT_AUTO|UNIT_DTYPE|UNIT_ATT), (RS04_DTYPE << UNIT_V_DTYPE), + "RS04", NULL, NULL }, + { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, + { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL, NULL, NULL, "set type based on file size at ATTACH" }, + { (UNIT_AUTO|UNIT_DTYPE), (RS03_DTYPE << UNIT_V_DTYPE), + NULL, "RS03", &rs_set_size, NULL, NULL, "Set drive type RS03" }, + { (UNIT_AUTO|UNIT_DTYPE), (RS04_DTYPE << UNIT_V_DTYPE), + NULL, "RS04", &rs_set_size, NULL, NULL, "Set drive type RS04" }, + { 0 } + }; + +DEVICE rs_dev = { + "RS", rs_unit, rs_reg, rs_mod, + RS_NUMDR, DEV_RADIX, 19, 1, DEV_RADIX, 16, + NULL, NULL, &rs_reset, + &rs_boot, &rs_attach, &rs_detach, + &rs_dib, DEV_DISABLE|DEV_DIS|DEV_UBUS|DEV_QBUS|DEV_MBUS|DEV_DEBUG, 0, + NULL, NULL, NULL, &rs_help, NULL, NULL, + &rs_description + }; + +/* Massbus register read */ + +t_stat rs_mbrd (int32 *data, int32 ofs, int32 drv) +{ +uint32 val, dtype, i; +UNIT *uptr; + +rs_update_ds (0, drv); /* update ds */ +uptr = rs_dev.units + drv; /* get unit */ +if (uptr->flags & UNIT_DIS) { /* nx disk */ + *data = 0; + return MBE_NXD; + } +dtype = GET_DTYPE (uptr->flags); /* get drive type */ +ofs = ofs & MBA_RMASK; /* mask offset */ + +switch (ofs) { /* decode offset */ + + case RS_CS1_OF: /* RSCS1 */ + val = (rscs1[drv] & CS1_RW) | CS1_DVA; /* DVA always set */ + break; + + case RS_DA_OF: /* RSDA */ + val = rsda[drv]; + break; + + case RS_DS_OF: /* RSDS */ + val = rsds[drv] & ~DS_MBZ; + break; + + case RS_ER_OF: /* RSER */ + val = rser[drv] & ~ER_MBZ; + break; + + case RS_AS_OF: /* RSAS */ + val = 0; + for (i = 0; i < RS_NUMDR; i++) { + if (rsds[i] & DS_ATA) + val |= (AS_U0 << i); + } + break; + + case RS_LA_OF: /* RSLA */ + val = GET_POS (rs_wait); + break; + + case RS_MR_OF: /* RSMR */ + val = rsmr[drv]; + break; + + case RS_DT_OF: /* RSDT */ + val = dtype? RS04_ID: RS03_ID; + break; + + default: /* all others */ + *data = 0; + return MBE_NXR; + } + +*data = val; +return SCPE_OK; +} + +/* Massbus register write */ + +t_stat rs_mbwr (int32 data, int32 ofs, int32 drv) +{ +int32 dtype; +UNIT *uptr; + +uptr = rs_dev.units + drv; /* get unit */ +if (uptr->flags & UNIT_DIS) /* nx disk */ + return MBE_NXD; +if ((ofs != RS_AS_OF) && sim_is_active (uptr)) { /* unit busy? */ + rs_set_er (ER_RMR, drv); /* won't write */ + rs_update_ds (0, drv); + return SCPE_OK; + } +dtype = GET_DTYPE (uptr->flags); /* get drive type */ +ofs = ofs & MBA_RMASK; /* mask offset */ + +switch (ofs) { /* decode PA<5:1> */ + + case RS_CS1_OF: /* RSCS1 */ + rscs1[drv] = data & CS1_RW; + if (data & CS1_GO) /* start op */ + return rs_go (drv); + break; + + case RS_DA_OF: /* RSDA */ + rsda[drv] = data; + break; + + case RS_AS_OF: /* RSAS */ + rs_clr_as (data); + break; + + case RS_MR_OF: /* RSMR */ + rsmr[drv] = data; + break; + + case RS_ER_OF: /* RSER */ + case RS_DS_OF: /* RSDS */ + case RS_LA_OF: /* RSLA */ + case RS_DT_OF: /* RSDT */ + break; /* read only */ + + default: /* all others */ + return MBE_NXR; + } /* end switch */ + +rs_update_ds (0, drv); /* update status */ +return SCPE_OK; +} + +/* Initiate operation - unit not busy, function set */ + +t_stat rs_go (int32 drv) +{ +int32 fnc, dtype, t; +UNIT *uptr; + +fnc = GET_FNC (rscs1[drv]); /* get function */ +if (DEBUG_PRS (rs_dev)) + fprintf (sim_deb, ">>RS%d STRT: fnc=%s, ds=%o, da=%o, er=%o\n", + drv, rs_fname[fnc], rsds[drv], rsda[drv], rser[drv]); +uptr = rs_dev.units + drv; /* get unit */ +rs_clr_as (AS_U0 << drv); /* clear attention */ +dtype = GET_DTYPE (uptr->flags); /* get drive type */ +if ((fnc != FNC_DCLR) && (rsds[drv] & DS_ERR)) { /* err & ~clear? */ + rs_set_er (ER_ILF, drv); /* not allowed */ + rs_update_ds (DS_ATA, drv); /* set attention */ + return MBE_GOE; + } + +switch (fnc) { /* case on function */ + + case FNC_DCLR: /* drive clear */ + rser[drv] = 0; /* clear errors */ + case FNC_NOP: /* no operation */ + return SCPE_OK; + + case FNC_SEARCH: /* search */ + case FNC_WRITE: /* write */ + case FNC_WCHK: /* write check */ + case FNC_READ: /* read */ + if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + rs_set_er (ER_UNS, drv); /* unsafe */ + break; + } + if (rsda[drv] & DA_INV) { /* bad address? */ + rs_set_er (ER_IAE, drv); + break; + } + rsds[drv] = rsds[drv] & ~DS_RDY; /* clr drive rdy */ + if (fnc == FNC_SEARCH) /* search? */ + rsds[drv] = rsds[drv] | DS_PIP; /* set PIP */ + t = abs (rsda[drv] - GET_POS (rs_wait)); /* pos diff */ + if (t < 1) /* min time */ + t = 1; + sim_activate (uptr, rs_wait * t); /* schedule */ + return SCPE_OK; + + default: /* all others */ + rs_set_er (ER_ILF, drv); /* not supported */ + break; + } + +rs_update_ds (DS_ATA, drv); /* set attn, req int */ +return MBE_GOE; +} + +/* Abort opertion - there is a data transfer in progress */ + +int32 rs_abort (void) +{ +return rs_reset (&rs_dev); +} + +/* Service unit timeout + + Complete search or data transfer command + Unit must exist - can't remove an active unit + Drives are buffered in memory - no IO errors +*/ + +t_stat rs_svc (UNIT *uptr) +{ +int32 i, fnc, dtype, drv; +int32 wc, abc, awc, mbc, da; +uint16 *fbuf = (uint16 *)uptr->filebuf; + +dtype = GET_DTYPE (uptr->flags); /* get drive type */ +drv = (int32) (uptr - rs_dev.units); /* get drv number */ +da = rsda[drv] * RS_NUMWD (dtype); /* get disk addr */ +fnc = GET_FNC (rscs1[drv]); /* get function */ + +if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + rs_set_er (ER_UNS, drv); /* set drive error */ + if (fnc >= FNC_XFR) /* xfr? set done */ + mba_set_don (rs_dib.ba); + rs_update_ds (DS_ATA, drv); /* set attn */ + return (rs_stopioe? SCPE_UNATT: SCPE_OK); + } +rsds[drv] = (rsds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */ + +switch (fnc) { /* case on function */ + + case FNC_SEARCH: /* search */ + rs_update_ds (DS_ATA, drv); + break; + + case FNC_WRITE: /* write */ + if ((uptr->flags & UNIT_WLK) && /* write locked? */ + (GET_TK (rsda[drv]) <= (int32) rswlk[drv])) { + rs_set_er (ER_WLE, drv); /* set drive error */ + mba_set_exc (rs_dib.ba); /* set exception */ + rs_update_ds (DS_ATA, drv); /* set attn */ + return SCPE_OK; + } + case FNC_WCHK: /* write check */ + case FNC_READ: /* read */ + if (rsda[drv] & DA_INV) { /* bad addr? */ + rs_set_er (ER_IAE, drv); /* set error */ + mba_set_exc (rs_dib.ba); /* set exception */ + rs_update_ds (DS_ATA, drv); /* set attn */ + break; + } + fbuf = fbuf + da; /* ptr into buffer */ + mbc = mba_get_bc (rs_dib.ba); /* get byte count */ + wc = (mbc + 1) >> 1; /* convert to words */ + if ((da + wc) > RS_SIZE (dtype)) { /* disk overrun? */ + rs_set_er (ER_AOE, drv); /* set err */ + wc = RS_SIZE (dtype) - da; /* trim xfer */ + mbc = wc << 1; /* trim mb count */ + } + if (fnc == FNC_WRITE) { /* write? */ + abc = mba_rdbufW (rs_dib.ba, mbc, fbuf); /* rd mem to buf */ + wc = (abc + 1) >> 1; /* actual # wds */ + awc = (wc + (RS_NUMWD (dtype) - 1)) & ~(RS_NUMWD (dtype) - 1); + for (i = wc; i < awc; i++) /* fill buf */ + fbuf[i] = 0; + if ((da + awc) > (int32) uptr->hwmark) /* update hw mark*/ + uptr->hwmark = da + awc; + } /* end if wr */ + else if (fnc == FNC_READ) /* read */ + mba_wrbufW (rs_dib.ba, mbc, fbuf); /* wri buf to mem */ + else mba_chbufW (rs_dib.ba, mbc, fbuf); /* check vs mem */ + + da = da + wc + (RS_NUMWD (dtype) - 1); + if (da >= RS_SIZE (dtype)) + rsds[drv] = rsds[drv] | DS_LST; + rsda[drv] = da / RS_NUMWD (dtype); + mba_set_don (rs_dib.ba); /* set done */ + rs_update_ds (0, drv); /* update ds */ + break; + } /* end case func */ + +if (DEBUG_PRS (rs_dev)) + fprintf (sim_deb, ">>RS%d DONE: fnc=%s, ds=%o, da=%o, er=%d\n", + drv, rs_fname[fnc], rsds[drv], rsda[drv], rser[drv]); +return SCPE_OK; +} + +/* Set drive error */ + +void rs_set_er (int32 flag, int32 drv) +{ +rser[drv] = rser[drv] | flag; +rsds[drv] = rsds[drv] | DS_ATA; +mba_upd_ata (rs_dib.ba, 1); +return; +} + +/* Clear attention flags */ + +void rs_clr_as (int32 mask) +{ +uint32 i, as; + +for (i = as = 0; i < RS_NUMDR; i++) { + if (mask & (AS_U0 << i)) + rsds[i] &= ~DS_ATA; + if (rsds[i] & DS_ATA) + as = 1; + } +mba_upd_ata (rs_dib.ba, as); +return; +} + +/* Drive status update */ + +void rs_update_ds (int32 flag, int32 drv) +{ +if (flag & DS_ATA) + mba_upd_ata (rs_dib.ba, 1); +if (rs_unit[drv].flags & UNIT_DIS) { + rsds[drv] = rser[drv] = 0; + return; + } +else rsds[drv] = (rsds[drv] | DS_DPR) & ~(DS_ERR | DS_WLK); +if (rs_unit[drv].flags & UNIT_ATT) { + rsds[drv] = rsds[drv] | DS_MOL; + if ((rs_unit[drv].flags & UNIT_WLK) && + (GET_TK (rsda[drv]) <= (int32) rswlk[drv])) + rsds[drv] = rsds[drv] | DS_WLK; + } +if (rser[drv]) + rsds[drv] = rsds[drv] | DS_ERR; +rsds[drv] = rsds[drv] | flag; +return; +} + +/* Device reset */ + +t_stat rs_reset (DEVICE *dptr) +{ +int32 i; +UNIT *uptr; + +mba_set_enbdis (MBA_RS, rs_dev.flags & DEV_DIS); +for (i = 0; i < RS_NUMDR; i++) { + uptr = rs_dev.units + i; + sim_cancel (uptr); + rscs1[i] = 0; + rser[i] = 0; + rsda[i] = 0; + rsmr[i] = 0; + rsds[i] = DS_RDY; + rs_update_ds (0, i); /* upd drive status */ + } +return SCPE_OK; +} + +/* Device attach */ + +t_stat rs_attach (UNIT *uptr, char *cptr) +{ +int32 drv, p; +t_stat r; + +uptr->capac = RS_SIZE (GET_DTYPE (uptr->flags)); +r = attach_unit (uptr, cptr); /* attach unit */ +if (r != SCPE_OK) /* error? */ + return r; +drv = (int32) (uptr - rs_dev.units); /* get drv number */ +rsds[drv] = DS_MOL | DS_RDY | DS_DPR; /* upd drv status */ +rser[drv] = 0; +rs_update_ds (DS_ATA, drv); /* upd drive status */ + +if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ + return SCPE_OK; +p = sim_fsize (uptr->fileref); /* get file size */ +if (((p + 1) >> 1) <= RS03_SIZE) { + uptr->flags &= ~UNIT_DTYPE; + uptr->capac = RS03_SIZE; + } +else { + uptr->flags |= UNIT_DTYPE; + uptr->capac = RS04_SIZE; + } +return SCPE_OK; +} + +/* Device detach */ + +t_stat rs_detach (UNIT *uptr) +{ +int32 drv; +extern int32 sim_is_running; + +if (!(uptr->flags & UNIT_ATT)) /* attached? */ + return SCPE_OK; +drv = (int32) (uptr - rs_dev.units); /* get drv number */ +rsds[drv] = 0; +if (!sim_is_running) /* from console? */ + rs_update_ds (DS_ATA, drv); /* request intr */ +return detach_unit (uptr); +} + +/* Set size command validation routine */ + +t_stat rs_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 dtype = GET_DTYPE (val); + +if (uptr->flags & UNIT_ATT) + return SCPE_ALATT; +uptr->capac = RS_SIZE (dtype); +return SCPE_OK; +} + +/* Set bad block routine */ + +/* Boot routine */ + +#define BOOT_START 02000 /* start */ +#define BOOT_ENTRY (BOOT_START + 002) /* entry */ +#define BOOT_UNIT (BOOT_START + 010) /* unit number */ +#define BOOT_CSR (BOOT_START + 014) /* CSR */ +#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint16)) + +static const uint16 boot_rom[] = { + 0042123, /* "SD" */ + 0012706, BOOT_START, /* mov #boot_start, sp */ + 0012700, 0000000, /* mov #unit, r0 */ + 0012701, 0172040, /* mov #RSCS1, r1 */ + 0012761, 0000040, 0000010, /* mov #CS2_CLR, 10(r1) ; reset */ + 0010061, 0000010, /* mov r0, 10(r1) ; set unit */ + 0012761, 0177000, 0000002, /* mov #-512., 2(r1) ; set wc */ + 0005061, 0000004, /* clr 4(r1) ; clr ba */ + 0005061, 0000006, /* clr 6(r1) ; clr da */ + 0012711, 0000071, /* mov #READ+GO, (r1) ; read */ + 0105711, /* tstb (r1) ; wait */ + 0100376, /* bpl .-2 */ + 0005002, /* clr R2 */ + 0005003, /* clr R3 */ + 0012704, BOOT_START+020, /* mov #start+020, r4 */ + 0005005, /* clr R5 */ + 0105011, /* clrb (r1) */ + 0005007 /* clr PC */ + }; + +t_stat rs_boot (int32 unitno, DEVICE *dptr) +{ +int32 i; +extern int32 saved_PC; +extern uint16 *M; +UNIT *uptr = rs_dev.units + unitno; + +for (i = 0; i < BOOT_LEN; i++) + M[(BOOT_START >> 1) + i] = boot_rom[i]; +M[BOOT_UNIT >> 1] = unitno & (RS_NUMDR - 1); +M[BOOT_CSR >> 1] = mba_get_csr (rs_dib.ba) & DMASK; +saved_PC = BOOT_ENTRY; +return SCPE_OK; +} + +t_stat rs_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +fprintf (st, "RS03/RS04 Massbus disk controller (RS)\n\n"); +fprintf (st, "Options include the ability to set units write enabled or write locked,\n"); +fprintf (st, "to set the drive type to RS03, RS04, or autosize:\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 RS device supports the BOOT command.\n"); +fprint_reg_help (st, dptr); +fprintf (st, "\nError handling is as follows:\n\n"); +fprintf (st, " error STOP_IOE processed as\n"); +fprintf (st, " not attached 1 report error and stop\n"); +fprintf (st, " 0 disk not ready\n\n"); +fprintf (st, " end of file x assume rest of disk is zero\n"); +fprintf (st, " OS I/O error x report error and stop\n"); +return SCPE_OK; +} + +char *rs_description (DEVICE *dptr) +{ +return "RS03/RS04 Massbus disk controller"; +} diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index 7a2c787a..ffa3aa93 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -1,6 +1,6 @@ /* pdp11_sys.c: PDP-11 simulator interface - Copyright (c) 1993-2012, Robert M Supnik + Copyright (c) 1993-2013, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 02-Sep-13 RMS Added third Massbus, RS03/RS04 29-Apr-12 RMS Fixed compiler warning (Mark Pizzolato) 19-Nov-08 RMS Moved I/O support routines to I/O library 15-May-08 RMS Added KE11-A, DC11 support @@ -92,6 +93,7 @@ extern DEVICE rx_dev; extern DEVICE ry_dev; extern DEVICE mba_dev[]; extern DEVICE rp_dev; +extern DEVICE rs_dev; extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev; extern DEVICE tm_dev; extern DEVICE tq_dev; @@ -131,6 +133,7 @@ DEVICE *sim_devices[] = { &sys_dev, &mba_dev[0], &mba_dev[1], + &mba_dev[2], &clk_dev, &pclk_dev, &ptr_dev, @@ -153,6 +156,7 @@ DEVICE *sim_devices[] = { &rx_dev, &ry_dev, &rp_dev, + &rs_dev, &rq_dev, &rqb_dev, &rqc_dev, diff --git a/Visual Studio Projects/PDP11.vcproj b/Visual Studio Projects/PDP11.vcproj index fc04e0f1..3688269f 100644 --- a/Visual Studio Projects/PDP11.vcproj +++ b/Visual Studio Projects/PDP11.vcproj @@ -291,6 +291,10 @@ RelativePath="..\PDP11\pdp11_rq.c" > + + diff --git a/descrip.mms b/descrip.mms index c727c74f..3a080993 100644 --- a/descrip.mms +++ b/descrip.mms @@ -534,7 +534,8 @@ PDP11_SOURCE1 = $(PDP11_DIR)PDP11_FP.C,$(PDP11_DIR)PDP11_CPU.C,\ $(PDP11_DIR)PDP11_SYS.C,$(PDP11_DIR)PDP11_TC.C, \ $(PDP11_DIR)PDP11_CPUMOD.C,$(PDP11_DIR)PDP11_CR.C,\ $(PDP11_DIR)PDP11_TA.C,$(PDP11_DIR)PDP11_DMC.C,\ - $(PDP11_DIR)PDP11_DUP.C,$(PDP11_DIR)PDP11_IO_LIB.C + $(PDP11_DIR)PDP11_DUP.C,$(PDP11_DIR)PDP11_RS.C,\ + $(PDP11_DIR)PDP11_IO_LIB.C PDP11_LIB2 = $(LIB_DIR)PDP11L2-$(ARCH).OLB PDP11_SOURCE2 = $(PDP11_DIR)PDP11_TM.C,$(PDP11_DIR)PDP11_TS.C,\ $(PDP11_DIR)PDP11_IO.C,$(PDP11_DIR)PDP11_RQ.C,\ diff --git a/makefile b/makefile index f8b4304c..4922ee45 100644 --- a/makefile +++ b/makefile @@ -711,7 +711,7 @@ PDP11 = ${PDP11D}/pdp11_fp.c ${PDP11D}/pdp11_cpu.c ${PDP11D}/pdp11_dz.c \ ${PDP11D}/pdp11_cr.c ${PDP11D}/pdp11_rf.c ${PDP11D}/pdp11_dl.c \ ${PDP11D}/pdp11_ta.c ${PDP11D}/pdp11_rc.c ${PDP11D}/pdp11_kg.c \ ${PDP11D}/pdp11_ke.c ${PDP11D}/pdp11_dc.c ${PDP11D}/pdp11_dmc.c \ - ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_rs.c ${PDP11D}/pdp11_io_lib.c PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT}