#include <stdio.h>
#include "regs.h"
#include "parity.h"
#include "io.h"
#include "trace.h"
#include "chan.h"
#include "console.h"
#include "lights.h"

#define RECLEN 24

extern char asciibcd[64];
extern char prtview[5][81];
extern char *devstr();

int tm[MAXCHAN];
char s[100];

/*
 * Card machine states:
 *	0:  9 left	1:  9 right
 *	2:  8 left	3:  8 right
 *	4:  7 left	5:  7 right
 *	6:  6 left	7:  6 right
 *	8:  5 left	9:  5 right
 *     10:  4 left     11:  4 right
 *     12:  3 left     13:  3 right
 *     14:  2 left     15:  2 right
 *     16:  1 left     17:  1 right
 *     18:  0 left     19:  0 right
 *     20: 11 left     21: 11 right
 *     22: 12 left     23: 12 right
 *     24: End of cycle
 *     47: Beginning of new cycle
 *
 * Read printer states:
 *	0:  9 left	1:  9 right
 *	2:  8 left	3:  8 right
 *	4:  7 left	5:  7 right
 *	6:  6 left	7:  6 right
 *	8:  5 left	9:  5 right
 *     10:  4 left     11:  4 right
 *     12:  3 left     13:  3 right
 *     14:  2 left     15:  2 right
 *     16:  1 left     17:  1 right
 *     18: 84 left     19: 84 right echo
 *     20:  0 left     21:  0 right
 *     22: 83 left     23: 83 right echo
 *     24: 11 left     25: 11 right
 *     26:  9 left     27:  9 right echo
 *     28: 12 left     29: 12 right
 *     30:  8 left     31:  8 right echo
 *     32:  7 left     33:  7 right echo
 *     34:  6 left     35:  6 right echo
 *     36:  5 left     37:  5 right echo
 *     38:  4 left     39:  4 right echo
 *     40:  3 left     41:  3 right echo
 *     42:  2 left     43:  2 right echo
 *     44:  1 left     45:  1 right echo
 *     46: End of cycle
 *     47: Beginning of new cycle
 */

unsigned short crstate, crcol[80];	/* Card reader card code */
unsigned short cpstate, cpcol[80];	/* Card punch card code */
unsigned short prstate, prcol[120];	/* Printer card code */
unsigned char tapestate = 0;		/* Tape state: 0 idle, 1 read, 2 write */
char cnvbuf[161];			/* Card data conversion buffer */
char prtbuf[73];			/* Printer data conversion buffer */
unsigned short pr_ws_rs[] = {		/* Convert from read state to write */
	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
	16, 17, 18, 18, 18, 19, 20, 20, 20, 21, 22, 22, 22, 23,
	24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 47
};
unsigned char tapebuf[196610];		/* Tape record buffer */
unsigned tapeloc;			/* Current location in tapebuf */

void
do_chan(int ch)
{

	run_chan(ch);
	if (csel[ch]) {
		csel[ch] = 0;
		ctrp[ch] = 1;
	}
}

void
run_chan(int ch)
{

	if (ccyc[ch] > cycle_count) {
		cycle_count = ccyc[ch];
	}
	while (cact[ch]) {
		cycle_chan(ch);
	}
}

void
active_chan(int ch)
{

	cycle_chan(ch);
	while (cact[ch] > 1) {
		cycle_chan(ch);
	}
}

void
man_chan(int ch)
{

	if (cwr[ch] && csel[ch] == WRITE_SEL) {
		cdrl[ch] = getmeml(car[ch]);
		cdrh[ch] = memh[car[ch]];
		car[ch] = (car[ch] + 1) & MEMLIMIT;
	}
	cact[ch] = 1;
	chan_in_op |= 1 << ch;
}

void
load_chan(int ch, int autoload)
{

	cycle_count++;
	load_chan_cycle(ch, autoload);
	while (cact[ch] > 1) {
		cycle_chan(ch);
	} 
	if (csel[ch] && ccyc[ch] < next_steal) {
		next_steal = ccyc[ch];
	}
}

void
load_chan_cycle(int ch, int autoload)
{
	char chsrh; unsigned long chsrl;

	if (autoload == 1) {
		chsrh = (char)SIGN + 002;
		chsrl = 000003000000;
		clr[ch] = 0;
	} else if (autoload == 2) {
		chsrh = kyh;
		chsrl = kyl;
	} else {
		chsrh = memh[clr[ch]];
		chsrl = getmeml(clr[ch]);
		clr[ch] = (clr[ch] + 1) & MEMLIMIT;

		itrc_h[itrc_idx] = chsrh;
		itrc_l[itrc_idx] = chsrl;
		itrc_buf[itrc_idx++] = clr[ch] + ((long)(ch+1) << 16);
		if (itrc_idx == 32)
			itrc_idx = 0;
	}
	cop[ch] = ((chsrh & SIGN) >> 5) | ((chsrh & 06) >> 1) |
		  ((chsrl & 000000200000) >> 13);
	cwr[ch] = ((chsrh & 1) << 14) | ((chsrl & 037777000000) >> 18);
	car[ch] = chsrl & 000000077777 & MEMLIMIT;
	if (chsrl & 000000400000) {
		car[ch] = getmeml(car[ch]) & 000000077777 & MEMLIMIT;
		cycle_count++;
	}
	if (autoload == 2)
		return;
	if (cop[ch] == 01) {	/* TCH */
		clr[ch] = car[ch];
		cact[ch] = 2;
	} else if (cwr[ch] && csel[ch] == WRITE_SEL) {
		cact[ch] = 3;
	} else {
		cact[ch] = 1;
	}
	chan_in_op |= 1 << ch;
}

void
cycle_chan(int ch)
{

	cycle_count++;
	if (cycle_count >= next_lights) {
		lights();
		next_lights = cycle_count + NEXTLIGHTS;
		next_steal = next_lights;
		check_intr();
	}
	switch (cact[ch]) {

	case 1:
		switch (csel[ch]) {

		case READ_SEL:
		case WRITE_SEL:
			rw_chan(ch);
			break;

		case BSR_SEL:
			bsr(ch);
			csel[ch] = 0;
			cact[ch] = 0;
			chan_in_op &= ~(1 << ch);
			break;

		case BSF_SEL:
			bsf(ch);
			csel[ch] = 0;
			cact[ch] = 0;
			chan_in_op &= ~(1 << ch);
			break;

		case WEF_SEL:
			wef(ch);
			csel[ch] = 0;
			cact[ch] = 0;
			chan_in_op &= ~(1 << ch);
			break;

		}
		break;

	case 2:
		load_chan_cycle(ch, 0);
		break;

	case 3:
		cdrl[ch] = getmeml(car[ch]);
		cdrh[ch] = memh[car[ch]];
		car[ch] = (car[ch] + 1) & MEMLIMIT;
		cact[ch] = 1;
		break;
	}
}

void
rw_chan(int ch)
{

	ccyc[ch] = cycle_count + 33;

	switch(cop[ch] & 07) {

	case 00:	/* IOCD */
		if (cwr[ch]) {
			if (csel[ch] == READ_SEL) {
				readword(ch);
				if (tm[ch])
					goto done1;
				if ((cop[ch] & 010) == 0) {
					setmeml(car[ch], cdrl[ch]);
					memh[car[ch]] = cdrh[ch];
					car[ch] = (car[ch] + 1) & MEMLIMIT;
				}
			} else {
				writeword(ch);
				cdrl[ch] = getmeml(car[ch]);
				cdrh[ch] = memh[car[ch]];
				if (cwr[ch] > 1)
					car[ch] = (car[ch] + 1) & MEMLIMIT;
			}
			cwr[ch]--;
			if (cwr[ch] > 0)
				return;
		}
done1:
		csel[ch] = 0;
		endrecord(ch);
		cact[ch] = 0;
		chan_in_op &= ~(1 << ch);
		return;

	case 02:	/* IORP */
		if (cwr[ch]) {
			if (ceor[ch])
				goto done2;
			if (csel[ch] == READ_SEL) {
				readword(ch);
				if (tm[ch])
					goto done2;
				if ((cop[ch] & 010) == 0) {
					setmeml(car[ch], cdrl[ch]);
					memh[car[ch]] = cdrh[ch];
					car[ch] = (car[ch] + 1) & MEMLIMIT;
				}
			} else {
				writeword(ch);
				cdrl[ch] = getmeml(car[ch]);
				cdrh[ch] = memh[car[ch]];
				if (cwr[ch] > 1)
					car[ch] = (car[ch] + 1) & MEMLIMIT;
			}
			cwr[ch]--;
			if (cwr[ch])
				return;
		}
done2:
		endrecord(ch);
		if (tm[ch]) {
			csel[ch] = 0;
			cact[ch] = 0;
			chan_in_op &= ~(1 << ch);
			return;
		}
		break;

	case 03:	/* IORT */
		if (cwr[ch]) {
			if (ceor[ch])
				goto done3;
			if (csel[ch] == READ_SEL) {
				readword(ch);
				if (tm[ch])
					goto done3;
				if ((cop[ch] & 010) == 0) {
					setmeml(car[ch], cdrl[ch]);
					memh[car[ch]] = cdrh[ch];
					car[ch] = (car[ch] + 1) & MEMLIMIT;
				}
			} else {
				writeword(ch);
				cdrl[ch] = getmeml(car[ch]);
				cdrh[ch] = memh[car[ch]];
				if (cwr[ch] > 1)
					car[ch] = (car[ch] + 1) & MEMLIMIT;
			}
			cwr[ch]--;
			if (cwr[ch])
				return;
		}
done3:
		endrecord(ch);
		cact[ch] = 0;
		chan_in_op &= ~(1 << ch);
		if (tm[ch]) {
			csel[ch] = 0;
		} else {
			ccyc[ch] = cycle_count + 600;
		}
		return;

	case 04:	/* IOCP */
		if (cwr[ch]) {
			if (csel[ch] == READ_SEL) {
				readword(ch);
				if (tm[ch])
					goto done4;
				if ((cop[ch] & 010) == 0) {
					setmeml(car[ch], cdrl[ch]);
					memh[car[ch]] = cdrh[ch];
					car[ch] = (car[ch] + 1) & MEMLIMIT;
				}
			} else {
				writeword(ch);
				cdrl[ch] = getmeml(car[ch]);
				cdrh[ch] = memh[car[ch]];
				if (cwr[ch] > 1)
					car[ch] = (car[ch] + 1) & MEMLIMIT;
			}
			cwr[ch]--;
			if (cwr[ch])
				return;
		}
done4:
		if (tm[ch]) {
			csel[ch] = 0;
			cact[ch] = 0;
			chan_in_op &= ~(1 << ch);
			return;
		}
		break;

	case 05:	/* IOCT */
		if (cwr[ch]) {
			if (csel[ch] == READ_SEL) {
				readword(ch);
				if (tm[ch])
					goto done5;
				if ((cop[ch] & 010) == 0) {
					setmeml(car[ch], cdrl[ch]);
					memh[car[ch]] = cdrh[ch];
					car[ch] = (car[ch] + 1) & MEMLIMIT;
				}
			} else {
				writeword(ch);
				cdrl[ch] = getmeml(car[ch]);
				cdrh[ch] = memh[car[ch]];
				if (cwr[ch] > 1)
					car[ch] = (car[ch] + 1) & MEMLIMIT;
			}
			cwr[ch]--;
			if (cwr[ch])
				return;
		}
done5:
		cact[ch] = 0;
		chan_in_op &= ~(1 << ch);
		if (tm[ch]) {
			csel[ch] = 0;
		} else {
			ccyc[ch] = cycle_count + 600;
		}
		return;

	case 06:	/* IOSP */
		if (cwr[ch]) {
			if (csel[ch] == READ_SEL) {
				readword(ch);
				if (tm[ch])
					goto done6;
				if ((cop[ch] & 010) == 0) {
					setmeml(car[ch], cdrl[ch]);
					memh[car[ch]] = cdrh[ch];
					car[ch] = (car[ch] + 1) & MEMLIMIT;
				}
			} else {
				writeword(ch);
				cdrl[ch] = getmeml(car[ch]);
				cdrh[ch] = memh[car[ch]];
				if (cwr[ch] > 1)
					car[ch] = (car[ch] + 1) & MEMLIMIT;
			}
			cwr[ch]--;
			if (cwr[ch] && !ceor[ch])
				return;
		}
done6:
		if (tm[ch]) {
			csel[ch] = 0;
			cact[ch] = 0;
			chan_in_op &= ~(1 << ch);
			return;
		}
		break;

	case 07:	/* IOST */
		if (cwr[ch]) {
			if (csel[ch] == READ_SEL) {
				readword(ch);
				if (tm[ch])
					goto done7;
				if ((cop[ch] & 010) == 0) {
					setmeml(car[ch], cdrl[ch]);
					memh[car[ch]] = cdrh[ch];
					car[ch] = (car[ch] + 1) & MEMLIMIT;
				}
			} else {
				writeword(ch);
				cdrl[ch] = getmeml(car[ch]);
				cdrh[ch] = memh[car[ch]];
				if (cwr[ch] > 1)
					car[ch] = (car[ch] + 1) & MEMLIMIT;
			}
			cwr[ch]--;
			if (cwr[ch] && !ceor[ch])
				return;
		}
done7:
		cact[ch] = 0;
		chan_in_op &= ~(1 << ch);
		if (tm[ch]) {
			csel[ch] = 0;
		} else {
			ccyc[ch] = cycle_count + 600;
		}
		return;


	default:	/* invalid ops, TCH handled in load_chan */
		machchk = 1;
		run = 0;
		cact[ch] = 0;
		chan_in_op &= ~(1 << ch);
		return;
	}

	cact[ch] = 2;
	ccyc[ch] = cycle_count + 1;
}

int
unitcheck(int ch, int wr)
{
	unsigned short un;

	tm[ch] = 0;
	un = cun[ch];
	if (ch == 0) {
		if (un == 0321 && wr == 1) {	/* Chan A Card reader */
			readcard();
			ccyc[ch] = cycle_count + 4600;
			return 0;
		}
		if (un == 0341 && wr == 0) {	/* Chan A Card punch */
			initpunch();
			ccyc[ch] = cycle_count + 8000;
			return 1;
		}
		if (un == 0361) {		/* Chan A BCD printer */
			initprint();
			ccyc[ch] = cycle_count + 5000;
			return 2;
		}
		if (un == 0362) {		/* Chan A Binary printer */
			initprint();
			ccyc[ch] = cycle_count + 5000;
			return 2;
		}
	}

	if (cbot[ch])
		ccyc[ch] = cycle_count + 4000;
	else
		ccyc[ch] = cycle_count + 600;
	if (un >= 0201 && un <= 0212)		/* BCD tape */
		return un - 0201 + 3 + 10*ch;
	if (un >= 0221 && un <= 0232)		/* Binary tape */
		return un - 0221 + 3 + 10*ch;

	iochk = 1;
	run = 0;
	return -1;
}

int
whatdev(int ch)
{
	unsigned short un;

	un = cun[ch];
	if (ch == 0) {
		if (un == 0321) {	/* Chan A Card reader */
			return 0;
		}
		if (un == 0341) {	/* Chan A Card punch */
			return 1;
		}
		if (un == 0361) {	/* Chan A BCD printer */
			return 2;
		}
		if (un == 0362) {	/* Chan A Binary printer */
			return 2;
		}
	}

	if (un >= 0201 && un <= 0212)	/* BCD tape */
		return un - 0201 + 3 + 10*ch;
	if (un >= 0221 && un <= 0232)	/* Binary tape */
		return un - 0221 + 3 + 10*ch;

	iochk = 1;
	run = 0;
	return -1;
}

void
readcard()
{
	register i;

	crstate = 0;
	for (i = 0; i < 80; i++)
		crcol[i] = 0;
	readrec(0, cnvbuf, sizeof cnvbuf - 1);
	if (iochk)
		return;
	bincard(cnvbuf, crcol);
}

void
initpunch()
{
	register i;

	cpstate = 0;
	for (i = 0; i < 80; i++)
		cpcol[i] = 0;
}

void
writepunch()
{

	cardbin(cpcol, cnvbuf);
	writerec(1, cnvbuf, sizeof cnvbuf - 1);
	initpunch();
	return;
}

void
initprint()
{
	register i;

	prstate = 0;
	for (i = 0; i < 120; i++)
		prcol[i] = 0;
}

void
writeprint()
{
	register i, j;

	cardbcd(prcol, prtbuf, 72);
	writerec(2, prtbuf, sizeof prtbuf - 1);
	for (i = 0; i < 4; i++)
		for (j = 0; j < 80; j++)
			prtview[i][j] = prtview[i + 1][j];
	for (j = 0; j < 72; j++)
		prtview[4][j] = asciibcd[prtbuf[j] & 077];
	prtview[4][72] = 0;
	logstr(prtview[4]);
	lights();
	pview();
	initprint();
	return;
}

void
printerror(char *s)
{
	register i, j;

	for (i = 0; i < 4; i++)
		for (j = 0; j < 80; j++)
			prtview[i][j] = prtview[i + 1][j];
	for (j = 0; s[j] && j < 72; j++)
		prtview[4][j] = s[j];
	for (; j < 80; j++)
		prtview[4][j] = ' ';
	prtview[4][72] = 0;
	logstr(prtview[4]);
	lights();
	pview();
}

void
readword(int ch)
{
	unsigned short un;
	register i, j;
	unsigned short col;
	unsigned short dev;
	unsigned char dchr;
	unsigned long m;

	un = cun[ch];
	cdrl[ch] = 0;
	cdrh[ch] = 0;
	ceor[ch] = 0;
	tm[ch] = 0;

	if (un == 0321) {	/* Card reader */
		if (crstate >= 24) {
			readcard();
			if (iochk)
				return;
		}
		j = (crstate & 1)? 36 : 0;
		col = 1 << (crstate >> 1);
		if (crcol[j++] & col)
			cdrh[ch] |= SIGN;
		for (i = 04; i; i >>= 1)
			if (crcol[j++] & col)
				cdrh[ch] |= i;
		for (i = 0; i < 32; i++) {
			cdrl[ch] <<= 1;
			if (crcol[j++] & col)
				cdrl[ch] |= 1;
		}
		crstate++;
		if (crstate == 24)
			ceor[ch] = 1;
		return;
	}
	if (un == 0361) {	/* BCD printer */
		if (prstate >= 46)
			initprint();
		j = (prstate & 1)? 36 : 0;
		switch (prstate) {

		case  0:	/*  9 left  */
		case  1:	/*  9 right */
		case  2:	/*  8 left  */
		case  3:	/*  8 right */
		case  4:	/*  7 left  */
		case  5:	/*  7 right */
		case  6:	/*  6 left  */
		case  7:	/*  6 right */
		case  8:	/*  5 left  */
		case  9:	/*  5 right */
		case 10:	/*  4 left  */
		case 11:	/*  4 right */
		case 12:	/*  3 left  */
		case 13:	/*  3 right */
		case 14:	/*  2 left  */
		case 15:	/*  2 right */
		case 16:	/*  1 left  */
		case 17:	/*  1 right */
			col = 1 << (prstate >> 1);
			goto write_row;

		case 20:	/*  0 left  */
		case 21:	/*  0 right */
			col = 01000;
			goto write_row;

		case 24:	/* 11 left  */
		case 25:	/* 11 right */
			col = 02000;
			goto write_row;

		case 28:	/* 12 left  */
		case 29:	/* 12 right */
			col = 04000;
write_row:
			cdrl[ch] = getmeml(car[ch]);
			cdrh[ch] = memh[car[ch]];
			if (cdrh[ch] & SIGN)
				prcol[j] |= col;
			j++;
			for (i = 04; i; i >>= 1) {
				if (cdrh[ch] & i)
					prcol[j] |= col;
				j++;
			}
			for (m = 020000000000; m; m >>= 1) {
				if (cdrl[ch] & m)
					prcol[j] |= col;
				j++;
			}
			break;

		case 18:	/* 84 left  echo */
		case 19:	/* 84 right echo */
			col = 00042;
			goto read_8row;

		case 22:	/* 83 left  echo */
		case 23:	/* 83 right echo */
			col = 00102;
			goto read_8row;


		case 26:	/*  9 left  echo */
		case 27:	/*  9 right echo */
			col = 00001;
			goto read_row;

		case 30:	/*  8 left  echo */
		case 31:	/*  8 right echo */
			col = 00002;
read_8row:
			if ((prcol[j++] & 00142) == col)
				cdrh[ch] |= SIGN;
			for (i = 04; i; i >>= 1)
				if ((prcol[j++] & 00142) == col)
					cdrh[ch] |= i;
			for (i = 0; i < 32; i++) {
				cdrl[ch] <<= 1;
				if ((prcol[j++] & 00142) == col)
					cdrl[ch] |= 1;
			}
			break;

		case 32:	/*  7 left  echo */
		case 33:	/*  7 right echo */
		case 34:	/*  6 left  echo */
		case 35:	/*  6 right echo */
		case 36:	/*  5 left  echo */
		case 37:	/*  5 right echo */
		case 38:	/*  4 left  echo */
		case 39:	/*  4 right echo */
		case 40:	/*  3 left  echo */
		case 41:	/*  3 right echo */
		case 42:	/*  2 left  echo */
		case 43:	/*  2 right echo */
		case 44:	/*  1 left  echo */
		case 45:	/*  1 right echo */
			col = 1 << ((prstate - 28) >> 1);

read_row:
			if (prcol[j++] & col)
				cdrh[ch] |= SIGN;
			for (i = 04; i; i >>= 1)
				if (prcol[j++] & col)
					cdrh[ch] |= i;
			for (i = 0; i < 32; i++) {
				cdrl[ch] <<= 1;
				if (prcol[j++] & col)
					cdrl[ch] |= 1;
			}
		}
		prstate++;
		if (prstate == 46) {
			ceor[ch] = 1;
			writeprint();
		}
		return;
	}

	/* Tape */

	dev = (un & 017) + 2 + 10*ch;
	if (tapestate == 0) {
		readrec(dev, tapebuf, sizeof tapebuf);

#ifdef IODEBUG
sprintf(s, "read  %s        %03o %03o %03o %03o %03o %03o %10ld", devstr(dev),
tapebuf[0], tapebuf[1], tapebuf[2], tapebuf[3], tapebuf[4], tapebuf[5], iopos[dev]);
printerror(s);
#endif

		tapeloc = 0;
		tapestate = 1;
		if (tapebuf[0] == 0217) {
			if (tapebuf[1] == 0) {
				ceof[ch] = 1;
				ceor[ch] = 1;
				tm[ch] = 1;
				tapestate = 0;
				return;
			}
			if (tapebuf[1] == 017) {
				tapebuf[0] = 0100;
				tapebuf[1] = 0100;
			}
		}
	}
	for (i = 0; i < 6; i++) {
		cdrh[ch] = 0;
		if (cdrl[ch] &	     004000000000)
			cdrh[ch] |= SIGN;
		cdrh[ch] |= (cdrl[ch] & 003400000000) >> 26;
		cdrl[ch] =  (cdrl[ch] & 000377777777) << 6;
		j = tapebuf[tapeloc++] & 0177;
		if (un & 020) {
			dchr = j & 077;
			j ^= oddpar[dchr];
		} else {
			dchr = binbcd[j & 077];
			j ^= evenpar[j & 077];
		}
		cdrl[ch] |= dchr & 077;
		if (j) {
			cchk[ch] = 1;
		}
	}
	if (tapebuf[tapeloc] == 0) {
		ceor[ch] = 1;
		tapestate = 0;
	}
}

void
writeword(int ch)
{
	unsigned short un;
	register i, j;
	unsigned short col;
	unsigned char dchr;

	un = cun[ch];
	ceor[ch] = 0;
	tm[ch] = 0;

	if (un == 0341) {	/* Card punch */
		if (cpstate >= 24)
			initpunch();
		j = (cpstate & 1)? 36 : 0;
		col = 1 << (cpstate >> 1);
		if (cdrh[ch] & SIGN)
			cpcol[j] |= col;
		j++;
		for (i = 04; i; i >>= 1) {
			if (cdrh[ch] & i)
				cpcol[j] |= col;
			j++;
		}
		for (i = 0; i < 32; i++) {
			if (cdrl[ch] & 020000000000)
				cpcol[j] |= col;
			j++;
			cdrl[ch] <<= 1;
		}
		cpstate++;
		if (cpstate == 24) {
			ceor[ch] = 1;
			writepunch();
		}
		return;
	}
	if (un == 0361) {	/* BCD printer */
		if (prstate >= 24)
			initprint();
		j = (prstate & 1)? 36 : 0;
		col = 1 << (prstate >> 1);
		if (cdrh[ch] & SIGN)
			prcol[j] |= col;
		j++;
		for (i = 04; i; i >>= 1) {
			if (cdrh[ch] & i)
				prcol[j] |= col;
			j++;
		}
		for (i = 0; i < 32; i++) {
			if (cdrl[ch] & 020000000000)
				prcol[j] |= col;
			j++;
			cdrl[ch] <<= 1;
		}
		prstate++;
		if (prstate == 24) {
			ceor[ch] = 1;
			writeprint();
		}
		return;
	}

	/* Tape */

	if (tapestate == 0) {
		tapeloc = 0;
		tapestate = 2;
	}
	dchr = ((cdrh[ch] & SIGN) >> 2) |
	       ((cdrh[ch] & HMSK) << 2) |
	       ((cdrl[ch] >> 30) & 03);
	if (un & 020)
		tapebuf[tapeloc++] = oddpar[dchr & 077];
	else
		tapebuf[tapeloc++] = bcdbin[dchr & 077];
	for (i = 1; i < 6; i++) {
		dchr = ((cdrl[ch] >> 24) & 077);
		if (un & 020)
			tapebuf[tapeloc++] = oddpar[dchr & 077];
		else
			tapebuf[tapeloc++] = bcdbin[dchr & 077];
		cdrl[ch] <<= 6;
	}
}

void
startrec(int ch)
{

	if (cun[ch] == 0321) {		/* Card reader */
		if (crstate >= 24)
			readcard();

	} else if (cun[ch] == 0341) {	/* Card punch */
		if (cpstate == 0)
			cpstate = 25;

	} else if (cun[ch] == 0361) {	/* BCD printer */
		if (prstate == 0)
			prstate = 47;
	}
}

void
endrecord(int ch)
{
	int dev;

	cdrh[ch] = 0;
	cdrl[ch] = 0;
	if (cun[ch] == 0321) {		/* Card reader */
		while (crstate < 24)
			readword(ch);

	} else if (cun[ch] == 0341) {	/* Card punch */
		if (cpstate != 0) {
			if (cpstate == 25)
				cpstate = 0;
			do {
				writeword(ch);
			} while (cpstate != 0);
		}

	} else if (cun[ch] == 0361) {	/* BCD printer */
		if (csel[ch] == READ_SEL) {
			prstate = pr_ws_rs[prstate];
		}
		if (prstate != 0) {
			if (prstate == 47)
				prstate = 0;
			do {
				writeword(ch);
			} while (prstate != 0);
		}

	} else {			/* Tape */

		if (tapestate == 2) {
			dev = (cun[ch] & 017) + 2 + 10*ch;

#ifdef IODEBUG
sprintf(s, "write %s rs %3d %03o %03o %03o %03o %03o %03o %10ld", devstr(dev), tapeloc,
tapebuf[0], tapebuf[1], tapebuf[2], tapebuf[3], tapebuf[4], tapebuf[5], iopos[dev]);
printerror(s);
#endif

			writerec(dev, tapebuf, tapeloc);
			tapeloc = 0;
		}
		tapestate = 0;
	}
	ceor[ch] = 0;
}
