;
; ******** SOLOS OPERATING SYSTEM ********
;          For McVideo Module
;          Modified:  Dec, 1982
;
; Routine Locations:
;
;  PSEUDO PORTS:  0 = KEYBOARD/VIDEO
;      1 = SERIAL PORT
;      2 = PARALLEL PORT
;
; AUTO-STARTUP CODE
;
START:  DB  0
INIT:  JMP  STRTA  ;SYSTEM RESTART ENTRY POINT
RETRN:  JMP COMND
  DB  0C3H  ;Required for PTDOS 1.5
;
;  OUTPUT DEVICE TABLE
;
OTAB:  DW  VDMOT  ;VDM DRIVER
  DW  SDROT  ;SERIAL OUTPUT
  DW  PROUT  ;PARALLAL OUTPUT
  DW  RETRN  ;CUSTOM DELETED
;
;  INPUT DEVICE TABLE
;
ITAB:  DW  KSTAT  ;KEYBOARD INPUT
;
  IF  PORTIN
  DW  SSTAT  ;SERIAL INPUT
  DW  PASTAT  ;PARALLEL INPUT
  ENDF
;
  IF  CURADR
  DW  RETRN
  DW  RETRN
  ENDF
;
  DW  RETRN  ;CUSTOM DELETED
  DB  0  ;FILLER
;
SOUT:  LDA  OPORT  ;SOUT ENTRY POINT
AOUT:  JMP  OUTPR  ;AOUT ENTRY POINT
SINP:  LDA  IPORT  ;SINP ENTRY POINT
AINP:  PUSH  H  ;THIS IS ACTUALLY AINP
  LXI  H,ITAB
;
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
;
;   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
  DW  0  ;SPACE FOR ANI 7FH
  JMP PRINT  ;GO CHECK FOR THE CONTROL-P
;
;  JMP TABLE OUTPUT ROUTINES
;
OUTPR:  PUSH  H
  LXI  H,OTAB  ;POINT TO OUTPUT TABLE
  JMP  IOPRC  ;AND DISPATCH TO OUTPUT ROUTINE
;
  IF  PORTIN
;
;  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
;
  ENDF
;
;  SERIAL DATA OUTPUT
;
SDROT:  IN  SERST  ;GET PORT STATUS
  RAL  .  ;PUT HIGH BIT IN CARRY
  JNC  SDROT  ;LOOP UNTIL TBE
  JMP  SDRO2  ;Continue later
  DB  0  ;This keeps VDMOT at XX54H
;
;  VIDEO DISPLAY ROUTINES
;
VDMOT:  PUSH  H  ;SAVE MOST REGISTERS
  PUSH  D
  PUSH  B
;
CHPCK:  LDA  FLGBYT  ;GET FLAG BYTE
  MOV  C,A
  LDA  PRTOG  ;PRINT TOGGLE ON?
  RRC  .
  JNC  CHPC0
  MOV  A,C
  ANI  SPRFLG  ;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
  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  '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
GOBK:  POP  B
  POP  D  ;RESTORE REGISTERS
  POP  H
  RET .  ;EXIT FROM VDMOT
;
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 BACKSPACE
;
PBACK:  CALL  PLEFT
  CALL  VDADD  ;GET SCREEN ADDRESS
  MVI  M,' '  ;PUT A BLANK THERE
  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
;
  IF  S64
  CPI  <VDMEM+1024
  ENDF
;
  IF  S80
  CPI  <VDMEM+1920
  ENDF
;
  JNZ  ERAS1  ;NO--KEEP BLANKING
  MOV  A,L
;
  IF  S64
  CPI  >VDMEM+1024
  ENDF
;
  IF  S80
  CPI  >VDMEM+1920
  ENDF
;
  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  FLGBYT  ;GET FLAG BYTE
  MOV  C,A  ;SAVE IT
  ANI  SPCFLG  ;SEE IF SPACE BAR HALT OK
  JNZ  PLF2  ;IF NOT, BYPASS
  IN  KDATA  ;LOOK AT KEYBOARD PORT
  CPI  ' '  ;SPACE BAR TYPED?
  JNZ  PLF2  ;NZ SAYS NO
PLF1:  CALL  KSTAT  ;WAIT FOR ANOTHER KEY
  JZ  PLF1
  LXI  H,PLF2  ;SET UP FOR SPEED ROUTINE
  PUSH  H  ;THIS WILL GET POPPED BY VDMOT
  PUSH  H
  PUSH  D
  PUSH  B
  JMP  VDEL1  ;GO CHECK FOR SPEED & ESC
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
;
  IF  CURADR
;
ESCS:  CALL  CREM  ;Remove cursor
  CALL  ESCPR  ;Process ESC sequence
  JMP  GOBACK  ;Exit
;
ESCPR:  MOV  A,B  ;Get next char
  CPI  '='  ;Is it 2nd part?
  MVI  A,'='+80H  ;Set flag if so
  JZ  PESC  ;Store it
  LDA  FLGESC  ;Get ESC flag
  PUSH  PSW  ;Save it
  ANI  7FH  ;Strip flag bit
  CPI  '='  ;See if 2nd was sent
  JZ  SETXY  ;OK, do X & Y
  POP  PSW  ;Opps! A bummer
  XRA  A
  CALL  PESC  ;Zero ESC flag
  JMP  CHPCK  ;Send char to screen
;
SETXY:  POP  PSW  ;Get back flag bit
  ANI  80H  ;See if set
  JZ  SETY  ;If not do X
X:  MOV  A,B
  CALL  CURSC
  MVI  A,'='  ;Reset flag bit
;
PESC:  STA  FLGESC
  RET  .
;
SETY:  STA  FLGESC
  MOV  A,B
  JMP  PCUR
;
  ENDF
;
;  Continuation of Serial Data Output
;
SDRO2:  ANI  40H  ;Check CTS bit (after RAL)
  JZ  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
;
;   *****  START UP SYSTEM  *****
;
STRTA  XRA A
  MVI  C,16  ;Clear only what's necessary
  LXI  H,SYSRAM  ;Point to start of RAM
;
CLERA:  MOV  M,A
  INX  H
  DCR  C
  JNZ  CLERA
;
  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  FLGBYT  ;GET FLAG BYTE
  PUSH  PSW
  XRA  A
  STA  OPORT  ;FORCE SCREEN OPERATIONS
  INR  A
  STA  FLGBYT  ;NO SPC/BAR HALT YET
  CALL  PROMPT  ;PUT PROMPT ON SCREEN
  POP  PSW
  STA  FLGBYT  ;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
;
  IF  HELIOS
  ASC  'BO'  ;PTDOS BOOT
  DW  DOS
  ENDF
;
  IF  TERM
  ASC  'TE'
  DW  TERMC
  ENDF
;
  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
;
  IF  MEMTST
  ASC  'TM'  ;TEST MEMORY
  DW  MEMT
  ENDF
;
  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  7
  DW  BELL
;
  IF  CURADR
  DB  ESC  ;ESCAPE
  DW  PESC
  ENDF
;
  DB  0  ;END OF TABLE
;
;  SECONDARY COMMAND TABLE FOR SET COMMAND
;
SETAB:  EQU  $
;
  IF PORTIN
  ASC  'I='  ;SET INPUT PORT
  DW  SETIN
  ENDF
;
  ASC  'O='  ;SET OUTPUT PORT
  DW  SETOT
  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  .
;
