/* 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(); };