1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-04-26 20:18:04 +00:00
Files
rcornwell.sims/PDP10/ks10_rp.c
2021-04-19 18:14:53 -07:00

1267 lines
46 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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 */
#define CS1_MCPE 0020000 /* */
#define CS1_TRE 0040000 /* Set if CS2 0177400 */
#define CS1_SC 0100000 /* Set if TRE or ATTN */
#define CSX_BUSY 02 /* RH11 is doing a transfer */
/* 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 */
/* RPDS - 176712 - drive status */
#define STATUS us10
#define DS_DF5 0000001 /* Drive forward 5in/sec */
#define DS_DF20 0000002 /* Drive forward 20in/sec */
#define DS_DIGB 0000004 /* Drive inner gaurd band */
#define DS_GRV 0000010 /* Go reverse read */
#define DS_DL64 0000020 /* Difference less 64 */
#define DS_DE1 0000040 /* Difference equal 1 */
#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 */
/* 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 u6
#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 */
#define PMR_DMD 0000001 /* Enable Diag mode */
#define PMR_DCLK 0000002 /* Diag Data Clock */
#define PMR_DIND 0000004 /* Diag Index Pulse */
#define PMR_DSCK 0000010 /* Diag Sector Clock */
#define PMR_DRDD 0000020 /* Diag Read Data */
#define PMR_DWRD 0000040 /* Diag Write Data */
#define PMR_ECE 0000100 /* In ECE field */
#define PMR_DFE 0000200 /* In Data Field */
#define PMR_ZD 0000400 /* After ECE field */
#define PMR_MSK 0000037 /* Mask bits in PMR */
/* RPDT - 176726 - drive type */
/* RPSN - 176730 - serial number */
/* us10 */
/* RPOF - 176732 - offset register */
#define RPOF_OFF 0000077 /* Offset value */
#define RPOF_OFNU 0000100
#define RPOF_OFD 0000200 /* Offset direction */
#define RPOF_HCI 0002000 /* Head compare inhibited */
#define RPOF_ECI 0004000 /* Error correct inhibit */
#define RPOF_FMT22 0010000 /* Format 22/20 sectors */
#define RPOF_SCG 0100000 /* Sign change */
/* 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 - unimplemented */
/* RPER3 - 176742 - error status 3 - more unsafe conditions - unimplemented */
//#define ERR2 us9
/* us9 */
//#define ERR3 us10
#define DATAPTR us9
/* 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
RM03 30 5 823 =67MB
RM05 30 19 823 =256MB
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)
#define RM03_DTYPE 3
#define RM03_SECT 30
#define RM03_SURF 5
#define RM03_CYL 823
#define RM03_DEV 020024
#define RM03_SIZE (RM03_SECT * RM03_SURF * RM03_CYL * RP_NUMWD)
#define RM05_DTYPE 4
#define RM05_SECT 30
#define RM05_SURF 19
#define RM05_CYL 823
#define RM05_DEV 020027
#define RM05_SIZE (RM05_SECT * RM05_SURF * RM05_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 },
{ RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV },
{ RM05_SECT, RM05_SURF, RM05_CYL, RM05_SIZE, RM05_DEV },
{ 0 }
};
int rp_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access);
int rp_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access);
uint16 rp_vect(struct pdp_dib *dibp);
void rp_setattn(UNIT *uptr);
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_dba;
uint16 rp_dbb;
t_addr rp_ba;
uint16 rp_cs2;
uint8 rp_ie;
uint16 rp_err2;
uint16 rp_err3;
uint16 rp_rmr[NUM_UNITS_RP];
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, &rp_vect, 0};
MTAB rp_mod[] = {
{ MTAB_XTD|MTAB_VUN, 0, "write enabled", "WRITEENABLED",
&set_writelock, &show_writelock, NULL, "Write enable drive" },
{ MTAB_XTD|MTAB_VUN, 1, NULL, "LOCKED",
&set_writelock, NULL, NULL, "Write lock drive" },
{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 },
{UNIT_DTYPE, (RM03_DTYPE << UNIT_V_DTYPE), "RM03", "RM03", &rp_set_type },
{UNIT_DTYPE, (RM05_DTYPE << UNIT_V_DTYPE), "RM05", "RM05", &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(UNIT, rp_cs2, 16)},
{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(DEVICE *dptr, t_addr addr, uint16 data, int32 access) {
int i;
int rp_unit = rp_cs2 & 07;
UNIT *uptr = &rpa_unit[rp_unit];
int dtype = GET_DTYPE(uptr->flags);
switch(addr & 076) {
/* u3 low */
case 000: /* RPC - 176700 - control */
sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o Status=%06o\n", rp_unit, uptr->CMD);
if (rp_cs2 & CS2_PAT) {
uba_set_parity(rpa_dib.uba_ctl);
uptr->CMD |= (ER1_PAR << 16);
break;
}
if (access == BYTE && addr & 1)
break;
rp_ie &= ~(CS1_IE);
rp_ie |= data & (CS1_IE);
if ((uptr->CMD & CS1_GO) != 0) {
uptr->CMD |= (ER1_RMR << 16);
sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o not ready %02o %06o\n", rp_unit,
addr & 077, data);
return 0;
}
rp_ba = ((data << 8) & 0600000) | (rp_ba & 0177777);
uptr->CMD &= ~077;
uptr->CMD |= data & 076;
/* Check if GO bit set */
if ((data & 1) == 0) {
if (data & CS1_TRE)
rp_cs2 &= (CS2_IR|CS2_OR|CS2_UAI|CS2_PAT|CS2_UNIT);
sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o no go %06o\n", rp_unit, data);
return 0; /* No, nop */
}
if ((uptr->flags & UNIT_ATT) == 0) {
sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o unattached %06o\n", rp_unit, data);
return 0; /* No, nop */
}
uba_clr_irq(&rpa_dib);
uptr->CMD &= 0777;
switch (GET_FNC(data)) {
case FNC_NOP:
break;
case FNC_RECAL: /* recalibrate */
uptr->DA &= ~0177777;
uptr->STATUS |= DS_PIP;
uptr->CMD |= CS1_GO;
break;
case FNC_SEEK: /* seek */
if (GET_FNC(data) == FNC_SEEK &&
GET_CY(uptr->DA) == (uptr->CCYL & 01777)) {
uptr->STATUS |= DS_ATA;
rp_setattn(uptr);
break;
}
/* Fall through */
case FNC_SEARCH: /* search */
if (rp_rmr[rp_unit] & 1) {
int sect = rp_drv_tab[dtype].sect;
if (GET_CY(uptr->DA) != (uptr->CCYL & 01777)) {
uptr->STATUS |= DS_PIP;
}
uptr->CCYL = (uptr->CCYL & (0177777 << 16)) | GET_CY(uptr->DA);
if ((uptr->CCYL & (RPOF_FMT22 << 16)) != 0)
sect += 2;
if ((GET_CY(uptr->DA) >= rp_drv_tab[dtype].cyl) ||
(GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) ||
(GET_SC(uptr->DA) >= sect)) {
uptr->STATUS |= DS_ATA;
uptr->CMD |= (ER1_IAE << 16);
rp_setattn(uptr);
break;
}
} else
if ((GET_CY(uptr->DA) >= rp_drv_tab[dtype].cyl) ||
(GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) ||
(GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect)) {
uptr->STATUS |= DS_ATA;
uptr->CMD |= (ER1_IAE << 16);
rp_setattn(uptr);
break;
}
/* Fall through */
case FNC_RETURN: /* return to center */
case FNC_OFFSET: /* offset */
case FNC_UNLOAD: /* unload */
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 */
if (GET_CY(uptr->DA) != (uptr->CCYL & 01777)) {
uptr->STATUS |= DS_PIP;
}
if (GET_FNC(data) >= FNC_XFER)
rp_ie |= CSX_BUSY;
uptr->CMD |= CS1_GO;
CLR_BUF(uptr);
uptr->DATAPTR = 0;
break;
case FNC_DCLR: /* drive clear */
uptr->STATUS &= DS_VV;
uptr->DA &= 003400177777;
uptr->CCYL &= 0177777;
rp_rmr[rp_unit] = 0;
uptr->CMD &= ~CS1_GO;
break;
case FNC_PRESET: /* read-in preset */
uptr->DA = 0;
uptr->CCYL &= 0177777;
/* Fall through */
case FNC_PACK: /* pack acknowledge */
uptr->STATUS |= DS_VV;
/* Fall through */
case FNC_RELEASE: /* port release */
break;
default:
uptr->STATUS |= DS_ATA;
uptr->CMD |= (ER1_ILF << 16);
}
if (GET_FNC(data) >= FNC_XFER)
uptr->STATUS &= (DS_VV|DS_PIP);
rp_cs2 &= (CS2_IR|CS2_OR|CS2_UAI|CS2_PAT|CS2_UNIT);
if ((uptr->CMD & CS1_GO) != 0 && ((rp_rmr[rp_unit] & 1) == 0))
sim_activate(uptr, 1000);
sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o AStatus=%06o %06o %06o\n", rp_unit, uptr->CMD, rp_cs2, uptr->STATUS);
break;
case 002: /* RPWC - 176702 - word count */
if ((rp_ie & (CSX_BUSY)) != 0) {
uptr->CMD |= (ER1_RMR << 16);
sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o not ready %02o %06o\n", rp_unit,
addr & 077, data);
return 0;
}
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 ((rp_ie & (CSX_BUSY)) != 0) {
uptr->CMD |= (ER1_RMR << 16);
sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o not ready %02o %06o\n", rp_unit,
addr & 077, data);
return 0;
}
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_cs2 & 0377);
}
rp_cs2 = ((CS2_DLT|CS2_WCE|CS2_NED|CS2_NEM|CS2_PGE|CS2_MDPE) & rp_cs2) |
((CS2_UAI|CS2_PAT|CS2_UNIT) & data);
if (data & CS2_CLR) {
rp_reset(&rpa_dev);
}
rp_cs2 |= CS2_IR;
rp_unit = rp_cs2 & 07;
if (rpa_unit[rp_cs2 & CS2_UNIT].flags & UNIT_DIS)
rp_cs2 |= CS2_NED;
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;
break;
case 016: /* RPAS - 176716 - attention summary */
if (access == BYTE && addr & 1)
break;
for (i = 0; i < 8; i++) {
if (data & (1<<i)) {
UNIT *u = &rpa_unit[i];
u->STATUS &= ~DS_ATA;
}
}
break;
case 024: /* RPMR - 176724 - maintenace register */
/* LA_REG has 10 bits for position in sector */
if (data & 1) {
if ((data & 076) == 0) {
if (rp_rmr[rp_unit] & 010)
uptr->LA_REG ++;
if (rp_rmr[rp_unit] & 04)
uptr->LA_REG = 0;
}
rp_rmr[rp_unit] = data;
} else
rp_rmr[rp_unit] = 0;
break;
case 020: /* RPLA - 176720 - look ahead register */
case 026: /* RPDT - 176726 - drive type */
break;
case 022: /* RPDB - 176722 - data buffer */
if ((rp_cs2 & CS2_IR) == 0) {
rp_cs2 |= CS2_DLT;
break;
}
rp_dba = rp_dbb;
rp_dbb = data;
if (rp_cs2 & CS2_IR)
rp_dba = rp_dbb;
rp_cs2 |= CS2_OR;
rp_cs2 &= ~CS2_IR;
break;
case 032: /* RPOF - 176732 - offset register */
uptr->CCYL &= 0177777;
uptr->CCYL |= data << 16;
break;
case 034: /* RPDC - 176734 - desired cylinder */
if ((uptr->CMD & CS1_GO) != 0) {
uptr->CMD |= (ER1_RMR << 16);
sim_debug(DEBUG_DETAIL, &rpa_dev, "RP%o not ready %02o %06o\n", rp_unit,
addr & 077, data);
break;
}
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 */
rp_err2 = data;
break;
case 042: /* RPER3 - 176742 - error status 3 - more unsafe conditions */
rp_err3 = data;
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(DEVICE *dptr, t_addr addr, uint16 *data, int32 access) {
int rp_unit = rp_cs2 & 07;
UNIT *uptr = &rpa_unit[rp_unit];
uint16 temp = 0;
int i;
switch(addr & 076) {
case 000: /* RPC - 176700 - control */
temp = uptr->CMD & 077;
temp |= (uint16)(rp_ie & (CS1_IE));
temp |= (rp_ba & 0600000) >> 8;
if ((rp_ie & CSX_BUSY) == 0)
temp |= CS1_RDY;
if (uptr->flags & UNIT_ATT)
temp |= CS1_DVA;
if (rp_cs2 & (CS2_MDPE|CS2_MXF|CS2_PGE|CS2_NEM|CS2_NED|CS2_PE|CS2_WCE|CS2_DLT))
temp |= CS1_TRE|CS1_SC;
for (i = 0; i < 8; i++) {
UNIT *u = &rpa_unit[i];
if (u->STATUS & DS_ATA) {
temp |= CS1_SC;
break;
}
}
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_cs2;
break;
case 012: /* RPDS - 176712 - drive status */
temp = uptr->STATUS;
if (((uptr->CMD >> 16) & 0177777) != 0 || rp_err2 != 0 || rp_err3 != 0)
temp |= DS_ERR;
if ((uptr->flags & UNIT_DIS) == 0)
temp |= DS_DPR;
if ((uptr->flags & UNIT_ATT) != 0)
temp |= DS_MOL;
if ((uptr->flags & UNIT_WPRT) != 0)
temp |= DS_WRL;
if ((uptr->CMD & CS1_GO) == 0)
temp |= DS_DRY;
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->STATUS & DS_ATA) {
temp |= 1 << i;
}
}
break;
case 020: /* RPLA - 176720 - look ahead register */
if ((uptr->LA_REG >> 10) >= 23)
uptr->LA_REG = 0;
temp = GET_SC(uptr->DA) << 6;
temp ^= ((uptr->LA_REG + 1) >> 4) & 07760;
if ((rp_rmr[rp_unit] & 1) == 0)
uptr->LA_REG+=1024;
break;
case 022: /* RPDB - 176722 - data buffer */
if ((rp_cs2 & CS2_OR) == 0) {
rp_cs2 |= CS2_DLT;
break;
}
temp = rp_dba;
rp_dba = rp_dbb;
rp_cs2 &= ~CS2_OR;
rp_cs2 |= CS2_IR;
break;
case 024: /* RPMR - 176724 - maintenace register */
if (rp_rmr[rp_unit] & 1)
temp = rp_rmr[rp_unit] & PMR_MSK;
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 = GET_CY(uptr->DA);
break;
case 036: /* RPCC - 176736 - current cylinder */
temp = uptr->CCYL & 0177777;
break;
case 040: /* RPER2 - 176740 - error status 2 - drive unsafe conditions */
temp = rp_err2;
break;
case 042: /* RPER3 - 176742 - error status 3 - more unsafe conditions */
temp = rp_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 %06o\n", rp_unit,
addr & 076, temp, PC);
if (rp_cs2 & CS2_PAT) {
uba_set_parity(rpa_dib.uba_ctl);
uptr->CMD |= (ER1_PAR << 16);
}
return 0;
}
uint16
rp_vect(struct pdp_dib *dibp)
{
return dibp->uba_vect;
}
/* Set the attention flag for a unit */
void rp_setattn(UNIT *uptr)
{
uptr->STATUS |= DS_ATA;
uptr->CMD &= ~CS1_GO;
if ((rp_ie & CSX_BUSY) == 0 && (rp_ie & CS1_IE) != 0)
uba_set_irq(&rpa_dib);
}
t_stat rp_svc (UNIT *uptr)
{
int dtype = GET_DTYPE(uptr->flags);
int cyl = GET_CY(uptr->DA);
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); /* set drive error */
uptr->STATUS |= DS_ATA;
rp_ie &= ~(CSX_BUSY);
uptr->CMD &= ~CS1_GO;
if (GET_FNC(uptr->CMD) >= FNC_XFER) { /* xfr? set done */
if ((rp_ie & CSX_BUSY) == 0 && (rp_ie & CS1_IE) != 0)
uba_set_irq(&rpa_dib);
} else {
rp_setattn(uptr);
}
return (SCPE_OK);
}
/* Check if seeking */
if (uptr->STATUS & 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->STATUS &= ~DS_PIP;
sim_activate(uptr, 10);
return SCPE_OK;
}
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->STATUS &= ~DS_PIP;
uptr->DATAPTR = 0;
}
}
/* Bump sector counter */
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 */
/* 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 ||
GET_CY(uptr->DA) >= rp_drv_tab[dtype].cyl)
uptr->CMD |= (ER1_IAE << 16);
rp_setattn(uptr);
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 ||
GET_CY(uptr->DA) >= rp_drv_tab[dtype].cyl)
uptr->CMD |= (ER1_IAE << 16);
rp_setattn( uptr);
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 (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect ||
GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) {
uptr->CMD |= (ER1_IAE << 16);
uptr->STATUS |= DS_ATA;
rp_ie &= ~(CSX_BUSY);
uptr->CMD &= ~CS1_GO;
if (rp_ie & 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;
if ((rp_cs2 & CS2_UAI) == 0)
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;
if ((rp_cs2 & CS2_UAI) == 0)
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);
if ((rp_cs2 & CS2_UAI) == 0)
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->STATUS |= DS_PIP;
}
}
uptr->LA_REG = GET_SC(uptr->DA) << 10;
sim_activate(uptr, 300);
return SCPE_OK;
}
rd_end:
uptr->LA_REG = GET_SC(uptr->DA) << 10;
sim_debug(DEBUG_DETAIL, dptr, "%s%o read done\n", dptr->name, unit);
uptr->CMD &= ~CS1_GO;
rp_ie &= ~(CSX_BUSY);
if (rp_ie & CS1_IE)
uba_set_irq(&rpa_dib);
return SCPE_OK;
case FNC_WRITE: /* write */
case FNC_WRITEH: /* write w/ headers */
if (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect ||
GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) {
uptr->CMD |= (ER1_IAE << 16);
uptr->STATUS |= DS_ATA;
rp_ie &= ~(CSX_BUSY);
uptr->CMD &= ~CS1_GO;
if (rp_ie & CS1_IE)
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_done;
if ((rp_cs2 & CS2_UAI) == 0)
rp_ba += 4;
rp_wc = (rp_wc + 2) & 0177777;
if (rp_wc == 0) {
sts = 0;
goto wr_done;
}
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_done;
if ((rp_cs2 & CS2_UAI) == 0)
rp_ba += 4;
rp_wc = (rp_wc + 2) & 0177777;
if (rp_wc == 0) {
sts = 0;
goto wr_done;
}
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) {
if ((sts = uba_read_npr(rp_ba, rpa_dib.uba_ctl, &buf)) == 0)
break;
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);
if ((rp_cs2 & CS2_UAI) == 0)
rp_ba += 4;
rp_wc = (rp_wc + 2) & 0177777;
if (rp_wc == 0) {
sts = 0;
goto wr_done;
}
}
wr_done:
while (uptr->DATAPTR < RP_NUMWD) {
rp_buf[uptr->DATAPTR++] = 0;
}
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->STATUS |= DS_PIP;
}
}
uptr->LA_REG = GET_SC(uptr->DA) << 10;
if (sts) {
sim_activate(uptr, 300);
} else {
sim_debug(DEBUG_DETAIL, dptr, "RP%o write done\n", unit);
uptr->STATUS &= ~DS_PIP;
rp_ie &= ~(CSX_BUSY);
uptr->CMD &= ~CS1_GO;
if (rp_ie & CS1_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 * dptr)
{
int i;
rp_ba = 0;
rp_wc = 0;
rp_ie = 0;
rp_err2 = 0;
rp_err3 = 0;
rp_cs2 = CS2_IR;
for (i = 0; i < 8; i++) {
UNIT *u = &rpa_unit[i];
u->STATUS &= DS_VV;
u->CMD &= 0177776;
u->CCYL &= ((OF_HCI|OF_ECI|OF_F22) << 16) | 0177777;
if (rp_rmr[i] & 1) {
u->CCYL = GET_CY(u->DA) | (((OF_HCI|OF_ECI|OF_F22) << 16) & u->CCYL);
}
rp_rmr[i] = 0;
}
uba_clr_irq(&rpa_dib);
sim_debug(DEBUG_DETAIL, dptr, "RP reset done\n");
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 i;
int da;
t_stat r;
if ((r = rp_reset(dptr) )!= SCPE_OK)
return r;
/* 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 = (int32)((rp_buf[0103] & 077) << DA_V_SC) |
(int32)(((rp_buf[0103] >> 8) & 077) << DA_V_SF) |
(int32)((rp_buf[0103] >> 24) << DC_V_CY);
len = (int)(rp_buf[0102] & RMASK);
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 = (int32)((rp_buf[06] & 077) << DA_V_SC) |
(int32)(((rp_buf[06] >> 8) & 077) << DA_V_SF) |
(int32)((rp_buf[06] >> 24) << DC_V_CY);
len = (int)(((rp_buf[07] & 077) * 4) & RMASK);
} else {
/* Normal is at 4 and 5*/
uptr->DA = (int32)((rp_buf[04] & 077) << DA_V_SC) |
(int32)(((rp_buf[04] >> 8) & 077) << DA_V_SF) |
(int32)((rp_buf[04] >> 24) << DC_V_CY);
len = (int)(((rp_buf[05] & 077) * 4) & RMASK);
}
/* 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 cty_reset(&cty_dev);
}
/* 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 (sim_switches & SIM_SW_REST)
return SCPE_OK;
uptr->DA = 0;
uptr->STATUS = DS_ATA;
if ((rp_ie & CSX_BUSY) == 0 && (rp_ie & CS1_IE) != 0)
uba_set_irq(&rpa_dib);
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->STATUS = 0;
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