#include "libc.h"

/*  a program to read an Intel hex file into a buffer
 *  and then load it
 *  this is useful for overlaying the monitor, BIOS,
 *  BDOS, or CCP to enable one to try a new version
 *  
 *  can load a 12k file above address D000            */

main(argc, argv)
int argc;
char *argv[];
  {
  FILE *fopen(), *ptr;
  int getc(), convrt();
  int j, k, l, chksum, count;
  static int pc = 0;
  char buf[30000], c;
  char *mem, *i;
  static int offset = 0;
  static int m = 0;

/*  check if instruction wanted  */

  if (argc == 1)  {
    printf("usage:  loadhex -on -gn filename\n");
    return;
    }

/*  check if arguments are present  */

  for (j = 1; argv[j][0] == '-'; j = j + 1)  {
    for (k = 2; argv[j][k] != '\0'; k = k + 1)  {
      if ((l = argv[j][k] - '0') > 9)
        l -= 7;
      m = (m << 4) + l;
      }
    if (argv[j][1] == 'o' || argv[j][1] == 'O')
      offset = m;
    if (argv[j][1] == 'g' || argv[j][1] == 'G')
      pc = m;
    }

/*  get file to be loaded  */

  ptr = fopen(argv[j], "r");
  if (ptr == NULL)  {
    printf("cannot open %s\n", argv[j]);
    return;
    }

/*  load hex file into buf[]  */

  i = buf;
  while ((*i++ = getc(ptr)) != EOF);

/*  disable interupts

  di();

/*  now convert hex, load into memory, and check checksum  */

  i = buf;
  for (;;)  {
    while (*i++ != ':');
    if ((count = convrt(i, 2)) == 0)
      break;
    i += 2;
    chksum = count;
    mem = convrt(i, 4) + offset;          /*  get memory address  */
    chksum += convrt(i, 2);
    i += 2;
    chksum += convrt(i, 2);
    i += 4;
    for (; count > 0; count--)  {
      c = convrt(i, 2);
      *mem++ = c;                         /*  load memory  */
      chksum += c;
      i += 2;
      }
    c = convrt(i, 2);
    chksum += c;

/*  check checksum and print error if different  */

    if ((chksum &= 0xFF) != 0)  {
      printf("checksum error at %x\n", --mem);
      return;
      }

    }

/*  enable interrupts  */

  ei();

/*  go and execute  */

  exe(pc);

  }

/*  function to convert the j-digit hex string i to an integer */

int convrt(i, j)
char *i;
int j;
  {
  int k, l, m;

  k = 0;
  for (l = 0; l < j; l++)  {
    if ((m = *i++ - '0') > 9)
      m -= 7;
    k = (k << 4) + m;
    }
  return(k);
  }


/*  these routines must be assenbled and linked
    with loadhex.o

;  routines to disable and enable interrupts
;
         public  di_
di_:     di
         ret
;
         public  ei_
ei_:     ei
         ret
;
;  a routine to continue execution at the address
;  of its argument
;
         public  exe_
exe_:    pop     h
         pop     h
         pchl
         end

 *  end assembly routines  */


