/*
   ============================================================================
	romp.c -- ROMP debug monitor
	(c) Copyright 1987,1988 -- D.N. Lynx Crowe

	See ROMPVER, below, for version number and date.

	CAUTION:  This code is designed to live in PROM, so initialized
	variables are PERMANENTLY initialized, since the compiler assigns
	initialized variables to the data segment, which ends up in PROM.

	Un-initialized variables go into the bss segment, which ends up in RAM.

	Set ON_B700 non-zero to get a Buchla 700 PROM,
	or zero to get a NASA 3D Helmet Display PROM.
   ============================================================================
*/

#define	ROMPVER	"22.00 -- 1988-06-20"

#define	TINYMSG	0	/* 1 for short messages, 0 for normal ones */

#define	ON_B700	1	/* 1 for Buchla 700, 0 for NASA */
#define	ONEMEG	1	/* 1 if 1024K, 0 if 512K RAM space (Buchla 700) */

#include "rom.h"

#if	ON_B700
#define	USER_RAM	0x00010000L	/* Start of user RAM  (TPA) */
#if	ONEMEG
#define	RAM_TOP		0x000FFFFEL	/* Default top word of memory */
#define	ISTACK		0x000FFFFEL	/* Default initial stack */
#else
#define	RAM_TOP		0x0007FFFEL	/* Default top word of memory */
#define	ISTACK		0x0007FFFEL	/* Default initial stack */
#endif
#define	KB_EI		2		/* Enable level for panel */
#define	DEFIPL		2		/* Default internal processor level */
#define	INITSR		0x2200		/* Default initial status register */
#define	BOOTFILE	"midas.abs"	/* Boot file name */
#define	BOOTKEY		39		/* Boot panel key */
#define	ROMPKEY		40		/* ROMP panel key */
#define	FIFOLIM		60000		/* FIFO clear limit */
#define	I_TABX		53		/* Tablet X */
#define	I_TABY		54		/* Tablet Y */
#define	I_CURX		55		/* Cursor X */
#define	I_CURY		56		/* Cursor Y */
#define	I_LONGL		57		/* LongPot Left */
#define	I_LONGR		58		/* LongPot Right */
#define	I_SCROLL	59		/* Scroll */
#define	I_TEMPO		73		/* Tempo Multiplier */
#define	I_TIME		74		/* Time Scaling */
#define	I_TUNE		75		/* Fine Tuning */
#define	I_LEVEL		76		/* Amplitude */
#define	BARBASE		5120L		/* Base of bars in VSDD RAM */
#define	SWBASE		38400L		/* Base of switches in VSDD RAM */
#define	MARGIN		4		/* Offset from left edge of screen */
#else
#define	DEFIPL		3
#define	USER_RAM	0x00008000L
#define	RAM_TOP		0x0001FFFEL
#define	ISTACK		0x0001FFFEL
#define	INITSR		0x2300
#endif

#define	ROMADDR		0x00100000L

#define	PRM_DATE	0x0100008L
#define	PRM_VERS	0x0100002L

#define	BPINST	0x4E4F		/* breakpoint instruction */

#define	CRLF	"\r\n"

#define	TACK	"K\r"		/* good response from load command */
#define	NACK	"?\r"		/* bad response from load command */

#define	SREC9	"04000000FB"	/* tail of a type 9 Motorola S-Record */

#define	MON_C	1		/* monitor character code */
#define	MON_S	2		/* monitor short code */
#define	MON_L	4		/* monitor long code */

/*
   ============================================================================
	error message string definitions
   ============================================================================
*/

#define	EMSG1	"\r\n** Command error **\r\n"
#define	EMSG2	"\r\n** Invalid parameter **\r\n"
#define	EMSG3	"\r\n** Unrecognized command **\r\n"

#define	EMSG5	"\r\n** Command not repeatable **\r\n"
#define EMSG6	"\r\n** Invalid line terminator **\r\n"
#define EMSG7	"\r\n** do_cmd() switch failed **\r\n"

#define	CANNED	"\r\n----- Cancelled -----\r\n"

/*
   ============================================================================
	initialized variables  (These end up in the data segment in PROM)
   ============================================================================
*/

struct cmdent {			/* command table entry */

	int8_t	*cname;		/* command name pointer */
	int16_t	(*cp)(void);	/* command parser function pointer */
	int16_t	(*cx)(void);	/* command execution function pointer */
	int8_t	*hstr;		/* help string pointer */
};

static	struct cmdent	cmtab[] = {

#if	ON_B700
	{"adisp",	cp_null,	cx_adsp,	""},
	{"boot",	cp_boot,	cx_boot,	""},
	{"bpb",		cp_null,	cx_bpb,		""},
#endif

	{"check",	cp_chek,	cx_chek,	"start,end"},
	{"copy",	cp_copy,	cx_copy,	"from,to,len"},

#if	ON_B700
	{"crash",	cp_null,	cx_crsh,	""},
	{"dinit",	cp_null,	cx_dini,	""},
#endif

	{"dump",	cp_dump,	cx_dump,	"from[,[to=from][,width=16]]"},
	{"exit",	cp_null,	cx_exit,	""},
	{"fill",	cp_fill,	cx_fill,	"loc,count,byte"},
	{"go",		cp_go,		cx_go,		"[addr][,[brk1][,brk2]]"},
	{"help",	cp_null,	cx_help,	""},
	{"ipl",		cp_ilev,	cx_ilev,	"level"},
	{"ldump",	cp_ldmp,	cx_ldmp,	"from[,[to=from][,width=4]]"},
	{"load",	cp_null,	cx_load,	""},	

#if	ON_B700
	{"midas",	cp_null,	cx_mlod,	""},
#endif

	{"monc",	cp_monc,	cx_mon,		"addr"},
	{"mons",	cp_mons,	cx_mon,		"addr"},
	{"monl",	cp_monl,	cx_mon,		"addr"},
	{"mset",	cp_mset,	cx_mset,	"addr,b1[,...,bn]"},
	{"mtest",	cp_mtst,	cx_mtst,	hs_mtst},
	{"next",	cp_null,	cx_next,	""},
	{"obmap",	cp_null,	cx_omap,	""},

#if	ON_B700
	{"read",	cp_read,	cx_read,	"sector,buffer,count"},
#endif

	{"regs",	cp_null,	cx_regs,	""},
	{"reset",	cp_null,	cx_rest,	""},
	{"rset",	cp_rset,	cx_rset,	"register,value"},
	{"vregs",	cp_null,	cx_vreg,	""},
	{"vrset",	cp_vrst,	cx_vrst,	"register,value"},
	{"wdump",	cp_wdmp,	cx_wdmp,	"from[,[to=from][,width=8]]"},
	{"wfill",	cp_wfil,	cx_wfil,	"loc,count,word"},

#if	ON_B700
	{"write",	cp_read,	cx_writ,	"sector,buffer,count"},
#endif

	{"wset",	cp_wset,	cx_wset,	"addr,w1[,...,wn]"},
	{"zap",		cp_null,	cx_zap,		""}
};

#define	NCMDS	((sizeof cmtab) / (sizeof cmtab[0]))

int8_t	ahex[] = "0123456789abcdefABCDEF";

int8_t	*rlist[] = {		/* register name list */

	"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
	"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
	"sr", "pc", "sp",
	(int8_t *)0
};

int8_t	*vrlist[] = {		/* video register name list */

	"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
	"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
	"h0", "h1", "h2", "h3", "v0", "v1", "v2", "v3",
	(int8_t *)0
};

#if	ON_B700
int16_t	sigadr[] = {		/* display offsets for signals */

	 0,  0,  0,  0,  0,   1,  1,  1,  1,  1,		/* keys	     */
	 2,  2,  2,  2,  2,   3,  3,  3,  3,  3,
	 4,  4,  4,  4,
	 7,  7,  7,  7,  7,   8,  8,  8,  8,  8,		/* sliders   */
	 9,  9,  9,  9,
	12, 12, 12, 12, 12,  13, 13, 13, 13, 13,		/* switches  */
	14, 14, 14, 14,
	17, 17,							/* tablet    */
	20, 20,							/* cursor    */
	23, 23,							/* longpot   */
	26,							/* scrollpot */
	29, 29, 29, 29, 29,  30, 30, 30, 30, 30,		/* digits    */
	32, 32, 32,						/* x, e, m   */
	35, 35, 35, 35,						/* pots      */
	37, 37,							/* pedals    */
	39, 39, 39, 39						/* analog in */
};
#endif

/*
   ============================================================================
	un-initialized variables  (These end up in the bss segment in RAM)
   ============================================================================
*/

int8_t	argsep;		/* argument separator */

int8_t	*aptr,		/* argument pointer */
	*monptr,	/* monitored variable pointer */
	*d_cur,		/* dump current from */
	*d_next,	/* dump next from */
	*d_last,	/* dump next to */
	*p_end,		/* end parameter */
	*p_from,	/* from parameter */
	*p_to,		/* to parameter */
	*sptr;		/* string scan pointer */

int16_t	argln,		/* argument length */
	b0flag,		/* breakpoint 0 flag */
	b1flag,		/* breakpoint 1 flag */
	cmdunit,	/* command unit */
	dflag,		/* dump limit flag */
	exflag,		/* exit do_cmd flag */
	first1,		/* first time flag */
	goflag,		/* pc set flag */
	ilast,		/* index of last command */
	inext,		/* command index for "next" command */
	iplev,		/* ROMP IPL level */
	monsw,		/* monitor switch */
	redo,		/* re-doable command flag */
	rnum,		/* register number */
	vrnum;		/* video register number */

#if	ON_B700
int16_t	asig,		/* signal number */
	aval,		/* signal value */
	astat,		/* signal status */
	aflag,		/* signal activity flag */
	baseled,	/* base LED for scan */
	ledcntr;	/* LED scan counter */

int16_t	sigtab[128][2];	/* signal table */

int32_t	afi,		/* analog FIFO input */
	ftimer;		/* analog FIFO clear timer */

uint16_t	baron,		/* bar 'on' color */
		baroff,		/* bar 'off' color */
		swon,		/* switch 'on' color */
		swoff;		/* switch 'off' color */

volatile 	uint16_t	*obj0;	/* object pointer */
#endif

uint16_t	*tba0,		/* breakpoint 0 temporary */
		*tba1;		/* breakpoint 1 temporary */

uint16_t	p_bv0,		/* breakpoint 0 value */
		p_bv1;		/* breakpoint 1 value */

uint16_t	*p_ba0,		/* breakpoint 0 address */
		*p_ba1;		/* breakpoint 1 address */

jmp_buf	restart;	/* jmp environment */

int32_t	p_goto,		/* goto parameter */
	p_len,		/* length parameter */
	p_value,	/* value parameter */
	p_width;	/* width parameter */

struct	regs	*regptr;	/* register save area pointer */

int8_t	argstr[MAXARGLN+1],	/* argument string */
	cmdline[MAXCMDLN+1],	/* command line */
	bfname[MAXFNLN+1],	/* boot file name */
	hs_mtst[MAXHS+1],	/* mtest help string */
	idbuf[MAXID+1],		/* ID string */
	promdate[PDATELN+1];	/* PROM date area */

/*
   ============================================================================
	cx_exit -- restart ROMP
   ============================================================================
*/

int16_t cx_exit(void)
{
	longjmp(&restart, 1);		/* restart ROMP */
	return(TRUE);			/* not reached */
}

/*
   ============================================================================
	cx_rest -- execute the reset command
   ============================================================================
*/

int16_t cx_rest(void)
{
	rjumpto((void *)ROMADDR);
	return(TRUE);			/* not reached */
}

/*
   ============================================================================
	cx_mlod() -- execute the midas command
   ============================================================================
*/

int16_t cx_mlod(void)
{
	register int16_t i;

	B_log_s = TRUE;
	B_dbg_s = FALSE;
	redo = FALSE;

	hdvini();
	_bpbin = FALSE;

	if (booter("midas.abs", 0L)) {

		return(FALSE);

	} else {

		for (i = 0; i < 8; i++)			/* clear d0..d7 */
			regptr->d_reg[i] = 0L;

		for (i = 0; i < 7; i++)			/* clear a0..a6 */
			regptr->a_reg[i] = 0L;

		regptr->a_reg[7] = ISTACK;		/* setup initial stack */

		regptr->reg_sr = INITSR;		/* setup sr */
		regptr->reg_pc = (uint32_t)B_buf_a;	/* setup pc */

		return(TRUE);
	}
}

/*
   ============================================================================
	cp_boot() -- parse boot command
   ============================================================================
*/

int16_t cp_boot(void)
{
	register int16_t i;
	register int8_t endc;

	redo = FALSE;

	for (;;) {

		writeln(cmdunit, "File name: ");
		endc = (int8_t)getln(cmdunit, MAXFNLN+1, bfname);
		writeln(cmdunit, CRLF);

		if (endc EQ A_CR)
			break;

		if (endc EQ CTL('X')) {

			writeln(cmdunit, CANNED);
			return(FALSE);
		}

		if (endc EQ ERR01)
			writeln(cmdunit, EMSG2);
	}

	for (i = 0; i < MAXFNLN+1; i++)
		if (bfname[i] EQ A_CR)
			bfname[i] = '\0';
	
	return(TRUE);
}

/*
   ============================================================================
	cx_boot() -- execute boot command
   ============================================================================
*/

int16_t cx_boot(void)
{
	register int16_t i;

	B_log_s = TRUE;
	B_dbg_s = FALSE;

	hdvini();
	_bpbin = FALSE;

	if (booter(bfname, 0L)) {

		return(FALSE);

	} else {

		for (i = 0; i < 8; i++)			/* clear d0..d7 */
			regptr->d_reg[i] = 0L;

		for (i = 0; i < 7; i++)			/* clear a0..a6 */
			regptr->a_reg[i] = 0L;

		regptr->a_reg[7] = ISTACK;		/* setup initial stack */

		regptr->reg_sr = INITSR;		/* setup sr */
		regptr->reg_pc = (uint32_t)B_buf_a;	/* setup pc */

		return(TRUE);
	}
}

/*
   =============================================================================
	dobar(nb, bv) -- draw bar 'nb' with value 'bv'
   =============================================================================
*/

void dobar(int16_t nb, int16_t bv)
{
	volatile uint16_t *bp;
	int16_t i;

	if ((nb LT 1) OR (nb GT 82))
		return;

	--nb;
	bp = obj0 + BARBASE + (int32_t)(sigadr[nb] + MARGIN + nb);

	for (i = 127; i GE 0; --i) {

		if (i GT bv) {

			*bp = baroff;
			bp += 128L;
			*bp = baroff;

		} else {

			*bp = baron;
			bp += 128L;
			*bp = baron;
		}

		bp += 128L;
	}
}

/*
   =============================================================================
	dosw(nb, sv) -- display value 'sv' of switch 'nb'
   =============================================================================
*/

void dosw(int16_t nb, int16_t sv)
{
	volatile uint16_t *bp;
	uint16_t j;
	int16_t i;

	if ((nb LT 1) OR (nb GT 82))
		return;

	--nb;
	bp = obj0 + SWBASE + (int32_t)(sigadr[nb] + MARGIN + nb);

	if (sv)
		j = swon;
	else
		j = swoff;

	for (i = 0; i < 8; i++) {

		*bp = j;
		bp += 128L;
	}
}

/*
   =============================================================================
	exp_c() -- expand a 4 bit color into a 16 bit word
   =============================================================================
*/

uint16_t exp_c(int16_t c)
{
	uint16_t r;

	r = (uint16_t)c & 0x000F;
	r |= r << 4;
	r |= r << 8;

	return(r);
}

/*
   =============================================================================
	cx_adsp() -- display values of analog processor variables as a bar graph
   =============================================================================
*/

int16_t cx_adsp(void)
{
	int16_t xasig, xastat, xaval;
	int32_t xafi;
	int32_t lc;
	volatile uint16_t *bp;
	int16_t	i, j, k;
	int16_t	oldi;

	memsetw(sigtab, 0, sizeof sigtab / 2);

	VHinit();
	VSinit();
	vsndpal(dfltpal);

	obj0 = (volatile uint16_t *)0x200400L;

	SetObj(0, 0, 0, obj0, 512, 350, 0, 0, (V_RES3 | V_TDE), -1);

	bp = obj0;
	
	for (lc = 0; lc < 44800; lc++)
		*bp++ = 0x0000;

	baron  = 0x0FFF & exp_c(P_WHT);
	baroff = 0x0FFF & exp_c(P_DKGRY);
	swon   = 0x0FFF & exp_c(P_YEL);
	swoff  = 0x0FFF & exp_c(P_DKGRY);

	SetPri(0, 7);

	for (i = 1; i < 83; i++) {

		dobar(i, 0);
		dosw(i, 0);
	}

	oldi = setipl(2);

	while (0L EQ BIOS(B_RDAV, CON_DEV)) {

		if (-1L NE (xafi = XBIOS(X_ANALOG))) {

			xasig  = 0x007F & (xafi >> 8);
			xastat = 0x0001 & (xafi >> 7);
			xaval  = 0x007F & xafi;

			if (xasig) {

				sigtab[xasig][0] = xaval;
				sigtab[xasig][1] = xastat;

				if (xasig LT 83) {

					dobar(xasig, xaval);
					dosw(xasig, xastat);
				}

			} else {

				for (i = 0; i < 83; i++)
					sigtab[i][1] = 0;
			}
		}
	}

	BIOS(B_GETC, CON_DEV);

	for (j = 1; j < 83; j++) {

		dobar(j, sigtab[j][0]);
		dosw(j, sigtab[j][1]);
	}

	k = 0;

	printf("\n");
	printf("       x0     x1     x2     x3     x4     x5     x6     x7     x8     x9\r\n");
	printf("     -----  -----  -----  -----  -----  -----  -----  -----  -----  -----\r\n");
			
	for (i = 0; i < 9; i++ ) {

		printf("%01dx   ", k/10);

		for (j = 0; j < 10; j++) {

			if (k)
				printf("%1d:%3d  ", sigtab[k][1], sigtab[k][0]);
			else
				printf("       ");

			if (++k EQ 83)
				goto outofit;
		}

		printf("\n");
	}

outofit:

	printf("\nTempo     = %3d,  Time      = %3d,  Tuning = %3d,  Level = %3d\n",
		sigtab[I_TEMPO][0], sigtab[I_TIME][0],
		sigtab[I_TUNE][0], sigtab[I_LEVEL][0]);

	printf("LongPot L = %3d,  LongPot R = %3d,  Scroll = %3d\n",
		sigtab[I_LONGL][0], sigtab[I_LONGR][0],
		sigtab[I_SCROLL][0]);

	printf("Tablet X  = %3d,  Tablet Y  = %3d\n",
		sigtab[I_TABX][0], sigtab[I_TABY][0]);

	printf("Cursor X  = %3d,  Cursor Y  = %3d\n",
		sigtab[I_CURX][0], sigtab[I_CURY][0]);

	setipl(oldi);
	return(TRUE);
}

/*
   =============================================================================
	waitcr2() -- wait for a CR from CON_DEV
		Returns:	0 = continue
				1 = ^G hit - abort
   =============================================================================
*/

int16_t waitcr2(void)
{
	int8_t	c;

	BIOS(B_PUTC, CON_DEV, '\007');

	while ('\r' NE (c = (0x7F & BIOS(B_GETC, CON_DEV)))) {

		if (c EQ '\007')
			return(1);
	}

	return(0);
}

/*
   ============================================================================
	xdtoi -- convert hex ASCII to an int digit
   ============================================================================
*/

int16_t xdtoi(int16_t c)
{
	register int16_t i;
	register int8_t *ap = &ahex[0];

	for (i = 0; i < 22; i++)
		if (c EQ *ap++) {
			if (i >15)
				return(i - 6);
			else
				return(i);
		}

	return(-1);
}

/*
   ============================================================================
	getcmd -- parse command from input line
   ============================================================================
*/

int16_t getcmd(void)
{
	register int16_t c;

	sptr = cmdline;
	argln = 0;
	aptr = argstr;
	memset(argstr, 0, MAXARGLN+1);

	do {

		switch (c = 0x00FF & *sptr) {

		case '\0':
		case A_CR:
		case A_LF:

			argsep = (int8_t)c;
			return(argln);

		case ' ':

			++sptr;

			while (*sptr EQ ' ')
				++sptr;

			if (*sptr EQ A_CR OR *sptr EQ A_LF OR *sptr EQ '\0')
				c = 0x00FF & *sptr;

			argsep = (int8_t)c;
			return(argln);

		default:

			if (isupper(c))
				c = _tolower(c);

			*aptr++ = (int8_t)c;
			++sptr;
			++argln;
		}

	} while (*sptr);

	argsep = 0;
	return(argln);
}

/*
   ============================================================================
	getarg -- parse out an argument to analyze
   ============================================================================
*/

int16_t getarg(void)
{
	register int16_t c;

	argln = 0;
	aptr = argstr;
	memset(argstr, 0, MAXARGLN+1);

	do {

		switch (c = 0x00FF & *sptr) {

		case '\0':
		case A_CR:
		case A_LF:

			argsep = (int8_t)c;
			return(argln);

		case ' ':

			++sptr;

			while (*sptr EQ ' ')
				++sptr;

			if (*sptr EQ A_CR OR *sptr EQ A_LF OR *sptr EQ '\0')
				c = 0x00FF & *sptr;

			argsep = (int8_t)c;
			return(argln);

		case ',':

			++sptr;
			argsep = (int8_t)c;
			return(argln);

		default:

			*aptr++ = (int8_t)c;
			++sptr;
			++argln;
		}

	} while (*sptr);

	argsep = 0;
	return(argln);
}

/*
   ============================================================================
	getlong -- get a long integer (either hex or decimal)
   ============================================================================
*/

int16_t getlong(int32_t *var)
{
	register int32_t	temp = 0L;
	register int16_t 	csw = FALSE,
			c;

	if (*aptr EQ '$') {

		++aptr;

		while (isxdigit(c = *aptr++)) {

			temp = (temp << 4) + xdtoi(c);
			csw = TRUE;
		}

	} else {

		while (isdigit(c = *aptr++)) {

			temp = (temp * 10) + (c - '0');
			csw = TRUE;
		}
	}

	if (csw)
		*var = temp;

	return(c);
}

/*
   ============================================================================
	setvar -- parse an expression and set a long variable
   ============================================================================
*/

int16_t setvar(int32_t *var, int32_t deflt)
{
	int16_t rc;
	int32_t temp;

	*var = deflt;
	aptr = argstr;

	rc = getlong(var);

	if (rc) {

		do {

			switch (rc) {

			case '+':

				temp = 0L;
				rc = getlong(&temp);
				*var = *var + temp;
				continue;

			case '-':

				temp = 0L;
				rc = getlong(&temp);
				*var = *var - temp;
				continue;

			default:

				*var = deflt;
				return(FALSE);
			}

		} while (rc);

		return(TRUE);
	}

	return(TRUE);
}

/*
   ============================================================================
	setp -- parse an expression and set a pointer variable
   ============================================================================
*/

int16_t setp(void *var, void *deflt)
{
	return setvar((int32_t *)var, (int32_t)deflt);
}

/*
   ============================================================================
	putn -- output a decimal number
   ============================================================================
*/

void putn(uint32_t num, int16_t cw, int16_t unit)
{
	register int16_t	d;

	if (!cw)
		return;

	putn(num/10, cw-1, unit);

	d =  (int16_t)(num % 10);

	BIOS(B_PUTC, unit, (d + '0'));	

	return;
}

/*
   ============================================================================
	puthn -- output a hex number
   ============================================================================
*/

void puthn(uint32_t num, int16_t cw, int16_t unit)
{
	register int16_t	d;

	if (!cw)
		return;

	puthn(num >> 4, cw-1, unit);

	d = 0x0F & num;

	if (d > 9)
		BIOS(B_PUTC, unit, (d - 10 + 'A'));
	else
		BIOS(B_PUTC, unit, (d + '0'));	

	return;
}

/*
   ============================================================================
	ddump -- do the hex portion of a dump
   ============================================================================
*/

int16_t ddump(int8_t *loc, int8_t *lastloc, int16_t nwide, int16_t unit)
{
	while (nwide--) {

		puthn((uint32_t)(0xFF & *loc), 2, unit);
		BIOS(B_PUTC, unit, ' ');

		if (BIOS(B_RDAV, unit)) {

			BIOS(B_GETC, unit);
			return(TRUE);
		}

		if (loc EQ lastloc) {

			dflag = TRUE;
			return(FALSE);
		}

		++loc;
	}


	return(FALSE);
}

/*
   ============================================================================
	padr -- print dump address
   ============================================================================
*/

void padr(void *adr, int16_t unit)
{
	puthn((uint32_t)adr, 8, unit);
	BIOS(B_PUTC, unit, ' ');
	BIOS(B_PUTC, unit, '-');
	BIOS(B_PUTC, unit, ' ');
}

/*
   ============================================================================
	dtext -- do the text portion of a dump
   ============================================================================
*/

int16_t dtext(int8_t *loc, int8_t *lastloc, int16_t nwide, int16_t unit)
{
	register int16_t c;

	BIOS(B_PUTC, unit, ' ');
	BIOS(B_PUTC, unit, '|');

	while (nwide--) {

		c = 0xFF & *loc;

		if (isascii(c) AND isprint(c))
			BIOS(B_PUTC, unit, c);
		else
			BIOS(B_PUTC, unit, '.');

		if (BIOS(B_RDAV, unit)) {

			BIOS(B_GETC, unit);
			BIOS(B_PUTC, unit, '|');
			return(TRUE);
		}

		if (loc EQ lastloc) {

			BIOS(B_PUTC, unit, '|');
			return(FALSE);
		}

		++loc;
	}

	BIOS(B_PUTC, unit, '|');
	return(FALSE);
}

/*
   ============================================================================
	cp_mset -- parse parameters for mset command
   ============================================================================
*/

int16_t cp_mset(void)
{
	redo = FALSE;

	if (0 EQ getarg())
		return(FALSE);

	if (argsep NE ',')
		return(FALSE);

	if (setp(&p_from, p_from) EQ FALSE)
		return(FALSE);

	return(TRUE);
}

/*
   ============================================================================
	cx_mset -- execute the mset command
   ============================================================================
*/

int16_t cx_mset(void)
{
	while (TRUE) {

		if (getarg())
			if (setvar(&p_value, p_value) EQ FALSE)
				return(FALSE);

		if (p_value & ~0xFFL)
			return(FALSE);

		*p_from++ = (int8_t)(0xFF & p_value);

		if (argsep EQ A_CR)
			return(TRUE);
	}
}

/*
   ============================================================================
	cp_wset -- parse parameters for wset command
   ============================================================================
*/

int16_t cp_wset(void)
{
	redo = FALSE;

	if (0 EQ getarg())
		return(FALSE);

	if (argsep NE ',')
		return(FALSE);

	if (setp(&p_from, p_from) EQ FALSE)
		return(FALSE);

	if ((int32_t)p_from & 1L)
		return(FALSE);

	return(TRUE);
}

/*
   ============================================================================
	cx_wset -- execute the wset command
   ============================================================================
*/

int16_t cx_wset(void)
{
	uint16_t	*p_uint;

	p_uint = (uint16_t *)p_from;

	while (TRUE) {

		if (getarg())
			if (setvar(&p_value, p_value) EQ FALSE)
				return(FALSE);

		if (p_value & ~0xFFFFL)
			return(FALSE);

		*p_uint++ = (uint16_t)(0xFFFF & p_value);

		if (argsep EQ A_CR)
			return(TRUE);
	}
}

/*
   ============================================================================
	cp_mtst -- parse mtest command arguments
   ============================================================================
*/

int16_t cp_mtst(void)
{
	inext = ilast;

	if (argsep EQ A_CR OR argsep EQ '\0') {

		p_from = (int8_t *)0x00000008L;
		p_to   = (int8_t *)USER_RAM - 2L;
		return(TRUE);
	}

	if (getarg())
		if (setp(&p_from, (int8_t *)USER_RAM) EQ FALSE)
			return(FALSE);

	if (argsep NE ',')
		return(FALSE);

	if (getarg())
		if (setp(&p_to, (int8_t *)RAM_TOP) EQ FALSE)
			return(FALSE);

	if ((int32_t)p_from & 1L)
		return(FALSE);

	if ((int32_t)p_to & 1L)
		return(FALSE);

	if (p_from GT p_to)
		return(FALSE);

	return(TRUE);
}

/*
   ============================================================================
	cx_mtst -- execute the mtest command
   ============================================================================
*/

int16_t cx_mtst(void)
{
	register int16_t	mask, was, *loc, *eloc, *oldloc;

	mask = 0x0001;
	loc = (int16_t *)p_from;
	eloc = (int16_t *)p_to;
	oldloc = loc;

	if (p_from LT (int8_t *)USER_RAM)
		setipl(7);

	do {

		while (mask) {

			*loc = mask;

			if (mask NE (was = *loc)) {
				if (p_from LT (int8_t *)USER_RAM)
					halt();
				else
					printf("%08lX was %04X, expected %04X\r\n",
						loc, was, mask);
			}

			*loc = ~mask;

			if (~mask NE (was = *loc)) {
				if (p_from LT (int8_t *)USER_RAM)
					halt();
				else
					printf("%08lX was %04X, expected %04X\r\n",
						loc, was, ~mask);
			}

			mask <<= 1;
		}

		mask = 0x0001;
		loc++;

	} while (loc LE eloc);

	if (oldloc LT (int16_t *)USER_RAM)
		rjumpto((void *)ROMADDR);

	return(TRUE);
}

/*
   ============================================================================
	cp_go -- parse parameters for go command
   ============================================================================
*/

int16_t cp_go(void)
{
	redo = FALSE;
	b0flag = FALSE;
	b1flag = FALSE;
	goflag = FALSE;

	if (getarg()) {

		if (setvar(&p_goto, p_goto) EQ FALSE)
			return(FALSE);

		if (1L & p_goto)
			return(FALSE);

		goflag = TRUE;

	}

	if (getarg()) {

		if (setp(&tba0, NULL) EQ FALSE)
			return(FALSE);

		if (1L & (int32_t)tba0)
			return(FALSE);

		b0flag = TRUE;
	}

	if (getarg()) {

		if (setp(&tba1, NULL) EQ FALSE)
			return(FALSE);

		if (1L & (int32_t)tba1)
			return(FALSE);

		b1flag = TRUE;
	}

	return(TRUE);
}

#if	ON_B700

/*
   ============================================================================
	cx_dini() -- execute the dinit command
   ============================================================================
*/

int16_t cx_dini(void)
{
	redo = TRUE;
	hdvini();
	return(TRUE);
}

#endif

/*
   ============================================================================
	cx_zap -- execute the zap command
   ============================================================================
*/

int16_t cx_zap(void)
{
	register int16_t *p, *q;

	p = (int16_t *)USER_RAM;
	q = (int16_t *)RAM_TOP;

	setipl(7);

	while (p LE q)
		*p++ = 0;

	rjumpto((void *)ROMADDR);
	return(TRUE);			/* not reached */
}

/*
   ============================================================================
	cx_omap() -- execute the omap command
   ============================================================================
*/

int16_t cx_omap(void)
{
	register int16_t i, width, xloc;

	printf("Pr B/C Locn      Wd Xloc Flags\r\n");

	for (i = 0; i < 16; i++) {

		xloc = (int16_t)(v_odtab[i][1] & 0x03FF);

		if (xloc & 0x0200)		/* sign extend xloc */
			xloc = xloc - 0x400;

		width = (int16_t)((v_odtab[i][1] >> 10) & 0x003F);

		printf("%2d %s ",
			i, ((v_odtab[i][0] & V_CBS) ? "Chr" : "Bit"));

		printf("$%08lX %2d %4d ",
			((int32_t)v_odtab[i][2] << 1), width, xloc);

		printf("$%04X\r\n", v_odtab[i][0]);
	}

	return(TRUE);
}

/*
   ============================================================================
	cx_help -- execute the help command
   ============================================================================
*/

int16_t cx_help(void)
{
	int16_t	i, j;

	j = 0;

	writeln(cmdunit, CRLF);

	for (i = 0; i < (int16_t)NCMDS; i++) {

		if (j++ EQ 22) {

			j = 0;

			if (waitcr2())
				return(TRUE);
		}

		writeln(cmdunit, "     ");
		writeln(cmdunit, cmtab[i].cname);
		writeln(cmdunit, "  ");
		writeln(cmdunit, cmtab[i].hstr);
		writeln(cmdunit, CRLF);
	}

	writeln(cmdunit, CRLF);
	return(TRUE);
}

/*
   ============================================================================
	cx_bpb -- execute bpb command
   ============================================================================
*/

int16_t cx_bpb(void)
{
	register struct bpb *bpp;

	if (0L EQ (bpp = (struct bpb *)BIOS(B_GBPB, 0) ) ) {

		writeln(cmdunit, "\r\n\nERROR -- Unable to read BPB\r\n\n");
		return(FALSE);

	} else {

		writeln(cmdunit, "\r\n\nBPB values:\r\n");
		writeln(cmdunit, "\r\n   recsiz   ");
		putn((uint32_t)bpp->recsiz, 5, cmdunit);
		writeln(cmdunit, "\r\n   clsiz     ");
		putn((uint32_t)bpp->clsiz, 4, cmdunit);
		writeln(cmdunit, "\r\n   clsizb   ");
		putn((uint32_t)bpp->clsizb, 5, cmdunit);
		writeln(cmdunit, "\r\n   rdlen     ");
		putn((uint32_t)bpp->rdlen, 4, cmdunit);
		writeln(cmdunit, "\r\n   fsiz      ");
		putn((uint32_t)bpp->fsiz, 4, cmdunit);
		writeln(cmdunit, "\r\n   fatrec   ");
		putn((uint32_t)bpp->fatrec, 5, cmdunit);
		writeln(cmdunit, "\r\n   datrec   ");
		putn((uint32_t)bpp->datrec, 5, cmdunit);
		writeln(cmdunit, "\r\n   numcl    ");
		putn((uint32_t)bpp->numcl, 5, cmdunit);
		writeln(cmdunit, "\r\n   bflags    ");
		puthn((uint32_t)bpp->bflags, 4, cmdunit);
		writeln(cmdunit, "\r\n   ntracks   ");
		putn((uint32_t)bpp->ntracks, 4, cmdunit);
		writeln(cmdunit, "\r\n   nsides    ");
		putn((uint32_t)bpp->nsides, 4, cmdunit);
		writeln(cmdunit, "\r\n   sec/cyl  ");
		putn((uint32_t)bpp->dspc, 5, cmdunit);
		writeln(cmdunit, "\r\n   sec/trk  ");
		putn((uint32_t)bpp->dspt, 5, cmdunit);
		writeln(cmdunit, "\r\n   hidden    ");
		putn((uint32_t)bpp->hidden, 4, cmdunit);
		writeln(cmdunit, "\r\n\n");
		return(TRUE);
	}
}

/*
   ============================================================================
	cx_go -- execute the go command
   ============================================================================
*/

int16_t cx_go(void)
{
	redo = FALSE;
	exflag = TRUE;
	wzcrsh = FALSE;

	if (goflag)
		regptr->reg_pc = (uint32_t)p_goto;

	if (b0flag ) {

		if (p_ba0) {

			if (*p_ba0 NE (uint16_t)BPINST) {

				writeln(cmdunit, "\r\n\n** Breakpoint 0 at ");
				puthn((uint32_t)p_ba0, 8, cmdunit);
				writeln(cmdunit, " was ");
				puthn(0xFFFFL & (uint32_t)(*p_ba0), 4, cmdunit);
				writeln(cmdunit, " instead of ");
				puthn(0xFFFFL & (uint32_t)BPINST, 4, cmdunit);
				writeln(cmdunit, " **\r\n\n");
			}

			*p_ba0 = p_bv0;
		}

		p_ba0 = tba0;
		p_bv0 = *p_ba0;
		*p_ba0 = (uint16_t)BPINST;
	}

	if (b1flag ) {

		if (p_ba1) {

			if (*p_ba1 NE (uint16_t)BPINST) {

				writeln(cmdunit, "\r\n\n** Breakpoint 1 at ");
				puthn((uint32_t)p_ba1, 8, cmdunit);
				writeln(cmdunit, " was ");
				puthn(0xFFFFL & (uint32_t)(*p_ba1), 4, cmdunit);
				writeln(cmdunit, " instead of ");
				puthn(0xFFFFL & (uint32_t)BPINST, 4, cmdunit);
				writeln(cmdunit, " **\r\n\n");
			}

			*p_ba1 = p_bv1;
		}

		p_ba1 = tba1;
		p_bv1 = *p_ba1;
		*p_ba1 = (uint16_t)BPINST;
	}

	return(TRUE);
}

/*
   ============================================================================
	cp_dump -- parse dump parameters
   ============================================================================
*/

int16_t cp_dump(void)
{
	inext = ilast;

	if (getarg())
		if (setp(&p_from, p_from) EQ FALSE) {

			redo = FALSE;
			return(FALSE);
		}

	if (argsep EQ A_CR OR argsep EQ '\0') {

		p_to = p_from;
		p_width = 16L;
		redo = TRUE;
		return(TRUE);
	}

	if (getarg())
		if (setp(&p_to, p_to) EQ FALSE) {

			redo = FALSE;
			return(FALSE);
	}

	if (argsep EQ A_CR OR argsep EQ '\0') {

		p_width = 16L;
		redo = TRUE;
		return(TRUE);
	}

	if (getarg())
		if (setvar(&p_width, p_width) EQ FALSE) {

			redo = FALSE;
			return(FALSE);
	}

	if ((p_width LE 0L) OR (p_width GT 16L)) {

		p_width = 16L;
		redo = FALSE;
		return(FALSE);
	}

	redo = TRUE;
	return(TRUE);
}

/*
   ============================================================================
	cp_fill -- parse parameters for fill command
   ============================================================================
*/

int16_t cp_fill(void)
{
	redo = FALSE;

	if (getarg())
		if (setp(&p_from, p_from) EQ FALSE)
			return(FALSE);

	if (getarg())
		if (setvar(&p_len, p_len) EQ FALSE)
			return(FALSE);

	if (getarg())
		if (setvar(&p_value, p_value) EQ FALSE)
			return(FALSE);

	if (p_value & ~0xFFL)
		return(FALSE);

	return(TRUE);
}

/*
   ============================================================================
	cp_wfil -- parse parameters for wfill command
   ============================================================================
*/

int16_t cp_wfil(void)
{
	redo = FALSE;

	if (getarg())
		if (setp(&p_from, p_from) EQ FALSE)
			return(FALSE);

	if (getarg())
		if (setvar(&p_len, p_len) EQ FALSE)
			return(FALSE);

	if (getarg())
		if (setvar(&p_value, p_value) EQ FALSE)
			return(FALSE);

	if ((int32_t)p_from & 1L)
		return(FALSE);

	if (p_value & ~0xFFFFL)
		return(FALSE);

	return(TRUE);
}

/*
   ============================================================================
	cp_copy -- parse parameters for copy command
   ============================================================================
*/

int16_t cp_copy(void)
{
	redo = FALSE;

	if (getarg())
		if (setp(&p_from, p_from) EQ FALSE)
			return(FALSE);

	if (getarg())
		if (setp(&p_to, p_to) EQ FALSE)
			return(FALSE);

	if (getarg())
		if (setvar(&p_len, p_len) EQ FALSE)
			return(FALSE);

	return(TRUE);
}

/*
   ============================================================================
	cp_chek -- parse parameters for chek command
   ============================================================================
*/

int16_t cp_chek(void)
{
	redo = FALSE;

	if (getarg())
		if (setp(&p_from, p_from) EQ FALSE)
			return(FALSE);

	if (getarg())
		if (setp(&p_to, p_to) EQ FALSE)
			return(FALSE);

	return(TRUE);
}

/*
   ============================================================================
	cp_read -- parse parameters for read command
   ============================================================================
*/

int16_t cp_read(void)
{
	redo = FALSE;

	if (getarg())
		if (setp(&p_from, p_from) EQ FALSE)
			return(FALSE);

	if (getarg())
		if (setp(&p_to, p_to) EQ FALSE)
			return(FALSE);

	if (getarg())
		if (setvar(&p_len, p_len) EQ FALSE)
			return(FALSE);

	if ((~0x7FFFL) & p_len)
		return(FALSE);

	if ((~0xFFFFL) & (int32_t)p_from)
		return(FALSE);

	return(TRUE);
}

/*
   ============================================================================
	cp_null -- parse null parameter line
   ============================================================================
*/

int16_t cp_null(void)
{
	return(TRUE);
}

/*
   ============================================================================
	cp_rset -- parse rset command parameters
   ============================================================================
*/

int16_t cp_rset(void)
{
	int16_t	rc;

	rc = 0;
	redo = FALSE;

	if (0 EQ getarg())
		return(FALSE);

	str2lc(argstr);

	if (0 EQ (rc = strlcmp(argstr, rlist)))
		return(FALSE);

	if (0 EQ getarg())
		return(FALSE);

	if (FALSE EQ setvar(&p_value, 0L))
		return(FALSE);

	rnum = rc;
	return(TRUE);
}


/*
   ============================================================================
	cx_chek -- process chek command
   ============================================================================
*/

int16_t cx_chek(void)
{
	register int32_t csum;
	register int8_t *cp;

	redo = FALSE;
	csum = 0L;

	for (cp = p_from; cp LE p_to; cp++)
		csum += 0x000000FFL & *cp;

	printf("Checksum = 0x%08lX\r\n", csum);

	return(TRUE);
}

/*
   ============================================================================
	cx_rset -- process rset command
   ============================================================================
*/

int16_t cx_rset(void)
{
	redo = FALSE;

	if (rnum < 1)
		return(FALSE);

	if (rnum < 9) {		/* d0..d7 -- data register */

		regptr->d_reg[rnum-1] = (uint32_t)p_value;
		return(TRUE);
	}

	if (rnum < 17) {	/* a0..a7 -- address register */

		regptr->a_reg[rnum-9] = (uint32_t)p_value;
		return(TRUE);
	}

	if (rnum EQ 17) {	/* sr -- status register */

		if ((~0xFFFFL) & p_value)
			return(FALSE);

		regptr->reg_sr = (uint16_t)p_value;
		return(TRUE);
	}

	if (rnum EQ 18) {	/* pc -- program counter */

		if (1L & p_value)
			return(FALSE);

		regptr->reg_pc = (uint32_t)p_value;
		return(TRUE);
	}

	if (rnum EQ 19) {	/* sp -- stack pointer */

		if (1L & p_value)
			return(FALSE);

		regptr->a_reg[7] = (uint32_t)p_value;
		return(TRUE);
	}

	return(FALSE);
}

/*
   ============================================================================
	cp_vrst -- parse vrset command parameters
   ============================================================================
*/

int16_t cp_vrst(void)
{
	int16_t	rc;

	rc = 0;
	redo = FALSE;

	if (0 EQ getarg())
		return(FALSE);

	str2lc(argstr);

	if (0 EQ (rc = strlcmp(argstr, vrlist)))
		return(FALSE);

	if (0 EQ getarg())
		return(FALSE);

	if (FALSE EQ setvar(&p_value, 0L))
		return(FALSE);

	if (vrnum < 17) {	/* complete register */

		vrnum = rc;
		return(TRUE);
	}

	if (vrnum < 21) {	/* horizontal register */

		if (p_value & ~0x003F)
			return(FALSE);

		vrnum = rc;
		return(TRUE);
	}

	if (vrnum < 25) {	/* vertical register */

		if (p_value & ~0x03FF)
			return(FALSE);

		vrnum = rc;
		return(TRUE);
	}

	return(FALSE);
}

/*
   ============================================================================
	cx_vrst -- process vrset command
   ============================================================================
*/

int16_t cx_vrst(void)
{
	redo = FALSE;

	if (vrnum < 1)
		return(FALSE);

	if (vrnum < 17) {	/* 1..16 -- r0..r15 -- complete register */

		v_regs[vrnum-1] = (uint16_t)p_value;
		return(TRUE);
	}

	if (vrnum < 21) {	/* 17..20 -- h0..h3 -- horizontal register */

		v_regs[vrnum-5] = (v_regs[vrnum-5] & 0x03FF) |
			(((uint16_t)p_value << 10) & 0xFC00);
		return(TRUE);
	}

	if (vrnum < 25) {	/* 21..24 -- v0..v3 -- vertical register */

		v_regs[vrnum-9] = (v_regs[vrnum-9] & 0xFC00) | (uint16_t)p_value;
		return(TRUE);
	}

	return(FALSE);
}

/*
   ============================================================================
	cx_vreg -- process vregs command
   ============================================================================
*/

int16_t cx_vreg(void)
{
	int16_t i, j, k, l;
	volatile uint16_t *rp;

	rp = &v_regs[0];
	l = 0;

	for (i = 0; i  < 2; i++) {

		for (j = 0; j < 2; j++) {

			for (k = 0; k < 4; k++) {

				writeln(cmdunit, "  ");
				putn((uint32_t)l++, 2, cmdunit);
				writeln(cmdunit, ":");
				puthn((uint32_t)*rp++, 4, cmdunit);
			}

			writeln(cmdunit, "  ");
		}

		writeln(cmdunit, "\r\n");
	}

	return(TRUE);
}

/*
   ============================================================================
	do_srec -- load a Motorola S record
   ============================================================================
*/

int16_t do_srec(int8_t *line)
{
	register int8_t *ldadr;
	register int16_t c, i, len;
	register uint16_t val, csum;

	if ('S' NE (c = *line++))
		return(-1);		/* error 1 = missing initial S */

	switch (c = *line++) {

	case '2':

		csum = 0;

		if (isxdigit(c = *line++))
			len = xdtoi(c);
		else
			return(-2);	/* error 2 = bad length byte */

		if (isxdigit(c = *line++))
			len = (len << 4) + xdtoi(c);
		else
			return(-2);

		csum += (len & 0xFF);
		ldadr = (int8_t *)0;
		len -= 4;

		for (i = 0; i < 3; i++) {

			if (isxdigit(c = *line++))
				val = (uint16_t)xdtoi(c);
			else
				return(-3);	/* error 3 = bad address byte */

			if (isxdigit(c = *line++))
				val = (val << 4) + (uint16_t)xdtoi(c);
			else
				return(-3);

			ldadr = (int8_t *)(((int32_t)ldadr << 8) + (int32_t)val);
			csum += (val & 0xFF);
		}

		for (i = 0; i < len; i++) {

			if (isxdigit(c = *line++))
				val = (uint16_t)xdtoi(c);
			else
				return(-4);	/* error 4 = bad data byte */

			if (isxdigit(c = *line++))
				val = (val << 4) + (uint16_t)xdtoi(c);
			else
				return(-4);

			csum += (val & 0xFF);
			*ldadr = (int8_t)(val & 0xFF);

			if ((*ldadr & 0xFF) NE (val & 0xFF))
				return(-5);	/* error 5 = store failed */

			ldadr++;
		}

		csum = 0xFF & ~csum;

		if (isxdigit(c = *line++))
			val = (uint16_t)xdtoi(c);
		else
			return(-6);		/* error 6 = bad checksum byte */

		if (isxdigit(c = *line++))
			val = (val << 4) + (uint16_t)xdtoi(c);
		else
			return(-6);

		if (csum NE (val & 0xFF))
			return(-7);		/* error 7 = bad checksum */

		return(1);

	case '9':

		if (memcmpu(line, SREC9, 10) EQ 0)
			return(0);
		else
			return(-8);		/* error 8 = bad end record */

	default:

		return(-9);			/* error 9 = unknown s type */
	}

	return(-10);			/* error 10 = switch failed */
}

/*
   ============================================================================
	cx_load -- process load command
   ============================================================================
*/

int16_t cx_load(void)
{
	register int16_t rc;

	do {

		rc = getrln(cmdunit, MAXCMDLN, cmdline);

		switch (rc) {

		case A_CR:

			rc = do_srec(cmdline);

			if (rc LT 0) {

				rc =  -rc;
				writeln(cmdunit, NACK);
				writeln(cmdunit, "** Load error ");
				putn((uint32_t)rc, 3, cmdunit);
				writeln(cmdunit, " **\r\n\n");
				return(FALSE);

			} else {

				writeln(cmdunit, TACK);
			}

			continue;

		case CTL('X'):

			rc = 1;
			writeln(cmdunit, TACK);
			continue;

		default:

			writeln(cmdunit, NACK);
			writeln(cmdunit, "** Load aborted on ");
			puthn((uint32_t)rc, 2, cmdunit);
			writeln(cmdunit, " **\r\n\n");
			return(FALSE);
		}

	} while (rc);

	return(TRUE);
}

/*
   ============================================================================
	cx_fill -- execute the fill command
   ============================================================================
*/

int16_t cx_fill(void)
{
	register int8_t *cp = p_from;
	register int32_t count;

	redo = FALSE;

	for (count = p_len; count > 0L; count--) {

		*cp = (int8_t)(0xFFL & p_value);

		if (*cp NE (int8_t)(0xFFL & p_value)) {

			writeln(cmdunit, "\r\n** FILL failed at ");
			puthn((uint32_t)cp, 8, cmdunit);
			writeln(cmdunit, " **\r\n");
			return(FALSE);
		}

		++cp;
	}

	return(TRUE);
}

/*
   ============================================================================
	cx_wfill -- execute the wfill command
   ============================================================================
*/

int16_t cx_wfil(void)
{
	register uint16_t *cp = (uint16_t *)p_from;
	register int32_t count;

	redo = FALSE;

	for (count = p_len; count > 0L; count--)
		*cp++ = (uint16_t)(0xFFFFL & p_value);

	return(TRUE);
}

/*
   ============================================================================
	cx_copy -- execute the copy command
   ============================================================================
*/

int16_t cx_copy(void)
{
	register int8_t	*from = p_from,
			*to = p_to;
	register int32_t	count = p_len;

	redo = FALSE;

	if (to GT from) {

		from = from + count;
		to = to + count;

		while (count--) {

			--from;
			--to;
			*to = *from;

			if (*from NE *to) {

				writeln(cmdunit, "\r\n** COPY failed from ");
				puthn((uint32_t)from, 8, cmdunit);
				writeln(cmdunit, " to ");
				puthn((uint32_t)to, 8, cmdunit);
				writeln(cmdunit, " with (from) = ");
				puthn((uint32_t)(*from), 2, cmdunit);
				writeln(cmdunit, " and (to) = ");
				puthn((uint32_t)(*to), 2, cmdunit);
				writeln(cmdunit, " **\r\n");
				return(FALSE);
			}
		}

	} else {

		while (count--) {

			*to = *from;

			if (*from NE *to) {

				writeln(cmdunit, "\r\n** COPY failed from ");
				puthn((uint32_t)from, 8, cmdunit);
				writeln(cmdunit, " to ");
				puthn((uint32_t)to, 8, cmdunit);
				writeln(cmdunit, " with (from) = ");
				puthn((uint32_t)(*from), 2, cmdunit);
				writeln(cmdunit, " and (to) = ");
				puthn((uint32_t)(*to), 2, cmdunit);
				writeln(cmdunit, " **\r\n");
				return(FALSE);
			}

			++from;
			++to;
		}
	}

	return(TRUE);
}
			

/*
   ============================================================================
	cx_dump -- execute the dump command
   ============================================================================
*/

int16_t cx_dump(void)
{
	register int16_t	nw, rc;

	redo= TRUE;
	d_cur = p_from;
	d_next = p_to + 1;
	d_last = ((int32_t)p_to - (int32_t)p_from) + d_next;
	nw = (int16_t)p_width;
	rc = TRUE;

	do {

		writeln(cmdunit, CRLF);
		padr(p_from, cmdunit);

		dflag = FALSE;

		if (ddump(p_from, p_to, nw, cmdunit))
			rc = FALSE;

		if (rc)
			if (dtext(p_from, p_to, nw, cmdunit))
				rc = FALSE;

		p_from = p_from + p_width;

		if (dflag)
			rc = FALSE;

	} while (rc);

	p_from = d_cur;

	writeln(cmdunit, CRLF);
	writeln(cmdunit, CRLF);

	return(TRUE);
}

/*
   ============================================================================
	wdump -- dump words in hex  (no ASCII)
   ============================================================================
*/

int16_t wdump(uint16_t *loc, uint16_t *lastloc, int16_t nwide, int16_t unit)
{
	while (nwide--) {

		puthn((uint32_t)(0xFFFFL & *loc), 4, unit);
		BIOS(B_PUTC,unit, ' ');

		if (BIOS(B_RDAV, unit))
			return(TRUE);

		if (loc EQ lastloc) {

			dflag = TRUE;
			return(FALSE);
		}

		++loc;
	}

	return(FALSE);
}

/*
   ============================================================================
	ldump -- dump longs in hex  (no ASCII)
   ============================================================================
*/

int16_t ldump(uint32_t *loc, uint32_t *lastloc, int16_t nwide, int16_t unit)
{
	while (nwide--) {

		puthn(*loc, 8, unit);
		BIOS(B_PUTC,unit, ' ');

		if (BIOS(B_RDAV, unit))
			return(TRUE);

		if (loc EQ lastloc) {

			dflag = TRUE;
			return(FALSE);
		}

		++loc;
	}

	return(FALSE);
}

/*
   ============================================================================
	cp_wdmp -- process parameters for wdump command
   ============================================================================
*/

int16_t cp_wdmp(void)
{
	inext = ilast;

	if (getarg())
		if (setp(&p_from, p_from) EQ FALSE) {

			redo = FALSE;
			return(FALSE);
		}

	if ((int32_t)p_from & 1L) {

		redo = FALSE;
		return(FALSE);
	}

	if (argsep EQ A_CR OR argsep EQ '\0') {

		p_to = p_from;
		p_width = 8;
		redo = TRUE;
		return(TRUE);
	}

	if (getarg())
		if (setp(&p_to, p_to) EQ FALSE) {

			redo = FALSE;
			return(FALSE);
		}

	if ((int32_t)p_to & 1L) {

		redo = FALSE;
		return(FALSE);
	}

	if (argsep EQ A_CR OR argsep EQ '\0') {

		p_width = 8;
		redo = TRUE;
		return(TRUE);
	}

	if (getarg())
		if (setvar(&p_width, p_width) EQ FALSE) {

			redo = FALSE;
			return(FALSE);
		}

	redo = TRUE;
	return(TRUE);
}

/*
   ============================================================================
	cp_ldmp -- process parameters for ldump command
   ============================================================================
*/

int16_t cp_ldmp(void)
{
	inext = ilast;

	if (getarg())
		if (setp(&p_from, p_from) EQ FALSE) {

			redo = FALSE;
			return(FALSE);
		}

	if ((int32_t)p_from & 1L) {

		redo = FALSE;
		return(FALSE);
	}

	if (argsep EQ A_CR OR argsep EQ '\0') {

		p_to = p_from;
		p_width = 4;
		redo = TRUE;
		return(TRUE);
	}

	if (getarg())
		if (setp(&p_to, p_to) EQ FALSE) {

			redo = FALSE;
			return(FALSE);
		}

	if ((int32_t)p_to & 1L) {

		redo = FALSE;
		return(FALSE);
	}

	if (argsep EQ A_CR OR argsep EQ '\0') {

		p_width = 4;
		redo = TRUE;
		return(TRUE);
	}

	if (getarg())
		if (setvar(&p_width, p_width) EQ FALSE) {

			redo = FALSE;
			return(FALSE);
		}

	redo = TRUE;
	return(TRUE);
}

/*
   ============================================================================
	cp_ilev -- parse the ipl command
   ============================================================================
*/

int16_t cp_ilev(void)
{
	int32_t	iplevl;

	if (argsep EQ A_CR OR argsep EQ '\0')
		return(TRUE);

	if (getarg())
		if (setvar(&iplevl, iplevl) EQ FALSE)
			return(FALSE);

	if (iplevl GT 7)
		return(FALSE);

	iplev = (int16_t)iplevl;

	return(TRUE);
}

/*
   ============================================================================
	cx_ilev -- execute ipl command
   ============================================================================
*/

int16_t cx_ilev(void)
{
	if (-1 EQ setipl(iplev)) {

		printf("ERROR -- Could not set IPL to %d\r\n", iplev);
		return(FALSE);
	} else
		printf("ROMP IPL now set to %d\r\n", iplev);

	return(TRUE);
}

/*
   ============================================================================
	cp_monc() -- parse the monc command
   ============================================================================
*/

int16_t cp_monc(void)
{
	if (getarg())
		if (setp(&monptr, monptr) EQ FALSE)
			return(FALSE);

	monsw = MON_C;
	redo = TRUE;
	return(TRUE);
}

/*
   ============================================================================
	cp_mons() -- parse the mons command
   ============================================================================
*/

int16_t cp_mons(void)
{
	if (getarg())
		if (setp(&monptr, monptr) EQ FALSE)
			return(FALSE);

	monsw = MON_S;
	redo = TRUE;
	return(TRUE);
}

/*
   ============================================================================
	cp_monl() -- parse the monl command
   ============================================================================
*/

int16_t cp_monl(void)
{
	if (getarg())
		if (setp(&monptr, monptr) EQ FALSE)
			return(FALSE);

	monsw = MON_L;
	redo = TRUE;
	return(TRUE);
}

/*
   ============================================================================
	cx_mon() -- process the mon commands
   ============================================================================
*/

int16_t cx_mon(void)
{
	register int8_t vc, vcc;
	register int16_t vs, vss, *vsp;
	register int32_t vl, vll, *vlp;

	switch (monsw) {

	case MON_C:

		vc = (int8_t)(*monptr & 0x0FF);
		puthn((uint32_t)vc, 2, cmdunit);
		writeln(cmdunit, "\r\n");

		while (!(0xFFFFL & BIOS(B_RDAV, CON_DEV))) {

			vcc = (int8_t)(*monptr & 0x0FF);

			if (vc NE vcc) {

				vc = vcc;
				puthn((uint32_t)vc, 2, cmdunit);
				writeln(cmdunit, "\r\n");
			}
		}

		BIOS(B_GETC, CON_DEV);
		return(TRUE);

	case MON_S:

		vsp = (int16_t *)monptr;
		vs = *vsp;
		puthn((uint32_t)vs, 4, cmdunit);
		writeln(cmdunit, "\r\n");

		while (!(0xFFFFL & BIOS(B_RDAV, CON_DEV))) {

			vss = *vsp;

			if (vs NE vss) {

				vs = vss;
				puthn((uint32_t)vs, 4, cmdunit);
				writeln(cmdunit, "\r\n");
			}
		}

		BIOS(B_GETC, CON_DEV);
		return(TRUE);


	case MON_L:

		vlp = (int32_t *)monptr;
		vl = *vlp;
		puthn((uint32_t)vl, 8, cmdunit);
		writeln(cmdunit, "\r\n");

		while (!(0xFFFFL & BIOS(B_RDAV, CON_DEV))) {

			vll = *vlp;

			if (vl NE vll) {

				vl = vll;
				puthn((uint32_t)vl, 8, cmdunit);
				writeln(cmdunit, "\r\n");
			}
		}

		BIOS(B_GETC, CON_DEV);
		return(TRUE);

	default:
		return(FALSE);
	}
}
		

/*
   ============================================================================
	cx_wdmp -- process wdump command
   ============================================================================
*/

int16_t cx_wdmp(void)
{
	int16_t	nw, rc;

	d_cur = p_from;
	d_next = p_to + 2;
	d_last = ((int32_t)p_to - (int32_t)p_from) + d_next;
	nw = (int16_t)p_width;
	rc = TRUE;

	do {

		writeln(cmdunit, CRLF);
		padr(p_from, cmdunit);
		dflag = FALSE;

		if (wdump((uint16_t *)p_from, (uint16_t *)p_to, nw, cmdunit))
			rc = FALSE;

		p_from = p_from + (p_width << 1);

		if (dflag)
			rc = FALSE;

	} while (rc);

	p_from = d_cur;

	writeln(cmdunit, CRLF);
	writeln(cmdunit, CRLF);
	return(TRUE);
}

/*
   ============================================================================
	cx_ldmp -- process ldump command
   ============================================================================
*/

int16_t cx_ldmp(void)
{
	int16_t	nw, rc;

	d_cur = p_from;
	d_next = p_to + 4;
	d_last = ((int32_t)p_to - (int32_t)p_from) + d_next;
	nw = (int16_t)p_width;
	rc = TRUE;

	do {

		writeln(cmdunit, CRLF);
		padr(p_from, cmdunit);
		dflag = FALSE;

		if (ldump((uint32_t *)p_from, (uint32_t *)p_to, nw, cmdunit))
			rc = FALSE;

		p_from = p_from + (p_width << 2);

		if (dflag)
			rc = FALSE;

	} while (rc);

	p_from = d_cur;

	writeln(cmdunit, CRLF);
	writeln(cmdunit, CRLF);
	return(TRUE);
}

/*
   ============================================================================
	do_cmd -- process a command line
   ============================================================================
*/

void do_cmd(void)
{
	int16_t	rc, i;

	/* prompt for a command line */

#if	TINYMSG
	writeln(cmdunit, "R: ");
#else
	writeln(cmdunit, "ROMP: ");
#endif

	/*  get a command line */

	rc = getln(cmdunit, MAXCMDLN, cmdline);

	/* dispatch based on rc */

	switch (rc) {

	case A_CR:

		writeln(cmdunit, CRLF);

		if (getcmd()) {

			for (i = 0; i < (int16_t)NCMDS; i++) {

				if (0 EQ strcmp(argstr, cmtab[i].cname)) {

					ilast = i;

					if ((*cmtab[i].cp)()) {

						if (FALSE EQ (*cmtab[i].cx)())
							writeln(cmdunit, EMSG1);

					} else {

						writeln(cmdunit, EMSG2);
					}

					return;
				}
			}

			writeln(cmdunit, EMSG3);
			return;

		} else {

			if (redo) {

				if (FALSE EQ (*cmtab[ilast].cx)())
					writeln(cmdunit, EMSG1);

			} else {

				writeln(cmdunit, EMSG5);
			}

			return;
		}

	case CTL('X'):

		writeln(cmdunit, CANNED);
		return;

	default:

		writeln(cmdunit, EMSG6);
		return;
	}

	writeln(cmdunit, EMSG7);
	return;
}

/*
   ============================================================================
	cx_next -- process the next command
   ============================================================================
*/

int16_t cx_next(void)
{
	p_to = d_last;	
	p_from = d_next;
	return((*cmtab[inext].cx)());
}

/*
   ============================================================================
	cx_read() -- process the read command
   ============================================================================
*/

int16_t cx_read(void)
{
	int32_t	rc;
	int16_t	ns, recno;

	ns = p_len & 0x7FFFL;
	recno = (int16_t)((int32_t)p_from & 0xFFFFL);

	rc = BIOS(B_RDWR, 2, p_to, ns, recno, 0);

	if (rc & 0xFFFFL) {

		writeln(cmdunit, "\r\nERROR reading disk:  ");
		puthn((uint32_t)rc, 8, cmdunit);
		writeln(cmdunit, "\r\n\n");
		return(FALSE);

	} else {

		return(TRUE);
	}
}

/*
   ============================================================================
	cx_writ() -- process the write command
   ============================================================================
*/

int16_t cx_writ(void)
{
	int32_t	rc;
	int16_t	ns, recno;

	ns = p_len & 0x7FFFL;
	recno = (int16_t)((int32_t)p_from & 0xFFFFL);

	rc = BIOS(B_RDWR, 3, p_to, ns, recno, 0);

	if (rc & 0xFFFFL) {

		writeln(cmdunit, "\r\nERROR writing disk:  ");
		puthn((uint32_t)rc, 8, cmdunit);
		writeln(cmdunit, "\r\n\n");
		return(FALSE);

	} else {

		return(TRUE);
	}
}

/*
   ============================================================================
	showrs() -- show registers
   ============================================================================
*/

void showrs(struct regs *rp)
{
	int16_t	i;
	uint16_t	srtemp;

	writeln(cmdunit, "       ");

	for (i = 0; i < 8; i++) {

		BIOS(B_PUTC, cmdunit, ' ');
		BIOS(B_PUTC, cmdunit, '0'+i);
		writeln(cmdunit, "_______");
	}

	writeln(cmdunit, "\r\nd0..d7 ");

	for (i = 0; i < 8; i++) {

		BIOS(B_PUTC, cmdunit, ' ');
		puthn(rp->d_reg[i], 8, cmdunit);
	}

	writeln(cmdunit, "\r\na0..a7 ");

	for (i = 0; i < 8; i++) {

		BIOS(B_PUTC, cmdunit, ' ');
		puthn(rp->a_reg[i], 8, cmdunit);
	}

	writeln(cmdunit, "\r\nPC =  ");
	puthn((uint32_t)rp->reg_pc, 8, cmdunit);

	srtemp = rp->reg_sr;
	writeln(cmdunit, ",    SR = ");
	puthn((uint32_t)srtemp & 0xFFFFL, 4, cmdunit);

	writeln(cmdunit, "  (IPL = ");
	puthn((uint32_t)(srtemp >> 8) & 0x7L, 1, cmdunit);
	writeln(cmdunit, ", ");

	if (srtemp & 0x8000)
		BIOS(B_PUTC, cmdunit, 'T');
	else
		BIOS(B_PUTC, cmdunit, '-');

	if (srtemp & 0x2000)
		BIOS(B_PUTC, cmdunit, 'S');
	else
		BIOS(B_PUTC, cmdunit, '-');

	BIOS(B_PUTC, cmdunit, ' ');

	if (srtemp & 0x10)
		BIOS(B_PUTC, cmdunit, 'X');
	else
		BIOS(B_PUTC, cmdunit, '-');

	if (srtemp & 0x8)
		BIOS(B_PUTC, cmdunit, 'N');
	else
		BIOS(B_PUTC, cmdunit, '-');

	if (srtemp & 0x4)
		BIOS(B_PUTC, cmdunit, 'Z');
	else
		BIOS(B_PUTC, cmdunit, '-');

	if (srtemp & 0x2)
		BIOS(B_PUTC, cmdunit, 'V');
	else
		BIOS(B_PUTC, cmdunit, '-');

	if (srtemp & 0x1)
		BIOS(B_PUTC, cmdunit, 'C');
	else
		BIOS(B_PUTC, cmdunit, '-');

	writeln(cmdunit, " )\r\n");
}

/*
   ============================================================================
	showcr() -- show crash registers
   ============================================================================
*/

void showcr(void)
{
	register int16_t	i;
	register int8_t	*cause;
	register uint16_t	srtemp;

	writeln(cmdunit, "BIOS Crash Area Dump\r\n");
	writeln(cmdunit, "       ");

	for (i = 0; i < 8; i++) {

		BIOS(B_PUTC, cmdunit, ' ');
		BIOS(B_PUTC, cmdunit, '0'+i);
		writeln(cmdunit, "_______");
	}

	writeln(cmdunit, "\r\nd0..d7 ");

	for (i = 0; i < 8; i++) {

		BIOS(B_PUTC, cmdunit, ' ');
		puthn(crshrg[i], 8, cmdunit);
	}

	writeln(cmdunit, "\r\na0..a7 ");

	for (i = 8; i < 16; i++) {

		BIOS(B_PUTC, cmdunit, ' ');
		puthn(crshrg[i], 8, cmdunit);
	}

	writeln(cmdunit, "\r\n\nPC =  ");
	puthn(crshpc, 8, cmdunit);

	srtemp = crshsr;
	writeln(cmdunit, ",    SR = ");
	puthn((uint32_t)srtemp & 0xFFFFL, 4, cmdunit);

	writeln(cmdunit, "  (IPL = ");
	puthn((uint32_t)(srtemp >> 8) & 0x7L, 1, cmdunit);
	writeln(cmdunit, ", ");

	if (srtemp & 0x8000)
		BIOS(B_PUTC, cmdunit, 'T');
	else
		BIOS(B_PUTC, cmdunit, '-');

	if (srtemp & 0x2000)
		BIOS(B_PUTC, cmdunit, 'S');
	else
		BIOS(B_PUTC, cmdunit, '-');

	BIOS(B_PUTC, cmdunit, ' ');

	if (srtemp & 0x10)
		BIOS(B_PUTC, cmdunit, 'X');
	else
		BIOS(B_PUTC, cmdunit, '-');

	if (srtemp & 0x8)
		BIOS(B_PUTC, cmdunit, 'N');
	else
		BIOS(B_PUTC, cmdunit, '-');

	if (srtemp & 0x4)
		BIOS(B_PUTC, cmdunit, 'Z');
	else
		BIOS(B_PUTC, cmdunit, '-');

	if (srtemp & 0x2)
		BIOS(B_PUTC, cmdunit, 'V');
	else
		BIOS(B_PUTC, cmdunit, '-');

	if (srtemp & 0x1)
		BIOS(B_PUTC, cmdunit, 'C');
	else
		BIOS(B_PUTC, cmdunit, '-');

	writeln(cmdunit, " )\r\n");


	writeln(cmdunit, "TRAP vector number = ");
	putn((uint32_t)crshvc[0], 2, cmdunit);

	cause = "  (no handler for interrupt)";

	switch (crshvc[0] & 0xFF) {

	case 2:		/* 2:  bus error */

		cause = "  (Bus error)";
		break;

	case 3:		/* 3:  address error */

		cause = "  (Address error)";
		break;

	case 4:		/* 4:  illegal instruction */

		cause = "  (Illegal instruction)";
		break;

	case 5:		/* 5:  zero divide */

		cause = "  (Zero divide)";
		break;

	case 6:		/* 6:  CHK instruction */

		cause = "  (CHK instruction)";
		break;

	case 7:		/* 7:  TRAPV instruction */

		cause = "  (TRAPV instruction)";
		break;

	case 8:		/* 8:  privilege violation */

		cause = "  (Privilege violation)";
		break;

	case 9:		/* 9:  trace */

		cause = "  (Trace -- not implemented)";
		break;

	case 10:	/* 10:  line 1010 emulator */

		cause = "  (Line 1010 Emulator -- not implemented)";
		break;

	case 11:	/* 11:  line 1111 emulator */

		cause = "  (Line 1111 Emulator -- not implemented";
		break;

	case 15:	/* 15:  uninitialized interrupt vector */

		cause = "  (Uninitialized interrupt)";
		break;

	case 24:	/* 24:  spurious interrupt */

		cause = "  (Spurious interrupt)";
		break;

	case 25:	/* 25:  Autovector Level 1*/

		cause = "  (Level 1 Interrupt -- unimplmented)";
		break;

	case 26:	/* 26:  Autovector Level 2 */

		cause = "  (Level 2 Interrupt -- unimplmented)";
		break;

	case 27:	/* 27:  Autovector Level 3 */

		cause = "  (Level 3 Interrupt -- unimplmented)";
		break;

	case 28:	/* 28:  Autovector Level 4 */

		cause = "  (Level 4 Interrupt -- unimplmented)";
		break;

	case 29:	/* 29:  Autovector Level 5 */

		cause = "  (Level 5 Interrupt -- unimplmented)";
		break;

	case 30:	/* 30:  Autovector Level 6 */

		cause = "  (Level 6 Interrupt -- unimplmented)";
		break;

	case 31:	/* 31:  Autovector Level 7 */

		cause = "  (Level 7 Interrupt -- unimplmented)";
		break;

	}

	writeln(cmdunit, cause);
	writeln(cmdunit, "\r\n");
}

/*
   ============================================================================
	cx_crsh -- process the crash command
   ============================================================================
*/

int16_t cx_crsh(void)
{
	if (!wzcrsh)
		printf("** Crash switch NOT set **\r\n");

	redo = FALSE;
	showcr();
	return(TRUE);
}

/*
   ============================================================================
	bphit -- clear breakpoints, see if any were hit
   ============================================================================
*/

int16_t bphit(void)
{
	int16_t	rc;

	rc = FALSE;

	if ((uint32_t)p_ba0 EQ regptr->reg_pc) {

		if (*p_ba0 EQ BPINST) {

			*p_ba0 = p_bv0;
			p_ba0 = 0L;
			p_bv0 = BPINST;
			rc = TRUE;

		} else {

			writeln(cmdunit, "** Breakpoint word at ");
			puthn((uint32_t)p_ba0, 8 , cmdunit);
			writeln(cmdunit, " was ");
			puthn(0xFFFFL & (uint32_t)(*p_ba0), 4, cmdunit);
			writeln(cmdunit, " instead of ");
			puthn((uint32_t)BPINST, 4, cmdunit);
			writeln(cmdunit, " **\r\n\n");
			rc = TRUE;
		}
	}

	if ((uint32_t)p_ba1 EQ regptr->reg_pc) {

		if (*p_ba1 EQ BPINST) {

			*p_ba1 = p_bv1;
			p_ba1 = 0L;
			p_bv1 = BPINST;
			rc = TRUE;

		} else {

			writeln(cmdunit, "** Breakpoint word at ");
			puthn((uint32_t)p_ba0, 8 , cmdunit);
			writeln(cmdunit, " was ");
			puthn(0xFFFFL & (uint32_t)(*p_ba1), 4, cmdunit);
			writeln(cmdunit, " instead of ");
			puthn((uint32_t)BPINST, 4, cmdunit);
			writeln(cmdunit, " **\r\n\n");
			rc = TRUE;
		}
	}

	if (p_ba0) {

		if (*p_ba0 EQ BPINST) {

			*p_ba0 = p_bv0;
			p_ba0 = 0L;
			p_bv0 = BPINST;
			rc = TRUE;

		} else {

			writeln(cmdunit, "** Breakpoint word at ");
			puthn((uint32_t)p_ba0, 8 , cmdunit);
			writeln(cmdunit, " was ");
			puthn(0xFFFFL & (uint32_t)(*p_ba0), 4, cmdunit);
			writeln(cmdunit, " instead of ");
			puthn((uint32_t)BPINST, 4, cmdunit);
			writeln(cmdunit, " **\r\n\n");
			rc = TRUE;
		}
	}

	if (p_ba1) {

		if (*p_ba1 EQ BPINST) {

			*p_ba1 = p_bv1;
			p_ba1 = 0L;
			p_bv1 = BPINST;
			rc = TRUE;

		} else {

			writeln(cmdunit, "** Breakpoint word at ");
			puthn((uint32_t)p_ba0, 8 , cmdunit);
			writeln(cmdunit, " was ");
			puthn(0xFFFFL & (uint32_t)(*p_ba1), 4, cmdunit);
			writeln(cmdunit, " instead of ");
			puthn((uint32_t)BPINST, 4, cmdunit);
			writeln(cmdunit, " **\r\n\n");
			rc = TRUE;
		}
	}

	if (rc)
		return(rc);

	writeln(cmdunit, "\r\n** Program invoked ROMP trap **\r\n");
	return(FALSE);
}

/*
   ============================================================================
	cx_regs() -- process the regs command
   ============================================================================
*/

int16_t cx_regs(void)
{
	showrs(regptr);
	return(TRUE);
}

/*
   ============================================================================
	rompbp() -- process a breakpoint for ROMP
   ============================================================================
*/

void rompbp(uint32_t d0, ...)
{
	register int16_t i;

	regptr = (struct regs *)&d0;	/* make registers accessable */
	regptr->reg_pc -= 2L;		/* adjust pc */

	if (-1 EQ setipl(iplev))		/* enable interrupts */
		writeln(cmdunit, "\r\n\n***** setipl() failed *****\r\n\n");

	if (first1) {			/* initial entry from xtrap15() */

		for (i = 0; i < 8; i++)		/* clear d0..d7 */
			regptr->d_reg[i] = 0L;

		for (i = 0; i < 7; i++)		/* clear a0..a6 */
			regptr->a_reg[i] = 0L;

		regptr->a_reg[7] = ISTACK;	/* setup initial stack */

		regptr->reg_sr = INITSR;	/* setup sr */
		regptr->reg_pc += 2L;		/* adjust pc past TRAP 15 */

	} else {			/* breakpoint */

		writeln(cmdunit, "\r\n\n** ROMP Breakpoint TRAP **\r\n");

		showrs(regptr);		/* show registers */

		if (bphit() EQ FALSE)		/* fixup breakpoints */
			regptr->reg_pc += 2L;	/* and maybe the pc */

	}

	first1 = FALSE;			/* not first time any more */
	exflag = FALSE;			/* clear exit flag */

	do {

		do_cmd();		/* process commands ... */

	} while (!exflag);		/* ... until exit flag is set */

	return;				/* return to xtrap15 */
}

/*
   ============================================================================
	progid() -- identify the program
   ============================================================================
*/

void progid(void)
{
	register int8_t *pcptr;

#if	TINYMSG

#if	ON_B700
	writeln(cmdunit, "\r\n\nB\r\n");
#else
	writeln(cmdunit, "\r\n\nN\r\n");
#endif

#else

#if	ON_B700
	writeln(cmdunit, "\r\n\nBuchla 700 BIOS / Debug PROM\r\n");
#else
	writeln(cmdunit, "\r\n\nNASA 3D Helmet Display BIOS / Debug PROM\r\n");
#endif

	writeln(cmdunit, "  ROMP Version ");
	writeln(cmdunit, ROMPVER);

	writeln(cmdunit, "\r\n  BIOS Version ");
	pcptr = (int8_t *)PRM_VERS;
	putn((uint32_t)*pcptr++, 2, cmdunit);
	BIOS(B_PUTC, cmdunit, '.');
	putn((uint32_t)*pcptr++, 2, cmdunit);
	writeln(cmdunit, promdate);

#endif
}

#if	ON_B700


/*
   ============================================================================
	pclr() -- clear the panel FIFO
   ============================================================================
*/

int16_t pclr(void)
{
	register int16_t i;

	ftimer = FIFOLIM;

	while (-1L NE (afi = XBIOS(X_ANALOG))) {	/* check panel inputs */

		asig  = 0x007F & (afi >> 8);	/* signal number */

		if (0 EQ asig) {

			/* all keys up */

			for (i = 0; i < 128; i++) {

				sigtab[i][0] = 0;
				sigtab[i][1] = 0;
			}

			break;
		}

		if (ftimer-- < 0)
			return(FAILURE);
	}

	return(SUCCESS);
}

/*
   ============================================================================
	pscan() -- scan the panel and maybe even load a program from diskette
   ============================================================================
*/

int16_t pscan(void)
{
	register int16_t i, c;

	if (0 EQ ledcntr--) {

		if ((baseled + 3) > 23)			/* turn on a LED */
			io_leds = (uint8_t)(baseled - 21);
		else
			io_leds = (uint8_t)(baseled + 3);

		io_leds = (uint8_t)(0x80 + baseled);	/* turn off a LED */

		if (++baseled > 23)			/* update LED number */
			baseled = 0;

		ledcntr = 200;
	}

	aflag = FALSE;

	if (-1L NE (afi = XBIOS(X_ANALOG))) {	/* check panel inputs */

		asig  = 0x007F & (afi >> 8);	/* signal number */
		astat = 0x0001 & (afi >> 7);	/* status */
		aval  = 0x007F & afi;		/* value */

		if (asig) {	/* active signal */

			aflag = TRUE;

			sigtab[asig][0] = aval;
			sigtab[asig][1] = astat;

		} else {	/* all keys up */

			aflag = FALSE;

			for (i = 0; i < 128; i++)
				sigtab[i][1] = 0;
		}
	}

	if (aflag) {	/* anything changed ? */

		if (astat AND (asig EQ BOOTKEY)) {		/* BOOT key */

			for (i = 0; i < 24; i++)	/* turn off LEDs */
				io_leds = (uint8_t)(0x80 + i);

			io_leds = 0x1F;			/* turn off LCD lamp */

			/* load and run BOOTFILE */

			B_log_s = FALSE;
			B_dbg_s = FALSE;

			hdvini();
			_bpbin = FALSE;

			if (booter(BOOTFILE, 0L))
				return(FALSE);
			else
				sjumpto((void *)B_buf_a, (void *)ISTACK);

		} else if (astat AND (asig EQ ROMPKEY)) {	/* ROMP key */

			for (i = 0; i < 24; i++)	/* turn off LEDs */
				io_leds = (uint8_t)(0x80 + i);

			return(TRUE);
		}
	}

	if (BIOS(B_RDAV, CON_DEV)) {

		c = 0x007F & BIOS(B_GETC, CON_DEV);

		if ((c EQ 'r') OR (c EQ 'R'))
			return(TRUE);
	}

	return(FALSE);
}
#endif

/*
   ============================================================================
	romp main routine
   ============================================================================
*/

void main(void)
{
	register int16_t i;
	register int8_t *pdptr, *pcptr;

	/* unpack PROM date */

	pcptr = (int8_t *)PRM_DATE;	/* prom date: yyyymmdd */
	pdptr = promdate;		/*  -- yyyy-mm-dd */
	*pdptr++ = ' ';
	*pdptr++ = '-';
	*pdptr++ = '-';
	*pdptr++ = ' ';
	*pdptr++ = (int8_t)(((*pcptr >> 4) & 0x0F) + '0');
	*pdptr++ = (int8_t)((*pcptr++ & 0x0F) + '0');
	*pdptr++ = (int8_t)(((*pcptr >> 4) & 0x0F) + '0');
	*pdptr++ = (int8_t)((*pcptr++ & 0x0F) + '0');
	*pdptr++ = '-';
	*pdptr++ = (int8_t)(((*pcptr >> 4) & 0x0F) + '0');
	*pdptr++ = (int8_t)((*pcptr++ & 0x0F) + '0');
	*pdptr++ = '-';
	*pdptr++ = (int8_t)(((*pcptr >> 4) & 0x0F) + '0');
	*pdptr++ = (int8_t)((*pcptr++ & 0x0F) + '0');
	*pdptr++ = '\0';

	/* initialize variables */

	sprintf(hs_mtst, "[[start=$%lX],[end=$%lx]]  (or $8..$%lX)",
		USER_RAM, RAM_TOP, (USER_RAM - 2L));

	cmdunit = CON_DEV;

	ilast = 0;
	inext = 0;
	iplev = DEFIPL;

	dflag  = FALSE;
	exflag = FALSE;
	redo   = FALSE;
	goflag = FALSE;
	b0flag = FALSE;
	b1flag = FALSE;

	p_goto  = ROMADDR;
	p_len   = 0L;
	p_width = 16L;
	p_value = 0L;

	p_ba0 = 0L;
	p_bv0 = BPINST;

	p_ba1 = 0L;
	p_bv1 = BPINST;

	tba0 = 0L;
	tba1 = 0L;

	inext = 0;

	tsetup();			/* patch the timer interrupt code */

#if	ON_B700
	baseled = 21;				/* setup LED scan */
	ledcntr = 0;				/* ... */
	io_leds = 0x9F;				/* turn on LCD lamp */
	GLCinit();				/* reset LCD display */

	GLCtext(0,  1, "Load  GoTo");
	GLCtext(1,  1, "Disk  ROMP");

	GLCtext(3, 15, "Buchla 700 -- BIOS/ROMP Firmware by D.N. Lynx Crowe");

	sprintf(idbuf, "BIOS Version %02d.%02d%s",
		*(int8_t *)PRM_VERS, *(int8_t *)(PRM_VERS+1), promdate);
	GLCtext(5, 30, idbuf);

	sprintf(idbuf, "ROMP Version %s", ROMPVER);
	GLCtext(6, 30, idbuf);
	GLCcrc(0, 0);

	BIOS(B_SETV, 47, trap15);	/* set ROMP trap vec */

	for (i = 0; i < 128; i++) {

		sigtab[i][0] = 0;
		sigtab[i][1] = 0;
	}

	XBIOS(X_CLRAFI);			/* clear the panel FIFO */
	setipl(KB_EI);				/* enable interrupts */
	pclr();					/* empty the panel FIFO */
	XBIOS(X_CLRAFI);			/* clear the panel FIFO */

	while (FALSE EQ pscan()) ;		/* do the panel scan */
#endif


	if (setjmp(&restart))	/* setup restart point */
		writeln(cmdunit, "\r\n***** ROMP Re-starting *****\r\n\n");

	tsetup();	/* patch the timer interrupt code */
	progid();	/* identify the program */

	BIOS(B_SETV, 47, trap15);	/* set ROMP trap vec */
	writeln(cmdunit, "\r\n\n");

	/* process commands */

	first1 = TRUE;			/* set break init flag */

	while (TRUE) {

		xtrap15();		/* trap into ROMP bp processor */
		writeln(cmdunit, "\r\n** xtrap15() returned to ROMP **\r\n\n");
	}
}

