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

void
posop()
{
	register chan;
	register dev;

	switch(op) {

	case 0000000:	/* HTR */
		stop = 1;
		cycle_count++;
		ic--;
		break;

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

	case 0000021:	/* TTR */
		ic = y;
		break;

	case 0000022:	/* TRCA */
		chan = 0;
		goto trcx;
	case 0000024:	/* TRCC */
		chan = 2;
		goto trcx;
	case 0000026:	/* TRCE */
		chan = 4;
		goto trcx;
	case 0000027:	/* TRCG */
		chan = 6;
	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 0000030:	/* TEFA */
	case 0000031:	/* TEFC */
	case 0000032:	/* TEFE */
	case 0000033:	/* TEFG */
		chan = (op & 03) << 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 0000040:	/* TLQ */
		if (trap)
			traptrace();
		if ((ach & SIGN) == 0) {
			if ((mqh & SIGN) == 0) {
				if ( (ach & (Q|P|HMSK)) > (mqh & HMSK) )
					goto tlqtr;
				if ( (ach & (Q|P|HMSK)) < (mqh & HMSK) )
					break;
				if ( acl > mql )
					goto tlqtr;
				break;
			} else {
				goto tlqtr;
			}
		} else {
			if ((mqh & SIGN) == 0) {
				break;
			} else {
				if ( (ach & (Q|P|HMSK)) > (mqh & HMSK) )
					break;
				if ( (ach & (Q|P|HMSK)) < (mqh & HMSK) )
					goto tlqtr;
				if ( acl > mql )
					break;
				if ( acl < mql )
					goto tlqtr;
				break;
			}
		}
tlqtr:		if (trap)
			ic = 00001;
		else
			ic = y;
		break;

	case 0000041:	/* IIA */
		sih ^= ach & (P|HMSK);
		sil ^= acl;
		break;

	case 0000042:	/* TIO */
		if (trap)
			traptrace();
		if ( ((ach & (P|HMSK)) & sih) == (ach & (P|HMSK)) &&
		     (acl & sil) == acl ) {
			if (trap)
				ic = 00001;
			else
				ic = y;
		}
		CYCLE();
		break;

	case 0000043:	/* OAI */
		sih |= ach & (P|HMSK);
		sil |= acl;
		break;

	case 0000044:	/* PAI */
		sih = ach & (P|HMSK);
		sil = acl;
		break;

	case 0000046:	/* TIF */
		if (trap)
			traptrace();
		if ( ((ach & (P|HMSK)) & ~sih) == (ach & (P|HMSK)) &&
		     (acl & ~sil) == acl ) {
			if (trap)
				ic = 00001;
			else
				ic = y;
		}
		CYCLE();
		break;

	case 0000051:	/* IIR */
		sil ^= srl & 0777777;
		break;

	case 0000054:	/* RFT */
		if ( ((srl & 0777777) & ~sil) == (srl & 0777777) )
			ic++;
		DCYCLE();
		DCYCLE();
		break;

	case 0000055:	/* SIR */
		sil |= srl & 0777777;
		break;

	case 0000056:	/* RNT */
		if ( ((srl & 0777777) & sil) == (srl & 0777777) )
			ic++;
		DCYCLE();
		DCYCLE();
		break;

	case 0000057:	/* RIR */
		sil &= ~(srl & 0777777);
		break;

	case 0000060:	/* TCOA */
	case 0000061:	/* TCOB */
	case 0000062:	/* TCOC */
	case 0000063:	/* TCOD */
	case 0000064:	/* TCOE */
	case 0000065:	/* TCOF */
	case 0000066:	/* TCOG */
	case 0000067:	/* TCOH */
		if (trap)
			traptrace();
		chan = op & 07;
		if (csel[chan]) {
			if (trap)
				ic = 00001;
			else
				ic = y;
		}
		break;

	case 0000074:	/* TSX */
		if (stop)
			setxr(-(ic));
		else
			setxr(-(ic-1));
		if (trap) {
			traptrace();
			ic = 00001;
		} else {
			ic = addr;
		}
		break;

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

	case 0000114:	/* CVR */
	case 0000115:
	case 0000116:
	case 0000117:
		cvr();
		break;

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

	case 0000131:	/* XCA */
		srh = ach & (SIGN|HMSK);
		srl = acl;
		ach = mqh;
		acl = mql;
		mqh = srh;
		mql = srl;
		break;

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

	case 0000161:	/* TQO */
		if (trap)
			traptrace();
		if (simulate && mqoflo != 0) {
			if (trap)
				ic = 00001;
			else
				ic = y;
			mqoflo = 0;
		}
		break;

	case 0000162:	/* TQP */
		if (trap)
			traptrace();
		if ((mqh & SIGN) == 0) {
			if (trap)
				ic = 00001;
			else
				ic = y;
		}
		break;

	case 0000200:	/* MPY */
		ACCESS(y);
		shcnt = 043;
		mpy();
		break;

	case 0000204:	/* VLM */
	case 0000205:	/* VLM (for 9M51B) */
		shcnt = ((srl & 000077000000) >> 18);
		ACCESS(y);
		if (shcnt)
			mpy();
		break;

	case 0000220:	/* DVH */
		ACCESS(y);
		shcnt = 043;
		div();
		if (divchk)
			run = 0;
		break;

	case 0000221:	/* DVP */
		ACCESS(y);
		shcnt = 043;
		div();
		break;

	case 0000224:	/* VDH */
		shcnt = ((srl & 000077000000) >> 18);
		ACCESS(y);
		if (shcnt) {
			div();
			if (divchk)
				run = 0;
		}
		break;

	case 0000225:	/* VDP */
	case 0000227:	/* VDP */
		shcnt = ((srl & 000077000000) >> 18);
		ACCESS(y);
		if (shcnt)
			div();
		break;

	case 0000240:	/* FDH */
		ACCESS(y);
		fdiv();
		if (divchk)
			run = 0;
		break;

	case 0000241:	/* FDP */
		ACCESS(y);
		fdiv();
		break;

	case 0000260:	/* FMP */
		ACCESS(y);
		fmpy(1);
		break;

	case 0000261:	/* DFMP */
		if (cpumode != 7094) goto ILLINST;
		ACCESS(y);
		dfmpy(1);
		break;

	case 0000300:	/* FAD */
		ACCESS(y);
		fadd(1);
		break;

	case 0000301:	/* DFAD */
		if (cpumode != 7094) goto ILLINST;
		ACCESS(y);
		dfadd(1);
		break;

	case 0000302:	/* FSB */
		ACCESS(y);
		srh ^= SIGN;
		fadd(1);
		break;

	case 0000303:	/* DFSB */
		if (cpumode != 7094) goto ILLINST;
		ACCESS(y);
		srh ^= SIGN;
		dfadd(1);
		break;

	case 0000304:	/* FAM */
		ACCESS(y);
		srh &= ~SIGN;
		fadd(1);
		break;

	case 0000305:	/* DFAM */
		if (cpumode != 7094) goto ILLINST;
		ACCESS(y);
		srh &= ~SIGN;
		dfadd(1);
		break;

	case 0000306:	/* FSM */
		ACCESS(y);
		srh |= SIGN;
		fadd(1);
		break;

	case 0000307:	/* DFSM */
		if (cpumode != 7094) goto ILLINST;
		ACCESS(y);
		srh |= SIGN;
		dfadd(1);
		break;

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

	case 0000322:	/* ERA */
		ACCESS(y);
		CYCLE();
		if (srh & SIGN)
			srh -= SIGN - P;
		ach = (ach ^ srh) & (P|HMSK);
		acl = acl ^ srl;
		if (srh & P)
			srh += SIGN - P;
		DCYCLE();
		break;

	case 0000340:	/* CAS */
		ACCESS(y);
		if ((ach & SIGN) == 0) {
			if ((srh & SIGN) == 0) {
				if ( (ach & (Q|P|HMSK)) > (srh & HMSK) )
					goto skip0;
				if ( (ach & (Q|P|HMSK)) < (srh & HMSK) )
					goto skip2;
				if ( acl > srl )
					goto skip0;
				if ( acl < srl )
					goto skip2;
				goto skip1;
			} else {
				goto skip0;
			}
		} else {
			if ((srh & SIGN) == 0) {
				goto skip2;
			} else {
				if ( (ach & (Q|P|HMSK)) > (srh & HMSK) )
					goto skip2;
				if ( (ach & (Q|P|HMSK)) < (srh & HMSK) )
					goto skip0;
				if ( acl > srl )
					goto skip2;
				if ( acl < srl )
					goto skip0;
				goto skip1;
			}
		}
skip2:		ic++;
skip1:		ic++;
skip0:		break;

	case 0000361:	/* ACL */
		ACCESS(y);
		if (srh & SIGN)
			srh -= SIGN - P;
		adderl = srl + acl;
		adderh = (srh & (P|HMSK)) + (ach & (P|HMSK));
		if (adderl < srl)
			adderh++;
		if (adderh & Q) {
			adderl++;
			if (adderl == 0)
				adderh++;
		}
		if (srh & P)
			srh += SIGN - P;
		acl = adderl;
		ach = (adderh & (P|HMSK)) | (ach & (SIGN|Q));
		CYCLE();
		break;

	case 0000400:	/* ADD */
		ACCESS(y);
		add();
		CYCLE();
		break;

	case 0000401:	/* ADM */
		ACCESS(y);
		srh &= ~SIGN;
		add();
		CYCLE();
		break;

	case 0000402:	/* SUB */
		ACCESS(y);
		srh ^= SIGN;
		add();
		CYCLE();
		break;

	case 0000420:	/* HPR */
		stop = 1;
		cycle_count++;
		addr = ic;
		ic--;
		break;

	case 0000440:	/* IIS */
		ACCESS(y);
		if (srh & SIGN)
			srh -= SIGN - P;
		sih ^= srh;
		sil ^= srl;
		if (srh & P)
			srh += SIGN - P;
		break;

	case 0000441:	/* LDI */
		ACCESS(y);
		if (srh & SIGN)
			srh -= SIGN - P;
		sih = srh;
		sil = srl;
		if (srh & P)
			srh += SIGN - P;
		break;

	case 0000442:	/* OSI */
		ACCESS(y);
		if (srh & SIGN)
			srh -= SIGN - P;
		sih |= srh;
		sil |= srl;
		if (srh & P)
			srh += SIGN - P;
		break;

	case 0000443:	/* DLD */
		if (cpumode != 7094) goto ILLINST;
		ACCESS(y);
		ach = srh;
		acl = srl;
		ACCESS(y+1);
		mqh = srh;
		mql = srl;
	        break;

	case 0000444:	/* OFT */
		ACCESS(y);
		if (srh & SIGN)
			srh -= SIGN - P;
		if ( (srh & ~sih) == srh &&
		     (srl & ~sil) == srl )
			ic++;
		if (srh & P)
			srh += SIGN - P;
		CYCLE();
		DCYCLE();
		break;

	case 0000445:	/* RIS */
		ACCESS(y);
		if (srh & SIGN)
			srh -= SIGN - P;
		sih &= ~srh;
		sil &= ~srl;
		if (srh & P)
			srh += SIGN - P;
		break;

	case 0000446:	/* ONT */
		ACCESS(y);
		if (srh & SIGN)
			srh -= SIGN - P;
		if ( (srh & sih) == srh  &&
		     (srl & sil) == srl )
			ic++;
		if (srh & P)
			srh += SIGN - P;
		CYCLE();
		DCYCLE();
		break;

	case 0000500:	/* CLA */
		ACCESS(y);
		ach = srh;
		acl = srl;
		break;

	case 0000502:	/* CLS */
		ACCESS(y);
		srh ^= SIGN;
		ach = srh;
		acl = srl;
		break;

	case 0000520:	/* ZET */
		ACCESS(y);
		if ((srh & HMSK) == 0 && srl == 0)
			ic++;
		break;

	case 0000534:	/* LXA */
		ACCESS(addr);
		setxr(srl);
		break;

	case 0000535:	/* LAC */
		ACCESS(addr);
		setxr(0100000 - (srl & 077777));
		break;

	case 0000540:	/* RCHA */
	case 0000541:	/* RCHC */
	case 0000542:	/* RCHE */
	case 0000543:	/* RCHG */
		chan = (op & 03) << 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 0000544:	/* LCHA */
	case 0000545:	/* LCHC */
	case 0000546:	/* LCHE */
	case 0000547:	/* LCHG */
		chan = (op & 03) << 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 0000560:	/* LDQ */
		ACCESS(y);
		mqh = srh;
		mql = srl;
		break;

	case 0000564:	/* ENB */
		ACCESS(y);
		ctrap_enb = srl & 00037700377;
		ctrap_ind = 1;
		break;

	case 0000600:	/* STZ */
		memh[y] = 0;
		setmeml(y, 0L);
		CYCLE();
		break;

	case 0000601:	/* STO */
		memh[y] = ach & (SIGN|HMSK);
		setmeml(y, acl);
		CYCLE();
		break;

	case 0000602:	/* SLW */
		memh[y] = ((ach << 4) & SIGN) | (ach & HMSK);
		setmeml(y, acl);
		CYCLE();
		break;

	case 0000604:	/* STI */
		srh = sih;
		srl = sil;
		if (srh & P)
			srh += SIGN - P;
		memh[y] = srh;
		setmeml(y, srl);
		break;

	case 0000621:	/* STA */
		setmeml(y, (getmeml(y) & 037777700000) |
			   (acl &     000000077777));
		CYCLE();
		break;

	case 0000622:	/* STD */
		memh[y] = (memh[y] & 0376) | (ach & 001);
		setmeml(y, (getmeml(y) & 000000777777) |
			   (acl &     037777000000));
		CYCLE();
		break;

	case 0000625:	/* STT */
		setmeml(y, (getmeml(y) & 037777077777) |
			   (acl &     000000700000));
		CYCLE();
		break;

	case 0000630:	/* STP */
		memh[y] = (memh[y] & 001) |
			  ((ach << 4) & SIGN) | (ach & 006);
		CYCLE();
		break;

	case 0000634:	/* SXA */
		setmeml(addr, (getmeml(addr) & 037777700000) | getxr());
		CYCLE();
		break;

	case 0000636:	/* SCA */
		{ unsigned short x = 0100000 - getxr() & 077777;
		if (tag == 0) x = 0;
		setmeml(addr, (getmeml(addr) & 037777700000) | x);
		CYCLE();
		}
		break;

	case 0000640:	/* SCHA */
	case 0000641:	/* SCHC */
	case 0000642:	/* SCHE */
	case 0000643:	/* SCHG */
		chan = (op & 03) << 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 0000734:	/* PAX */
		setxr(acl);
		break;

	case 0000737:	/* PAC */
		setxr(0100000 - (acl & 077777));
		break;

	case 0000754:	/* PXA */
		ach = 0;
		acl = getxr();
		break;

	case 0000756:   /* PCA */
		ach = 0;
		if (tag != 0) {
		   acl = (0100000 - getxr()) & 077777;
		}
		else
		   acl = 0;
	        break;

	case 0000761:	/* NOP */
		cycle_count++;
		break;

	case 0000762:	/* RDS */
		chan = (addr & 017000) >> 9;
		if (chan && chan <= NUMCHAN) {
			chan--;
			if (cact[chan])
				do_chan(chan);
			cun[chan] = (addr - getxr()) & 0777;
			if (unitcheck(chan, 1) != -1) {
				ctrp[chan] = 0;
				csel[chan] = READ_SEL;
				startrec(chan);
			}
		} else {
			machchk = 1;
			run = 0;
		}
		CYCLE();
		break;

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

	case 0000764:	/* BSR */
		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] = BSR_SEL;
				cact[chan] = 1;
				chan_in_op |= 1 << chan;
			}
		} else {
			machchk = 1;
			run = 0;
		}
		CYCLE();
		break;

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

	case 0000766:	/* WRS */
		chan = (addr & 017000) >> 9;
		if (chan && chan <= NUMCHAN) {
			chan--;
			if (cact[chan])
				do_chan(chan);
			cun[chan] = (addr - getxr()) & 0777;
			if (unitcheck(chan, 0) != -1) {
				ctrp[chan] = 0;
				csel[chan] = WRITE_SEL;
				startrec(chan);
			}
		} else {
			machchk = 1;
			run = 0;
		}
		CYCLE();
		break;

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

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

	case 0000771:	/* ARS */
		for (y &= 0377; y; y--) {
			acl >>= 1;
			if (ach & 1)
				acl |= 020000000000;
			ach = (ach & SIGN) | ((ach >> 1) & (Q|P|HMSK));
		}
		break;

	case 0000772:	/* REW */
		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) {
				dorewind(dev);
			}
		} else {
			machchk = 1;
			run = 0;
		}
		CYCLE();
		break;

	case 0000774:	/* AXT */
		setxr(srl);
		break;

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

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

void
cvr()
{
	register unsigned i;

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