261 lines
7.8 KiB
C
261 lines
7.8 KiB
C
/* b5500_dr.c: Burrioughs 5500 Drum controller
|
||
|
||
Copyright (c) 2015, 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 "b5500_defs.h"
|
||
|
||
#if (NUM_DEVS_DR > 0)
|
||
|
||
#define UNIT_DR UNIT_ATTABLE | UNIT_DISABLE | UNIT_FIX | \
|
||
UNIT_BUFABLE | UNIT_MUSTBUF
|
||
|
||
|
||
/* in u4 is current address */
|
||
/* in u5 Bits 30-16 of W */
|
||
#define ADDR u4
|
||
#define CMD u5
|
||
|
||
#define DR_CHAN 000003 /* Channel number */
|
||
#define DR_RD 000004 /* Executing a read command */
|
||
#define DR_WR 000010 /* Executing a write command */
|
||
#define DR_RDY 000040 /* Device Ready */
|
||
|
||
#define AUXMEM (1 << UNIT_V_UF)
|
||
|
||
t_stat drm_srv(UNIT *);
|
||
t_stat drm_boot(int32, DEVICE *);
|
||
t_stat drm_attach(UNIT *, CONST char *);
|
||
t_stat drm_detach(UNIT *);
|
||
t_stat set_drum(UNIT * uptr, int32 val, CONST char *cptr,
|
||
void *desc);
|
||
t_stat set_auxmem(UNIT * uptr, int32 val, CONST char *cptr,
|
||
void *desc);
|
||
t_stat drm_help (FILE *, DEVICE *, UNIT *, int32, const char *);
|
||
const char *drm_description (DEVICE *);
|
||
|
||
|
||
MTAB drm_mod[] = {
|
||
{AUXMEM, 0, "DRUM", "DRUM", &set_drum, NULL, NULL, "Device is drum"},
|
||
{AUXMEM, AUXMEM, "AUXMEM", "AUXMEM", &set_auxmem, NULL, NULL, "Device is memory unit"},
|
||
{0}
|
||
};
|
||
|
||
|
||
UNIT drm_unit[] = {
|
||
{UDATA(&drm_srv, UNIT_DR, 32*1024)}, /* DRA */
|
||
{UDATA(&drm_srv, UNIT_DR, 32*1024)}, /* DRB */
|
||
};
|
||
|
||
DEVICE drm_dev = {
|
||
"DR", drm_unit, NULL, drm_mod,
|
||
NUM_DEVS_DR, 8, 15, 1, 8, 64,
|
||
NULL, NULL, NULL, &drm_boot, &drm_attach, &drm_detach,
|
||
NULL, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
|
||
NULL, NULL, &drm_help, NULL, NULL,
|
||
&drm_description
|
||
};
|
||
|
||
|
||
|
||
|
||
/* Start off a disk command */
|
||
t_stat drm_cmd(uint16 cmd, uint16 dev, uint8 chan, uint16 *wc, uint8 rd_flg)
|
||
{
|
||
UNIT *uptr;
|
||
int u = (dev==DRUM1_DEV)? 0: 1;
|
||
|
||
uptr = &drm_unit[u];
|
||
|
||
/* If unit disabled return error */
|
||
if (uptr->flags & UNIT_DIS) {
|
||
return SCPE_NODEV;
|
||
}
|
||
|
||
if ((uptr->flags & (UNIT_BUF)) == 0) {
|
||
sim_debug(DEBUG_CMD, &drm_dev, "Drum not buffered\n");
|
||
return SCPE_UNATT;
|
||
}
|
||
|
||
/* Check if drive is ready to recieve a command */
|
||
if ((uptr->CMD & DR_RDY) == 0)
|
||
return SCPE_BUSY;
|
||
|
||
uptr->CMD = chan;
|
||
if (rd_flg)
|
||
uptr->CMD |= DR_RD;
|
||
else
|
||
uptr->CMD |= DR_WR;
|
||
uptr->ADDR = cmd << 3;
|
||
sim_debug(DEBUG_CMD, &drm_dev, "Drum access %s %06o\n",
|
||
(uptr->CMD & DR_RD) ? "read" : "write", uptr->ADDR);
|
||
sim_activate(uptr, 100);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
|
||
/* Handle processing disk controller commands */
|
||
t_stat drm_srv(UNIT * uptr)
|
||
{
|
||
int chan = uptr->CMD & DR_CHAN;
|
||
uint8 *ch = &(((uint8 *)uptr->filebuf)[uptr->ADDR]);
|
||
|
||
|
||
/* Process for each unit */
|
||
if (uptr->CMD & DR_RD) {
|
||
/* Transfer one Character */
|
||
if (chan_write_drum(chan, ch, 0)) {
|
||
uptr->CMD = DR_RDY;
|
||
chan_set_end(chan);
|
||
return SCPE_OK;
|
||
}
|
||
uptr->ADDR++;
|
||
if (uptr->ADDR > ((int32)uptr->capac << 3)) {
|
||
sim_debug(DEBUG_CMD, &drm_dev, "Drum overrun\n");
|
||
uptr->CMD = DR_RDY;
|
||
chan_set_error(chan);
|
||
chan_set_end(chan);
|
||
return SCPE_OK;
|
||
}
|
||
sim_activate(uptr, 40);
|
||
}
|
||
|
||
/* Process for each unit */
|
||
if (uptr->CMD & DR_WR) {
|
||
/* Transfer one Character */
|
||
if (chan_read_drum(chan, ch, 0)) {
|
||
uptr->CMD = DR_RDY;
|
||
chan_set_end(chan);
|
||
return SCPE_OK;
|
||
}
|
||
uptr->ADDR++;
|
||
if (uptr->ADDR > ((int32)uptr->capac << 3)) {
|
||
sim_debug(DEBUG_CMD, &drm_dev, "Drum overrun\n");
|
||
uptr->CMD = DR_RDY;
|
||
chan_set_error(chan);
|
||
chan_set_end(chan);
|
||
return SCPE_OK;
|
||
}
|
||
sim_activate(uptr, 40);
|
||
}
|
||
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Boot from given device */
|
||
t_stat
|
||
drm_boot(int32 unit_num, DEVICE * dptr)
|
||
{
|
||
int dev = (unit_num)? DRUM2_DEV:DRUM1_DEV;
|
||
t_uint64 desc;
|
||
|
||
desc = (((t_uint64)dev)<<DEV_V)|DEV_IORD|DEV_OPT|020LL;
|
||
return chan_boot(desc);
|
||
}
|
||
|
||
|
||
t_stat
|
||
drm_attach(UNIT * uptr, CONST char *file)
|
||
{
|
||
t_stat r;
|
||
int u = uptr - drm_unit;
|
||
|
||
if ((r = attach_unit(uptr, file)) != SCPE_OK)
|
||
return r;
|
||
if ((sim_switches & SIM_SW_REST) == 0)
|
||
uptr->CMD |= DR_RDY;
|
||
uptr->hwmark = uptr->capac;
|
||
if (u)
|
||
iostatus |= DRUM2_FLAG;
|
||
else
|
||
iostatus |= DRUM1_FLAG;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
drm_detach(UNIT * uptr)
|
||
{
|
||
t_stat r;
|
||
int u = uptr - drm_unit;
|
||
if ((r = detach_unit(uptr)) != SCPE_OK)
|
||
return r;
|
||
uptr->CMD = 0;
|
||
if (u)
|
||
iostatus &= ~DRUM2_FLAG;
|
||
else
|
||
iostatus &= ~DRUM1_FLAG;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
set_drum(UNIT * uptr, int32 val, CONST char *cptr, void *desc) {
|
||
if ((uptr->flags & AUXMEM) == 0)
|
||
return SCPE_OK;
|
||
if (uptr->flags & UNIT_ATT)
|
||
drm_detach(uptr);
|
||
uptr->flags |= UNIT_ATTABLE;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
set_auxmem(UNIT * uptr, int32 val, CONST char *cptr, void *desc) {
|
||
int u = uptr - drm_unit;
|
||
|
||
if (uptr->flags & AUXMEM)
|
||
return SCPE_OK;
|
||
if (uptr->flags & UNIT_ATT)
|
||
detach_unit(uptr);
|
||
uptr->flags &= ~UNIT_ATTABLE;
|
||
if (uptr->filebuf == 0) {
|
||
uptr->filebuf = calloc(uptr->capac, 8);
|
||
uptr->flags |= UNIT_BUF;
|
||
}
|
||
uptr->CMD = DR_RDY;
|
||
if (u)
|
||
iostatus |= DRUM2_FLAG;
|
||
else
|
||
iostatus |= DRUM1_FLAG;
|
||
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
drm_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
fprintf (st, "B430 Magnetic Drum or B6500 memory module\n\n");
|
||
fprintf (st, "There are up to two drum units DR0 and DR1. These can either\n");
|
||
fprintf (st, "be attached to a file or set to AUXMEM. Setting to AUXMEM causes\n");
|
||
fprintf (st, "them to exist only during the given sim run. Setting back to DRUM\n");
|
||
fprintf (st, "will clear whatever was stored on the drum. If the device is set\n");
|
||
fprintf (st, "to DRUM it must be attached to a file which it will buffer until\n");
|
||
fprintf (st, "the unit is detached, or the sim exits. MCP must be configured to\n");
|
||
fprintf (st, "the drum\n\n");
|
||
fprint_set_help (st, dptr) ;
|
||
fprint_show_help (st, dptr) ;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
const char *
|
||
drm_description (DEVICE *dptr)
|
||
{
|
||
return "B430 Magnetic Drum or B6500 memory module";
|
||
}
|
||
#endif
|