; Z-19.ASM	Z-19 emulator for the SSM VB3 video card
; 
;		Version 1.0  Released 82.4.18
;		Copyleft (L) Scott W. Layson.  All rights reversed.
;		This code is in the public domain.
;
;	This code performs approximate (but usually adequate) emulation
;	of the Heath/Zenith Z-19 terminal on the SSM VB3 video card.  It
;	supports most of the Z-19 features required for normal text editing.
;	About the only useful thing missing is the special 25th line (49th?).
;
;	Things to note about this code:
;	-- The indentation in this file looks so strange because I edit with
;	   five-column instead of eight-column tabs.
;	-- Sections of this code, especially the relatively low-level routines,
;	   are not well commented.  Sorry 'bout that.
;	-- The code uses Intel mnemonics, but there are a couple of Z-80
;	   block moves inserted with `db's.  If you don't have a Z-80, you'll
;	   have to replace these with 8080 loops that do the same thing.
;	-- This file requires MAC for assembly as it stands, though it might
;	   not be very hard to make it ASM-compatible.
;	-- It assumes that the video controller has already been initialized
;	   (to 48 lines, but you can change this in the block of code below).
;	-- There's no keyboard I/O code in this file.
;	-- I have to turn the lower 48K of my main memory off, because my
;	   ExpandoRam II doesn't respond to PHANTOM* on write.  You will
;	   presumably have to change or remove this code; it's all right
;	   near the beginning.
;	-- This code uses a fair amount of stack space; I don't know exactly
;	   how much.  Because of this and because I'm turning most of main
;	   memory off, I use a private stack at the top of memory.  I recommend
;	   you do likewise if possible.
;	-- I normally use this code in "roll mode" rather than "scroll mode":
;	   after the last line on the screen is printed, the cursor is placed
;	   on the top line, which is then cleared.  The screen is never scrolled.
;	   I find this more comfortable on a P39 monitor, where scrolling leaves
;	   "trails".  The Z-19, of course, supports only "scroll mode".  The
;	   defaults for this and other modes are set in the `db's at the end
;	   of the file.
;	-- The behavior of this code when it gets an insert- or delete- line
;	   command is a little weird.  Instead of doing the insertion or
;	   deletion immediately, it counts the number of successive insertions
;	   or deletions and only executes them when it gets some other kind
;	   of command.  Sometimes this means that when you give an insert-line
;	   or delete-line command to your editor, nothing happens until you
;	   type another character.  The insert-n-lines and delete-n-lines
;	   commands, on the other hand, are executed immediately.
;	-- Consider: when you put a terminal into inverse video mode and give
;	   it a clear command of some sort (clear-to-end-of-line, home-and-clear-
;	   screen), should it clear to inverse or normal spaces?  The Z-19 clears
;	   to normal spaces; this code, like most other "smart" terminals these
;	   days, clears to inverse spaces.  Likewise for the other video
;	   attributes it supports.
;	-- The "graphics" mode accesses the user-definable font ROM.  Obviously,
;	   for emulation of Z-19 graphics mode, you must burn a ROM with that
;	   character set.
;
; Here is a list of control characters and escape sequences the code
; currently supports.  A `*' marks sequences the Z-19 doesn't have.
;
;  BS
;  TAB
;  CR
;  LF
;  Esc @			Enter insert-char mode
;  Esc A			Cursor up
;  Esc B			Cursor down
;  Esc C			Cursor forward
;  Esc D			Cursor backward
;  Esc E			Home and clear
;  Esc F			Enter graphics mode
;  Esc G			Exit graphics mode
;  Esc H			Home
;  Esc J			Clear to end of screen
;  Esc K			Clear to end of line
;  Esc L			Insert line
;  Esc M			Delete line
;  Esc N			Delete char
;  Esc O			Exit insert-char mode
;  Esc Y <r> <c>	Cursor pos
; *Esc l <n>		Insert n lines
; *Esc m <n>		Delete n lines
;  Esc p			Enter inverse video
;  Esc q			Exit inverse video
;  Esc x/y 5		Turn cursor off/on
; *Esc x/y *		Enter/exit scroll mode
; *Esc x/y A		Enter/exit inverse video
; *Esc x/y B		Enter/exit hide-char mode
; *Esc x/y C		Enter/exit underline mode
; *Esc x/y D		Enter/exit blink mode
; *Esc x/y E		Enter/exit strike-thru mode
; *Esc x/y F		Enter/exit dim mode
; *Esc x/y @		Set/clear all video modes
;  Esc v			Wrap mode on
;  Esc w			Wrap mode off
;

; And now the code itself.

vnormal	equ 3			; standard character attribute code
vinverse	equ 4			; inverse video bit
bs		equ 08h
tab		equ 09h
lf		equ 0ah
cr		equ 0dh
esc		equ 1Bh
vkbstat	equ 0e0h			; video keyboard status port
vkbdata	equ 0e1h			; video keyboard data port
vc		equ 0d0h			; video controller registers:
vhcount	equ vc + 0		;	char times per scan
vhsync	equ vc + 1		;	interlace(1), hsp(4), hbp(3)
vchars	equ vc + 2		;	0(1), scans/char(4), chars/line(3)
vlines	equ vc + 3		;	lines/frame
vscans	equ vc + 4		;	scans/frame
vvsync	equ vc + 5		;	vertical scan delay
vscrol	equ vc + 6		;	scroll register
vcolin	equ vc + 9		;	cursor column in
vcolout	equ vc + 12		;	cursor column out
vrowin	equ vc + 8		;	cursor row in
vrowout	equ vc + 13		;	cursor row out
vncols	equ 80			; number of cols
vnrows	equ 48			; number of rows
vvideo	equ 2000h			; address of video memory
voffset	equ 1000h			; offset to attributes
ramcard	equ 0FFh			; ExpandoRam bank-switch port
ramoff	equ 1			; to turn main memory off
ramon	equ 0			; to turn memory back on


		org 0F810h

; Main entry point.  The character is in C.

h19		push h			; save registers
		push d
		push b
		lxi h, 0
		dad sp			; get stack pointer
		lxi sp, 0			; move stack to high memory
		push h			; save old SP
		mvi a, ramoff		; turn main memory off
		out ramcard
		out vkbstat		; enable VB3
		call curoff		; turn cursor off
		call process		; process char
		call curon		; cursor back on
		out vkbdata		; disable VB3
		mvi a, ramon		; turn main memory back on
		out ramcard
		pop h			; recover old SP
		sphl				; and put the stack back where it was
		pop b			; restore registers
		pop d
		pop h
		ret				; and done!

process	lda escmode		; are we in an escape sequence?
		ora a
		jnz escseq		; yes: go interpret this char
		mov a, c
		cpi esc			; test for esc before checking insdelcnt
		jz doesc			; in case we're getting another ins or del
		
		lda insdelcnt		; any saved line insertions or deletions to do?
		ora a
		cnz doinsdel		; yes: do them first
		
		mov a, c			; check for the known control chars
		cpi cr			; (others are displayed)
		jz docr
		cpi lf
		jz dolf
		cpi bs
		jz dobs
		cpi tab
		jz dotab
		
; we have a displayable character.
display	lda insmode		; are we in insert-char mode?
		ora a
		cnz inschar		; yes: move rest of line over first
		lda attrib		; get current attribute byte
		mov b, a			; set up for putchar
		call putchar
		call right		; move cursor right
		rnz				; done if no wrap
		lda wrapp			; are we in wrap mode?
		ora a
		rz				; no: return
		jmp nextline		; wrap occurred

; write the char in c, attribute in b, to the video memory.
putchar	push h
		call addr			; get memory address of char
		mov m, c			; store char
		lxi d, voffset
		dad d			; address of attribute
		mov m, b			; store attribute
		pop h
		ret

nextline	mvi l, 0			; move to col. 0

; move the cursor down one line.  Clear the new line
; if the cursor was on the last logical line.  Scroll the screen
; if in scroll mode.

dolf		lda scrollp		; are we in scroll mode?
		ora a
		jnz dolfscr		; yes: go do the right thing
dolfnscr	lda lastlrow		; do lf in non-scroll mode:
		cmp h			; are we moving off the last logical row?
		push psw			; save the answer to that question
		call down			; move down
		jnz dolf3
		mvi h, 0			; wrap to top of screen
dolf3	pop psw			; are we moving off the last row?
		rnz				; no: done
		call nextlrow		; increment last-logical-row
		jmp dolf2

dolfscr	call down			; do lf in scroll mode
		rnz				; not moving off bottom: done
		call nextlrow		; increment last-logical-row
		out vscrol		; scroll screen
		sta lastprow		; set last-physical-row

dolf2	push h
		mvi l, 0
		call cleol		; clear the new line
		pop h
		ret

nextlrow	lda lastlrow		; increment last-logical-row
		inr a
		cpi vnrows		; modulo vnrows
		jnz nextl1
		xra a
nextl1	sta lastlrow		; store result
		ret

docr		mvi l, 0			; CR: set col to 0
		ret

dobs		jmp left			; BS: move cursor left

dotab	mov a, l			; TAB: move to current col...
		ani 0F8h			; ... modulo 8 ...
		adi 8			; ... plus 8
		cpi vncols
		jz right			; except near edge of screen
		mov l, a
		ret

; turn the cursor off.  Returns logical cursor address in HL.
curoff	lhld curaddr		; get logical cursor address
		mvi a, 0FFh
		out vcolout		; move cursor off screen
		ret

; turn the cursor on.  Called with logical cursor address in HL.
curon	shld curaddr		; save logical cursor address
		lda curoffp
		ora a
		rnz				; if cursor turned off, leave it off screen
		mov a, l			; set column
		out vcolout
		lda lastprow		; set row relative to last physical row
		inr a
		add h
		cpi vnrows
		jc curon1
		sui vnrows
curon1	out vrowout
		ret

; move the cursor left, if possible.  Returns Z iff at left edge.
left		mov a, l			; get col
		dcr l
		ora a
		rnz				; R(not at left edge)
		mov l, a			; force col. 0
		ret

; move the cursor right, if possible.  Returns Z iff at right edge.
right	inr l
		mvi a, vncols
		cmp l
		rnz				; R(not at right edge)
		mvi l, vncols - 1	; can't just dcr, cuz it clears Z!
		ret

; move the cursor down, if possible.  Returns Z iff at bottom.
down		inr h
		mvi a, vnrows
		cmp h
		rnz				; R(not at bottom)
		mvi h, vnrows - 1	; can't just dcr, cuz it clears Z!
		ret

; move the cursor up, if possible.  Returns Z iff at top.
up		mov a, h
		dcr h
		ora a
		rnz
		mov h, a
		ret

; clear to end of line.
cleol	mov d, h			; set de to end of line
		mvi e, vncols - 1
		mvi c, ' '		; space character in c
		lda attrib		; current attribute in b
		mov b, a
		jmp fills			; and do it!

; home and clear.
hcl		call home
		jmp cleow


; cursor home.
home		lxi h, 0
		ret

; clear to end of window (screen).
cleow	lda lastprow
		sta lastlrow		; set lastlrow to bottom of screen
		mvi d, vnrows - 1	; set de to end of screen
		mvi e, vncols - 1
		mvi c, ' '		; space char in c
		lda attrib		; current attribute in b
		mov b, a
		jmp fills			; and do it!

; insert a character at the cursor.
inschar	push b
		push h
		mvi a, vncols - 1	; how many chars to move?
		sub l
		jz insch1			; none: skip
		mov c, a
		mvi b, 0			; # chars in bc
		push b			; and save it
		mvi l, vncols - 1	; set hl to end of line
		call addr			; get starting address of move
		push h
		mov d, h			; dest in de
		mov e, l
		dcx h			; source in hl
;		lddr				; and move!
		db 0EDh, 0B8h		; Z80 instruction
		pop h			; address
		pop b			; byte count
		lxi d, voffset		; now do attributes
		dad d
		mov d, h			; just like before
		mov e, l
		dcx h
;		lddr
		db 0EDh, 0B8h		; another Z80 instruction
insch1	pop h
		pop b
		ret

; delete a character at the cursor.
delchar	push b
		push h
		mvi a, vncols - 1	; get # of chars to move
		sub l
		jz delch1			; none: skip
		mov c, a
		mvi b, 0			; # chars in bc
		push b
		call addr			; get starting address
		push h
		mov d, h			; de = dest
		mov e, l
		inx h			; hl = source
;		ldir				; and move!
		db 0EDh, 0B0h		; Z80 instruction
		pop h			; address
		pop b			; byte count
		lxi d, voffset		; now do attributes
		dad d
		mov d, h			; just like before
		mov e, l
		inx h
;		ldir				; and move!
		db 0EDh, 0B0h		; Z80 instruction
delch1	pop h			; get current row, col back
		push h
		mvi l, vncols - 1	; set up to clear last char in line
		mvi c, ' '
		lda attrib
		mov b, a
		call putchar		; do it
		pop h
		pop b
		ret

; delete the line containing the cursor.
delline	mvi c, 1			; and fall through

; delete <n> lines, starting with the one containing the cursor.
; <n> is in C.
delnlines	push h
		mov a, h
		add c			; other end of region to be deleted
		cpi vnrows
		jm deln1
		mvi a, vnrows
deln1	mov l, a			; h = first dest, l = first source
		mvi a, vnrows
		sub l
		mov b, a			; b = no. of lines to move
		call moveblk
		mvi a, vnrows
		sub c			; c = no. of lines to clear
		mov h, a			; h = first row to clear
		call clrblk
		pop h
		mvi l, 0			; move to beginning of line
		ret

; insert a line where the cursor is.
insline	mvi c, 1			; and fall through

; insert <n> lines before the line containing the cursor.
; <n> is in C.
insnlines	push h
		mov a, h
		mov l, h
		add c			; other end of region to be inserted
		cpi vnrows
		jm insn1
		mvi a, vnrows
insn1	mov h, a			; h = first dest, l = first source
		mvi a, vnrows
		sub h
		mov b, a			; b = no. of lines to move
		call moveblk
		mov h, l			; h = first row to clear
		call clrblk		; c = no. of lines to clear
		pop h
		mvi l, 0			; move to beginning of line
		ret

; move a block of B lines from row L to row H.
moveblk	push h
		push d
		push b
		mov a, l
		cmp h
		jm movbrev
movbfwd	mov d, h
		mov h, l
movbfwd1	mov a, b
		ora a
		jz movbret
		dcr b
		call movelin
		inr h
		inr d
		jmp movbfwd1

movbrev	mov a, h
		add b
		mov d, a			; d = h + b
		mov a, l
		add b
		mov h, a			; h = l + b
movbrev1	mov a, b
		ora a
		jz movbret
		dcr b
		dcr h
		dcr d
		call movelin
		jmp movbrev1

movbret	pop b
		pop d
		pop h
		ret


; clear C lines starting at H.
clrblk	push h
		push d
		push b
		mvi l, 0
clrblk1	mov a, c
		ora a
		jz clrblk2
		push b
		call cleol
		pop b
		inr h
		dcr c
		jmp clrblk1
clrblk2	pop b
		pop d
		pop h
		ret

; move a line from row H to row D.
movelin	push h
		push d
		push b
		mvi l, 0
		mov e, l
		lxi b, voffset
		call addr
		push h
		dad b
		xchg
		call addr
		push h
		dad b
		xchg
		lxi b, vncols
;		ldir
		db 0EDh, 0B0h		; Z80 instruction
		pop d
		pop h
		lxi b, vncols
;		ldir
		db 0EDh, 0B0h		; Z80 instruction
		pop b
		pop d
		pop h
		ret


; get physical address from logical address.

addr		push b
		lda lastprow
		inr a
		add h
		cpi vnrows
		jc addr1
		sui vnrows
addr1	mov c, a
		mvi b, 0
		mov a, l			; save col
		lxi h, rowtab
		dad b
		dad b
		mov c, a			; get col back
		mov a, m			; look row up in table
		inx h
		mov h, m
		mov l, a
		dad b			; add col
		pop b
		ret

rowtab
j		set vncols
i		set 0
		rept vnrows
		dw vvideo + j * i
i		set i + 1
		endm


; fill the screen with the data in C, the attribute in B
; from x, y location HL through DE.
fills	push h
		call addr
		xchg
		call addr
		mov a, h
		cmp d
		jnz fills1a
		mov a, l
		cmp e
fills1a	xchg
		jnc fills1		; J(area to fill doesn't wrap)
		push d
		push b
		lxi d, vvideo + vnrows * vncols - 1
		call fills2
		pop b
		pop d
		lxi h, vvideo
fills1	call fills2
		pop h
		ret

fills2	push b
		push h
		push d
		call fill			; fill in the data
		pop h
		pop d
		lxi b, voffset
		dad b
		xchg
		dad b
		pop b
		mov c, b
		call fill			; fill in the attributes
		ret

fill		mov m, c			; put down first copy
		mov a, e
		sub l
		mov c, a
		mov a, d
		sbb h
		mov b, a			; bc = de - hl = no. bytes to move
		ora c
		rz				; R(nothing to do -- only one byte to fill)
		mov d, h			; hl = source
		mov e, l
		inx d			; de = dest
;		ldir
		db 0EDh, 0B0h		; Z80 instruction
		ret


; turn on escape mode.
doesc	mvi a, stesc
		sta escmode
		ret


;
; These are the various escape-states we can be in.  They indicate
; what part of an escape sequence we've seen already.
stesc	equ 1			; Esc
stcprow	equ 2			; Esc Y
stcpcol	equ 3			; Esc Y <row>
stsetmode	equ 4			; Esc x
stclrmode equ 5			; Esc y
stinsn	equ 6			; Esc l
stdeln	equ 7			; Esc m

; We get here if we're in the middle of an escape sequence.
; escmode is in A.

escseq	push psw
		xra a
		sta escmode		; clear escape mode here, for convenience
		pop psw
		
		cpi stcprow		; row byte?
		jz docprow
		cpi stcpcol		; col byte?
		jz docpcol
		cpi stsetmode		; set-mode byte?
		jz dosetmode
		cpi stclrmode		; clear-mode byte?
		jz doclrmode
		cpi stinsn		; insert-n-lines byte?
		jz doinsn
		cpi stdeln		; delete-n-lines byte?
		jz dodeln
		
		mov a, c
		cpi 'L'			; insert (1) line?
		jz doinslin
		cpi 'M'			; delete (1) line?
		jz dodellin
		
		lda insdelcnt		; for anything else: do any saved
		ora a			; insertions/deletions first
		cnz doinsdel
		
		mov a, c
		cpi 'Y'			; cursor pos?
		jz docp
		cpi 'K'			; clear to end of line?
		jz docleol
		cpi 'E'			; home and clear screen?
		jz dohcl
		cpi 'H'			; home?
		jz dohome
		cpi 'J'			; clear to end of screen?
		jz docleow
		cpi 'A'			; cursor up?
		jz doup
		cpi 'B'			; cursor down?
		jz dodown
		cpi 'C'			; cursor right?
		jz doright
		cpi 'D'			; cursor left?
		jz doleft
		cpi '@'			; set char-insert mode?
		jz inschon
		cpi 'O'			; clear char-insert mode?
		jz inschoff
		cpi 'N'			; delete char?
		jz dodelchar
		cpi 'l'			; insert n lines?
		jz doinsnlins
		cpi 'm'			; delete n lines?
		jz dodelnlins
		cpi 'p'			; set inverse video?
		jz doinvon
		cpi 'q'			; clear inverse video?
		jz doinvoff
		cpi 'x'			; set mode?
		jz setmode
		cpi 'y'			; clear mode?
		jz clrmode
		cpi 'v'			; set wrap mode?
		jz dowrapon
		cpi 'w'			; clear wrap mode?
		jz dowrapoff
		cpi 'F'			; set graphics mode?
		jz dografon
		cpi 'G'			; clear graphics mode?
		jz dografoff

escfail	push b			; not any recognized command.  display
		mvi c, esc		; sequence literally so user can see what
		call display		; happened
		pop b
		call display
		ret

docp		mvi a, stcprow		; cursor pos command: set esc mode
		sta escmode
		ret

docprow	mov a, c			; get row byte
		sui 32			; subtract bias
		mov h, a
		mvi a, stcpcol		; set new esc mode
		sta escmode
		lda curoffp
		inr a			; cursor off during CP
		sta curoffp
		ret

docpcol	mov a, c			; get col byte
		sui 32			; subtract bias
		mov l, a
		lda curoffp
		dcr a			; cursor back on (unless it was already off)
		sta curoffp
		ret

docleol	equ cleol

dohcl	equ hcl

dohome	equ home

docleow	equ cleow

doup		equ up

dodown	equ down

doright	equ right

doleft	equ left

inschon	mvi a, 1			; set insert-char mode
		sta insmode
		ret

inschoff	xra a			; clear insert-char mode
		sta insmode
		ret

dodelchar	equ delchar

doinslin	lda insdelcnt		; accumulate insertions
		ora a
		push psw
		cm doinsdel		; do any saved deletions first
		pop psw
		inr a			; then increment insdelcnt
		sta insdelcnt
		ret

dodellin	lda insdelcnt		; accumulate deletions
		dcr a
		push psw
		cp doinsdel		; do any saved insertions first
		pop psw
		sta insdelcnt
		ret

doinsnlins mvi a, stinsn		; set escmode to expect no. of insertions
		sta escmode
		ret

dodelnlins mvi a, stdeln		; set escmode to expect no. of deletions
		sta escmode
		ret

doinsn	equ insnlines

dodeln	equ delnlines

doinsdel	lda insdelcnt		; do saved insertions/deletions
		ora a			; any to do?
		rz				; no: done
		push b
		jm doinsdel1		; pos: insertions; neg: deletions
		mov c, a			; insertion was saved
		call insnlines		; do it
		jmp doinsdel2
doinsdel1	cma
		inr a
		mov c, a			; deletion was saved
		call delnlines		; do it
doinsdel2	pop b
		xra a
		sta insdelcnt		; clear saved count
		ret

doinvon	lda attrib		; inverse video on
		ori vinverse
		sta attrib
		ret

doinvoff	lda attrib		; inverse video off
		cma
		ori vinverse
		cma
		sta attrib
		ret

setmode	mvi a, stsetmode	; set escmode to expect mode to set
		sta escmode
		ret

clrmode	mvi a, stclrmode	; set escmode to expect mode to clear
		sta escmode
		ret

; come here with a mode to set in C
dosetmode	mov a, c
		cpi '5'
		jz setcuroff		; turn cursor off
		cpi '@'
		jnc setattr		; set display attributes
		cpi '*'
		jz setscrol		; set scroll mode
		push b
		mvi c, esc		; display unimplemented sequence, so
		call display		; user can see what happened
		mvi c, 'x'
		call display
		pop b
		call display
		ret

setcuroff	mvi a, 1			; turn cursor off
		sta curoffp
		ret

setattr	call attrbit		; get bit for this attribute
		lda attrib		; or it into current attribute byte
		ora e
		sta attrib
		ret

setscrol	lda scrollp		; set scroll (Z-19 normal) mode
		ora a
		rnz				; already on
		mvi a, 1
		sta scrollp
		mvi h, vnrows - 1
		lda lastlrow		; get last logical row
		out vscrol		; make it last physical row
		sta lastprow
		ret

; come here with a mode to clear in C
doclrmode	mov a, c
		cpi '5'
		jz clrcuroff		; turn cursor back on
		cpi '@'
		jnc clrattr		; clear an attribute
		cpi '*'
		jz clrscrol		; turn roll mode back on
		push b
		mvi c, esc		; display unimplemented sequence
		call display		; so the user can see what happened
		mvi c, 'y'
		call display
		pop b
		call display
		ret

clrcuroff	xra a			; turn cursor back on
		sta curoffp
		ret

clrattr	call attrbit		; get bit for attribute
		lda attrib
		cma
		ora e			; clear it in current attr. byte
		cma
		sta attrib
		ret

clrscrol	lda scrollp		; set "roll" mode: no scrolling
		ora a
		rz 				; scroll mode already off
		xra a
		sta scrollp
		lda lastlrow
		mov h, a
		mvi a, vnrows - 1	; return screen to 0-origin
		out vscrol
		sta lastprow
		ret

; given command char in A, leaves attribute bit set in E
attrbit	sbi '@'
		jz attrbit1
		mov e, a
		mvi a, 2			; start with 2
attrbit2	rlc				; rotate left
		dcr e			; the right number of times
		jnz attrbit2
		mov e, a
		ret
attrbit1	mvi e, 0FCh		; '@': all attributes
		ret

dowrapon	mvi a, 1			; turn wrap mode (end-of-line wrapping) on
		sta wrapp
		ret

dowrapoff	xra a			; turn wrap mode (end-of-line wrapping) off
		sta wrapp
		ret

dografon	lda attrib		; turn graphics mode on (enable ROM)
		ani 0FDh
		sta attrib
		ret

dografoff	lda attrib		; turn graphics mode off (disable ROM)
		ori 2
		sta attrib
		ret



;
; Data section.  If you want to change the default modes (e.g., to
; wrapping and scrolling), this is the place to do it.  (Just change
; wrapp and scrollp.)
;

curaddr	dw 0				; logical address of cursor
lastprow	db vnrows - 1		; physical last row
lastlrow	db vnrows - 1		; logical last row
attrib	db 3				; character attribute byte
escmode	db 0				; escape-sequence mode
wrapp	db 0				; wrap at end of line?
insmode	db 0				; insert-character mode
scrollp	db 0				; scroll mode
curoffp	db 0				; cursor-off mode
insdelcnt	db 0				; insert/delete line count

; End of Z-19.ASM -- Z-19 Emulator for SSM VB3