
#include <stdio.h>
#include "regs.h"
#include "s709.h"
#include "arith.h"
#include "io.h"
#include "chan.h"
#include "negop.h"

void
negop()
{
	register chan;
	register dev;

	switch(op) {

	case 0100020:	/* TRA */
		if (trap) {
			traptrace();
			ic = 00001;
		} else {
			ic = y;
		}
		break;

	case 0100021:	/* ESNT */
		if (cpumode != 7094) goto ILLINST;
		break;

	case 0100022:	/* TRCB */
		chan = 1;
		goto trcx;
	case 0100024:	/* TRCD */
		chan = 3;
		goto trcx;
	case 0100026:	/* TRCF */
		chan = 5;
		goto trcx;
	case 0100027:	/* TRCH */
		chan = 7;
	trcx:
		if (ctrap_enb & (01000000 << chan))
			break;
		if (trap)
			traptrace();
		if (cchk[chan]) {
			cchk[chan] = 0;
			if (trap)
				ic = 00001;
			else
				ic = y;
		}
		break;

	case 0100030:	/* TEFB */
	case 0100031:	/* TEFD */
	case 0100032:	/* TEFF */
	case 0100033:	/* TEFH */
		chan = ((op & 03) << 1) + 1;
		if (ctrap_enb & (1 << chan))
			break;
		if (trap)
			traptrace();
		if (ceof[chan]) {
			ceof[chan] = 0;
			if (trap)
				ic = 00001;
			else
				ic = y;
		}
		break;

	case 0100042:	/* RIA */
		sih &= ~ach;
		sil &= ~acl;
		break;

	case 0100046:	/* PIA */
		ach = sih;
		acl = sil;
		break;

	case 0100051:	/* IIL */
		sih ^= (srl & 0740000) >> 14;
		sil ^= (srl & 0037777) << 18;
		break;

	case 0100054:	/* LFT */
		adderh = (srl & 0740000) >> 14;
		adderl = (srl & 0037777) << 18;
		if ( (adderh & ~sih) == adderh &&
		     (adderl & ~sil) == adderl )
			ic++;
		DCYCLE();
		DCYCLE();
		break;

	case 0100055:	/* SIL */
		sih |= (srl & 0740000) >> 14;
		sil |= (srl & 0037777) << 18;
		break;

	case 0100056:	/* LNT */
		adderh = (srl & 0740000) >> 14;
		adderl = (srl & 0037777) << 18;
		if ( (adderh & sih) == adderh &&
		     (adderl & sil) == adderl )
			ic++;
		DCYCLE();
		DCYCLE();
		break;

	case 0100057:	/* RIL */
		sih &= ~((srl & 0740000) >> 14);
		sil &= ~((srl & 0037777) << 18);
		break;

	case 0100060:	/* TCNA */
	case 0100061:	/* TCNB */
	case 0100062:	/* TCNC */
	case 0100063:	/* TCND */
	case 0100064:	/* TCNE */
	case 0100065:	/* TCNF */
	case 0100066:	/* TCNG */
	case 0100067:	/* TCNH */
		if (trap)
			traptrace();
		chan = op & 07;
		if (!csel[chan]) {
			if (trap)
				ic = 00001;
			else
				ic = y;
		}
		break;

	case 0100100:	/* TNZ */
		if (trap)
			traptrace();
		if ((ach & (Q|P|HMSK)) != 0 || acl != 0) {
			if (trap)
				ic = 00001;
			else
				ic = y;
		}
		break;

	case 0100114:	/* CAQ */
	case 0100115:
	case 0100116:
	case 0100117:
		caq();
		break;

	case 0100120:	/* TMI */
		if (trap)
			traptrace();
		if ((ach & SIGN) != 0) {
			if (trap)
				ic = 00001;
			else
				ic = y;
		}
		break;

	case 0100130:	/* XCL */
		srh = ((ach << 4) & SIGN) | (ach & HMSK);
		srl = acl;
		ach = ((mqh & SIGN) >> 4) | (mqh & HMSK);
		acl = mql;
		mqh = srh;
		mql = srl;
		break;

	case 0100140:	/* TNO */
		if (trap)
			traptrace();
		if (acoflo == 0) {
			if (trap)
				ic = 00001;
			else
				ic = y;
		} else {
			acoflo = 0;
		}
		break;

	case 0100154:	/* CRQ */
	case 0100155:
	case 0100156:
	case 0100157:
		crq();
		break;

	case 0100200:	/* MPR */
		ACCESS(y);
		shcnt = 043;
		mpy();
		rnd();
		break;

	case 0100240:	/* DFDH */
		if (cpumode != 7094) goto ILLINST;
		ACCESS(y);
		dfdiv();
		if (divchk)
			run = 0;
		break;

	case 0100241:	/* DFDP */
		if (cpumode != 7094) goto ILLINST;
		ACCESS(y);
		dfdiv();
		break;

	case 0100260:	/* UFM */
		ACCESS(y);
		fmpy(0);
		break;

	case 0100261:	/* DUFM */
		if (cpumode != 7094) goto ILLINST;
		ACCESS(y);
		dfmpy(0);
		break;

	case 0100300:	/* UFA */
		ACCESS(y);
		fadd(0);
		break;

	case 0100301:	/* DUFA */
		if (cpumode != 7094) goto ILLINST;
		ACCESS(y);
		dfadd(0);
		break;

	case 0100302:	/* UFS */
		ACCESS(y);
		srh ^= SIGN;
		fadd(0);
		break;

	case 0100303:	/* DUFS */
		if (cpumode != 7094) goto ILLINST;
		ACCESS(y);
		srh ^= SIGN;
		dfadd(0);
		break;

	case 0100304:	/* UAM */
		ACCESS(y);
		srh &= ~SIGN;
		fadd(0);
		break;

	case 0100305:	/* DUAM */
		if (cpumode != 7094) goto ILLINST;
		ACCESS(y);
		srh &= ~SIGN;
		dfadd(0);
		break;

	case 0100306:	/* USM */
		ACCESS(y);
		srh |= SIGN;
		fadd(0);
		break;

	case 0100307:	/* DUSM */
		if (cpumode != 7094) goto ILLINST;
		ACCESS(y);
		srh |= SIGN;
		dfadd(0);
		break;

	case 0100320:	/* ANA */
		ACCESS(y);
		if (srh & SIGN)
			srh -= SIGN - P;
		ach = ach & srh;
		acl = acl & srl;
		if (srh & P)
			srh += SIGN - P;
		CYCLE();
		break;

	case 0100340:	/* LAS */
		ACCESS(y);
		if (srh & SIGN)
			srh -= SIGN - P;
		if ( (ach & (Q|P|HMSK)) > (srh & 017) )
			goto skip0;
		if ( (ach & (Q|P|HMSK)) < (srh & 017) )
			goto skip2;
		if ( acl > srl )
			goto skip0;
		if ( acl < srl )
			goto skip2;
		goto skip1;
skip2:		ic++;
skip1:		ic++;
skip0:		if (srh & P)
			srh += SIGN - P;
		break;

	case 0100400:	/* SBM */
		ACCESS(y);
		srh |= SIGN;
		add();
		CYCLE();
		break;

	case 0100500:	/* CAL */
		ACCESS(y);
		ach = ((srh & SIGN) >> 4) | (srh & HMSK);
		acl = srl;
		break;

	case 0100501:	/* ORA */
		ACCESS(y);
		if (srh & SIGN)
			srh -= SIGN - P;
		ach = ach | srh;
		acl = acl | srl;
		if (srh & P)
			srh += SIGN - P;
		CYCLE();
		break;

	case 0100520:	/* NZT */
		ACCESS(y);
		if ((srh & HMSK) != 0 || srl != 0)
			ic++;
		break;

	case 0100534:	/* LXD */
		ACCESS(addr);
		setxr(((srh & 1) << 14) |
			  ((srl & 037777000000) >> 18));
		break;

	case 0100535:	/* LDC */
		ACCESS(addr);
		setxr(0100000 - (((srh & 1) << 14) |
		                 ((srl & 037777000000) >> 18)));
		break;

	case 0100540:	/* RCHB */
	case 0100541:	/* RCHD */
	case 0100542:	/* RCHF */
	case 0100543:	/* RCHH */
		chan = ((op & 03) << 1) + 1;
		CYCLE();
		ctrp[chan] = 0;
		ceof[chan] = 0;
		cchk[chan] = 0;
		if (csel[chan] == READ_SEL || csel[chan] == WRITE_SEL) {
			clr[chan] = y;
			ceor[chan] = 0;
			load_chan(chan, 0);
		} else {
			iochk = 1;
		}
		break;

	case 0100544:	/* LCHB */
	case 0100545:	/* LCHD */
	case 0100546:	/* LCHF */
	case 0100547:	/* LCHH */
		chan = ((op & 03) << 1) + 1;
		CYCLE();
		if ((csel[chan] == READ_SEL || csel[chan] == WRITE_SEL) &&
		    cact[chan]) {
			run_chan(chan);
			if (csel[chan] == READ_SEL || csel[chan] == WRITE_SEL) {
				clr[chan] = y;
				load_chan(chan, 0);
			} else {
				iochk = 1;
			}
		} else {
			iochk = 1;
		}
		break;

	case 0100600:	/* STQ */
		memh[y] = mqh;
		setmeml(y, mql);
		CYCLE();
		break;

	case 0100602:	/* ORS */
		ACCESS(y);
		if (srh & SIGN)
			srh -= SIGN - P;
		srh = (ach & (P|HMSK)) | srh;
		srl = acl | srl;
		if (srh & P)
			srh += SIGN - P;
		memh[y] = srh;
		setmeml(y, srl);
		CYCLE();
		break;

	case 0100603:	/* DST */
		if (cpumode != 7094) goto ILLINST;
		memh[y] = ach & (SIGN|HMSK);
		setmeml(y, acl);
		memh[y+1] = mqh;
		setmeml(y+1, mql);
		CYCLE();
		break;

	case 0100620:	/* SLQ */
		memh[y] = mqh;
		setmeml(y, (getmeml(y) & 000000777777) |
			   (mql &     037777000000));
		CYCLE();
		break;

	case 0100625:	/* STL */
		setmeml(y, (getmeml(y) & 037777700000) | ic);
		CYCLE();
		break;

	case 0100634:	/* SXD */
		memh[addr] = (memh[addr] & 0376) | (getxr() >> 14);
		setmeml(addr, (getmeml(addr) &		000000777777) |
		      (((unsigned long)getxr() << 18) & 037777000000));
		CYCLE();
		break;

	case 0100636:	/* SCD */
		{ unsigned short x = 0100000 - getxr();
		if (tag == 0) x = 0;
		memh[addr] = (memh[addr] & 0376) | (x >> 14);
		setmeml(addr, (getmeml(addr) &		000000777777) |
		      (((unsigned long)x << 18) & 037777000000));
		CYCLE();
		}
		break;

	case 0100640:	/* SCHB */
	case 0100641:	/* SCHD */
	case 0100642:	/* SCHF */
	case 0100643:	/* SCHH */
		chan = ((op & 03) << 1) + 1;
		CYCLE();
		srh = ((cop[chan] << 5) & SIGN) |
		      ((cop[chan] << 1) & 06) |
		      ((clr[chan] >> 14) & 1);
		srl = ((cop[chan] << 13) & 000000200000) |
		      (((long)clr[chan] << 18) & 037777000000) |
		       (car[chan] & 000000077777);
		setmeml(y, srl);
		memh[y] = srh;
		break;

	case 0100734:	/* PDX */
		setxr(((ach & 1) << 14) |
			  ((acl & 037777000000) >> 18));
		break;

	case 0100737:	/* PDC */
		setxr(0100000 - (((ach & 1) << 14) |
		                 ((acl & 037777000000) >> 18)));
		break;

	case 0100754:	/* PXD */
		ach = (getxr() >> 14) & 1;
		acl = ((unsigned long)getxr() << 18) & 037777000000;
		break;

	case 0100756:	/* PCD */
		if (tag == 0) {
		   ach = 0;
		   acl = 0;
		} else {
		   unsigned short x = 0100000 - getxr();
		   ach = x >> 14 ;
		   acl = (x << 18) & 037777000000;
		}
		break;

	case 0100763:	/* LGL */
		for (y &= 0377; y; y--) {
			ach = (ach & SIGN) | ((ach << 1) & (Q|P|HMSK));
			if (ach & P)
				acoflo = 1;
			if (acl & 020000000000)
				ach++;
			acl <<= 1;
			if (mqh & SIGN)
				acl++;
			mqh = mqh << 1;
			if (mqh & P)
				mqh += (SIGN - P);
			if (mql & 020000000000)
				mqh++;
			mql <<= 1;
		}
		break;

	case 0100764:	/* BSF */
		chan = (addr & 017000) >> 9;
		if (chan && chan <= NUMCHAN) {
			chan--;
			if (cact[chan])
				do_chan(chan);
			cun[chan] = (addr - getxr()) & 0777;
			dev = unitcheck(chan, -1);
			if (dev != -1) {
				csel[chan] = BSF_SEL;
				cact[chan] = 1;
				chan_in_op |= 1 << chan;
			}
		} else {
			machchk = 1;
			run = 0;
		}
		CYCLE();
		break;

	case 0100765:	/* LGR */
		for (y &= 0377; y; y--) {
			mql >>= 1;
			if (mqh & 1)
				mql |= 020000000000;
			if (mqh & SIGN)
				mqh -= (SIGN - P);
			mqh >>= 1;
			if (acl & 1)
				mqh |= SIGN;
			acl >>= 1;
			if (ach & 1)
				acl |= 020000000000;
			ach = (ach & SIGN) | ((ach >> 1) & (P|HMSK));
		}
		break;

	case 0100772:	/* RUN */
		chan = (addr & 017000) >> 9;
		if (chan && chan <= NUMCHAN) {
			chan--;
			if (cact[chan])
				do_chan(chan);
			cun[chan] = (addr - getxr()) & 0777;
			dev = unitcheck(chan, -1);
			if (dev != -1) {
				unload(dev);
			}
		} else {
			machchk = 1;
			run = 0;
		}
		CYCLE();
		break;

	case 0100773:	/* RQL */
		for (y &= 0377; y; y--) {
			adderh = mqh;
			mqh <<= 1;
			if (mqh & P)
				mqh += (SIGN - P);
			if (mql & 020000000000)
				mqh++;
			mql <<= 1;
			if (adderh & SIGN)
				mql++;
		}
		break;

	case 0100774:	/* AXC */
		setxr(0100000 - (srl & 077777));
		break;

	default:
ILLINST:
		machchk = 1;
		run = 0;
		break;
	}
}

void
crq()
{
	register unsigned i;

	srl = (srl & 037777700000) | addr;
	shcnt = ((srl & 000377000000) >> 18);
	while (shcnt) {
		i = (mqh & SIGN) >> 2 |
		    (mqh & HMSK) << 2 |
		    mql >> 30;
		i = (srl + i) & 077777;
		ACCESS(i);
		for (i = 0; i < 6; i++) {
			mqh = (mqh << 1) & (P|HMSK);
			if (mqh & P)
				mqh += SIGN - P;
			if (mql & 020000000000)
				mqh++;
			mql <<= 1;
		}
		mql |= (srh & SIGN) >> 2 |
		       (srh & HMSK) << 2 |
		       srl >> 30;
		shcnt--;
	}
	tag &= 1;
	if (tag)
		setxr(srl);
}

void
caq()
{
	register unsigned i;
	register t;

	srl = (srl & 037777700000) | addr;
	shcnt = ((srl & 000377000000) >> 18);
	while (shcnt) {
		i = (mqh & SIGN) >> 2 |
		    (mqh & HMSK) << 2 |
		    mql >> 30;
		i = (srl + i) & 077777;
		ACCESS(i);
		for (i = 0; i < 6; i++) {
			t = mqh & SIGN;
			mqh = (mqh << 1) & (P|HMSK);
			if (mqh & P)
				mqh += SIGN - P;
			if (mql & 020000000000)
				mqh++;
			mql <<= 1;
			mql |= t >> 7;
		}
		if (srh & SIGN)
			srh -= SIGN - P;
		adderl = srl + acl;
		adderh = (srh & (P|HMSK)) + (ach & (Q|P|HMSK));
		if (adderl < srl)
			adderh++;
		if (srh & P)
			srh += SIGN - P;
		acl = adderl;
		ach = (adderh & (Q|P|HMSK)) | (ach & SIGN);
		shcnt--;
	}
	tag &= 1;
	if (tag)
		setxr(srl);
}
