Fix divide of 0 on KS10 processor. Fix write access for auxiliary processor memory. Updated support new PIDP10 panel. Allow eight Unibux ports on the TEN device. Added GE DATANET-760 device to PDP6 Removed USER mode restriction for idle detection. Added Data Disc 6600 Television Display System.
402 lines
13 KiB
C
402 lines
13 KiB
C
/* kx10_ddc.c: Drum RES-10 Disk Controller.
|
||
|
||
Copyright (c) 2013-2022, 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 MEDDCHANTABILITY,
|
||
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"
|
||
|
||
#ifndef NUM_DEVS_DDC
|
||
#define NUM_DEVS_DDC 0
|
||
#endif
|
||
|
||
#if (NUM_DEVS_DDC > 0)
|
||
|
||
#define DDC_DEVNUM 0440 /* 0174 */
|
||
#define NUM_UNITS_DDC 4
|
||
|
||
/* Flags in the unit flags word */
|
||
|
||
#define UNIT_V_DTYPE (UNIT_V_UF + 0) /* disk type */
|
||
#define UNIT_M_DTYPE 1
|
||
#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
|
||
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
|
||
|
||
/* Parameters in the unit descriptor */
|
||
|
||
#define STATUS u3 /* Current status */
|
||
#define POS u4 /* Position in sector buffer */
|
||
#define UFLAGS u5 /* Function */
|
||
#define SEC us9 /* Sector counter */
|
||
|
||
|
||
/* CONI bits */
|
||
#define QUEUE_PAR 0400000000000LL
|
||
#define DDC_BSY 0000001000000LL
|
||
#define DDC_DON 0000000400000LL
|
||
#define DDC_CSE 0000000001000LL
|
||
#define DDC_QF 0000000000400LL
|
||
#define DDC_RDY 0000000000200LL /* Drum Ready */
|
||
#define DDC_SPA 0000000000100LL /* Drum Silo Parity Error */
|
||
#define DDC_NXM 0000000000040LL /* NXM */
|
||
#define DDC_EXC 0000000000020LL /* Exceed Capacity */
|
||
#define DDC_HUD 0000000000010LL /* Drum Hung */
|
||
#define DDC_MPE 0000000000004LL /* MPE */
|
||
#define DDC_OVR 0000000000002LL /* Data overrun */
|
||
#define DDC_CKR 0000000000001LL /* Checksum error */
|
||
|
||
/* CONO bits */
|
||
#define DDC_RST 0000000600000LL /* Drum Reset */
|
||
#define DDC_CLR 0000000400000LL /* Clear Int */
|
||
#define DDC_ERR 0000000200000LL /* Clear Errors */
|
||
#define DDC_EXF 0000000100000LL /* Execute FR */
|
||
#define DDC_EXQ 0000000040000LL /* Execute Queue */
|
||
|
||
/* Command words */
|
||
#define DDC_CMD 0700000000000LL /* Drum command */
|
||
#define DDC_SEQ 0003700000000LL /* Sequence number */
|
||
#define DDC_PIA 0000070000000LL /* PIA */
|
||
#define DDC_FUNC 0000006000000LL /* Function */
|
||
#define DDC_READ 0000002000000LL
|
||
#define DDC_WRITE 0000004000000LL
|
||
#define DDC_DISK 0000001400000LL /* Logical Disc */
|
||
#define DDC_TRK 0000000377600LL /* Track */
|
||
#define DDC_SEC 0000000000177LL /* Sector */
|
||
|
||
/* DataI bits */
|
||
/* DDC_SEC 0000000000177LL Sector */
|
||
#define DDC_DONE 0400000000000LL /* Done flag */
|
||
|
||
/* Drum Status */
|
||
#define DDC_PWB 0700000000000LL
|
||
#define DDC_SECCNT 0017700000000LL /* Sequence counter */
|
||
#define DDC_ADDR 0000000777777LL
|
||
|
||
/* DataI */
|
||
/* 177 Sector number */
|
||
|
||
/* Number of sectors = 13 */
|
||
/* Sector size = 0200 words */
|
||
|
||
|
||
|
||
#define DDC10_WDS 0200
|
||
|
||
#define DDC_SIZE (7000 * DDC10_WDS)
|
||
|
||
uint64 ddc_buf[DDC10_WDS];
|
||
uint64 ddc_cmd[16];
|
||
int ddc_cmdptr;
|
||
int ddc_putptr;
|
||
|
||
t_stat ddc_devio(uint32 dev, uint64 *data);
|
||
t_stat ddc_svc(UNIT *);
|
||
void ddc_ini(UNIT *, t_bool);
|
||
t_stat ddc_reset(DEVICE *);
|
||
t_stat ddc_attach(UNIT *, CONST char *);
|
||
t_stat ddc_detach(UNIT *);
|
||
t_stat ddc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||
const char *cptr);
|
||
const char *ddc_description (DEVICE *dptr);
|
||
|
||
|
||
UNIT ddc_unit[] = {
|
||
/* Controller 1 */
|
||
{ UDATA (&ddc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||
UNIT_ROABLE, DDC_SIZE) },
|
||
{ UDATA (&ddc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||
UNIT_ROABLE, DDC_SIZE) },
|
||
{ UDATA (&ddc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||
UNIT_ROABLE, DDC_SIZE) },
|
||
{ UDATA (&ddc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||
UNIT_ROABLE, DDC_SIZE) },
|
||
|
||
};
|
||
|
||
DIB ddc_dib = {DDC_DEVNUM, 1, &ddc_devio, NULL};
|
||
|
||
MTAB ddc_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" },
|
||
{0}
|
||
};
|
||
|
||
REG ddc_reg[] = {
|
||
{0}
|
||
};
|
||
|
||
DEVICE ddc_dev = {
|
||
"DDC", ddc_unit, ddc_reg, ddc_mod,
|
||
NUM_UNITS_DDC, 8, 18, 1, 8, 36,
|
||
NULL, NULL, &ddc_reset, NULL, &ddc_attach, &ddc_detach,
|
||
&ddc_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, dev_debug,
|
||
NULL, NULL, &ddc_help, NULL, NULL, &ddc_description
|
||
};
|
||
|
||
|
||
t_stat ddc_devio(uint32 dev, uint64 *data) {
|
||
UNIT *uptr;
|
||
DEVICE *dptr;
|
||
|
||
dptr = &ddc_dev;
|
||
uptr = &dptr->units[0];
|
||
switch(dev & 3) {
|
||
case CONI:
|
||
sim_debug(DEBUG_CONI, dptr, "DDC %03o CONI %06o PC=%o\n", dev,
|
||
(uint32)*data, PC);
|
||
*data = uptr->STATUS;
|
||
if (ddc_cmdptr != ((ddc_putptr + 2) & 0xf)) {
|
||
*data |= DDC_RDY;
|
||
}
|
||
if (ddc_cmdptr == ddc_putptr) {
|
||
*data |= DDC_BSY;
|
||
}
|
||
*data |= ((t_uint64)uptr->UFLAGS) << 25;
|
||
break;
|
||
case CONO:
|
||
if (*data & DDC_CLR) { /* Clear irq */
|
||
uptr->STATUS &= ~(DDC_DON);
|
||
clr_interrupt(ddc_dib.dev_num);
|
||
}
|
||
if (*data & DDC_ERR) { /* Clear error */
|
||
uptr->STATUS &= ~(DDC_SPA|DDC_NXM|DDC_EXC|DDC_HUD|DDC_MPE|
|
||
DDC_OVR|DDC_CKR|DDC_QF);
|
||
}
|
||
if (*data & DDC_EXF) { /* Execute FR */
|
||
}
|
||
if (*data & DDC_EXQ) { /* Execute Queue */
|
||
if (!sim_is_active(uptr)) {
|
||
sim_activate(uptr, 100);
|
||
uptr->POS = 0;
|
||
}
|
||
}
|
||
|
||
sim_debug(DEBUG_CONO, dptr, "DDC %03o CONO %06o PC=%o\n", dev,
|
||
(uint32)*data, PC);
|
||
break;
|
||
case DATAI:
|
||
*data = (t_uint64)(uptr->SEC++);
|
||
uptr->SEC &= 0177;
|
||
if (uptr->SEC > (13 << 2))
|
||
uptr->SEC = 0;
|
||
if ((uptr->STATUS & DDC_DON) != 0)
|
||
*data |= DDC_DONE;
|
||
sim_debug(DEBUG_DATAIO, dptr, "DDC %03o DATI %012llo PC=%o\n",
|
||
dev, *data, PC);
|
||
break;
|
||
case DATAO:
|
||
sim_debug(DEBUG_DATAIO, dptr, "DDC %03o DATO %012llo, PC=%o\n",
|
||
dev, *data, PC);
|
||
/* Insert the command into the queue */
|
||
if (((ddc_putptr + 1) & 0xf) != ddc_cmdptr) {
|
||
int func;
|
||
int pia;
|
||
int dsk;
|
||
int trk;
|
||
int sec;
|
||
int seq;
|
||
ddc_cmd[ddc_putptr] = *data;
|
||
sec = ddc_cmd[ddc_putptr] & DDC_SEC;
|
||
trk = (ddc_cmd[ddc_putptr] & DDC_TRK) >> 7;
|
||
dsk = (ddc_cmd[ddc_putptr] & DDC_DISK) >> 17;
|
||
func = (ddc_cmd[ddc_putptr] & DDC_FUNC) >> 19;
|
||
pia = (ddc_cmd[ddc_putptr] & DDC_PIA) >> 21;
|
||
seq = (ddc_cmd[ddc_putptr] & DDC_SEQ) >> 24;
|
||
sim_debug(DEBUG_DETAIL, dptr, "DDC %d cmd %d %d %d %d %o\n",
|
||
dsk, trk, sec, func, pia, seq);
|
||
|
||
ddc_putptr = (ddc_putptr + 1) & 0xf;
|
||
} else {
|
||
uptr->STATUS |= DDC_QF;
|
||
}
|
||
break;
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat ddc_svc (UNIT *uptr)
|
||
{
|
||
int wc;
|
||
int func;
|
||
int pia;
|
||
int dsk;
|
||
int trk;
|
||
int sec;
|
||
int seq;
|
||
t_addr adr;
|
||
uint64 word;
|
||
DEVICE *dptr;
|
||
UNIT *duptr;
|
||
|
||
dptr = &ddc_dev;
|
||
sec = (ddc_cmd[ddc_cmdptr] & DDC_SEC) >> 2;
|
||
trk = (ddc_cmd[ddc_cmdptr] & DDC_TRK) >> 7;
|
||
dsk = (ddc_cmd[ddc_cmdptr] & DDC_DISK) >> 17;
|
||
func = (ddc_cmd[ddc_cmdptr] & DDC_FUNC) >> 19;
|
||
pia = (ddc_cmd[ddc_cmdptr] & DDC_PIA) >> 21;
|
||
seq = (ddc_cmd[ddc_cmdptr] & DDC_SEQ) >> 24;
|
||
word = ddc_cmd[ddc_cmdptr+1];
|
||
adr = word & RMASK;
|
||
duptr = &ddc_dev.units[dsk];
|
||
|
||
if ((duptr->flags & UNIT_ATT) == 0) {
|
||
uptr->STATUS |= DDC_DON|DDC_HUD;
|
||
uptr->UFLAGS = seq;
|
||
sim_debug(DEBUG_DETAIL, dptr, "DDC %d Set done %d %d\n", dsk, pia, seq);
|
||
|
||
set_interrupt(ddc_dib.dev_num, pia);
|
||
uptr->POS = 0;
|
||
|
||
ddc_cmdptr += 2;
|
||
ddc_cmdptr &= 0xf;
|
||
if (ddc_cmdptr != ddc_putptr)
|
||
sim_activate(uptr, 100);
|
||
}
|
||
|
||
if (uptr->POS == 0) {
|
||
int da;
|
||
da = ((trk * 13) + sec) * DDC10_WDS;
|
||
(void)sim_fseek(duptr->fileref, da * sizeof(uint64), SEEK_SET);
|
||
wc = sim_fread (&ddc_buf[0], sizeof(uint64),
|
||
DDC10_WDS, duptr->fileref);
|
||
sim_debug(DEBUG_DETAIL, dptr, "DDC %d Read %d %d %d %d %d %o\n",
|
||
dsk, da, trk, sec, func, pia, seq);
|
||
for (; wc < DDC10_WDS; wc++)
|
||
ddc_buf[wc] = 0;
|
||
}
|
||
|
||
if (func == 2) {
|
||
if (Mem_write_word(adr, &ddc_buf[uptr->POS], 0)) {
|
||
uptr->STATUS |= DDC_NXM;
|
||
goto done;
|
||
}
|
||
} else if (func == 1) {
|
||
if (Mem_read_word(adr, &ddc_buf[uptr->POS], 0)) {
|
||
uptr->STATUS |= DDC_NXM;
|
||
goto done;
|
||
}
|
||
}
|
||
sim_debug(DEBUG_DATA, dptr, "DDC %d xfer %06o %012llo\n",
|
||
dsk, adr, ddc_buf[uptr->POS]);
|
||
uptr->POS++;
|
||
word = (word & LMASK) | ((adr + 1) & RMASK);
|
||
|
||
if (uptr->POS == DDC10_WDS) {
|
||
done:
|
||
if (func == 2) {
|
||
int da;
|
||
da = ((trk * 13) + sec) * DDC10_WDS;
|
||
(void)sim_fseek(duptr->fileref, da * sizeof(uint64), SEEK_SET);
|
||
wc = sim_fwrite (&ddc_buf[0], sizeof(uint64),
|
||
DDC10_WDS, duptr->fileref);
|
||
sim_debug(DEBUG_DETAIL, dptr, "DDC %d Write %d %d %d %d %d %o\n",
|
||
dsk, da, trk, sec, func, pia, seq);
|
||
}
|
||
sec ++;
|
||
ddc_cmd[ddc_cmdptr] &= ~DDC_SEC;
|
||
ddc_cmd[ddc_cmdptr] |= (DDC_SEC & (sec << 2));
|
||
word += 0000100000000LL;
|
||
sim_debug(DEBUG_DETAIL, dptr, "DDC %d next sect %012llo %012llo\n", dsk, word, ddc_cmd[ddc_cmdptr]);
|
||
if ((word & DDC_SECCNT) == 0) {
|
||
ddc_cmd[ddc_cmdptr+1] = (word & (DDC_SECCNT|DDC_PWB)) | (adr & RMASK);
|
||
uptr->STATUS |= DDC_DON;
|
||
uptr->UFLAGS = seq;
|
||
uptr->SEC = sec << 2;
|
||
sim_debug(DEBUG_DETAIL, dptr, "DDC %d Set done %d %d\n", dsk, pia, seq);
|
||
|
||
set_interrupt(ddc_dib.dev_num, pia);
|
||
uptr->POS = 0;
|
||
|
||
ddc_cmdptr += 2;
|
||
ddc_cmdptr &= 0xf;
|
||
if (ddc_cmdptr != ddc_putptr)
|
||
sim_activate(uptr, 100);
|
||
return SCPE_OK;
|
||
}
|
||
uptr->POS = 0;
|
||
}
|
||
ddc_cmd[ddc_cmdptr+1] = word;
|
||
sim_activate(uptr, 100);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
|
||
|
||
|
||
t_stat
|
||
ddc_reset(DEVICE * dptr)
|
||
{
|
||
UNIT *uptr;
|
||
int i;
|
||
ddc_cmdptr = ddc_putptr = 0;
|
||
for (i = 0; i < NUM_UNITS_DDC; i++) {
|
||
uptr = &dptr->units[i];
|
||
uptr->SEC = 0;
|
||
uptr->UFLAGS = 0;
|
||
uptr->STATUS = 0;
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Device attach */
|
||
|
||
t_stat ddc_attach (UNIT *uptr, CONST char *cptr)
|
||
{
|
||
t_stat r;
|
||
|
||
r = attach_unit (uptr, cptr);
|
||
if (r != SCPE_OK || (sim_switches & SIM_SW_REST) != 0)
|
||
return r;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Device detach */
|
||
|
||
t_stat ddc_detach (UNIT *uptr)
|
||
{
|
||
if (!(uptr->flags & UNIT_ATT)) /* attached? */
|
||
return SCPE_OK;
|
||
if (sim_is_active (uptr)) /* unit active? */
|
||
sim_cancel (uptr); /* cancel operation */
|
||
return detach_unit (uptr);
|
||
}
|
||
|
||
t_stat ddc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
fprintf (st, "DDC-10 Drum Drives (DDC)\n\n");
|
||
fprintf (st, "The DDC controller implements the RES-10 disk controller that talked\n");
|
||
fprintf (st, "to drum drives.\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 two disk types\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");
|
||
fprint_reg_help (st, dptr);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
const char *ddc_description (DEVICE *dptr)
|
||
{
|
||
return "DDC-10 disk controller";
|
||
}
|
||
|
||
#endif
|