These include simulators for the IBM 701, IBM 702, IBM 704, IBM 705, IBM 705/3, IBM 709, IBM 1410/IBM 7010, IBM 7070, IBM 7080, IBM 7090 and IBM7094. These basically were a collection of machines that shared a common set it peripherals, Each group had its own instruction set, hence different simulators. IBM 701 -> i701 IBM 702/705/705/3/7080 -> i7080 IBM 7070/7074 -> i7070 IBM 1410/7010 -> i7010 IBM 704 -> i704 IBM 704/709/7090/7094 -> i7090 The i7090 can be set to simulate a IBM 704 however you end up disabling almost everything, since the 704 did not have any channels. A build option exists that allows this one to be built without all the extra features. The i7090 simulator’s implementation of the IBM 7094 is a more complete implementation of the IBM 7094 which can run CTSS while the existing simh I7094 can’t.
1597 lines
67 KiB
C
1597 lines
67 KiB
C
/* i7070_chan.c: IBM 7070 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 7070 channel is:
|
||
There are 4 types of channel:
|
||
PIO: Basic polled mode transfer. Channel only manages
|
||
status and disconnect of devices.
|
||
7604: Basic channel.
|
||
7907: Enhanced channel for disk, hypertape and com controlers.
|
||
|
||
Common registers to all but PIO channels.
|
||
ADDR<0:16> Location to read or write next word from.
|
||
CMD<0:6> Channel command.
|
||
LIMIT<0:16> Transfer limit
|
||
ASM<0:44> Assembled data from devices.
|
||
LOCATION<0:16> Address of next command.
|
||
|
||
Simulation registers to handle device handshake.
|
||
STATUS<0:16> Simulated register for basic channel status.
|
||
SENSE<0:16> Additional flags for 7907 channels.
|
||
*/
|
||
|
||
#include "i7070_defs.h"
|
||
|
||
extern UNIT cpu_unit;
|
||
|
||
#define CHAN_DEF UNIT_DISABLE|CHAN_SET
|
||
|
||
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);
|
||
|
||
|
||
/* Channel data structures
|
||
|
||
chan_dev Channel device descriptor
|
||
chan_unit Channel unit descriptor
|
||
chan_reg Channel register list
|
||
chan_mod Channel modifiers list
|
||
*/
|
||
|
||
uint32 location[NUM_CHAN]; /* Location of RDW instruction*/
|
||
uint32 caddr[NUM_CHAN]; /* Channel memory address */
|
||
uint8 bcnt[NUM_CHAN]; /* Channel character count */
|
||
uint8 cmd[NUM_CHAN]; /* Current command */
|
||
uint8 op[NUM_CHAN]; /* Operators for 7907 channel */
|
||
uint32 limit[NUM_CHAN]; /* Word count */
|
||
t_uint64 assembly[NUM_CHAN]; /* Assembly register */
|
||
uint32 chan_flags[NUM_CHAN]; /* Unit status */
|
||
uint32 chan_info[NUM_CHAN]; /* Private channel info */
|
||
uint8 chan_irq[NUM_CHAN]; /* Channel has a irq pending */
|
||
extern uint16 pri_latchs[10];
|
||
|
||
#define CHAN_OUTDEV 0x010000 /* Type out device */
|
||
#define CHAN_PRIO 0x008000 /* Channel has priority pending */
|
||
#define CHAN_TWE 0x004000 /* Channel format error */
|
||
#define CHAN_SEOR 0x002000 /* Channel saw a eor */
|
||
#define CHAN_NORDW 0x020000 /* No RDW for this command */
|
||
#define CHAN_SEOS 0x040000 /* Channel saw a end of segment */
|
||
#define CHAN_SCLR 0x080000 /* Short record */
|
||
#define CHAN_FIRST 0x100000 /* First tranfered word */
|
||
#define CHAN_START 0x200000 /* Channel has just started */
|
||
#define CHAN_OCTAL 0x400000 /* Octal conversion */
|
||
|
||
const char *chan_type_name[] = {
|
||
"Polled", "Unit Record", "7604", "7907", ""};
|
||
|
||
|
||
UNIT chan_unit[] = {
|
||
/* Puesdo channel for PIO devices */
|
||
{UDATA(NULL, CHAN_SET|CHAN_S_TYPE(CHAN_UREC)|UNIT_S_CHAN(CHAN_CHUREC),0)},
|
||
/* Normal channels */
|
||
{UDATA(NULL, CHAN_DEF|UNIT_S_CHAN(CHAN_A)|CHAN_S_TYPE(CHAN_7604),0)},/* A */
|
||
{UDATA(NULL, CHAN_DEF|UNIT_S_CHAN(CHAN_B)|CHAN_S_TYPE(CHAN_7604),0)},/* B */
|
||
{UDATA(NULL, CHAN_DEF|UNIT_S_CHAN(CHAN_C)|CHAN_S_TYPE(CHAN_7604),0)},/* C */
|
||
{UDATA(NULL, CHAN_DEF|UNIT_S_CHAN(CHAN_D)|CHAN_S_TYPE(CHAN_7604),0)},/* D */
|
||
{UDATA(NULL, CHAN_DEF|UNIT_S_CHAN(CHAN_E)|CHAN_S_TYPE(CHAN_7907),0)},/* E */
|
||
{UDATA(NULL, CHAN_DEF|UNIT_S_CHAN(CHAN_F)|CHAN_S_TYPE(CHAN_7907),0)},/* F */
|
||
{UDATA(NULL, CHAN_DEF|UNIT_S_CHAN(CHAN_G)|CHAN_S_TYPE(CHAN_7907),0)},/* G */
|
||
{UDATA(NULL, CHAN_DEF|UNIT_S_CHAN(CHAN_H)|CHAN_S_TYPE(CHAN_7907),0)} /* H */
|
||
};
|
||
|
||
REG chan_reg[] = {
|
||
{BRDATA(ADDR, caddr, 10, 18, NUM_CHAN), REG_RO|REG_FIT},
|
||
{BRDATA(CMD, cmd, 8, 6, NUM_CHAN), REG_RO|REG_FIT},
|
||
{BRDATA(LIMIT, limit, 10, 18, NUM_CHAN), REG_RO|REG_FIT},
|
||
{BRDATA(ASM, assembly, 16, 44, NUM_CHAN), REG_VMIO|REG_RO|REG_FIT},
|
||
{BRDATA(LOCATION, location, 10, 18, NUM_CHAN), REG_RO|REG_FIT},
|
||
{BRDATA(FLAGS, chan_flags, 2, 32, NUM_CHAN), REG_RO|REG_FIT},
|
||
{NULL}
|
||
};
|
||
|
||
MTAB chan_mod[] = {
|
||
{CHAN_MODEL, CHAN_S_TYPE(CHAN_UREC), "UREC", NULL, NULL,NULL,NULL},
|
||
{CHAN_MODEL, CHAN_S_TYPE(CHAN_7604), "7604", NULL, NULL, NULL, NULL},
|
||
{CHAN_MODEL, CHAN_S_TYPE(CHAN_7907), "7907", NULL, NULL, NULL, NULL},
|
||
{MTAB_VUN, 0, "UNITS", NULL, NULL, &print_chan, NULL, "Show units on channel"},
|
||
{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},
|
||
{"CH1", 0x0100 << 1},
|
||
{"CH2", 0x0100 << 2},
|
||
{"CH3", 0x0100 << 3},
|
||
{"CH4", 0x0100 << 4},
|
||
{"CHA", 0x0100 << 5},
|
||
{"CHB", 0x0100 << 6},
|
||
{"CHC", 0x0100 << 7},
|
||
{"CHD", 0x0100 << 8},
|
||
{0, 0}
|
||
};
|
||
|
||
DEVICE chan_dev = {
|
||
"CH", chan_unit, chan_reg, chan_mod,
|
||
NUM_CHAN, 10, 18, 1, 10, 44,
|
||
NULL, NULL, &chan_reset, NULL, NULL, NULL,
|
||
NULL, DEV_DEBUG, 0, chn_debug,
|
||
NULL, NULL, &chan_help, NULL, NULL, &chan_description
|
||
};
|
||
|
||
#define DELTA_CHAR 057
|
||
#define SM_CHAR 037
|
||
#define SM_MEM 0x39
|
||
#define RM_CHAR 0x80
|
||
|
||
/* Translation tables */
|
||
uint8 bcd_mem[64] = {
|
||
/* ? 1 2 3 4 5 6 7 */
|
||
/* 00 */ 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||
/* 8 9 0 =/# !/@ ? ? tm */
|
||
/* 10 */ 0x98, 0x99, 0x90, 0x45, 0x46, 0x47, 0x48, 0x49,
|
||
/* sp / S T U V W X */
|
||
/* 20 */ 0x60, 0x31, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||
/* Y Z rm , %/( ? ? sm */
|
||
/* 30 */ 0x88, 0x89, 0x80, 0x35, 0x36, 0x37, 0x38, 0x39,
|
||
/* - J K L M N O P */
|
||
/* 40 */ 0x30, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||
/* Q R -0 $ * ? ? del */
|
||
/* 50 */ 0x78, 0x79, 0x70, 0x25, 0x26, 0x27, 0x28, 0xFF,
|
||
/*+/& A B C D E F G */
|
||
/* 60 */ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||
/* H I +0 . sq ? ? gm */
|
||
/* 70 */ 0x68, 0x69, 0x60, 0x15, 0x16, 0x17, 0x18, 0x19
|
||
};
|
||
|
||
uint8 mem_bcd[256] = {
|
||
/* sp */
|
||
/* 00 */ 020, 000, 000, 000, 000, 000, 000, 000,
|
||
/* */
|
||
/* 08 */ 000, 000, 000, 000, 000, 000, 000, 000,
|
||
/* sq ? */
|
||
/* 10 */ 000, 000, 000, 000, 000, 073, 074, 075,
|
||
/* ? ? */
|
||
/* 18 */ 076, 077, 000, 000, 000, 000, 000, 000,
|
||
/*+/- $ * ? */
|
||
/* 20 */ 060, 000, 000, 000, 000, 053, 054, 055,
|
||
/* ? +/- */
|
||
/* 28 */ 056, 060, 000, 000, 000, 000, 000, 000,
|
||
/* - / , %/( ? */
|
||
/* 30 */ 040, 021, 000, 000, 000, 033, 034, 035,
|
||
/* ? sm */
|
||
/* 38 */ 036, 037, 000, 000, 000, 000, 000, 000,
|
||
/* =/# !/@ ? */
|
||
/* 40 */ 000, 000, 000, 000, 000, 013, 014, 015,
|
||
/* ? tm */
|
||
/* 48 */ 016, 017, 000, 000, 000, 000, 000, 000,
|
||
/* */
|
||
/* 50 */ 000, 000, 000, 000, 000, 000, 000, 000,
|
||
/* */
|
||
/* 58 */ 000, 000, 000, 000, 000, 000, 000, 000,
|
||
/* +0 A B C D E F G */
|
||
/* 60 */ 072, 061, 062, 063, 064, 065, 066, 067,
|
||
/* H I */
|
||
/* 68 */ 070, 071, 000, 000, 000, 000, 000, 000,
|
||
/* -0 J K L M N O P */
|
||
/* 70 */ 052, 041, 042, 043, 044, 045, 046, 047,
|
||
/* Q R */
|
||
/* 78 */ 050, 051, 000, 000, 000, 000, 000, 000,
|
||
/* rm S T U V W X */
|
||
/* 80 */ 032, 000, 022, 023, 024, 025, 026, 027,
|
||
/* Y Z */
|
||
/* 88 */ 030, 031, 000, 000, 000, 000, 000, 000,
|
||
/* 0 1 2 3 4 5 6 7 */
|
||
/* 90 */ 012, 001, 002, 003, 004, 005, 006, 007,
|
||
/* 8 9 */
|
||
/* 98 */ 010, 011, 000, 000, 000, 000, 000, 000
|
||
};
|
||
|
||
|
||
t_stat
|
||
chan_reset(DEVICE * dptr)
|
||
{
|
||
int i;
|
||
|
||
/* Clear channel assignment */
|
||
for (i = 0; i < NUM_CHAN; i++) {
|
||
chan_flags[i] = 0;
|
||
chan_info[i] = 0;
|
||
caddr[i] = 0;
|
||
cmd[i] = 0;
|
||
bcnt[i] = 10;
|
||
chan_irq[i] = 0;
|
||
limit[i] = 0;
|
||
location[i] = 0;
|
||
}
|
||
return chan_set_devs(dptr);
|
||
}
|
||
|
||
/* Boot from given device */
|
||
t_stat
|
||
chan_boot(int32 unit_num, DEVICE * dptr)
|
||
{
|
||
return SCPE_NOFNC; /* Not implimented until I know how boot work */
|
||
}
|
||
|
||
t_stat
|
||
chan_issue_cmd(uint16 chan, uint16 dcmd, uint16 dev) {
|
||
DEVICE **dptr;
|
||
DIB *dibp;
|
||
uint32 j;
|
||
UNIT *uptr;
|
||
|
||
for (dptr = sim_devices; *dptr != NULL; dptr++) {
|
||
int r;
|
||
|
||
dibp = (DIB *) (*dptr)->ctxt;
|
||
/* If no DIB, not channel device */
|
||
if (dibp == 0)
|
||
continue;
|
||
uptr = (*dptr)->units;
|
||
/* If this is a 79XX device, check it */
|
||
if (dibp->ctype & CH_TYP_79XX) {
|
||
for (j = 0; j < (*dptr)->numunits; j++, uptr++) {
|
||
if ((uptr->flags & UNIT_DIS) == 0 &&
|
||
UNIT_G_CHAN(uptr->flags) == chan &&
|
||
(dev == ((UNIT_SELECT & uptr->flags) != 0))) {
|
||
r = dibp->cmd(uptr, dcmd, dev);
|
||
if (r != SCPE_NODEV)
|
||
return r;
|
||
}
|
||
}
|
||
} else if ((dibp->addr & dibp->mask) == (dev & dibp->mask)) {
|
||
if (dibp->upc == 1) {
|
||
for (j = 0; j < (*dptr)->numunits; j++) {
|
||
if ((uptr->flags & UNIT_DIS) == 0 &&
|
||
UNIT_G_CHAN(uptr->flags) == chan) {
|
||
r = dibp->cmd(uptr, dcmd, dev);
|
||
if (r != SCPE_NODEV)
|
||
return r;
|
||
}
|
||
uptr++;
|
||
}
|
||
} else {
|
||
if ((uptr->flags & UNIT_DIS) == 0 &&
|
||
UNIT_G_CHAN(uptr->flags) == chan) {
|
||
r = dibp->cmd(uptr, dcmd, dev);
|
||
if (r != SCPE_NODEV)
|
||
return r;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return SCPE_NODEV;
|
||
}
|
||
|
||
/* Execute the next channel instruction. */
|
||
void
|
||
chan_proc()
|
||
{
|
||
int chan;
|
||
int cmask;
|
||
|
||
/* 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;
|
||
|
||
cmask = 0x0100 << chan;
|
||
switch (CHAN_G_TYPE(chan_unit[chan].flags)) {
|
||
case CHAN_UREC:
|
||
case CHAN_7604:
|
||
/* If channel is disconnecting, do nothing */
|
||
if (chan_flags[chan] & DEV_DISCO)
|
||
continue;
|
||
|
||
/* If device requested attention, abort current command */
|
||
if (chan_flags[chan] & CHS_ATTN) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_EXP, &chan_dev, "chan %d Attn\n",
|
||
chan);
|
||
chan_flags[chan] &=
|
||
~(CHS_ATTN | STA_START | STA_ACTIVE | STA_WAIT);
|
||
/* Disconnect if selected */
|
||
if (chan_flags[chan] & DEV_SEL)
|
||
chan_flags[chan] |= (DEV_DISCO);
|
||
continue;
|
||
}
|
||
|
||
/* If no select, stop channel */
|
||
if ((chan_flags[chan] & DEV_SEL) == 0
|
||
&& (chan_flags[chan] & STA_TWAIT)) {
|
||
t_uint64 temp;
|
||
int adr;
|
||
chan_trap:
|
||
if (chan != 0) {
|
||
adr = 100 + (chan * 10) + (chan_info[chan] & 0xf);
|
||
temp = 2;
|
||
if (chan_info[chan] & CHAN_TWE)
|
||
temp = 0;
|
||
else if (chan_flags[chan] & CHS_ERR)
|
||
temp = 1;
|
||
else if (chan_flags[chan] & CHS_EOF)
|
||
temp = 5;
|
||
else if (chan_info[chan] & CHAN_SEOS)
|
||
temp = 6;
|
||
else if (chan_info[chan] & CHAN_SCLR)
|
||
temp = 7;
|
||
else if ((chan_info[chan] & CHAN_NORDW) == 0) {
|
||
if ((chan_info[chan] & CHAN_SEOR) == 0 &&
|
||
caddr[chan] > limit[chan])
|
||
temp = 4;
|
||
else if (caddr[chan] < limit[chan])
|
||
temp = 3;
|
||
}
|
||
chan_flags[chan] &= ~(CHS_ERR|CHS_EOF);
|
||
temp <<= 32;
|
||
if (chan_info[chan] & CHAN_NORDW) {
|
||
temp |= M[adr] & 0xFFFFFFFFLL;
|
||
} else {
|
||
upd_idx(&temp, caddr[chan]);
|
||
bin_dec(&temp, location[chan], 0, 4);
|
||
}
|
||
temp |= PSIGN;
|
||
/* Copy over flag */
|
||
temp |= M[adr] & 0xF000000000LL;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_TRAP, &chan_dev,
|
||
"chan %d Trap: %012llx prio=%d\n\r", chan,
|
||
temp, (chan_info[chan]&CHAN_PRIO)?1:0);
|
||
M[adr] = temp;
|
||
if ((chan_info[chan] & CHAN_PRIO) ||
|
||
((temp >> 32) & 0xf) != 2)
|
||
pri_latchs[chan] |= 1 << (chan_info[chan] & 0xF);
|
||
chan_info[chan] &= ~CHAN_PRIO;
|
||
} else if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_TRAP, &chan_dev, "chan %d Trap %04x\n",
|
||
chan, chan_info[chan]);
|
||
chan_flags[chan] &=
|
||
~(STA_START | STA_ACTIVE | STA_WAIT | STA_TWAIT);
|
||
continue;
|
||
}
|
||
|
||
/* No activity, nothing happening here folks, move along */
|
||
if ((chan_flags[chan] & (STA_ACTIVE | STA_WAIT)) == 0) {
|
||
/* This could be a no data command, if pending priorty
|
||
request, ask device if it is ready */
|
||
if ((cmd[chan] & CHN_SEGMENT) == 0 &&
|
||
chan_info[chan] & CHAN_PRIO &&
|
||
chan_issue_cmd(chan, IO_TRS, chan_info[chan]&0xf)
|
||
== SCPE_OK)
|
||
goto chan_trap;
|
||
continue;
|
||
}
|
||
|
||
/* If first time through here, load up channel control */
|
||
if (chan_flags[chan] & STA_ACTIVE && chan_info[chan] & CHAN_START)
|
||
chan_fetch(chan);
|
||
|
||
/* Process reading of a segment command */
|
||
if ((cmd[chan] & (CHN_SEGMENT|CHN_RM_FND)) ==
|
||
(CHN_SEGMENT|CHN_RM_FND)) {
|
||
/* Two backspaces and a read */
|
||
switch (cmd[chan] & (CHN_RM_FND|CHN_NUM_MODE|CHN_COMPRESS)) {
|
||
case CHN_RM_FND:
|
||
if (chan_issue_cmd(chan, IO_BSR,
|
||
chan_info[chan]&0xf) == SCPE_OK) {
|
||
cmd[chan] |= CHN_COMPRESS;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"segment %d bsr 2\n\r", chan);
|
||
}
|
||
break;
|
||
case CHN_RM_FND|CHN_COMPRESS:
|
||
if (chan_issue_cmd(chan, IO_BSR,
|
||
chan_info[chan]&0xf) == SCPE_OK) {
|
||
cmd[chan] |= CHN_NUM_MODE;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"segment %d bsr 2\n\r", chan);
|
||
if (chan_flags[chan] & CHS_BOT) {
|
||
chan_flags[chan] &= ~(STA_ACTIVE);
|
||
goto chan_trap;
|
||
}
|
||
}
|
||
break;
|
||
case CHN_RM_FND|CHN_NUM_MODE|CHN_COMPRESS:
|
||
chan_info[chan] &= ~(CHAN_SEOS|CHAN_FIRST);
|
||
if ( chan_issue_cmd(chan, IO_RDS,
|
||
chan_info[chan]&0xf) == SCPE_OK) {
|
||
cmd[chan] &= ~(CHN_NUM_MODE|CHN_COMPRESS|CHN_RM_FND);
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"segment %d read\n\r", chan);
|
||
chan_flags[chan] &= ~(STA_WAIT|DEV_REOR);
|
||
}
|
||
break;
|
||
}
|
||
/* Device ready, decide command to issue */
|
||
if (cmd[chan] & CHN_RECORD) {
|
||
if (chan_flags[chan] & CHS_BOT) {
|
||
chan_flags[chan] |= STA_TWAIT;
|
||
}
|
||
/* Two backspaces and a read */
|
||
} else if (chan_flags[chan] & CHS_EOT) {
|
||
chan_flags[chan] |= STA_TWAIT;
|
||
}
|
||
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:
|
||
/* Process reading of a segment command */
|
||
if (cmd[chan] & CHN_SEGMENT) {
|
||
/* Check if hit end of record */
|
||
#if 0 /* Check segment operation correct before removing */
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chk segment %d %d data = %012llx",
|
||
chan, bcnt[chan], assembly[chan]);
|
||
|
||
if ((chan_flags[chan] & (STA_WAIT|DEV_REOR))
|
||
== (STA_WAIT|DEV_REOR)) {
|
||
chan_flags[chan] &= ~(STA_WAIT|DEV_REOR|DEV_FULL);
|
||
chan_info[chan] &= ~(CHAN_SEOS|CHAN_FIRST);
|
||
continue;
|
||
}
|
||
|
||
if (bcnt[chan] >= 6 && chan_flags[chan] & DEV_REOR) {
|
||
if (chan_info[chan] & CHAN_SEOS) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev, " found\n");
|
||
/* Correct error */
|
||
chan_info[chan] &= ~(CHAN_TWE|CHAN_SEOS|CHAN_SCLR);
|
||
/* What we were looking for? */
|
||
if (caddr[chan] >= limit[chan]) {
|
||
chan_flags[chan] &= ~(STA_ACTIVE|CHS_EOF);
|
||
chan_flags[chan] |= STA_TWAIT;
|
||
chan_info[chan] |= CHAN_SEOR;
|
||
} else
|
||
caddr[chan]++;
|
||
}
|
||
chan_info[chan] &= ~(CHAN_SEOS|CHAN_FIRST|CHAN_TWE);
|
||
chan_flags[chan] &= ~(DEV_FULL|DEV_REOR|CHS_ERR);
|
||
} else
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev, " search\n");
|
||
/* How about regular record */
|
||
chan_flags[chan] &= ~DEV_FULL;
|
||
/* Wait for next record */
|
||
chan_flags[chan] |= STA_WAIT|DEV_DISCO;
|
||
if (cmd[chan] & CHN_RECORD)
|
||
cmd[chan] |= CHN_RM_FND;
|
||
else
|
||
cmd[chan] |= CHN_RM_FND|CHN_COMPRESS|CHN_NUM_MODE;
|
||
assembly[chan] = 0;
|
||
bcnt[chan] = 10;
|
||
#endif
|
||
continue;
|
||
}
|
||
|
||
/* If we are not waiting EOR save it in memory */
|
||
if ((chan_flags[chan] & STA_WAIT) == 0) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d data < %011llx\n",
|
||
chan, assembly[chan]);
|
||
if (caddr[chan] < MEMSIZE)
|
||
M[caddr[chan]] = assembly[chan];
|
||
|
||
if (bcnt[chan] != 0)
|
||
chan_info[chan] |= CHAN_SCLR;
|
||
else
|
||
chan_info[chan] &= ~CHAN_SCLR;
|
||
/* Check if last transfer before final */
|
||
if (caddr[chan] >= limit[chan] && cmd[chan] & CHN_LAST) {
|
||
chan_flags[chan] &= ~(STA_ACTIVE);
|
||
chan_flags[chan] |= STA_TWAIT|STA_WAIT;
|
||
} else
|
||
caddr[chan]++;
|
||
|
||
/* Update channel status word */
|
||
if (chan != 0 && (chan_info[chan] & CHAN_NORDW) == 0) {
|
||
int adr = 100 + (chan * 10) + (chan_info[chan]&0xf);
|
||
upd_idx(&M[adr], caddr[chan]);
|
||
bin_dec(&M[adr], location[chan], 0, 4);
|
||
}
|
||
|
||
/* Check for record mark */
|
||
if ((cmd[chan] & CHN_RECORD) &&
|
||
(assembly[chan] & SMASK) == ASIGN &&
|
||
(assembly[chan] & 0xFF) == RM_CHAR) {
|
||
if (cmd[chan] & CHN_LAST) {
|
||
chan_flags[chan] &= ~(STA_ACTIVE);
|
||
chan_flags[chan] |= STA_TWAIT|STA_WAIT;
|
||
} else
|
||
chan_fetch(chan);
|
||
}
|
||
bcnt[chan] = 10;
|
||
assembly[chan] = 0;
|
||
}
|
||
chan_info[chan] |= CHAN_FIRST; /* Saved one char */
|
||
chan_flags[chan] &= ~DEV_FULL;
|
||
|
||
/* Device does not need a word and has not given us one */
|
||
case 0:
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
/* Check EOR at end of segment */
|
||
if (cmd[chan] & CHN_SEGMENT) {
|
||
if ((chan_info[chan] & CHAN_FIRST) == 0 &&
|
||
bcnt[chan] == 8 &&
|
||
assembly[chan] == (ASIGN|(((t_uint64)SM_MEM) << 32))){
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chk segment %d %d data = %012llx found\n\r",
|
||
chan, bcnt[chan], assembly[chan]);
|
||
|
||
/* What we were looking for? */
|
||
if (caddr[chan] >= limit[chan]) {
|
||
chan_flags[chan] &= ~(STA_ACTIVE|CHS_EOF);
|
||
chan_flags[chan] |= STA_TWAIT;
|
||
} else
|
||
caddr[chan]++;
|
||
} else
|
||
/* Check if hit end of record */
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DETAIL, &chan_dev,
|
||
"chk segment %d %d data = %012llx search\n\r",
|
||
chan, bcnt[chan], assembly[chan]);
|
||
/* Correct error */
|
||
chan_info[chan] &= ~(CHAN_TWE|CHAN_SEOS|CHAN_SCLR);
|
||
|
||
assembly[chan] = 0;
|
||
bcnt[chan] = 10;
|
||
chan_flags[chan] &= ~(DEV_REOR|DEV_FULL);
|
||
/* Wait for next record */
|
||
chan_flags[chan] |= STA_WAIT|DEV_DISCO;
|
||
if (cmd[chan] & CHN_RECORD)
|
||
cmd[chan] |= CHN_RM_FND;
|
||
else
|
||
cmd[chan] |= CHN_RM_FND|CHN_COMPRESS|CHN_NUM_MODE;
|
||
continue;
|
||
}
|
||
/* Device idle, expecting data from it */
|
||
/* Check if got EOR */
|
||
chan_flags[chan] &= ~(DEV_REOR|STA_ACTIVE|STA_WAIT);
|
||
chan_flags[chan] |= STA_TWAIT|DEV_DISCO;
|
||
chan_info[chan] |= CHAN_SEOR;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_EXP, &chan_dev, "chan %d EOR< %o\n",
|
||
chan, cmd[chan]);
|
||
continue;
|
||
}
|
||
if (caddr[chan] > limit[chan]
|
||
&& (chan_flags[chan] & STA_WAIT) == 0) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_EXP, &chan_dev,
|
||
"chan %d < WC0 %o\n", chan, cmd[chan]);
|
||
if (cmd[chan] & CHN_LAST) {
|
||
chan_flags[chan] &= ~(STA_ACTIVE);
|
||
chan_flags[chan] |= STA_TWAIT|STA_WAIT|DEV_DISCO;
|
||
chan_info[chan] &= ~CHAN_SEOR;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_EXP, &chan_dev,
|
||
"chan %d < DISCO\n", chan);
|
||
} else
|
||
chan_fetch(chan);
|
||
}
|
||
break;
|
||
|
||
/* Device has word, but has not taken it yet */
|
||
case DEV_WRITE | DEV_FULL:
|
||
continue; /* Do nothing if no data xfer pending */
|
||
|
||
/* Device needs a word of data */
|
||
case DEV_WRITE: /* Device needs data word */
|
||
/* If we are waiting on EOR, do nothing */
|
||
if (chan_flags[chan] & STA_WAIT)
|
||
continue;
|
||
|
||
/* Special for write segment mark command */
|
||
if (cmd[chan] & CHN_SEGMENT) {
|
||
/* Send one char */
|
||
assembly[chan] = SM_MEM;
|
||
bcnt[chan] = 2;
|
||
caddr[chan] = limit[chan]+1;
|
||
chan_flags[chan] &= ~(STA_ACTIVE);
|
||
chan_flags[chan] |= STA_TWAIT|STA_WAIT|DEV_FULL|DEV_WEOR;
|
||
cmd[chan] = CHN_ALPHA|CHN_SEGMENT;
|
||
chan_info[chan] |= CHAN_NORDW;
|
||
continue;
|
||
}
|
||
/* Give device new word if we have one */
|
||
if (caddr[chan] <= limit[chan]) {
|
||
/* Check if got EOR */
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
chan_flags[chan] &= ~(STA_WAIT | DEV_REOR
|
||
| STA_ACTIVE);
|
||
chan_flags[chan] |= STA_TWAIT;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_EXP, &chan_dev,
|
||
"chan %d EOR> %o\n", chan, cmd[chan] & 070);
|
||
continue;
|
||
}
|
||
|
||
if (caddr[chan] < MEMSIZE)
|
||
assembly[chan] = M[caddr[chan]];
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d data > %011llx\n", chan,
|
||
assembly[chan]);
|
||
bcnt[chan] = 10;
|
||
chan_flags[chan] |= DEV_FULL;
|
||
|
||
/* Check if last transfer before final */
|
||
if (caddr[chan] >= limit[chan] && cmd[chan] & CHN_LAST) {
|
||
chan_flags[chan] &= ~(STA_ACTIVE);
|
||
chan_flags[chan] |= STA_TWAIT|STA_WAIT;
|
||
} else
|
||
caddr[chan]++;
|
||
|
||
/* Update channel status word */
|
||
if (chan != 0 && (chan_info[chan] & CHAN_NORDW) == 0) {
|
||
int adr = 100 + (chan * 10) + (chan_info[chan]&0xf);
|
||
upd_idx(&M[adr], caddr[chan]);
|
||
bin_dec(&M[adr], location[chan], 0, 4);
|
||
}
|
||
|
||
/* Check for record mark */
|
||
if ((cmd[chan] & CHN_RECORD) &&
|
||
(assembly[chan] & SMASK) == ASIGN &&
|
||
(assembly[chan] & 0xFF) == RM_CHAR) {
|
||
if (cmd[chan] & CHN_LAST) {
|
||
chan_flags[chan] &= ~(STA_ACTIVE);
|
||
chan_flags[chan] |= STA_TWAIT|STA_WAIT;
|
||
} else
|
||
chan_fetch(chan);
|
||
}
|
||
|
||
continue; /* Don't start next command until data taken */
|
||
}
|
||
|
||
/* Wait for device to recognize EOR */
|
||
if (chan_flags[chan] & DEV_WEOR)
|
||
continue;
|
||
|
||
/* Get here if passed limit */
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_EXP, &chan_dev, "chan %d > WC0 %o stat=%x\n",
|
||
chan, cmd[chan] & 070, chan_flags[chan]);
|
||
|
||
if (cmd[chan] & CHN_LAST) {
|
||
chan_flags[chan] |= DEV_DISCO | DEV_WEOR | STA_TWAIT;
|
||
chan_flags[chan] &= ~(STA_START | STA_ACTIVE);
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_EXP, &chan_dev,
|
||
"chan %d > DISCO\n", chan);
|
||
} else
|
||
chan_fetch(chan);
|
||
}
|
||
break;
|
||
case CHAN_7907:
|
||
/* If channel is disconnecting, just hold on */
|
||
if (chan_flags[chan] & DEV_DISCO)
|
||
continue;
|
||
|
||
/* If no select, stop channel */
|
||
if ((chan_flags[chan] & DEV_SEL) == 0
|
||
&& (chan_flags[chan] & STA_TWAIT)) {
|
||
t_uint64 temp;
|
||
|
||
temp = 2;
|
||
if (chan_info[chan] & CHAN_TWE)
|
||
temp = 1;
|
||
else if (chan_flags[chan] & SNS_UEND)
|
||
temp = 5;
|
||
else if ((chan_info[chan] & CHAN_SEOR) == 0 && op[chan] == 1)
|
||
temp = 4;
|
||
else if (caddr[chan] <= limit[chan] &&
|
||
(op[chan] == 1 || op[chan] == 3))
|
||
temp = 3;
|
||
temp <<= 36;
|
||
chan_irq[chan] |= chan_flags[chan] & (SNS_ATTN1|SNS_ATTN2);
|
||
temp |= (chan_irq[chan])?MSIGN:PSIGN;
|
||
chan_flags[chan] &= ~(SNS_UEND|CTL_CNTL|CTL_SNS|CTL_READ|
|
||
CTL_WRITE|CTL_PREAD|CTL_PWRITE);
|
||
upd_idx(&temp, caddr[chan]);
|
||
bin_dec(&temp, location[chan], 0, 4);
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_TRAP, &chan_dev, "chan %d Trap: %012llx\n",
|
||
chan, temp);
|
||
M[(chan - 4) + 300] = temp;
|
||
if ((chan_info[chan] & CHAN_PRIO) || ((temp >> 36) & 0xf) != 2)
|
||
pri_latchs[8] |= 1<<(4-chan);
|
||
chan_flags[chan] &=
|
||
~(STA_START | STA_ACTIVE | STA_WAIT | STA_TWAIT);
|
||
chan_info[chan] &= ~CHAN_PRIO;
|
||
continue;
|
||
}
|
||
|
||
/* Check if device raised attention */
|
||
if ((chan_flags[chan] & (STA_ACTIVE|DEV_SEL|STA_TWAIT)) == 0 &&
|
||
(chan_flags[chan] & (SNS_ATTN1|SNS_ATTN2))) {
|
||
t_uint64 temp;
|
||
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_TRAP, &chan_dev, "chan %d Attn Trap\n",
|
||
chan);
|
||
temp = 2;
|
||
if (chan_flags[chan] & SNS_UEND)
|
||
temp = 5;
|
||
temp <<= 36;
|
||
temp |= MSIGN;
|
||
chan_irq[chan] |= chan_flags[chan] & (SNS_ATTN1|SNS_ATTN2);
|
||
chan_flags[chan] &= ~(SNS_ATTN1|SNS_ATTN2|SNS_UEND);
|
||
upd_idx(&temp, caddr[chan]);
|
||
bin_dec(&temp, location[chan], 0, 4);
|
||
M[(chan - 4) + 300] = temp;
|
||
pri_latchs[9] |= 1 << (4 - chan);
|
||
continue;
|
||
}
|
||
|
||
/* Nothing more to do if not active. */
|
||
if (chan_flags[chan] & STA_ACTIVE) {
|
||
t_uint64 temp;
|
||
|
||
/* Execute the next command */
|
||
switch (op[chan]) {
|
||
case 6: /* Tranfer in channel */
|
||
/* I am not sure if this is correct, but it passes
|
||
diagnostics */
|
||
location[chan] = limit[chan];
|
||
break;
|
||
case 0: /* Write status */
|
||
temp = PSIGN|(2LL << 36);
|
||
upd_idx(&temp, caddr[chan]);
|
||
bin_dec(&temp, location[chan], 0, 4);
|
||
M[caddr[chan]] = temp;
|
||
break;
|
||
case 1: /* Read */
|
||
/* Check if in other mode */
|
||
if (chan_flags[chan] & (CTL_CNTL)) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d read busy %04x\n",
|
||
chan, chan_flags[chan]);
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
chan_flags[chan] &=
|
||
~(CTL_CNTL|DEV_REOR|DEV_WRITE);
|
||
} else
|
||
continue;
|
||
}
|
||
/* Check if last command not finished */
|
||
if (chan_flags[chan] & (CTL_SNS|CTL_WRITE)) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d read busy %04x\n",
|
||
chan, chan_flags[chan]);
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan_flags[chan] |= DEV_DISCO;
|
||
chan_flags[chan] &= ~(CTL_SNS|CTL_WRITE);
|
||
}
|
||
continue;
|
||
}
|
||
|
||
/* If not already in read mode, set read mode */
|
||
if ((chan_flags[chan] & CTL_READ) == 0) {
|
||
chan_flags[chan] |= CTL_READ;
|
||
chan_flags[chan] &= ~(DEV_FULL|DEV_WRITE|DEV_REOR);
|
||
chan_info[chan] &= ~CHAN_SEOR;
|
||
bcnt[chan] = 10;
|
||
assembly[chan] = 0;
|
||
continue;
|
||
}
|
||
|
||
/* Has device given us a word */
|
||
if (chan_flags[chan] & DEV_FULL) {
|
||
/* Check if record mark */
|
||
if ((cmd[chan] & CHN_RECORD) &&
|
||
(assembly[chan] & SMASK) == ASIGN &&
|
||
(assembly[chan] & 0xFF) == RM_CHAR) {
|
||
break;
|
||
}
|
||
|
||
|
||
/* Check if ready to transfer something */
|
||
if (caddr[chan] <= limit[chan]) {
|
||
M[caddr[chan]] = assembly[chan];
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d data > %012llx\n",
|
||
chan, assembly[chan]);
|
||
caddr[chan]++;
|
||
bcnt[chan] = 10;
|
||
assembly[chan] = 0;
|
||
chan_flags[chan] &= ~DEV_FULL;
|
||
/* Check if last word transfered */
|
||
if (caddr[chan] > limit[chan])
|
||
break;
|
||
}
|
||
|
||
/* Check if we still have a select signal */
|
||
if ((chan_flags[chan] & DEV_SEL) == 0) {
|
||
chan_info[chan] |= CHAN_TWE;
|
||
chan_flags[chan] &=
|
||
~(CTL_WRITE|CTL_END|STA_ACTIVE);
|
||
break;
|
||
}
|
||
|
||
/* Device gave us a EOR, get next word */
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
chan_info[chan] |= CHAN_SEOR;
|
||
chan_flags[chan] &= ~DEV_REOR;
|
||
break;
|
||
}
|
||
continue;
|
||
}
|
||
|
||
/* Abort if we get control end */
|
||
if (chan_flags[chan] & CTL_END) {
|
||
/* Disconnect channel if select still active */
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan_flags[chan] |= (DEV_DISCO);
|
||
}
|
||
if (chan_flags[chan] & DEV_REOR)
|
||
chan_info[chan] |= CHAN_SEOR;
|
||
chan_flags[chan] &=
|
||
~(DEV_REOR|CTL_SNS|CTL_READ|CTL_WRITE|CTL_END);
|
||
break;
|
||
}
|
||
continue;
|
||
|
||
case 3: /* Write */
|
||
/* Check if in other mode */
|
||
if (chan_flags[chan] & (CTL_CNTL)) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d write busy %04x\n",
|
||
chan, chan_flags[chan]);
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
chan_flags[chan] &=
|
||
~(CTL_CNTL|DEV_REOR|DEV_WRITE);
|
||
} else
|
||
continue;
|
||
}
|
||
/* Check if last command not finished */
|
||
if (chan_flags[chan] & (CTL_SNS|CTL_READ)) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d write busy %04x\n",
|
||
chan, chan_flags[chan]);
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan_flags[chan] |= DEV_DISCO;
|
||
chan_flags[chan] &= ~(CTL_READ|CTL_SNS);
|
||
}
|
||
continue;
|
||
}
|
||
|
||
/* If not in write, flag as write */
|
||
if ((chan_flags[chan] & CTL_WRITE) == 0) {
|
||
chan_flags[chan] |= CTL_WRITE|DEV_WRITE;
|
||
}
|
||
|
||
/* Command finished?*/
|
||
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] &=
|
||
~(DEV_REOR|CTL_SNS|CTL_READ|CTL_WRITE|CTL_END);
|
||
break;
|
||
}
|
||
|
||
/* Check if we still have a select signal */
|
||
if ((chan_flags[chan] & DEV_SEL) == 0 &&
|
||
caddr[chan] < limit[chan]) {
|
||
chan_info[chan] |= CHAN_TWE;
|
||
chan_flags[chan] &= ~(CTL_WRITE|CTL_END|STA_ACTIVE);
|
||
break;
|
||
}
|
||
|
||
/* Check if device needs data */
|
||
if ((chan_flags[chan] & DEV_FULL) == 0) {
|
||
/* Got EOR? */
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
if (caddr[chan] > limit[chan]) {
|
||
chan_info[chan] |= CHAN_SEOR;
|
||
}
|
||
chan_flags[chan] |= DEV_DISCO;
|
||
chan_flags[chan] &= ~DEV_REOR;
|
||
break;
|
||
}
|
||
|
||
|
||
/* Check if ready to transfer something */
|
||
if (caddr[chan] <= limit[chan]) {
|
||
assembly[chan] = M[caddr[chan]];
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d data > %012llx\n",
|
||
chan, assembly[chan]);
|
||
caddr[chan]++;
|
||
bcnt[chan] = 10;
|
||
chan_flags[chan] |= DEV_FULL;
|
||
/* Check if record mark */
|
||
if ((cmd[chan] & CHN_RECORD) &&
|
||
(assembly[chan] & SMASK) == ASIGN &&
|
||
(assembly[chan] & 0xFF) == RM_CHAR) {
|
||
chan_flags[chan] |= DEV_WEOR;
|
||
break;
|
||
}
|
||
continue;
|
||
}
|
||
chan_info[chan] |= CHAN_SEOR;
|
||
break;
|
||
}
|
||
continue;
|
||
|
||
case 5: /* Sense */
|
||
/* Check if in other mode */
|
||
if (chan_flags[chan] & (CTL_CNTL)) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d sense busy %04x\n",
|
||
chan, chan_flags[chan]);
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
chan_flags[chan] &=
|
||
~(CTL_CNTL|DEV_REOR|DEV_WRITE);
|
||
} else
|
||
continue;
|
||
}
|
||
if (chan_flags[chan] & CTL_SNS) {
|
||
/* Check if we still have a select signal */
|
||
if ((chan_flags[chan] & DEV_SEL) == 0) {
|
||
chan_info[chan] |= CHAN_TWE;
|
||
chan_flags[chan] &= ~(CTL_SNS|STA_ACTIVE);
|
||
chan_flags[chan] |= STA_TWAIT;
|
||
break;
|
||
}
|
||
|
||
/* If device ended, quit transfer */
|
||
if ((chan_flags[chan] & DEV_FULL) == 0) {
|
||
if (chan_flags[chan] & CTL_END) {
|
||
/* Disconnect channel if select still active */
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan_flags[chan] |= (DEV_DISCO);
|
||
}
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
chan_info[chan] |= CHAN_SEOR;
|
||
chan_flags[chan] &= ~DEV_REOR;
|
||
}
|
||
chan_flags[chan] &= ~(CTL_SNS);
|
||
break;
|
||
}
|
||
|
||
/* Check if last word transfered */
|
||
if (caddr[chan] > limit[chan]) {
|
||
if (chan_flags[chan] & SNS_UEND) {
|
||
chan_flags[chan] |=
|
||
(DEV_DISCO | DEV_WEOR);
|
||
chan_flags[chan] &= ~(DEV_SEL);
|
||
} else {
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
chan_flags[chan] &= ~DEV_REOR;
|
||
chan_info[chan] |= CHAN_SEOR;
|
||
}
|
||
}
|
||
chan_flags[chan] &= ~(CTL_SNS);
|
||
break;
|
||
}
|
||
} else {
|
||
/* Device has given us a dataword */
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d data < %012llx\n",
|
||
chan, assembly[chan]);
|
||
M[caddr[chan]] = assembly[chan];
|
||
assembly[chan] = 0;
|
||
bcnt[chan] = 10;
|
||
chan_flags[chan] &= ~DEV_FULL;
|
||
if (caddr[chan] >= limit[chan])
|
||
break;
|
||
caddr[chan]++;
|
||
}
|
||
/* Handle EOR on sense */
|
||
if (chan_flags[chan] & DEV_REOR) {
|
||
chan_flags[chan] &= ~(CTL_SNS|DEV_REOR);
|
||
chan_info[chan] |= CHAN_SEOR;
|
||
break;
|
||
}
|
||
continue;
|
||
}
|
||
|
||
/* Check if in other mode */
|
||
if (chan_flags[chan] & (CTL_CNTL|CTL_READ|CTL_WRITE)) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d sense busy %04x\n",
|
||
chan, chan_flags[chan]);
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan_flags[chan] |= DEV_DISCO|DEV_WEOR|STA_WAIT;
|
||
}
|
||
chan_flags[chan] &= ~(CTL_CNTL|CTL_READ|CTL_WRITE);
|
||
continue;
|
||
}
|
||
|
||
/* Start sense command */
|
||
chan_flags[chan] |= CTL_SNS;
|
||
chan_flags[chan] &= ~(CTL_END|DEV_REOR|DEV_FULL);
|
||
switch(chan_issue_cmd(chan,0,chan_test(chan, CTL_SEL))){
|
||
case SCPE_IOERR:
|
||
case SCPE_NODEV:
|
||
chan_info[chan] |= CHAN_TWE;
|
||
chan_flags[chan] &= ~STA_ACTIVE;
|
||
case SCPE_BUSY: /* Device not ready yet, wait */
|
||
chan_flags[chan] &= ~(CTL_SNS);
|
||
continue;
|
||
case SCPE_OK:
|
||
/* Device will be waiting for command */
|
||
break;
|
||
}
|
||
/* Get channel ready to transfer */
|
||
chan_flags[chan] &= ~DEV_WRITE;
|
||
chan_flags[chan] |= DEV_SEL;
|
||
continue;
|
||
|
||
case 4: /* Transfer command */
|
||
if (chan_flags[chan] & CTL_CNTL)
|
||
goto xfer;
|
||
if (chan_flags[chan] & (CTL_READ|CTL_WRITE|CTL_SNS)) {
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_DATA, &chan_dev,
|
||
"chan %d control busy %04x\n",
|
||
chan, chan_flags[chan]);
|
||
if (chan_flags[chan] & DEV_SEL) {
|
||
chan_flags[chan] |= DEV_DISCO|DEV_WEOR|STA_WAIT;
|
||
}
|
||
chan_flags[chan] &= ~(CTL_SNS|CTL_READ|CTL_WRITE);
|
||
continue;
|
||
}
|
||
chan_flags[chan] |= CTL_CNTL;
|
||
/* Get channel ready to transfer */
|
||
chan_flags[chan] &= ~(CTL_END|DEV_REOR|DEV_FULL);
|
||
|
||
switch(chan_issue_cmd(chan,0,chan_stat(chan,CTL_SEL))){
|
||
case SCPE_IOERR:
|
||
case SCPE_NODEV:
|
||
chan_info[chan] |= CHAN_TWE;
|
||
chan_flags[chan] &=
|
||
~(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;
|
||
}
|
||
|
||
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|CTL_CNTL);
|
||
chan_info[chan] |= CHAN_SEOR;
|
||
break;
|
||
}
|
||
|
||
/* Wait for device to grab the command */
|
||
if (chan_flags[chan] & DEV_FULL)
|
||
continue;
|
||
|
||
/* Check if device ready for next command word */
|
||
if ((chan_flags[chan] & (DEV_WRITE | DEV_FULL)) ==
|
||
DEV_WRITE) {
|
||
if (caddr[chan] <= limit[chan]) {
|
||
assembly[chan] = M[caddr[chan]];
|
||
chan_flags[chan] |= DEV_FULL;
|
||
bcnt[chan] = 10;
|
||
if (chan_dev.dctrl & cmask)
|
||
sim_debug(DEBUG_CMD, &chan_dev,
|
||
"chan %d cmd > %012llx\n",
|
||
chan, assembly[chan]);
|
||
if (caddr[chan] < limit[chan])
|
||
caddr[chan]++;
|
||
continue;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case 2: /* Read Backwards */
|
||
/* Unknown commands at moment */
|
||
case 7:
|
||
case 8:
|
||
case 9:
|
||
chan_info[chan] |= CHAN_TWE;
|
||
if (chan_flags[chan] & DEV_SEL)
|
||
chan_flags[chan] |= DEV_DISCO;
|
||
chan_flags[chan] &=
|
||
~(STA_ACTIVE|CTL_WRITE|CTL_READ|CTL_CNTL|CTL_SNS);
|
||
break;
|
||
|
||
}
|
||
|
||
/* If last all done */
|
||
if (cmd[chan] & CHN_LAST || chan_flags[chan] & (SNS_UEND)
|
||
|| chan_info[chan] & CHAN_TWE) {
|
||
if (chan_flags[chan] & DEV_SEL)
|
||
chan_flags[chan] |= DEV_DISCO;
|
||
chan_flags[chan] &= ~(STA_ACTIVE);
|
||
chan_flags[chan] |= STA_TWAIT;
|
||
} else
|
||
chan_fetch(chan);
|
||
}
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
|
||
void
|
||
chan_fetch(int chan)
|
||
{
|
||
uint32 loc = location[chan];
|
||
t_uint64 temp;
|
||
|
||
sim_interval--;
|
||
chan_info[chan] &= ~CHAN_START;
|
||
if (loc < MEMSIZE)
|
||
temp = M[loc];
|
||
else {
|
||
cmd[chan] |= CHN_LAST;
|
||
return;
|
||
}
|
||
location[chan] = (loc + 1);
|
||
if ((temp & SMASK) == MSIGN)
|
||
cmd[chan] |= CHN_LAST;
|
||
get_rdw(temp, &caddr[chan], &limit[chan]);
|
||
op[chan] = (temp >> 36) & 0xf;
|
||
if (chan_dev.dctrl & (0x0100 << chan))
|
||
sim_debug(DEBUG_CHAN, &chan_dev,
|
||
"chan %d fetch adr=%05d op=%d cmd=%03o caddr=%05d limit=%05d\n",
|
||
chan, loc, op[chan], cmd[chan], caddr[chan], limit[chan]);
|
||
}
|
||
|
||
void chan_set_attn_a(int chan) {
|
||
pri_latchs[0] |= 0x002;
|
||
}
|
||
|
||
void chan_set_attn_b(int chan) {
|
||
pri_latchs[0] |= 0x004;
|
||
}
|
||
|
||
void chan_set_attn_inq(int chan) {
|
||
if (chan == CHAN_UREC)
|
||
pri_latchs[0] |= 0x080;
|
||
else
|
||
pri_latchs[0] |= 0x100;
|
||
}
|
||
|
||
void chan_clear_attn_inq(int chan) {
|
||
if (chan == CHAN_UREC)
|
||
pri_latchs[0] &= ~0x080;
|
||
else
|
||
pri_latchs[0] &= ~0x100;
|
||
}
|
||
|
||
|
||
/* Issue a command to a channel */
|
||
int
|
||
chan_cmd(uint16 dev, uint16 dcmd, uint16 addr)
|
||
{
|
||
uint32 chan;
|
||
int prio;
|
||
t_stat r;
|
||
|
||
/* Find device on given channel and give it the command */
|
||
chan = (dev >> 8) & 0xf;
|
||
/* If no channel device, quick exit */
|
||
if (chan_unit[chan].flags & UNIT_DIS)
|
||
return SCPE_IOERR;
|
||
/* Unit is busy doing something, wait */
|
||
if (chan_flags[chan] & (DEV_SEL|DEV_DISCO|STA_TWAIT|STA_WAIT|STA_ACTIVE))
|
||
return SCPE_BUSY;
|
||
/* Ok, try and find the unit */
|
||
prio = (dev & 0x1000)? 1: 0;
|
||
dev &= 0xff;
|
||
location[chan] = addr;
|
||
cmd[chan] = dcmd & 0xff;
|
||
dcmd >>= 8;
|
||
chan_info[chan] = (dev & 0xf) | (chan << 4);
|
||
chan_info[chan] |= CHAN_START;
|
||
/* Special check for console */
|
||
if (chan == 0 && dev == 0)
|
||
chan_info[chan] |= CHAN_OUTDEV;
|
||
|
||
/* Check for octal translation */
|
||
if (chan == 1 && dev & 020)
|
||
chan_info[chan] |= CHAN_OCTAL;
|
||
|
||
/* Enable priority */
|
||
if (prio)
|
||
chan_info[chan] |= CHAN_PRIO;
|
||
assembly[chan] = 0;
|
||
bcnt[chan] = 10;
|
||
|
||
if (CHAN_G_TYPE(chan_unit[chan].flags) == CHAN_7907) {
|
||
chan_flags[chan] |= STA_ACTIVE;
|
||
if (dev & 1)
|
||
chan_flags[chan] |= CTL_SEL;
|
||
else
|
||
chan_flags[chan] &= ~CTL_SEL;
|
||
chan_fetch(chan);
|
||
return SCPE_OK;
|
||
}
|
||
r = chan_issue_cmd(chan, dcmd, dev);
|
||
if (r != SCPE_OK) {
|
||
/* No device, kill active */
|
||
chan_flags[chan] &= ~(STA_ACTIVE);
|
||
} else {
|
||
extern uint32 IC;
|
||
/* If transfering data, activate channel */
|
||
if (chan_flags[chan] & DEV_SEL)
|
||
chan_flags[chan] |= STA_ACTIVE;
|
||
|
||
if (chan_dev.dctrl & (0x0100 << chan))
|
||
sim_debug(DEBUG_CMD, &chan_dev,
|
||
"chan %d cmd=%o IC=%05d addr=%05d\n\r", chan, dcmd, IC, addr);
|
||
}
|
||
return r;
|
||
}
|
||
|
||
/*
|
||
* Write a word to the assembly register.
|
||
*/
|
||
int
|
||
chan_write(int chan, t_uint64 * data, int flags)
|
||
{
|
||
return TIME_ERROR;
|
||
}
|
||
|
||
/*
|
||
* Read next word from assembly register.
|
||
*/
|
||
int
|
||
chan_read(int chan, t_uint64 * data, int flags)
|
||
{
|
||
return TIME_ERROR;
|
||
}
|
||
|
||
/*
|
||
* Write a char to the assembly register.
|
||
*/
|
||
int
|
||
chan_write_char(int chan, uint8 * data, int flags)
|
||
{
|
||
uint8 ch = *data;
|
||
/* 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_WEOR;
|
||
chan_flags[chan] |= DEV_REOR;
|
||
return END_RECORD;
|
||
}
|
||
if (chan_flags[chan] & STA_ACTIVE) {
|
||
chan_flags[chan] |= CHS_ATTN; /* We had error */
|
||
}
|
||
if (chan == 0) {
|
||
chan_flags[chan] |= DEV_DISCO;
|
||
}
|
||
return TIME_ERROR;
|
||
}
|
||
|
||
#if 0 /* Check segment working before removing */
|
||
/* Check for segment mark */
|
||
if (flags & DEV_REOR && (chan_info[chan] & CHAN_FIRST) == 0) {
|
||
if (ch == SM_CHAR)
|
||
chan_info[chan] |= CHAN_SEOS;
|
||
assembly[chan] |= ASIGN|(((t_uint64)bcd_mem[ch]) << 32);
|
||
if (cmd[chan] & CHN_ALPHA)
|
||
chan_flags[chan] |= DEV_FULL|DEV_REOR;
|
||
else
|
||
chan_flags[chan] |= DEV_REOR;
|
||
chan_flags[chan] &= ~DEV_WRITE;
|
||
chan_proc();
|
||
return END_RECORD;
|
||
}
|
||
|
||
/* Clear first char in record flag */
|
||
chan_info[chan] |= CHAN_FIRST;
|
||
#endif
|
||
|
||
if (ch == DELTA_CHAR && (cmd[chan] & CHN_ALPHA) == 0) {
|
||
if (bcnt[chan] == 10)
|
||
cmd[chan] ^= CHN_NUM_MODE;
|
||
else
|
||
chan_info[chan] |= CHAN_TWE;
|
||
} else {
|
||
if (chan_flags[chan] & CTL_SNS) {
|
||
/* Set sign based on attention signal */
|
||
if (bcnt[chan] == 10) {
|
||
if (chan_irq[chan] & (SNS_ATTN1 >> (chan_info[chan] & 1)))
|
||
assembly[chan] = PSIGN;
|
||
else
|
||
assembly[chan] = MSIGN;
|
||
chan_irq[chan] &= ~(SNS_ATTN1 >> (chan_info[chan] & 1));
|
||
}
|
||
/* Store character */
|
||
ch &= 0x17;
|
||
if (ch & 0x04)
|
||
ch ^= 0x24; /* Bit move */
|
||
ch |= 0x44;
|
||
bcnt[chan]-=2;
|
||
assembly[chan] |= ((t_uint64)ch) << (4 * bcnt[chan]);
|
||
} else if (cmd[chan] & CHN_NUM_MODE) {
|
||
ch &= 0xf;
|
||
if (ch == 0 || ch > 10)
|
||
chan_info[chan] |= CHAN_TWE;
|
||
else if (ch == 10)
|
||
ch = 0;
|
||
bcnt[chan]--;
|
||
assembly[chan] |= ((t_uint64)ch) << (4 * bcnt[chan])|PSIGN;
|
||
/* Check for sign digit */
|
||
switch(*data & 060) {
|
||
case 0: /* Normal digit */
|
||
case 020: /* error */
|
||
if (bcnt[chan] == 0)
|
||
chan_info[chan] |= CHAN_TWE;
|
||
break;
|
||
case 040:
|
||
if (bcnt[chan] > 5)
|
||
chan_info[chan] |= CHAN_TWE;
|
||
assembly[chan] &= DMASK;
|
||
/* Put number in right location */
|
||
while(bcnt[chan] != 0) {
|
||
bcnt[chan]--;
|
||
assembly[chan] >>= 4;
|
||
}
|
||
assembly[chan] |= MSIGN;
|
||
break;
|
||
case 060:
|
||
if (bcnt[chan] > 5)
|
||
chan_info[chan] |= CHAN_TWE;
|
||
assembly[chan] &= DMASK;
|
||
/* Put number in right location */
|
||
while(bcnt[chan] != 0) {
|
||
bcnt[chan]--;
|
||
assembly[chan] >>= 4;
|
||
}
|
||
assembly[chan] |= PSIGN;
|
||
break;
|
||
}
|
||
} else {
|
||
if (chan_info[chan] & CHAN_OCTAL)
|
||
ch = ((ch & 070) << 1) | (ch & 07);
|
||
else
|
||
ch = bcd_mem[ch];
|
||
if (ch == 0xFF) {
|
||
chan_info[chan] |= CHAN_TWE;
|
||
ch = 0;
|
||
}
|
||
bcnt[chan] -= 2;
|
||
assembly[chan] |= ((t_uint64)ch) << (8 * (bcnt[chan] / 2));
|
||
assembly[chan] |= (chan_info[chan] & CHAN_OCTAL)?PSIGN:ASIGN;
|
||
}
|
||
}
|
||
|
||
if (flags & DEV_REOR) {
|
||
chan_flags[chan] |= DEV_FULL|DEV_REOR;
|
||
chan_flags[chan] &= ~DEV_WRITE;
|
||
if (bcnt[chan] != 0 && ((cmd[chan] & (CHN_NUM_MODE)) == 0 ||
|
||
(cmd[chan] & (CHN_ALPHA)) != 0))
|
||
chan_info[chan] |= CHAN_SCLR;
|
||
chan_info[chan] |= CHAN_SEOR;
|
||
chan_proc();
|
||
return END_RECORD;
|
||
} else if (bcnt[chan] == 0) {
|
||
chan_flags[chan] |= DEV_FULL;
|
||
chan_flags[chan] &= ~DEV_WRITE;
|
||
chan_proc();
|
||
}
|
||
|
||
/* If Writing end of record, abort */
|
||
if (flags & DEV_WEOR) {
|
||
chan_flags[chan] &= ~(DEV_FULL | DEV_WEOR);
|
||
return END_RECORD;
|
||
}
|
||
|
||
return DATA_OK;
|
||
}
|
||
|
||
/*
|
||
* Read next char from assembly register.
|
||
*/
|
||
int
|
||
chan_read_char(int chan, uint8 * data, int flags)
|
||
{
|
||
uint8 ch;
|
||
/* Return END_RECORD if requested */
|
||
if (flags & DEV_WEOR) {
|
||
chan_flags[chan] &= ~(DEV_WEOR /*| STA_WAIT*/);
|
||
return END_RECORD;
|
||
}
|
||
|
||
chan_proc();
|
||
|
||
/* Check if he write out last data */
|
||
if ((chan_flags[chan] & DEV_FULL) == 0) {
|
||
if (chan_flags[chan] & DEV_WEOR) {
|
||
chan_flags[chan] &= ~(DEV_WEOR | STA_WAIT | DEV_WRITE);
|
||
chan_flags[chan] |= DEV_REOR|DEV_DISCO;
|
||
return END_RECORD;
|
||
}
|
||
if (chan_flags[chan] & STA_ACTIVE) {
|
||
chan_flags[chan] |= CHS_ATTN;
|
||
}
|
||
if (chan == 0) {
|
||
chan_flags[chan] |= DEV_DISCO;
|
||
}
|
||
return TIME_ERROR;
|
||
}
|
||
|
||
/* Send control words differently */
|
||
if (chan_flags[chan] & CTL_CNTL) {
|
||
if ((assembly[chan] & SMASK) == ASIGN) {
|
||
bcnt[chan] -= 2;
|
||
ch = (assembly[chan] >> (4 * bcnt[chan])) & 0xff;
|
||
*data = mem_bcd[ch];
|
||
} else {
|
||
bcnt[chan]--;
|
||
ch = (assembly[chan] >> (4 * bcnt[chan])) & 0xf;
|
||
if (ch == 0)
|
||
ch = 10;
|
||
*data = ch;
|
||
}
|
||
goto done;
|
||
}
|
||
|
||
/* Handle console type out */
|
||
if (chan_info[chan] & CHAN_OUTDEV) {
|
||
if (bcnt[chan] == 10 && (cmd[chan] & CHN_NUM_MODE) == 0) {
|
||
switch(assembly[chan] & SMASK) {
|
||
case ASIGN: break;
|
||
case PSIGN: *data = 060;
|
||
cmd[chan] |= CHN_NUM_MODE;
|
||
return SCPE_OK;
|
||
case MSIGN: *data = 040;
|
||
cmd[chan] |= CHN_NUM_MODE;
|
||
return SCPE_OK;
|
||
}
|
||
}
|
||
if (cmd[chan] & CHN_NUM_MODE) {
|
||
bcnt[chan]--;
|
||
ch = (assembly[chan] >> (4 * bcnt[chan])) & 0xf;
|
||
if (ch == 0)
|
||
ch = 10;
|
||
if (bcnt[chan] == 0)
|
||
cmd[chan] &= ~CHN_NUM_MODE;
|
||
*data = ch;
|
||
} else {
|
||
bcnt[chan] -= 2;
|
||
ch = (assembly[chan] >> (4 * bcnt[chan])) & 0xff;
|
||
*data = mem_bcd[ch];
|
||
}
|
||
goto done;
|
||
}
|
||
|
||
/* Check for mode change */
|
||
if (bcnt[chan] == 10 && (cmd[chan] & (CHN_ALPHA)) == 0) {
|
||
if (((assembly[chan] & SMASK) == ASIGN &&
|
||
(cmd[chan] & CHN_NUM_MODE) == CHN_NUM_MODE)
|
||
||((assembly[chan] & SMASK) != ASIGN &&
|
||
(cmd[chan] & CHN_NUM_MODE) == CHN_ALPHA_MODE)) {
|
||
*data = DELTA_CHAR;
|
||
cmd[chan] ^= CHN_NUM_MODE;
|
||
return DATA_OK;
|
||
}
|
||
/* Handle zero compression here */
|
||
if ((cmd[chan] & (CHN_NUM_MODE|CHN_COMPRESS)) ==
|
||
(CHN_NUM_MODE|CHN_COMPRESS)) {
|
||
while((assembly[chan] >> (4 * bcnt[chan]) & 0xf) == 0 &&
|
||
bcnt[chan] < 5)
|
||
bcnt[chan]--;
|
||
}
|
||
}
|
||
|
||
/* If in number mode, dump as number */
|
||
if (cmd[chan] & CHN_NUM_MODE) {
|
||
bcnt[chan]--;
|
||
ch = (assembly[chan] >> (4 * bcnt[chan])) & 0xf;
|
||
if (ch == 0)
|
||
ch = 10;
|
||
if (bcnt[chan] == 0)
|
||
ch |= ((assembly[chan] & SMASK) == MSIGN)? 040: 060;
|
||
*data = ch;
|
||
} else {
|
||
bcnt[chan] -= 2;
|
||
ch = (assembly[chan] >> (4 * bcnt[chan])) & 0xff;
|
||
*data = mem_bcd[ch];
|
||
}
|
||
|
||
done:
|
||
if (bcnt[chan] == 0) {
|
||
chan_flags[chan] &= ~DEV_FULL;
|
||
bcnt[chan] = 10;
|
||
}
|
||
/* 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;
|
||
chan_proc();
|
||
} else
|
||
chan_flags[chan] |= DEV_WRITE;
|
||
return DATA_OK;
|
||
}
|
||
|
||
void
|
||
chan_set_load_mode(int chan)
|
||
{
|
||
cmd[chan] &= ~CHN_ALPHA;
|
||
cmd[chan] |= CHN_NUM_MODE;
|
||
}
|
||
|
||
void
|
||
chan9_set_error(int chan, uint32 mask)
|
||
{
|
||
if (chan_flags[chan] & mask)
|
||
return;
|
||
chan_flags[chan] |= mask;
|
||
}
|
||
|
||
t_stat
|
||
chan_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
fprintf (st, "%s\n\n", chan_description(dptr));
|
||
fprintf (st, "The 7070 supports up to 8 channels. Channel models include\n\n");
|
||
fprintf (st, " 7604 standard multiplexor channel\n");
|
||
fprintf (st, " 7907 advanced capabilities channel\n\n");
|
||
fprintf (st, "Channels are fixed on the 7070.\n\n");
|
||
fprintf (st, "Channel * is for unit record devices.\n");
|
||
fprint_set_help(st, dptr);
|
||
fprint_show_help(st, dptr);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
const char *
|
||
chan_description(DEVICE *dptr)
|
||
{
|
||
return "IBM 7070 channel controller";
|
||
}
|
||
|
||
|