Coherent4.2.10/conf/mm/src/vtmmas.s

////////
/ sys/io.386/vtmmas.s
/ Memory mapped video driver assembler assist.
/ Almost identical to mmas.s, they should be kept in sync until merged.
////////

//////////
/
/ This module handles special characters and escape sequences
/ as described in ANSI X3.4-1977 and ANSI X3.64-1979.
/ It recognizes only a subset of the X3.64 sequences.
/ It handles some ASCII control characters (cf. asctab), as follows:
/	BEL			audible signal
/	BS			backspace
/	CR			carriage return
/	ESC			[see tables below]
/	FF			form feed
/	HT			horizontal tab
/	LF/NL			line feed/newline
/	VT			vertical tab
/ In the default font (font 0), other control characters are ignored
/ and all other ASCII characters are printed.
/ In font 1, all characters (including control chars) except ESC are printed.
/ In font 2, all characters except ESC are printed with the high bit toggled.
/ ASCII ESC introduces an escape sequence (cf. esctab), as follows:
/	ESC 7			save cursor position
/	ESC 8			restore cursor position
/	ESC =			enter alternate keypad (cf. kb.c)
/	ESC >			exit alternate keypad (cf. kb.c)
/	ESC D		IND	index
/	ESC E		NEL	next line
/	ESC M		RI	reverse index
/	ESC [		CSI	[see table below]
/	ESC `		DMI	disable manual input
/	ESC b		EMI	enable manual input
/	ESC c		RIS	reset to initial state
/	ESC t			enter numlock (cf. kb.c)
/	ESC u			exit numlock (cf. kb.c)
/ ESC [ (a.k.a. ANSI CSI) introduces a function (cf. csitab), as follows:
/	ESC [ > 13 h		enable CRT saver
/	ESC [ > 13 l		disable CRT saver
/	ESC [ ?	4 h		set smooth scroll
/	ESC [ ?	4 l		set jump scroll
/	ESC [ ?	7 h		enable wraparound
/	ESC [ ?	7 l		disable wraparound
/	ESC [ ?	8 h		set erase in current color even if reversed
/	ESC [ ?	8 l		set erase in original foreground color
/	ESC [ ?	25 h		enable line 25
/	ESC [ ?	25 l		disable line 25
/	ESC [ <n> @	ICH	insert character
/	ESC [ <n> A	CUU	cursor up
/	ESC [ <n> B	CUD	cursor down
/	ESC [ <n> C	CUF	cursor forward
/	ESC [ <n> D	CUB	cursor backward
/	ESC [ <n> E	CNL	cursor next line
/	ESC [ <n> F	CPL	cursor preceding line
/	ESC [ <n> G	CHA	cursor horizontal absolute
/	ESC [ <n;m> H	CUP	cursor position
/	ESC [ <n> I	CHT	cursor horizontal tabulation
/	ESC [ <n> J	ED	erase in display
/	ESC [ <n> K	EL	erase in line
/	ESC [ <n> L	IL	insert line
/	ESC [ <n> M	DL	delete line
/	ESC [ <n> O	EA	erase in area
/	ESC [ <n> P	DCH	delete character
/	ESC [ <n> S	SU	scroll up
/	ESC [ <n> T	SD	scroll down
/	ESC [ <n> X	ECH	erase character
/	ESC [ <n> Z	CBT	cursor backward tabulation
/	ESC [ <n> `	HPA	horizontal position absolute
/	ESC [ <n> a	HPR	horizontal position relative
/	ESC [ <n> d	VPA	vertical position absolute
/	ESC [ <n> e	VPR	vertical position relative
/	ESC [ <n;m> f	HVP	horizontal and vertical position
/ ESC [ <n1;...;nn> m	SGR	select graphic rendition (see details below)
/	ESC [ <n;m> r		set scrolling region
/	ESC [ <n> v		select cursor rendition (0=visible, 1=invisible)
/
//////////

////////
/
/ State driven code.
/
/ Register use:
/	DS:ESI	input string
/	ES:EDI	current screen location
/	FS:EBP	terminal information
/	AH	character attributes
/	AL	character
/	BH	(usually) kept zeroed for efficiency
/	CX	input count
/	DH	current row
/	DL	current column
/
////////

	.unixorder

/ Externals referenced by this module.
	.globl	islock
	.globl	vtmmbeeps
	.globl	vtmmvcnt
	.globl	vtmmcrtsav
	.globl	vtactive		/ index of currently active screen

/ Globals defined in this module.
	.globl	VIDSLOW			/ Patchable kernel variable
	.globl	vtmminit
	.globl	vtmmgo
	.globl	vtmm_voff
	.globl	vtmm_von
	.globl	vtds_sel

/ Definitions.

ATTR	.define	%ah			/ attribute byte
ROW	.define	%dh			/ currently active vertical position
COL	.define	%dl			/ currently active horizontal position
POS	.define	%edi			/ currently active display address

/ Manifest constants.

	.set	NCOL, 80		/ number of columns
	.set	NROW, 24		/ initial number of rows
	.set	NCR, 1			/ number of horizontal lines per char
	.set	NHB, 160		/ number of horizontal bytes per line
	.set	NRB, 160		/ number of bytes per character row(NCR*NHB)
	.set	MAXARGS, 8		/ max number of args in parameter list

	.set	MONO,		0x03B4	/ color port
	.set	COLOR,		0x03D4	/ color port
	.set	DEFATTR,	0x07	/ default attribute
	.set	UNDERLINE,	0x01	/ mono underline bit
	.set	CULATTR,	0x47	/ color underline attribute (wht/red)
	.set	INTENSE,	0x08	/ high intensity attribute bit
	.set	BLINK,		0x80	/ blinking attribute bit
	.set	TIMEOUT,	900	/ seconds before video disabled

	.set	SEG_386_UD,	0x10 	/ 32 bit user data segment descriptor
	.set	SEG_ROM,	0x40	/ ROM descriptor         @ F0000
	.set	SEG_VIDEOa,	0x48	/ 0x48: video descriptor @ B0000
	.set	SEG_VIDEOb,	0x50	/ 0x50: video descriptor @ B8000

/ Magic constants from <sys/io.h>.
	.set	IO_SEG, 0
	.set	IO_IOC, 4
	.set	IO_BASE, 12
	.set	IOSYS, 0
	.set	IOUSR, 1

/ Offsets corresponding to <sys/vt.h> VTDATA structure.
	.set	MM_FUNC,	0	/ current state
	.set	MM_PORT,	4	/ adapter base i/o port
	.set	MM_BASE,	8	/ adapter base memory address
	.set	MM_OFFSET,	12	/ offset within segment
	.set	MM_ROW,		16	/ screen row
	.set	MM_COL,		20	/ screen column
	.set	MM_POS,		24	/ screen position
	.set	MM_ATTR,	28	/ attributes
	.set	MM_N1,		32	/ numeric argument 1
	.set	MM_N2,		33	/ numeric argument 2
	.set	MM_NARGS,	40	/ arg count
	.set	MM_BROW,	44	/ base row
	.set	MM_EROW,	48	/ end row
	.set	MM_LROW,	52	/ legal row limit
	.set	MM_SROW,	56	/ saved cursor row
	.set	MM_SCOL,	60	/ saved cursor column
	.set	MM_IBROW,	64	/ initial base row
	.set	MM_IEROW,	68	/ initial end row
	.set	MM_INVIS,	72	/ cursor invisible mask
	.set	MM_SLOW,	76	/ slow [no flicker] video update
	.set	MM_WRAP,	80	/ wrap to start of next line
	.set	MM_EORIG,	81	/ erase in original foreground color
	.set	MM_OATTR,	84	/ original attribute
	.set	MM_FONT,	88	/ current font [012]
	.set	MM_ESC,		92	/ escape char. state
	.set	MM_VISIBLE,	96	/ set if screen is being displayed
	.set	MM_MSEG,	100	/ heap space copy
	.set	MM_MOFF,	104	/
	.set	MM_VSEG,	108	/ video memory
	.set	MM_VOFF,	112	/

////////
/
/ Data.
/
////////

	.data
VIDSLOW:.long	0

	.text
	.align	4

////////
/
/ Constant data tables (in .text segment).
/
////////

////////
/
/ asctab - table of functions indexed by ASCII character.
/ This is used for mapping control characters only.
/
////////

asctab:	.long	eval,	eval,	eval,	eval	/* NUL  SOH  STX  ETX  */
	.long	eval,	eval,	eval,	mm_bel	/* EOT  ENQ  ACK  BEL  */
	.long	mm_bs,	mm_ht,	mm_lf,	mm_vt	/* BS   HT   LF   VT   */
	.long	mm_ff,	mm_cr,	eval,	eval	/* FF   CR   SO   SI   */
	.long	eval,	eval,	eval,	eval	/* DLE  DC1  DC2  DC3  */
	.long	eval,	eval,	eval,	eval	/* DC4  NAK  SYN  ETB  */
	.long	eval,	eval,	eval,	mm_esc	/* CAN  EM   SUB  ESC  */
	.long	eval,	eval,	eval,	eval	/* FS   GS   RS   US   */

////////
/
/ esctab - table of functions indexed by character following ESC - 0x20.
/
////////

esctab:	.long	eval,	eval,	eval,	eval	/*   ! " # \040 - \043 */
	.long	eval,	eval,	eval,	eval	/* $ % & ' \044 - \047 */
	.long	eval,	eval,	eval,	eval	/* ( ) * + \050 - \053 */
	.long	eval,	eval,	eval,	eval	/* , - . / \054 - \057 */
	.long	eval,	eval,	eval,	eval	/* 0 1 2 3 \060 - \063 */
	.long	eval,	eval,	eval,	mm_new	/* 4 5 6 7 \064 - \067 */
	.long	mm_old,	eval,	eval,	eval	/* 8 9 : ; \070 - \073 */
	.long	eval,	mm_spc,	mm_spc,	eval	/* < = > ? \074 - \077 */
	.long	eval,	eval,	eval,	eval	/* @ A B C \100 - \103 */
	.long	mm_ind,	mm_nel,	eval,	eval	/* D E F G \104 - \107 */
	.long	eval,	eval,	eval,	eval	/* H I J K \110 - \113 */
	.long	eval,	mm_ri,	eval,	eval	/* L M N O \114 - \117 */
	.long	eval,	eval,	eval,	eval	/* P Q R S \120 - \123 */
	.long	eval,	eval,	eval,	eval	/* T U V W \124 - \127 */
	.long	eval,	eval,	eval,	csi	/* X Y Z [ \130 - \133 */
	.long	eval,	eval,	eval,	eval	/* \ ] ^ _ \134 - \137 */
	.long	mm_dmi,	eval,	mm_emi,	vtmminit	/* ` a b c \140 - \143 */
	.long	eval,	eval,	eval,	eval	/* d e f g \144 - \147 */
	.long	eval,	eval,	eval,	eval	/* h i j k \150 - \153 */
	.long	eval,	eval,	eval,	eval	/* l m n o \154 - \157 */
	.long	eval,	eval,	eval,	eval	/* p q r s \160 - \163 */
	.long	mm_spc,	mm_spc,	eval,	eval	/* t u v w \164 - \167 */
	.long	eval,	eval,	eval,	eval	/* x y z { \170 - \173 */
	.long	eval,	eval,	eval,	eval	/* | } ~ ? \174 - \177 */

////////
/
/ csitab - table of functions indexed by character following ESC [ <params>.
/
////////

csitab:	.long	eval,	eval,	eval,	eval	/* NUL  SOH  STX  ETX  */
	.long	eval,	eval,	eval,	eval	/* EOT  ENQ  ACK  BEL  */
	.long	eval,	eval,	eval,	eval	/* BS   HT   LF   VT   */
	.long	eval,	eval,	eval,	eval	/* FF   CR   SO   SI   */
	.long	eval,	eval,	eval,	eval	/* DLE  DC1  DC2  DC3  */
	.long	eval,	eval,	eval,	eval	/* DC4  NAK  SYN  ETB  */
	.long	eval,	eval,	eval,	eval	/* CAN  EM   SUB  ESC  */
	.long	eval,	eval,	eval,	eval	/* FS   GS   RS   US   */
	.long	eval,	eval,	eval,	eval	/*   ! " # \040 - \043 */
	.long	eval,	eval,	eval,	eval	/* $ % & ' \044 - \047 */
	.long	eval,	eval,	eval,	eval	/* ( ) * + \050 - \053 */
	.long	eval,	eval,	eval,	eval	/* , - . / \054 - \057 */
	.long	eval,	eval,	eval,	eval	/* 0 1 2 3 \060 - \063 */
	.long	eval,	eval,	eval,	eval	/* 4 5 6 7 \064 - \067 */
	.long	eval,	eval,	eval,	eval	/* 8 9 : ; \070 - \073 */
	.long	eval,	eval,	csi_gt,	csi_q	/* < = > ? \074 - \077 */
	.long	mm_ich,	mm_cuu,	mm_cud,	mm_cuf	/* @ A B C \100 - \103 */
	.long	mm_cub,	mm_cnl,	mm_cpl,	mm_cha	/* D E F G \104 - \107 */
	.long	mm_cup,	mm_cht,	mm_ed,	mm_el	/* H I J K \110 - \113 */
	.long	mm_il,	mm_dl,	eval,	mm_ea	/* L M N O \114 - \117 */
	.long	mm_dch,	eval,	eval,	mm_su	/* P Q R S \120 - \123 */
	.long	mm_sd,	eval,	eval,	eval	/* T U V W \124 - \127 */
	.long	mm_ech,	eval,	mm_cbt,	eval	/* X Y Z [ \130 - \133 */
	.long	eval,	eval,	eval,	eval	/* \ ] ^ _ \134 - \137 */
	.long	mm_hpa,	mm_hpr,	eval,	eval	/* ` a b c \140 - \143 */
	.long	mm_vpa,	mm_vpr,	mm_hvp,	eval	/* d e f g \144 - \147 */
	.long	eval,	eval,	eval,	eval	/* h i j k \150 - \153 */
	.long	eval,	mm_sgr,	eval,	eval	/* l m n o \154 - \157 */
	.long	eval,	eval,	mm_ssr,	eval	/* p q r s \160 - \163 */
	.long	eval,	eval,	mm_scr,	eval	/* t u v w \164 - \167 */
	.long	eval,	eval,	eval,	eval	/* x y z { \170 - \173 */
	.long	eval,	eval,	eval,	eval	/* | } ~ ? \174 - \177 */

////////
/
/ rowtab - array of offsets to each display row.
/
////////

rowtab:	.long	NRB *  0,	NRB *  1,	NRB *  2,	NRB *  3
	.long	NRB *  4,	NRB *  5,	NRB *  6,	NRB *  7
	.long	NRB *  8,	NRB *  9,	NRB * 10,	NRB * 11
	.long	NRB * 12,	NRB * 13,	NRB * 14,	NRB * 15
	.long	NRB * 16,	NRB * 17,	NRB * 18,	NRB * 19
	.long	NRB * 20,	NRB * 21,	NRB * 22,	NRB * 23
	.long	NRB * 24,	NRB * 25,	NRB * 26,	NRB * 27
	.long	NRB * 28,	NRB * 29,	NRB * 30,	NRB * 31

////////
/
/ fcolor - foreground color
/ bcolor - background color
/
/ Indexed by ANSI color (black,red,green,brown,blue,magenta,cyan,white)
/ to get graphics color (black,blue,green,cyan,red,magenta,brown,white)
/ which is properly preshifted for installation in attribute byte.
/
////////

fcolor:	.byte	0x00, 0x04, 0x02, 0x06, 0x01, 0x05, 0x03, 0x07
bcolor:	.byte	0x00, 0x40, 0x20, 0x60, 0x10, 0x50, 0x30, 0x70

////////
/
/ Global functions.
/
////////

////////
/
/ vtmminit - initialize screen
/
////////
vtmminit:
	movw	%fs:MM_BASE(%ebp),%es
	movb	$0x63,%fs:MM_ESC(%ebp)		/ schedule keyboard initialization
	movl	%fs:MM_BASE(%ebp),%edx
	movw	%dx,%es
	movw	%fs:MM_BASE(%ebp),%dx
	cmpb	$0,%fs:MM_VISIBLE(%ebp)
	jne	vtmminit0

	movl	%fs:MM_PORT(%ebp),%edx		/ turn video off
	addl	$4,%edx
	movb	$0x21,%al
	outb	(%dx)

	movl	%fs:MM_PORT(%ebp),%edx		/ zero display offset
	movb	$12,%al
	outb	(%dx)
	incl	%edx
	subb	%al,%al
	outb	(%dx)
	decl	%edx
	movb	$13,%al
	outb	(%dx)
	incl	%edx
	subb	%al,%al
	outb	(%dx)

	movl	%fs:MM_PORT(%ebp),%edx		/ reset border to black
	addl	$5,%edx
	subb	%al,%al
	outb	(%dx)

	incl	%edx				/ reset TECMAR XMSR register
	outb	(%dx)

vtmminit0:
	movl	$0,%fs:MM_INVIS(%ebp)
	movb	$DEFATTR,ATTR
	movb	ATTR,%fs:MM_ATTR(%ebp)
	movb	ATTR,%fs:MM_OATTR(%ebp)
	movb	$1,%fs:MM_WRAP(%ebp)
	movb	%fs:MM_IBROW(%ebp),ROW
	movb	ROW,%fs:MM_BROW(%ebp)
	movb	%fs:MM_IEROW(%ebp),%bl
	movb	%bl,%fs:MM_EROW(%ebp)
	subl	%ebx,%ebx
	jmp	mm_ff

////////
/
/ vtmmgo( iop, vp, index )
/ IO *iop;
/ VTDATA *vp;
/ int index;
/
////////

	.set	FRAME,32			/ ra, bx, si, di, ds, es, fs, bp

vtmmgo:
	push	%ebx
	push	%esi
	push	%edi
	push	%ds
	push	%es
	push	%fs
	push	%ebp
	movl	%esp,%ebp

	push	%ds				/ copy ds to fs
	pop	%fs

	cld
	movl	FRAME+0(%ebp),%ebx		/ iop
	movl	IO_BASE(%ebx),%esi		/ iop->io_base
	movl	IO_IOC(%ebx),%ecx		/ iop->io_ioc

	cmpl	$IOSYS,IO_SEG(%ebx)		/ user address space
	je	?vtmmgo1
	movl	$SEG_386_UD,%eax
	movw	%ax,%ds
?vtmmgo1:
	movl	FRAME+4(%ebp),%ebp		/ vtp
	movl	$0,%edx				/ assume not visible
	cmpb	$0,%fs:MM_VISIBLE(%ebp)		/ if this is the case, then
	je	?vtmmgo4				/ don't mess with the video hw
	movl	%fs:MM_PORT(%ebp),%edx		/ turn video off if color board
	cmpl	$MONO,%edx
	je	?vtmmgo4
	cmpb	$0,%fs:MM_SLOW(%ebp)		/ check for slow [flicker-free]
	je	?vtmmgo3

	movl	$0x3DA,%edx
?vtmmgo2:	inb	(%dx)				/ wait for vertical retrace
	testb	$8,%al
	je	?vtmmgo2
?vtmmgo3:
	movl	$0x3D8,%edx			/ disable video
	movb	$0x25,%al
	outb	(%dx)
?vtmmgo4:
	movb	%fs:MM_ROW(%ebp),ROW
	movb	%fs:MM_COL(%ebp),COL
	movw	%fs:MM_BASE(%ebp),%es
	movl	%fs:MM_POS(%ebp),POS
	subl	%ebx,%ebx
	movb	%fs:MM_ATTR(%ebp),ATTR
	ijmp	%fs:MM_FUNC(%ebp)

exit:	pop	%ebx
	movl	%ebx,%fs:MM_FUNC(%ebp)
	movb	ATTR,%fs:MM_ATTR(%ebp)
	movb	ROW,%fs:MM_ROW(%ebp)		/ save row,column
	movb	COL,%fs:MM_COL(%ebp)
	movl	POS,%fs:MM_POS(%ebp)		/ save position

/ Update the cursor only on the screen associated with the keyboard.
	movl	%fs:vtactive,%edx
	cmpl	FRAME+8(%esp),%edx		/ "index" - 3rd arg.
	jne	exit0

	movl	%fs:MM_PORT(%ebp),%edx		/ adjust cursor location
	movl	POS,%ebx
	addl	%fs:MM_OFFSET(%ebp),%ebx	/ adjust to screen
	orl	%fs:MM_INVIS(%ebp),%ebx
	shrl	$1,%ebx

	movb	$14,%al
	outb	(%dx)
	incl	%edx
	movb	%bh,%al
	outb	(%dx)
	decl	%edx
	movb	$15,%al
	outb	(%dx)
	incl	%edx
	movb	%bl,%al
	outb	(%dx)

exit0:
	movl	%fs:MM_PORT(%ebp),%edx		/ turn video on
	cmpb	$0,%fs:MM_VISIBLE(%ebp)		/ iff screen is visible
	je	exit1

	addl	$4,%edx
	movb	$0x29,%al
	outb	(%dx)
	movl	$TIMEOUT,%fs:vtmmvcnt		/ TIMEOUT seconds before video disabled

exit1:
	movl	FRAME+0(%esp),%ebx		/ iop
	movl	%ecx,%eax
	xchg	%ecx,%fs:IO_IOC(%ebx)
	subl	%fs:IO_IOC(%ebx),%ecx
	addl	%ecx,%fs:IO_BASE(%ebx)

	/ ra, bx, si, di, ds, es, fs, bp
	pop	%ebp
	pop	%fs
	pop	%es
	pop	%ds
	pop	%edi
	pop	%esi
	pop	%ebx
	ret

////////
/
/ vtmm_voff(vp)	-- turn video display off
/ VTDATA *vp;
/
////////

vtmm_voff:
	movb	$0x21,%al
	jmp	vtmm_von1

////////
/
/ vtmm_von(vp)	-- turn video display on
/ VTDATA *vp;
/
////////

vtmm_von:
	movl	$TIMEOUT,vtmmvcnt			/ TIMEOUT seconds before video disabled
	movb	$0x29,%al
vtmm_von1:
	push	%ebp
	movl	%esp,%ebp
	movl	8(%ebp),%ebp			/ VTERM *
	movl	%ds:MM_PORT(%ebp),%edx
	addl	$4,%edx
	outb	(%dx)
	pop	%ebp
	ret

////////
/
/ vtds_sel() - return DS in EAX.
/
////////

vtds_sel:
	movl	$0,%eax
	movw	%ds,%ax
	ret

////////
/
/ Local functions.
/
////////

////////
/
/ alx10pbl: return AL * 10 + BL in AL.
/ The result is a byte quantity, overflow is ignored.
/
////////

alx10pbl:
	movb	%al,%bh
	shlb	$2,%al			/ n1 * 4
	addb	%bh,%al			/ n1 * 5
	shlb	$1,%al			/ n1 * 10
	addb	%bl,%al			/ n1 * 10 + digit
	subb	%bh,%bh			/ clear bh
	ret

////////
/
/ blankncol: Blank $NCOL characters at the current screen location.
/ blank: Blank ECX characters at the current screen location.
/ blanklines: Blank BL lines at the current screen location.
/ The blank characters use the original attribute,
/ i.e. they are not reverse video even if the state is reversed.
/
////////

blankncol:
	movl	$NCOL,%ecx
blank:	push	%eax				/ save current attribute
	cmpb	$0,%fs:MM_EORIG(%ebp)
	je	?blank1
	movb	%fs:MM_OATTR(%ebp),ATTR		/ get original attribute
?blank1:
	movb	$' ',%al
	addl	%fs:MM_OFFSET(%ebp),%edi
	rep
	stosw
	subl	%fs:MM_OFFSET(%ebp),%edi
	pop	%eax				/ restore current attribute
	ret

blanklines:
	push	%ecx
?blank1:
	call	blankncol
	decb	%bl
	jg	?blank1
	pop	%ecx
	ret

////////
/
/ copyf: copy display forward.
/ copyb: copy display backward.
/ Arguments:
/	EDI	destination address
/	EBX	offset
/	ECX	byte count (assumed even)
/
////////

copyf:
	push	%ds
	push	%esi
	push	%edi
	movw	%fs:MM_BASE(%ebp),%ds
	movl	%edi,%esi
	addl	%ebx,%esi
copyf1:
	shrl	$1,%ecx			/ word count
	addl	%fs:MM_OFFSET(%ebp),%edi
	addl	%fs:MM_OFFSET(%ebp),%esi
	rep
	movsw
	cld
	subl	%ebx,%ebx
	pop	%edi
	pop	%esi
	pop	%ds
	ret

copyb:
	push	%ds
	push	%esi
	push	%edi
	movw	%fs:MM_BASE(%ebp),%ds
	movl	%edi,%esi
	subl	%ebx,%esi
	addl	%ecx,%edi
	addl	%ecx,%esi
	subl	$2,%edi
	subl	$2,%esi
	std
	jmp	copyf1

////////
/
/ getn1: get first parameter to BL.
/ If the parameter is 0, adjust it to 1.
/
////////

getn1:	movb	%fs:MM_N1(%ebp),%bl
	orb	%bl,%bl
	jne	?getn1a
	incb	%bl
?getn1a:
	ret

////////
/
/ getrow: get row number from first parameter to ROW.
/ Adjust parameter n to row n-1, except 0 means row 0.
/
////////

getrow:	movb	%fs:MM_N1(%ebp),ROW
	decb	ROW
	jge	?getrow1
	subb	ROW,ROW
?getrow1:
	ret

////////
/
/ repos - reposition cursor, i.e. recompute POS from ROW and COL
/
////////

repos:	movb	COL,%bl			/ reposition to ROW and COL
	lea	(,%ebx,2),POS		/ COL * 2
	movb	ROW,%bl
	addl	%cs:rowtab(,%ebx,4),POS	/ POS = 160 * ROW + 2 * COL
	jmp	eval

////////
/
/ Ewait - wait for next input char to evaluate
/
/ eval - evaluate input character
/
////////

ewait:
	call	exit
eval:
	jcxz	ewait			/ no more characters
	decl	%ecx			/ decrement count
	lodsb				/ char to AL
	cmpb	$0,%fs:MM_FONT(%ebp)	/ font 0?
	jne	?eval2
?eval1:	cmpb	$0x20,%al		/ font 0
	jae	mmputc			/ write characters 0x20-0xFF
	movb	%al,%bl
	ijmp	%cs:asctab(,%ebx,4)	/ process controls 0x00-0x1F

?eval2:	cmpb	$0x1B,%al		/ watch for ESC
	je	?eval1			/ process ESC regardless of font
	cmpb	$1,%fs:MM_FONT(%ebp)	/ font 1?
	je	mmputc			/ font 1, write all chars as is
	cmpb	$2,%fs:MM_FONT(%ebp)	/ font 2?
	jne	?eval1			/ not font [012], treat as 0
	xorb	$0x80,%al		/ font 2, toggle high bit
/	jmp	mmputc			/ and display

////////
/
/ mmputc - put character in al on screen
/
////////

mmputc:
	addl	%fs:MM_OFFSET(%ebp),POS	/ adjust for screen
	stosw				/ Update display memory.
	subl	%fs:MM_OFFSET(%ebp),POS	/ adjust for screen
	incb	COL
	cmpb	$NCOL,COL		/ Past end of line?
	jl	eval			/ Not past
	cmpb	$0,%fs:MM_WRAP(%ebp)	/ Yes past, Wrap around?
	jne	?nextline
	subl	$2,POS			/ No wrap, adjust back to end of line.
	decb	COL
	jmp	eval

?nextline:
	subb	COL,COL			/ Wrap to next line.
next1:	incb	ROW
	cmpb	%fs:MM_EROW(%ebp),ROW	/ Past scrolling region?
	jle	eval			/ Not past
	movb	%fs:MM_EROW(%ebp),ROW	/ Yes past, scroll up 1 line.
/	jmp	scrollup

////////
/
/ scrollup - scroll display upwards
/
////////

scrollup:
	push	%ecx
	movb	%fs:MM_BROW(%ebp),%bl
	movl	%cs:rowtab(,%ebx,4),%edi	/ destination
	movb	ROW,%bl
	movl	%cs:rowtab(,%ebx,4),%ecx	/ start of current row
	push	%ecx
	subl	%edi,%ecx		/ bytes to shift
	movl	$NHB,%ebx		/ offset
	call	copyf			/ shift
	pop	%edi
	call	blankncol		/ blank current row
	pop	%ecx
	movb	COL,%bl			/ reposition to ROW and COL
	lea	(,%ebx,2),POS		/ COL * 2
	movb	ROW,%bl
	addl	%cs:rowtab(,%ebx,4),POS
	jmp	ewait

////////
/
/ Esc state - entered when last char was ESC - transient state.
/
////////

mm_esc0:
	call	exit
mm_esc:	jcxz	mm_esc0
	decl	%ecx
	lodsb				/ character to AL
	movb	%al,%bl
	subb	$0x20,%bl
	cmpb	$0x80-0x20,%bl
	jae	mmputc
	ijmp	%cs:esctab(,%ebx,4)

////////
/
/ Csi state - entered when last two chars were ESC [
/
/ Get ANSI X3.64 parameter list arguments.
/ The arguments have the format
/	p1;p2;...pn
/ where each parameter is a possibly empty string of ASCII digits [0-9].
/ Store the arguments starting at MM_N1 and the arg count at MM_NARGS;
/ empty parameters have default value 0.
/ Parameters are assumed to fit into bytes, values above 255 will not work.
/ Return the next character after the parameter list in AL.
/ If more than MAXARGS parameters are given, the extras get eaten.
/
////////

csi:
	movl	$0,%fs:MM_N1(%ebp)	/ initialize args 1 to 4
	movl	$0,%fs:MM_N1+4(%ebp)	/ initialize args 5 to 8
	movl	$1,%fs:MM_NARGS(%ebp)	/ initialize arg count
	jmp	csi1

csi0:
	call	exit
csi1:
	jcxz	csi0			/ no more characters
	decl	%ecx			/ decrement count
	lodsb				/ char to AL
	cmpb	$';',%al
	je	csi3			/ semi means another parameter follows
	movb	%al,%bl
	subb	$'0',%bl
	cmpb	$9,%bl
	jna	csi2			/ digit
csival:
	movb	%al,%bl			/ nondigit
	shlb	$1,%bl
	jc	mmputc			/ write high-bit characters
	ijmp	%cs:csitab(,%ebx,2)	/ process others via csitab

csi2:					/ add digit in BL into current parameter
	push	%edi
	lea	MM_N1-1(%ebp),%edi	/ address of 0th parameter
	addl	%fs:MM_NARGS(%ebp),%edi	/ + arg count = address of current param
	movb	%fs:(%edi),%al		/ current parameter value to AL
	call	alx10pbl
	movb	%al,%fs:(%edi)		/ pn = (pn * 10) + digit
	pop	%edi
	jmp	csi1			/ look for more digits or params

csi3:					/ prepare for next parameter after semi
	cmpl	$MAXARGS,%fs:MM_NARGS(%ebp)
	jae	csi5			/ too many parameters, oops
	incl	%fs:MM_NARGS(%ebp)	/ bump parameter count
	jmp	csi1			/ and look for more digits or params

csi4:
	call	exit
csi5:					/ too many parameters, eat remaining
	jcxz	csi4			/ no more characters
	decl	%ecx			/ decrement count
	lodsb				/ char to AL
	cmpb	$';',%al
	je	csi5			/ semi means another parameter follows
	movb	%al,%bl
	subb	$'0',%bl
	cmpb	$9,%bl
	jna	csi5			/ digit
	jmp	csival			/ nondigit, process as above

////////
/
/ Csi_gt state - entered after input sequence ESC [ >
/	
////////

csi_gt0:
	call	exit
csi_gt:	jcxz	csi_gt0
	decl	%ecx
	lodsb
	movb	%al,%bl
	subb	$'0',%bl
	cmpb	$9,%bl
	ja	?csi_gt1
	movb	%fs:MM_N1(%ebp),%al
	call	alx10pbl
	movb	%al,%fs:MM_N1(%ebp)	/ n1 = (n1 * 10) + digit
	jmp	csi_gt

?csi_gt1:
	cmpb	$'h',%al
	je	mm_cgh
	cmpb	$'l',%al
	je	mm_cgl
	jmp	eval

////////
/
/ Csi_q state - entered after input sequence ESC [ ?
/	
////////

csi_q0:
	call	exit
csi_q:	jcxz	csi_q0
	decl	%ecx
	lodsb
	movb	%al,%bl
	subb	$'0',%bl
	cmpb	$9,%bl
	ja	?csi_q1
	movb	%fs:MM_N1(%ebp),%al
	call	alx10pbl
	movb	%al,%fs:MM_N1(%ebp)	/ n1 = (n1 * 10) + digit
	jmp	csi_q

?csi_q1:
	cmpb	$'h',%al
	je	mm_cqh
	cmpb	$'l',%al
	je	mm_cql
	jmp	eval

////////
/
/ mm_bel - schedule beep
/
////////

mm_bel:	movb	$-1,%fs:vtmmbeeps
	jmp	eval

////////
/
/ mm_bs - backspace
/
////////

mm_bs:	movb	$1,%bl
	jmp	mm_cub1

////////
/
/ mm_cbt - cursor backward tabulation
/
/	Moves the active position horizontally in the backward direction
/	to the preceding in a series of predetermined positions.
/
////////

mm_cbt:	call	getn1
	salb	$3,%bl			/ n1 * 8 = distance to move
	addb	$7,COL
	andb	$0xF8,COL		/ calculate next tab stop
	subb	%bl,COL			/ step back
	jge	?mm_cbt1
	subb	COL,COL			/ can't step past column 0
?mm_cbt1:
	jmp	repos

////////
/
/ mm_cgh - process 'ESC [ > N1 h' escape sequence
/
/	Recognized sequences:	ESC [ > 13 h	-- Set CRT saver enabled.
/
////////

mm_cgh:	movl	$1,%ebx
mm_cgh1:
	cmpb	$13,%fs:MM_N1(%ebp)
	jne	?mm_cgh2
	movl	%ebx,%fs:vtmmcrtsav
?mm_cgh2:
	jmp	eval

////////
/
/ mm_cgl - process 'ESC [ > N1 l' escape sequence
/
/	Recognized sequences:	ESC [ > 13 l	-- Reset CRT saver.
/
////////

mm_cgl:	subl	%ebx,%ebx
	jmp	mm_cgh1

////////
/
/ mm_cht - cursor horizontal tabulation
/
/	Advances the active position horizontally to the next or following
/	in a series of predetermined positions.
/
////////

mm_cht:	call	getn1
mm_cht1:
	salb	$3,%bl			/ n1 * 8 = distance to move
	push	%ecx
	subl	%ecx,%ecx
	movb	COL,%cl
	andb	$7,%cl
	subb	%cl,%bl			/ distance from current position
	movb	%bl,%cl
	addb	%cl,COL
	call	blank
	pop	%ecx
	cmpb	$NCOL,COL
	jb	eval
	subb	$NCOL,COL
	jmp	next1

////////
/
/ mm_cnl - cursor next line
/
/	Moves the active position to the first position of the next display line.
/	Scrolls the active display if necessary.
/
////////

mm_cnl:	subb	COL,COL
	call	getn1
	addb	%bl,ROW
	jmp	mm_ind1

////////
/
/ mm_cpl - cursor preceding line
/
/	Moves the active position to the first position of the preceding
/	display line.
/
////////

mm_cpl:	subb	COL,COL
	call	getn1
	subb	%bl,ROW
mm_cpl1:
	cmpb	%fs:MM_BROW(%ebp),ROW
	jge	repos
	movb	%fs:MM_BROW(%ebp),ROW
	movb	$1,%bl
	jmp	mm_il1

////////
/
/ mm_cqh - process 'ESC [ ? N1 h' escape sequence
/
/	Recognized sequences:	ESC [ ? 4 h	-- Set smooth scroll.
/				ESC [ ? 7 h	-- Set wraparound.
/				ESC [ ? 8 h	-- Erase in current foreground
/				ESC [ ? 25 h	-- Enable line 25.
/
////////

mm_cqh:
	cmpb	$25,%fs:MM_N1(%ebp)	/ enable line 25
	je	mm_cqh25
	movb	$1,%bl			/ flag 1 to BL
mm_cqh1:				/ flag in BL, 0 or 1
	cmpb	$4,%fs:MM_N1(%ebp)	/ Smooth scroll.
	jne	?mm_cqh2
	movb	%bl,%fs:MM_SLOW(%ebp)
?mm_cqh2:
	cmpb	$7,%fs:MM_N1(%ebp)	/ Wraparound.
	jne	?mm_cqh3
	movb	%bl,%fs:MM_WRAP(%ebp)
?mm_cqh3:
	cmpb	$8,%fs:MM_N1(%ebp)	/ original foreground erase
	jne	?mm_cqh4
	movb	%bl,%fs:MM_EORIG(%ebp)
?mm_cqh4:
	jmp	eval
mm_cqh25:
	movb	$NROW+1,%fs:MM_LROW(%ebp)	/ set row limit 25
	movb	$NROW,%fs:MM_IEROW(%ebp)	/ set initial end row 24
	cmpb	$NROW-1,%fs:MM_EROW(%ebp)
	jne	?mm_cqh25a			/ current end row not 23, leave it
	incb	%fs:MM_EROW(%ebp)		/ set end row to 24
?mm_cqh25a:
	jmp	eval

////////
/
/ mm_cql - process 'ESC [ ? N1 l' escape sequence
/
/	Recognized sequences:	ESC [ ? 4 l	-- Set jump scroll.
/				ESC [ ? 7 l	-- Reset wraparound.
/				ESC [ ? 8 l	-- Erase in original foreground
/				ESC [ ? 25 l	-- Disable line 25.
/
////////

mm_cql:
	cmpb	$25,%fs:MM_N1(%ebp)	/ disable line 25
	je	?mm_cql25
	subb	%bl,%bl			/ flag 0 to BL
	jmp	mm_cqh1			/ use ESC ? n h code with flag reset
?mm_cql25:
	movb	$NROW,%fs:MM_LROW(%ebp)		/ set row limit 24
	movb	$NROW-1,%fs:MM_IEROW(%ebp)	/ set initial end row 23
	cmpb	$NROW,%fs:MM_EROW(%ebp)
	jne	?mm_cql25a		/ current end row not 24, leave it
	decb	%fs:MM_EROW(%ebp)	/ set end row to 23
?mm_cql25a:
	cmpb	$NROW,ROW		/ check if on last line
	jne	eval
	decb	ROW
	jmp	repos			/ reposition cursor to previous row

////////
/
/ mm_cr - carriage return
/
/	Moves the active position to first position of current display line.
/
////////

mm_cr:	subb	COL,COL
	movb	ROW,%bl
	movl	%cs:rowtab(,%ebx,4),POS
	jmp	eval

////////
/
/ mm_cub - cursor backwards
/
////////

mm_cub:	call	getn1
mm_cub1:
	cmpb	COL,%bl
	ja	?mm_cub2		/ back up to preceding line
	subb	%bl,COL
	jmp	repos

?mm_cub2:
	subb	COL,%bl			/ adjust count for current line
	decb	%bl			/ to last column of preceding line
	movb	$NCOL-1,COL
	decb	ROW
	cmpb	%fs:MM_BROW(%ebp),ROW
	jge	mm_cub1			/ still in the screen, keep trying
	subb	COL,COL
	movb	%fs:MM_BROW(%ebp),ROW
	jmp	repos

////////
/
/ mm_cud - cursor down
/
/	Moves the active position downward without altering the
/	horizontal position.
/
////////

mm_cud:	call	getn1
	addb	%bl,ROW
	cmpb	%fs:MM_EROW(%ebp),ROW
	jna	?mm_cud1
	movb	%fs:MM_EROW(%ebp),ROW
?mm_cud1:
	jmp	repos			/ reposition cursor

////////
/
/ mm_cuf - cursor forward
/
/	Moves the active position in the forward direction.
/
////////

mm_cuf:	call	getn1
	addb	%bl,COL
?mm_cuf1:
	cmpb	$NCOL,COL
	jb	?mm_cuf2
	subb	$NCOL,COL
	incb	ROW
	cmpb	%fs:MM_EROW(%ebp),ROW
	jna	?mm_cuf1
	movb	%fs:MM_EROW(%ebp),ROW
	movb	$NCOL-1,COL
?mm_cuf2:
	jmp	repos

////////
/
/ mm_cup - cursor position
/
/	Moves the active position to the position specified by two parameters.
/	The first parameter (mm_n1) specifies the vertical position (%fs:MM_ROW(%ebp)).
/	The second parameter (mm_n2) specifies the horizontal position (%fs:MM_COL(%ebp)).
/	A parameter value of 0 or 1 for the first or second parameter
/	moves the active position to the first line or column in the
/	display respectively.
/
////////

mm_cup:	call	getrow
/	addb	%fs:MM_BROW(%ebp),ROW
	cmpb	%fs:MM_EROW(%ebp),ROW
	jna	mm_cup1
	movb	%fs:MM_EROW(%ebp),ROW
mm_cup1:
	movb	%fs:MM_N2(%ebp),COL
	jmp	mm_hpa1

////////
/
/ mm_cuu - cursor up
/
/	Moves the active position upward without altering the horizontal
/	position.
/
////////

mm_cuu:	call	getn1
	subb	%bl,ROW
	cmpb	%fs:MM_BROW(%ebp),ROW
	jge	?mm_cuu1
	movb	%fs:MM_BROW(%ebp),ROW
?mm_cuu1:
	jmp	repos			/ reposition cursor

////////
/
/ mm_dch - delete characters
/
////////

mm_dch:	call	getn1
	movb	%bl,%al			/ characters to delete
	push	%ecx
	movb	ROW,%bl			/ current row
	movl	%cs:rowtab+4(,%ebx,4),%ecx	/ start of next row
	subl	POS,%ecx		/ characters left in this row * 2
	movb	%al,%bl
	shll	$1,%ebx			/ characters to delete * 2
	subl	%ebx,%ecx		/ byte count to ECX
	jle	?dch2			/ tried to delete too many, ignore
	push	%ecx
	call	copyf
	pop	%ecx
	addl	%ecx,POS		/ destination to blank
	movzxb	%al,%ecx		/ chars to blank
	call	blank
?dch2:
	pop	%ecx
	jmp	repos			/ reposition cursor

////////
/
/ mm_dl - delete line
/
/	Removes the contents of the active line.
/	The contents of all following lines are shifted in a block
/	toward the active line.
/
////////

mm_dl:
	call	getn1
	push	%ecx
	movb	%bl,%al			/ lines to delete to AL
	movb	ROW,%bl
	jmp	mm_su1

////////
/
/ mm_dmi - disable manual input
/
/	Set flag preventing keyboard input, and causing cursor to vanish.
/
////////

mm_dmi:
	movl	$1,%fs:islock
	jmp	eval

////////
/
/ mm_ea - erase in area
/
/	Erase some or all of the characters in the currently active area
/	according to the parameter:
/		0 - erase from active position to end inclusive (default)
/		1 - erase from start to active position inclusive
/		2 - erase all of active area
/
////////

mm_ea:	movb	%fs:MM_N1(%ebp),%al
	cmpb	$0,%al
	jne	?mm_ea1
	movb	%fs:MM_EROW(%ebp),%bl
	jmp	mm_el0
?mm_ea1:
	cmpb	$1,%al
	jne	mm_ea2
	movb	%fs:MM_BROW(%ebp),%bl
	jmp	mm_el1
mm_ea2:
	subb	COL,COL
	movb	%fs:MM_BROW(%ebp),ROW
	movb	ROW,%bl
	movl	%cs:rowtab(,%ebx,4),POS
	movb	%fs:MM_EROW(%ebp),%bl
	subb	ROW,%bl
	incb	%bl			/ rows to erase
	jmp	mm_ff1

////////
/
/ mm_ech - erase characters
/
////////

mm_ech:	call	getn1
	movb	%bl,%al			/ characters to erase
	movb	ROW,%bl			/ current row
	push	%ecx
	movl	%cs:rowtab+4(,%ebx,4),%ecx	/ start of next row
	subl	POS,%ecx		/ characters left in this row * 2
	shrl	$1,%ecx			/ characters left in this row
	cmpb	%cl,%al
	ja	?ech2			/ tried to erase too many, ignore
	movzxb	%al,%ecx		/ chars to erase
	call	blank			/ blank n characters
?ech2:
	pop	%ecx
	jmp	repos			/ reposition cursor

////////
/
/ mm_ed - erase in display
/
/	Erase some or all of the characters in the display according to the
/	parameter
/		0 - erase from active position to end inclusive (default)
/		1 - erase from start to active position inclusive
/		2 - erase all of display
/
////////

mm_ed:	movb	%fs:MM_N1(%ebp),%al
	cmpb	$0,%al
	jne	?mm_ed1
	movb	%fs:MM_LROW(%ebp),%bl
	decb	%bl
	jmp	mm_el0
?mm_ed1:
	cmpb	$1,%al
	jne	mm_ff
	subb	%bl,%bl
	jmp	mm_el1

////////
/
/ mm_el - erase in line
/
/	Erase some or all of the characters in the line according to the
/	parameter:
/		0 - erase from active position to end inclusive (default)
/		1 - erase from start to active position inclusive
/		2 - erase entire line
/
////////

mm_el:	movb	%fs:MM_N1(%ebp),%al
	movb	ROW,%bl
	cmpb	$0,%al
	je	mm_el0
	cmpb	$1,%al
	je	mm_el1
	movl	%cs:rowtab(,%ebx,4),POS
	subb	COL,COL
	movb	$1,%bl
	jmp	mm_ff1

mm_el1:	push	%ecx
	movl	POS,%ecx
	movl	%cs:rowtab(,%ebx,4),POS
mm_el1a:
	subl	POS,%ecx
	jl	?mm_el1b
	shrl	$1,%ecx
	call	blank
?mm_el1b:
	pop	%ecx
	jmp	repos

mm_el0:	push	%ecx
	movl	%cs:rowtab+4(,%ebx,4),%ecx
	jmp	mm_el1a

////////
/
/ mm_emi - enable manual input
/
/	Clear flag preventing keyboard input.
/
////////

mm_emi:
	movl	$0,%fs:islock
	jmp	eval

////////
/
/ mm_ff - form feed, clear and home cursor
/
////////

mm_ff:	subb	COL,COL
	movb	%fs:MM_BROW(%ebp),ROW
	subl	POS,POS
	movb	%fs:MM_LROW(%ebp),%bl
mm_ff1:
	call	blanklines
	jmp	repos

////////
/
/ mm_cha - cursor horizontal absolute
/ mm_hpa - horizontal position absolute
/
/	Moves the active position within the active line to the position
/	specified by the parameter.  A parameter value of zero or one
/	moves the active position to the first position of the active line.
/
////////

mm_cha:
mm_hpa:	movb	%fs:MM_N1(%ebp),COL
mm_hpa1:
	decb	COL
	jge	mm_hpa2
	subb	COL,COL
mm_hpa2:
	cmpb	$NCOL,COL
	jb	?mm_hpa3
	movb	$NCOL-1,COL
?mm_hpa3:
	jmp	repos

////////
/
/ mm_hpr - horizontal position relative
/
/	Moves the active position forward the number of positions specified
/	by the parameter.  A parameter value of zero or one indicates a
/	single-position move.
/
////////

mm_hpr:	call	getn1
	addb	%bl,COL
	jmp	mm_hpa2

////////
/
/ mm_ht - horizontal tabulation
/
////////

mm_ht:	movb	$1,%bl
	jmp	mm_cht1

////////
/
/ mm_hvp - horizontal and vertical position
/
/	Moves the active position to the position specified by two parameters.
/	The first parameter specifies the vertical position (%fs:MM_ROW(%ebp)).
/	The second parameter specifies the horizontal position (%fs:MM_COL(%ebp)).
/	A parameter value of zero or one moves the active position to the
/	first line or column in the display.
/
////////

mm_hvp:	call	getrow
	cmpb	%fs:MM_LROW(%ebp),ROW
	jna	?mm_hvp1
	movb	%fs:MM_LROW(%ebp),ROW
?mm_hvp1:
	jmp	mm_cup1

////////
/
/ mm_ich - insert characters
/
////////

mm_ich:	call	getn1
	movb	%bl,%al			/ characters to insert
	push	%ecx
	movb	ROW,%bl			/ current row
	movl	%cs:rowtab+4(,%ebx,4),%ecx	/ start of next row
	subl	POS,%ecx		/ characters left in this row * 2
	movb	%al,%bl
	shll	$1,%ebx			/ characters to insert * 2
	subl	%ebx,%ecx		/ characters to shift
	jl	?ich2			/ tried to insert too many, ignore
	push	%edi
	addl	%ebx,%edi		/ destination
	call	copyb
	pop	%edi			/ restore current position
	movzxb	%al,%ecx		/ chars to blank
	call	blank
?ich2:
	pop	%ecx
	jmp	repos			/ reposition cursor

////////
/
/ mm_il - insert line
/
/	Insert a erased line at the active line by shifting the contents
/	of the active line and all following lines away from the active line.
/	The contents of the last line in the scrolling region are removed.
/
////////

mm_il:	call	getn1
mm_il1:
	push	%ecx
	movb	%bl,%al			/ lines to scroll to AL
	movb	ROW,%bl			/ beginning row to scroll in BL
	jmp	mm_sd1

////////
/
/ mm_ind - index
/ mm_lf - line feed
/ mm_nel - next line
/ mm_vt - vertical tab
/
/	Moves the active position to the next display line.
/	Scrolls the active display if necessary.
/
////////

mm_ind:
mm_lf:
mm_nel:
mm_vt:	incb	ROW
mm_ind1:
	cmpb	%fs:MM_EROW(%ebp),ROW
	jna	repos
	movb	%fs:MM_EROW(%ebp),ROW
	jmp	scrollup

////////
/
/ mm_new - save cursor position
/
////////

mm_new:	movb	COL,%fs:MM_SCOL(%ebp)
	movb	ROW,%fs:MM_SROW(%ebp)
	jmp	eval

////////
/
/ mm_old - restore old cursor position
/
////////

mm_old:	movb	%fs:MM_SCOL(%ebp),COL
	movb	%fs:MM_SROW(%ebp),ROW
	jmp	repos

////////
/
/ mm_ri - reverse index
/
/	Moves the active position to the same horizontal position on the
/	preceding line.  Scrolling occurs if above scrolling region.
/
////////

mm_ri:	decb	ROW
	jmp	mm_cpl1

////////
/
/ mm_scr - select cursor rendition
/
/	Invokes the cursor rendition specified by the parameter.
/
/	Recognized renditions are:	0 - cursor visible
/					1 - cursor invisible
////////

mm_scr:	decb	 %fs:MM_N1(%ebp)
	je	?mm_scr1
	jg	?mm_scr2
	movl	$0,%fs:MM_INVIS(%ebp)
	jmp	eval

?mm_scr1:
	movl	$-1,%fs:MM_INVIS(%ebp)
?mm_scr2:
	jmp	eval

////////
/
/ mm_sd - scroll down
/
////////

mm_sd:
	call	getn1
	push	%ecx
	movb	%bl,%al			/ lines to scroll to AL
	movb	%fs:MM_BROW(%ebp),%bl
mm_sd1:
	push	%ebx
	movb	%fs:MM_EROW(%ebp),%cl
	subb	%bl,%cl
	incb	%cl			/ lines in scrolling area
	addb	%al,%bl			/ destination line
	cmpb	%fs:MM_EROW(%ebp),%bl
	ja	mm_sd3			/ too many
	movl	%cs:rowtab(,%ebx,4),%edi	/ destination
	subb	%al,%cl			/ lines to move
	jle	mm_sd3			/ scrolled more than available
	movzxb	%cl,%ecx
	imull	$NHB,%ecx,%ecx		/ bytes to move
	movzxb	%al,%ebx
	imull	$NHB,%ebx,%ebx		/ offset
	call	copyb
	pop	%ebx			/ restore first row to blank to BL
mm_sd2:
	movl	%cs:rowtab(,%ebx,4),%edi
	movzxb	%al,%ecx
	imull	$NCOL,%ecx,%ecx		/ bytes to blank
	call	blank
	pop	%ecx
	jmp	repos			/ leaves cursor unchanged

mm_sd3:
	pop	%ebx
	pop	%ecx
	jmp	mm_ea2			/ erase active area

////////
/
/ mm_sgr - select graphic rendition
/
/	Invokes the graphic rendition specified by the parameter.
/	All following characters in the data stream are rendered
/	according to the parameters until the next occurrence of
/	SGR in the data stream.
/
/	Recognized renditions are:	0	reset all
/					1	high intensity
/					4	underline
/					5	slow blink
/					7	reverse video
/					8	concealed on
/					10	select primary font
/					11	select first alternate font
/					12	select second alternate font
/					30-37	foreground color
/					40-47 	background color
/					50-57	border color
/
/	This is the only escape sequence which takes a parameter sequence
/	of unspecified length.
/
////////

mm_sgr:	movb	%fs:MM_N1(%ebp),%al
	cmpb	$10,%al
	jge	?mm_sgr10
	cmpb	$0,%al			/ reset all = 0
	jne	?mm_sgr1
	movl	$0,%fs:islock		/ clear keyboard lock state
	movb	%fs:MM_OATTR(%ebp),ATTR	/ restore original attribute
	jmp	?mm_sgrnext

?mm_sgr1:
	cmpb	$1,%al			/ bold =  1
	jne	?mm_sgr4
	orb	$INTENSE,ATTR
	jmp	?mm_sgrnext

?mm_sgr4:
	cmpb	$4,%al			/ underline = 4
	jne	?mm_sgr5
	cmpl	$COLOR,%fs:MM_PORT(%ebp)	/ color card?
	je	?mm_sgr4c		/ yes
	andb	$BLINK|INTENSE,ATTR	/ retain BLINK and INTENSE
	orb	$UNDERLINE,ATTR
	jmp	?mm_sgrnext

?mm_sgr4c:
	orb	$CULATTR,ATTR
	jmp	?mm_sgrnext

?mm_sgr5:
	cmpb	$5,%al			/ blinking = 5
	jne	?mm_sgr7
	orb	$BLINK,ATTR
	jmp	?mm_sgrnext

?mm_sgr7:
	cmpb	$7,%al			/ reverse video = 7
	jne	?mm_sgr8
	movb	$0x70,%al		/ reversed attribute for mono
	cmpl	$COLOR,%fs:MM_PORT(%ebp)	/ color card?
	jne	?mm_sgr7b
	movb	%fs:MM_OATTR(%ebp),%al	/ yes, exchange foreground/background
	rolb	$4,%al
?mm_sgr7b:
	andb	$BLINK|INTENSE,ATTR	/ retain BLINK and INTENSE
	orb	%al,ATTR
	jmp	?mm_sgrnext

?mm_sgr8:
	cmpb	$8,%al			/ concealed on = 8
	jne	?mm_sgrnext		/ n1 = 9, ignore
	cmpl	$COLOR,%fs:MM_PORT(%ebp)	/ color card?
	jne	?mm_sgr9a

	andb	$0x70,ATTR		/ Yes,	Set foreground color
	movb	ATTR,%al		/	to background color.
	rorb	$4,%al
	orb	%al,ATTR
	jmp	?mm_sgrnext

?mm_sgr9a:
	andb	$0x80,ATTR		/ No, set attributes to non-display.
	jmp	?mm_sgrnext		/	retain blink attribute.

?mm_sgr10:
	subb	$10,%al			/ map 10-57 to 0-47
	cmpb	$2,%al			/ foreground color
	jg	?mm_sgr10a		/ >12
	movb	%al,%fs:MM_FONT(%ebp)	/ set font [012]
	jmp	?mm_sgrnext

?mm_sgr10a:
	cmpl	$COLOR,%fs:MM_PORT(%ebp)	/ color card?
	jne	?mm_sgrnext		/ no, ignore remaining options

?mm_sgr30:
	subb	$20,%al			/ map 30-57 to 0-27
	jl	?mm_sgrnext		/ <30, ignore
	cmpb	$7,%al			/ foreground color
	jg	?mm_sgr40
	movb	%al,%bl
	andb	$0xf8,ATTR		/ mask out old foreground
	orb	%cs:fcolor(%ebx),ATTR	/ and replace with new
	movb	%fs:MM_OATTR(%ebp),%al	/ get original attribute
	andb	$0xf8,%al		/ mask out old foreground
	orb	%cs:fcolor(%ebx),%al	/ and replace with new
	movb	%al,%fs:MM_OATTR(%ebp)	/ and store
	jmp	?mm_sgrnext
?mm_sgr40:
	subb	$10,%al			/ map 40-57 to 0-17
	jl	?mm_sgrnext		/ <40, ignore
	cmpb	$7,%al			/ background color
	jg	?mm_sgr50
	movb	%al,%bl
	andb	$0x8f,ATTR		/ mask out old background
	orb	%cs:bcolor(%ebx),ATTR	/ and replace with new
	movb	%fs:MM_OATTR(%ebp),%al	/ get original attribute
	andb	$0x8f,%al		/ mask out old background
	orb	%cs:bcolor(%ebx),%al	/ and replace with new
	movb	%al,%fs:MM_OATTR(%ebp)	/ and store
	jmp	?mm_sgrnext
?mm_sgr50:
	subb	$10,%al			/ map 50-57 to 0-7
	jl	?mm_sgrnext		/ <50, ignore
	cmpb	$7,%al			/ border color
	jg	?mm_sgrnext
	movb	%al,%bl
	movb	%cs:fcolor(%ebx),%al
	push	%edx
	movl	%fs:MM_PORT(%ebp),%edx
	addl	$5,%edx
	outb	(%dx)
	pop	%edx
/	jmp	?mm_sgrnext

/ Parameter n1 has been processed, check if more params were specified.
?mm_sgrnext:
	decl	%fs:MM_NARGS(%ebp)	/ adjust count
	je	eval			/ done
	push	%ds
	push	%es
	push	%esi
	push	%edi
	push	%ecx
	movw	%fs,%cx
	movw	%cx,%ds
	movw	%cx,%es
	movl	$MAXARGS-1,%ecx		/ count
	lea	MM_N1(%ebp),%edi	/ destination
	movl	%edi,%esi
	incl	%esi			/ source
	rep
	movsb				/ shift remaining args down 1
	pop	%ecx
	pop	%edi
	pop	%esi
	pop	%es
	pop	%ds
	jmp	mm_sgr			/ process next parameter

////////
/
/ mm_spc - schedule special keyboard function
/
////////

mm_spc:	movb	%al,%fs:MM_ESC(%ebp)
	jmp	eval

////////
/
/ mm_ssr - set scrolling region
/
////////

mm_ssr:	movb	%fs:MM_N1(%ebp),%al
	decb	%al
	jge	?mm_ssr1
	subb	%al,%al
?mm_ssr1:
	cmpb	%fs:MM_LROW(%ebp),%al
	ja	?mm_ssr3
	movb	%fs:MM_N2(%ebp),%bl
	decb	%bl
	jge	?mm_ssr2
	subb	%bl,%bl
?mm_ssr2:
	cmpb	%fs:MM_LROW(%ebp),%bl
	ja	?mm_ssr3
	cmpb	%bl,%al
	ja	?mm_ssr3
	movb	%al,%fs:MM_BROW(%ebp)
	movb	%bl,%fs:MM_EROW(%ebp)
	movb	%al,ROW
	subb	COL,COL
?mm_ssr3:
	jmp	repos

////////
/
/ mm_su - scroll up
/
////////

mm_su:
	call	getn1
	push	%ecx
	movb	%bl,%al			/ lines to scroll to AL
	movb	%fs:MM_BROW(%ebp),%bl
mm_su1:
	movl	%cs:rowtab(,%ebx,4),%edi	/ destination
	movb	%fs:MM_EROW(%ebp),%cl
	subb	%bl,%cl
	incb	%cl			/ lines in scrolling area
	subb	%al,%cl			/ lines to move
	jle	?mm_su2			/ scrolled more than available
	movzxb	%cl,%ecx
	imull	$NHB,%ecx,%ecx		/ bytes to move
	movzxb	%al,%ebx
	imull	$NHB,%ebx,%ebx		/ offset
	call	copyf
	movb	%fs:MM_EROW(%ebp),%bl
	incb	%bl
	subb	%al,%bl			/ first row to blank
	jmp	mm_sd2

?mm_su2:
	pop	%ecx
	jmp	mm_ea2			/ erase active area

////////
/
/ mm_vpa - vertical position absolute
/
/	Moves the active position to the line specified by the parameter
/	without changing the horizontal position.
/	A parameter value of 0 or 1 moves the active position vertically
/	to the first line.
/
////////

mm_vpa:	call	getrow
mm_vpa1:
	cmpb	%fs:MM_LROW(%ebp),ROW
	jna	?mm_vpa2
	movb	%fs:MM_LROW(%ebp),ROW
?mm_vpa2:
	jmp	repos

////////
/
/ mm_vpr - vertical position relative
/
/	Moves the active position downward the number of lines specified
/	by the parameter without changing the horizontal position.
/	A parameter value of zero or one moves the active position
/	one line downward.
/
////////

mm_vpr:	call	getn1
	addb	%bl,ROW
	jmp	mm_vpa1

/ end of vtmmas.s