;**********************************************
;*					      *
;*	BIOS ROUTINES FROM EPROM MONITOR      *
;*					      *
;**********************************************
;
;This file is an excerpt from my EPROM monitor, listing several I/O routines
;useful for a high-level ROM-based driver for CP/M and UCSD Pascal.
;With luck, you will find it useful to draw from, in particular the following:
; 0.  Highly compact Z-80 code, designed to run quickly.
; 1.  Video driver routines for a memory-mapped 24x80 terminal, including:
;     a.  Choice of scrolling (with choice of speed) or page-type (with
; 	  optional wait at end of screen) operation.
;     b.  Full screen and cursor commands for the UCSD editor.
; 2.  Interrupt-driven keyboard routines featuring a type-ahead queue.
; 3.  Interrupt-driven flushing and/or halting outputs as desired.
; 4.  Printer routines offering:
;     a. Two types of printer (daisywheel and dot-matrix).
;     b. A Diablo driver supporting std & proportional-spaced printwheels.
;     c. Expansion of horizontal tabs.
;
;THE REST OF THE MONITOR IS AN OFFSHOOT OF TDL'S ZAPPLE.  IF YOU WOULD LIKE
;A COPY OF IT, SEND ME A DISK WITH RETURN POSTAGE AND SOME SORT OF PROOF THAT
;YOU HAVE PURCHASED ZAPPLE (NOW SOLD THROUGH COMPUTER DESIGN LABS).
;
;This program is designed to be assembled by the TDL assembler, though it is
;easily altered to work with Digital Research's macroassembler.
.XLINK
.PABS
.PHEX
.LOC	  0F000H
;JUMP VECTORS:
BASE:	JMP	CSTART	;COLD START ROUTINE--designed here as a subroutine only
CI:	JMP	MCI
	JMP	RI
JCO:	JMP	CO
	JMP	PO
	JMP	LIST
CSTS:	JMP	MCSTS
;
;   <<< CONTROL CHARACTER ASSIGNMENTS >>>
;
BELL	=  7
BS	=  8
HT	=  9	;  "   HORIZONTAL TAB
LF	= 10	;  "   LINE FEED
FF	= 12	;  "   FORM FEED (OR CLEAR CRT)
CR	= 13	;  "   CARRIAGE RETURN
GOTYCH	= 14	;^N = MOV CURS TO Y = (B)
CRONLY	= 11H	;^Q = CARRIAGE RETURN ONLY
DC1	= 11H	;ASCII DC1 FOR DIABLO
TONECH	= 12H	;^R = PLAY NOTE DETAILED IN HL
DC3	= 13H	;ASCII DC3 FOR DIABLO
NDFSCH	= 14H	;^T = NONDESTRUCTV FORWRD SPACE
EEOLCH	= 15H	;^U = ERASE TO END OF LINE
EEOSCH	= 16H	;^V = ERASE TO END OF SCREEN
RLFCH	= 17H	;^W = REVERSE LINE FEED
GTXYCH	= 18H	;^X = GO TO XY (NEXT 2 CHARS)
REVCH	= 19H	;^Y = REVERSE FIELD TOGGLE
HOMECH	= 1AH	;^Z = HOME CURSOR
ESC	= 1BH	;ASCII ESCAPE
GREYCH	= 1CH	;^\ = GREY ENABLE TOGGLE
GRPHTG	= 1DH	;^] = GRAPHICS (PCG) TOGGLE
PADNXT	= 1EH	;^^ = NXT CHAR IS # USPACS TO PAD
;
.REMARK|
   <<< STS DATA >>>  this is STatuS word that is primary controller of options

BIT 0	1 = PROPORTIONAL SPACING PWHEEL PRESENT
BIT 1	EDIT MODE/ENABLE JOYSTICK (1 = ON)
BIT 2	WAIT ENABLE (1 = WAIT, PAGE MODE ONLY)
BIT 3	SLOW SCROLL ENABLE (1 = SLOW)
BIT 4	-PAGE/+SCROLL MODE
BIT 5	PRINTER TOGGLE: 0 = MALIBU / 1 = DIABLO
BIT 6	BIOS TYPE (0 = CPM, 1 = PASCAL)
BIT 7	TOGGLE: 1->PRINTER TO FOLLOW CONSOL OUTPUT

   <<< IOBYTE DATA >>>

A.	INTEL STANDARD IOBYTE - LOCATN 0003
BITS 0,1 = CONSOLE (0=TTY,1=CRT,2=BATCH,3=USR)
BITS 2,3 = READER (0=TTY,1=FAST READR,3&4=USR)
BITS 4,5 = PUNCH (0=TTY,1=FAST PUNCH,3&4=USR)
BITS 6,7 = LIST (0=TTY,1=CRT,3=LIN PRTR,4=USR)
NOTE: IN ZAPPLE, 3 IN READER/PUNCH = CASSETTE

B.	MY USE
BIT 0	1 = BEEP OCCURS WITH KEYBOARD INPUT
BIT 7	1=LIST -> SELECTED PRINTER // 0= -> CRT

   <<< SPECIAL CHAR SEQUENCE DOCUMENTATION >>>
TYPING A "^]" THEN ANOTHER CHARACTER
	ALLOWS YOU TO DO THE FOLLOWING:
   WHEN THE NEXT
    CHAR IS A:	    YOU GET:
	"]"	CRT SCREEN CLEARS
	"\"	FORMFEED TO MALIBU
	"@"	FORMFEED TO DIABLO
	"L"	LOGICAL LIST --> PRINTER
	"C"	   "	 "   --> CRT
	"D"	PRINTER SWITCHES TO DIABLO
	"M"	PRINTER IS MALIBU (DEFAULT)
	"R"	DIABLO HAS PROPORTIONAL-SPACE
		 PRINTWHEEL
	"A"	DIABLO HAS PLAIN PRINTWHEEL
	"F"	PRINTER FOLLOWS CONSOLE OUTPUT
	"N"	NO PRINTER FOLLOWING CONSOLE
	"B"	COMPUTER BEEPS WHEN KEY PRESSED
		 (TOGGLE)
	"E"	EDIT (JOYSTICK) TOGGLE
	"S"	SLOW SCROLL TOGGLE
	"P"	PAGE/SCROLL TOGGLE
	"W"	WAIT AT SCREEN BOTTOM ENABLE
	<ESC>	SKIP THE ENTIRE THING
|
;   <<< CONSTANTS >>>
;
;MEMORY CONSTANTS:
MSIZE	= 56	;SIZE OF MEMORY IN KBYTES
MEMSIZ	= (MSIZE*1024)-1 ;LAST RAM ADDRESS
MSTACK	= MEMSIZ-43H	;MONITOR STACK
USTACK	= MEMSIZ-57H	;USER STACK
GOEXIT	= MEMSIZ-2DH	;START OF EXIT ROUTN
LOCGOT	= MEMSIZ - 2AH	;GOTO INSTRUCTION
LOCLXI	= GOEXIT	;LXI H	   "
LOCUSP	= MEMSIZ - 2FH	;USER SP STORAGE
;
;MAP OF I/O CONTROL WORDS
IOBYTE	= 3	;NOT INTEL STANDARD
KYBDBF	= 20H	;16 BYTES OF KEYBOARD BUFFER
COLMNO	= 41H	;PRINTER COLUMN NO FOR H TAB
STS	= 42H	;STATUS WORD FOR I/O OPERATIONS
STSINZ	= 10H	;INITIAL STS VALUE
OUTCTL	= 43H	;RSRVD FOR PASCAL, OUTPUT CONTL
  ;00 = OUTPUTS ENABLED; 0FFH = DUMP OUTPT (^F
  ;TOGGLE); ANYTHING ELSE = STOP (CTL S TOGGLE)
CIPTR	= 44H	;CI ROUTN POINTR FOR KYBD BUFF
KYBDPR	= 45H	;KYBD INTERRPT RTN PNTR, KYBDBF
COL	= 46H	;COLUMN NO.
LIN	= 47H	;LINE NO.
LASTLN	= 48H	;LAST LINE (CHANGE TO SCROLL)
REVERS	= 49H	;REVERSE FIELD TOGGLE (BIT 7)
CTOGGL	= 49H	;0-3: CONTROL NIBBLE FOR VIDEO
LASTCH	= 4AH	;LAST CHAR PRINTED (DIABLO PS)
LASTSP	= 4BH	;SPACING OF LAST CHAR (DIABLO)
OLDDSP	= 4CH	;CURRENT SPACING OF DIABLO (PS)
PDWITH	= 4DH	;USED BY R-JUSTIFYING TEXT OUT-
; PUTTERS: STORES # MICROSPCS TO ADD TO NXT BLNK
DOPAD	= 4DH	;0FFH -> NEXT CHAR = NO. USPACES
COFLAG	= 4EH	;MULTIPLE USES, ONLY 1 AT A TIME:
; BIT 0: 1 -> NEXT CHAR = GO TO Y COORD (+20H)
; BIT 1: 1 -> NEXT CHAR = "  "  X   "      "
; BIT 6: BACKSLASH FLAG (USED CP/M ONLY, 6&7 USED
; BIT 7: DELETE FLAG	TO DUMP ECHOING DELETED CHAR)
ERRFLG	= 4FH	;DISK I/O ERROR FLAG FOR PASCAL
DMAADD	= 50H	;DMA ADDRESS STORAGE, DISK I/O
NBYTES	= 52H	;NO. BYTES TO R/W THIS SECTOR
;
;   <<< DISK I/O TEMPORARIES >>>--disk routines still in progress
;
DSKTMP	= MEMSIZ-21H	;START OF DISK TEMP'S
SECLEN	= DSKTMP	;0=128/2=512 BYTES/SECTOR
DSKDR	= SECLEN+1	;CURRENT DISK DRIVE
NUMSEC	= DSKDR+1	;# SECTORS PER TRACK
NUMDSK	= NUMSEC+1	;# DISKS ON LINE (1-4)
DBLSID	= NUMDSK+1	;0FFH = DBL-SIDED DRIVE
ERCNT	= DBLSID+1	;ERROR COUNT, DISK I/O
IDECNT	= ERCNT+1	;ERROR COUNT, ID READ
TRK	= IDECNT+1	;CURRENT TRACK NO.
SECT	= TRK+1		;CURRENT SECTOR NO.
;	IDTAB IS THE BUFFER FOR ID READS
IDTAB	= SECT+1	;TRACK NO.
IDTAB1	= IDTAB+1	;ZERO
IDTAB2	= IDTAB+2	;SECTOR NO.
IDTAB3	= IDTAB+3
IDTAB4	= IDTAB+4	;CRC
IDTAB5	= IDTAB+5	;CRC
;
TRKTBL	= IDTAB+6
;
.REMARK|
TRKTBL CONTAINS TRACK SECTOR SIZE & DENSITY
FOR EACH DISK DRIVE (MAX 4 DRIVES)

DRIVE   ADDR	   TRACK     DENSITY	 SECSIZ
  4	TRKTBL	   0 - 76    1 OR 2	 0 OR 2
  5	TRKTBL+3
  9	TRKTBL+6
 10	TRKTBL+9


MAP OF CONTROL PORT (AT 'CRTPRT'):  (port contolling Objectv Desgn video)
BIT 0: 0=8/1=7 DOTS/CHAR HORIZONTALLY
BIT 1: 0=DISABLE/1=ENABLE VIDEO OUTPUT
BIT 2: 0=NO WAIT/1=WAIT FOR HORZ SYNC(NO SNOW)
BIT 3: 0=LOW/1=HIGH BEEP CONTROL BIT
BIT 4: 0=CLR&DISABLE/1=ENABLE INTERRUPT
BIT 5: 0=LOW/1=HIGH EXTERNAL CONTROL BIT
BIT 6: 0=TO 5027/1=TO MEMORY: VIDEO R/W
BIT 7: MEMORY: 0=CHARACTER AREA/1=4-BIT CNTRL

5027 ADDRESSES/DATA:  (main LSI chip on Objectv Design Video board)
ADD TVADD TO EACH OF THE FOLLOWING ADDRESSES:
0 =	HORIZONTAL LINE CNT (TOT WIDTH) 8 BITS
1 =	7	6 5 4 3		2 1 0
	0	HOR SYNC WIDTH	HOR SYNC DELAY
2 =	7	6 5 4 3		2 1 0
	0(X)	SCANS/ROW	CHARS/DATA ROW
3 =	7 6		5 4 3 2 1 0
	SKEW (10)	DATA ROWS/FRAME
4 =	SCAN LINES/FRAME (BUT -256 AND /2)
5 =	VERTICAL DATA START
6 =	LAST DISPLAYED DATA ROW
A =	RESET
B =	UP SCROLL
E = 	START TIMING CHAIN

	<<< MAP OF STACK >>>

IN *ASCENDING* ORDER (ON TOP OF MEMORY)  (ASSUME 56K)
DFA0 ON DOWN:	CP/M OR PASCAL BIOS
DF80 - DFA7:  USER STACK (28H BYTES)
DFA8:	      INITIAL USER SP
DFA8 - DFBB:  MONITOR STACK (14H BYTES)
DFBC:	      INITIAL MONITOR SP
DFBC - DFD1:  USER REGISTR STORAGE (14H BYTES): (see Zapple monitor)
	DFBC:		R
	DFBD:		I
	DFBF,E:		Y
	DFC1,0:		X
	DFC2:		F'
	DFC3:		A'
	DFC5,4:		BC'
	DFC7,6:		DE'
	DFC9,8:		HL'
	DFCB,A:		DE
	DFCD,C:		BC
	DFCE:		F
	DFCF:		A
	DFD1,0:		STACK POINTER
DFD2 - DFDD:	EXIT ROUTINE (0CH BYTES)
	DFD3,4:		HL REG STORAGE
	DFD6,7:		PC  "	"
	DFD8,9:		1ST TRAP ADDRESS
	DFDA:		1ST  "	 DATA
	DFDB,C,D:	2ND TRAP
DFDE - DFDD:	DISK I/O TEMPORARIES
DFFE,DFFF:	KYBD INPUT VECTOR
	TOP OF MEMORY

<<NOTE>>
THE BIOS MUST LEAVE 128 BYTES FREE FOR PROPER
MONITOR FUNCTION, THOUGH 96 (60H) ARE ENOUGH 
IF STACK NOT USED
|
;CONSTANTS
TVHADD	= 0E8H		;HI BYTE TVADDRESS
CRTPRT	= 0E8H		;OUTPUT CONTROL PORT
TVADD	= TVHADD * 100H ;TOTAL ADDRESS
TVRESET	= TVADD + 0AH	;RESET 5027
TVSTART	= TVADD + 0EH  ;START 5027 TIMING CHAIN
CRTINT	= 7	;INITLIZING DATA FOR CNTRL PORT
MAXCOL	= 80	;MAX COLS PER LINE
MAXLIN	= 24	;MAX LINES PER PAGE
PASMSK	= 40H	;STS MASK FOR PASCAL BIT
PAGMSK	= 10H	;STS MASK FOR PAGE/SCROLL BIT
PCGRAM	= 0E000H	;START OF PCG RAM
;
ADR0	= 0E0H	;DMA ADDR. REGISTR PORT
WCT0	= 0E1H	;DMA WORD COUNT REGISTER PORT
CMND	= 0E8H	;DMA COMMAND REGISTER PORT
ADISK	= 0F8H
DCOM	= ADISK
DSTAT	= ADISK
TRACK	= ADISK+1
SECTP	= ADISK+2
DDATA	= ADISK+3
DWAIT	= ADISK+4
DCONT	= ADISK+4
DMACHK	= ADISK+5 ;DMA INTRQ. CHECK PORT
;
;CURSOR-MOVING INPUT CHARACTERS, USED BY READJY
UPCURS	= 11	;^K (V-TAB)
DNCURS	= LF
RTCURS	= FF	;^L
LFCURS	= BS
;
;I/O PORTS:
LINEPT	= 21H	;MALIBU PRINTER STATUS/DATA
DBSTAT	= 24H	;DIABLO STATUS INFO
DBDATA	= 25H	;DIABLO DATA PORT
TARBST	= 0	;TARBELL STATUS
TARBDA	= 1	;TARBELL DATA
HORJOY	= 0FH	;HORIZONTAL POT OF JOYSTICK
VERJOY	= 0EH	;VERTICAL POT
SENSE	= 0FFH	;SENSE SWITCHES
;
TVPARM: .BYTE	70H,7BH,4DH,97H,03H,14H,23
;
ONMSG:	.ASCIZ	[FF]'GZAP MONITOR V2.0'
;
CSTART: MVI	A,STSINZ  ;INITL STS VALUE
	STA	STS
	MVI	A,81H	;INITL IOBYTE
	STA	IOBYTE
	LXI	SP,MSTACK
	LXI	D,ONMSG
	CALL	PRTMSG
ESTART: CALL	WARMIZ	  ;ERROR START POINT
	RET		;normally, monitor would start here
;
WARMIZ:	SUB	A	;this routine is also called by external
	STA	COLMNO	; routines (primarily CP/M and Pascal BIOS) when
	LXI	H,REVERS ; I wish to reinitialize console i/o.
	MVI	B,7
..ZERO:	MOV	M,A	;zero out part of i/o variable space
	INX	H
	DJNZ	..ZERO
	LXI	H,MEMSIZ-2  ;JUST BELOW KYBDVC
	MVI	B,66
..ZRIT:	MOV	M,A	;zero out high memory
	DCX	H
	DJNZ	..ZRIT
	LXI	H,USTACK
	SHLD	LOCUSP	;INITLZ USER SP--used by Zapple
	MVI	A,0C3H
	STA	LOCGOT	;JUMP INSTRUCTN
	STA	38H	;TRAP
	MVI	A,21H	;LXI H,... INSTRUCTN
	STA	LOCLXI
	LXI	H,TRAP	;38h contains jump to monitor trap
	SHLD	39H
	LXI	H,KYBDBF
	MOV	A,L
	STA	CIPTR
	STA	KYBDPR
	MVI	B,10H
IKBF:	MVI	M,0FFH	;fill keyboard buffer with 0ffh's (means empty)
	INX	H
	DJNZ	IKBF
	LXI	H,KYBDIN
	SHLD	MEMSIZ-1	;KYBDVEC LOCATN
	RET
;
;
;MONITOR I/O ROUTINES
;
;	The joystick routines utilize a Cromemco D + 7A I/O board.
HORPOS: MVI	A,RTCURS
	RNC
	MVI	A,LFCURS
	RET
;
VERPOS: MVI	A,UPCURS
	RNC
	MVI	A,DNCURS
	RET
;
GETVER: IN	VERJOY
GETDIS: RAL		;input is in 2's compliment
	JRC	FLIPIT	;1 in bit 7 -> negative displacement
	ANI	0C0H	;ignore any but > 1/4 from center
	RET
FLIPIT: CMA
	ANI	0C0H
	STC
	RET
;
READJY: POP	H	;joystick routine begins here
	EI
	PUSH	B
	LDA	STS	;see if joystick enabled
	ANI	2
	JRZ	CFLASH	;skip if not
	IN	HORJOY
	CALL	GETDIS
	JRNZ	GETJTM	;got a horizontal displacement
	CALL	GETVER
	JRZ	CFLASH	;skip if no horiz or vertical displacement
GETJTM: CPI	40H	;see the magnitude of the displacement
	JRNZ	NXTJOY
	MVI	C,14	;least displacement -> longest delay
	JMPR	JOYTIM
NXTJOY: CPI	80H
	JRNZ	NXTJY1
	MVI	C,4	;mid displacement -> less delay
	JMPR	JOYTIM
NXTJY1: MVI	C,1	;must be great displacement, short delay
JOYTIM: CALL	FLSHTV	;flash cursor for length of time in C
	POP	B
	JRNZ	MCI	;but abort if key pressed
	IN	HORJOY	;now look at joystick all over again
	CALL	GETDIS	; to see if changed
	JRNZ	HORPOS	;and return appropriate control char if displaced
	CALL	GETVER
	JRNZ	VERPOS
	PUSH	B
CFLASH: MVI	C,20	;flash cursor to let 'em know you're waiting
	CALL	FLSHTV
	POP	B
;
MCI:	PUSH	H	;main console input routine entry
	MVI	A,MEMSIZ>8  ;HIBYTE	;this sets up correct location of
	STAI				;keyboard interrupt jump vector
	IM2				; ("KYBDVEC")
	CALL	CHKCI
	JRZ	READJY	;if no input waiting, see if joystick enabled
	DCR	A	; else correct char input
	MVI	M,0FFH	;store 0ffh to mark buffer spot blank
	PUSH	PSW
	LDA	IOBYTE
	RAR		;if enabled,
	CC	BEEP	;ACKNOWLEDGE KYBD INPUT
	MOV	A,L
	STA	CIPTR	;save present buffer pointer
	POP	PSW
	POP	H
	RET
;
BEEP:	PUSH	B	;this routine puts out a very brief "beep" to
	MVI	H,5	; my speaker (via the Cromemco D+7AI/O) to mark
	MVI	C,60H	; keyboard input.  A rough sawtooth wave.
..LOOP:	MOV	B,C
	MVI	A,7FH
	OUT	9
..B0:	DJNZ	..B0
	MVI	A,40H
	OUT	9
	MOV	B,C
..B1:	DJNZ	..B1
	SUB	A
	OUT	9
	MOV	B,C
..B2:	DJNZ	..B2
	DCR	H
	JRNZ	..LOOP
	POP	B
	RET
;
MCSTS:	PUSH	H	;this is main Console STatuS routine
	CALL	CHKCI
	POP	H
	RZ		;0 -> no input char awaiting
	MVI	A,0FFH	;0ffh -> input char ready
	RET
;
CHKCI:	LHLD	CIPTR
	MVI	H,0
	MOV	A,M
	INR	A
	RNZ
CHKNCH: INX	H
	MOV	A,L
	ANI	0FH
	JRNZ	OKPTR
	LXI	H,KYBDBF
OKPTR:	MOV	A,M
	INR	A
	RET
;
KYBDIN: PUSH	PSW	;this is main keyboard interrupt handler
	PUSH	B
	PUSH	H
	CALL	SVKYBD	;doing it this way allows multiple exits,
	POP	H	; but only one set of register push/pop's
	POP	B
	POP	PSW
	EI
	RET
;
SVKYBD: IN	20H	;data port - no need to check status port (caused
	ANI	7FH	; interrupt)
	CPI	1DH	;^] = GO TO SPECIAL I/O
	JRZ	SPECIO	;     ROUTINE
	CPI	6	;^F = PASCAL FLUSH ALL
	JRZ	SOCTL	;     OUTPUT TOGGLE
	CPI	13H	;^S = PASCAL STOP ALL
	JRZ	SOCTL	;     OUTPUT TOGGLE
	CPI	1EH	;CTL '^' = FORCED ERROR
	JRZ	GOTRAP
	PUSH	PSW	;SAVE CHAR
STOCHR: LHLD	KYBDPR
	MVI	H,0
	MOV	A,M	;see where next empty buffer slot is
	INR	A
	JRZ	PUTCHR
	CALL	CHKNCH
	JRZ	PUTCHR
	CALL	HONK	;error with buffer pointer
	POP	PSW
	RET
PUTCHR: POP	PSW	;got an empty slot; store char
	MOV	M,A
	MOV	A,L
	STA	KYBDPR
	RET
;
SOCTL:	PUSH	PSW	;SAVE CHARACTER
	LDA	STS	;SEE IF ENABLED
	ANI	40H	;ONLY FOR PASCAL
	JRZ	STOCHR
	LDA	OUTCTL	;NOW SEE WHAT TO DO
	ORA	A	;IF NOW 0, SET IT
	JRZ	SETOC
	INR	A	;IF FF, RESET IT
	JRZ	RESOC
	POP	PSW   ;ELSE CHECK IF CHNG FROM
	CPI	6     ;STOP TO DUMP (CTL F = 6)
	JRZ	SETDMP	;THEN SET TO DUMP
	PUSH	PSW	;ELSE 
RESOC:	POP	PSW	;RESET OUTCTL
	SUB	A
	JMPR	STOROC
SETOC:	POP	PSW
	CPI	13H	;IF ^S (STOP OUTPUT),
	JRZ	STOROC	;THEN STORE NON-0/FF
SETDMP: MVI	A,0FFH	;ELSE SIGNAL DUMP
STOROC: STA	OUTCTL
	RET
;
GOTRAP: POP	H	;CLEAR RETURN TO KYBDIN
	POP	H	;RESTORE REGISTERS
	POP	B
	POP	PSW
	JMP	RESTART	;this is my trap routine--you'll have to add your own
;			*NOTE* RESTART is not defined in this short version!!!
SPECIO: CALL	MCI	;this routine allows you to change i/o parameters on
	ANI	05FH	;CONVT TO UPPER CASE		the fly!
	CPI	ESC	;A WAY OUT
	RZ
	MVI	C,FF	;READY TO CLEAR
	LXI	H,STS	;OR FIX STS
	CPI	']'	;CLEAR TV
	JZ	CO
	CPI	'D'	;CHANGE TO DIABLO
	JRZ	..DIAB
	CPI	'R'	;PROPORTNL SPACE WHEEL
	JRZ	..PSPC
	CPI	'A'	;STANDARD PRINTWHEEL
	JRZ	..SSPC
	CPI	'M'	;CHANGE TO MALIBU
	JRZ	..MALB
	CPI	'P'	;PAGE/SCROLL MODE TOGGL
	JRZ	..PAGE
	CPI	'S'	;SLOW DOWN SCROLL TOGGL
	JRZ	..SLOW
	CPI	'W'	;WAIT AT BOTTOM TOGGLE
	JRZ	..WAIT
	CPI	'E'	;EDIT (JOYSTICK) TOGGLE
	JRZ	..EDIT
	CPI	'F'	;PRINTER FOLLOWS CNSOLE
	JRZ	..FLLW	; (PASCAL ONLY)
	CPI	'N'	;PRINTER DOES NOT
	JRZ	..NOFW	; FOLLOW CONSOLE
	CPI	'\'	;FORM FEED TO MALIBU
	JRZ	..MFF
	CPI	'@'	;FORM FEED TO DIABLO
	JRZ	..DFF
	LXI	H,IOBYTE
	CPI	'B'	;KEYBOARD BEEP TOGGLE
	JRZ	..BEEP
	CPI	'L'	;LOGICAL LIST--> PRINTR
	JRZ	..LIST
	CPI	'C'	;LOGICAL LIST--> CRT
	JRNZ	SPECIO	;ELSE WRONG CHAR TYPED
	RES	7,M
	RET
..DIAB:	SET	5,M
	RET
..PSPC:	SET	0,M	;PROPORTIONAL-SPACE
	RET
..EDIT: MVI	A,2	;EDIT BIT
	JMPR	..TSTS
..FLLW:	SET	7,M	;PRINTER TO FOLLOW CO
	RET
..MALB:	RES	5,M	;PRINTER TO MALIBU
	RET
..NOFW:	RES	7,M	;NO PRINTER FOLLOW
	RET
..SSPC:	RES	0,M	;STANDARD PRINTWHEEL
	RET
..PAGE:	MVI	A,10H
..TSTS:	XRA	M	;TOGGLE STS
	MOV	M,A
	RET
..SLOW: MVI	A,8
	JMPR	..TSTS
..WAIT: MVI	A,4
	JMPR	..TSTS
..MFF:	MOV	A,C
	OUT	LINEPT
	RET
..DFF:	MOV	A,C
	OUT	DBDATA	;HOPE NO CONFLICT
	RET
..BEEP: MVI	A,1
	JMPR	..TSTS
..LIST:	SET	7,M	;SET BIT 7
	RET
;
;
GETPAD:	MOV	A,C
	SUI	20H
	STA	PDWITH
	RET
;
LIST:	LDA	DOPAD	;this is entry to main list routine
	INR	A	;SEE IF THIS CHAR = # U-SP (no. of microspaces)
	JRZ	GETPAD
	LDA	IOBYTE	;IF LIST NOT -> CRT,
	RAL		;
	JRC	..OK	;THEN DO IT,
	LDA	STS	;ELSE IF LISTER TRYING
	RAL		;  TO FOLLOW CRT,
	RC		; THEN DUMP, (don't write it twice on CRT)
	JMP	CO	; ELSE SEND IT TO CRT
..OK:	PUSH	H
	PUSH	D
	PUSH	B
	CALL	DOLIST
	POP	B
	POP	D
	POP	H
	MOV	A,C
	RET
;
DOLIST:	CALL	CHKOCL	;CHECK OUTCTL IF ENABLD
	MOV	A,C
	RNZ		;DUMP IF CTL F ACTIVE
	LXI	H,COLMNO
	CPI	' '
	JRC	LOCTL	;special handling for control characters
	INR	M	;INCR COLUMNO
GOLO:	LDA	STS	;SEE WHICH PRINTER
	BIT	5,A	;STS BIT 5 DETERMINES
	JRNZ	GODIAB
;
;MALIBU DRIVER ROUTINE	-- next few steps dump characters that mess up listing
	CPI	13H	;10 STEPS/LF = GRAPHICS
	RZ		; LINE FEED
	CPI	16H	;STANDARD GRAPHICS CHAR
	RZ		; SET
	CPI	17H	;16 STEPS/LF = CONDENS-
	RZ	  ;ED LF (NORMAL = 20 STEPS/LF)
LIST0:	CPI	10H	;ALT CHR SET 1;  <NOTE>
	RZ	    ;ENTER HERE;FOR NL GRAPHICS (BUT MOV A,C)
	CPI	12H	;ALT CHAR SET 2
	RZ
LIST1:	IN	LINEPT	;status port (input) = data port (output)
	RAR
	JRC	LIST1
	MVI	A,20H
..LLP:	DCR	A
	JRNZ	..LLP
	MOV	A,C
	CPI	'}'	;MALIBU WON'T PRINT RT
	JRNZ	..GO	; BRACKET.
	MVI	A,'>'
..GO:	OUT	LINEPT
	RET
;
LOCTL:	CPI	CR	;control character routines to keep column no. current
	JRZ	..CR
	CPI	CRONLY
	JRZ	..CRO
	CPI	BS
	JRZ	..BS
	CPI	PADNXT
	JRZ	..PAD
	CPI	HT
	JRNZ	GOLO
..HT:	MVI	C,' '	;expand horizontal tabs
	CALL	LIST
	MOV	A,M
	ANI	7
	JRNZ	..HT
	RET
..CRO:	MVI	C,CR
..CR:	MVI	M,0
	JMPR	GOLO
..BS:	DCR	M
	JMPR	GOLO
..PAD:	MVI	A,0FFH	;pad char means next char is extra no. of microspaces
	STA	DOPAD	; to add to next blank (used with Diablo to ease right
	RET		; justification)
;
GODIAB:	RAR		;SEE WHICH PRINTWHEEL
	JRNC	DIABLO	;JUMP IF STANDARD
;
PRPRTL:	LXI	H,LASTCH ;PROPORTIONAL SPACING
	MOV	A,C
	SUI	' '	;NOW SEE WHAT CHAR
	JRNC	..PRT	;JMP IF PRINTING CHAR
	PUSH	B
	MVI	B,0	;ELSE MUST BE CTL CHAR
	CALL	SPDIAB	;SET 0 SPACES/CHAR
	MOV	C,M	;PRINT OLD CHAR
	CALL	DIABLO
	POP	B
	SUB	A	;TELL 'M LAST WAS CTL
	MOV	M,A
	INX	H
	MOV	M,A
	MOV	A,C	;IF THIS CHAR = BS
	CPI	BS	; THEN EXIT (NOTE: > 1
	RZ		; BS IN ROW IS DUMPED)
	JMPR	DIABLO	;ELSE PRINT & EXIT
..PRT:	PUSH	H
	LXI	H,PROTBL
	MOV	E,A
	MVI	D,0
	DAD	D
	MOV	B,M	;GET NEW DISPLACEMENT
	POP	H
	MOV	A,B	;IS THIS VALID CHAR?
	ORA	A	;0 = NO, PAD W/ BLANK
	JRNZ	..NPAD
	LXI	B,800H + ' ' ;16 USPACES WIDE
..NPAD:	LDA	LASTSP	;OLD DISPLACEMENT
	ORA	A	;WAS LAST CTRL CHAR?
	JRZ	..SKIP	;THEN FORGET SPACING,
	ADD	B	;ELSE GET TOTAL
	PUSH	B	;SAVE CHAR & DISPLCMT
	MOV	B,A	;SEND CORRECT SPACING
	CALL	SPDIAB
	MOV	C,M	;NOW PRINT OLD CHAR
	CALL	DIABLO
	POP	B
..SKIP: MOV	M,C	;STORE THIS CHAR...
	INX	H
	MOV	M,B	; AND THIS DISPLACEMENT
	RET
;
SPDIAB:	LDA	OLDDSP	;IF OLD SPACING = THIS
	CMP	B	; ONE, NOTHING TO DO.
	RZ		;else set spacing to correct new value (in B)
	MOV	A,B
	STA	OLDDSP
	MVI	C,ESC
	CALL	DIABLO
	MVI	C,1FH
	CALL	DIABLO
	MOV	C,B
	INR	C	;ADD ONE TO TRUE SPACE
;
DIABLO: IN	DBSTAT	;diablo driver
	RAL
	JRC	..GCH
..SEND:	IN	DBSTAT
	RAR
	JRNC	..SEND
	MOV	A,C
	OUT	DBDATA
	CPI	' '	;IF SPACE, THEN
	RNZ
	LDA	PDWITH	;SEE IF PADDING NEEDED
	ORA	A
	RZ		;IF NOT, ALL DONE.
	MOV	B,A
	SUB	A
	STA	PDWITH	;RESET
	CALL	SPDIAB	;SET WIDTH OF SP NEEDED
	MVI	C,' '	;TO PAD,
	CALL	DIABLO	; PRINT ALTERED SPACE
	MVI	C,ESC  ;RESTORE NL SPACING (IG-
	CALL	DIABLO ;NORED BY PROPOR SP RTN)
	MVI	C,'S'
	JMPR	DIABLO
;
..GCH:	IN	DBDATA	;see if buffer-full char sent
	CPI	13H
	JRNZ	..SEND	;if not, go on
..WAIT:	IN	DBSTAT	;else wait til empty
	RAL	
	JRNC	..WAIT
	IN	DBDATA
	JMPR	..SEND
;
PROTBL:		;PROPORTIONAL SPACING TABLE
.BYTE	6	;' ', HEX 20 (PRINTS AS CENTS)
.BYTE	3	;'!'
.BYTE	4	;'"'
.BYTE	6	;'#'
.BYTE	5	;'$'
.BYTE	8	;'%'
.BYTE	7	;'&'
.BYTE	2	;'''
.BYTE	3	;'(', HEX 28
.BYTE	3	;')'
.BYTE	5	;'*'
.BYTE	5	;'+'
.BYTE	3	;','
.BYTE	4	;'-'
.BYTE	3	;'.'
.BYTE	4	;'/'
.BYTE	5	;'0', HEX 30
.BYTE	5	;'1'
.BYTE	5	;'2'
.BYTE	5	;'3'
.BYTE	5	;'4'
.BYTE	5	;'5'
.BYTE	5	;'6'
.BYTE	5	;'7'
.BYTE	5	;'8', HEX 38
.BYTE	5	;'9'
.BYTE	3	;':'
.BYTE	3	;';'
.BYTE	6	;'<' (PRINTS AS "1/4")
.BYTE	5	;'='
.BYTE	6	;'>' (PRINTS AS "1/2")
.BYTE	5	;'?'
.BYTE	8	;'@', HEX 40
.BYTE	7	;'A'
.BYTE	6	;'B'
.BYTE	7	;'C'
.BYTE	7	;'D'
.BYTE	6	;'E'
.BYTE	6	;'F'
.BYTE	7	;'G'
.BYTE	7	;'H', HEX 48
.BYTE	3	;'I'
.BYTE	5	;'J'
.BYTE	7	;'K'
.BYTE	6	;'L'
.BYTE	8	;'M'
.BYTE	7	;'N'
.BYTE	7	;'O'
.BYTE	6	;'P', HEX 50
.BYTE	7	;'Q'
.BYTE	7	;'R'
.BYTE	5	;'S'
.BYTE	6	;'T'
.BYTE	7	;'U'
.BYTE	6	;'V'
.BYTE	8	;'W'
.BYTE	7	;'X', HEX 58
.BYTE	7	;'Y'
.BYTE	6	;'Z'
.BYTE	0	;'[' NONPRINTING
.BYTE	0	;'\' NONPRINTING
.BYTE	0	;']' NONPRINTING
.BYTE	0	;'^' NONPRINTING
.BYTE	5	;'_'
.BYTE	3	;'`', HEX 60 (PRINTS AS ",")
.BYTE	5	;'a'
.BYTE	5	;'b'
.BYTE	5	;'c'
.BYTE	5	;'d'
.BYTE	5	;'e'
.BYTE	4	;'f'
.BYTE	5	;'g'
.BYTE	5	;'h', HEX 68
.BYTE	3	;'i'
.BYTE	3	;'j'
.BYTE	5	;'k'
.BYTE	3	;'l'
.BYTE	8	;'m'
.BYTE	5	;'n'
.BYTE	5	;'o'
.BYTE	5	;'p', HEX 70
.BYTE	5	;'q'
.BYTE	4	;'r'
.BYTE	4	;'s'
.BYTE	4	;'t'
.BYTE	5	;'u'
.BYTE	5	;'v'
.BYTE	7	;'w'
.BYTE	5	;'x', HEX 78
.BYTE	5	;'y'
.BYTE	5	;'z'
.BYTE	3	;'{' (PRINTS AS ".")
.BYTE	0	;'|' NONPRINTING
.BYTE	0	;'}' NONPRINTING
.BYTE	0	;'~' NONPRINTING
.BYTE	0	;<DEL> NONPRINTING
;
;
;*********************************
;*				 *
;*    SPEAKER DRIVER ROUTINE	 *
;*				 *
;*********************************
;
;PLAY NOTE (PITCH IN L, DURATN IN H)
; NOTE: DURATION IS SHORTER FOR HIGHER PITCH
; [ROUGHLY ~ 1 / LOG (FREQ)]; SHAPE ~ TRIANGLE
TONE:	MOV	D,H
	MOV	E,L
	MOV	C,L
..LOOP:	MVI	A,3AH
	OUT	9
	MOV	B,C
..T1:	DJNZ	..T1
	MVI	A,54H
	OUT	9
	MOV	B,C
..T2:	DJNZ	..T2
	MVI	A,7FH
	OUT	9
	MOV	B,C
..T3:	DJNZ	..T3
	MVI	A,54H
	OUT	9
	MOV	B,C
..T4:	DJNZ	..T4
	MVI	A,3AH
	OUT	9
	MOV	B,C
..T5:	DJNZ	..T5
	MOV	B,C
	SUB	A
	OUT	9
..T6:	DJNZ	..T6
	STC
	RALR	E
	JRNC	..LOOP
	STC
	RALR	L
	JRNC	..LOOP
	DCR	D
	JRNZ	..LOOP
	RET
;
HONK:	LXI	H,5020H	;20H-LONG TONE FREQ 50H
DOTONE:	PUSH	D
	CALL	TONE
	POP	D
	RET
;
;**********************************************
;* OBJECTIVE DESIGN VIDEO DRIVER SUBROUTINES  *
;**********************************************
;
;ENTER AT TVOUT:
;
TVHOME: SUB	A
	MOV	B,A	;Y = 0
	MOV	E,A	;CARRIAGE RTN
;
GOTOY:	LDA	LASTLN	;PUT CURSOR ON LINE
	MOV	D,A	;Y-TH FROM TOP
	INR	B	;PASSED IN B
 ..GY1: CALL	NLF
	DJNZ	..GY1
	RET
;
;SPECCO USED FOR GOTOXY ROUTINES AND CP/M DELETE
; HANDLING (ECHOED CHARACTERS ARE DUMPED AFTER A
; DELETE; THE CURSOR IS BACKED UP INSTEAD.  SPECIAL
; PROVISION IS MADE TO DUMP MBASIC'S BACKSLASHES).
;<NOTE> THE DELETE FLAG <MUST> BE SET IN CP/M CBIOS
; WHEN CONSLIN ROUTINE DETECTS DELETE CHAR TYPED
SPECCO:	LXI	H,COFLAG
	MOV	B,A
	MOV	A,C
	SUI	20H	;PREPARE FOR GOTO X/Y
	DCR	M	;SEE IF GOTOY
	JRZ	..GOTY
	BIT	0,M	;? GOTOX
	JRNZ	..GOTX
	MOV	A,B
	RAL		;A HAS INTACT BYTE
	JRC	..GDF
	RES	6,M	;MUST HAVE BEEN BACK-
	RET		; SLASH FLAG
..GOTY:	MOV	B,A
	JMPR	GOTOY
..GOTX:	MOV	E,A
	RET
..GDF:	MOV	A,C	;IF CHAR = "\", THEN WE'RE
	CPI	'\'	; IN MBASIC; DUMP THIS CHAR
	JRNZ	..NBS	; AND FLAG TO DUMP ONE MORE
	SET	6,M
	RET
..NBS:	CPI	7FH	;DUMP DELETE CHARS
	RZ
	RES	M,7	;ELSE RESET COFLAG
	CPI	' '	; AND IF CONTROL CHAR
	RC		;  THEN DUMP
	MVI	C,BS	;  ELSE DO BS-SPACE-BS
	CALL	CO
	MVI	C,' '
	CALL	CO
	MVI	C,BS
;
TVOUT:	LDA	COFLAG
	ORA	A
	JRNZ	SPECCO
	MOV	A,C
	CPI	' '
	JRC	TVCNTL	;special handling for contrl chars
CHAR:	CPI	40H	;SPECIAL CAPS ALPHABET
	JRC	..C	; (HARDWARE SPECIFIC)
	CPI	60H
	JRNC	..C
	ANI	1FH
	MOV	C,A
 ..C:	LDA	REVERS
	ANI	80H	;GET RID OF ALL BUT 7TH
	ORA	C	;SET BIT IF NEEDED (causes reversed char)
	MOV	M,A
	LDA	CTOGGL	;GET TOGGLE BYTE (<>0 means grey &/or graphics char)
	ANI	0FH	;GET RID OF LAST 4 BITS
	JRZ	..C1
	MOV	B,A	;ctoggl itself moved to control memory
	CALL	CTRL	;SWITCH TO CONTRL MEMRY
	MOV	M,B
	CALL	DSPLY	;RESTORE
 ..C1:	CALL	INCURS
	SUB	A
	ORA	E
	RNZ		;ALL DONE IF NOT START
	JMP	DELLIN	; OF LINE
;
TVCNTL:	CPI	1EH	;+1 > THAN MAX CTL CHAR
	RNC
	SUI	7	;CHAR < 7 IGNORED
	RC
	ADD	A	;2 BYTES/ENTRY
	LXI	H,TVTBL
	MVI	B,0
	MOV	C,A
	DAD	B	;GET DISPLACEMENT
	MOV	C,M
	INX	H
	MOV	B,M
	MOV	H,B
	MOV	L,C
	PCHL
;
TVTBL:	.WORD	HONK	;07 = ASCII BELL
	.WORD	TVBS	;08 = ASCII BACKSP
	.WORD	TVHTAB	;09 = ASCII HTAB
	.WORD	TVLF	;0A = ASCII LINEFEED
	.WORD	QUIT	;0B NOT USED
	.WORD	TVFF	;0C = ASCII FORMFEED
	.WORD	TVCR	;0D = ASCII CR
	.WORD	GOTOY	;0E = GOTOY (PASSED IN B)
	.WORD	QUIT	;0F NOT USED
	.WORD	QUIT	;10 NOT USED <*AVOID*>
	.WORD	TVCR	;11(^Q),ALTERNATE CR
	.WORD	DOTONE	;12(^R),PLAY TONE
	.WORD	QUIT	;13 NOT USED
	.WORD	INCURS	;14(^T),NONDESTRCTIV SP
	.WORD	DELLIN	;15(^U),ERASE TO END LN
	.WORD	DELSCN	;16(^V),ERASE TO END SC
	.WORD	TVRLF	;17(^W),REVERSE LINEFD
	.WORD	GOTOXY	;18(^X),SET GOTOXY FLAG
	.WORD	TVREV	;19(^Y),REVERSE TOGGLE
	.WORD	TVHOME	;1A(^Z),HOME CURSOR
	.WORD	QUIT	;1B NOT USED
	.WORD	TVGREY	;1C(^\),GREY TONE TOGGL
	.WORD	TVPCG	;1D(^]),GRAPHICS TOGGLE
;
GOTOXY:	MVI	A,2
	STA	COFLAG
	RET
;
TVHTAB: MOV	A,E
	CPI	MAXCOL-1;DUMP IF END OF LINE
	RNC
	CALL	INCURS
	MOV	A,E
	ANI	7
	JRNZ	TVHTAB
QUIT:	RET		;USED TO ABORT
;
TVBS:	DCR	E
	RP	    ;OK IF NOT OFF END OF LINE
	INR	E
	RET
;
TVCR:	MVI	E,0
	RET
;
DELSCN: PUSH	D
 ..LP:	CALL	DELLIN
	LDA	LASTLN
	CMP	D
	JRZ	..DONE
	CALL	NLF
	MVI	E,0	;ERASE WHOLE NEXT LINE
	JMPR	..LP
 ..DONE: POP	D
	RET
;
TVRLF:	SUB	A
	ORA	D
	JRNZ	..OK	;CHECK NOT TOP LINE
	LDA	STS	;STILL OK IF NOT
	ANI	PAGMSK	;IN PAGE MODE
	RZ
	MVI	D,24	;RESET D
 ..OK:	DCR	D
	LDA	LASTLN
	CMP	D
	RNZ		;NO SCROLL NEEDED
	DCR	A	;DCRMENT LASTLN FOR REV
	JP	SCROLL	; SCROLL
	MVI	A,23
	JMPR	SCROLL
;
;
INCURS: INR	E	;increment cursor
	MOV	A,E
	CPI	MAXCOL	;INCR OK IF NOT OFF LIN
	RNZ
	DCR	E
	LDA	STS
	CMA
	ANI	PASMSK+PAGMSK	;IF SCROLL MODE
	RZ		;AND PASCAL THEN DUMP
TVCRLF: MVI	E,0	;ELSE CRLF
;
TVLF:	LDA	LASTLN
	CMP	D	;IF NOT LAST LINE,
	JNZ	NLF	; JUST INCR
	CALL	NLF	; ELSE 1ST GO TO NEXT
	LDA	STS	; LINE.
	ANI	PAGMSK	;IF PAGE MODE THEN
	JRZ	TVPAGE
	CALL	SLOSCL	;DELAY IF CHOSEN
	LDA	LASTLN
	INR	A
	CPI	24
	JRC	SCROLL	;CORRECT IF OUT OF
	SUB	A	; BOUNDS
SCROLL: STA	LASTLN	;SAVE FOR FUTURE
	PUSH	PSW	; REFERENCE
	CALL	FRMAT	;GO INTO CONTROL MODE
	POP	PSW
	STA	TVADD+6 ;SEND TO 5027 TO SCROLL
	CALL	DSPLY	;BACK INTO DATA MODE
ERSTLN: PUSH	D	;ERASE THIS WHOLE LINE
	MVI	E,0
	CALL	DELLIN
	POP	D
	RET
TVPAGE: CALL	WAIT	;WAIT IF CHOSEN, THEN:
;
TVFF:	SUB	A	;this part wholly resets TV board
	STA	CTOGGL
	OUT	CRTPRT
	STA	TVRESET	;RESET 5027
	LXI	H,TVPARM
	LXI	D,TVADD
	LXI	B,7
	LDIR
	STA	TVRESET	;DUMMY DATA TO RESET
	STA	TVSTART	;AND START 5027 AGAIN
	MVI	A,23
	STA	LASTLN
	MVI	A,41H	;SWITCH TO DATA
	CALL	CLRIT
	MVI	A,0C5H	;SWITCH TO CNTRL MEMORY
	CALL	CLRIT
	LXI	D,0
	JMPR	DSPLY
;
TVREV:	MVI	A,80H
	JMPR	CTLTGL
TVGREY: MVI	A,1	;GREY MASK	
	JMPR	CTLTGL
TVPCG:	MVI	A,12	;PCG ENABLE SWITCH
CTLTGL: LXI	H,CTOGGL
	XRA	M
	MOV	M,A
	RET
;
DELLIN: PUSH	D	;delete rest of this line
	CALL	CONVT1
	MVI	A,63
	MVI	B,' '
 ..DL1: CMP	E
	JRC	..MT64	;MUST BE PAST 63RD COL
	MOV	M,B
	INX	H
	INR	E
	JMPR	..DL1
 ..MT64: CALL	CONVT1	;SET HL TO NEW MEMORY
	MVI	A,MAXCOL-1	; AREA
 ..DL2: CMP	E
	JRC	..RTN
	MOV	M,B
	INX	H
	INR	E
	JMPR	..DL2
 ..RTN: POP	D
	RET
;
CLRIT:	OUT	CRTPRT
	MVI	B,' '
	LXI	H,TVADD
	LXI	D,780H	;SIZE OF MEMORY
 ..LP:	MOV	M,B
	INX	H
	DCX	D
	MOV	A,D
	ORA	E
	JRNZ	..LP
	RET
;
NLF:	INR	D	;PLAIN, NONSCROLLING
	MOV	A,D	; LINE FEED.
	CPI	24	;OK UNLESS > 23
	RC
	MVI	D,0
	RET
;
;
CONVT:	LHLD	COL	;find present cursor location in screen memory
	XCHG		;D HAS LIN, E HAS COL
CONVT1: MOV	A,E	;ENTER HERE IF ALREADY
	CPI	64	; HAVE LIN & COL
	JRNC	INAUX
	MOV	A,D
	RRC
	RRC		;LIN * 64
	MOV	H,A
	ANI	0C0H
	ADD	E	;ADD COL
	MOV	L,A	;LOW BYTE ABSOLUTE ADDR
	MOV	A,H
	ANI	7
	ADI	TVHADD
	MOV	H,A	;HI BYTE
	RET
INAUX:	ANI	15	;GET DISPLACEMENT
	MOV	L,A	;TEMP STORAG
	MOV	A,D
	RRC
	RRC
	RRC
	RRC		;LIN * 16
	MOV	H,A	;TEMP STORAGE
	ANI	0F0H
	ADD	L
	MOV	L,A	;CORRECT LOW BYTE
	MOV	A,H
	ANI	15
	ADI	TVHADD+6 ;START OF AUX MEM (HI)
	MOV	H,A	;CORRECT HI BYTE
	RET
;
CTRL:	MVI	A,0C0H	;this signals video board to switch to alternate memory
SETPRT: ORI	CRTINT	;ADD INITLZING DATA	(used only for grey scale &
	OUT	CRTPRT				 graphics)
	RET
;
DSPLY:	MVI	A,40H	;go to main display (ie, normal) memory
	JMPR	SETPRT
;
FRMAT:	SUB	A	;switch to 5027 registers
	JMPR	SETPRT
;
STOPIT: HLT		;WAIT FOR ANY INPUT
CHKOCL: LDA	STS	;CHECK IF OUTCTL ENABLD
	ANI	PASMSK
	RZ
	LDA	OUTCTL
	ORA	A	;0 = ALL OK
	RZ
	INR	A	;0FFH = DUMP
	JRNZ	STOPIT
	DCR	A	;RESET ZFLAG
	RET
;
FLSHTV: PUSH	H	;flash cursor for length of time in C
	PUSH	D
	CALL	CONVT
	POP	D
	MOV	B,M
	PUSH	B
	MVI	A,80H
	XRA	M
	MOV	M,A
FLTV0:	CALL	TIMR	;delay
	DCR	C
	JRZ	FLNXT
	CALL	CSTS	;abort if char typed
	JRZ	FLTV0
FLNXT:	POP	B
	MOV	M,B	;restore char
	POP	H
FLTV1:	CALL	CSTS
	RNZ
	DCR	C
	RZ
	CALL	TIMR
	JMPR	FLTV1
;
TIMR:	MVI	B,11
TIM0:	SUB	A
TIM1:	DCR	A
	JRNZ	TIM1
	DJNZ	TIM0
	RET
;
WAIT:	LDA	STS
	ANI	4	;SEE IF WAIT ENABLED
	RZ
WAITOK: JMP	CI	;wait 'til keyboard input (dump) & return
;
SLOSCL: LDA	STS
	ANI	8	;SEE IF SLOW SCROLL
	RZ		; ENABLED.
	IN	0FFH	;SENSE SWITCHES determine time constant
	MOV	B,A
	JMPR	TIM0
;
;
RI:	INR	A
	JRNZ	NORESET ;0FFH IN REG A CAUSES
RRESET: MVI	A,10H	; RESET
	OUT	TARBST
	RET
NORESET: CALL	CSTS
	JRZ	RI1
	CALL	CI
	STC
	RET
RI1:	IN	TARBST
	ANI	10H
	JRNZ	NORESET
	IN	TARBDA
	RET
;
PO:	IN	TARBST
	ANI	20H
	JRNZ	PO
	MOV	A,C
	OUT	TARBDA
	RET
;
;************************
;*	SUBROUTINES	*
;************************
;
;
PRTMSG: LDAX	D
	ORA	A
	RZ
	MOV	C,A
	CALL	CO
	INX	D
	JMPR	PRTMSG
;
BLK:	MVI	C,' '
;
CO:	CALL	CHKOCL
	MOV	A,C
	RNZ
	PUSH	H
	PUSH	D
	PUSH	B
	CPI	FF
	JRZ	..GO
	LDA	STS
	RAL
	CC	LIST
..GO:	CALL	CONVT
	CALL	TVOUT
	XCHG
	SHLD	COL	;SAVE VIDEO PARAMETERS
	POP	B
	POP	D
	POP	H
	MOV	A,C
	RET
;
CRLF:	MVI	C,CR	
	CALL	CO
	MVI	C,LF
	JMPR	CO
;
.END	;but this won't assemble without RESTART being defined or deleted
	; (see keyboard interrupt vector handler)

notes on quickie interrupt hardware:  Tie the interrupt acknowledge line
to an 8T97 (3-state buffer) so that it pulls down Bit 0 when active (but
otherwise does not affect it one way or another).  This will give you an
interrupt vector location at location 0FE hex at any page you wish.

Let me know if the above material is not terribly clear (though I assume
a reasonable knowledge of assembly language programming in my notes, and
I don't think you can use this material without it).