; ******** SOLOS OPERATING SYSTEM ********
;
; PROCESSOR TECHNOLOGY CORP.
; EMERYVILLE, CALIFORNIA
;
;
;     VERSION   1.3
;     RELEASE   3/27/77
;
;
;
;
;
;     THIS 2048 BYTE PROGRAM IS THE STANDARD SOL STAND
; ALONE OPERATING SYSTEM.  IT IS CONFIGURED TO OPTIMIZE
; THE CONVENIENCE AND POWER OF THE SOL-20 AND ONE OR TWO
; CASSETTE RECORDERS IN STAND ALONE COMPUTER APPLICATIONS.
;
;
;COMMANDS:
;  TE      TERMINAL MODE
;  DU SSSS EEEE    DUMP (START ADDR   END ADDR)
;  EN SSSS      ENTER HEX TO MEMORY
;  EX SSSS      EXECUTE
;  GE FILENAME/U    GET (U=TAPE UNIT 0 OR 1, DFLT=1)
;  SA FNAME/U SSSS EEEE  SAVE ON TAPE (UNIT 0 OR 1)
;  XE FILENAME/U    AUTO LOAD/EXECUTE
;  CA      CATALOG OF TAPE FILES
;  CU LL SSSS    CUSTOM COMMAND (LL=LABLE)
;  SET TA N    SET TAPE SPEED (N:0=FAST,1=SLOW)
;  SET S=NN    SET DISPLAY SPEED (O-->FF)
;  SET I=N      SET IN PSEUDO PORT (N=0 - 3)
;  SET O=N      SET OUT PSEUDO PORT (N=0 - 3)
;  SET N=NN    SET NULLS (N=0 - FF)
;  SET CI SSSS    SET CUSTOM INPUT DRIVER ADDR
;  SET CO SSSS    SET CUSTOM OUTPUT DRIVER ADDR
;  SET XE SSSS    SET AUTO-EXECUTE ADDRESS FOR TAPE SAVE
;  SET TY NN    SET FILE TYPE FOR TAPE HEADER
;  SET CR NN    OVERRIDE CRC ERRORS (FF=IGNORE ERRORS)
;
;
;  PSEUDO PORTS:  0 = KEYBOARD/VIDEO
;      1 = SERIAL PORT
;      2 = PARALLEL PORT
;      3 = USER DEFINED (SET CI, SET CO)
;
;
;
; ORG  0C000H
;
;
;
; AUTO-STARTUP CODE
;
START:  DB  0
INIT:  JMP  STRTA  ;SYSTEM RESTART ENTRY POINT
;
;
;     ENTRY POINTS
;
;     THESE JUMP POINTS ARE PROVIDED TO ALLOW COMMON ENTRY
; LOCATIONS FOR ALL VERSIONS OF SOLOS.  THEY ARE USED
; EXTENSIVLY BY SOL SYSTEM PROGRAMS AND IT IS RECOMMENDED
; THAT USER ROUTINES ACCESS SOLOS THROUGH THESE POINTS.
;   
RETRN:  JMP  COMND  ;RETURN TO SYSTEM ENTRY POINT
  IF  STD
FOPEN:  JMP  BOPEN  ;FILE OPEN ENTRY
FCLOS:  JMP  PCLOS  ;FILE CLOSE ENTRY
RDBYT:  JMP  RTBYT  ;CASSETTE READ BYTE ENTRY
WRBYT:  JMP  WTBYT  ;CASSETTE WRITE BYTE ENTRY
  ENDF
  IF  EXT
FOPEN:  CALL CASEXT
FCLOS:  CALL CASEXT
RDBYT:  CALL CASEXT
WRBYT:  CALL CASEXT
  ENDF
RDBLK:  JMP  RTAPE  ;CASSETTE READ BLOCK ENTRY
WRBLK:  JMP  WTAPE  ;CASSETTE WRITE BLOCK ENTRY
;   
;
;   SYSTEM I/O ENTRY POINTS
;
;   THESE ROUTINES PERFORM SYSTEM I/O
; THERE ARE TWO ENTRY TYPES:
;       SINP/SOUT    REG "A" WILL BE SET TO THE STANDARD
;                    SYSTEM PSEUDO PORT.
;       AINP/AOUT    REG "A" MUST BE SET BY THE USER AND
;                    WILL SPECIFY THE DESIRED PSEUDO PORT.
;
; THE FOLLOWING ARE THE PSEUDO PORTS:
;  PORT  DESCRIPTION
;  ----  --------------------------------
;   0  KEYBOARD WHEN INPUT, AND VDM WHEN OUTPUT
;   1  SERIAL I/O PORT
;   2  PARALLEL I/O PORT
;   3  USER DEFINED I/O PORT
;   
SOUT:  LDA  OPORT  ;SOUT ENTRY POINT
AOUT:  JMP  OUTPR  ;AOUT ENTRY POINT
SINP:  LDA  IPORT  ;SINP ENTRY POINT
  IF  STD
AINP:  EQU  $  ;AINP ENTRY POINT
  ENDF
  IF  EXT
AINP:  JMP  AINP1
  ENDF
;  ADDITIONAL ENTRY POINTS
  IF  EXT
  JMP  CRLF
  JMP  HEOUT
  JMP  HBOUT
  JMP  BOUT
  JMP  ADOUT
AINP1:  EQU  $
  ENDF
;   
;******** END OF SYSTEM ENTRY POINTS *********
  PUSH  H  ;THIS IS ACTUALLY AINP
  LXI  H,ITAB
;
;
;   THIS ROUTINE PROCESSES THE I/O REQUESTS BY DISPATCHING
; TO THE DRIVER REQUESTED IN REGISTER "A".  ON ENTRY HL
; HAS THE PROPER DISPATCH TABLE.
;
IOPRC:  ANI  3  ;KEEP REGISTER "A" TO FOUR VALUES
  RLC    ;COMPUTE ENTRY ADDRESS
  ADD  L
  MOV  L,A  ;WE HAVE ADDRESS
  JMP  DISPT  ;DISPATCH TO IT
;
;
;  ***** SOL SYSTEM I/O ROUTINES *****
;   
;
;   THIS ROUTINE IS A MODEL OF ALL INPUT ROUTINES WITHIN
; SOLOS.  EACH ROUTINE FIRST TESTS THE STATUS INPUT FOR
; DATA AVAILABLE.  IF NO CHARACTERHAS BEEN RECEIVED THE
; ROUTINE RETURNS WITH THE ZERO FLAG SEG.  OTHERWISE THE
; CHARACTER IS INPUT AND A RETURN MADE WITH THE CHARACTER
; IN THE ACCUMULATOR AND THE ZERO FLAG RESET.
;
;
;   KEYBOARD INPUT DRIVER
;
KSTAT:  IN  STAPT  ;GET STATUS WORK
  CMA    ;INVERT IT FOR PROPER RETURN
  ANI  KDR  ;TEST KEYBOARD BIT
  RZ    ;ZERO IS NO CHARACTER RECEIVED
;   
  IN  KDATA  ;GET CHARACTER
  RET    ;GO BACK WITH IT
;
;
;   THIS JUMP IS PART OF THE AUTO START UP CODE
;
  DB  0  ;VERIFY ADDR=C037 
  JMP  INIT  ;THIS SHOULD BE C038
;
;
;  JMP TABLE OUTPUT ROUTINES
;
;   THIS ROUTINE SETS UP THE DISPATCH TABLE FOR OUTPUT
; ROUTINES.  THE CHARACTER FOR OUTPUT IS IN REGISTER "B".
; OUTPUT IS MADE TO THE DRIVER POINTED TO BY THE REGISTER
; "A".  THE DEVICE DRIVERS ARE DEFINED AS FOLLOWS:
;
;  0 - DISPLAY SCREEN
;  1 - SERIAL OUTPUT PORT
;  2 - PARALLEL OUTPUT PORT
;  3 - USER DEFINED OR ERROR FLAG
;
; ENTRY AT:  SOUT SELECTS CURRENT OUTPUT DEVICE
;    AOUT SELECTS DEVICE IN REGISTER "A"
;
OUTPR:  PUSH  H
  LXI  H,OTAB  ;POINT TO OUTPUT TABLE
  JMP  IOPRC  ;AND DISPATCH TO OUTPUT ROUTINE
;
;
;
;  SERIAL INPUT DRIVER
;
SSTAT:  IN  SERST  ;GET SERIAL STATUS WORD
  ANI  SDR  ;TEST FOR SERIAL DATA READY
  RZ    ;FLAGS ARE SET
;
  IN  SDATA  ;GET DATA BYTE
  RET    ;WE HAVE IT
;
;
;  SERIAL DATA OUTPUT
;
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 ROUTINES
;
;
;   THESE ROUTINES ALLOW FOR STANDARD VIDEO TERMINAL
; OPERATIONS.  ON ENTRY, THE CHARACTER FOR OUTPUT IS IN
; REGISTER B AND ALL REGISTERS EXCEPT "A" AND FLAGS ARE
; UNALTERED ON RETURN.
;
;
VDMOT:  PUSH  H  ;SAVA MOST REGISTERS
  PUSH  D
  PUSH  B
;
; TEST IS ESC SEPUENCE HAS BEEN STARTED
;
  LDA  ESCFL  ;GET ESCAPE FLAG
  ORA  A
  JNZ  ESCS  ;IF NON-ZERO GO PROCESS THE REST
;
;
CHPCK:  MOV  A,B  ;SAVE IN B...STRIP PARITY BEFORE SCREEN!
  ANI  7FH  ;CLR PARITY TO LOCATE IN TBL
  MOV  B,A  ;KEEP IT W/OUT PARITY IN B TOO
  JZ  GOBK  ;DO A QUICK EXIT IF A NULL
  LXI  H,TBL  ;POINT TO SPECIAL SHARACTER TABLE
  CALL  TSRCH  ;GO PROCESS
;
GOBACK:  CALL  VDADD  ;GET SCREEN ADDRESS
  MOV  A,M  ;GET PRESENT CURSOR CHARACTER
  ORI 80H
  MOV  M,A  ;CURSOR IS BACK ON
  LHLD  SPEED-1  ;GET DELAY SPEED
  INR  L  ;MAKE SURE IT IS NON-ZERO
  XRA  A  ;DELAY WILL END WHEN H=0
TIMER:  DCX  H  ;TIMER DELAYS HERE
  CMP  H  ;DONE WITH DELAY YET
  JNZ  TIMER  ;KEEP DELAYING
  IF  EXT
  CALL  SINP  ;CHARACTER WAITING?
  JZ  GOBK  ;NOPE
  CPI  ESC
  JZ  COMND  ;RETURN TO SOLOS ON ESCAPE
  CPI  ' '  ;IS IT SPACE?
  JNZ  VDEL1
VDEL0:  CALL  SINP  ;WAIT FOR NEXT CHARACTER
  JZ  VDEL0
VDEL1:  CPI  '0'  ;GO BACK IF NOT 0-9
  JC  GOBK
  CPI  '9'+1
  JNC  GOBK
  ANI  0FH  ;KEEP LOWER NIBBLE
  JZ  SESPD
  MOV  C,A
  MVI  A,1  ;SET BIT
SPDLP:  DCR  C
  JZ  SESPD
  RLC .  ;MOVE IT OVER
  JC  STSLO  ;9 IS SLOWEST
  JMP  SPDLP
STSLO:  MVI  A,-1
SESPD:  STA  SPEED  ;SET NEW SPEED
  ENDF
GOBK:  POP  B
  POP  D  ;RESTORE REGISTERS
  POP  H
  RET    ;EXIT FROM VDMOT
;   
NEXT:  INX  H
  INX  H
;   
;
;   THIS ROUTINE SEARCHES THROUGH A SINGLE CHARACTER 
; TABLE FOR A MATCH TO THE CHARACTER IN "B".  IF FOUND
; A DISPATCH IS MADE TO THE ADDRESS FOLLOWING THE MATCHED
; CHARACTER.  IF NOT FOUND THE CHARACTER IS DISPLAYED ON
; THE MONITOR.
;   
TSRCH:  MOV  A,M  ;GET CHR FROM TABLE
  ORA  A
  IF  STD
  JZ  CHAR  ;ZERO IS THE LAST
  ENDF
  IF  EXT
  JZ  OCHAR  ;ZERO IS THE LAST
  ENDF
  CMP  B  ;TEST THE CHR
  INX  H  ;POINT FORWARD
  JNZ  NEXT
  PUSH  H  ;FOUND ONE...SAVE ADDRESS
  CALL CREM  ;REMOVE CURSOR
  XTHL    ;GET DISPATCH ADDRESS TO HL
  JMP  DISPT  ;DISPATCH NOW
;
;  PUT CHARACTER TO SCREEN
;   
  IF  STD
CHAR:  MOV  A,B  ;GET CHARACTER
  CPI  7FH  ;IS IT A DEL?
  RZ    ;GO BACK IF SO
  ENDF
;   
;   
;   
OCHAR:  EQU  $  ;ACTUALLY PUT CHAR TO SCREEN NOW
  CALL  VDADD  ;GET SCREEN ADDRESS
  MOV  M,B  ;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
  ANI  3FH  ;MOD 64 AND WRAP
  STA  NCHAR
  RNZ    ;DIDN'T HIT END OF LINE, OK
PDOWN:  EQU  $  ;CURSOR DOWN ONE LINE HERE
  LDA  LINE  ;GET THE LINE COUNT
  INR  A
CURSC:  ANI  0FH  ;STORE THE NEW
CUR:  STA  LINE  ;STORE THE NEW
  RET
;
; ERASE SCREEN
;
PERSE:  LXI  H,VDMEM  ;POINT TO SCREEN
  MVI  M,80H+' '  ;THIS IS THE CURSOR
;
  INX  H  ;BUMP  1ST
ERAS1:  EQU  $  ;LOOPS HERE TO ERASE SCREEN
  MVI  M,' '  ;BLANK IT OUT
  INX  H  ;NEXT
  MOV   A,H  ;SEE IF END OF SCREEN YET
  CPI  0D0H
  JC  ERAS1  ;NO--KEEP BLANKING
  STC    ;CARRY WILL SAY COMPLETE ERASE
;
PHOME:  MVI  A,0  ;RESET CURSOR--CARRY=ERASE, ELSE HOME
  STA  LINE  ;ZERO LINE
  STA  NCHAR  ;LEFT SIDE OF SCREEN
  RNC    ;IF NO CARRY, WE ARE DONE WITH HOME
;
ERAS3:  OUT  DSTAT  ;RESET SCROOL 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
;
;
;  ROUTINE TO MOVE THE CURSOR UP ONE LINE
;
PUP:  LDA   LINE  ;GET LINE COUNT
  DCR  A
  JMP  CURSC  ;MERGE TO HANDLE CURSOR
;
;  MOVE CURSOR LEFT ONE POSITION
;
PLEFT:  LDA  NCHAR
  DCR  A
PCUR:  EQU  $  ;CURSOR ON SAME LINE
  ANI  3FH  ;LET CURSOR WRAP
  STA  NCHAR  ;UPDATED CURSOR
  RET
;
;  CURSOR RIGHT ONE POSITION
;
PRIT:  LDA  NCHAR
  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  ;'C' 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    ;MADES FOUR
  MOV  L,A  ;L HAS IT
  ANI  3  ;MOD THREE FOR LATER
  ADI  <VDMEM  ;LOW SCREEN OFFSET
  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 SOUND ALARM ON BELL
;   
  IF  EXT
PBELL:  OUT  ALARM  ;DING
  JMP  OCHAR
  ENDF
;   
;  ROUTINE TO PROCESS A CARRIAGE RETURN
;   
PCR:  EQU  $
  IF  STD
  CALL  CLINE  ;CLEAR FROM CURRENT CURSOR TO END OF LINE
  ENDF
  IF  EXT
  XRA  A  ;REWIND TO BEGINNING OF LINE
  ENDF
;
;ORIGINAL HAD 'CALL CLINE' INSTEAD OF 'XRA A' AS SHOWN
;ABOVE. THIS CAUSED DISK COMMANDS TO DISAPPEAR FROM THE
;SCREEN AS CP/M MUST OUTPUT TWO 'CR' CHARACTERS.
;
  JMP  PCUR  ;AND STORE THE NEW VALUE
;
;  ROUTINE TO PROCESS A LINEFEED
;
PLF:  LDA  LINE  ;GET LINE COUNT
  INR  A
  ANI  15  ;SEE IF IT WRAPPED AROUND
  JNZ  CUR  ;NO--NO NEED TO SCROLL
  JMP  SROL  ;YES--THEN SCROLL
;
;  SET ESCAPE PROCESS FLAG
;
PESC:  MVI  A,-1
  STA  ESCFL  ;SET FLAG
  RET
;
;  PROCESS ESCAPE SEQUENCE
;
ESCS:  CALL  CREM  ;REMOVE CURSOR
  CALL  ESCSP  ;PROCESS THE NEXT PART OF SEQUENCE
  JMP  GOBACK
;
ESCSP:  LDA  ESCFL  ;GET ESCAPE FLAG
  CPI  -1  ;TEST FLAG
  JZ  SECOND
;
;  PROCESS THIRD CHR OF ESC SEQUENCE
;
  LXI  H,ESCFL
  MVI  M,0  ;NO MORE PARTS TO THE SEQUENCE
  CPI  2
  JC  SETX  ;SET X IF IS ONE
  JZ  SETY  ;SET Y IF IS TWO
  CPI  8
  JZ  STSPD  ;SET NEW DISPLAY SPEED IF "8"
  CPI  9
  JC  OCHAR  ;PUT IT ON THE SCREEN
  RNZ
;
;  TAB ABSOLUTE TO VALUE IN REG B
;
SETX:  MOV  A,B  ;GET CHARACTER
  JMP  PCUR
;
;  SET CURSOR TO LINE "B"
;
SETY:  MOV A,B
  JMP  CURSC
;
;
;  PROCESS SECOND CHR OF ESC SEPUENCE
;
SECOND:  MOV  A,B  ;GET WHICH
  CPI  3
  JZ  CURET  ;RETURN CURSOR PARAMETERS
  CPI  4
  JNZ  ARET2
;
;  ESC <4>  RETURN ABSOLUTE SCREEN ADDRESS
;
ARET:  MOV  B,H
  MOV  C,L  ;PRESENT SCREEN ADDRESS TO BC FOR RETURN
;
ARET1:  POP  H  ;RETURN ADDRESS
  POP  D  ;OLD B
  PUSH  B
  PUSH  H
  XRA  A
ARET2:  STA  ESCFL
  RET
;
;
;  RETURN PRESENT SCREEN PARAMETERS IN "BC"
;
CURET:  LXI  H,NCHAR
  MOV  B,M  ;CHARACTER POSITION
  INX  H
  MOV  C,M  ;LINE POSITION
  JMP  ARET1
;
;
;  ***** START UP SYSTEM *****
;
; CLEAR SCREEN AND THE FIRST 256 BYTES OF GLOBAL RAM
; THEN ENTER THE COMMAND MODE
;   
  IF  STD
STRTA:  XRA  A
  MOV  C,A
  ENDF
  IF  EXT
STRTA:  LDA  IGNCR+1  ;CHECK SYSTEM RAM
  ORA  A  ;ASSUME POWER-UP NON-ZERO
  MVI  A,0
  JNZ  STRT1
  MVI  A,3CH  ;CLEAR C800 -  C83B ONLY
STRT1  MOV  C,A
  XRA  A
  ENDF
  LXI  H,SYSRAM  ;CLEAR THR FIRST PAGE
;   
CLERA:  MOV  M,A
  INX  H
  DCR  C  ;ORIGINAL INR C  ****
  JNZ  CLERA
;
  LXI  SP,SYSTP  ;SET UP THE STACK FOR CALL
  CALL  PERSE
COMN1:  XRA  A
  OUT STAPT  ;BE SURE TAPES ARE OFF
  STA  OPORT
  STA  IPORT
;
;
;
;  ***** COMMAND MODE *****
;
;
;  THIS ROUTINE GETS AND PROCESSES COMMANDS
;
COMND:  LXI  SP,SYSTP  ;SET STACK POINTER
  LDA  OPORT  ;GET PORT
  PUSH  PSW
  XRA  A
  STA  OPORT  ;FORCE SCREEN OPERATIONS
  CALL  PROMPT  ;PUT PROMPT ON SCREEN
  CALL  GCLIN  ;GET COMMAND LINE
  POP  PSW
  STA  OPORT  ;RESTORE DEFAULT PORT
  CALL  COPRC  ;PROCESS THE LINE
  JMP  COMND  ;OVER AND OVER
;
;
;
; THIS ROUTINE READS A COMMAND LINE
; FROM THE SYSTEM KEYBOARD
;
;  C/R  TERMINATES THE SWQUENCE ERASING ALL 
;    CHARS TO THE RIGHT OF THE CURSOR
;  L/F  TERMINATES THE SEQUENCE
;  MODE  RESTARTS THE COMMAND LINE
;
GCLIN:  CALL  SINP  ;READ INPUT DEVICE
  JZ  GCLIN
  ANI  7FH  ;CLEAR PARITY BIT
  JZ  COMN1  ;THIS WAS A MODE (OR EVEN CTRL-@)
  MOV  B,A
  CPI  CR  ;CARRIAGE RETURN
  JZ  CLINE  ;YES--DONE WITH LINE
  CPI  LF  ;LINE FEED
  RZ    ;YES--DONE WITH LINE, LEAVE AS IS
  CPI  7FH  ;DELETE CHR?
  JNZ  CONT
  IF  STD
  MVI  B,BACKS  ;REPLACE IT
  ENDF
  IF EXT
  MVI  B,07FH  ;REPLACE IT
  ENDF
;
CONT:  CALL  SOUT
  JMP  GCLIN
;
;
; FIND AND PROCESS COMMAND
;
COPRC:  CALL  CREM  ;REMOVE THE CURSOR
  MVI  C,1  ;SET FOR CHARACTER POSITION
  CALL  VDAD2  ;GET SCREEN ADDRESS
  XCHG
  LXI  H,START  ;MAKE SURE HL PT TO SOLOS START
  PUSH  H  ;SAVE IT FOR LATER DISPT
  CALL  SCHR  ;SCAN PAST BLANKS
  JZ  ERR1  ;NO COMMAND?
  XCHG    ;HL HAS FIRST CHR
;   
  LXI  D,COMTAB  ;POINT TO COMMAND TABLE
  CALL  FDCOM  ;SEE IF IN PRIMARY COMMAND TABLE
  IF  STD
  CZ  FDCOU  ;IF NOT, TRY CUSTOM TABLE NEXT
  ENDF
  IF  EXT
  CZ  FDCOE  ;SCAN EXTENSION TABLE, THEN CUSTOM
  ENDF
DISPO:  EQU  $  ;HERE TO SEE IF ERROR OR DISP
  JZ  ERR2  ;NOT VALID, ERROR
  INX  D  ;BUMP TO PTR OF RTN
  XCHG    ;HL PT TO RTN ADDR
;
;
;  THIS IS THE DISPATCH ROUTINE
;  HL PT TO RTN ADDRESS, HL WILL BE RESTORED FROM STACK
;  SO THAT HL ARE RESTORED BEFORE DISPATCH.
;
DISPT:  EQU  $  ;OFF TO A ROUTINE
  MOV  A,M  ;LO ADDR
  INX  H
  MOV  H,M  ;HI ADDR
  MOV  L,A  ;HL NOW COMPLETE
DISP1:  EQU  $  ;HERE TO GO OFF TO HL
  XTHL    ;XCHG HL W/HL ON STACK
  MOV  A,L  ;ALSO COPY HERE FOR SETS
  RET    ;AND GO OFF TO THE RTN
;   
;  CHECKS FOR PRESENCE OF EXTENSION TABLE
;   
  IF  EXT
CKEXT:  LDA  SOLEXT
  CPI  0C3H
  RET
  ENDF
;   
;
;  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
; WITH HL POINTING TO ORIGINAL VALUE AND ZERO FLAG SET.
;   
  IF  EXT
FDCOE:  CALL  CKEXT  ;CHECK FOR EXTENSION
  JNZ  FDCOU  ;NOT THERE
  LXI  D,EXTCT  ;POINT TO EXTENDED COMMAND TABLE
  CALL  FDCOM  ;SCAN EXT
  JZ  FDCOU  ;NOT FOUND, SCAN CUST
  RET
  ENDF
;   
FDCOU:  LXI  D,CUTAB  ;HERE TO SCAN CUSTOM TBL ONLY
;   
  IF  STD
FDCOM:  LDAX  D
  ORA  A  ;TEST FOR TABLE END
  RZ    ;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
  ENDF
;   
  IF  EXT
FDCOM:  MOV  A,M  ;GET CHARACTER
  CPI  61H  ;LOWER CASE?
  JC  FDCO1  ;NO
  ANI  5FH  ;MAKE IT UPPER CASE
FDCO1:  MOV  C,A  ;SAVE IN C
  LDAX  D  ;GET TABLE CHARACTER
  ORA  A  ;TEST FOR TABLE END
  RZ  .  ;NOT FOUND. COMMAND ERROR
  PUSH  H
  CMP  C
  INX  D
  JNZ  NCOM  ;NOT FOUND
  INX  H
  MOV  A,M  ;GET SECOND CHARACTER
  CPI  61H
  JC  FDCO2
  ANI  5FH  ;U.C.
FDCO2:  MOV  C,A
  LDAX  D
  CMP  C
  JNZ  NCOM
  ENDF
;   
  POP  H  ;RESTORE ORIGINAL SCAN ADDR
  ORA  A  ;SET NON-ZERO FLAG SAYING FOUND
  RET    ;WITH NON-ZERO SET
;
;
NCOM:  INX  D  ;GO TO NEXT ENTRY
  INX  D
  INX  D
  POP  H  ;GET BACK ORIGINAL ADDRESS
  JMP  FDCOM  ;CONTINUE SEARCH
;
;
;  ***** COMMAND TABLE *****
;
; THIS TABLE DESCRIBES THE VALID COMMANDS FOR SOLOS
;   
COMTAB  EQU  $
  IF  STD
  ASC 'TE'  ;TERMINAL MODE
  DW  TERM
  ENDF
  ASC 'DU'  ;DUMP
  DW  DUMP
  ASC 'EN'  ;ENTER
  DW  ENTER
  ASC 'EX'  ;EXECUTE
  DW  EXEC
  ASC 'GE'  ;GET A FILE
  DW  TLOAD
  ASC 'SA'  ;SAVE A FILE
  DW  TSAVE
  ASC 'XE'  ;AUTO-EXECUTE A FILE
  DW  TXEQ
  ASC 'CA'  ;CATALOG OF TAPE FILES
  DW  TLIST
  ASC 'SE'  ;SET COMMAND
  DW  CSET
  ASC 'CU'  ;CUSTOM COMMAND
  DW  CUSET
  IF  EXT
  ASC 'BO'  ;DOS BOOTS
  DW  DOS
  ENDF
  DB  0  ;END OF TABLE MARK
;   
;   
;  DISPLAY DRIVER COMMAND TABLE
;   
;     THIS TABLE DEFINES THE CHARACTERS FOR SPECIAL
; PROCESSING.  IF THE CHARACTER IS NOT IN THE TABLE IT
; GOES TO THE SCREEN.
;
TBL:  DB  CLEAR-80H  ;CLEAR SCREEN
  DW  PERSE
  DB  UP-80H    ;UP CURSOR
  DW  PUP
  DB  DOWN-80H  ;DOWN CURSOR
  DW  PDOWN
  DB  LEFT-80H  ;LEFT CURSOR
  DW  PLEFT
  DB  RIGHT-80H    ;RIGHT CURSOR
  DW  PRIT
  DB  HOME-80H  ;HOME CURSOR
  DW  PHOME
  IF  EXT
  DB  BELL  ;BELL
  DW  PBELL
  DB  CEOL  ;CLEAR TO EOL
  DW  CLINE
  ENDF
  DB  CR    ;CARRIAGE RETURN
  DW  PCR
  DB  LF    ;LINE FEED
  DW  PLF
  IF  STD
  DB  BACKS    ;BACKSPACE
  ENDF
  IF  EXT
  DB  07FH  ;BACKSPACE
  ENDF
  DW  PBACK
  DB  ESC    ;ESCAPE KEY
  DW  PESC
  DB  0    ;END OF TABLE
;
;
;  OUTPUT DEVICE TABLE
;
OTAB:  DW  VDMOT  ;VDM DRIVER
  DW  SDROT  ;SERIAL OUTPUT
  DW  PROUT  ;PARALLAL OUTPUT
  DW  ERROT  ;ERROR OR USER DRIVER HANDLER
;
;
;  INPUT DEVICE TABLE
;
ITAB:  DW  KSTAT  ;KEYBOARD INPUT
  DW  SSTAT  ;SERIAL INPUT
  DW  PASTAT  ;PARALLEL INPUT
  DW  ERRIT  ;ERROR OR USER DRIVER HANDLER
;
;
;  SECONDARY COMMAND TABLE FOR SET COMMAND
;
SETAB:  ASC 'TA'  ;SET TAPE SPEED
  DW  TASPD
  ASC 'S='  ;SET DISPLAY SPEED
  DW  DISPD
  ASC 'I='  ;SET INPUT PORT
  DW  SETIN
  ASC 'O='  ;SET OUTPUT PORT
  DW  SETOT
  IF  STD
  ASC 'N='  ;SET NULLS
  DW  SETNU
  ENDF
  ASC 'CI'  ;SET CUSTOM DRIVER ADDRESS
  DW  SETCI
  ASC 'CO'  ;SET CUSTOM OUTPUT DRIVER ADDRESS
  DW  SETCO
  ASC 'XE'  ;SET HEADER XEQ ADDRESS
  DW  SETXQ
  ASC 'TY'  ;SET HEADER TYPE
  DW  SETTY
  ASC 'CR'  ;SET CRC TO ALLOW IGNORING OF CRC ERRORS
  DW  SETCR
  DB  0  ;END OF TABLE MARK
;
;
;  SOLOS PORT ERROR HANDLER
;   
ERRIT:  PUSH  H  ;SAVE HL ONCE AGAIN
  LHLD  UIPRT  ;GET USER INPUT PORT ADDRESS
  JMP  ERRO1  ;AND GO PROCESS
;
ERROT:  PUSH  H
  LHLD  UOPRT  ;GET USER OUTPUT PORT ADDRESS
ERRO1:  MOV  A,L  ;TEST HL FOR ZERO
  ORA  H
  JZ  COMN1  ;IF ZERO RETURN TO COMMAND MODE
  XTHL    ;ADDRESS TO STACK...OLD HL TO HL
  RET    ;GO TO THE DRIVER

