Card reader handle EOF correctly. Line printer proper handling of paging. Magtape clean up debug message. Update 7010, 7070, 7080 for EOF handling.
1710 lines
67 KiB
C
1710 lines
67 KiB
C
/* i7090_chan.c: IBM 7090 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
|
||
|
||
The system state for the IBM 7090 channel is:
|
||
There are 4 types of channel:
|
||
704: Basic polled mode transfer. Channel only manages
|
||
status and disconnect of devices.
|
||
7607: Basic channel.
|
||
7909: Enhanced channel for disk, hypertape and com controlers.
|
||
7289: Special CTSS channel, like 7607, but first command
|
||
is drum address.
|
||
|
||
Common registers to all but 704 channels.
|
||
ADDR<0:16> Address of next command.
|
||
CMD<0:6> Channel command.
|
||
WC<0:15> Word count remaining.
|
||
ASM<0:35> Assembled data from devices.
|
||
LOCATION<0:16> Location to read or write next word from.
|
||
|
||
7909 adds following two registers.
|
||
SMS<0:6> Select register.
|
||
COUNT<0:6> Counter.
|
||
|
||
Simulation registers to handle device handshake.
|
||
STATUS<0:16> Simulated register for basic channel status.
|
||
SENSE<0:16> Additional flags for 7909 channels.
|
||
*/
|
||
|
||
#include "i7090_defs.h"
|
||
|
||
extern uint16 iotraps;
|
||
extern uint8 iocheck;
|
||
extern uint8 dualcore;
|
||
extern UNIT cpu_unit;
|
||
extern uint16 IC;
|
||
extern t_uint64 MQ;
|
||
extern uint32 drum_addr;
|
||
extern t_uint64 hsdrm_addr;
|
||
|
||
t_stat chan_reset(DEVICE * dptr);
|
||
void chan_fetch(int chan);
|
||
t_stat chan_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||
const char *cptr);
|
||
const char *chan_description (DEVICE *dptr);
|
||
void chan9_seqcheck(int chan);
|
||
uint32 dly_cmd(UNIT *, uint16, uint16);
|
||
|
||
/* Channel data structures
|
||
|
||
chan_dev Channel device descriptor
|
||
chan_unit Channel unit descriptor
|
||
chan_reg Channel register list
|
||
chan_mod Channel modifiers list
|
||
*/
|
||
|
||
uint16 caddr[NUM_CHAN]; /* Channel memory address */
|
||
uint8 bcnt[NUM_CHAN]; /* Channel character count */
|
||
uint8 cmd[NUM_CHAN]; /* Current command */
|
||
uint16 wcount[NUM_CHAN]; /* Word count */
|
||
t_uint64 assembly[NUM_CHAN]; /* Assembly register */
|
||
uint16 location[NUM_CHAN]; /* Pointer to next opcode */
|
||
uint32 chan_flags[NUM_CHAN]; /* Unit status */
|
||
uint16 chan_info[NUM_CHAN]; /* Private channel info */
|
||
uint8 counter[NUM_CHAN]; /* Channel counter */
|
||
uint8 sms[NUM_CHAN]; /* Channel mode infomation */
|
||
uint8 chan_irq[NUM_CHAN]; /* Channel has a irq pending */
|
||
|
||
/* 7607 channel commands */
|
||
#define IOCD 000
|
||
#define TCH 010
|
||
#define IORP 020
|
||
#define IORT 030
|
||
#define IOCP 040
|
||
#define IOCT 050
|
||
#define IOSP 060
|
||
#define IOST 070
|
||
|
||
/* 7909 channel commands */
|
||
#define WTR 000
|
||
#define WTRX 004
|
||
#define XMT 001
|
||
#define XMTX 005
|
||
#define TCH9 010
|
||
#define TCHX 014
|
||
#define LIPT 011
|
||
#define LIPTX 015
|
||
#define CTL 020
|
||
#define CTLR 021
|
||
#define CTLW 024
|
||
#define SNS 025
|
||
#define LAR 030
|
||
#define SAR 031
|
||
#define TWT 034
|
||
#define XXXX 035
|
||
#define CPYP 040
|
||
#define CPYP2 041
|
||
#define CPYP3 044
|
||
#define CPYP4 045
|
||
#define CPYD 050
|
||
#define TCM 051
|
||
#define CPYDX 054
|
||
#define TCMX 055
|
||
#define XXXZ 060
|
||
#define LIP 061
|
||
#define TDC 064
|
||
#define LCC 065
|
||
#define SMS 070
|
||
#define ICC 071
|
||
#define ICCX 075
|
||
|
||
/* Values for chan_info */
|
||
#define CHAINF_START 1 /* Channel started */
|
||
#define CHAINF_RUN 2 /* Transfer in progress */
|
||
|
||
#define nxt_chan_addr(chan) caddr[chan] = \
|
||
((dualcore) ? (0100000 & caddr[chan]) : 0) | \
|
||
((caddr[chan] + 1) & MEMMASK);
|
||
|
||
/* Globally visible flags */
|
||
|
||
const char *chan_type_name[] = {
|
||
"Polled", "Unit Record", "7607", "7909", "7289"};
|
||
|
||
/* Delay device for IOD instruction */
|
||
DIB dly_dib =
|
||
{ CH_TYP_PIO, 1, 0333, 07777, &dly_cmd, NULL };
|
||
|
||
|
||
UNIT chan_unit[] = {
|
||
/* Puesdo channel for 704 devices */
|
||
{UDATA(NULL, UNIT_DISABLE | CHAN_SET |
|
||
CHAN_S_TYPE(CHAN_PIO)|UNIT_S_CHAN(0), 0)},
|
||
/* Normal channels */
|
||
#if NUM_CHAN > 1
|
||
{UDATA(NULL, CHAN_AUTO | CHAN_SET | CHAN_S_TYPE(CHAN_7607)|
|
||
UNIT_S_CHAN(CHAN_A), 0)}, /* A */
|
||
{UDATA(NULL, UNIT_DISABLE | CHAN_AUTO|UNIT_S_CHAN(CHAN_B), 0)}, /* B */
|
||
{UDATA(NULL, UNIT_DISABLE | CHAN_AUTO|UNIT_S_CHAN(CHAN_C), 0)}, /* C */
|
||
{UDATA(NULL, UNIT_DISABLE | CHAN_AUTO|UNIT_S_CHAN(CHAN_D), 0)}, /* D */
|
||
{UDATA(NULL, UNIT_DISABLE | CHAN_AUTO|UNIT_S_CHAN(CHAN_E), 0)}, /* E */
|
||
{UDATA(NULL, UNIT_DISABLE | CHAN_AUTO|UNIT_S_CHAN(CHAN_F), 0)}, /* F */
|
||
{UDATA(NULL, UNIT_DISABLE | CHAN_AUTO|UNIT_S_CHAN(CHAN_G), 0)}, /* G */
|
||
{UDATA(NULL, UNIT_DISABLE | CHAN_AUTO|UNIT_S_CHAN(CHAN_H), 0)} /* H */
|
||
#endif
|
||
};
|
||
|
||
REG chan_reg[] = {
|
||
{BRDATA(ADDR, caddr, 8, 16, NUM_CHAN), REG_RO|REG_FIT},
|
||
{BRDATA(CMD, cmd, 8, 6, NUM_CHAN), REG_RO|REG_FIT},
|
||
{BRDATA(WC, wcount, 8, 15, NUM_CHAN), REG_RO|REG_FIT},
|
||
{BRDATA(ASM, assembly, 8, 36, NUM_CHAN), REG_RO|REG_FIT},
|
||
{BRDATA(LOCATION, location, 8, 16, NUM_CHAN), REG_RO|REG_FIT},
|
||
{BRDATA(FLAGS, chan_flags, 2, 32, NUM_CHAN), REG_RO|REG_FIT},
|
||
{BRDATA(COUNTER, counter, 8, 6, NUM_CHAN), REG_RO|REG_FIT },
|
||
{BRDATA(SMS, sms, 2, 6, NUM_CHAN), REG_RO|REG_FIT},
|
||
{NULL}
|
||
};
|
||
|
||
MTAB chan_mod[] = {
|
||
#ifdef I7090
|
||
{CHAN_MODEL, CHAN_S_TYPE(CHAN_PIO), "704 Channel", NULL, NULL, NULL, NULL},
|
||
{CHAN_MODEL, CHAN_S_TYPE(CHAN_7607), "7607", "7607", NULL, NULL, NULL},
|
||
{CHAN_MODEL, CHAN_S_TYPE(CHAN_7909), "7909", "7909", NULL, NULL, NULL},
|
||
{CHAN_MODEL, CHAN_S_TYPE(CHAN_7289), "7289", "7289", NULL, NULL, NULL},
|
||
{CHAN_AUTO, 0, "FIXED", "FIXED", NULL, NULL, NULL},
|
||
{CHAN_AUTO, CHAN_AUTO, "AUTO", "AUTO", NULL, NULL, NULL},
|
||
{CHAN_SET, CHAN_SET, "set", NULL, NULL, NULL, NULL},
|
||
{MTAB_VUN, 0, "Units", NULL, NULL, &print_chan, NULL},
|
||
#endif
|
||
{0}
|
||
};
|
||
|
||
/* Simulator debug controls */
|
||
DEBTAB chn_debug[] = {
|
||
{"CHANNEL", DEBUG_CHAN},
|
||
{"TRAP", DEBUG_TRAP},
|
||
{"CMD", DEBUG_CMD},
|
||
{"DATA", DEBUG_DATA},
|
||
{"DETAIL", DEBUG_DETAIL},
|
||
{"EXP", DEBUG_EXP},
|
||
{"SENSE", DEBUG_SNS},
|
||
{"CH0", 0x0100 << 0},
|
||
{"CHA", 0x0100 << 1},
|
||
{"CHB", 0x0100 << 2},
|
||
{"CHC", 0x0100 << 3},
|
||
{"CHD", 0x0100 << 4},
|
||
{"CHE", 0x0100 << 5},
|
||
{"CHF", 0x0100 << 6},
|
||
{"CHG", 0x0100 << 7},
|
||
{"CHH", 0x0100 << 8},
|
||
{0, 0}
|
||
};
|
||
|
||
DEVICE chan_dev = {
|
||
"CH", chan_unit, chan_reg, chan_mod,
|
||
NUM_CHAN, 8, 15, 1, 8, 36,
|
||
NULL, NULL, &chan_reset, NULL, NULL, NULL,
|
||
&dly_dib, DEV_DEBUG, 0, chn_debug,
|
||
NULL, NULL, &chan_help, NULL, NULL, &chan_description
|
||
};
|
||
|
||
|
||
/* Nothing special to do, just return true if cmd is write and we got here */
|
||
uint32 dly_cmd(UNIT * uptr, uint16 cmd, uint16 dev)
|
||
{
|
||
if (cmd == IO_WRS)
|
||
return SCPE_OK;
|
||
return SCPE_NODEV;
|
||
}
|
||
|
||
|
||
|
||
t_stat
|
||
chan_reset(DEVICE * dptr)
|
||
{
|
||
int i;
|
||
|
||
/* Clear channel assignment */
|
||
for (i = 0; i < NUM_CHAN; i++) {
|
||
if (chan_unit[i].flags & CHAN_AUTO)
|
||
chan_unit[i].flags &= ~CHAN_SET;
|
||
else
|
||
chan_unit[i].flags |= CHAN_SET;
|
||
chan_flags[i] = 0;
|
||
chan_info[i] = 0;
|
||
caddr[i] = 0;
|
||
cmd[i] = 0;
|
||
sms[i] = 0;
|
||
bcnt[i] = 6;
|
||
chan_irq[i] = 0;
|
||
wcount[i] = 0;
|
||
location[i] = 0;
|
||
counter[i] = 0;
|
||
}
|
||
return chan_set_devs(dptr);
|
||
}
|
||
|
||
/* Boot from given device */
|
||
t_stat
|
||
chan_boot(int32 unit_num, DEVICE * dptr)
|
||
{
|
||
/* Tell device to do a read, 3 records */
|
||
/* Set channel address = 0, wc = 3, location = 0, CMD=0 */
|
||
/* Set M[1] = TCO? 1, IC = 1 */
|
||
UNIT *uptr = &dptr->units[unit_num];
|
||
int chan = UNIT_G_CHAN(uptr->flags);
|
||
|
||
if (CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_PIO) {
|
||
IC = 0;
|
||
} else {
|
||
IC = 1;
|
||
/* Grab next channel command */
|
||
location[chan] = 0;
|
||
chan_fetch(chan);
|
||
}
|
||
chan_flags[chan] |= STA_ACTIVE;
|
||
chan_flags[chan] &= ~STA_PEND;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Preform BCD to binary translation for 7909 channel */
|
||
void
|
||
bcd_xlat(int chan, int direction)
|
||
{
|
||
int i;
|
||
t_uint64 na = 0;
|
||
|
||
for (i = 30; i >= 0; i -= 6) {
|
||
uint8 ch = (uint8)(assembly[chan] >> i) & 077;
|
||
|
||
if (direction) { /* D->M Read */
|
||
switch (ch & 060) {
|
||
case 000:
|
||
if (ch == 0)
|
||
ch = 060;
|
||
else if (ch == 012)
|
||
ch = 0;
|
||
break;
|
||
case 020:
|
||
case 060:
|
||
ch ^= 040;
|
||
case 040:
|
||
break;
|
||
}
|
||
} else { /* M->D Write */
|
||
switch (ch & 060) {
|
||
case 000:
|
||
if (ch == 0)
|
||
ch = 012;
|
||
else if (ch == 012)
|
||
ch = 020;
|
||
break;
|
||
case 060:
|
||
if (ch == 060)
|
||
ch = 060; /* => 000 */
|
||
case 020:
|
||
ch ^= 040;
|
||
case 040:
|
||
break;
|
||
}
|
||
}
|
||
na |= ((t_uint64) ch) << i;
|
||
}
|
||
assembly[chan] = na;
|
||
}
|
||
|
||
/* Execute the next channel instruction. */
|
||
void
|
||
chan_proc()
|
||
{
|
||
int chan;
|
||
#ifdef I7090
|
||
int cmask;
|
||
#endif
|
||
|
||
/* Scan channels looking for work */
|
||
for (chan = 0; chan < NUM_CHAN; chan++) {
|
||
/* Skip if channel is disabled */
|
||
if (chan_unit[chan].flags & UNIT_DIS)
|
||
continue;
|
||
|
||
/* If channel is disconnecting, do nothing */
|
||
if (chan_flags[chan] & DEV_DISCO)
|
||
continue;
|
||
|
||
#ifdef I7090
|
||
cmask = 0x0100 << chan;
|
||
#endif
|
||
switch (CHAN_G_TYPE(chan_unit[chan].flags)) {
|
||
case CHAN_PIO:
|
||
if ((chan_flags[chan] & (DEV_REOR|DEV_SEL|DEV_FULL)) ==
|
||
(DEV_SEL|DEV_REOR)) {
|
||
sim_debug(DEBUG_DETAIL, &chan_dev, "chan got EOR\n");
|
||
chan_flags[chan] |= (DEV_DISCO);
|
||
}
|
||
|
||
break;
|
||
#ifdef I7090
|
||
case CHAN_7289: /* Special channel for HS drum */
|
||
/* On first command, copy it to drum address and load another */
|
||
if ((chan_info[chan] & (CHAINF_RUN | CHAINF_START)) ==
|
||
CHAINF_START) {
|
||
hsdrm_addr = M[location[chan] - 1];
|
||
chan_info[chan] |= CHAINF_RUN;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev, "chan %d HDaddr %012llo\n",
|
||
chan, hsdrm_addr);
|
||
chan_fetch(chan);
|
||
continue;
|
||
}
|
||
if ((chan_info[chan] & CHAINF_START) == 0)
|
||
continue;
|
||
/* Fall through and behave like 7607 from now on */
|
||
case CHAN_7607:
|
||
/* If no select, stop channel */
|
||
if ((chan_flags[chan] & DEV_SEL) == 0
|
||
&& (chan_flags[chan] & STA_TWAIT)) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_TRAP, &chan_dev, "chan %d Trap IC=%06o\n",
|
||
chan, IC);
|
||
iotraps |= 1 << chan;
|
||
chan_flags[chan] &= ~(STA_START | STA_ACTIVE | STA_WAIT | STA_TWAIT);
|
||
chan_info[chan] = 0;
|
||
continue;
|
||
}
|
||
|
||
/* If device requested attention, abort current command */
|
||
if (chan_flags[chan] & CHS_ATTN) {
|
||
if (chan_flags[chan] & DEV_SEL)
|
||
chan_flags[chan] |= (DEV_DISCO);
|
||
chan_flags[chan] &=
|
||
~(CHS_ATTN | STA_START | STA_ACTIVE | STA_WAIT);
|
||
chan_info[chan] = 0;
|
||
switch(cmd[chan]) {
|
||
case IORT:
|
||
case IOCT:
|
||
case IOST:
|
||
iotraps |= 1 << chan;
|
||
break;
|
||
}
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d attn< %o\n", chan, cmd[chan] & 070);
|
||
continue;
|
||
}
|
||
|
||
/* If we are waiting and get EOR, then continue along */
|
||
if ((chan_flags[chan] & (STA_WAIT|DEV_REOR|DEV_FULL)) ==
|
||
(STA_WAIT|DEV_REOR)) {
|
||
chan_flags[chan] &= ~(STA_WAIT|DEV_WEOR);
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev, "chan %d clr wait EOR\n",
|
||
chan);
|
||
}
|
||
|
||
/* All done if waiting for EOR */
|
||
if (chan_flags[chan] & STA_WAIT)
|
||
continue;
|
||
|
||
/* No activity, nothing happening here folks, move along */
|
||
if ((chan_flags[chan] & (STA_ACTIVE | STA_WAIT)) == 0) {
|
||
/* Check if Trap wait and no pending LCHx, force disconnect */
|
||
if ((chan_flags[chan] & (STA_TWAIT|STA_PEND|DEV_SEL))
|
||
== (STA_TWAIT|DEV_SEL))
|
||
chan_flags[chan] |= DEV_DISCO|DEV_WEOR;
|
||
continue;
|
||
}
|
||
|
||
/* If command is a transfer, Do transfer */
|
||
if ((cmd[chan] & 070) == TCH) {
|
||
location[chan] = caddr[chan];
|
||
chan_fetch(chan);
|
||
/* Give up bus if next command is a tranfer. */
|
||
if ((cmd[chan] & 070) == TCH)
|
||
continue;
|
||
}
|
||
|
||
/* None disabled, active channel is if transfering */
|
||
switch (chan_flags[chan] & (DEV_WRITE | DEV_FULL)) {
|
||
/* Device has given us a dataword */
|
||
case DEV_FULL:
|
||
/* If we are not waiting EOR save it in memory */
|
||
if (/*(chan_flags[chan] & CHS_ERR) == 0 &&*/ (cmd[chan] & 1) == 0) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev, "chan %d data < %012llo\n",
|
||
chan, assembly[chan]);
|
||
M[caddr[chan]] = assembly[chan];
|
||
} else {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev, "chan %d data * %012llo\n",
|
||
chan, assembly[chan]);
|
||
}
|
||
nxt_chan_addr(chan);
|
||
assembly[chan] = 0;
|
||
bcnt[chan] = 6;
|
||
wcount[chan]--;
|
||
chan_flags[chan] &= ~DEV_FULL;
|
||
|
||
/* Device does not need a word and has not given us one */
|
||
case 0:
|
||
/* Device idle, expecting data from it */
|
||
|
||
/* Check if got EOR */
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
switch (cmd[chan] & 070) {
|
||
case IORP:
|
||
case IOSP:
|
||
chan_flags[chan] &= ~(DEV_REOR|DEV_WEOR/* | STA_WAIT*/);
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d EOR< %o\n",
|
||
chan, cmd[chan] & 070);
|
||
chan_fetch(chan);
|
||
chan_flags[chan] |= STA_ACTIVE;
|
||
continue; /* Handle new command next time */
|
||
case IORT:
|
||
case IOST:
|
||
chan_flags[chan] &= ~(DEV_REOR|DEV_WEOR);
|
||
chan_flags[chan] &= ~(STA_ACTIVE/*|STA_WAIT*/);
|
||
chan_flags[chan] |= STA_TWAIT;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d EOR< %o\n",
|
||
chan, cmd[chan] & 070);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
/* Done with transfer */
|
||
if (wcount[chan] == 0
|
||
/* && (chan_flags[chan] & STA_WAIT) == 0*/) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d < WC0 %o\n", chan,
|
||
cmd[chan] & 070);
|
||
switch (cmd[chan] & 070) {
|
||
case IOCD: /* Transfer and disconnect */
|
||
chan_flags[chan] |= DEV_DISCO | DEV_WEOR;
|
||
chan_flags[chan] &=
|
||
~(STA_START | STA_ACTIVE | STA_PEND);
|
||
if (CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_7289) {
|
||
iotraps |= 1 << chan;
|
||
sim_debug(DEBUG_TRAP, &chan_dev, "chan %d Trap\n",
|
||
chan);
|
||
}
|
||
chan_info[chan] = 0;
|
||
break;
|
||
|
||
case IORP: /* Transfer until end of record */
|
||
chan_flags[chan] |= STA_WAIT | DEV_WEOR;
|
||
break;
|
||
case IOSP: /* Transfer and proceed */
|
||
case IOCP: /* Transfer and proceed, no eor */
|
||
chan_fetch(chan);
|
||
break;
|
||
|
||
case IORT: /* Transfer, continue if LCH pending, */
|
||
/* else trap, Skip rest of record */
|
||
chan_flags[chan] |= STA_WAIT | DEV_WEOR /*| STA_TWAIT*/;
|
||
break;
|
||
case IOST: /* Transfer, continue if LCH, else trap */
|
||
case IOCT: /* Transfer but no end of record, else trap */
|
||
chan_flags[chan] &= ~(STA_ACTIVE/*|STA_WAIT*/);
|
||
chan_flags[chan] |= STA_TWAIT;
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Check if device left us */
|
||
if ((chan_flags[chan] & DEV_SEL) == 0) {
|
||
switch (cmd[chan] & 070) {
|
||
case IOCP:
|
||
case IORP:
|
||
case IOSP:
|
||
case IOCD:
|
||
chan_flags[chan] &= ~(STA_START|STA_ACTIVE|STA_WAIT);
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d -Sel< %o\n", chan, cmd[chan] & 070);
|
||
continue; /* Handle new command next time */
|
||
case IOCT:
|
||
case IORT:
|
||
case IOST: /* Behave like EOR */
|
||
chan_flags[chan] &= ~(STA_ACTIVE|STA_WAIT);
|
||
chan_flags[chan] |= STA_TWAIT;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d -Sel< %o\n", chan, cmd[chan] & 070);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
/* Device has word, but has not taken it yet */
|
||
case DEV_WRITE | DEV_FULL:
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
switch (cmd[chan] & 070) {
|
||
case IORP:
|
||
case IORT:
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d EOR>+ %o\n", chan, cmd[chan] & 070);
|
||
chan_flags[chan] &= ~DEV_FULL;
|
||
}
|
||
}
|
||
continue; /* Do nothing if no data xfer pending */
|
||
|
||
/* Device needs a word of data */
|
||
case DEV_WRITE: /* Device needs data word */
|
||
/* Check if device left us */
|
||
if ((chan_flags[chan] & DEV_SEL) == 0) {
|
||
switch (cmd[chan] & 070) {
|
||
case IOCP:
|
||
case IORP:
|
||
case IOSP:
|
||
chan_fetch(chan);
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d -Sel< %o\n", chan, cmd[chan] & 070);
|
||
continue; /* Handle new command next time */
|
||
case IOCD:
|
||
chan_flags[chan] &= ~(STA_START|STA_ACTIVE);
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d -Sel< %o\n", chan, cmd[chan] & 070);
|
||
continue;
|
||
case IOCT:
|
||
case IORT:
|
||
case IOST:
|
||
chan_flags[chan] &= ~(STA_ACTIVE);
|
||
chan_flags[chan] |= STA_TWAIT;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d -Sel< %o\n", chan, cmd[chan] & 070);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
/* Wait for device to recognize EOR */
|
||
if (chan_flags[chan] & DEV_WEOR) {
|
||
continue;
|
||
}
|
||
|
||
/* Check if got EOR */
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
switch (cmd[chan] & 070) {
|
||
case IORP:
|
||
chan_flags[chan] &= ~(DEV_REOR);
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d EOR> %o\n", chan, cmd[chan] & 070);
|
||
chan_fetch(chan);
|
||
chan_flags[chan] |= STA_ACTIVE;
|
||
break;
|
||
case IORT:
|
||
chan_flags[chan] &= ~(DEV_REOR|STA_ACTIVE);
|
||
chan_flags[chan] |= STA_TWAIT;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d EOR> %o\n", chan, cmd[chan] & 070);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
/* Give device new word if we have one */
|
||
if (wcount[chan] != 0) {
|
||
|
||
if (cmd[chan] & 1) {
|
||
assembly[chan] = 0;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d data > *\n", chan);
|
||
} else {
|
||
assembly[chan] = M[caddr[chan]];
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d data > %012llo\n", chan,
|
||
assembly[chan]);
|
||
}
|
||
nxt_chan_addr(chan);
|
||
bcnt[chan] = 6;
|
||
wcount[chan]--;
|
||
chan_flags[chan] |= DEV_FULL;
|
||
continue; /* Don't start next command until data taken */
|
||
}
|
||
|
||
/* Get here if wcount == 0 */
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d > WC0 %o stat=%08x\n",
|
||
chan, cmd[chan] & 070, chan_flags[chan]);
|
||
|
||
switch (cmd[chan] & 070) {
|
||
case IOCD: /* Transfer and disconnect */
|
||
chan_flags[chan] |= DEV_DISCO | DEV_WEOR;
|
||
chan_flags[chan] &=
|
||
~(STA_START | STA_ACTIVE | STA_PEND);
|
||
if (CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_7289)
|
||
iotraps |= 1 << chan;
|
||
chan_info[chan] = 0;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d > DISCO\n", chan);
|
||
break;
|
||
|
||
case IORP: /* Transfer until end of record */
|
||
chan_flags[chan] |= DEV_WEOR|STA_WAIT;
|
||
break;
|
||
case IOSP: /* Transfer and proceed */
|
||
case IOCP: /* Transfer and proceed, no eor */
|
||
chan_fetch(chan);
|
||
break;
|
||
|
||
case IORT: /* Transfer, continue if LCH pending, */
|
||
/* else trap, Skip rest of record */
|
||
chan_flags[chan] |= DEV_WEOR|STA_WAIT;
|
||
break;
|
||
case IOST: /* Transfer, continue if LCH, else trap */
|
||
case IOCT: /* Transfer but no end of record, else trap */
|
||
chan_flags[chan] &= ~STA_ACTIVE;
|
||
chan_flags[chan] |= STA_TWAIT;
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case CHAN_7909:
|
||
again:
|
||
/* If waiting for EOR just spin */
|
||
if (chan_flags[chan] & STA_WAIT) {
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
chan_flags[chan] &=
|
||
~(STA_WAIT|DEV_REOR|CTL_SNS|CTL_READ|CTL_WRITE);
|
||
if (chan_flags[chan] & DEV_SEL)
|
||
chan_flags[chan] |= DEV_DISCO;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d EOR Continue\n", chan);
|
||
}
|
||
continue;
|
||
}
|
||
|
||
/* Nothing more to do if not active. */
|
||
if (chan_flags[chan] & STA_ACTIVE) {
|
||
/* Execute the next command */
|
||
switch (cmd[chan]) {
|
||
case XXXZ:
|
||
case XXXX:
|
||
case TWT:
|
||
/* Check if command not allowed */
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
}
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_TRAP, &chan_dev, "chan %d CPU Trap\n",
|
||
chan);
|
||
iotraps |= 1 << chan;
|
||
chan_flags[chan] |= CTL_INHB;
|
||
case WTR:
|
||
case WTRX:
|
||
/* Check if command not allowed */
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
}
|
||
/* Go into a wait state */
|
||
chan_flags[chan] &= ~STA_ACTIVE;
|
||
location[chan]--;
|
||
break;
|
||
case XMT:
|
||
case XMTX:
|
||
/* Check if command not allowed */
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
}
|
||
if (wcount[chan] == 0)
|
||
break;
|
||
wcount[chan]--;
|
||
M[caddr[chan]] = M[location[chan]];
|
||
nxt_chan_addr(chan);
|
||
bcnt[chan] = 6;
|
||
location[chan]++;
|
||
continue;
|
||
case LIPT:
|
||
case LIPTX:
|
||
chan_flags[chan] &= ~(SNS_IRQ | SNS_IMSK | SNS_UEND);
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_TRAP, &chan_dev, "chan %d %02o LIPT\n",
|
||
chan, chan_flags[chan] & 077);
|
||
/* Fall through */
|
||
|
||
case TCH9:
|
||
case TCHX:
|
||
location[chan] = caddr[chan];
|
||
break;
|
||
case LIP:
|
||
chan_flags[chan] &= ~(SNS_IRQ | SNS_IMSK | SNS_UEND);
|
||
location[chan] = (uint16)M[040 + (2 * chan)] & MEMMASK;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_TRAP, &chan_dev, "chan %d %02o LIP\n",
|
||
chan, chan_flags[chan] & 077);
|
||
break;
|
||
case CTL:
|
||
if (chan_flags[chan] & CTL_CNTL)
|
||
goto xfer;
|
||
if (chan_flags[chan] & (CTL_READ | CTL_WRITE | CTL_SNS)) {
|
||
chan9_seqcheck(chan);
|
||
continue;
|
||
}
|
||
chan_flags[chan] |= CTL_CNTL;
|
||
goto finddev;
|
||
case CTLR:
|
||
if (chan_flags[chan] & CTL_CNTL)
|
||
goto xfer;
|
||
if (chan_flags[chan] & (CTL_READ | CTL_WRITE | CTL_SNS)) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
}
|
||
chan_flags[chan] |= CTL_CNTL | CTL_PREAD;
|
||
goto finddev;
|
||
case CTLW:
|
||
if (chan_flags[chan] & CTL_CNTL)
|
||
goto xfer;
|
||
if (chan_flags[chan] & (CTL_READ | CTL_WRITE | CTL_SNS)) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
}
|
||
chan_flags[chan] |= CTL_CNTL | CTL_PWRITE;
|
||
goto finddev;
|
||
case SNS:
|
||
if (chan_flags[chan] & (CTL_CNTL | CTL_READ | CTL_WRITE)) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
}
|
||
chan_flags[chan] |= CTL_SNS;
|
||
finddev:
|
||
chan_flags[chan] &= ~(DEV_REOR|CTL_END|DEV_WEOR);
|
||
{
|
||
DEVICE **dptr;
|
||
UNIT *uptr;
|
||
DIB *dibp;
|
||
|
||
for (dptr = sim_devices; *dptr != NULL; dptr++) {
|
||
int num = (*dptr)->numunits;
|
||
int j;
|
||
|
||
dibp = (DIB *) (*dptr)->ctxt;
|
||
/* If not device or 7909 type, just skip */
|
||
if (dibp == 0 || (dibp->ctype & CH_TYP_79XX) == 0)
|
||
continue;
|
||
uptr = (*dptr)->units;
|
||
for (j = 0; j < num; j++, uptr++) {
|
||
if ((uptr->flags & UNIT_DIS) == 0 &&
|
||
UNIT_G_CHAN(uptr->flags) == chan &&
|
||
(sms[chan] & 1) ==
|
||
((UNIT_SELECT & uptr->flags) != 0)) {
|
||
goto found;
|
||
}
|
||
}
|
||
}
|
||
/* If no device, stop right now */
|
||
chan9_set_error(chan, SNS_ADCHECK);
|
||
chan_flags[chan] &= ~(CTL_PREAD | CTL_PWRITE | CTL_SNS |
|
||
CTL_CNTL);
|
||
iotraps |= 1 << chan;
|
||
chan_flags[chan] &= ~STA_ACTIVE;
|
||
break;
|
||
found:
|
||
/* Get channel ready to transfer */
|
||
chan_flags[chan] &=
|
||
~(CTL_END|CTL_SEL|DEV_REOR|DEV_FULL);
|
||
bcnt[chan] = 6;
|
||
|
||
/* Call device to start it running */
|
||
if (sms[chan] & 1)
|
||
chan_flags[chan] |= CTL_SEL;
|
||
switch (dibp->cmd(uptr, cmd[chan], sms[chan])) {
|
||
case SCPE_IOERR:
|
||
case SCPE_NODEV:
|
||
chan9_set_error(chan, SNS_IOCHECK);
|
||
iotraps |= 1 << chan;
|
||
chan_flags[chan] &= ~(CTL_PREAD|CTL_PWRITE|CTL_SNS|
|
||
CTL_CNTL|STA_ACTIVE);
|
||
continue;
|
||
case SCPE_BUSY: /* Device not ready yet, wait */
|
||
continue;
|
||
case SCPE_OK: /* Device will be waiting for command */
|
||
break;
|
||
}
|
||
}
|
||
/* Special out for sense command */
|
||
if (cmd[chan] == SNS) {
|
||
chan_flags[chan] &= ~DEV_WRITE;
|
||
chan_flags[chan] |= DEV_SEL;
|
||
break;
|
||
}
|
||
chan_flags[chan] |= DEV_WRITE;
|
||
xfer:
|
||
/* Check if comand tranfer done */
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
chan_flags[chan] &=
|
||
~(DEV_WRITE | DEV_REOR | DEV_FULL);
|
||
chan_flags[chan] &= ~(CTL_READ | CTL_WRITE);
|
||
if ((chan_flags[chan] & CTL_END) == 0)
|
||
chan_flags[chan] |= (chan_flags[chan] &
|
||
(CTL_PREAD | CTL_PWRITE)) >> 2;
|
||
if ((chan_flags[chan] & (SNS_UEND|CTL_END)) ==
|
||
(SNS_UEND|CTL_END) && (sms[chan] & 010) == 0)
|
||
chan_flags[chan] &= ~STA_ACTIVE;
|
||
chan_flags[chan] &= ~(CTL_CNTL | CTL_PREAD |
|
||
CTL_PWRITE | CTL_END);
|
||
if (chan_flags[chan] & CTL_WRITE)
|
||
chan_flags[chan] |= DEV_WRITE;
|
||
bcnt[chan] = 6;
|
||
break;
|
||
}
|
||
|
||
/* Check if device ready for next command word */
|
||
if ((chan_flags[chan] & (DEV_WRITE | DEV_FULL)) ==
|
||
DEV_WRITE) {
|
||
assembly[chan] = M[caddr[chan]];
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_CMD, &chan_dev,
|
||
"chan %d cmd > %012llo\n",
|
||
chan, assembly[chan]);
|
||
nxt_chan_addr(chan);
|
||
bcnt[chan] = 6;
|
||
chan_flags[chan] |= DEV_FULL;
|
||
}
|
||
continue;
|
||
|
||
case LAR:
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
}
|
||
assembly[chan] = M[caddr[chan]];
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_CMD, &chan_dev,
|
||
"chan %d LAR > %012llo\n",
|
||
chan, assembly[chan]);
|
||
break;
|
||
case SAR:
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
}
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_CMD, &chan_dev,
|
||
"chan %d SAR < %012llo\n",
|
||
chan, assembly[chan]);
|
||
M[caddr[chan]] = assembly[chan];
|
||
break;
|
||
case CPYP:
|
||
case CPYP2:
|
||
case CPYP3:
|
||
case CPYP4:
|
||
if (chan_flags[chan] & (DEV_REOR|CTL_END)) {
|
||
if (sms[chan] & 0100) {
|
||
chan9_set_error(chan, SNS_UEND);
|
||
if (chan_flags[chan] & DEV_SEL)
|
||
chan_flags[chan] |= (DEV_DISCO | DEV_WEOR);
|
||
chan_flags[chan] &=
|
||
~(STA_WAIT|DEV_REOR|CTL_SNS|CTL_READ|CTL_WRITE);
|
||
break;
|
||
}
|
||
if (wcount[chan] != 0)
|
||
chan_flags[chan] &= ~(DEV_REOR);
|
||
}
|
||
case CPYD:
|
||
case CPYDX:
|
||
if ((chan_flags[chan] & (CTL_READ|CTL_WRITE|CTL_SNS))==0) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
}
|
||
|
||
|
||
if ((chan_flags[chan] & DEV_FULL) == 0) {
|
||
/* Check if we still have a select signal */
|
||
if (wcount[chan] != 0 &&
|
||
(chan_flags[chan] & DEV_SEL) == 0) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
}
|
||
|
||
/* Check if last word transfered */
|
||
if (wcount[chan] == 0) {
|
||
if (cmd[chan] == CPYD || cmd[chan] == CPYDX ||
|
||
chan_flags[chan] & SNS_UEND) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d DISC %o\n", chan, cmd[chan] & 070);
|
||
if (sms[chan] & 0100 &&
|
||
(chan_flags[chan] & DEV_REOR) == 0)
|
||
chan9_set_error(chan, SNS_UEND);
|
||
chan_flags[chan] |= (DEV_WEOR);
|
||
if (chan_flags[chan] & DEV_SEL)
|
||
chan_flags[chan] |= DEV_DISCO;
|
||
chan_flags[chan] &=
|
||
~(CTL_SNS | CTL_READ | CTL_WRITE);
|
||
if ((chan_flags[chan] & (SNS_UEND|CTL_END)) ==
|
||
(SNS_UEND|CTL_END) &&
|
||
(sms[chan] & 010) == 0)
|
||
chan_flags[chan] &= ~STA_ACTIVE;
|
||
} else {
|
||
if (chan_flags[chan] & DEV_REOR)
|
||
chan_flags[chan] &= ~DEV_REOR;
|
||
}
|
||
break;
|
||
}
|
||
|
||
/* Check for record end in non-concurrent IRQ mode*/
|
||
if (chan_flags[chan] & DEV_REOR && sms[chan] & 0100) {
|
||
chan9_set_error(chan, SNS_UEND);
|
||
chan_flags[chan] &= ~(CTL_SNS|CTL_READ|CTL_WRITE);
|
||
if (chan_flags[chan] & DEV_SEL)
|
||
chan_flags[chan] |= (DEV_DISCO | DEV_WEOR);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Check if ready to transfer something */
|
||
switch (chan_flags[chan] & (DEV_WRITE | DEV_FULL)) {
|
||
case DEV_WRITE | DEV_FULL:
|
||
case 0:
|
||
/* If device ended, quit transfer */
|
||
if (chan_flags[chan] & CTL_END) {
|
||
/* Disconnect channel if select still active */
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan_flags[chan] |= (DEV_DISCO);
|
||
chan_flags[chan] &= ~(STA_WAIT);
|
||
}
|
||
if (sms[chan] & 0100 && wcount[chan] != 0)
|
||
chan9_set_error(chan, SNS_UEND);
|
||
chan_flags[chan] &= ~(DEV_WRITE|DEV_FULL|DEV_REOR|
|
||
CTL_SNS|CTL_READ|CTL_WRITE|CTL_END);
|
||
/* Get new command ready after disco */
|
||
chan_fetch(chan);
|
||
}
|
||
continue; /* Do nothing if no data xfer */
|
||
case DEV_WRITE: /* Device needs data word */
|
||
assembly[chan] = M[caddr[chan]];
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d data > %012llo\n",
|
||
chan, assembly[chan]);
|
||
if (sms[chan] & 020) /* BCD Xlat mode */
|
||
bcd_xlat(chan, 0);
|
||
if (sms[chan] & 040) { /* Read backward */
|
||
caddr[chan] =
|
||
((dualcore) ? (0100000 & caddr[chan]) : 0) |
|
||
((caddr[chan] - 1) & MEMMASK);
|
||
} else {
|
||
nxt_chan_addr(chan);
|
||
}
|
||
bcnt[chan] = 6;
|
||
wcount[chan]--;
|
||
chan_flags[chan] |= DEV_FULL;
|
||
break;
|
||
case DEV_FULL: /* Device has given us a dataword */
|
||
if (bcnt[chan] != 0)
|
||
assembly[chan] <<= 6 * bcnt[chan];
|
||
if (sms[chan] & 020) /* BCD Xlat mode */
|
||
bcd_xlat(chan, 1);
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d data < %012llo\n",
|
||
chan, assembly[chan]);
|
||
M[caddr[chan]] = assembly[chan];
|
||
if (sms[chan] & 040) { /* Read backward */
|
||
caddr[chan] =
|
||
((dualcore) ? (0100000 & caddr[chan]) : 0) |
|
||
((caddr[chan] - 1) & MEMMASK);
|
||
} else {
|
||
nxt_chan_addr(chan);
|
||
}
|
||
assembly[chan] = 0;
|
||
bcnt[chan] = 6;
|
||
wcount[chan]--;
|
||
chan_flags[chan] &= ~DEV_FULL;
|
||
break;
|
||
}
|
||
|
||
continue;
|
||
|
||
case TCM:
|
||
case TCMX:
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
} else {
|
||
/* Compare wordcount high to wordcound low */
|
||
/* 0 = chan check, 1-6 = assmebly, 7 = 0 */
|
||
uint8 v;
|
||
uint8 ch = wcount[chan] >> 12;
|
||
uint8 mask = wcount[chan] & 077;
|
||
uint8 flag = wcount[chan] & 0100;
|
||
|
||
if (ch == 0) {
|
||
v = (chan_flags[chan] >> 5) & 077;
|
||
} else if (ch == 7) {
|
||
v = 0;
|
||
} else {
|
||
v = (uint8)(077 & (assembly[chan] >> (6 * (6-ch))));
|
||
}
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"TCM %d:%02o & %02o\n\r", ch, v, mask);
|
||
if ((v == mask && flag == 0)
|
||
|| ((v & mask) == mask && flag != 0))
|
||
location[chan] = caddr[chan];
|
||
}
|
||
break;
|
||
case TDC:
|
||
if (counter[chan] != 0) {
|
||
location[chan] = caddr[chan];
|
||
counter[chan]--;
|
||
}
|
||
break;
|
||
case LCC:
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
}
|
||
counter[chan] = caddr[chan] & 077;
|
||
break;
|
||
case SMS:
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
}
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan %d SMS %03o -> %03o %03o ",
|
||
chan, sms[chan], caddr[chan] & 0177,
|
||
(SNS_IRQS & chan_flags[chan])>>5);
|
||
sms[chan] = caddr[chan] & 0177;
|
||
/* Check to see if IRQ still pending */
|
||
if ((chan_flags[chan] & CTL_INHB) == 0 &&
|
||
chan_flags[chan] & SNS_IRQS &
|
||
(~((sms[chan] << 5) & (SNS_IMSK ^ SNS_IRQS)))) {
|
||
chan_irq[chan] = 1;
|
||
}
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev, "Irqs = %03o %o\n",
|
||
((chan_flags[chan] & SNS_IRQS)>>5) &
|
||
((sms[chan] ^ 016) | 061), chan_irq[chan]);
|
||
break;
|
||
case ICC:
|
||
case ICCX:
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan9_seqcheck(chan);
|
||
break;
|
||
}
|
||
/* transfer counter from wordcount high to assembly */
|
||
/* 0 = SMS to 6, 1-6 = assmebly, 7 = nop */
|
||
{
|
||
t_uint64 v = counter[chan] & 077;
|
||
uint8 ch = wcount[chan] >> 12;
|
||
|
||
if (ch == 0) {
|
||
/* Not what POO says, but what diags want */
|
||
/* POO says other digits not affected. */
|
||
assembly[chan] = sms[chan] & 00137;
|
||
} else if (ch != 7) {
|
||
assembly[chan] &= ~(077L << (6 * (6 - ch)));
|
||
assembly[chan] |= (v << (6 * (6 - ch)));
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Check for intrupts */
|
||
if (chan_irq[chan] ||
|
||
/* Can only interupt when channel inactive */
|
||
((chan_flags[chan] & (DEV_SEL | STA_ACTIVE | CTL_CNTL | CTL_SNS
|
||
| SNS_IRQ | CTL_INHB | CTL_READ | CTL_WRITE)) == 0 &&
|
||
cmd[chan] != TWT &&
|
||
(chan_flags[chan] & SNS_IRQS &
|
||
(((sms[chan] ^ 016) | 061) << 5)))) {
|
||
uint8 ocmd = cmd[chan];
|
||
M[040 + (chan * 2)] = location[chan] & MEMMASK;
|
||
M[040 + (chan * 2)] |= ((t_uint64) caddr[chan]) << 18;
|
||
chan_flags[chan] |= STA_ACTIVE|CTL_INHB;
|
||
location[chan] = 041 + (chan * 2);
|
||
chan_irq[chan] = 0;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_TRAP, &chan_dev, "chan irq %d\n\r", chan);
|
||
chan_fetch(chan);
|
||
/* Fake a xec type trap */
|
||
if ((ocmd & 073) == WTR || ocmd == TWT)
|
||
location[chan] = (uint16)(M[040 + (chan * 2)] + 1)& MEMMASK;
|
||
else
|
||
location[chan] = (uint16)M[040 + (chan * 2)] & MEMMASK;
|
||
goto again;
|
||
}
|
||
|
||
if (chan_flags[chan] & STA_ACTIVE) {
|
||
uint8 c = cmd[chan];
|
||
chan_fetch(chan);
|
||
/* Check if we should interupt during unusual end */
|
||
if (sms[chan] & 0100 && (c & 070) == CPYP &&
|
||
(cmd[chan] & 071) == CPYD && wcount[chan] == 0) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chan non-concur %d\n\r", chan);
|
||
chan9_set_error(chan, SNS_UEND);
|
||
chan_flags[chan] &= ~(CTL_SNS|CTL_READ|CTL_WRITE);
|
||
if (chan_flags[chan] & DEV_SEL)
|
||
chan_flags[chan] |= DEV_WEOR|DEV_DISCO;
|
||
chan_fetch(chan);
|
||
}
|
||
if (cmd[chan] != TCM && (chan_flags[chan] & DEV_DISCO) == 0)
|
||
goto again;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
void
|
||
chan_fetch(int chan)
|
||
{
|
||
uint16 loc;
|
||
t_uint64 temp;
|
||
|
||
sim_interval--;
|
||
loc = location[chan] & MEMMASK;
|
||
if (dualcore)
|
||
loc |= location[chan] & 0100000;
|
||
temp = M[loc];
|
||
location[chan] = ((loc + 1) & MEMMASK) | (loc & 0100000);
|
||
cmd[chan] = (uint8)(((temp >> 30) & 074) | ((temp >> 16) & 1));
|
||
wcount[chan] = (uint16)(temp >> 18) & 077777;
|
||
caddr[chan] = (uint16)temp & MEMMASK;
|
||
if (dualcore)
|
||
caddr[chan] |= temp & 0100000;
|
||
/* Check indirect bit */
|
||
if (temp & 0400000) {
|
||
caddr[chan] = (uint16)M[caddr[chan]];
|
||
if (dualcore)
|
||
caddr[chan] &= 0100000 | MEMMASK;
|
||
else
|
||
caddr[chan] &= MEMMASK;
|
||
sim_interval--;
|
||
}
|
||
/* Clear pending IO traps for channel */
|
||
if (chan_dev.dctrl & (0x0100 << chan))
|
||
sim_debug(DEBUG_CHAN, &chan_dev,
|
||
"chan %d fetch adr=%05o cmd=%03o caddr=%05o wcount=%05o\n",
|
||
chan, location[chan], cmd[chan], caddr[chan],
|
||
wcount[chan]);
|
||
}
|
||
|
||
/* Reset the channel, clear any pending device */
|
||
void
|
||
chan_rst(int chan, int type)
|
||
{
|
||
/* Issure reset command to device */
|
||
if (type == 0 && CHAN_G_TYPE(chan_unit[chan].flags) != CHAN_7909)
|
||
return;
|
||
if (type != 0 && CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_7909)
|
||
return;
|
||
if (chan_dev.dctrl & (0x0100 << chan))
|
||
sim_debug(DEBUG_CHAN, &chan_dev, "Reset channel\n");
|
||
/* Clear outstanding traps on reset */
|
||
if (type)
|
||
iotraps &= ~(1 << chan);
|
||
chan_info[chan] &= ~(CHAINF_START | CHAINF_RUN);
|
||
chan_flags[chan] &= (CHS_EOF|CHS_BOT|CHS_EOT|DEV_DISCO|DEV_SEL);
|
||
caddr[chan] = 0;
|
||
cmd[chan] = 0;
|
||
sms[chan] = 0;
|
||
chan_irq[chan] = 0;
|
||
wcount[chan] = 0;
|
||
location[chan] = 0;
|
||
counter[chan] = 0; /* Channel memory address */
|
||
}
|
||
|
||
/* Issue a command to a channel */
|
||
int
|
||
chan_cmd(uint16 dev, uint16 dcmd)
|
||
{
|
||
UNIT *uptr;
|
||
int32 chan;
|
||
DEVICE **dptr;
|
||
DIB *dibp;
|
||
int j;
|
||
|
||
/* Find device on given channel and give it the command */
|
||
chan = (dev >> 9) & 017;
|
||
/* If no channel device, quick exit */
|
||
if (chan_unit[chan].flags & UNIT_DIS)
|
||
return SCPE_IOERR;
|
||
/* On 704 device new command aborts current operation */
|
||
if (CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_PIO &&
|
||
(chan_flags[chan] & (DEV_SEL | DEV_DISCO)) == DEV_SEL) {
|
||
/* Check if device picked up last transfer */
|
||
if ((chan_flags[chan] & (DEV_FULL|DEV_WRITE)) == (DEV_FULL|DEV_WRITE))
|
||
return SCPE_BUSY;
|
||
/* Yes, disconnect device and tell it to write a EOR */
|
||
if ((chan_flags[chan] & (DEV_WRITE)) == (DEV_WRITE) ||
|
||
(chan_flags[chan] & (DEV_FULL)) == (DEV_FULL))
|
||
chan_flags[chan] |= DEV_DISCO | DEV_WEOR;
|
||
return SCPE_BUSY;
|
||
}
|
||
/* Unit is busy doing something, wait */
|
||
if (chan_flags[chan] & (DEV_SEL | DEV_DISCO | STA_TWAIT | STA_WAIT))
|
||
return SCPE_BUSY;
|
||
chan_flags[chan] &= ~(DEV_REOR|DEV_WEOR|DEV_FULL|DEV_WRITE|STA_WAIT);
|
||
/* Ok, try and find the unit */
|
||
dev &= 07777;
|
||
for (dptr = sim_devices; *dptr != NULL; dptr++) {
|
||
int r;
|
||
|
||
dibp = (DIB *) (*dptr)->ctxt;
|
||
/* If no DIB, not channel device */
|
||
if (dibp == NULL || dibp->ctype == CHAN_7909 ||
|
||
(dibp->addr & dibp->mask) != (dev & dibp->mask))
|
||
continue;
|
||
uptr = (*dptr)->units;
|
||
if (dibp->upc == 1) {
|
||
int num = (*dptr)->numunits;
|
||
|
||
for (j = 0; j < num; j++) {
|
||
if (UNIT_G_CHAN(uptr->flags) == chan) {
|
||
r = dibp->cmd(uptr, dcmd, dev);
|
||
if (r != SCPE_NODEV) {
|
||
bcnt[chan] = 6;
|
||
cmd[chan] = 0;
|
||
caddr[chan] = 0;
|
||
location[chan] = 0;
|
||
return r;
|
||
}
|
||
}
|
||
uptr++;
|
||
}
|
||
} else {
|
||
if (UNIT_G_CHAN(uptr->flags) == chan) {
|
||
r = dibp->cmd(uptr, dcmd, dev);
|
||
if (r != SCPE_NODEV) {
|
||
bcnt[chan] = 6;
|
||
cmd[chan] = 0;
|
||
caddr[chan] = 0;
|
||
location[chan] = 0;
|
||
return r;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return SCPE_NODEV;
|
||
}
|
||
|
||
|
||
/* Give channel a new address to start working at */
|
||
int
|
||
chan_start(int chan, uint16 addr)
|
||
{
|
||
/* Hold this command until after channel has disconnected */
|
||
if (chan_flags[chan] & DEV_DISCO)
|
||
return SCPE_BUSY;
|
||
|
||
/* Depending on channel type controls how command works */
|
||
if (CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_7909) {
|
||
if (chan_flags[chan] & STA_ACTIVE)
|
||
return SCPE_BUSY;
|
||
chan_flags[chan] &=
|
||
~(CTL_CNTL | CTL_SNS | CTL_READ | CTL_PREAD | CTL_INHB |
|
||
CTL_WRITE | CTL_PWRITE | SNS_UEND | SNS_IOCHECK);
|
||
} else {
|
||
/* All clear, start ball rolling on new command */
|
||
/* Force iocheck if attempt to load inactive channel with command */
|
||
if ((chan_flags[chan] & DEV_SEL) == 0) {
|
||
/* Fetch next command */
|
||
location[chan] = addr;
|
||
chan_fetch(chan);
|
||
return SCPE_IOERR;
|
||
}
|
||
}
|
||
if (chan_dev.dctrl & (0x0100 << chan))
|
||
sim_debug(DEBUG_CHAN, &chan_dev,
|
||
"chan %d start IC=%05o addr=%o\n\r", chan, IC - 1, addr);
|
||
/* Fetch next command */
|
||
location[chan] = addr;
|
||
chan_fetch(chan);
|
||
chan_flags[chan] &= ~(STA_PEND|STA_TWAIT|STA_WAIT|DEV_WEOR|DEV_FULL);
|
||
chan_flags[chan] |= STA_START | STA_ACTIVE;
|
||
chan_info[chan] |= CHAINF_START;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Give channel a new address to start working at */
|
||
int
|
||
chan_load(int chan, uint16 addr)
|
||
{
|
||
if (CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_7909) {
|
||
if (chan_flags[chan] & STA_ACTIVE)
|
||
return SCPE_BUSY;
|
||
/* Ignore command if this waiting on IRQ */
|
||
if (cmd[chan] == TWT && iotraps & (1 << chan))
|
||
return SCPE_OK;
|
||
chan_flags[chan] &= ~(CTL_INHB);
|
||
location[chan] = caddr[chan];
|
||
} else {
|
||
/* Force iocheck if attempt to load channel with command,
|
||
that has not been started or is not in select state */
|
||
if ((chan_flags[chan] & (DEV_SEL | STA_START)) != (DEV_SEL|STA_START))
|
||
return SCPE_IOERR;
|
||
|
||
/* If channel active, or waiting EOR, should hold CPU */
|
||
if (chan_flags[chan] & (STA_ACTIVE | STA_WAIT)) {
|
||
chan_flags[chan] |= STA_PEND;
|
||
return SCPE_BUSY;
|
||
}
|
||
chan_flags[chan] &= ~(STA_PEND|STA_TWAIT);
|
||
location[chan] = addr;
|
||
}
|
||
/* All clear, start ball rolling on new command */
|
||
if (chan_dev.dctrl & (0x0100 << chan))
|
||
sim_debug(DEBUG_CHAN, &chan_dev,
|
||
"chan %d load IC=%05o addr=%o stat=%08x\n\r", chan, IC - 1,
|
||
addr, chan_flags[chan]);
|
||
chan_fetch(chan);
|
||
chan_flags[chan] |= STA_ACTIVE;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* return the channels current command address */
|
||
void
|
||
chan_store(int chan, uint16 loc)
|
||
{
|
||
t_uint64 reg = 0LL;
|
||
|
||
/* Check if channel has units attached */
|
||
if (chan_unit[chan].flags & CHAN_SET) {
|
||
/* Return command/addr/xcmd/location */
|
||
if (CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_7909) {
|
||
reg = location[chan] & MEMMASK;
|
||
reg |= ((t_uint64) caddr[chan]) << 18;
|
||
/* Check if channel has units attached */
|
||
} else {
|
||
/* If doing a TCH, process it */
|
||
if ((cmd[chan] & 070) == TCH)
|
||
chan_proc();
|
||
reg = caddr[chan];
|
||
reg |= ((t_uint64) (location[chan] & MEMMASK)) << 18;
|
||
reg |= ((t_uint64) (cmd[chan] & 070)) << 30;
|
||
reg |= ((t_uint64) (cmd[chan] & 01)) << 16;
|
||
}
|
||
}
|
||
if (chan_dev.dctrl & (0x0100 << chan))
|
||
sim_debug(DEBUG_SNS, &chan_dev, "chan %d status %012llo\n\r",
|
||
chan,reg);
|
||
M[loc & (MEMMASK | 0100000)] = reg;
|
||
}
|
||
|
||
/* Store channel diagnostic bits */
|
||
void
|
||
chan_store_diag(int chan, uint16 loc)
|
||
{
|
||
t_uint64 reg;
|
||
int results;
|
||
|
||
/* Counter[6], iocheck,seq check, unusal end, attn 1,
|
||
* attn 2, adpter check, prepare to read, prepare to write,
|
||
* read status, write status, interupt */
|
||
if (CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_7909) {
|
||
reg = ((t_uint64) counter[chan]) << 30;
|
||
results = SNS_MASK & chan_flags[chan];
|
||
if (results & (((sms[chan] ^ 016) | 061) << 5))
|
||
results |= 1;
|
||
reg |= ((t_uint64) (results)) << 19;
|
||
if (chan_dev.dctrl & (0x0100 << chan))
|
||
sim_debug(DEBUG_SNS, &chan_dev, "chan %d diags %012llo\n\r",
|
||
chan,reg);
|
||
M[loc & (MEMMASK | 0100000)] = reg;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Write a word to the assembly register.
|
||
*/
|
||
int
|
||
chan_write(int chan, t_uint64 * data, int flags)
|
||
{
|
||
|
||
/* Check if last data still not taken */
|
||
if (chan_flags[chan] & DEV_FULL) {
|
||
/* Nope, see if we are waiting for end of record. */
|
||
if (chan_flags[chan] & DEV_WEOR) {
|
||
chan_flags[chan] |= DEV_REOR;
|
||
chan_flags[chan] &= ~(DEV_WEOR|DEV_FULL);
|
||
return END_RECORD;
|
||
}
|
||
|
||
/* If active set attention, report IO error if
|
||
device does not want to disconnect */
|
||
if (chan_flags[chan] & STA_ACTIVE) {
|
||
chan_flags[chan] |= CHS_ATTN;
|
||
if ((flags & DEV_DISCO) == 0)
|
||
iocheck = 1;
|
||
}
|
||
|
||
/* If requested, force disconnect */
|
||
chan_flags[chan] |= DEV_DISCO & flags;
|
||
|
||
return TIME_ERROR;
|
||
} else {
|
||
if (CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_PIO)
|
||
MQ = *data;
|
||
assembly[chan] = *data;
|
||
bcnt[chan] = 6;
|
||
chan_flags[chan] |= DEV_FULL;
|
||
chan_flags[chan] &= ~DEV_WRITE;
|
||
if (flags & DEV_REOR) {
|
||
chan_flags[chan] |= DEV_REOR;
|
||
}
|
||
}
|
||
|
||
return DATA_OK;
|
||
}
|
||
|
||
/*
|
||
* Read next word from assembly register.
|
||
*/
|
||
int
|
||
chan_read(int chan, t_uint64 * data, int flags)
|
||
{
|
||
|
||
/* Return END_RECORD if requested */
|
||
if (flags & DEV_WEOR) {
|
||
chan_flags[chan] |= DEV_REOR;
|
||
chan_flags[chan] &= ~(DEV_WEOR);
|
||
return END_RECORD;
|
||
}
|
||
|
||
/* Check if no data waiting */
|
||
if ((chan_flags[chan] & DEV_FULL) == 0) {
|
||
/* Nope, see if we are waiting for end of record. */
|
||
if (chan_flags[chan] & DEV_WEOR) {
|
||
chan_flags[chan] |= DEV_WRITE;
|
||
chan_flags[chan] &= ~(DEV_WEOR);
|
||
return END_RECORD;
|
||
}
|
||
|
||
/* If active set attention, report IO error if
|
||
device does not want to disconnect */
|
||
if (chan_flags[chan] & STA_ACTIVE) {
|
||
chan_flags[chan] |= CHS_ATTN;
|
||
if ((flags & DEV_DISCO) == 0)
|
||
iocheck = 1;
|
||
}
|
||
|
||
/* If requested, force disconnect */
|
||
chan_flags[chan] |= DEV_DISCO & flags;
|
||
|
||
return TIME_ERROR;
|
||
} else {
|
||
*data = assembly[chan];
|
||
bcnt[chan] = 6;
|
||
chan_flags[chan] &= ~DEV_FULL;
|
||
/* If end of record, don't transfer any data */
|
||
if (flags & DEV_REOR) {
|
||
chan_flags[chan] &= ~(DEV_WRITE);
|
||
chan_flags[chan] |= DEV_REOR;
|
||
} else
|
||
chan_flags[chan] |= DEV_WRITE;
|
||
}
|
||
return DATA_OK;
|
||
}
|
||
|
||
/*
|
||
* Write a char to the assembly register.
|
||
*/
|
||
int
|
||
chan_write_char(int chan, uint8 * data, int flags)
|
||
{
|
||
/* If Writing end of record, abort */
|
||
if (chan_flags[chan] & DEV_WEOR) {
|
||
chan_flags[chan] &= ~(DEV_FULL | DEV_WEOR);
|
||
return END_RECORD;
|
||
}
|
||
|
||
/* Check if last data still not taken */
|
||
if (chan_flags[chan] & DEV_FULL) {
|
||
/* Nope, see if we are waiting for end of record. */
|
||
if (chan_flags[chan] & DEV_WEOR) {
|
||
chan_flags[chan] |= DEV_REOR;
|
||
chan_flags[chan] &= ~(DEV_WEOR|DEV_FULL);
|
||
return END_RECORD;
|
||
}
|
||
|
||
/* If active set attention, report IO error if
|
||
device does not want to disconnect */
|
||
if (chan_flags[chan] & STA_ACTIVE) {
|
||
chan_flags[chan] |= CHS_ATTN;
|
||
if ((flags & DEV_DISCO) == 0)
|
||
iocheck = 1;
|
||
}
|
||
|
||
/* If requested, force disconnect */
|
||
chan_flags[chan] |= DEV_DISCO & flags;
|
||
|
||
return TIME_ERROR;
|
||
} else {
|
||
int cnt = --bcnt[chan];
|
||
t_uint64 wd;
|
||
|
||
if (CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_PIO)
|
||
wd = MQ;
|
||
else
|
||
wd = assembly[chan];
|
||
wd &= 0007777777777LL;
|
||
wd <<= 6;
|
||
wd |= (*data) & 077;
|
||
if (CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_PIO)
|
||
MQ = wd;
|
||
else
|
||
assembly[chan] = wd;
|
||
|
||
if (cnt == 0) {
|
||
chan_flags[chan] |= DEV_FULL;
|
||
chan_flags[chan] &= ~DEV_WRITE;
|
||
}
|
||
if (flags & DEV_REOR) {
|
||
chan_flags[chan] |= DEV_FULL|DEV_REOR;
|
||
chan_flags[chan] &= ~DEV_WRITE;
|
||
}
|
||
}
|
||
|
||
|
||
return DATA_OK;
|
||
}
|
||
|
||
/*
|
||
* Read next char from assembly register.
|
||
*/
|
||
int
|
||
chan_read_char(int chan, uint8 * data, int flags)
|
||
{
|
||
|
||
/* Return END_RECORD if requested */
|
||
if (flags & DEV_WEOR) {
|
||
chan_flags[chan] &= ~(DEV_WEOR);
|
||
return END_RECORD;
|
||
}
|
||
|
||
/* Check if he write out last data */
|
||
if ((chan_flags[chan] & DEV_FULL) == 0) {
|
||
/* Nope, see if we are waiting for end of record. */
|
||
if (chan_flags[chan] & DEV_WEOR) {
|
||
chan_flags[chan] |= DEV_WRITE|DEV_REOR;
|
||
chan_flags[chan] &= ~(DEV_WEOR);
|
||
return END_RECORD;
|
||
}
|
||
|
||
/* If active set attention, report IO error if
|
||
device does not want to disconnect */
|
||
if (chan_flags[chan] & STA_ACTIVE) {
|
||
chan_flags[chan] |= CHS_ATTN;
|
||
if ((flags & DEV_DISCO) == 0)
|
||
iocheck = 1;
|
||
}
|
||
|
||
/* If requested, force disconnect */
|
||
chan_flags[chan] |= DEV_DISCO & flags;
|
||
|
||
return TIME_ERROR;
|
||
} else {
|
||
int cnt = --bcnt[chan];
|
||
t_uint64 wd = assembly[chan];
|
||
*data = (uint8)(077 & (wd >> 30));
|
||
wd <<= 6;
|
||
wd |= 077 & (wd >> 36);
|
||
wd &= 0777777777777LL;
|
||
if (CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_PIO)
|
||
MQ = wd;
|
||
assembly[chan] = wd;
|
||
if (cnt == 0) {
|
||
chan_flags[chan] &= ~DEV_FULL;
|
||
bcnt[chan] = 6;
|
||
}
|
||
/* If end of record, don't transfer any data */
|
||
if (flags & DEV_REOR) {
|
||
chan_flags[chan] &= ~(DEV_WRITE|DEV_FULL);
|
||
chan_flags[chan] |= DEV_REOR;
|
||
} else
|
||
chan_flags[chan] |= DEV_WRITE;
|
||
}
|
||
return DATA_OK;
|
||
}
|
||
|
||
void
|
||
chan9_seqcheck(int chan)
|
||
{
|
||
/* Disconnect channel if active */
|
||
if (chan_flags[chan] & DEV_SEL)
|
||
chan_flags[chan] |= DEV_DISCO;
|
||
chan_flags[chan] &= ~(CTL_READ|CTL_WRITE|CTL_SNS|STA_ACTIVE);
|
||
if (chan_dev.dctrl & (0x0100 << chan))
|
||
sim_debug(DEBUG_EXP, &chan_dev, "chan %d seq\n", chan);
|
||
chan9_set_error(chan, SNS_SEQCHECK);
|
||
}
|
||
|
||
void
|
||
chan9_set_error(int chan, uint32 mask)
|
||
{
|
||
if (chan_flags[chan] & mask)
|
||
return;
|
||
chan_flags[chan] |= mask;
|
||
if (mask & (~((sms[chan] << 5) & (SNS_IMSK ^ SNS_IRQS)))) {
|
||
chan_irq[chan] = 1;
|
||
}
|
||
}
|
||
|
||
t_stat
|
||
chan_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
#ifdef I7090
|
||
fprintf(st, "%s\n\n", chan_description(dptr));
|
||
fprintf (st, "The 7090 supports up to 8 channels. Channel models include\n\n");
|
||
fprintf (st, " Unit record Polled mode I/O devices\n");
|
||
fprintf (st, " 7607 standard multiplexor channel\n");
|
||
fprintf (st, " 7909 advanced capabilities channel\n");
|
||
fprintf (st, " 7289 special channel for high speed drum\n\n");
|
||
fprintf (st, "Channels can be reconfigured on the 7090, this generally ");
|
||
fprintf (st, "happens automatically.\nHowever at times it can be useful to ");
|
||
fprintf (st, "force a channel to a specific device. If\ndevices are attached");
|
||
fprintf (st, "to incorrect channel types an error will be reported at sim\n");
|
||
fprintf (st, "start. The first channel is fixed for Polled mode devices.\n\n");
|
||
fprint_set_help(st, dptr);
|
||
fprint_show_help(st, dptr);
|
||
#else
|
||
fprintf(st, "IBM 704 Channel\n\n");
|
||
fprintf(st, "Psuedo device to display IBM 704 I/O. The IBM 704 used polled");
|
||
fprintf(st, " I/O,\nThe assembly register and the flags can be displayed\n");
|
||
fprintf(st, "There are no options for the this device\n");
|
||
#endif
|
||
return SCPE_OK;
|
||
}
|
||
|
||
const char *
|
||
chan_description(DEVICE *dptr)
|
||
{
|
||
return "IBM 7090 channel controller";
|
||
}
|