/***********************************************************************
*
* binloader.c - IBM 7090 emulator binary loader routines for ASM7090
*            object files.
*
* Changes:
*   10/20/03   DGP   Original.
*   12/28/04   DGP   Changed for new object formats.
*   
***********************************************************************/

#define EXTERN extern

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <errno.h>

#include "sysdef.h"
#include "regs.h"
#include "trace.h"
#include "lights.h"
#include "io.h"
#include "chan.h"
#include "console.h"
#include "screen.h"
#include "binloader.h"

extern char errview[5][81];
extern int errno;

int
binloader (char *file, int loadpt)
{
   FILE *fd;
   FILE *lfd;
   int transfer = 0;
   int loadaddr = 0200;
   int curraddr = 0200;
   char inbuf[82];

#ifdef DEBUGLOADER
   lfd = fopen ("load.log", "w");
   fprintf (lfd, "binloader: file = '%s', loadpt = %d\n", file, loadpt);
#endif

   if (loadpt > 0)
   {
      loadaddr = loadpt;
      curraddr = loadpt;
   }

   if ((fd = fopen (file, "r")) == NULL)
   {
      sprintf (errview[0], "binloader: open failed: %s",
	       strerror(errno));
      sprintf (errview[1], "filename: %s", file);
      iochk = 1;
      run = 0;
#ifdef DEBUGLOADER
      fprintf (lfd, "error: %s\n", errview[0]);
      fprintf (lfd, "       %s\n", errview[1]);
      fclose (lfd);
#endif
      return (-1);
   }

   while (fgets (inbuf, sizeof(inbuf), fd))
   {
      char *op = inbuf;
      int i;

      for (i = 0; i < 5; i++)
      {
	 char otag;
	 char item[16];
	 union 
	 {
	    uint32 ldata[2];
	    t_uint64 lldata;
	 } d;

	 otag = *op++;
	 if (otag == ' ') break;
	 strncpy (item, op, 12);
	 item[12] = '\0';
	 d.lldata = strtoll (item, NULL, 8);

#ifdef DEBUGLOADER
	 fprintf (lfd, "loadaddr = %5.5o, curraddr = %5.5o\n",
		  loadaddr, curraddr);
	 fprintf (lfd, "   otag = %c, item = %s\n", otag, item);
	 fprintf (lfd, "   d.ldata = %2.2o %11.11o\n",
		  d.ldata[MSL], d.ldata[LSL]);
	 fprintf (lfd, "   d.lldata = %12.12llo\n", d.lldata);
#endif

         switch (otag)
	 {
	 case IDT_TAG:
	    break;

	 case ABSORG_TAG:
	    curraddr = loadaddr = d.ldata[LSL] & 077777;
	    break;

	 case RELORG_TAG:
	    curraddr = ((d.ldata[LSL] & 077777) + loadaddr) & 077777;
	    break;

	 case BSS_TAG:
	    curraddr = (curraddr + (d.ldata[LSL] & 077777)) & 077777;
	    break;

	 case ABSDATA_TAG:
	    memh[curraddr] = ((d.ldata[MSL] << 4) & SIGN)
			    | (d.ldata[MSL] & HMSK);
	    meml[curraddr] = d.ldata[LSL];
	    curraddr++;
	    break;

	 case RELADDR_TAG:
	    memh[curraddr] = ((d.ldata[MSL] << 4) & SIGN) 
			    | (d.ldata[MSL] & HMSK);
	    meml[curraddr] = d.ldata[LSL] + loadaddr;
	    curraddr++;
	    break;

	 case ABSXFER_TAG:
	    transfer = 1;
	 case ABSENTRY_TAG:
	    srh = 00; /* TRA   addr */
	    srl = 002000000000 | d.ldata[LSL];
	    if (transfer) goto GOSTART;
	    break;

	 case RELXFER_TAG:
	    transfer = 1;
	 case RELENTRY_TAG:
	    srh = 00; /* TRA   addr */
	    srl = 002000000000 | (d.ldata[LSL] + loadaddr);
	    if (transfer) goto GOSTART;
	    break;

	 default: ;
	 }
	 op += 12;
      }
   }

GOSTART:
#ifdef DEBUGLOADER
   fclose (lfd);
#endif
   fclose (fd);
}
