/* cmon.c
C monitor program for Lark
L. Stewart September 24, 1982 10:27 AM
L. Stewart December 2, 1982 7:55 PM, invert NMI I/O bit
*/
/* machine language assist */
extern setup(); /* setup I/O controllers. */
extern putchar(); /* put character to console */
extern putcrchar(); /* put character to console */
extern getchar(); /* return character from console */
extern chav(); /* returns true if getchar won't block */
extern outbyte(); /* outbyte(port, byte) */
extern inbyte(); /* read byte from io device */
extern fetchb(); /* return byte at address */
extern storeb(); /* store(byte, address) */
extern portstr(); /* load IO registers from command string */
/* monitor machine language assist */
extern dump();
/*
extern tslc();
*/
extern startm(); /* execute using register save area */
extern int mstate[14]; /* register save area */
extern int lip;
extern int lnmi;
extern int eitype;
/* c runtime library */
extern int isdigit(); /* is character IN [0..9] */
extern lc(); /* lower case */
extern int eqstr(); /* case-insensitive string matcher */
extern wf();
extern wfcr();
extern wf1();
extern wf2();
extern ssenable();
extern ssreturn();
/* other packages */
extern InitAnalog();
extern GetPIO();
extern int stframe;
extern int stbyte;
extern loadhex();
/*
extern setspeed();
*/
extern int cmklo;
extern int cmkhi;
/* statics */
char cmd;
char leftover;
int any;
int mlerr[3];
int result;
char *rnary[14];
/* breakpoint */
int brkadr;
char brkcb;
int sscount;
int audb;
struct regs {
int ax, bx, cx, dx;
int sp, bp, si, di;
int cs, ds, ss, es;
int ip, fl;
};
struct regs *regp;
#define RESET 255
#define BREAK 3
#define TRACE 1
#define NMI 2
#define DIVERR 0
#define OVERR 4
#define EXTINT 254
main(why)
int why;
{
/* execution comes here on system reset with why=0 */
switch (why) {
case BREAK: { monbrk(); break; };
case TRACE: { montr(); break; };
case NMI: { monnmi(); break; };
case DIVERR: { monde(); break; };
case OVERR: { monov(); break; };
case EXTINT: { monei(); break; };
default: { moninit(); break; };
};
regp = (struct regs *) mstate; /* use mstate later */
/* we use NMI for refresh, and the nmi pushbutton is
connected to a parallel port bit, which refresh tests */
/* (someday) */
for (;;) {
result = ssenable(mlerr);
if (result) wf(" ##\r");
wf("% ");
StartEL();
cmd = lc(getchar());
switch (cmd) {
case 'a': { togaudio(); break; };
case 'b': { setbrk(); break; };
case 'c': { clock(); break; };
case 'd': { dump(0); break; };
case 'e': { elcmd(); break; };
case 'f': { TraceStack(regp->bp); break; };
case 'g': { gocmd(); break; };
case 'i': { incmd(); break; };
case 'n': { sscount = 0; sings(); break; };
case 'o': { outcmd(); break; };
case 'r': { readcmd(); break; };
case 's': { subst(); break; };
case 't': { tslc(); break; };
case 'w': { dump(1); break; };
case 'x': { regcmd(); break; };
default: { unknown(); break; };
};
};
};
moninit()
{
setup(); /* start refresh, in particular */
datainit(); /* register names */
InitAnalog();
wf("Lark Monitor\r");
testbrk();
brkadr = 0; /* no breakpoint set */
audb = 0;
};
monbrk()
{
wf1("\r Break at %04x\r", regp->ip-1);
if (regp->ip != brkadr+1) wf("unknown breakpoint!\r");
else { /* put back code byte and back up ip */
storeb(brkcb, brkadr);
regp->ip = brkadr;
};
};
montr()
{
if (brkadr) { /* proceeding from breakpoint */
storeb(0xcc, brkadr); /* replace breakpoint */
regp->fl = regp->fl & 0xfeff;
startm(); /* continue */
};
if ((sscount < 20) && (regp->ip == lip)) {
sscount = sscount + 1;
sings();
};
wf1(" ss at %04x", regp->ip);
if (sscount > 1) wf1(", %d tries", sscount);
wfcr();
};
monnmi()
{
wf1("\rNMI at %04x\r", regp->ip);
while(!(GetPIO(2) & 1));
lnmi = 0;
};
monov()
{
wf1("\rOverflow at %04x\r", regp->ip);
};
monei()
{
wf1("\rExternal interrupt, type %x\r", eitype);
};
monde()
{
wf1("\rDivide Error at %04x\r", regp->ip);
};
setbrk()
{
int new;
testbrk();
wf("Break at: ");
brkadr = gethex();
innew('\r');
testbrk();
};
testbrk()
{
if (brkadr != 0 && fetchb(brkadr) == 0xcc)
wf2("\r breakpoint at %04x! code might be %02x\r", brkadr, brkcb);
};
clock()
{
wf2("Clock = %04x%04x\r", cmkhi, cmklo);
};
elcmd()
{
wf1("EtherLoad, host %02x\r", GetPIO(1) & 0xff);
StartEL();
};
readcmd()
{
putchar('R');
loadhex();
regp->cs = stframe;
regp->ip = stbyte;
wfcr();
};
sings() /* single step */
{
testbrk();
brkadr = 0;
regp->fl = regp->fl | 0x0100;
startm();
};
gocmd()
{
wf("GO!\r");
regp->fl = regp->fl & 0xfeff; /* clear single step */
if (brkadr) {
testbrk();
brkcb = fetchb(brkadr);
if (brkadr == regp->ip) regp->fl = regp->fl | 0x0100;
else storeb(0xcc, brkadr);
};
startm();
};
unknown()
{
wf(" ??\r");
};
mlabort()
{
ssreturn(mlerr, 1);
};
debug(s)
char *s;
{
wf1("\rDebug: %s\r", s);
mlabort();
};
int innewp(c) /* invalid number not ending with */
char c;
{
if (!any || leftover != c) return(1);
return(0);
};
innew(c)
char c;
{
if (innewp(c)) mlabort();
};
regcmd()
{
int i;
char name[3];
name[2] = 0;
putchar('X');
name[0] = egetchar();
if (leftover == '\r') { printregs(); return; };
name[1] = egetchar();
for (i = 0; i < 14; i += 1)
if (eqstr(rnary[i], name)) { modreg(i); return; };
mlabort();
};
modreg(i)
int i;
{
int newval;
wf1("=%04x -", mstate[i]);
newval = gethex();
innew('\r');
mstate[i] = newval;
};
printregs()
{
prseven(0);
prseven(7);
};
prseven(start)
int start;
{
int i;
for (i = start; i < (start+7); i += 1) printreg(i);
wfcr();
};
printreg(i)
int i;
{
wf2(" %s=%04x", rnary[i], mstate[i]);
};
incmd()
{
int port;
int first;
putchar('I');
first = 1;
port = gethex();
if (!any) mlabort()
for (;;) {
if (!first && innewp(',')) break;
wf1("\r%02x", inbyte(port));
if (leftover=='\r') break;
first = 0;
egetchar();
};
if (first && (leftover=='\r')) wfcr();
};
int egetchar() /* getchar with echo */
{
leftover = getchar() & 0177;
putcrchar(leftover);
if (leftover == 0177) mlabort();
return(leftover);
};
outcmd()
{
int port, val;
putchar('O');
port = gethex();
innew(',');
for (;;) {
val = gethex();
if (innewp(',') && innewp('\r')) mlabort();
outbyte(port, val)
if (leftover == '\r') break;
wf("\r- ");
};
};
subst()
{
int adr, val;
putchar('S');
adr = gethex();
if (innewp(',')) return;
for (;;) {
val = fetchb(adr);
wf1(" %02x- ", val);
val = gethex();
if (leftover != ',' && leftover != '\r') mlabort();
if (any) storeb(val, adr);
adr += 1;
if (leftover == '\r') return;
else wfcr();
wf1("%04x- ", adr);
};
};
int gethex()
{
int v;
v = 0;
any = 0;
for (;;) {
egetchar();
if (isdigit(leftover)) {
v = (v<<4);
v += (leftover-'0');
any = 1;
continue;
};
leftover = lc(leftover);
if (leftover>='a' && leftover<='f') {
v = (v<<4);
v += (leftover-'a'+10);
any = 1;
continue;
};
break;
};
return(v);
};
datainit()
{
rnary[0] = "AX";
rnary[1] = "BX";
rnary[2] = "CX";
rnary[3] = "DX";
rnary[4] = "SP";
rnary[5] = "BP";
rnary[6] = "SI";
rnary[7] = "DI";
rnary[8] = "CS";
rnary[9] = "DS";
rnary[10] = "SS";
rnary[11] = "ES";
rnary[12] = "IP";
rnary[13] = "FL";
};