/* romarg.s -- AIS/3200 RAMless-Monitor main body
 * copyright(c) American Information Systems Corporation
 *  Dock Williams
 *  February, 1984	updated for system 5.2 July, 1984
 *
 *  original idea and code by Franco I.
 *
 *  the ramless monitor uses no ram to perform its functions
 *	only the CPU registers are used in the ramless monitor
 *
 * pattern of register usage:
 *
 * r0-r5:
 *	early in command line processing: input character fifo
 *	an input character is read into r5 as a byte
 *	if it is determined that it was a legal character
 *	the character is echoed and pushed onto the input
 *	character fifo queue, if it was illegal it is ignored.
 *	bytes are ordered in the fifo in the following way:
 *	in registers r5-r1 the most significant byte is
 *	the oldest byte and the least significant byte is
 *	the latest byte to be pushed forward from somewhere
 *	lower in the fifo, r0 is reversed so that the current
 *	byte in r0 is always the top of the fifo
 *	later, after the fifo has been interpreted:
 *	r0-r2 form up to three arguments that were
 *	converted from the input fifo registers that can
 *	be used as input parameters to a command.
 *	r3-r5 are used as temporaries and their use will
 *	change with almost every command, with r5 being
 *	primarily used for io
 *	
 * r6:	return address for single character io
 *	and as a temporary when not doing single
 *	character
 * r7:	general return address
 * fp:	remembered address for open command
 * mod:	remembered last open type
 */
	.file	"raml.s"

#include "promhdr.h"
#include "3200config.h"

	.set	BCKSPC,0x08
	.set	TAB,0x09
	.set	SPC,0x20	
	.set	BELL,0x07
	.set	CR,0x0D
	.set	LF,0x0A
	.set	ESC,0x1B
	.set	CTRL_Q,0x11
	.set	CTRL_S,0x13
	.set	DEL,0x7F

	.globl	_ramless_monitor
	.globl	ramless_quiet
	.globl	epushc
	.globl	pushc	
	.globl	erase	

/*  */

#define PARENABLES (SBUS_TMOENABLE | SBUS_PARENABLE | HOST_TMOENABLE | HOST_PARENABLE)

_ramless_monitor:
	/* 
	 * turn off
	 *	host bus parity checking,
	 *	host bus timeout,
	 *	system bus parity checking,
	 *	system bus timeout,
	 *	and pick enable
	 */
	movb	$(PARENABLES | PICK_ENABLE), @(UART_PARENABLE + U_CLROUT)

	addr	_RMbootmsg,r5		/* print AIS/3200 Ramless Monitor */
	addr	lab1,r7			/* return address */
	br	printm
lab1:
	addr	_copyright,r5		/* print copyright (c) 1984 */
	addr	lab2,r7			/* return address */
	br	printm
lab2:
	addr	_corporation,r5		/* print American Infor... */
	addr	ramless_quiet,r7	/* return address */
	br	printm

break:
	bpt				/* for debugging with monitor */
	br	_ramless_monitor	/* otherwise this is deadly */


/*  */

ramless_quiet:			/* quiet entry point */
	movqd	0,r0
	lprw	mod,r0		/* clear, because we're not in open mode */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r0		/* disable special mmu functions */
#endif /************************** MMU Available ***********************/

	addr	getinpl,r7	/* return address */
	br	crlf		/* print a cr/lf combination */
getinpl:
	bicpsrw	(PSR_I | PSR_S | PSR_U)	/* disable interrupts */
	addr	sprompt,r5
	addr	getv,r7
	br	printm
sprompt:
	.byte	SQ:R,SQ:M,SQ:>,SQ: ,0

getv:
	movqd	0,r0		/* clear registers */
	movqd	0,r1
	movqd	0,r2
	movqd	0,r3
	movqd	0,r4
	movqd	0,r5
	bispsrw	PSR_S		/* switch to user stack */
	lprd	sp,r0		/* clear user stack pointer */
	bicpsrw	PSR_S		/* switch back to interrupt stack */

	/* get an input character */
getc:
	addr	chkinc,r6
	br	inc

/*  */

	/* figure out what to do with it */
chkinc:
	cmpb	r5,TAB
	beq	pushspc
	cmpb	r5,BCKSPC
	beq	erase
	cmpb	r5,DEL
	beq	erase
	cmpb	r5,LF
	beq	openchk
	cmpb	r5,CR
	beq	openchk
	cmpb	r5,SQ:^
	beq	openchk
	cmpb	r5,SQ:+
	beq	openchk
	cmpb	r5,SQ:-
	beq	openchk
	cmpb	r5,SQ:?
	beq	epushc
	cmpb	r5,SQ:@
	beq	openchk
	cmpb	r5,SPC
	blt	getc		/* illegal character, ignore */
	beq	epushc
	cmpb	r5,SQ:`
	beq	reopen
	cmpb	r5,SQ:\
	beq	reopen
	cmpb	r5,SQ:/
	beq	reopen
	cmpb	r5,SQ:0
	blt	getc		/* illegal character, ignore */
	cmpb	r5,SQ:9
	ble	epushc
	cmpb	r5,SQ:A
	blt	getc		/* illegal character, ignore */
	cmpb	r5,SQ:Z
	ble	epushc
	br	getc		/* illegal character, ignore */

/*  */

openchk:
	sprd	mod,r6
	cmpb	SQ:/,r6	/* have to be in open mode for ^+-@ to make sense */
	beq	savtype
	cmpb	SQ:\,r6
	beq	savtype
	cmpb	SQ:`,r6
	beq	savtype
	cmpb	SQ:^,r5		/* if not in open mode ^+-@ are errors */
	beq	error
	cmpb	SQ:+,r5
	beq	error
	cmpb	SQ:-,r5
	beq	error
	cmpb	SQ:@,r5
	beq	error

	movd	r5,r6
	movqd	0,r7		/* shifting amount */
	movqb	0,r5		/* clear last character */
rechk:
	cmpb	r6,CR		/* get rid of spaces,tabs, and cr that */
	beq	rshift6		/* may be part of a regular command */
	cmpb	r6,SPC
	beq	rshift6
	cmpb	r6,TAB
	beq	rshift6
	cmpqb	0,r6
	beq	ramless_quiet
	lprd	mod,r6		/* store regular command */
	br	convertinput	/* convert input for regular command */
rshift6:
	lshd	-8,r6
	addb	-8,r7		/* icrement shift amount */
	lshd	r7,r5		/* shift out useless byte */
	movqb	0,r5		/* overwrite it */
	negb	r7,r7		/* shift back to where it was */
	lshd	r7,r5
	negb	r7,r7		/* restore shift to correct sense */
	br	rechk

/*  */

savtype:
	rotd	-8,r6		/* r6 has remembered current open type */
	movb	r5,r6		/* r5 is current command  */
	rotd	8,r6
	lprw	mod,r6		/* save for use after conversion */
	cmpb	SQ:^,r5		/* echo this command character */
	beq	echocmd		/* all rest will get echoed later */
	cmpb	SQ:@,r5		/* echo this command character */
	bne	convertinput	/* all rest will get echoed later */
echocmd:
	addr	convertinput,r6	/* echo command character then convert input */
	br	outc

reopen:
	addr	openecho,r6	/* echo open command character */
	br	outc		/* r5 has open command character */
openecho:
	lprd	mod,r5
	rotd	-8,r5
	cmpqb	0,r5
	beq	open
	rotd	8,r5
	br	convertinput	/* must have got an address */

/*  */

	/* for wierd characters */
	/* instead of throwing them away just echo a space */
	/* and push a space onto the input queue */
pushspc:
	movb	SPC,r5
	br	epushc

	#echo and then push onto the input queue
epushc:
	addr	chkqueue,r6
	br 	boutc
chkqueue: 			/* if next byte to be shifted out */
	cmpqb	0,r0		/* is zero we have room for one character */
	bne	fifovflow

	/* after pushing this input character go get another */
	addr	getc,r7

	/* push a character onto the input queue */
pushc:	
	rotd	8,r1
	movb	r1,r0
	rotd	-8,r0
	rotd	8,r2
	movb	r2,r1
	rotd	8,r3
	movb	r3,r2
	rotd	8,r4
	movb	r4,r3
	rotd	8,r5
	movb	r5,r4
	jump	0(r7)

/*  */

	/* erase a character from the input queue */
erase:	
	rotd	-8,r5
	cmpqb	0,r5		/* check if any characters in fifo */
	rotd	8,r5
	beq	getc		/* if none, just return */
	
	movb	BCKSPC,r5	/* print backspace, space, backspace */
	addr	erase1,r6
	br	boutc
erase1:
	movb	SPC,r5
	addr	backspace,r6
	br	boutc
backspace:
	movb	BCKSPC,r5
	addr	popc,r6
boutc:	br	outc

popc:				/* remove the last pushed character */
	movb	r4,r5
	rotd	-8,r5
	movb	r3,r4
	rotd	-8,r4
	movb	r2,r3
	rotd	-8,r3
	movb	r1,r2
	rotd	-8,r2
	movb	r0,r1
	rotd	-8,r1
	movqb	0,r0
	rotd	8,r0
	br	getc

/*  */

	/* get the first argument out of the fifo and put it into r4 */
	/* after fisrt forming it in r6 */

convertinput:
	movqd	0,r6

	/* move argument characters to head of fifo */
head5:
	cmpqb	0,r0		/* is top of fifo zero */
	beq	pump5		/* yes, then throw it away */
	cmpb	SPC,r0
	bne	conv5
pump5:
	movqb	0,r5

	/* check if the input fifo registers have any characters */
	cmpqd	0,r0
	bne	gotsome
	cmpqd	0,r1
	bne	gotsome
	cmpqd	0,r2
	bne	gotsome
	cmpqd	0,r3
	bne	gotsome
	cmpqd	0,r4
	bne	gotsome
	cmpqd	0,r5
	beq	svinr2		/* no more input */
gotsome:
	addr	head5,r7
	br	pushc
		
conv5:
	movb	r0,r5

	cmpb	r5,SQ:0
	blt	svinr4
	cmpb	r5,SQ:9
	ble	digitcv5
	cmpb	r5,SQ:A
	blt	svinr4
	cmpb	r5,SQ:F
	ble	atoxcv5
	br	svinr4
digitcv5:
	subb	0x30,r5
	br	shiftd5
atoxcv5:
	subb	0x37,r5
shiftd5:
	lshd	4,r6
	orb	r5,r6
	movqb	0,r5

	/* signify received valid hex char */
	bispsrw	PSR_S		/* switch to user stack */
	adjspb	-1		/* increment user stack pointer */
	bicpsrw	PSR_S		/* switch back to interrupt stack */

	addr	conv5,r7
	br	pushc

/*  */

	/* save first argument in r4 temporarily */
svinr4:
	movd	r6,r4
	movqd	0,r6

	/* get next arguments characters to head of the fifo */
head4:
	cmpb	SPC,r0
	bne	conv4
pump4:
	addr	head4,r7
push4c:
	rotd	8,r1
	movb	r1,r0
	rotd	-8,r0
	rotd	8,r2
	movb	r2,r1
	rotd	8,r3
	movb	r3,r2
	movqb	0,r3
	jump	0(r7)
conv4:
	movb	r0,r5
	cmpb	r5,SQ:0
	blt	svinr3
	cmpb	r5,SQ:9
	ble	digitcv4
	cmpb	r5,SQ:A
	blt	svinr3
	cmpb	r5,SQ:F
	ble	atoxcv4
	br	svinr3
digitcv4:
	subb	0x30,r5
	br	shiftd4
atoxcv4:
	subb	0x37,r5
shiftd4:
	lshd	4,r6
	orb	r5,r6
	movqb	0,r5

	addr	conv4,r7
	br	push4c

/*  */

	/* save second argument, convert third */
svinr3:
	movd	r6,r3
	movqd	0,r6

head3:
	cmpb	SPC,r0
	bne	conv3
pump3:
	addr	head3,r7
push3c:
	rotd	8,r1
	movb	r1,r0
	rotd	-8,r0
	rotd	8,r2
	movb	r2,r1
	movqb	0,r2
	jump	0(r7)

conv3:
	movb	r0,r5

	cmpb	r5,SQ:0
	blt	svinr2
	cmpb	r5,SQ:9
	ble	digitcv3
	cmpb	r5,SQ:A
	blt	svinr2
	cmpb	r5,SQ:F
	ble	atoxcv3
	br	svinr2
digitcv3:
	subb	0x30,r5
	br	shiftd3
atoxcv3:
	subb	0x37,r5
shiftd3:
	lshd	4,r6
	orb	r5,r6

	addr	conv3,r7
	br	push3c

/*  */

/* save third argument in r2 and move the arguments from their temporary */
/* places to r0 and r1 respectively to get ready for command execution */
svinr2:
	movd	r6,r2		/* arguemnt 3 */
	movd	r3,r1		/* argument 2 */
	movd	r4,r0		/* argument 1 */

	sprd	mod,r6
	cmpb	SQ:/,r6
	beq	opchk
	cmpb	SQ:\,r6
	beq	opchk
	cmpb	SQ:`,r6
	bne	docommand
opchk:
	rotd	-8,r6
	cmpb	SQ:+,r6
	beq	forward
	cmpb	SQ:-,r6
	beq	backward
	cmpb	CR,r6
	beq	wrt
	cmpb	LF,r6
	beq	nxtwrt
	cmpb	SQ:^,r6
	beq	prevwrt
	cmpb	SQ:@,r6
	beq	movtoloc
	lprd	fp,r0
	br	open

/*  */

	/* move the current location forward by the given input amount */
	/* else just use the default for the current size and move forward */
	/* that amount */
forward:
	movb	r6,r5
	addr	echoforw,r6
	br	outc
echoforw:
	cmpqb	0,r0
	beq	plusdef
	addr	0(fp),r6
	addd	r0,r6
	lprd	fp,r6
	br	opcrlf

plusdef:
	sprw	mod,r6
	cmpb	SQ:/,r6
	beq	plus4
	cmpb	SQ:\,r6
	beq	plus2
	cmpb	SQ:`,r6
	bne	error
plus1:
	addr	1(fp),r6
	lprd	fp,r6
	br	opcrlf
plus2:
	addr	2(fp),r6
	lprd	fp,r6
	br	opcrlf
plus4:
	addr	4(fp),r6
	lprd	fp,r6
	br	opcrlf

opcrlf:
	addr	open,r7		/* print carriage return - line feed */
	br	crlf		/* and jump to open */

/*  */

	/* move the current location back by the given input amount */
	/* else just backup the default current size  */
backward:
	movb	r6,r5
	addr	echoback,r6
	br	outc
echoback:
	cmpb	0,r0
	beq	minusdef
	addr	0(fp),r6
	subd	r0,r6
	lprd	fp,r6
	br	opcrlf
minusdef:
	sprw	mod,r6
	cmpb	SQ:/,r6
	beq	minus4
	cmpb	SQ:\,r6
	beq	minus2
	cmpb	SQ:`,r6
	bne	error
minus1:
	addr	-1(fp),r6
	lprd	fp,r6
	br	opcrlf
minus2:
	addr	-2(fp),r6
	lprd	fp,r6
	br	opcrlf
minus4:
	addr	-4(fp),r6
	lprd	fp,r6
	br	opcrlf

/*  */

	/* received a '^', write the current location if received input */
	/* in any case, advance to the previous location by the current size */
prevwrt:
	bispsrw	PSR_S		/* switch to user stack pointer */
	sprd	sp,r6
	bicpsrw	PSR_S		/* switch back to interrupt stack pointer */
	cmpqd	0,r6
	beq	minusdef
	addr	minusdef,r7
	br	wrtaloc

	/* received a LF, write the current location if received input */
	/* in any case, advance to the next location by the current size */
nxtwrt:
	bispsrw	PSR_S		/* switch to user stack pointer */
	sprd	sp,r6
	bicpsrw	PSR_S		/* switch back to interrupt stack pointer */
	cmpqd	0,r6
	beq	plusdef		/* write nothing, just advance pointer */
	addr	plusdef,r7	/* write and advance pointer */
	br	wrtaloc

	/* received a CR, write the location if recieved input */
	/* else just return to top level monitor */
wrt:
	bispsrw	PSR_S		/* switch to user stack pointer */
	sprd	sp,r6
	bicpsrw	PSR_S		/* switch back to interrupt stack pointer */
	cmpqd	0,r6
	beq	ramless_quiet
	addr	ramless_quiet,r7
	br	wrtaloc

/*  */

	/* write a location in memory using the correct current size */
wrtaloc:
	sprd	mod,r6		/* get current open type */
	cmpb	SQ:/,r6
	beq	wrtdouble
	cmpb	SQ:\,r6
	beq	wrtword
	cmpb	SQ:`,r6
	bne	error
wrtbyte:
	movb	r0,0(fp)
	br	r7ret
wrtword:
	movw	r0,0(fp)
	br	r7ret
wrtdouble:
	movd	r0,0(fp)
r7ret:
	jump	0(r7)

/* move the current open location to the contents at the current address */
/* implements the '@' option of open */
movtoloc:
	movd	0(fp),r6
	lprd	fp,r6
	br	opcrlf

/*  */

error:
	addr	errmsg,r5
	addr	getinpl,r7
	br	printm

errmsg:	.byte	CR,LF,SQ:?,SQ:?,0

fifovflow:
	addr	_fifomsg,r5
	addr	ramless_quiet,r7
	br	printm
