;   
;    THIS ROUTINE IS THE PARALLEL DEVICE HANGLER
; NO PROVISION IS MADE FOR CONTROLLING THE PORT
; CONTROL BIT.
;
;
;  PARALLEL INPUT DRIVER
;
PASTAT:  IN  STAPT
  CMA    ;INVERT STATUS FLAGS
  ANI  PDR  ;TEST BIT
  RZ
  IN  PDATA  ;GET DATA
  RET
;
;  PARALLEL OUTPUT HANDLER
;
PROUT:  IN  STAPT  ;GET STATUS
  ANI  PXDR  ;TEST IF DEVICE IS READY
  JNZ  PROUT  ;LOOP UNTIL SO
  MOV  A,B
  OUT  PDATA
  RET
;
;
;  OUTPUT A CR/LF FOLLOWED BY A PROMPT
;
PROMPT:  CALL  CRLF
  MVI  B,'>'  ;THE PROMPT
  JMP  SOUT  ;PUT IT ON THE SCREEN
;
;
CRLF:  MVI  B,LF  ;LINE FEED
  CALL  SOUT
  MVI  B,CR  ;CARRIAGE RETURN
  CALL  SOUT
  IF  EXT
  RET
  ENDF
  IF  STD
;  NOW OUTPUT THE NULLS
  LDA  NUCNT  ;GET DESIRED COUNT
  MOV  C,A  ;STORE IN C
NULOT:  DCR  C
  RM    ;RETURN WHEN PAST ZERO
  XRA  A  ;GET A NULL
  CALL  OUTH
  JMP  NULOT
  ENDF
;
;
;    SCAN OFF OPTIONAL PARAMETER.  IF PRESENT RETURN WITH
; VALUE IN HL AND COPY OF 'L' IN 'A'.  IF NOT PRESENT
; RETURN WITH A "1" IN 'A' AND HL UNTOUCHED.
;
PSCAN:  CALL  SBLK
  MVI  A,1  ;DEFAULT VALUE
  RZ    ;IF NONE
  CALL  SHEX  ;CONVERT VALUE
  MOV  A,L  ;GET LOWER HALF
  RET
;
;
;   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
  CPI  '='  ;ALSO ALLOW EQUAL TO STOP US
  JZ  SCHR  ;IF SO, PTR AT CHAR FOLLOWING
  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 NONBLANK CHR IN 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 VALUE TO HEX.  ERRORS RETURN TO
; THE ERROR HANDLER.
;
SCONV:  CALL  SBLK  ;FIND IF VALUE IS PRESENT
  JZ  ERR1  ;ABORT TO ERROR IF NONE
;
;
;  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
  IF  EXT
  CPI  61H  ;LOWER CASE?
  JC  SHE2  ;NO
  ANI  5FH  ;MAKE IT U.C.
SHE2:  EQU  $
  ENDF
  CPI  20H  ;IS IT A SPACE
  RZ    ;IF SO
  CPI  '/'  ;SLASH IS ALSO LEGAL
  RZ
  CPI  ':'  ;EVEN THE COLON IS ALLOWED
  RZ
;
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
;   
  IF STD
;
;  ***** TERMINAL COMMAND *****
;
;  THIS ROUTINE GETS CHARACTERS FROM THE SYSTEM KEYBOARD
; AND OUTPUTS THEM TO THE SELECTED 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:  CALL  PSCAN  ;FIND IF INPUT PARAMETER IS PRESENT
  STA  IPORT  ;SINP WILL USE THIS DRIVER (DEFAULT IS 1)
  CALL  PSCAN  ;NOW FOR THE OUTPUT DRIVER
  STA  OPORT
;
TERM1:  CALL  KSTAT  ;IS THERE ONE WAITING?
  JZ  TIN  ;IF NOT
  MOV  B,A  ;SAVE IT IN B
  CPI  MODE  ;IS IT MODE?
  JZ  COMN1  ;YES...RESET AND QUIT TERM
  JC  TOUT  ;NON-CURSOR KEY...SEND TO TERM PORT
  CALL  VDMOT  ;PROCESS IT
  JMP  TIN
;
TOUT:  CALL  SOUT  ;OUTPUT IT TO THE SERIAL PORT
TIN:  CALL  SINP  ;GET INPUT STATUS
  JZ  TERM1  ;LOOP IF NOT
  ANI  7FH  ;NO HIGH BITS FROM HERE
  JZ  TERM1  ;A NULL IS IGNORED
  MOV  B,A  ;IT'S OUTPUT FROM 'B'
  CPI  1BH  ;IS IT A CONTROL CHAR TO BE IGNORED
  JNC  TERM2  ;NO...TO VDM AS IS THEN
  CPI  CR  ;CR OR LF ARE SPECIAL CASES THOUGH
  JZ  TERM2  ;AND MUST BE PASSED STD MODE TO VDM
  CPI  LF
  JZ  TERM2
  LDA  ESCFL  ;A CTRL CHAR...ARE WE W/IN ESC SEQUENCE?
  ORA  A  ;IF YES, THEN OUTPUT CTRL CHAR DIRECTLY TO VDM
  JNZ  TERM2  ;WE SURE ARE, LET VDM DRIVER HANDLE IT
  PUSH  B  ;SAVE THE CHARACTER
  MVI  B,ESC  ;CTRL CHAR TO VDM VIA ESC SEQUENCE
  CALL  VDMOT
  MVI  B,7  ;SAY TO PUT OUT NEXT CHAR AS IS
  CALL   VDMOT  ;ALMOST READY
  POP  B  ;RESTORE CHAR
TERM2:  EQU  $  ;ALL READY TO OUTPUT THE CHAR
  CALL  VDMOT  ;PUT IT ON THE SCREEN
  JMP  TERM1  ;LOOP OVER AND OVER
;   
  ENDF
;
;
;  ***** DUMP COMMAND *****
;
;   THIS ROUTINE DUMPS CHARACTERS FROM MEMORY TO THE
; CURRENT OUTPUT DEVICE.  ALL VALUES ARE DISPLATED AS
; ASCII HEX.
;
;   THE COMMAND FORM IS A FOLLOWS:
;
;  DU   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  PSCAN  ;SEE IF SECOND WAS GIVIN
  POP  D
  XCHG    ;HL HAS START, DE HAS END
;
DLOOP:  CALL  CRLF
  CALL  ADOUT  ;OUTPUT ADDRESS
  CALL  BOUT  ;ANOTHER SPACE TO KEEP IT PRETTY
  MVI  C,16  ;VALUES PER LINE
;
DLP1:  MOV  A,M  ;GET THE CHAR
  PUSH  B  ;SAVE VALUE COUNT
  CALL  HBOUT  ;SEND IT OUT WITH A BLANK
  MOV  A,L  ;COMPARE DE AND HL
  SUB  E
  MOV  A,H
  SBB  D
  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
  CALL  SINP  ;SEE IF A CHAR WAITING
  JZ  BOUT  ;NO
  IF  STD
  ANI  7FH  ;CLR PARITY FIRST THO
  JZ  COMND  ;EITHER MODE OR CTRL-@
  CPI  ' '  ;IS IT A SPACE
  JNZ  BOUT  ;NO...IGNORE THE CHAR
WTLP1:  CALL  SINP  ;IF SPACE, WAIT UNTIL ANY OTHER KEY HIT
  JZ  WTLP1  ;THIS ALLOWS LOOKING AT THE DISPLAY
  ENDF
BOUT:  MVI  B,' '
  JMP  SOUT  ;PUT IT OUT
;
HEOUT:  MOV  C,A  ;GET THE CHARACTER
  RRC    ;MOVE THE HIGH FOUR DOWN
  RRC
  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  ;YUP
  ADI  7  ;MAKE IT A LETTER
OUTH:  MOV  B,A  ;OUTPUT IT FROM REGISTER 'B'
  JMP  SOUT
;
;
;  ***** 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.
; A COLON ':' SETS THE PREVIOUS VALUE AS A NEW ADDRESS FOR
; ENTRY.
;
ENTER:  CALL  SCONV  ;SCAN OVER CHARS AND GET ADDRESS
  PUSH  H  ;SAVE ADDRESS
  XRA  A
  STA  OPORT  ;ENTER VALUES TO SCREEN BUFFER
;
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
;
  CPI  '/'  ;COMMAND TERMINATOR
  JZ  COMN1  ;IF SO, RETURN TO STANDARD INPUT
  CALL  SHEX  ;CONVERT VALUE
  CPI  ':'  ;ADDRESS TERMINATOR
  JZ  ENLO3  ;GO PROCESS IF SO
  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
;
ENLO3:  XTHL    ;PUT NEW ADDRESS ON STACK
  INX  D  ;MOVE SCAN PAST TERMINATOR  
  JMP  ENLO1
;
;
;  ***** 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 SOLOS COMMAND MODE.
; THE STARTING ADDRESS OF SOLOS IS PASSED TO THE PROGRAM
; IN REGISTER PAIR HL SO IT CAN ADJUST INTERNAL PARAMETERS
; FOR SOLOS OPERATION.
;
;
EXEC:  CALL  SCONV  ;SCAN PAST BLANKS AND GET PARAMETER
EXEC1:  PUSH  H  ;PUT GO ADDRESS ON STACK
  LXI  H,START  ;TELL THE PROGRAM WHERE WE CAME FROM
  RET    ;AND DISPATCH IT
;
;
;    THIS ROUTINE GETS A NAME OF UP TO 5 CHARACTERS
; FROM THE INPUT STRING.  IF THE TERMINATOR IS A 
; SLASH (/) THEN THE CHARACTER FOLLOWING IS TAKEN
; AS THE CASSETTE UNIT SPECIFICATION.
;
;
NAMES:  LXI  H,THEAD  ;POINT TO INTERNAL HEADER
NAME:  CALL  SBLK  ;SCAN OVER TO FIRST CHRS
  MVI  B,6  ;UP TO SIX ARE ACCEPTED
;
NAME1:  LDAX  D  ;GET CHARACTER
  CPI  ' '  ;NO UNIT DELIMITER
  JZ  NFIL
  CPI  '/'  ;UNIT DELIMITER
  JZ  NFIL
  MOV  M,A
  INX  D  ;BUMP THE SCAN POINTER
  INX  H
  DCR  B
  JNZ  NAME1  ;FALL THROUGH TO ERR1 IF TOO MANY CHRS IN NAME
;
;   
;  ***** SOLOS ERROR HANDLER *****
;   
ERR1:  XCHG    ;GET SCAN ADDRESS TO HL
  IF  STD
ERR2:  MVI  M,'?'  ;PUT QUESTION MARK ON SCREEN
  JMP  COMN1  ;AND RETURN TO COMMAND MODE
  ENDF
  IF  EXT
ERR2:  CALL  CRLF  ;PUT ^ BELOW BAD CHARACTER
  LXI  D,40H
  DAD  D  ;MOVE DOWN ONE LINE
  MOV  A,H
  CPI  0D0H  ;WRAP?
  JNZ  ERR3  ;NO
  MVI  H,0CCH
ERR3:  MVI  M,'^'
  JMP  COMN1
  ENDF
;
;
;    HERE WE HAVE SCANNED OFF THE NAME.  ZERO FILL FOR
; NAMES LESS THAN FIVE CHARACTERS.
;
NFIL:  MVI  M,0  ;PUT IN AT LEAST ONE ZERO
  INX  H
  DCR  B
  JNZ  NFIL  ;LOOP UNTIL B IS ZERO
;
  CPI  '/'  ;IS THERE A UNIT SPECIFICATION?
  MVI  A,1  ;PRETEND NOT
  JNZ  DEFLT
  INX  D  ;MOVE PAST THE TERMINATOR
  CALL  SCHR  ;GO GET UNIT SPEC
  SUI  '0'  ;REMOVE ASCII BIAS
;
DEFLT:  EQU  $  ;MOVE OVER TO INTERNAL REPRESENTATION
  ANI  1  ;JUST BIT ZERO
  MVI  A,TAPE1  ;ASSUME TAPE ONE
  JNZ  STUNT  ;IF NON-ZERO, ITS ONE
  RAR
STUNT:  STA  FNUMF  ;SET IT IN
  RET
;
;
;
;   THIS ROUTINE PROCESSES THE XEQ AND GET COMMANDS
;
;
TXEQ:  DB  3EH  ;THIS BEGINS "MVI A,0AFH"
TLOAD:  XRA  A  ;A=0 MEANS TLOAD, ELSE TXEQ
  PUSH  PSW  ;SAVE FLAG FOR LATER
  LXI  H,DHEAD  ;PLACE DUMMY HEADER HERE
  CALL  NAME  ;SET IN NAME AND UNIT
  LXI  H,0  ;PRETEND NO SECOND VALUE
  CALL  PSCAN  ;GO GET THE ADDRESS (IF PRESENT)
;
TLOA2:  XCHG    ;PUT ADDRESS IN DE
  LXI  H,DHEAD  ;POINT TO DUMMY HEADER WITH NAME TO LOAD
  MOV  A,M  ;SEE IF A NAME WAS ENTERED
  ORA  A  ;IS THERE A NAME?
  JNZ  TLOA3  ;YES...SEARCH FOR IT
  LXI  H,THEAD  ;NO NAME, LOAD 1ST FILE
TLOA3:  PUSH  H  ;SAVE PTR TO NAME TO LOAD
  CALL  ALOAD  ;GET UNIT AND SPEED
  POP  H  ;RESTORE PTR TO HDR TO LOAD
  CALL  RTAPE  ;READ IN THE TAPE
  JC  TAERR  ;TAPE ERROR?
;
  CALL  NAOUT  ;PUT OUT THE HEADER PARAMETERS
  POP  PSW  ;RESTORE FLAG FROM ORIGINAL ENTRY
  ORA  A
  RZ    ;AUTO XEQ NOT WANTED
  LDA  HTYPE  ;CHECK TYPE
  ORA  A  ;SET FLAGS
  JM  TAERR  ;TYPE IS NOW XEQ
  LDA  THEAD+5  ;GET CHARACTER PAST NAME
  ORA  A
  JNZ  TAERR  ;THE BYTE MUST BE ZERO FOR AUTO XEQ
  LHLD  XEQAD  ;GET THE TAPE ADDRESS
  JMP  EXEC1  ;AND GO TO IT
;
;
;  ***** GET COMMAND *****
;
; THIS ROUTINE IS USED TO SAVE PROGRAMS AND DATA ON
; THE CASSETTE UNIT
;
;
TSAVE:  CALL  NAMES  ;GET NAME AND UNIT
  CALL  SCONV  ;GET START ADDRESS
  PUSH  H  ;USE THE STACK AS A REGISTER
  CALL  SCONV  ;GET END ADDRESS
  XTHL    ;PUT END ON STACK, GET BACK START
  PUSH  H  ;SAVE START ON TOP OF STACK
  CALL  PSCAN  ;SEE IF OPTIONAL HEADER ADDRESS WAS GIVEN
  SHLD  LOADR  ;PUT HEADER ADDRESS IN PLACE
;
  POP  H  ;"FROM" ADDRESS TO HL
  POP  D  ;GET BACK END ADDRESS
  PUSH  H  ;SAVE FROM AGAIN FOR LATER
  MOV  A,E  ;NOW CALCULATE SIZE
  SUB  L  ;SIZE=END-START+1
  MOV  L,A
  MOV  A,D
  SBB  H
  MOV  H,A
  INX  H
  SHLD  BLOCK  ;STORE THE SIZE
  PUSH  H  ;SAVE IT FOR THE READ ALSO
;
  CALL  ALOAD  ;GET UNIT AND SPEED
  LXI  H,THEAD  ;POINT TO HEADER
  CALL  WHEAD  ;AND WRITE IT OUT
;  NOW WRITE OUT THE DATA
  POP  D  ;GET SIZE TO DE
  POP  H  ;GET BACK "FROM" ADDRESS
  JMP  WRLO1  ;WRITE OUT THE DATA AND RETURN
;
;
;   OUTPUT ERROR AND HEADER
;
TAERR:  CALL  CRLF
  MVI  D,6
  LXI  H,ERRM  ;POINT TO ERROR MESSAGE
  CALL  NLOOP  ;OUTPUT ERROR
  CALL  NAOUT  ;THEN THE HEADER
  JMP  COMN1  ;AND BE SURE THE TAPE UNITS ARE OFF
;
ERRM:  ASC  'ERROR '
;
;
;   THIS ROUTINE READS HEADERS FROM THE TAPE AND OUTPUTS
; THEM TO THE OUTPUT DEVICE.  IT CONTINUES UNTIL THE
; MODE KEY IS DEPRESSED.
;
TLIST:  CALL  NAMES  ;SET UP UNIT IF GIVEN
  CALL  CRLF
;
;
LLIST:  CALL  ALOAD
  MVI  B,1
  CALL  TON  ;TURN ON THE TAPE
;
LIST1:  CALL  RHEAD
  JC  COMN1  ;TURN OFF THE TAPE UNIT
  JNZ  LIST1
  CALL  NAOUT  ;OUTPUT THE HEADER
  JMP  LIST1  ;LOOP UNTIL MODE IS DEPRESSED
;
;
; THIS ROUTINE GETS THE CASSETTE UNIT NUMBER AND
; SPEED TO REGISTER "A" FOR THE TAPE CALLS
;
ALOAD:  LXI  H,FNUMF  ;POINT TO THE UNIT SPECIFICATION
  LDA  TSPD  ;GET THE TAPE SPEED
  ORA  M  ;PUT THEM TOGETHER
  RET    ;AND GO BACK
;
;
; THIS ROUTINE OUTPUTS THE NAME AND PARAMETERS OF
; THEAD TO THE OUTPUT DEVICE.
;
;
NAOUT:  MVI  D,8
  LXI  H,THEAD-1  ;POINT TO THE HEADER
  CALL  NLOOP  ;OUTPUT THE HEADER
  CALL  BOUT  ;ANOTHER BLANK
  LHLD  LOADR  ;NOW THE LOAD ADDRESS
  CALL  ADOUT  ;PUT IT OUT
  IF  STD
  LHLD  BLOCK  ;AND THE BLOCK SIZE
  ENDF
  IF  EXT
  XCHG
  LHLD  BLOCK  ;GET BLOCK SIZE
  DAD  D
  DCX  H  ;MAKE IT LAST ADDRESS
  ENDF
  CALL  ADOUT
  JMP  CRLF  ;DO THE CRLF AND RETURN
;
;
NLOOP:  MOV  A,M  ;GET CHARACTER
  ORA  A
  JNZ  CHRLI  ;IF IT ISN'T A ZERO
  MVI  A,' '
CHRLI:  CALL  OUTH  ;OUTPUT CHAR NOW
  INX  H
  DCR  D
  JNZ  NLOOP
  RET
;
;
;
;
;  ***** SET COMMAND *****
;
; THIS ROUTINE GETS THE ASSOCIATED PARAMETER AND
; DISPATCHES TO THE PROPER ROUTINE FOR SETTING
; GLOBAL VALUES.
;   
CSET:  EQU  $  ;THIS IS THE SET COMMAND
  CALL  SBLK  ;LOOK FOR SET NAME
  JZ  ERR1  ;MUST HAVE A LEAST SOMETHING!!
  PUSH  D  ;SAVE SCAN ADDRESS
  CALL  SCONV  ;CONVERT FOLLOWING VALUE
  XTHL    ;GET SCAN ADDR BACK...SAVE VALUE ON STACK
  LXI  D,SETAB  ;SECONDARY COMMAND TABLE
  CALL  FDCOM  ;SEE IF IN TABLE
  JMP  DISPO  ;AND EITHER ERR OR OFF TO IT
;
;
; THIS ROUTINE SETS THE TAPE SPEED
;
TASPD:  ORA  A  ;IS IT ZERO?
  JZ  SETSP  ;YES...THAT'S A VALID SPEED
  MVI  A,32  ;SET TO SLOW IF NON-ZERO
SETSP:  STA  TSPD  ;SPEED IS STORED HERE
  RET
;
;
STSPD:  MOV  A,B  ;ESCAPE COMES HERE TO SET SPEED
DISPD:  STA  SPEED  ;SET DISPLAY SPEED
  RET
;
; SET INPUT DRIVER
;
SETIN:  EQU  $
  STA  IPORT
  RET
;
; SET OUTPUT DRIVER
;   
SETOT:  EQU  $
  STA  OPORT
  RET
;
; SET USERS CUSTOM INPUT DRIVER ADDRESS
;
SETCI:  SHLD  UIPRT
  RET
;
; SET USERS CUSTOM OUTPUT DRIVER ADDRESS
;
SETCO:  SHLD  UOPRT
  RET
;
; SET TYPE BYTE INTO HEADER
;   
SETTY:  STA  HTYPE
  RET
;
; SET EXECUTE ADDRESS INTO HEADER
;
SETXQ:  SHLD  XEQAD
  RET
;   
;   
  IF  STD
SETNU:  STA  NUCNT  ;SET THE NULL COUNT
  RET    ;THAT'S DONE
  ENDF
;
;
SETCR:  EQU  $  ;SET TO IGNORE CRC ERRORS
  STA  IGNCR  ;FF=IGNORE ERRORS, ELSE=NORMAL
  RET
;
;
;
;  CUSTOM COMMAND NAME AND ADDRESS INTO CUSTOM COMMAND
;
CUSET:  CALL  NAMES  ;CUSTOM COMMAND ENTRY/REMOVAL
  LXI  H,COMND  ;DEFAULT ADDR IF NONE GIVEN
  CALL  PSCAN  ;GET RTN ADDRESS
  PUSH  H  ;SAVE RTN ADDRESS
  LXI  H,THEAD  ;POINT AT NAME TO SEARCH
  CALL  FDCOU  ;SEARCH IT IN CUSTOM TABLE
  JZ  CUSE2  ;NOT IN TABLE...ENTER IT
  DCX  D  ;IN TABLE, REMOVE IT
  MVI  M,0  ;CHANGE NEW NAME TO BE ZERO
CUSE2  EQU  $
  MOV  A,M  ;GET 1ST CHAR OF NAME
  IF  EXT
  CPI  61H  ;LOWER CASE?
  JC  CUSE3  ;NO
  ANI  5FH  ;MAKE IT UPPER CASE
CUSE3  EQU  $
  ENDF
  STAX  D  ;ENTER IT INTO TABLE
  INX  D  ;AND THE 2ND NAME
  INX  H
  MOV  A,M
  IF  EXT
  CPI  61H
  JC  CUSE4
  ANI  5FH
CUSE4  EQU  $
  ENDF
  STAX  D  ;NAME NOW ENTERED
  INX  D  ;GET SET TO ENTER ADDRESS
  POP  H  ;RESTORE RTN ADDR
  XCHG
  MOV  M,E  ;SET ADDR IN NOW
  INX  H  ;AND HI BYTE OF ADDR
  MOV  M,D
  RET    ;NAME IS NOW ENTERED OR CLEARED
;   

