
#include <stdio.h>
#include "regs.h"
#include "trace.h"
#include "s709.h"
#include "io.h"
#include "chan.h"
#include "negop.h"
#include "posop.h"
#include "sense.h"
#include "console.h"
#include "lights.h"
#include "screen.h"

/*
 * IBM 709x simulator
 */

unsigned short
getxr()
{

	if (multtag) {
		unsigned short r;

		r = 0;
		if (tag & 1)
			r |= xr[1];
		if (tag & 2)
			r |= xr[2];
		if (tag & 4)
			r |= xr[4];
		return r;
	} else {
		return xr[tag];
	}
}

void
setxr(unsigned long r)
{

     if (tag != 0) {
	r &= 077777;
	if (multtag) {
		if (tag & 1)
			xr[1] = r;
		if (tag & 2)
			xr[2] = r;
		if (tag & 4)
			xr[4] = r;
	} else {
		xr[tag] = r;
	}
     }
}

void
traptrace()
{

	setmeml(0, (getmeml(0) & 037777000000) | (ic - 1));
}

void
steal_cycle()
{

	if (single_cycle) {
		console();
	}
	if (cycle_count >= next_lights) {
		lights();
		next_lights = cycle_count + NEXTLIGHTS;
		check_intr();
	}
	next_steal = next_lights;
}

void
s709()
{
	register i;
	unsigned char t;
	unsigned long l;

	clear();
	run = 0;
	for (;;) {
		if (stop && chan_in_op == 0)
			run = 0;
		if (addrstop && ic == stopic)
			run = 0;
		if (run != 1 || !automatic) {
			for (i = 0; i < MAXCHAN; i++) {
				ccyc[i] = 0;
				if (run == 2 && csel[i])
					man_chan(i);
				if (cact[i])
					do_chan(i);
				csel[i] = 0;
			}
			run = 0;
			console();
			if (!run)
				continue;
			if (run == 2) {
				run = 0;
				goto exec;
			}
			if (run == 3) {
				run = 1;
				goto exec;
			}
			if (stop)
				ic = addr;
			stop = 0;
		}
		if (stop) {
			cycle_count++;
			goto chans;
		}

		/*
		 * Fetch
		 */

		srh = memh[ic];
		srl = getmeml(ic);

		itrc_h[itrc_idx] = srh;
		itrc_l[itrc_idx] = srl;
		itrc_buf[itrc_idx++] = ic;
		if (itrc_idx == 32)
			itrc_idx = 0;
		ic++;

	exec:
		op = (srh << 8) |	((srl & 037700000000) >> 24);
		flag =			 (srl & 000060000000) == 000060000000;
		tag =			((srl & 000000700000) >> 15);
		addr =			 (srl & 000000077777);
		CYCLE();
		if (op & 03000) {
			decr = ((srh & 1) << 14) | ((srl & 037777000000) >> 18);
			switch(op & 0103000) {

			case 0101000:	/* STR */
				setmeml(0, (getmeml(0) & 037777700000) | ic);
				CYCLE();
				ic = 00002;
				break;

			case 0001000:	/* TXI */
				if (trap)
					traptrace();
				setxr(getxr() + decr);
				if (trap)
					ic = 00001;
				else
					ic = addr;
				CYCLE();
				break;

			case 0002000:	/* TIX */
				if (trap)
					traptrace();
				if (getxr() > decr) {
					setxr(getxr() - decr);
					if (trap)
						ic = 00001;
					else
						ic = addr;
				}
				CYCLE();
				break;

			case 0102000:	/* TNX */
				if (trap)
					traptrace();
				if (getxr() <= decr) {
					if (trap)
						ic = 00001;
					else
						ic = addr;
				} else {
					setxr(getxr() - decr);
				}
				CYCLE();
				break;
			case 0003000:	/* TXH */
				if (trap)
					traptrace();
				if (getxr() > decr) {
					if (trap)
						ic = 00001;
					else
						ic = addr;
				}
				CYCLE();
				break;

			case 0103000:	/* TXL */
				if (trap)
					traptrace();
				if (getxr() <= decr) {
					if (trap)
						ic = 00001;
					else
						ic = addr;
				}
				CYCLE();
				break;

			}
		} else {

			if (flag) {
				switch (op) {
				case 0000767:	/* ALS */
				case 0000771:	/* ARS */
				case 0000763:	/* LLS */
				case 0000765:	/* LRS */
				case 0100763:	/* LGL */
				case 0100765:	/* LGR */
				case 0100773:	/* RQL */
					flag = 0;
				}
			}
			if (flag) {
				l = getmeml((addr - getxr()) & MEMLIMIT);
				t = tag;
				tag = (l & 0700000) >> 15;
				y = (l - getxr()) & MEMLIMIT;
				tag = t;
			} else {
				y = (addr - getxr()) & MEMLIMIT;
			}

			if (op == 0000522) {	/* XEC */
				srh = memh[y];
				srl = getmeml(y);
				goto exec;
			} else if ( (op & 0007777) == 0000760 ) { /* PSE, MSE */
				sense_instr();
				CYCLE();
			} else if ( (op & 0100000) == 0 ) {
				posop();
			} else {
				negop();
			}
		}
		single_cycle = 0;
		if (spill) {
			ACCESS(0);
			srl = (srl & 000000700000) | ic | (long)spill << 18;
			srh &= SIGN | 06;
			memh[0] = srh;
			setmeml(0, srl);
			spill = 0;
			ic = 00010;
		}
chans:
		for (i = 0; i < NUMCHAN; i++) {
			if (csel[i] && ccyc[i] <= cycle_count) {
				if (cact[i]) {
					active_chan(i);
					if (csel[i] && !cact[i]) {
						csel[i] = 0;
						ctrp[i] = 1;
					}
				} else {
					endrecord(i);
					csel[i] = 0;
				}
			}
			if (ctrap_ind) {
				if (ctrap_enb & (1 << i)) {
					if (ctrp[i]) {
						ctrp[i] = 0;
						srl = 0000001000000;
						goto chan_trap;
					}
					if (ceof[i]) {
						ceof[i] = 0;
						srl = 0000004000000;
						goto chan_trap;
					}
				}
				if ((ctrap_enb & (01000000 << i)) && cchk[i]) {
					cchk[i] = 0;
					srl = 0000002000000;
chan_trap:
					y = (i << 1) + 012;
					srl |= ic | (getmeml(y) & 0700000);
					setmeml(y, srl);
					srh = memh[y + 1];
					srl = getmeml(y + 1);
					ctrap_ind = 0;
					stop = 0;
					goto exec;
				}
			}
		}
	}
}

int
main(argc, argv)
	int	argc;
	char	**argv;
{
	int	i;

	cpumode = 709;
	ioinit();
	for (i = 1; i < argc; i++) {
	     if (*argv[i] == '-') {
	        char *bp = &argv[i][1];
		switch (*bp) {
		case 'm': /* cpu mode */
		   bp++;
		   cpumode = atoi (bp);
		   if (cpumode != 709 && cpumode != 7090 && cpumode != 7094)
		      goto usage;
		   break;
		case 'h':
	    usage:
		   printf ("usage: s709 [-mCPU] [r=cr] [p=print] [u=punch] [c#=tape]\n");
		   printf ("   CPU = 709, 7090 or 7094, default = 709\n");
		   exit(1);
	        default:
		   goto usage;
		}
	     }
	     else {
		mount(argv[i]);
	     }
	}
	clearscreen();
	screenposition (1,1);
	kyh = (char)SIGN;
	kyl = 0100037;
	automatic = 1;
	s709();
	iofin();
	return 0;
}
