/* LarkELoad.c
   Pup package based download and teledebugging
   L. Stewart, December 27, 1982  10:59 PM, created from cmeload.c
   L. Stewart, February 24, 1983  8:46 PM, new protocol
   L. Stewart, April 29, 1983  8:12 PM, slave and call stuff
 */

#include <Ec.h>
#include <Env.h>
#include <Queue.h>
#include <Pup.h>
#include <LarkSlave.h>

/* the format of junk is
  struct Advice {
    bit setAddr;
    bit setAdvice;
    bit(14) advice;
    };
 */
struct Core {
  int advice, addrlo, addrhi, count;
  char data[1];
  };

/* from runtime */
extern MoveBlock();
extern ByteBlt();
extern Swab();
extern DoubleEQ();

/* from Pup package */
extern OpenLevel1Socket();
extern SendPup();
extern ReleasePBI();
extern CheckCheckSum();
extern SwapSourceAndDest();

extern int localNet;
extern int localHost;
extern int lenPup;

/* local variables */
static struct Port elPort;
static int elSoc;

#define ELWrite 0x00c0
#define ELRead 0x00c2
#define ELStateRead 0x00c6
#define ELDebug 0x00c8

/* read and write the slave address space */
#define ELSWrite 0x00ce
#define ELSRead 0x00d0

/* call a procedure */
#define ELCall 0x00d2

ELoadProc(pbi)
  struct PBI *pbi;
  {
  struct Pup *p;
  char *caddr;
  char *cdata;
  int ccount;
  int ptype;
  int maxLength;
  struct Core *core;
  p = pbi->pup;
  ptype = p->type;
  if ((p->dPort.host == 0) && (ptype != ELStateRead)) goto reject;
  core = (struct Core *) &p->data;
  caddr = Swab(core->addrlo);
  maxLength = ((lenPup - pupOvWords) - 3) << 1;
  ccount = Swab(core->count);
  if (ccount < 0) goto reject;
  if (ccount > maxLength) {
    ccount = maxLength;
    core->count = Swab(maxLength);
    };
  cdata = &core->data[0];
  if (core->addrhi) goto reject;
  if (!CheckCheckSum(p)) goto reject;
  switch (ptype) {
    case ELWrite:
      ByteBlt(caddr, cdata, ccount);
    case ELRead:
      if (Ugt(caddr, 0xffcf)) goto reject;
      if (Ugt(ccount, 0xffd0 - ((int) caddr))) goto reject;
      ByteBlt(cdata, caddr, ccount);
      /* swap source and destination */
      SwapSourceAndDest(p);
      p->length = Swab((31 + ccount) & 0xfffe);
      Block();
      p->type = p->type + 1;
      SendPup(pbi);
      return;
    case ELSWrite:
      SlaveBLT(caddr, cdata, ccount);  /* how tell when it is done ? */
    case ELSRead:
      SlaveBLT(cdata, caddr, ccount);
      SwapSourceAndDest(p);
      p->length = Swab((31 + ccount) & 0xfffe);
      Block();
      p->type = p->type + 1;
      SendPup(pbi);
      return;
    case ELCall:
      ClientCallPkt(cdata);
      SwapSourceAndDest(p);
      p->type = p->type + 1;
      SendPup(pbi);
      return;
    case ELStateRead: 
      if ((int) caddr != 1) goto reject;
      ByteBlt(cdata, 0xda00, ccount);
      /* swap source and destination */
      SwapSourceAndDest(p);
      p->length = Swab((31 + ccount) & 0xfffe);
      Block();
      p->type = p->type + 1;
      SendPup(pbi);
      return;
    case ELDebug: { CallDebugger(ecPup1+21); goto reject; };
    default: goto reject;
    };
  reject: ReleasePBI(pbi);
  };

/* call ELoad to set up a TeleDebug server */
ELoad()
  {
  elPort.net = localNet;
  elPort.host = localHost;
  elPort.socket.LS = 0;
  elPort.socket.ms = 0x3000;
  elSoc = OpenLevel1Socket(&elPort, &ELoadProc, 0);
  if (!elSoc) CallDebugger(ecPup1+10);
  };

struct CCPArgs {
  int proc;
  int nargs;
  int returnSlot;
  int args[5];
  };

ClientCallPkt(cp)
  struct CCPArgs *cp;
  {
  BlockSwab(cp, 8);
  if (cp->nargs > 5) return;
  cp->returnSlot = Apply(&cp->args[0], cp->proc, cp->nargs);
  BlockSwab(cp, 8);
  };