;
; ******** SOLOS OPERATING SYSTEM ********
;          For McVideo Module
;          Mod (2.1) Modified:  Mar, 1983
;
;
;
; AUTO-STARTUP CODE
;
START: DB 0  ;USED IN 4 PHASE WONDER
INIT:  JMP  STRTA  ;COLD START ENTRY POINT
RETRN:  JMP COMND  ;WARM START ENTRY POINT
MSGV:  JMP MEMT9  ;OUTPUT MESSAGE UNTIL '00'
PIN:  JMP SSTAT  ;SERIAL INPUT
POUT:  JMP SDROT  ;SERIAL PRINTER OUTPUT
  JMP HEOUT  ;OUTPUT 'A' IN HEX
  JMP ADOU1  ;OUTPUT 'HL' IN HEX
  JMP DUMP1  ;DUMP MEMORY
SOUT:  JMP VDMOT  ;VDM OUTPUT
  JMP CRLF  ;CRLF OUT
SINP:  JMP KSTAT  ;INPUT HANDLER
  JMP EXDEP  ;MEMORY EDITOR
  JMP ENTR1  ;BYTE ENTER ROUTINE
  JMP ZIP4  ;MEMORY FILL ROUTINE
  JMP SERCH  ;MEMORY SEARCH
;
;   KEYBOARD INPUT DRIVER
;
KSTAT:  IN  STAPT  ;GET STATUS WORD
  CMA .  ;INVERT IT FOR PROPER RETURN
  ANI  KDR  ;TEST KEYBOARD BIT
  RZ .  ;ZERO IS NO CHARACTER RECEIVED
  IN  KDATA  ;GET CHARACTER
  RET .
;
;  ROUTINE TO BACKSPACE
;
PBACK:  CALL  PLEFT
  CALL  VDADD  ;GET SCREEN ADDRESS
  MVI  M,' '  ;PUT A BLANK THERE
  RET  .
;
;  SERIAL DATA OUTPUT
;
SDROT:  IN  SERST  ;Get port status
  ANI  0A0H  ;Mask off all but CTS and TBE bits
  CPI  0A0H  ;Check if bits present
  JNZ  SDROT  ;If missing, go back
  MOV  A,B  ;Move in char
  CPI  7FH  ;Deletes get an underline
  JNZ  SDRO3
  MVI  A,BACKS
SDRO3:  OUT  SDATA  ;Send it out
  RET
;
;  VIDEO DISPLAY ROUTINES
;
VDMOT:  PUSH  H  ;SAVE MOST REGISTERS
  PUSH  D
  PUSH  B
;
CHPCK:  LDA  PRTOG  ;GET FLAG BYTE
  MOV  C,A
  RRC  .  ;PRINT WANTED?
  JNC  CHPC0
  MOV  A,C
  ANI  80H  ;WHICH PRINTER?
  PUSH PSW
;
  IF  EPSON
  CZ  PROUT  ;OUT PARALLEL PORT
  POP  PSW
  CNZ SDROT  ;OUT SERIAL PORT
  ENDF
;
  IF  TI810
  CZ  SDROT
  POP  PSW
  CNZ  PROUT
  ENDF
;
CHPC0:  MOV  A,B  ;REJECT NULLS
  ANI  7FH
  MOV  B,A
  JZ  GOBK
;
CHPC4:  LXI  H,TBL  ;POINT TO SPECIAL CHARACTER TABLE
  CALL  TSRCH  ;GO PROCESS
;
GOBACK:  CALL  VDADD  ;GET SCREEN ADDRESS
  MOV  A,M
  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
;
VDEL0:  CALL  KSTAT  ;CHARACTER WAITING?
  JZ  GOBK  ;NOPE
;
VDEL1: CPI  ESC  ;RETURN TO SOLOS ON ESCAPE
  JZ  COMND
;
VDEL2:  EQU  $
VDEL3:  CPI  '1'  ;GO BACK IF NOT 1-9
  JC  GOBK
  CPI  '9'+1
  JNC  GOBK
  ANI  0FH  ;KEEP LOWER NIBBLE
  JZ  SESPD
  MOV  C,A
  XRA  A
  STC  .  ;SET BIT
SPDLP:  DCR  C
  JZ  SESPD
  RAL  .  ;MOVE IT OVER
  JMP  SPDLP
;
SESPD:  STA  SPEED  ;SET NEW SPEED
GOBK:  POP  B
  POP  D  ;RESTORE REGISTERS
  POP  H
  RET .  ;EXIT FROM VDMOT
;
;  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
;
NEXT:  INX  H
  INX  H
;
TSRCH:  MOV  A,M  ;GET CHR FROM TABLE
  ORA  A
  JZ  OCHAR  ;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
  XTHL .  ;GET DISPATCH ADDRESS TO HL
  JMP  DISPT  ;DISPATCH NOW
;
;  THIS ROUTINE READS A COMMAND LINE FROM KEYBOARD
;
GCLIN:  CALL  SINP  ;READ INPUT DEVICE
  JZ  GCLIN
  ANI  7FH  ;CLEAR PARITY BIT
  CPI  ESC
  JZ  COMN1  ;ABORT LINE
  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
CONT:  CALL SOUT
  JMP GCLIN
;
; ROUTINE TO CALCULATE SCREEN ADDRESS
;
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 POSITIIN
VDAD0:  CPI  NLINES
  JC  VDAD1
  SUI  NLINES
  JMP  VDAD0
;
VDAD1:  PUSH  D
  LXI  H,VDMEM-LLGTH
  LXI  D,LLGTH
VDAD3:  DAD  D
  DCR  A
  JP  VDAD3
  MOV  E,C
  DAD  D
  POP  D
  RET  .
;
;  ROUTINE TO REMOVE CURSOR
;
CREM:  CALL  VDADD  ;GET CURRENT SCREEN ADDRESS
  MOV  A,M
  ANI  7FH  ;STRIP OFF THE CURSOR
  MOV  M,A
  RET
;
;  PUT CHARACTER TO SCREEN
;
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  LLGTH-1  ;END OF LINE?
  JC  OK
  LDA  LINE
  CPI  NLINES-1  ;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
  LDA  BOT  ;DO THE HARDWARE SCROLL
  INR  A
  CPI  NLINES
  JNZ  SROLX
  XRA  A
SROLX:  CALL  ERAS3
  XRA  A  ;CLEAR THE LINE
  JMP  CLIN1
;
; INCREMENT LINE COUNTER IF NECESSARY
;
OK:  LDA  NCHAR  ;GET CHR POSITION
  INR  A
  CPI  LLGTH
  STA  NCHAR
  RNZ .  ;DIDN'T HIT END OF LINE, OK
  XRA  A
  STA  NCHAR
;
PDOWN:  EQU  $  ;CURSOR DOWN ONE LINE HERE
  LDA  LINE  ;GET THE LINE COUNT
  INR  A
CURSC:  CPI  NLINES
  JNZ  CUR
  XRA  A
CUR:  STA  LINE  ;STORE THE NEW COUNT
  RET
;
; ERASE SCREEN
;
PERSE:  LXI  H,VDMEM  ;POINT TO SCREEN
  MVI  M,0A0H  ;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  <VDMEM+1920
  JNZ  ERAS1  ;NO--KEEP BLANKING
  MOV  A,L
  CPI  >VDMEM+1920
  JNZ  ERAS1
  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 SCROLL PARAMETERS
  STA  BOT  ;BEGINNING OF TEXT OFFSET
  RET
;
CLINE:  CALL  VDADD  ;GET CURRENT SCREEN ADDRESS
  LDA  NCHAR  ;CURRENT CURSOR POSITION
CLIN1:  CPI  LLGTH
  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
  JP  CURSC
  MVI  A,NLINES-1
  JMP  CURSC  ;MERGE TO HANDLE CURSOR
;
;  MOVE CURSOR LEFT ONE POSITION
;
PLEFT:  LDA  NCHAR
  DCR  A
  JP  PCUR
  MVI  A,LLGTH-1
PCUR:  EQU  $  ;CURSOR ON SAME LINE
  CPI  LLGTH
  JNZ  PCUR1
  XRA  A
PCUR1:  STA  NCHAR  ;UPDATED CURSOR
  RET  .
;
;  CURSOR RIGHT ONE POSITION
;
PRIT:  LDA  NCHAR
  INR  A
  JMP  PCUR
;
;  ROUTINE TO PROCESS A CARRIAGE RETURN
;
PCR:  EQU  $
  CALL  CLINE  ;CLEAR THE LINE
  XRA  A
  JMP  PCUR  ;STORE NEW LINE VALUE
;
;  ROUTINE TO PROCESS A LINEFEED
;
PLF:  LDA  PRTOG  ;SEE IF SPACE BAR HALT OK
  ANI  8
  JNZ  PLF2  ;NOT YET
  IN  KDATA  ;LOOK AT KEYBOARD PORT
  CPI  ' '  ;SPACE BAR TYPED?
  JNZ  PLF2  ;NZ SAYS NO
;
PLF1:  CALL  KSTAT  ;WAIT FOR ANOTHER KEY
  JZ  PLF1
;
PLF2:  LDA  LINE  ;GET LINE COUNT
  INR  A
  CPI  NLINES
  JNZ  PLF3  ;NO--NO NEED TO SCROLL
  XRA  A
  JMP  SROL  ;YES--THEN SCROLL
;
PLF3:  STA  LINE
  JMP  PCR
;
;   *****  START UP SYSTEM  *****
;
STRTA  XRA A
  MVI  C,48  ;Clear only what's necessary
  LXI  H,SYSRAM  ;Point to start of RAM
;
CLERA:  MOV  M,A
  INX  H
  DCR  C
  JNZ  CLERA
  IN  STAPT
  IN  KDATA  ;CLEAR INPUT GARBAGE
  LXI  SP,SYSTP  ;SET UP THE STACK FOR CALL
  CALL  PERSE
COMN1:  XRA  A
  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
  LDA  PRTOG  ;GET FLAG BYTE
  PUSH  PSW
  ORI  8
  STA  PRTOG  ;NO SPC/BAR HALT YET
  CALL  PROMPT  ;PUT PROMPT ON SCREEN
  POP  PSW
  STA  PRTOG  ;SPC/BAR OK NOW
  CALL  GCLIN  ;GET COMMAND LINE
  POP  PSW
  STA  OPORT  ;RESTORE DEFAULT PORT
  CALL  COPRC  ;PROCESS THE LINE
  JMP  COMND  ;OVER AND OVER
;
; 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
;
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
;
DISPT:  EQU  $  ;OFF TO A ROUTINE
  MOV  A,M  ;LO ADDR
  INX  H
  MOV  H,M  ;HI ADDR
  MOV  L,A  ;HL NOW CGMPLETE
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
;
;  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.
;
FDCOM:  LDAX  D
  ORA  A  ;TEST FOR TABLE END
  RZ  .  ;NOT FOUND. COMMAND ERROR
  PUSH  H
  CMP  M
  INX  D
  JNZ  NCOM  ;NOT FOUND
  INX  H
  LDAX  D
  CMP  M
  JNZ  NCOM
  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  $
  ASC  'DU'  ;DUMP
  DW  DUMP
  ASC  'EN'  ;ENTER
  DW  ENTER
  ASC  'EX'  ;EXECUTE
  DW  EXEC
  ASC  'SE'  ;SET COMMAND
  DW  CSET
  ASC  'CM'  ;COMPARE MEMORY
  DW  COMPM
  ASC  'BO'  ;PTDOS BOOT
  DW  DOS
  ASC  'NS'  ;NORTHSTAR BOOT
  DW  0E800H
  ASC  'ED'  ;EDIT
  DW  EXDEP
  ASC  'MM'  ;MOVE MEMORY
  DW  MOVE
  ASC  'ZI'  ;ZIP OR FILL MEMORY
  DW  ZIP
  ASC  'SM'  ;SEARCH MEMORY
  DW  SERCH
  ASC  'HM'  ;HEX MATH
  DW  HMATH
  ASC  'TM'  ;TEST MEMORY
  DW  MEMT
;
  DB  0  ;END OF TABLE MARK
;
;  DISPLAY DRIVER COMMAND TABLE
;
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
  DB  CEOL  ;CLEAR TO EOL
  DW  CLINE
  DB  CR  ;CARRIAGE RETURN
  DW  PCR
  DB  LF  ;LINE FEED
  DW  PLF
  DB  BACKS  ;BACKSPACE
  DW  PBACK
  DB  7FH  ;DELETE
  DW  PBACK
  DB  'P'-40H  ;TOGGLE PRINTER
  DW  PRINT
  DB  7
  DW  BELL
;
  DB  0  ;END OF TABLE
;
;  SECONDARY COMMAND TABLE FOR SET COMMAND
;
SETAB:  EQU  $
;
  ASC  'M='  ;SET MODE BYTE
  DW  SETMD
  ASC  'C='  ;SET MOVE COUNT
  DW  SETMOV
  DB  0  ;END OF TABLE MARK
;
DHLOP  LDAX D
  CMP  M
  RNZ
  DCR  B
  RZ
  INX  H
  INX  D
  JMP  DHLOP
;
BELL:  MOV  A,B
  OUT  KDATA
  RET  .
;
PRINT:  LDA  PRTOG
  XRI  1
  STA  PRTOG
  RET  .
;
