/***********************************************************************
*
* s709.c - IBM 7090 emulator main routines.
*
* Changes:
*   ??/??/??   PRP   Original. Version 1.0.0
*   01/20/05   DGP   Changes for correct channel operation.
*   01/28/05   DGP   Revamped channel and tape controls.
*   02/07/05   DGP   Added command file.
*   
***********************************************************************/

#define EXTERN

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sysdef.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"

int prtviewlen;
int panelmode;
char prtview[100][82];

static FILE *cmdfd;
static int usecmdfile;
static char cmdfile[256];

/*
 * IBM 709x simulator
 */

uint16
getxr()
{

   if (tag == 0) return (0);
   if (multtag)
   {
      uint16 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(uint32 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()
{
   int32  i;
   uint32 l;
   uint8  t;

   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++)
	 {
            channel[i].ccyc = 0;
            if (run == 2 && channel[i].csel)
               man_chan(i);
            if (channel[i].cact)
               do_chan(i);
            channel[i].csel = 0;
         }
         run = 0;
	 if (usecmdfile)
	 {
	    if (commands(cmdfd) < 0)
	       usecmdfile = 0;
	 }
	 else
	 {
	    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 | (uint32)spill << 18;
         srh &= SIGN | 06;
         memh[0] = srh;
         setmeml(0, srl);
         spill = 0;
         ic = 00010;
      }
chans:
      for (i = 0; i < NUMCHAN; i++)
      {
         if (channel[i].csel && channel[i].ccyc <= cycle_count)
	 {
            if (channel[i].cact)
	    {
               active_chan(i);
               if (channel[i].csel && !channel[i].cact)
	       {
                  channel[i].csel = 0;
                  channel[i].ctrp = 1;
               }
            }
	    else
	    {
               endrecord(i, 0);
               channel[i].csel = 0;
            }
         }
         if (ctrap_ind)
	 {
            if (ctrap_enb & (1 << i))
	    {
#ifdef DEBUGTRAP
            fprintf (stderr,
		     "TRAP: Channel %c ctrap_enb = %o, trap = %d\n",
		     'A' + i, ctrap_enb, trap);
#endif
               if (channel[i].ctrp)
	       {
                  channel[i].ctrp = 0;
                  srl = 0000001000000;
                  goto chan_trap;
               }
               if (channel[i].ceof)
	       {
#ifdef DEBUGIO
                  fprintf (stderr,
			   "TRAP: Clear EOF \n");
#endif
                  channel[i].ceof = 0;
                  srl = 0000004000000;
                  goto chan_trap;
               }
            }
            if ((ctrap_enb & (01000000 << i)) && channel[i].cchk)
	    {
               channel[i].cchk = 0;
               srl = 0000002000000;
chan_trap:
               y = (i << 1) + 012;
               srl |= ic | (getmeml(y) & 0700000);
#ifdef DEBUGIO
               fprintf (stderr,
			"TRAP: Channel %c srl = %o ",
			'A' + i, srl);
               fprintf (stderr,
			"addr = %o\n", y);
#endif
               setmeml(y, srl);
               srh = memh[y + 1];
               srl = getmeml(y + 1);
               ctrap_ind = 0;
               stop = 0;
               goto exec;
            }
         }
      }
   }
}

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

   cmdfile[0] = '\0';
   cpumode = 7090;
   windowlen = 25;
   panelmode = 1;
   usecmdfile = 0;
   ioinit();

   for (i = 1; i < argc; i++)
   {
      if (*argv[i] == '-')
      {
	 char *bp = &argv[i][1];
	 switch (*bp)
	 {
	 case 'c': /* Command file spec */
	    bp++;
	    strcpy (cmdfile,bp);
	    usecmdfile = 1;
	    break;

	 case 'm': /* cpu mode */
	    bp++;
	    cpumode = atoi (bp);
	    if (cpumode != 709 && cpumode != 7090 && cpumode != 7094)
	       goto usage;
	    break;

	 case 'p': /* turn off panel mode */
	    panelmode = 0;
	    break;

	 case 'w': /* Set window length */
	    bp++;
	    windowlen = atoi(bp);
	    break;

	 case 'h': /* help */
    usage:
	    printf (
	      "usage: s709 [-options] [r=cr] [p=print] [u=punch] [c#=tape]\n");
	    printf (" options:\n");
	    printf ("    -cCMDFILE    - Command file\n"); 
	    printf ("    -mCPU        - CPU mode\n");
	    printf ("            CPU = 709, 7090 or 7094, default = 709\n");
	    printf ("    -p           - Turn off panel mode\n");
	    printf ("    -wNN         - Window size for panel\n");
	    exit(1);

	 default:
	    goto usage;
	 }
      }
      else
      {
	 mount(argv[i]);
      }
   }

   prtviewlen = windowlen - 20;
   if (panelmode)
   {
      clearscreen();
      screenposition (1,1);
   }
   else
      printf("IBM %d Simulator %s\n", cpumode, VERSION); 

   if (usecmdfile)
   {
      if ((cmdfd = fopen (cmdfile, "r")) == NULL)
      {
         char temp[256];
	 sprintf (temp, "Unable to open command file: %s", cmdfile);
	 perror (temp);
	 exit (1);
      }
   }
   kyh = (char)SIGN;
   kyl = 0100037;
   /*kyh = 00; *//* TRA   3 */
   /*kyl = 002000000003 ;*/
   automatic = 1;
   s709();
   iofin();
   if (panelmode)
      screenposition (windowlen, 1);
   return 0;
}
