/* LarkMonELoad.c
TeleLoad server using trivial ether driver
L. Stewart, February 11, 1983 2:21 PM, created from LarkELoad.c
L. Stewart, February 18, 1983 7:00 PM, SendState
L. Stewart, February 24, 1983 2:17 PM, Advice & setHost bits
L. Stewart, March 3, 1983 2:39 PM, access to statics
L. Stewart, April 28, 1983 11:27 AM, tl stuff to LarkMonML
L. Stewart, April 28, 1983 11:36 AM, larger state block, CheckState
L. Stewart, April 28, 1983 5:27 PM, Checksum
*/
#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 system */
extern SingleStep();
extern GoNormal();
extern GoFromBreak();
extern int mState[1];
extern int advice;
/* from runtime */
extern MoveBlock();
extern ByteBlt();
extern Swab();
extern DoubleEQ();
/* from Trivial Pup package */
extern SLCReset();
extern SStartRx();
extern struct PBI *SCheckRx();
extern SStartTx();
extern int SCheckTx(); /* BOOL */
/* local variables */
static int elBuf[130];
static struct PBI elPBI;
static int tlID[2];
static int stateTimer;
static int stateInterval;
static int gotReply;
/* next section must stay in order for GetDebugPtrs
to work (why?) */
extern int tlNet;
extern int tlHost;
extern int tlImHost;
extern int localNet;
#define ELWrite 0x00c0
#define ELRead 0x00c2
#define ELStateWrite 0x00c4
#define ELStateRead 0x00c6
#define ELDebug 0x00c8
#define ELBooted 0x00c9
/* these are for new break and single step facilities */
#define ELSingleStep 0x00ca
#define ELGoFromBreak 0x00cc
/* read and write the slave address space */
#define ELSWrite 0x00ce
#define ELSRead 0x00d0
/* call a procedure */
#define ELCall 0x00d2
/* call ELoad to set up a TeleDebug server */
StartEL()
{
SLCReset();
elPBI.pup = (struct Pup *) &elBuf[2];
tlID[0] = tlID[1] = 0x6767;
SStartRx(&elPBI, 256);
};
CheckEL()
{
if (SCheckRx() == 0) return;
ELoadProc(&elPBI);
SStartRx(&elPBI, 256);
};
static ELoadProc(pbi)
struct PBI *pbi;
{
struct Pup *pup;
char *caddr;
char *cdata;
int cAdvice;
int ccount;
int pupType;
int maxLength;
int dHost;
struct Core *core;
pup = pbi->pup;
/* check for various bad things */
if (pup->dPort.socket.LS != 0) goto reject;
if (pup->dPort.socket.ms != 0x3000) goto reject;
/* accept broadcase teledeb packets for now */
dHost = pup->dPort.host;
if ((dHost != EtherHost()) && (dHost != 0)) goto reject;
if (!CheckCheckSum(pup)) goto reject;
core = (struct Core *) &pup->data;
if (core->addrhi) goto reject;
ccount = Swab(core->count);
if (ccount < 0) goto reject;
maxLength = ((128 - pupOvWords) - 3) << 1;
if (ccount > maxLength) {
ccount = maxLength;
core->count = Swab(maxLength);
};
caddr = Swab(core->addrlo);
cdata = &core->data[0];
cAdvice = Swab(core->advice);
if (dHost == 0) cAdvice &= 0x3fff;
core->advice = Swab(advice);
pupType = pup->type;
switch (pupType) {
case ELStateWrite:
case ELSingleStep:
case ELGoFromBreak:
if (dHost == 0) goto reject;
if (((int) caddr != 1) || (ccount != 28)) goto reject;
ByteBlt(mState, cdata, ccount);
case ELStateRead:
if ((int) caddr != 1) goto reject;
ByteBlt(cdata, mState, ccount);
pup->length = Swab((31 + ccount) & 0xfffe);
pup->type = pup->type + 1;
ReplyTo(cAdvice, pbi);
if (pupType == ELStateWrite) GoNormal();
if (pupType == ELGoFromBreak) GoFromBreak();
if (pupType == ELSingleStep) SingleStep();
goto ok;
case ELWrite:
if (dHost == 0) goto reject;
ByteBlt(caddr, cdata, ccount);
case ELRead:
if (Ugt(caddr, 0xffcf)) goto reject;
if (Ugt(ccount, 0xffd0 - ((int) caddr))) goto reject;
ByteBlt(cdata, caddr, ccount);
pup->length = Swab((31 + ccount) & 0xfffe);
pup->type = pup->type + 1;
ReplyTo(cAdvice, pbi);
goto ok;
case ELDebug: {
if (dHost != 0) CallDebugger(0xfffa);
goto reject;
};
case ELSWrite:
if (dHost == 0) goto reject;
SlaveBLT(caddr, cdata, ccount); /* how tell when it is done ? */
case ELSRead:
SlaveBLT(cdata, caddr, ccount);
pup->length = Swab((31 + ccount) & 0xfffe);
pup->type = pup->type + 1;
ReplyTo(cAdvice, pbi);
goto ok;
case ELCall:
CallPkt(cdata);
pup->type = pup->type + 1;
ReplyTo(cAdvice, pbi);
goto ok;
default: goto reject;
};
ok:
gotReply = true;
reject:
};
/* Call this routine with a filled in pup which came from the
right place.
*/
static ReplyTo(cAdvice, pbi)
int cAdvice;
struct PBI *pbi;
{
struct Pup *pup;
struct EtherEncapsulation *ee;
int temp;
if (cAdvice & 0x4000) advice = cAdvice & 0x3fff;
pup = pbi->pup;
temp = (int) pup;
temp -= 4;
ee = (struct EtherEncapsulation *) temp;
/* save Pup ID and source */
MoveBlock(tlID, &pup->id[0], 2);
if (cAdvice & 0x8000) {
tlNet = pup->sPort.net;
tlHost = pup->sPort.host;
tlImHost = ee->src;
};
/* always believe net we are told we are on */
if (pup->dPort.net != 0) localNet = pup->dPort.net;
/* Swap source and destination */
ee->dst = ee->src;
ee->src = EtherHost();
ee->type = 2;
SwapSourceAndDest(pup);
pup->transport = 0;
ReallySetCheckSum(pup);
SStartTx(pbi);
while (!SCheckTx(pbi)) CheckWDT();
};
SetCheckSum(pup)
int *pup;
/* struct Pup *pup; */
{
/*
pup->data.words[((Swab(pup->length)-pupOvBytes)+1)>>1] = -1;
*/
pup[((Swab(*pup) +1) >> 1) - 1] = -1;
};
CheckCheckSum(pup)
int *pup;
/* struct Pup *pup; */
{
int ck;
/*
ck = pup->data.words[((Swab(pup->length)-pupOvBytes)+1)>>1];
*/
ck = pup[((Swab(*pup) +1) >> 1) - 1];
if ((ck == -1) || (ck == CheckSum(pup))) return(true);
return(false);
};
ReallySetCheckSum(pup)
int *pup;
/* struct Pup *pup; */
{
/*
pup->data.words[((Swab(pup->length)-pupOvBytes)+1)>>1] = CheckSum(pup);
*/
pup[((Swab(*pup) +1) >> 1) - 1] = CheckSum(pup);
};
SwapSourceAndDest(pup)
struct Pup *pup;
{
int temp[3];
MoveBlock(temp, &pup->dPort, 3);
MoveBlock(&pup->dPort, &pup->sPort, 3);
MoveBlock(&pup->sPort, temp, 3);
};
FirstSendState()
{
gotReply = false;
stateInterval = 1000;
SendState();
};
CheckState()
{
if (gotReply) return;
if (TmrExp(&stateTimer)) {
if (stateInterval < 0) stateInterval = 1000;
if (stateInterval >= 5000) {
tlNet = 0;
tlHost = 0;
localNet = 0;
tlImHost = 0;
};
if (stateInterval < 30000) stateInterval += 1000;
SendState();
StartEL();
};
};
static SendState()
{
struct Pup *pup;
struct EtherEncapsulation *ee;
int temp;
struct Core *core;
SLCReset();
elPBI.pup = (struct Pup *) &elBuf[2];
pup = elPBI.pup;
temp = (int) pup;
temp -= 4;
ee = (struct EtherEncapsulation *) temp;
ee->src = tlImHost;
pup->sPort.net = tlNet;
pup->sPort.host = tlHost;
pup->dPort.net = localNet;
pup->dPort.host = EtherHost();
pup->sPort.socket.LS = pup->dPort.socket.LS = 0;
pup->sPort.socket.ms = pup->dPort.socket.ms = 0x3000;
pup->type = ELBooted;
DoubleIncrement(tlID, 1);
MoveBlock(&pup->id[0], tlID, 2);
core = (struct Core *) &pup->data;
core->count = Swab(38);
core->addrhi = 0;
core->addrlo = Swab(1);
ByteBlt(&core->data[0], mState, 48);
pup->length = Swab((31 + 48) & 0xfffe);
ReplyTo(false, &elPBI);
SetTmr(stateInterval, &stateTimer);
};
int *GetELBuf()
{
return(elBuf);
};
int *GetDebugPtrs()
{
return(&tlNet);
};
SlaveBLT(dest, src, count)
int dest, src, count;
{
StoreW(src, BltFrom);
StoreW(dest, BltTo);
/* works in words */
StoreW(count >> 1, BltCount);
StartSlave(4, 0);
SetTmr(count, &dest);
while (!TmrExp(&dest)) CheckWDT();
};
/* the packet data field contains
proc
nargs
arguments
first word past end is at cdata+4+(2*nargs)
*/
struct CPArgs {
int proc;
int nargs;
int returnSlot;
int args[5];
};
extern int stackLimit;
extern int monEnd;
CallPkt(cp)
struct CPArgs *cp;
{
int stklimit;
BlockSwab(cp, 8);
if (cp->nargs > 5) return;
stklimit = stackLimit;
stackLimit = (int) &monEnd;
stackLimit += 20;
cp->returnSlot = Apply(&cp->args[0], cp->proc, cp->nargs);
BlockSwab(cp, 8);
stackLimit = stklimit;
};
BlockSwab(ptr, count)
int *ptr, count;
{
int i;
for (i = 0; i < count; i += 1) ptr[i] = Swab(ptr[i]);
};