blob: 9436af1f5810e3aba76d097dfacb67b5c4063f66 [file] [log] [blame] [raw]
/* i7000_chan.c: IBM 7000 Channel simulator
Copyright (c) 2005-2016, 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.
channel
Common routines for handling channel functions.
*/
#include "i7000_defs.h"
extern DEVICE *sim_devices[];
int num_devs[NUM_CHAN];
t_stat
chan_set_devs(DEVICE * dptr)
{
int i;
for(i = 0; i < NUM_CHAN; i++) {
num_devs[i] = 0;
}
/* Build channel array */
for (i = 0; sim_devices[i] != NULL; i++) {
UNIT *uptr = sim_devices[i]->units;
DIB *dibp = (DIB *) sim_devices[i]->ctxt;
int ctype;
int num;
/* If no DIB, not channel device */
if (dibp == NULL)
continue;
/* Skip channel devices */
if (sim_devices[i] == &chan_dev)
continue;
/* Skip disabled devices */
if (sim_devices[i]->flags & DEV_DIS)
continue;
ctype = dibp->ctype;
if (dibp->upc > 1) {
int chan = UNIT_G_CHAN(uptr->flags);
int type = CHAN_G_TYPE(chan_unit[chan].flags);
if (((1 << type) & ctype) == 0) {
if ((chan_unit[chan].flags & CHAN_SET) ||
((chan_unit[chan].flags & CHAN_AUTO)
&& num_devs[chan] != 0)) {
for (num = sim_devices[i]->numunits; num > 0; num--)
(uptr++)->flags |= UNIT_DIS;
goto nextdev;
}
}
/* Set channel to highest type */
if ((chan_unit[chan].flags & CHAN_SET) == 0) {
/* Set type to highest found */
for(type = 7; type >=0; type--)
if (ctype & (1 << type))
break;
chan_unit[chan].flags &= ~(CHAN_MODEL);
chan_unit[chan].flags |= CHAN_S_TYPE(type)|CHAN_SET;
}
num_devs[chan] += sim_devices[i]->numunits;
if (dibp->ini != NULL) {
for (num = sim_devices[i]->numunits; num > 0; num--) {
uptr->flags &= ~UNIT_CHAN;
uptr->flags |= UNIT_S_CHAN(chan);
dibp->ini(uptr++, 1);
}
}
goto nextdev;
}
for (num = sim_devices[i]->numunits; num > 0; num--) {
int chan = UNIT_G_CHAN(uptr->flags);
int type = CHAN_G_TYPE(chan_unit[chan].flags);
if ((uptr->flags & UNIT_DIS) == 0) {
if (((1 << type) & ctype) == 0) {
if ((chan_unit[chan].flags & CHAN_SET) ||
((chan_unit[chan].flags & CHAN_AUTO)
&& num_devs[chan] != 0)) {
uptr->flags |= UNIT_DIS;
goto next;
}
}
/* Set channel to highest type */
if ((chan_unit[chan].flags & CHAN_SET) == 0) {
/* Set type to highest found */
for(type = 7; type >=0; type--)
if (ctype & (1 << type))
break;
chan_unit[chan].flags &= ~(CHAN_MODEL);
chan_unit[chan].flags |= CHAN_S_TYPE(type)|CHAN_SET;
}
num_devs[chan]++;
if (dibp->ini != NULL)
dibp->ini(uptr, 1);
}
next:
uptr++;
}
nextdev:
;
}
return SCPE_OK;
}
/* Print help for "SET dev CHAN" based on allowed types */
void help_set_chan_type(FILE *st, DEVICE *dptr, const char *name)
{
#if NUM_CHAN > 1
DIB *dibp = (DIB *) dptr->ctxt;
int ctype = dibp->ctype;
int i;
int m;
fprintf (st, "Devices can be moved to any channel via the command\n\n");
fprintf (st, " sim> SET %s CHAN=x where x is", dptr->name);
if (ctype & 3) {
if (ctype == 1 || ctype == 2)
fprintf(st, " only");
fprintf (st, " %s", chname[0]);
if ((ctype & ~3) != 0)
fprintf(st, " or");
}
if ((ctype & ~3) != 0)
fprintf(st, " %s to %s", chname[1], chname[NUM_CHAN-1]);
fprintf (st, "\n\n%s can be attached to ", name);
m = 1;
for(i = 0; ctype != 0; i++) {
if (ctype & m) {
fprintf(st, "%s", chan_type_name[i]);
ctype &= ~m;
if (ctype != 0)
fprintf(st, ", or ");
}
m <<= 1;
}
fprintf(st, " channel\n");
#endif
}
/* Sets the device onto a given channel */
t_stat
set_chan(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
int newch;
int chan;
int num;
int type;
int ctype;
int compat;
if (cptr == NULL)
return SCPE_ARG;
if (uptr == NULL)
return SCPE_IERR;
dptr = find_dev_from_unit(uptr);
if (dptr == NULL)
return SCPE_IERR;
chan = UNIT_G_CHAN(uptr->flags);
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
for(newch = 0; newch < NUM_CHAN; newch++)
if (strcmp(cptr, chname[newch]) == 0)
break;
if (newch == NUM_CHAN)
return SCPE_ARG;
if (newch == chan)
return SCPE_OK;
ctype = dibp->ctype;
compat = ctype;
/* Update the number of devices on this channel */
num_devs[newch] = 0;
for (num = 0; sim_devices[num] != NULL; num++) {
UNIT *u = sim_devices[num]->units;
DIB *dibp = (DIB *) sim_devices[num]->ctxt;
int units = sim_devices[num]->numunits;
/* If no DIB, not channel device */
if (dibp == NULL)
continue;
/* Skip channel devices */
if (sim_devices[num] == &chan_dev)
continue;
/* Skip disabled devices */
if (sim_devices[num]->flags & DEV_DIS)
continue;
if (dibp->upc > 1) {
if ((u->flags & UNIT_DIS) == 0 &&
UNIT_G_CHAN(u->flags) == chan) {
num_devs[newch] += units;
compat &= dibp->ctype;
}
} else {
int i;
for (i = 0; i < units; i++) {
if ((u->flags & UNIT_DIS) == 0 &&
UNIT_G_CHAN(u->flags) == chan) {
num_devs[newch]++;
compat &= dibp->ctype;
}
u++;
}
}
}
/* If nothing left on channel, drop set bit */
if (num_devs[newch] == 0 && chan_unit[newch].flags & CHAN_AUTO) {
chan_unit[newch].flags &= ~CHAN_SET;
compat = ctype;
}
/* Check if same type or everyone can handle new type */
type = CHAN_G_TYPE(chan_unit[newch].flags);
if (((1 << type) & ctype) == 0) {
/* If set or no common types */
if (chan_unit[newch].flags & CHAN_SET && compat == 0)
return SCPE_IERR;
if ((chan_unit[newch].flags & CHAN_AUTO) &&
(compat == 0 && num_devs[newch] != 0))
return SCPE_IERR;
else {
/* Set type to highest compatable type */
for(type = 7; type >=0; type--)
if (compat >> type)
break;
chan_unit[newch].flags &= ~(CHAN_MODEL);
chan_unit[newch].flags |= CHAN_S_TYPE(type)|CHAN_SET;
}
}
/* Set channel to highest type */
if ((chan_unit[chan].flags & CHAN_SET) == 0) {
/* Set type to highest found */
for(type = 7; type >=0; type--)
if (ctype >> type)
break;
chan_unit[chan].flags &= ~(CHAN_MODEL);
chan_unit[chan].flags |= CHAN_S_TYPE(type)|CHAN_SET;
}
/* Detach unit from orignal channel */
if (dibp->upc > 1)
num_devs[chan] -= dptr->numunits;
else
num_devs[chan]--;
if (num_devs[chan] == 0 && (chan_unit[chan].flags & CHAN_AUTO))
chan_unit[chan].flags &= ~CHAN_SET;
/* Hook up to new channel */
if (dibp->upc > 1) {
uint32 unit;
for (unit = 0; unit < dptr->numunits; unit++) {
/* Set the new channel */
dptr->units[unit].flags &= ~UNIT_CHAN;
dptr->units[unit].flags |= UNIT_S_CHAN(newch);
}
num_devs[newch] += dptr->numunits;
} else {
/* Set the new channel */
uptr->flags &= ~UNIT_CHAN;
uptr->flags |= UNIT_S_CHAN(newch);
num_devs[newch]++;
}
return SCPE_OK;
}
/* Print devices on channel */
t_stat
print_chan(FILE * st, UNIT * uptr, int32 v, CONST void *desc)
{
int chan = uptr - chan_unit;
int i;
/* Check all devices */
fprintf(st, "units=");
for (i = 0; sim_devices[i] != NULL; i++) {
UNIT *u = sim_devices[i]->units;
DIB *dibp = (DIB *) sim_devices[i]->ctxt;
uint32 num;
/* If no DIB, not channel device */
if (dibp == NULL)
continue;
/* Skip channel devices */
if (sim_devices[i] == &chan_dev)
continue;
/* Skip disabled devices */
if (sim_devices[i]->flags & DEV_DIS)
continue;
if (dibp->upc > 1) {
if ((u->flags & UNIT_DIS) == 0 &&
UNIT_G_CHAN(u->flags) == chan)
fprintf(st, "%s, ", sim_devices[i]->name);
} else {
for (num = 0; num < sim_devices[i]->numunits; num++) {
if ((u->flags & UNIT_DIS) == 0 &&
UNIT_G_CHAN(u->flags) == chan)
fprintf(st, "%s%d, ", sim_devices[i]->name, num);
u++;
}
}
}
return SCPE_OK;
}
t_stat
get_chan(FILE * st, UNIT * uptr, int32 v, CONST void *desc)
{
DEVICE *dptr;
DIB *dibp;
int chan;
if (uptr == NULL)
return SCPE_IERR;
chan = UNIT_G_CHAN(uptr->flags);
dptr = find_dev_from_unit(uptr);
if (dptr == NULL)
return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
fprintf(st, "Chan=%s", chname[chan]);
return SCPE_OK;
}
t_stat
chan9_set_select(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
{
int newsel;
DEVICE *dptr;
DIB *dibp;
if (cptr == NULL)
return SCPE_ARG;
if (uptr == NULL)
return SCPE_IERR;
if (*cptr == '\0' || cptr[1] != '\0')
return SCPE_ARG;
if (*cptr == '0')
newsel = 0;
else if (*cptr == '1')
newsel = 1;
else
return SCPE_ARG;
dptr = find_dev_from_unit(uptr);
if (dptr == NULL)
return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
/* Change to new selection. */
if (dibp->upc > 1) {
uint32 unit;
for (unit = 0; unit < dptr->numunits; unit++) {
if (newsel)
dptr->units[unit].flags |= UNIT_SELECT;
else
dptr->units[unit].flags &= ~UNIT_SELECT;
}
} else {
if (newsel)
uptr->flags |= UNIT_SELECT;
else
uptr->flags &= ~UNIT_SELECT;
}
return SCPE_OK;
}
t_stat
chan9_get_select(FILE * st, UNIT * uptr, int32 v, CONST void *desc)
{
if (uptr == NULL)
return SCPE_IERR;
if (uptr->flags & UNIT_SELECT)
fputs("Select=1", st);
else
fputs("Select=0", st);
return SCPE_OK;
}
/* Check channel for error */
int chan_error(int chan)
{
return chan_flags[chan] & CHS_ATTN;
}
/* Check channel for flag, clear it if it was set */
int chan_stat(int chan, uint32 flag)
{
if (chan_flags[chan] & flag) {
chan_flags[chan] &= ~flag;
return 1;
}
return 0;
}
/* Check channel for flag */
int chan_test(int chan, uint32 flag)
{
if (chan_flags[chan] & flag)
return 1;
return 0;
}
/* Check channel is selected */
int chan_select(int chan)
{
return chan_flags[chan] & DEV_SEL;
}
/* Check channel is active */
int chan_active(int chan)
{
return (chan_flags[chan] &
(DEV_DISCO |DEV_SEL | STA_ACTIVE | STA_WAIT | STA_TWAIT)) != 0;
}
void
chan_set_attn(int chan)
{
chan_flags[chan] |= CHS_ATTN;
}
void
chan_set_eof(int chan)
{
chan_flags[chan] |= CHS_EOF;
}
void
chan_set_error(int chan)
{
chan_flags[chan] |= CHS_ERR;
}
void
chan_set_sel(int chan, int need)
{
chan_flags[chan] &=
~(DEV_WEOR | DEV_REOR | DEV_FULL | DEV_WRITE | DEV_DISCO);
chan_flags[chan] |= DEV_SEL;
if (need)
chan_flags[chan] |= DEV_WRITE;
}
void
chan_clear_status(int chan)
{
chan_flags[chan] &=
~(CHS_ATTN | CHS_EOT | CHS_BOT | DEV_REOR | DEV_WEOR);
}
void
chan_set(int chan, uint32 flag)
{
chan_flags[chan] |= flag;
}
void
chan_clear(int chan, uint32 flag)
{
chan_flags[chan] &= ~flag;
}
void
chan9_clear_error(int chan, int sel) {
chan_flags[chan] &= ~(SNS_UEND | (SNS_ATTN1 >> sel));
}
void
chan9_set_attn(int chan, int sel)
{
uint16 mask = SNS_ATTN1 >> sel;
chan9_set_error(chan, mask);
}