;
;
;
;                     *****              *
;                    *                   *
;                    * * *       **      *
;                         *     *  *     *
;                    *****       **      ******
;
;                         SYSTEM SOLFTWARE
;
;
;                     <<>>     CONSOL     <<>>
;
;
;      VERSION: 1.0:5
;      RELEASE: 10.11.76
;
;
;
;      THIS PROGRAM IS THE MINIMUM SoL OPERATING SYSTEM.
;  IT PROVIDES ALL NECESSARY DISPLAY ROUTINES ALONG WITH
;  STANDARDIZED CALLING POINTS FOR INPUT/OUTPUT OPERATIONS.
;
;      COMMANDS ARE ALSO AVAILABLE TO ENTER DATA TO MEMORY
;  AND TO DISPLAY MEMORY DATA ON THE SCREEN.  AN EXECUTE
;  COMMAND IS PROVIDED TO ALLOW PROGRAM EXCUTION OUTSIDE
;  OF THE CONSOL PROM AND PROVISION IS MADE FOR CASSETTE
;  TAPE LOAD OF PROGRAMS OR DATA.
;
;
;  NOTE: CONSOL,SOLOS AND SOLED ARE REGISTERED TRADEMARKS
;        OF:
;              PROCESSOR TECHNOLOGY CORP.
;                  EMERYVILLE,CALIF
;
;    THE FOLLOWING CODE IS THE PROPERTY OF PROCESSOR
;  TECHNOLOGY CORP.  IT IS DISTRIBUTED ON A 'PERSONAL USE
;  BASIS FOR THE BENIFIT OF SoL SYSTEM OWNERS.  ALL FORMS
;  OF THE CODE ARE COPYRIGHT 1976 BY PROCESSOR TECHNOLOGY
;  AND ALL RIGHTS THERIN ARE RESERVED.
;
;
	ORG	0C000H	; START OF PROM AREA
;
;
;   AUTO-STARTUP CODE
;
	DB	0	; FOUR PHASE WONDER
BGIN	JMP	STRTA
;
;
;
;              ----=  SoL SYSTEM I/O ROUTINES =-----
;
;   THE FOLLOWING CODE IS STANDARDIZED FOR ALL SoL SYSTEM
;   SOLFTWARE IT PROVIDES COMMON ENTRY POINTS FOR INPUT AND
;   OUTPUT OPERATIONS.  CONSOL DOES NOT HAVE PROVISION FOR
;   PARALLEL I/O OPERATIONS BECAUSE OF SPACE LIMITATIONS.
;
;
;
;
;            JUMP TABLE INPUT/OUTPUT ROUTINES
;
;   THIS ROUTINE OUTPUTS THE CHARACTER IN REGISTER 'B' TO
; THE OUTPUT DEVICE POINTED TO BY THE CURRENT OUTPUT SELECT
; REGISTER.  THE DEVICES ARE DEFINED AS FOLLOWS:
;
;       0 - VDM SCREEN
;       1 - SERIAL OUTPUT PORT
;       2 - PARALLEL OUTPUT PORT (NOT AVAILABLE ON CONSOL)
;       3 - ERROR HANDLER
;
;   ENTRY AT:  SOUT SELECTS CURRENT OUTPUT DEVICE
;              AOUT SELECTS DEVICE IN REGISTER 'A'
;
SOUT	LDA	OPORT	; GET PORT NUMBER FROM MEMORY LOCATION
AOUT	ANI	3	; KEEP IT IN CONTROL
	PUSH	H	; WE'LL RESTORE IT LATER
	LXI	H,OTAB	; POINT TO TABLE
	RLC		; COMPUTE ADDRESS
	ADD	L
	MOV	L,A	; WE HAVE IT
	JMP	DISPT	; GO TO HL....
;
;
;
;   THIS ROUTINE INPUTS A CHARACTER TO REGISTER 'A' FROM
; THE CURRENT INPUT DEVICE POINTED TO BY THE CURRENT INPUT
; SELECT REGISTER.
;
;   ENTRY POINTS ARE DEFINED:
;
;         0 - KEYBOARD INPUT
;         1 - SERIAL INPUT
;         2 - PARALLEL INPUT (NOT AVAILABLE ON CONSOL)
;         3 - ERROR HANDLER
;
SINP	LDA	IPORT	; GET PORT NUMBER FROM MEMORY LOCATION
AINP	ANI	3	; WE MUST BE REASONABLE
	PUSH	H	; SAVE H&L
	LXI	H,ITAB	; POINT TO TABLE
	RLC		; THE MATH
	ADD	L
	MOV	L,A	; DONE
	JMP	DISPT	; WE HAVE THE ADDRESS ... GO TO HEAVEN
;
;
;       KEYBOARD INPUT STATUS CHECK
;
;  THIS ROUTINE TESTS THE KEYBOARD STATUS AND RETURNS
;  WITH THE TEST BITS SET.
;
KSTAT	IN	STAPT	; GET STATUS WORD
	ANI	KDR	; TEST KEYBOARD BIT
	RET		; FLAGS ARE SET
;
;
;        KEYBOARD DATA INPUT
;
;  THIS ROUTINE, ENTRY AT KREAD, GETS THE DATA FROM THE
;  KEYBOARD.  ON RETURN THE CHARACTER IS IN REGISTER 'A'.
;
KREA1	POP	H	; JUMP TABLE ENTRY POINT
KREAD	CALL	KSTAT	; CHECK STATUS
	JNZ	KREAD	; WAIT FOR INPUT
	IN	KDATA	; GET DATA
	RET		; GO BACK WITH IT
;
;
;   SERIAL INPUT STATUS CHECK
;
SSTAT	IN	SERST	; GET SERIAL STATUS WORD
	ANI	SDR	; TEST FOR SERIAL DATA READY
	RET		; FLAGS ARE SET
;
;
;    SERIAL DATA INPUT
;
SREA1	POP	H	; RESTORE HL FROM JUMP TABLE ENTRY
SREAD	CALL	SSTAT	; NORMAL ENTRY POINT
	JZ	SREAD	; WAIT FOR INPUT
	IN	SDATA	; GET DATA BYTE
	RET		; WE HAVE IT
;
;
;    SERIAL DATA OUTPUT
;
SEROT	POP	H	; JUMP TABLE ENTRY POINT
SDROT	IN	SERST	; GET PORT STATUS
	RAL		; PUT HIGH BIT IN CARRY
	JNC	SDROT	; LOOP UNTIL TRANSMITTER BUFFER IS EMPTY
	MOV	A,B	; GET THE CHARACTER BACK
	OUT	SDATA	; SEND IT OUT
	RET		; AND WE'RE DONE
;
;
;
;
;
;                VIDEO DISPLAY DRIVER ROUTINES
;
;
;  THESE ROUTINES ALLOW FOR STANDARD VIDEO TERMINAL
;  OPERATIONS.  ON ENTRY, THE CHARACTER FOR OUTPUT IS IN
;  REGISTER B AND ALL REGISTERS ARE UNALTERED ON RETURN.
;
;     THE 'CONSOL' VERSION OF THIS ROUTINE IS A MINIMUM
;  IMPLEMENTATION OF ROUTINES ORIGINATED BY:
;
;               IAN KETTLEBOROUGH
;                      OF
;             COLLEGE STATION, TEXAS
;
;   SOLOS AND SOLED CONTAIN THE ESC SEQUENCES AND OTHER
;  FULL IMPLEMENTATION FEATURES.
;
VDMOT	PUSH	H	; SAVE EVERYBODY
VDMO1	PUSH	D	; ENTRY FROM DEVICE SELECT
	PUSH	B
	PUSH	PSW
	MOV	A,B	; SAVE IN B...STRIP PARITY BEFORE SCREEN!
	LXI	H,TBL
	CALL	TSRCH	; GO PROCESS
;
GOBACK	CALL	VDADD	; GET SCREEN ADDRESS
	MOV	A,M
	ORI	80H
	MOV	M,A	; CURSOR IS BACK ON
GOBK	POP	PSW
	POP	B
	POP	D	; RESTORE ALL REGISTERS
	POP	H
	RET		; EXIT FROM VDMOT
;
;
TSRCH	MOV	A,M	; GET CHR FROM TABLE
	ORA	A
	JZ	CHAR	; ZERO IS THE LAST
	CMP	B	; TEST THE CHR
	INX	H	; POINT FORWARD
	JNZ	NEXT
	PUSH	H	; FOUND ONE ... SAVE ADDRESS
	CALL	CREM	; REMOVE CURSOR
	POP	H
;
;
;    THIS ROUTINE DISPATCHES TO THE ADDRESS POINTED TO
;  BY THE HL REGISTER PAIR.  THE RETURN ADDRESS IS THE
;  LAST ENTRY ON THE STACK.
;
DISPT	MOV	A,M	; GET LOW BYTE
	INX	H
	MOV	H,M	; AND THE HIGH
	MOV	L,A	; WE HAVE PLACED THEM BOTH
	PCHL		; GO TO IT
;
;
NEXT	INX	H	; GO TO NEXT
	INX	H
	JMP	TSRCH
;
;
CHAR	MOV	A,B	; GET CHARACTER
	ORA	A
	RZ		; RETURN IF A NULL
	CPI	7FH	; IS IT A DEL?
	RZ		; GO BACK IF SO
;
;
;
OCHAR	CALL	VDADD	; GET SCREEN ADDRESS
	MOV	A,B	; GET CHARACTER FOR OUTPUT
	ANI	7FH	; NO HIGH BITS GO PAST HERE
	MOV	M,A	; PUT CHR ON SCREEN
	LDA	NCHAR	; GET CHARACTER POSITION
	CPI	63	; END OF LINE?
	JC	OK
	LDA	LINE
	CPI	15	; END OF SCREEN?
	JNZ	OK
;
;   END OF SCREEN...ROLL UP ONE LINE
;
SCROLL	XRA	A
	STA	NCHAR	; BACK TO FIRST CHAR POSITION
SROL	MOV	C,A
	CALL	VDAD	; CALCULATE LINE TO BE BLANKED
	XRA	A
	CALL	CLIN1	; CLEAR IT
	LDA	BOT
	INR	A
	ANI	0FH
	JMP	ERAS3
;
;   INCREMENT LINE COUNTER IF NECESSARY
;
OK	LDA	NCHAR	; GET CHR POSITION
	INR	A
	STA	NCHAR	; STORE THE NEW
	CPI	64
	RC
	XRA	A	; WE'RE PAST THE END... REWIND THE COUNT
	STA	NCHAR
	LDA	LINE	; GET THE LINE COUNT
	INR	A
	ANI	0FH	; MOD 15 INCREMENT
CUR	STA	LINE	; STORE THE NEW
	RET
;
;    ERASE SCREEN
;
PERSE	LXI	H,VDMEM	; POINT TO SCREEN
	MVI	M,80H+' '	; THIS IS THE CURSOR
;
ERAS1	INX	H	; BUMP THE COUNT
	MOV	A,H	; GET HIGH ORDER
	CPI	0D0H	; THE TOP
	JNC	ERAS2
	MVI	M,' '	; PUT IN A BLANK
	JMP	ERAS1
;
ERAS2	XRA	A
	STA	LINE	; ZERO LINE
	STA	NCHAR	; LEFT SIDE OF SCREEN
;
ERAS3	OUT	DSTAT	; RESET SCROLL PARAMETERS
	STA	BOT	; BEGINNING OF TEXT OFFSET
	RET
;
;
CLINE	CALL	VDADD	; GET CURRENT SCREEN ADDRESS
	LDA	NCHAR	; CURRENT CURSOR POSITION
CLIN1	CPI	64	; NO MORE THAN 63
	RNC		; ALL DONE
	MVI	M,' '	; ALL SPACED OUT
	INX	H
	INR	A
	JMP	CLIN1	; LOOP TO END OF LINE
;
;    HOME CURSOR
;
PHOME	XRA	A
	STA	NCHAR
	JMP	CUR
;
; MOVE CURSOR DOWN ONE LINE
;
PDOWN	LDA	LINE
	CPI	15
	RZ	; HOW FAR IS DOWN?
	INR	A
	JMP	CUR
;
; ROUTINE TO MOVE THE CURSOR UP ONE LINE
;
PUP	LDA	LINE	; GET LINE COUNT
	ORA	A
	RZ		; DON'T GO MORE UP THAN UP
	DCR	A
	JMP	CUR
;
;  MOVE CURSOR LEFT ONE POSITION
;
PLEFT	LDA	NCHAR
	ORA	A
	RZ		; DON'T GO MORE BACK THAN BACK
	DCR	A
PCUR	STA	NCHAR
	RET
;
;     CURSOR  RIGHT ONE POSITION
;
PRIT	LDA	NCHAR
	CPI	63
	RZ		; HOW RIGHT CAN WE BE?
	INR	A
	JMP	PCUR
;
;   ROUTINE TO CALCULATE SCREEN ADDRESS
;
;   ENTRY AT:    RETURNS:
;
;         VDADD  CURRENT SCREEN ADDRESS
;         VDAD2  ADDRESS OF CURRENT LINE, CHAR 'C'
;         VDAD   LINE 'A', CHARACTER POSITION 'C'
;
VDADD	LDA	NCHAR	; GET CHARACTER POSITION
	MOV	C,A	; IC' KEEPS IT
VDAD2	LDA	LINE	; LINE POSITION
VDAD	MOV	L,A	; INTO 'L'
	LDA	BOT	; GET TEXT OFFSET
	ADD	L	; ADD IT TO THE LINE POSITION
	RRC		; TIMES TWO
	RRC		; MAKES FOUR
	MOV	L,A	; L HAS IT
	ANI	3	; MOD THREE FOR LATER
	MOV	D,A
	MVI	A,VDMEM SHR 8 ; LOW SCREEN OFFSET
	ADD	D
	MOV	H,A	; NOW H IS DONE
	MOV	A,L	; TWIST L'S ARM
	ANI	0C0H
	ADD	C
	MOV	L,A
	RET		; H & L ARE NOW PERVERTED
;
;    ROUTINE TO REMOVE CURSOR
;
CREM	CALL	VDADD	; GET CURRENT SCREEN ADDRESS
	MOV	A,M
	ANI	7FH	; STRIP OFF THE CURSOR
	MOV	M,A
	RET
;
;     ROUTINE TO BACKSPACE
;
PBACK	CALL	PLEFT
	CALL	VDADD	; GET SCREEN ADDRESS
	MVI	M,' '	; PUT A BLANK THERE
	RET
;
;     ROUTINE TO PROCESS A CARRIAGE RETURN
;
PCR	CALL	CLINE	; CLEAR FROM CURRENT CURSOR TO END OF LINE
	XRA	A	; REWIND IT
	JMP	PCUR	; AND STORE THE NEW VALUE
;
;   ROUTINE TO PROCESS LINEFEED
;
PLF	LDA	LINE	; GET LINE COUNT
	CPI	15	; ARE WE AT THE BOTTOM?
	JNC	SC
	INR	A
	JMP	CUR	; ONE MORE LINE UP
;
SC	XRA	A
	JMP	SROL
;
;
;
;     THIS TABLE DEFINES THE CHARACTERS FOR SPECIAL
; PROCESSING.  IF THE CHARACTER IS NOT IN THE TABLE IT
; GOES TO THE SCREEN.
;
TBL	DB	CLEAR	; SCREEN
	DW	PERSE
	DB	UP	; CURSOR
	DW	PUP
	DB	DOWN
	DW	PDOWN
	DB	LEFT
	DW	PLEFT
	DB	RIGHT
	DW	PRIT
	DB	HOME
	DW	PHOME
	DB	CR	; CARRIAGE RETURN
	DW	PCR
	DB	LF	; LINE FEED
	DW	PLF
	DB	BACKS	; BACK SPACE
	DW	PBACK
	DB	MODE	; MODE KEY
	DW	COMND
	DB	0	; END OF TABLE
;
;   OUTPUT DEVICE TABLE
;
OTAB	DW	VDMO1	; VDM DRIVER
	DW	SEROT	; SERIAL OUTPUT
	DW	ERROT	; ERROR HANDLER (FOR CONSOL)
	DW	ERROT	; ERROR HANDLER
;
;   INPUT DEVICE TABLE
;
ITAB	DW	KREA1	; KEYBOARD INPUT
	DW	SREA1	; SERIAL INPUT
	DW	ERROT	; ERROR HANDLER (FOR CONSOL)
	DW	ERROT	; ERROR HANDLER
;
;
;            COMMAND TABLE
;
;  THIS TABLE DESCRIBES THE VALID COMMANDS FOR CONSOL
;
COMTAB	DW	'TE'
	DW	TERM
	DW	'DU'
	DW	DUMP
	DW	'EN'
	DW	ENTER
	DW	'EX'
	DW	EXEC
	DW	'TL'
	DW	TLOAD
	DW	'BA'	; SPECIAL COMMAND TO EXECUTE 0
	DW	0
	DB	0	; END OF TABLE MARK
;
;
;              CONSOL PORT ERROR HANDLER
;
ERROT	XRA	A
	STA	IPORT	; DEFAULT TO SCREEN
	STA	OPORT	; DEFAULT TO SCREEN
;
;
;
;
;            =--  COMMAND MODE  --=
;
;
;   THIS ROUTINE GETS AND PROCESSES COMMANDS
;
COMND	LXI	SP,SYSTP	; SET STACK POINTER
	CALL	PROMPT	; PUT PROMPT ON SCREEN
	CALL	GCLIN	; GET COMMAND LINE
	CALL	COPRC	; PROCESS THE LINE
	JMP	COMND	; OVER AND OVER
;
;
;
;   THIS ROUTINE READS A COMMAND LINE FROM THE SYSTEM
;  KEYBOARD AND PROCESSES IT TO THE SCREEN.
;
;  C/R   TERMINATES THE SEQUENCE ERASING ALL CHARS TO THE
;        RIGHT OF THE CURSOR
;  L/F   TERMINATES THE SEQUENCE
;  MODE  RESTARTS THE COMMAND LINE.
;
GCLIN	CALL	KREAD	; READ KEYBOARD
	CPI	20H
	MOV	B,A
	JC	PROCS	; PROCESS CONTROL CHARACTER
CONT	CALL	VDMOT
	JMP	GCLIN
;
;   PROCESS CONTROL KEYS
;
PROCS	CPI	CR
	JZ	CRPRC	; ERASE THE REMAINING LINE PRIOR TO RETURN
	CPI	LF
	RZ		; IF SO GO PROCESS
	JMP	GCLIN	; NO CONTROL CHARS TO SCREEN
;
;
CRPRC	CALL	CLINE	; CLEAR REMAINING LINE
	RET		; NOW PROCESS
;
;
;      FIND AND PROCESS    COMMAND
;
COPRC	CALL	CREM	; REMOVE THE CURSOR
	MVI	C,1	; SET FOR CHARACTER POSITION
	CALL	VDAD2	; GET SCREEN ADDRESS
	XCHG
	CALL	SCHR	; SCAN PAST BLANKS
	JZ	ERR1	; NO COMMAND?
	XCHG		; HL HAS FIRST CHR
	LXI	D,COMTAB	; POINT TO COMMAND TABLE
;
;   THIS ROUTINE SEARCHES THROUGH A TABLE, POINTED TO
;  BY 'DE', FOR A DOUBLE CHARACTER MATCH OF THE 'HL'
;  MEMORY CONTENT.  IF NO MATCH IS FOUND THE SCAN ENDS
;  BY PLACING A QUESTION MARK WITHIN THE SEARCH STRING.
;
FDCOM	LDAX	D
	ORA	A	; TEST FOR TABLE END
	JZ	ERR2	; NOT FOUND..COMMAND ERROR
	PUSH	H	; SAVE START OF SCAN ADDRESS
	CMP	M	; TEST FIRST CHR
	INX	D
	JNZ	NCOM
;
	INX	H
	LDAX	D
	CMP	M	; NOW SECOND CHARACTER
	JNZ	NCOM	; GOODNESS
;
	POP	B	; CLEAR THE STACK
	XCHG		; DE HAS SCAN ADDRESS
	INX	H	; HL HAS COMMAND ADDRESS
	JMP	DISPT	; DISPATCH TO IT
;
;
NCOM	INX	D	; GO TO NEXT ENTRY
	INX	D
	INX	D
	POP	H	; GET BACK ORIGINAL ADDRESS
	JMP	FDCOM	; CONTINUE SEARCH
;
;
;      OUTPUT A CRLF FOLLOWED BY A PROMPT
;  ( WITH CONSOL ALL OPERATIONS ARE ON THE SCREEN)
;
PROMPT	CALL	CRLF
	MVI	B,'>'	; THE PROMPT
	JMP	VDMOT	; PUT IT ON THE SCREEN
;
CRLF	MVI	B,LF	; LINE FEED
	CALL	VDMOT
	MVI	B,CR	; CARRIAGE RETURN
	JMP	VDMOT	; PUT IT OUT AND RETURN
;
;
;  SCAN OVER UP TO 12 CHARACTERS LOOKING FOR A BLANK
;
SBLK	MVI	C,12	; MAXIMUM COMMAND STRING
SBLK1	LDAX	D
	CPI	BLANK
	JZ	SCHR	; GOT A BLANK NOW SCAN PAST IT
	INX	D
	DCR	C	; NO MORE THAN TWELVE
	JNZ	SBLK1
	RET		; GO BACK WITH ZERO FLAG SET
;
;
;  SCAN PAST UP TO 10 BLANK POSITIONS LOOKING FOR
; A NON BLANK CHARACTER.
;
SCHR	MVI	C,10	; SCAN TO FIRST NON BLANK CHR WITHIN 10
SCHR1	LDAX	D	; GET NEXT CHARACTER
	CPI	SPACE
	RNZ		; WE'RE PAST THEM
	INX	D	; NEXT SCAN ADDRESS
	DCR	C
	RZ		; COMMAND ERROR
	JMP	SCHR1	; KEEP LOOPING
;
;  THIS ROUTINE SCANS OVER CHARACTERS, PAST BLANKS AND
; CONVERTS THE FOLLOWING ADDRESS TO HEX.  ERRORS RETURN TO
; THE ERROR HANDLER.
;
SCONV	CALL	SBLK
	JZ	ERR1
;
;  THIS ROUTINE CONVERTS ASCII DIGITS INTO BINARY FOLLOWING
; A STANDARD HEX CONVERSION.  THE SCAN STOPS WHEN AN ASCII
; SPACE IS ENCOUNTERED.  PARAMETER ERRORS REPLACE THE ERROR
; CHARACTER ON THE SCREEN WITH A QUESTION MARK.
;
SHEX	LXI	H,0	; CLEAR H & L
SHE1	LDAX	D	; GET CHARACTER
	CPI	20H	; IS IT A SPACE?
	RZ		; IF SO
;
HCONV	DAD	H	; MAKE ROOM FOR THE NEW ONE
	DAD	H
	DAD	H
	DAD	H
	CALL	HCOV1	; DO THE CONVERSION
	JNC	ERR1	; NOT VALID HEXIDECIMAL VALUE
	ADD	L
	MOV	L,A	; MOVE IT IN
	INX	D	; BUMP THE POINTER
	JMP	SHE1
;
HCOV1	SUI	48	; REMOVE ASCII BIAS
	CPI	10
	RC		; IF LESS THAN 9
	SUI	7	; IT'S A LETTER??
	CPI	10H
	RET		; WITH TEST IN HAND
;
;
;    SYSTEM START UP, CLEAR PART OF RAM AND SET STACK
; POINTER, FALLING THROUGH TO TERMINAL MODE.
;
STRTA	XRA	A
	MOV	C,A	; WE CLEAR THE FIRST 256 BYTES
	LXI	H,SYSRAM	; POINT TO SYSTEM RAM
;
CLERA	MOV	M,A
	INX	H
	INR	C
	JNZ	CLERA	; CLEAR FIRST 256 BYTES
;
;
;
;                 TERM COMMAND
;
;   THIS ROUTINE GETS CHARACTERS FROM THE SYSTEM KEYBOARD
;  AND OUTPUTS THEM TO THE SERIAL OUTPUT PORT.  IT IS
;  INTENDED TO CONFIGURE THE SoL AS A STANDARD VIDEO
;  TERMINAL.  COMMAND KEYS ARE NOT OUTPUT TO THE OUTPUT
;  PORT BUT ARE INTERPRETED AS DIRECT SoL COMMANDS.
;  THE MODE COMMAND, RECEIVED BY THE KEYBOARD, PUTS THE
;  SoL IN THE COMMAND MODE.
;
;
TERM	LXI	SP,SYSTP	; SET STACK POINTER
	CALL	TOFF	; SLOW DOWN THE TAPES
	CALL	PERSE	; CLEAR THE SCREEN
;
KIN	CALL	KSTAT	; IS THERE ONE WAITINGI
	JNZ	TIN
	IN	KDATA	; GET THE CHARACTER
	MOV	B,A
	ANI	80H	; COMMAND KEY?
	JZ	TOUT
	CALL	VDMOT	; PROCESS IT
	JMP	TIN
;
TOUT	CALL	SDROT	; OUTPUT IT TO THE SERIAL PORT
TIN	CALL	SSTAT	; GET SERIAL STATUS
	JZ	KIN	; LOOP IF NOT
	IN	SDATA	; GET DATA
	ANI	7FH	; NO HIGH BITS FROM HERE
	MOV	B,A	; IT'S OUTPUT FROM 'B'
	CALL	VDMOT	; PUT IT ON THE SCREEN
	JMP	KIN	; LOOP OVER AND OVER
;
;
;
;            DUMP COMMAND
;
;     THIS ROUTINE DUMPS CHARACTERS FROM MEMORY TO THE
;  CURRENT OUTPUT DEVICE.  (WITH CONSOL ALL OUTPUT GOES TO
;  THE SCREEN).  ALL VALUES ARE DESPLAYED AS ASCII HEX.
;
;  THE COMMAND FORM IS AS FOLLOWS:
;
;        DUmp addr1 addr2
;
;    THE VALUES FROM ADDR1 TO ADDR2 ARE THEN OUTPUT TO THE
;  OUTPUT DEVICE.  IF ONLY ADDR1 IS SPECIFIED THEN THE
;  VALUE AT THAT ADDRESS IS OUTPUT.
;
DUMP	CALL	SCONV	; SCAN TO FIRST ADDRESS AND CONVERT IT
	PUSH	H	; SAVE THE VALUE
	CALL	SCHR	; GET THE NEXT
	POP	H
	JZ	POVER	; NO SECOND VALUE
	PUSH	H
	CALL	SHEX	; GET SECOND
	POP	D	; THIS IS THE FIRST
	JMP	NPASS	; MIND BENDERS
;
POVER	MOV	D,H	; NO SECOND PARAMETER COPY FIRST TO DE
	MOV	E,L
NPASS	XCHG		; HL HAS START, DE HAS END
;
DLOOP	CALL	CRLF
	IN	KDATA
	CPI	MODE	;  MODE KEY' WILL ESCAPE THE DUMP
	JZ	COMND
	CALL	ADOUT	; OUTPUT ADDRESS
	CALL	BOUT	; ANOTHER SPACE TO KEEP IT PRETTY
	MVI	C,16	; VALUES PER LINE
;
DLP1	MOV	A,M	; GET THE CHR
	PUSH	B	; SAVE VALUE COUNT
	CALL	HBOUT	; SEND IT OUT WITH A BLANK
	CALL	ACOMP	; COMPARE ADDRESSES
	JNC	COMND	; ALL DONE
	POP	B	; VALUES PER LINE
	INX	H
	DCR	C	; BUMP THE LINE COUNT
	JNZ	DLP1	; NOT ZERO IF MORE FOR THIS LINE
	JMP	DLOOP	; DO A LFCR BEFORE THE NEXT
;
;    OUTPUT HL AS HEX 16 BIT VALUE
;
ADOUT	MOV	A,H	; H FIRST
	CALL	HEOUT
	MOV	A,L	; THEN L FOLLOWED BY A SPACE
;
HBOUT	CALL	HEOUT
BOUT	MVI	B,' '
	JMP	VDMOT	; CONSOL PUTS IT ON THE SCREEN
;
HEOUT	MOV	C,A	; GET THE CHARACTER
	RRC
	RRC		; MOVE THE HIGH FOUR DOWN
	RRC
	RRC
	CALL	HEOU1	; PUT THEM OUT
	MOV	A,C	; THIS TIME THE-LOW FOUR
;
HEOU1	ANI	0FH	; FOUR ON THE FLOOR
	ADI	48	; WE WORK WITH ASCII HERE
	CPI	58	; 0-9?
	JC	OUTH	; YUPI
	ADI	7	; MAKE IT A LETTER
OUTH	MOV	B,A	; OUTPUT IT FROM REGISTER 'B'
	JMP	VDMOT
;
;   COMPARE DE AND HL
;
ACOMP	MOV	A,L
	SUB	E
	MOV	A,H
	SBB	D
	RET		; FLAGS ARE SET
;
;
;           ENTER COMMAND
;
;   THIS ROUTINE GETS VALUES FROM THE KEYBOARD AND ENTERS
; THEM INTO MEMORY.  THE INPUT VALUES ARE SCANNED FOLLOWING
; A STANDARD 'GCLIN' INPUT SO ON SCREEN EDITING MAY TAKE
; PLACE PRIOR TO THE LINE TERMINATOR.  A BACK SLASH '/'
; ENDS THE ROUTINE AND-RETURNS CONTROL TO THE COMMAND MODE.
;
ENTER	CALL	SCONV	; SCAN OVER CHARS AND GET ADDRESS
	PUSH	H	; SAVE ADDRESS
;
ENLOP	CALL	CRLF
	MVI	B,':'
	CALL	CONT	; GET LINE OF INPUT
	CALL	CREM	; REMOVE THE CURSOR
	MVI	C,1	; START SCAN
	CALL	VDAD2	; GET ADDRESS
	XCHG		; ....TO DE
;
ENLO1	MVI	C,3	; NO MORE THAN THREE SPACES BETWEEN VALUES
	CALL	SCHR1	; SCAN TO NEXT VALUE
	JZ	ENLOP	; LAST ENTRY FOUND START NEW LINE
ENLO2	LDAX	D	; GET THE CHR
	CPI	'/'	; COMMAND TERMINATOR?
	JZ	COMND	; IF SO...
	CALL	SHEX	; CONVERT VALUE
	MOV	A,L	; GET LOW PART AS CONVERTED
	POP	H	; GET MEMORY ADDRESS
	MOV	M,A	; PUT IN THE VALUE
	INX	H
	PUSH	H	; BACK GOES THE ADDRESS
	JMP	ENLO1	; CONTINUE THE SCAN
;
;
;
;              EXECUTE COMMAND
;
;   THIS ROUTINE GETS THE FOLLOWING PARAMETER AND DOES A
; PROGRAM JUMP TO THE LOCATION GIVEN BY IT.  IF PROPER
; STACK OPERATIONS ARE USED WITHIN THE EXTERNAL PROGRAM
; IT CAN DO A STANDARD 'RET'URN TO THE CONSOL COMMAND MODE.
;
;
EXEC	CALL	SCONV	; SCAN PAST BLANKS AND GET PARAMETER
	PCHL		; GO ........ (AMD TAKE NOTE)
;
;
;
;           TAPE LOAD COMMAND
;
;   THIS ROUTINE READS FROM EITHER TAPE UNIT PLACING
; THE READ DATA INTO MEMORY.  WHILE SPACE WITHIN CONSOL
; DOES NOT ALLOW FOR 'STANDARD' TAPE ROUTINES THIS
; COMMAND WILL LOAD SoL- BASIC5 AND OTHER STANDARD SoL
; SYSTEM SOLFTWARE FOR DIRECT EXECUTION.
;
;
TLOAD	CALL	SBLK	; SCAN TO SPEED PARAMETER
	JZ	DFLT	; DEFAULT TO HIGH SPEED IF NONE
	CALL	SHEX	; CONVERT IT
	MOV	A,L	; GET VALUE
	ANI	1	; ONLY BIT ZERO COUNTS
	MVI	A,32	; PRETEND ITS SLOW
	JNZ	SETSP
;
DFLT	XRA	A	; MAKE IT FAST
SETSP	ORI	TAPE1+TAPE2	; CONSOL STARTS BOTH TAPES
	OUT	STAPT	; START TAPES AND SELECT SPEED
	CALL	DELAY	; WAIT WHILE THE TAPE UNIT WINDS UP
	IN	TDATA	; CLEAR THE UART FLAGS
;
TLOD1	CALL	RHEAD	; READ PAST HEADER
	JNZ	TLOD1	; IF ERROR START OVER
;
	LHLD	BLOCK	; GET BLOCK SIZE
	XCHG		; ...TO DE
	LHLD	LOADR	; GET LOAD ADDRESS
;
LOLOOP	MOV	A,D	; GET COUNT
	ORA	E
	JZ	TOFF	; COUNT IS ZERO-TURN OFF TAPE AND RETURN
	LXI	B,-256	; THIS MANY PRIOR TO CRC TEST
	XCHG		; COUNT TO HL
	DAD	B	; A LITTLE MATH
	JNC	LBLK	; NO CARRY, IT'S THE LAST BLOCK
	MVI	B,0	; 256 TO READ
;
RDBLK	MVI	C,0	; ZERO THE CRC
	XCHG		; ROUND ROBIN
RTBYT	CALL	TAPIN	; GET CHARACTER
	MOV	M,A	; STORE IT
	INX	H	; BUMP MEMORY LOCATION
	XRA	C	; UPDATE THE CRC
	CMA
	SUB	C
	MOV	C,A	; STORE THE NEW
	DCR	B	; COUNT DOWN
	JNZ	RTBYT	; STILL MORE IF NOT ZERO
;
	CALL	CRCCK	; CHECK CRC AND FALL THROUGH TO ERROR IF NO GOOD
	JZ	LOLOOP	; TEST OK
;
TERR	MVI	B,'G'-40H	; BELL CHARACTER
	CALL	VDMOT	; PUT IT ON THE SCREEN
	JMP	COMND
;
;
;    CONSOL ERROR HANDLER
;
ERR1	XCHG		; GET SCAN ADDRESS
ERR2	MVI	M,'?'	; PUT A QUESTION MARK THERE
	JMP	COMND	; AND GO TO COMMAND MODE
;
;   READ  THE HEADER
;
RHEAD	MVI	B,10	; FIND 10 NULLS
RHEA1	IN	STAPT	; GET A BYTE
	ANI	TDR
	JZ	RHEA1
	IN	TDATA	; IGNORE ERROR CONDITIONS
	ORA	A	; ZERO?
	JNZ	RHEAD
	DCR	B
	JNZ	RHEA1	; LOOP UNTIL 10 IN A ROW
;
;    WAIT FOR THE START CHARACTER
;
SOHL	CALL	TAPIN
	DCR	A
	JNZ	SOHL	; WAIT FOR A '1'
;
;    NOW  GET THE HEADER
;
	LXI	H,THEAD	; POINT TO BUFFER
	LXI	B,HLEN*256	; LENGTH OF HEADER IN 'B',C<O
;
RHED1	CALL	TAPIN	; GET BYTE
	MOV	M,A	; STORE IT
	INX	H	; INCREMENT ADDRESS
	XRA	C	; NOW CALCULATE THE CRC
	CMA		; INSIDE OUT AND UPSIDE DOWN
	SUB	C	; SQUEEZE IT
	MOV	C,A	; AND SAVE AGAIN
	DCR	B	; WHOLE HEADER YET?
	JNZ	RHED1	; LOOP UNTIL DONE
;
;   THIS  ROUTINE GETS THE NEXT BYTE AND COMPARES IT
; TO THE  VALUE IN REGISTER C. THE FLAGS ARE SET ON
; RETURN.
;
CRCCK	CALL	TAPIN	; GET CRC BYTE
	CMP	C	; COMPARE IT WITH CALCULATED
	RET
;
;
;    THIS ROUTINE GETS THE NEXT AVAILABLE BYTE FROM THE
;  TAPE.  WHILE WAITING FOR THE BYTE THE KEYBOARD IS TESTED
;  FOR A 'MODE' COMMAND.  IF RECEIVED THE TAPE LOAD IS
;  TERMINATED AND A RETURN TO THE COMMAND MODE IS MADE.
;
TAPIN	IN	STAPT	; CHECK STATUS
	ANI	TDR
	JNZ	TREDY	; ONE IS AVAILABLE
	IN	KDATA	; CHECK FOR MODE WHILE WE'RE WAITING
	CPI	MODE
	JZ	COMND	; MODE WAS GIVEN..ABORT OPERATION
	JMP	TAPIN	; NOT MODE...STAY IN LOOP
;
TREDY	IN	STAPT
	ANI	TFE+TOE	; DATA ERROR?
	JNZ	TERR	; IF FRAMING OR OVERRUN ERROR
	IN	TDATA	; GET THE DATA
	RET
;
; THIS ROUTINE CALCULATES THE LENGTH OF THE LAST BLOCK
;
LBLK	LXI	B,-1
	DAD	B	; COMPLEMENT HL
	INX	H	; .......TWO'S
	MOV	B,L	; LENGTH TO REGISTER 3
	LXI	H,0	; TELL DE WE'RE DONE
	JMP	RDBLK	; ONWARD TO THE END
;
;   THIS  ROUTINE TURNS THE TAPE UNITS OFF
;
TOFF	XRA	A
	OUT	STAPT	; GIVE COMMAND
	RET		; AND GRIND TO A SLOW STOP
;
;
DELAY	LXI	D,0	; START LOOP
DLOP1	DCX	D	; DOWN COUNT
	MOV	A,D
	ORA	E	; TEST FOR ZERO
	JNZ	DLOP1	; IF NOT
	RET
;
;
;
;
;                 <<  SoL SYSTEM EQUATES  >>
;
;
;          VDM PARAMETERS
;
VDMEM	EQU      0CC00H	; VDM SCREEN MEMORY
;
;
;          KEYBOARD SPECIAL KEY ASSIGNMENTS
;
DOWN	EQU	9AH
UP	EQU	97H
LEFT	EQU	81H
RIGHT	EQU	93H
LOADK	EQU	8CH	; LOAD KEY
MODE	EQU	80H
CLEAR	EQU	8BH
HOME	EQU	08EH
BACKS	EQU	5FH	; BACKSPACE
LF	EQU	10
CR	EQU	13
BLANK	EQU	' '
SPACE	EQU	BLANK
CX	EQU	'X'-40H
;
;          PORT ASSIGNMENTS
;
STAPT	EQU	0FAH	; STATUS PORT GENERAL
SERST	EQU	0F8H	; SERIAL STATUS PORT
SDATA	EQU	0F9H	; SERIAL DATA
TDATA	EQU	0FBH	; TAPE DATA
KDATA	EQU	0FCH	; KEYBOARD DATA
PDATA	EQU	0FDH	; PARALLEL DATA
DSTAT	EQU	0FEH	; VDM DISPLAY PARAMETER PORT
SENSE	EQU	0FFH	; SENSE SWITCHES
;
;
;
;          BIT ASSIGNMENT MASKS
;
SCD	EQU	1	; SERIAL CARRIER DETECT
SDSR	EQU	2	; SERIAL DATA SET READY
SPE	EQU	4	; SERIAL PARITY ERROR
SFE	EQU	8	; SERIAL FRAMING ERROR
SOE	EQU	16	; SERIAL OVERRUN ERROR
SCTS	EQU	32	; SERIAL CLEAR TO SEND
SDR	EQU	64	; SERIAL DATA READY
STBE	EQU	128	; SERIAL TRANSMITTER BUFFER EMPTY
;
KDR	EQU	1	; KEYBOARD DATA READY
PDR	EQU	2	; PARALLEL DATA READY
PXDR	EQU	4	; PARALLEL DEVICE READY
TFE	EQU	8	; TAPE FRAMING ERROR
TOE	EQU	16	; TAPE OVERFLOW ERROR
TDR	EQU	64	; TAPE DATA READY
TTBE	EQU	128	; TAPE TRANSMITTER BUFFER EMPTY
;
SOK	EQU	1	; SCROLL OK FLAG
;
TAPE1	EQU	64	; TAPE ONE 'ON' BIT
TAPE2	EQU	128	; TAPE TWO
;
;
;
;
;               SoL SYSTEM GLOBAL AREA
;
	ORG	0C800H	; START OF 1K RAM AREA
;
SYSRAM	EQU	$	; START OF SYSTEM RAM
SYSTP	EQU	$+1024	; STACK IS AT THE TOP
;
;
;           CONSOL PARAMETER AREA
;
NCHAR	DS	1	; CURRENT CHARACTER POSITION
LINE	DS	1	; CURRENT LINE POSITION
BOT	DS	1	; BEGINNING OF TEXT DISPLACEMENT
OPORT	DS	1	; OUTPUT PORT
IPORT	DS	1	; INPUT PORT
;
;
;
THEAD	DS	5	; NAME
	DS	1	; THIS BYTE MUST BE ZERO
HTYPE	DS	1	; TYPE
BLOCK	DS	2	; BLOCK SIZE
LOADR	DS	2	; LOAD ADDRESS
XEQAD	DS	2	; AUTO EXECUTE ADDRESS
HSPR	DS	3	; SPARES
;
HLEN	EQU	$-THEAD	; LENGTH OF HEADER
;
;
	END
