If the record ended as a multiple of 8 characters, an extra gm would be addded and an extra word written.
775 lines
21 KiB
C
775 lines
21 KiB
C
/* B5500_io.c: Burroughs 5500 I/O System.
|
||
|
||
Copyright (c) 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.
|
||
|
||
*/
|
||
|
||
#include "b5500_defs.h"
|
||
|
||
#define EOR 1
|
||
#define USEGM 2
|
||
|
||
t_stat chan_reset(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
|
||
*/
|
||
|
||
t_uint64 D[NUM_CHAN]; /* Current I/O instruction */
|
||
uint8 CC[NUM_CHAN]; /* Channel character count */
|
||
t_uint64 W[NUM_CHAN]; /* Assembly register */
|
||
uint8 status[NUM_CHAN]; /* Channel status */
|
||
uint8 cstatus; /* Active status */
|
||
|
||
#define WC(x) (uint16)(((x) & DEV_WC) >> DEV_WC_V)
|
||
#define toWC(x) (((t_uint64)(x) << DEV_WC_V) & DEV_WC)
|
||
|
||
|
||
UNIT chan_unit[] = {
|
||
/* Normal channels */
|
||
{UDATA(NULL,UNIT_DISABLE,0)},/* A */
|
||
{UDATA(NULL,UNIT_DISABLE,0)},/* B */
|
||
{UDATA(NULL,UNIT_DISABLE,0)},/* C */
|
||
{UDATA(NULL,UNIT_DISABLE,0)},/* D */
|
||
};
|
||
|
||
REG chan_reg[] = {
|
||
{BRDATA(D, D, 8, 48, NUM_CHAN), REG_RO},
|
||
{BRDATA(CC, CC, 7, 6, NUM_CHAN), REG_RO},
|
||
{BRDATA(W, W, 8, 48, NUM_CHAN), REG_RO},
|
||
{NULL}
|
||
};
|
||
|
||
|
||
/* Simulator debug controls */
|
||
DEBTAB chn_debug[] = {
|
||
{"CHANNEL", DEBUG_CHAN},
|
||
{"DETAIL", DEBUG_DETAIL},
|
||
{"DATA", DEBUG_DATA},
|
||
{"CH0", 0x0100 << 0},
|
||
{"CH1", 0x0100 << 1},
|
||
{"CH2", 0x0100 << 2},
|
||
{"CH3", 0x0100 << 3},
|
||
{0, 0}
|
||
};
|
||
|
||
DEVICE chan_dev = {
|
||
"IO", chan_unit, chan_reg, NULL,
|
||
NUM_CHAN, 10, 18, 1, 10, 44,
|
||
NULL, NULL, &chan_reset, NULL, NULL, NULL,
|
||
NULL, DEV_DEBUG, 0, chn_debug
|
||
};
|
||
|
||
|
||
|
||
t_stat
|
||
chan_reset(DEVICE * dptr)
|
||
{
|
||
int i;
|
||
int j = 1;
|
||
|
||
cstatus = 0;
|
||
/* Clear channel assignment */
|
||
for (i = 0; i < NUM_CHAN; i++) {
|
||
status[i] = 0;
|
||
D[i] = 0;
|
||
W[i] = 0;
|
||
CC[i] = 0;
|
||
if (chan_unit[i].flags & UNIT_DIS)
|
||
cstatus |= j;
|
||
j <<= 1;
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Boot from given device */
|
||
t_stat
|
||
chan_boot(t_uint64 desc)
|
||
{
|
||
M[020] = desc;
|
||
M[010] = 020;
|
||
loading = 1;
|
||
start_io();
|
||
return SCPE_OK;
|
||
}
|
||
|
||
int
|
||
find_chan() {
|
||
int i;
|
||
int chan;
|
||
|
||
i = 1;
|
||
for(chan = 0; chan < NUM_CHAN; chan++) {
|
||
if ((cstatus & i) == 0)
|
||
break;
|
||
i <<= 1;
|
||
}
|
||
|
||
if (chan == NUM_CHAN) {
|
||
return 0;
|
||
}
|
||
return chan + 1;
|
||
}
|
||
|
||
void
|
||
chan_release(int chan) {
|
||
cstatus &= ~(1 << chan);
|
||
}
|
||
|
||
int
|
||
chan_advance(int chan) {
|
||
uint16 addr = (uint16)(D[chan] & CORE);
|
||
|
||
if (D[chan] & DEV_WCFLG) {
|
||
uint16 wc = WC(D[chan]);
|
||
if (wc == 0) {
|
||
status[chan] |= EOR;
|
||
return 1;
|
||
}
|
||
D[chan] &= ~DEV_WC;
|
||
D[chan] |= toWC(wc-1);
|
||
}
|
||
if (addr > MEMSIZE) {
|
||
D[chan] |= DEV_MEMERR;
|
||
status[chan] |= EOR;
|
||
return 1;
|
||
}
|
||
W[chan] = M[addr];
|
||
D[chan] &= ~CORE;
|
||
if (D[chan] & DEV_BACK)
|
||
D[chan] |= (t_uint64)((addr - 1) & CORE);
|
||
else
|
||
D[chan] |= (t_uint64)((addr + 1) & CORE);
|
||
CC[chan] = 0;
|
||
return 0;
|
||
}
|
||
|
||
void
|
||
start_io() {
|
||
int i;
|
||
int chan;
|
||
t_stat r;
|
||
uint16 dev;
|
||
uint16 cmd;
|
||
uint16 wc;
|
||
int addr;
|
||
|
||
chan = find_chan();
|
||
|
||
addr = M[010] & CORE;
|
||
|
||
if (chan == 0) {
|
||
IAR |= IRQ_1;
|
||
return;
|
||
}
|
||
chan--;
|
||
i = 1 << chan;
|
||
sim_debug(DEBUG_DETAIL, &chan_dev, "strtio(%016llo %d)\n", M[addr], chan);
|
||
D[chan] = M[addr] & D_MASK;
|
||
CC[chan] = 0;
|
||
W[chan] = 0;
|
||
dev = (uint16)((D[chan] & DEVMASK) >> DEV_V);
|
||
cmd = (uint16)((D[chan] & DEV_CMD) >> DEV_CMD_V);
|
||
wc = WC(D[chan]);
|
||
D[chan] &= ~DEV_RESULT;
|
||
status[chan] = 0;
|
||
if (dev & 1) {
|
||
#if (NUM_DEVS_MT > 0)
|
||
status[chan] = USEGM;
|
||
r = mt_cmd(cmd, dev, chan, &wc);
|
||
#else
|
||
r = SCPE_UNATT;
|
||
#endif
|
||
} else {
|
||
switch(dev) {
|
||
#if (NUM_DEVS_DR > 0)
|
||
case DRUM1_DEV:
|
||
case DRUM2_DEV:
|
||
r = drm_cmd(cmd, dev, chan, &wc, (uint8)((M[addr] & PRESENT)!=0));
|
||
break;
|
||
#endif
|
||
|
||
#if (NUM_DEVS_CDR > 0) | (NUM_DEVS_CDP > 0)
|
||
case CARD1_DEV:
|
||
case CARD2_DEV:
|
||
r = card_cmd(cmd, dev, chan, &wc);
|
||
break;
|
||
#endif
|
||
|
||
#if (NUM_DEVS_DSK > 0)
|
||
case DSK1_DEV:
|
||
case DSK2_DEV:
|
||
/* Need to pass word count to identify interrogates */
|
||
r = dsk_cmd(cmd, dev, chan, &wc);
|
||
break;
|
||
#endif
|
||
|
||
#if (NUM_DEVS_DTC > 0)
|
||
case DTC_DEV:
|
||
status[chan] = USEGM;
|
||
/* Word count is TTU and BUF number */
|
||
r = dtc_cmd(cmd, dev, chan, &wc);
|
||
if (r == SCPE_OK)
|
||
D[chan] &= ~DEV_WC;
|
||
D[chan] &= ~(DEV_BIN|DEV_WCFLG);
|
||
wc = 0;
|
||
break;
|
||
#endif
|
||
|
||
#if (NUM_DEVS_LPR > 0)
|
||
case PRT1_DEV:
|
||
case PRT2_DEV:
|
||
r = lpr_cmd(cmd, dev, chan, &wc);
|
||
if (r == SCPE_OK)
|
||
D[chan] &= ~DEV_BACK; /* Clear this bit, since printer
|
||
uses this to determine 120/132
|
||
char line */
|
||
break;
|
||
#endif
|
||
|
||
#if (NUM_DEVS_CON > 0)
|
||
case SPO_DEV:
|
||
status[chan] = USEGM;
|
||
r = con_cmd(cmd, dev, chan, &wc);
|
||
break;
|
||
#endif
|
||
default:
|
||
r = SCPE_UNATT;
|
||
break;
|
||
}
|
||
}
|
||
if (wc != 0) {
|
||
D[chan] &= ~DEV_WC;
|
||
D[chan] |= toWC(wc) | DEV_WCFLG;
|
||
}
|
||
switch(r) {
|
||
case SCPE_OK:
|
||
cstatus |= i;
|
||
return;
|
||
case SCPE_NXDEV:
|
||
case SCPE_UNATT:
|
||
D[chan] |= DEV_NOTRDY;
|
||
break;
|
||
case SCPE_BUSY:
|
||
D[chan] |= DEV_BUSY;
|
||
break;
|
||
case SCPE_EOF:
|
||
D[chan] |= DEV_EOF;
|
||
break;
|
||
}
|
||
chan_set_end(chan);
|
||
}
|
||
|
||
|
||
void
|
||
chan_set_end(int chan) {
|
||
uint16 dev;
|
||
dev = (uint16)((D[chan] & DEVMASK) >> DEV_V);
|
||
/* Set character count if reading and tape */
|
||
if ((dev & 1) && (D[chan] & DEV_IORD)) {
|
||
D[chan] &= ~((7LL)<<DEV_WC_V);
|
||
/* If not data transfered, return zero code */
|
||
if ((D[chan] & DEV_BACK) != 0 &&
|
||
(status[chan] & EOR) != 0)
|
||
D[chan] |= ((t_uint64)((7-CC[chan]) & 07)) << DEV_WC_V;
|
||
else
|
||
D[chan] |= ((t_uint64)(CC[chan] & 07)) << DEV_WC_V;
|
||
}
|
||
|
||
M[014+chan] = D[chan];
|
||
if (loading == 0)
|
||
IAR |= IRQ_5 << chan;
|
||
else
|
||
loading = 0;
|
||
sim_debug(DEBUG_DETAIL, &chan_dev, "endio (%016llo %o)\n", D[chan], chan);
|
||
}
|
||
|
||
void
|
||
chan_set_eof(int chan) {
|
||
D[chan] |= DEV_EOF;
|
||
}
|
||
|
||
void
|
||
chan_set_parity(int chan) {
|
||
D[chan] |= DEV_PARITY;
|
||
}
|
||
|
||
void
|
||
chan_set_error(int chan) {
|
||
D[chan] |= DEV_ERROR;
|
||
}
|
||
|
||
void
|
||
chan_set_wcflg(int chan) {
|
||
D[chan] |= DEV_WCFLG;
|
||
}
|
||
|
||
void
|
||
chan_set_read(int chan) {
|
||
D[chan] |= DEV_IORD;
|
||
}
|
||
|
||
void
|
||
chan_set_gm(int chan) {
|
||
D[chan] |= DEV_BACK;
|
||
}
|
||
|
||
void
|
||
chan_set_notrdy(int chan) {
|
||
D[chan] |= DEV_NOTRDY;
|
||
chan_set_end(chan);
|
||
}
|
||
|
||
void
|
||
chan_set_eot(int chan) {
|
||
D[chan] &= ~DEV_WC;
|
||
D[chan] |= DEV_EOT;
|
||
}
|
||
|
||
void
|
||
chan_set_bot(int chan) {
|
||
D[chan] &= ~DEV_WC;
|
||
D[chan] |= DEV_BOT;
|
||
}
|
||
|
||
void
|
||
chan_set_blank(int chan) {
|
||
D[chan] &= ~DEV_WC;
|
||
D[chan] |= DEV_BLANK;
|
||
}
|
||
|
||
void
|
||
chan_set_wrp(int chan) {
|
||
D[chan] |= DEV_ERROR|DEV_MEMERR;
|
||
}
|
||
|
||
void
|
||
chan_set_wc(int chan, uint16 wc) {
|
||
D[chan] &= ~DEV_WC;
|
||
D[chan] |= toWC(wc);
|
||
}
|
||
|
||
|
||
/*
|
||
Internal BCD
|
||
00 0000 00 1010 0000 -> 1010
|
||
00 0001 00 0001
|
||
00 0010 00 0010
|
||
00 0011 00 0011
|
||
00 0100 00 0100
|
||
00 0101 00 0101
|
||
00 0110 00 0110
|
||
00 0111 00 0111
|
||
00 1000 00 1000
|
||
00 1001 00 1001
|
||
00 1010 00 1011 1010 -> 1011
|
||
00 1011 00 1100 1011 -> 1100
|
||
00 1100 00 0000 1100 -> 0000
|
||
00 1101 00 1101
|
||
00 1110 00 1110
|
||
00 1111 00 1111
|
||
01 0000 11 1010 0000 -> 1010 10
|
||
01 0001 11 0001 1
|
||
01 0010 11 0010 2
|
||
01 0011 11 0011 3
|
||
01 0100 11 0100
|
||
01 0101 11 0101
|
||
01 0110 11 0110
|
||
01 0111 11 0111
|
||
01 1000 11 1000 8
|
||
01 1001 11 1001 9
|
||
01 1010 11 1011 1010 -> 1011 10
|
||
01 1011 11 1100 1011 -> 1100 11
|
||
01 1100 11 0000 1100 -> 0000 12
|
||
01 1101 11 1101 13
|
||
01 1110 11 1110 14
|
||
01 1111 11 1111 15
|
||
10 0000 10 1010 0000 -> 1010
|
||
10 0001 10 0001
|
||
10 0010 10 0010
|
||
10 0011 10 0011
|
||
10 0100 10 0100
|
||
10 0101 10 0101
|
||
10 0110 10 0110
|
||
10 0111 10 0111
|
||
10 1000 10 1000
|
||
10 1001 10 1001
|
||
10 1010 10 1011 1010 -> 1011
|
||
10 1011 10 1100 1011 -> 1100
|
||
10 1100 10 0000 1100 -> 0000
|
||
10 1101 10 1101
|
||
10 1110 10 1110
|
||
10 1111 10 1111
|
||
11 0000 01 0000
|
||
11 0001 01 0001
|
||
11 0010 01 0010
|
||
11 0011 01 0011
|
||
11 0100 01 0100
|
||
11 0101 01 0101
|
||
11 0110 01 0110
|
||
11 0111 01 0111
|
||
11 1000 01 1000
|
||
11 1001 01 1001
|
||
11 1010 01 1011 1010 -> 1011
|
||
11 1011 01 1100 1011 -> 1100
|
||
11 1100 01 1010 1100 -> 1010
|
||
11 1101 01 1101
|
||
11 1110 01 1110
|
||
11 1111 01 1111 */
|
||
|
||
/* returns 1 when channel can take no more characters.
|
||
A return of 1 indicates that the character was not
|
||
processed.
|
||
*/
|
||
int chan_write_char(int chan, uint8 *ch, int flags) {
|
||
uint8 c;
|
||
|
||
if (status[chan] & EOR)
|
||
return 1;
|
||
|
||
if (D[chan] & DEV_INHTRF) {
|
||
status[chan] |= EOR;
|
||
return 1;
|
||
}
|
||
|
||
/* Check if first word */
|
||
if (CC[chan] == 0) {
|
||
uint16 wc = WC(D[chan]);
|
||
|
||
if (D[chan] & DEV_WCFLG && wc == 0) {
|
||
sim_debug(DEBUG_DATA, &chan_dev, "zerowc(%d)\n", chan);
|
||
status[chan] |= EOR;
|
||
return 1;
|
||
}
|
||
W[chan] = 0;
|
||
}
|
||
|
||
c = *ch & 077;
|
||
if ((D[chan] & DEV_BIN) == 0) {
|
||
/* Translate BCL to BCD */
|
||
uint8 cx = c & 060;
|
||
|
||
c &= 017;
|
||
switch(c) {
|
||
case 0:
|
||
/* 11-0 -> 01 C */
|
||
/* 10-0 -> 10 C */
|
||
/* 01-0 -> 11 0 */
|
||
/* 00-0 -> 00 C */
|
||
if (cx != 020)
|
||
c = 0xc;
|
||
break;
|
||
case 1:
|
||
case 2:
|
||
case 3:
|
||
case 4:
|
||
case 5:
|
||
case 6:
|
||
case 7:
|
||
case 8:
|
||
case 9:
|
||
case 0xd:
|
||
case 0xe:
|
||
case 0xf:
|
||
break;
|
||
case 0xa:
|
||
/* 11-A -> 01 0 */
|
||
/* 10-A -> 10 0 */
|
||
/* 01-A -> 11 C */
|
||
/* 00-A -> 00 0 */
|
||
if (cx == 020)
|
||
c = 0xc;
|
||
else
|
||
c = 0;
|
||
break;
|
||
case 0xb:
|
||
c = 0xa;
|
||
break;
|
||
case 0xc:
|
||
c = 0xb;
|
||
break;
|
||
}
|
||
c |= cx ^ ((cx & 020)<<1);
|
||
}
|
||
|
||
if (D[chan] & DEV_BACK)
|
||
W[chan] |= ((t_uint64)c) << ((CC[chan]) * 6);
|
||
else
|
||
W[chan] |= ((t_uint64)c) << ((7 - CC[chan]) * 6);
|
||
CC[chan]++;
|
||
|
||
if (CC[chan] == 8) {
|
||
uint16 addr = (uint16)(D[chan] & CORE);
|
||
|
||
M[addr] = W[chan];
|
||
sim_debug(DEBUG_DATA, &chan_dev, "write(%d, %05o, %016llo)\n",
|
||
chan, addr, W[chan]);
|
||
|
||
if (chan_advance(chan))
|
||
return 1;
|
||
W[chan] = 0;
|
||
}
|
||
if (flags) {
|
||
if ((D[chan] & (DEV_BIN|DEV_WCFLG)) == 0) {
|
||
/* Insert group mark */
|
||
if (D[chan] & DEV_BACK) {
|
||
int i = CC[chan];
|
||
W[chan] |= (t_uint64)037LL << ((CC[chan]) * 6);
|
||
|
||
while(i < 8) {
|
||
W[chan] |= (t_uint64)014LL << (i * 6);
|
||
i++;
|
||
}
|
||
} else {
|
||
W[chan] |= 037LL << ((7 - CC[chan]) * 6);
|
||
}
|
||
CC[chan]++;
|
||
}
|
||
|
||
/* Flush last word */
|
||
if (CC[chan] != 0) {
|
||
uint16 addr = (uint16)(D[chan] & CORE);
|
||
|
||
M[addr] = W[chan];
|
||
sim_debug(DEBUG_DATA, &chan_dev, "writef(%d, %05o, %016llo)\n",
|
||
chan, addr, W[chan]);
|
||
(void)chan_advance(chan);
|
||
W[chan] = 0;
|
||
}
|
||
status[chan] |= EOR;
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Returns 1 on last character. If it returns 1, the
|
||
character in ch is not valid. If flag is set to 1, then
|
||
this is the last character the device will request.
|
||
*/
|
||
int chan_read_char(int chan, uint8 *ch, int flags) {
|
||
uint8 c;
|
||
int gm;
|
||
|
||
if (status[chan] & EOR)
|
||
return 1;
|
||
|
||
if (D[chan] & DEV_INHTRF) {
|
||
status[chan] |= EOR;
|
||
return 1;
|
||
}
|
||
|
||
if (CC[chan] == 0) {
|
||
uint16 addr = (uint16)(D[chan] & CORE);
|
||
if (chan_advance(chan))
|
||
return 1;
|
||
sim_debug(DEBUG_DATA, &chan_dev, "read(%d, %05o, %016llo)\n", chan,
|
||
addr, W[chan]);
|
||
}
|
||
|
||
if (D[chan] & DEV_BACK)
|
||
c = 077 & (W[chan] >> ((CC[chan]) * 6));
|
||
else
|
||
c = 077 & (W[chan] >> ((7 - CC[chan]) * 6));
|
||
gm = (c == 037);
|
||
CC[chan]++;
|
||
if (CC[chan] == 8) {
|
||
CC[chan] = 0;
|
||
}
|
||
if ((D[chan] & DEV_BIN) == 0) {
|
||
/* Translate BCD to BCL */
|
||
uint8 cx = c & 060;
|
||
c &= 017;
|
||
switch(c) {
|
||
case 0:
|
||
if (cx != 060)
|
||
c = 0xa;
|
||
break;
|
||
case 1:
|
||
case 2:
|
||
case 3:
|
||
case 4:
|
||
case 5:
|
||
case 6:
|
||
case 7:
|
||
case 8:
|
||
case 9:
|
||
case 0xd:
|
||
case 0xe:
|
||
case 0xf:
|
||
break;
|
||
case 0xa:
|
||
c = 0xb;
|
||
break;
|
||
case 0xb:
|
||
c = 0xc;
|
||
break;
|
||
case 0xc:
|
||
if (cx == 060)
|
||
c = 0xa;
|
||
else
|
||
c = 0;
|
||
break;
|
||
}
|
||
c |= cx ^ ((cx & 020)<<1);
|
||
}
|
||
*ch = c;
|
||
if ((status[chan] & USEGM) != 0 && (D[chan] & DEV_WCFLG) == 0 && gm) {
|
||
status[chan] |= EOR;
|
||
return 1;
|
||
}
|
||
if (flags) {
|
||
status[chan] |= EOR;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* Same as chan_read_char, however we do not check word count
|
||
nor do we advance it.
|
||
*/
|
||
int chan_read_disk(int chan, uint8 *ch, int flags) {
|
||
uint8 c;
|
||
|
||
if (CC[chan] == 0) {
|
||
uint16 addr = (uint16)(D[chan] & CORE);
|
||
if (addr > MEMSIZE) {
|
||
D[chan] |= DEV_MEMERR;
|
||
return 1;
|
||
}
|
||
|
||
W[chan] = M[addr];
|
||
D[chan] &= ~CORE;
|
||
D[chan] |= (addr + 1) & CORE;
|
||
}
|
||
|
||
c = 077 & (W[chan] >> ((7 - CC[chan]) * 6));
|
||
CC[chan]++;
|
||
*ch = c;
|
||
if (CC[chan] == 8) {
|
||
CC[chan] = 0;
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
int
|
||
chan_advance_drum(int chan) {
|
||
uint16 addr = (uint16)(D[chan] & CORE);
|
||
uint16 wc = WC(D[chan]);
|
||
if (wc == 0) {
|
||
status[chan] |= EOR;
|
||
return 1;
|
||
}
|
||
D[chan] &= ~DEV_WC;
|
||
D[chan] |= toWC(wc-1);
|
||
if (addr > MEMSIZE) {
|
||
D[chan] |= DEV_MEMERR;
|
||
status[chan] |= EOR;
|
||
return 1;
|
||
}
|
||
|
||
W[chan] = M[addr];
|
||
D[chan] &= ~CORE;
|
||
D[chan] |= (addr + 1) & CORE;
|
||
CC[chan] = 0;
|
||
return 0;
|
||
}
|
||
|
||
/* returns 1 when channel can take no more characters.
|
||
A return of 1 indicates that the character was not
|
||
processed.
|
||
*/
|
||
int chan_write_drum(int chan, uint8 *ch, int flags) {
|
||
uint8 c;
|
||
|
||
if (status[chan] & EOR)
|
||
return 1;
|
||
|
||
/* Check if first word */
|
||
if (CC[chan] == 0) {
|
||
uint16 wc = WC(D[chan]);
|
||
|
||
if (wc == 0) {
|
||
status[chan] |= EOR;
|
||
return 1;
|
||
}
|
||
W[chan] = 0;
|
||
}
|
||
|
||
c = *ch;
|
||
c &= 077;
|
||
|
||
W[chan] |= (t_uint64)c << ((7 - CC[chan]) * 6);
|
||
CC[chan]++;
|
||
|
||
if (CC[chan] == 8) {
|
||
uint16 addr = (uint16)(D[chan] & CORE);
|
||
|
||
M[addr] = W[chan];
|
||
if (chan_advance_drum(chan))
|
||
return 1;
|
||
}
|
||
if (flags) {
|
||
/* Flush last word */
|
||
if (CC[chan] != 0) {
|
||
uint16 addr = (uint16)(D[chan] & CORE);
|
||
|
||
M[addr] = W[chan];
|
||
(void)chan_advance_drum(chan);
|
||
}
|
||
status[chan] |= EOR;
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Returns 1 on last character. If it returns 1, the
|
||
character in ch is not valid. If flag is set to 1, then
|
||
this is the last character the device will request.
|
||
*/
|
||
int chan_read_drum(int chan, uint8 *ch, int flags) {
|
||
uint8 c;
|
||
|
||
if (status[chan] & EOR)
|
||
return 1;
|
||
|
||
|
||
if (CC[chan] == 0) {
|
||
if (chan_advance_drum(chan))
|
||
return 1;
|
||
}
|
||
|
||
c = 077 & (W[chan] >> ((7 - CC[chan]) * 6));
|
||
CC[chan]++;
|
||
if (CC[chan] == 8) {
|
||
CC[chan] = 0;
|
||
}
|
||
*ch = c;
|
||
if (flags) {
|
||
status[chan] |= EOR;
|
||
}
|
||
return 0;
|
||
}
|
||
|