/* LarkMon.c
C monitor program for Lark
L. Stewart February 18, 1983 6:56 PM
L. Stewart February 23, 1983 3:16 PM, MainRet, ClockPtr
L. Stewart February 24, 1983 1:48 PM, StatePtr
L. Stewart February 24, 1983 1:48 PM, SetDebugHost
L. Stewart March 3, 1983 2:24 PM, WDTBoot InitAnalog
L. Stewart April 28, 1983 11:35 AM, open relays, persistant SendState, CallWithStack
*/
#include "Env.h"
#include "Lark.h"
#include "LarkNet.h"
/* machine language assist */
extern StartM(); /* execute using register save area */
extern int mState[15]; /* register save area */
extern int monRelays;
/* StartM saves regp->ip in lastIP before starting execution */
extern int lastIP;
/* The refresh interrupt handler watches for down transitions
of the NMI button. lastNMI holds the previous state.
*/
extern int lastNMI;
extern int bootSwitches;
extern int rtcLow;
/* other packages */
extern StoreB(); /* store(byte, address) */
extern SetTmr(); /* SetTmr(interval, &timer) */
extern TmrExp(); /* if (TmrExp(&timer)) { ... } */
extern KickWDT(); /* kick watchdog timer */
extern InitAnalog();
extern GetBootSwitches();
extern GetPIO();
/* TeleLoad package */
extern FirstSendState();
extern StartEL();
extern CheckEL();
extern int tlNet;
extern int tlHost;
extern int tlImHost;
extern int localNet;
struct regs {
int ax, bx, cx, dx;
int sp, bp, si, di;
int cs, ds, ss, es;
int ip, fl, why;
};
/* statics */
struct regs *regp; /* register save area */
int ssCount; /* number of tries at single stepping */
int breakSS; /* BOOLEAN -- proceeding from a breakpoint */
int wdtTimer; /* timer for scheduling WDT kicks */
#define RESET 0xffff
#define EXTINT 0xfffe
#define RUNERR 0xfffd
#define MONRET 0xfffc
#define SSFAIL 0xfffb
#define TeleBoot 0xfffa
#define MainRet 0xfff9
#define WDTBoot 0xfff8
#define Running 0xff00
#define TRACE 1
#define NMI 2
MonMain(why)
int why;
{
regp = (struct regs *) mState; /* use mstate later */
PokeWDT();
/* some reasons for booting require special treatment
most will just be reported to the debugging machine
*/
switch (why) {
case WDTBoot: { InitAnalog(); break; };
case RESET: { MonInit(); break; };
case TRACE: { MonTrace(); break; };
case NMI: { MonNMI(); break; };
};
/* save relay states in monRelays, then open relays */
monRelays = 0;
if (GetPIO(iapioa) & 0x0080) monRelays |= 8; /* revert */
if (!(GetPIO(iapioa) & 0x0040)) monRelays |= 4; /* off hook */
if (!(GetPIO(ipioc) & 0x0010)) monRelays |= 2; /* a relay */
if (GetPIO(ipioc) & 0x0020) monRelays |= 1; /* revert hs relay */
Revert(true);
RevertHS(true);
GoOffHook(false);
ARelay(false);
bootSwitches = GetBootSwitches();
FirstSendState();
StartEL();
for (;;) {
CheckState(); /* keep trying until get an answer */
CheckWDT();
CheckEL();
};
};
static MonInit()
{
InitAnalog();
/* this is super ugly */
tlHost = 0; /* broadcast */
tlNet = 0; /* local */
tlImHost = 0; /* broadcast */
localNet = 0; /* local */
};
/* There will need to be three ways to begin execution
1. normal resumption
2. single step
3. resumption from a breakpoint
However, resumption from a breakpoint could be omitted by having
the debug machine do the single step and then put the
breakpoint instruction back
*/
SingleStep()
{
regp->fl = regp->fl | 0x0100;
breakSS = 0;
ssCount = 0;
PokeWDT();
StartM();
};
GoNormal()
{
regp->fl = regp->fl & 0xfeff; /* clear single step */
breakSS = 0;
ssCount = 0;
PokeWDT();
StartM();
};
GoFromBreak()
{
regp->fl = regp->fl | 0x0100; /* set single step */
breakSS = -1;
ssCount = 0;
PokeWDT();
StartM();
};
/* the proper response to a breakpoint is to put back the
original instruction byte and back up IP by 1
*/
static MonTrace()
{
/* if an interrupt is pending at the time a single step is attempted
control will come here, but without executing the single-stepped
instruction.
We just keep trying for awhile.
*/
if (regp->ip == lastIP) {
if (ssCount >= 20) CRestart(SSFAIL);
ssCount = ssCount + 1;
StartM();
};
if (breakSS != 0) { /* proceeding from breakpoint */
StoreB(0xcc, lastIP); /* replace breakpoint */
regp->fl = regp->fl & 0xfeff; /* clear single step */
StartM(); /* continue */
};
};
static MonNMI()
{
/* wait for button to be released */
while(!(GetPIO(2) & 1)) CheckWDT();
lastNMI = 0;
};
/* Utilities */
PokeWDT()
{
KickWDT();
SetTmr(200, &wdtTimer);
};
CheckWDT()
{
if (TmrExp(&wdtTimer)) PokeWDT();
};