;
;  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
  CALL  CLINE  ;CLEAR THE LINE
  MVI  B,'#'  ;THE PROMPT
  JMP  SOUT  ;PUT IT ON THE SCREEN
;
CRLF:  MVI  B,LF  ;LINEFEED
  CALL  SOUT
  MVI  B,CR  ;CARRIAGE RETURN
  JMP  SOUT
;
; 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 LEAVE HL UNTOUCHED.
; (PSCAN DOES NOT ABORT IF NO PARAMETER PRESENT)
;
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  ;DE IS POINTING TO CHR ON SCREEN
  CPI  BLANK
  JZ  SCHR  ;GOT A BLANK NOW SCAN PAST IT
  CPI  ','
  JZ  SCHR  ;COMMA IS OK TOO
  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 UP TO 10 BLANK POSITIONS LOOKING
; FOR A NON-BLANK CHARACTER
;
SCHR:  MVI  C,10
SCHR1:  LDAX  D  ;GET NEXT CHARACTER
  CPI  ' '  ;CHECK FOR BLANKS
  RNZ  .  ;WE'RE PAST THEM
  INX  D  ;NEXT SCAN ADDRESS
  DCR  C
  RZ  .  ;COMMAND ERROR
  JMP  SCHR1  ;KEEP LOOPING
;
; SCONV ABORTS TO SOLOS IF NO PARAMETER
;
SCONV:  CALL  SBLK  ;FIND IF VALUE IS PRESENT
  JZ  ERR1  ;ABORT TO ERROR IF NONE
;
SHEX:  LXI  H,0  ;CLEAR H & L
SHE1:  LDAX  D  ;GET CHARACTER
SHE2:  CPI  ' '  ;IS IT A SPACE
  RZ  .    ;IF SO
  CPI  '/'  ;SLASH IS ALSO LEGAL
  RZ  .
  CPI  ':'  ;EVEN THE COLON IS ALLOWED
  RZ  .
  CPI  ','  ;COMMA TOO
  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 HEX
  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
;
;  OUTPUT HL AS HEX 16 BIT VALUE
;
ADOUT:  CALL  ADOU1
  MVI  B,' '
  JMP  SOUT
;
ADOU1:  MOV  A,H  ;H FIRST
  CALL  HEOUT
  MOV  A,L  ;THEN L
  JMP  HEOUT
;
HBOUT:  CALL  HEOUT
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  144  ;WE WORK WITH ASCII HERE
  DAA  .  ;ADJUST IT TO DECIMAL
  ACI  64  ;MAKE IT A LETTER
  DAA  .  ;ADJUST AGAIN
  MOV  B,A  ;OUTPUT IT FROM REGISTER 'B'
  JMP  SOUT
;
;  ***** ENTER COMMAND *****
;
ENTER:  CALL  SCONV  ;SCAN OVER CHARS AND GET ADDRESS
  CALL  ENTR1
  JMP  COMN1
;
ENTR1:  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:  CALL  SCHR  ;SCAN TO NEXT VALUE
  JZ  ENLOP  ;LAST ENTRY FOUND, START NEW LINE
;
  CPI  '/'  ;COMMAND TERMINATOR
  RZ  .  ;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 *****
;
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
;
;  ***** SOLOS ERROR HANDLER *****
;
ERR1:  XCHG .  ;GET SCAN ADDRESS TO HL
ERR2:  CALL  CRLF  ;PUT ^ BELOW BAD CHARACTER
  LXI  D,80
  DAD  D  ;MOVE DOWN ONE LINE
  MOV  A,H
  CPI  <VDMEM+1920
  JNZ  ERR3  ;NO
  MOV  A,L
  CPI  >VDMEM+1920
  JC   ERR3
  LXI  D,-1920
  DAD  D
;
ERR3:  MVI  M,'^'
  JMP  COMN1
;
;  ***** SET COMMAND *****
;
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
;
; SET MODE BYTE
;
SETMD:  STA  PRTOG
  RET  .
;
; SET COUNT FOR MULTIPLE MOVES
;
SETMOV:  EQU  $
  STA  MOVCNT
  RET  .
;
  IF  HELIOS
;
DOS EQU $
;
;  Helios II bootstrap
;  Syntax:  BOOT
;
PTBOOT:  EQU  $
 MVI  A,0CFH
 OUT  0F7H  restore, latch load head, select 0
 OUT  0F5H  reset TC, ABORT, CRC error and checked
 MVI  A,-1
 OUT  0F1H  set do nothing
;
BOOTL  IN 0F0H  wait til ABORT clears
 ANI  40H
 JNZ  BOOTL
 MVI  A,0DFH
 OUT  0F7H  latch load head, select 0
;
IFIN  IN  0F0H  wait for index
 RLC
 JC  IFIN
 LXI  D,1290H
;
IFIN2:  DCX D
 MOV  A,D
 ORA  E
 JNZ  IFIN2
;
IFIN3:  IN 0F0H  wait for index - again!
 RLC
 JC  IFIN3
;
SWAIT IN 0F0H  wait for SREADY (controller ready)
 ANI 2
 JZ SWAIT
 MVI A,40H
 OUT 0F3H  set DMA length to 340H
 MVI A,3
 OUT 0F4H
 XRA A
 OUT 0F5H  set DMA start to DMA
 OUT 0F6H
 MVI A,3
 OUT 0F1H  read disk (latch 3 to U22)
;
PTDLOOP EQU $
 IN 0F0H  wait until CRC error, TC, or
;              SREADY (controller ready)
 ANI 0BH
 JZ PTDLOOP
 ANI 8  non-zero means CRC error
 JNZ PTBOOT
 JMP 4
;
 ENDF
;
 IF TERM
;
;  ***** TERM COMMAND *****
;
;  THIS ROUTINE GETS CHARACTERS FROM THE SYSTEM
;  KEYBOARD AND OUTPUTS THEM TO THE SELECTED
;  PORT.  IT CONFIGURES THE SOL AS A VIDEO TERM-
;  INAL.  COMMAND KEYS ARE NOT OUTPUT.  THE MODE
;  KEY RETURNS TO THE COMMAND MODE.
;
TERMC:  CALL  PSCAN
  STA  IPORT
  CALL  PSCAN
  STA  OPORT
;
TERM1:  CALL  KBSTA
  JZ  TIN
  MOV  B,A
  CPI  MODE
  JZ  COMN1
  JC  TOUT
  MOV  A,B
  ANI  7FH
  MOV  B,A
  CALL  VDMOT
  JMP  TIN
;
TOUT:  CALL  SOUT
TIN:  CALL  SINP
  JZ  TERM1
  ANI  7FH
  JZ  TERM1
  MOV  B,A
  CALL  VDMOT
  JMP  TERM1
;
KBSTA:  IN  STAPT
  CMA  .
  ANI  KDR
  RZ  .
  IN  KDATA
  RET  .
;
  ENDF
;
;  ***** DUMP COMMAND *****
;
;  Syntax: DUMP <addr>
;          DUMP <addr1> <addr2>
;          DUMP <addr1>,<byte-count>
;
DUMP:  CALL  GETADR
  CALL  DUMP1
  JMP  COMND
;
DUMP1:  PUSH  H  ;SAVE THE VALUE
  POP  D  ;GET END
  LHLD  UIPRT  ;HL HAS START, DE HAS END
;
DLOOP:  SHLD  UIPRT  ;SAVE FOR ASCII
  CALL  CRLF  ;GET READY FOR NEW LINE
  LHLD  UIPRT  ;GET LINE ADDRESS
  CALL  ADOU1  ;OUTPUT ADDRESS
  MVI  B,':'  ;MOVE IN THE DUMP DISCRIPTOR
  CALL  SOUT
  CALL  BOUT
  CALL  BOUT  ;TWO SPACES TO KEEP IT PRETTY
  MVI  C,16  ;VALUES PER LINE
;
PRHEX:  MOV  A,M  ;GET THE CHAR
  PUSH  B  ;SAVE COUNT
  CALL  HBOUT  ;PRINT THE BYTE
  POP  B
  CALL  PRSPC  ;CHECK FOR END
  JNC  BFILL  ;ABORT HEX, DO ASCII
  JNZ  PRHEX  ;NOT ZERO IF MORE FOR THIS LINE
;
PREH1:  LHLD  UIPRT  ;GET LINE ADDR BACK
  MVI  C,16  ;VALUES PER LINE
;
PRASC:  MOV  A,M  ;GET THE CHAR
  ANI  7FH  ;STRIP HIGH BIT
  CPI  7FH  ;NO DELETES!
  JZ  PERIOD
  CPI  5FH  ;NO BACKSPACES
  JZ  PERIOD
  CPI  20H  ;NO CTRL CHAR
  JP  SKIP
;
PERIOD:  MVI  A,'.'  ;ALL NON-ASCII GET THIS
SKIP:  MOV  B,A  ;PUT CHAR IN B
  CALL  SOUT  ;SEND IT OUT
  CALL  PRSPC  ;CHECK FOR END
  RNC  .  ;ALL DONE
  JNZ  PRASC
  JMP  DLOOP  ;DO NEXT LINE
;
BFILL:  CALL PRSP1  ;CHECK IF END OF LINE
  JZ  PREH1  ;DO ASCII NOW
  CALL  BOUT  ;BLANK FILL LINE
  CALL  BOUT
  CALL  BOUT
  JMP  BFILL  ;LOOP UNTIL LINE FILLED
;
PRSPC:  CALL  CDEHL  ;COMPARE DE HL
  RNC  .  ;ALL DONE
PRSP1:  INX  H
  DCR  C  ;BUMP THE COUNT
  PUSH  PSW
  MOV  A,C
  ANI  3
  CZ  BOUT  ;AN EXTRA SPACE EACH 4 VALUES
  POP  PSW
  RET  .
;
CDEHL  MOV  A,L  ;COMPARE DE AND HL
  SUB  E
  MOV  A,H
  SBB  D
  RET  .
;
GETADR  CALL  SCONV  ;GET FIRST VALUE
GETA1:  SHLD  UIPRT  ;SAVE IT
  CALL  SCHR  ;ANY MORE?
  RZ  .  ;RETURN IF NOT
  LDAX  D  ;GET NEXT CHAR
  CPI  ','  ;SEE IF MEANS BYTE MODE
  PUSH  PSW  ;SAVE ZERO FLAG
  JNZ  GET1  ;IF "," WE BUMP DE
  INX  D
GET1:  CALL  SHEX  ;NOW CONVERT VALUE
  POP  PSW  ;GET FLAG BACK
  RNZ  .  ;IF NOT BYTE MODE, RET
  PUSH  D  ;SAVE DE FOR MORE
  XCHG  .  ;PUT HL IN DE
  LHLD  UIPRT  ;GET 1ST VALUE
  DAD  D  ;ADD THE BYTE TO IT
  POP  D  ;GET DE BACK
  ORA  A  ;RESET ZERO FLAG
  RET  .
;
;  ***** MOVE MEMORY COMMAND *****
;
;  SYNTAX:
;  MMEM <p1>,<p2> <p3>   ; From <p1>, <p2> bytes are
;                                moved to <p3>
;  MMEM <p1> <p2> <p3>   ; The segment from <p1> to <p2>
;                                is moved to <p3>
;
;  Notes:  Moves may overlap in any order.  Multiple
;  moves of the same block (for ROM programming) may be
;  done by first seting the move count with SET C=<value>.
;
MOVE  EQU  $
  LDA  MOVCNT  ;GET # OF MOVES
  STA  MOVLFT  ;STORE IN MOVES LEFT
;
MOVAGN  PUSH D  ;SAVE DE FOR REPEAT MOVES
  CALL  GETPAR  ;GET THE PARAMETERS
  CALL  MOVE3  ;SUBTRACT P1 FROM P2
;
; B HAS # BYTES, D HAS FROM ADR, H HAS TO ADR
;
MOVE2:  JNC  MOVE4  ;MOVE UP
  LDAX  D
  MOV  M,A
  DCX  B
  INX  H
  INX  D
  MOV  A,C  ;DONE?
  ORA  B
  JNZ  MOVE2+3
  JMP  MOVE6
;
MOVE3:  PUSH  B  ;SAVE P1
  PUSH  D  ;SAVE COMMAND POINTER
  CALL  CMB  ;COMPLEMENT B
  INX  B  ; + 1
  DAD  B  ;P2 - P1 + 1
  POP  D  ;RESTORE COMMAND POINTER
  POP  B  ;GET P1
  PUSH  H  ;SAVE P2 - P1 + 1
  PUSH  B  ;SAVE P1
  CALL  SCONV  ;GET P3
  POP  D
  CALL  CDEHL
  POP  B
  RET  .
;
MOVE4:  DCX  B  ;ADD BC - 1 TO DE AND HL
  DAD  B
  PUSH  H
  PUSH  D  ;MOVE DE TO HL
  POP  H
  DAD  B
  PUSH  H
  POP  D
  POP  H
  INX  B  ;RESTORE B
;
MOVE5:  LDAX  D
  MOV  M,A
  DCX  B
  DCX  H
  DCX  D
  MOV  A,C  ;DONE?
  ORA  B
  JNZ  MOVE5
;
MOVE6:  LDA  MOVLFT  ;MULTIPLE MOVES?
  ORA  A
  JZ  COMND
  DCR  A
  STA  MOVLFT
  POP  D
  JMP MOVAGN
;
GETPAR  CALL GETADR  ;GET P1,P2
  JZ  ERR1  ;NO 2ND PARAMETER
  PUSH  D  ;SAVE POINTER
  XCHG  .  ;MOVE HL TO DE
  LHLD  UIPRT  ;GET P1
  PUSH  H
  POP  B  ;PUT IT IN BC
  XCHG  .  ;GET HL BACK
  POP  D  ;GET DE BACK
  RET  .
;
CMB  MOV  A,B  ;COMPLEMENT B (P1)
  CMA
  MOV  B,A
  MOV  A,C
  CMA
  MOV  C,A
  INX  B
  RET  .
;
;  ***** ZIP  COMMAND *****
;
;  SYNTAX:                         |Byte |From | To
;                                  |value|addr |addr
;                                  |-----|-----|-----
;  ZIP                             |  0  |  0  |SOLOS
;  ZIP <byte>                      |byte |  0  |SOLOS
;  ZIP <byte>  <add1>              |byte |  0  |addr1
;  ZIP <byte>  <add1>  <add2>      |byte |addr1|addr2
;  ZIP <byte>  <add1>,<byte-count> |byte |addr1|#bytes
;
ZIP  EQU  $
  DCX  H
  PUSH  H  ;SAVE SOLOS ADDRESS - 1
  CALL SBLK  ;LOOK FOR PARM
  MVI  A,0
  JZ  ZIP1  ;NONE
  CALL SHEX
  MOV  A,L
;
ZIP1:  POP  H  ;GET ADD1 DEFAULT
  PUSH  PSW  ;SAVE BYTE
  CALL  PSCAN  ;ADD1 IN HL
  PUSH  H
  CALL  GETA1  ;LOOK FOR LAST PARM
  JZ  ZIP2  ;NO ADD2
  POP  D  ;LOW LIM IN DE, UP LIM IN HL
  JMP  ZIP3
;
ZIP2:  LXI D,0  ;DEFAULT LOWER LIMIT
  POP  H  ;0 IN DE, UP LIM IN HL
ZIP3:  POP B  ;BYTE TO B
  XCHG  .  ;LOW LIM IN HL, UP LIM IN DE
;
ZIP4  EQU  $
  MOV  M,B  ;STORE BYTE
  CALL  CDEHL
  INX  H
  RNC  .  ;DONE
  JMP  ZIP4
;
;  ***** SEARCH MEMORY COMMAND *****
;
;  SYNTAX:
;  SMEM <low-adr>  <high-adr>  <sring>
;       <low-adr>,<byte-count> <string>
;       Up to 16 ASCII characters enclosed by "   "s.
;       Up to 16 hex values terminated by C/R.
;       A wild card "*" is permitted in hex string.
;       The wild card will match any byte.
;       Ex:SM C000,7FF  CD * C0 <CR>
;
SERCH  EQU  $
  CALL  GETADR  ;GET P1 & P2
  JZ  ERR1  ;NO P2
  PUSH  H
  CALL  SBLK  ;GET STRING
  JZ  ERR1  ;NO STRING
;
SRCH1  LDAX  D  ;GET 1ST CHAR
  CPI  22H  ;'"' FOR ASCII
  PUSH  PSW
;
  LXI  H,AUXBU  ;AUX BUFFER
  MVI  B,16  ;16 CHARACTERS
SRCH2 MVI  M,0  ;ZERO BUFFER
  INX  H
  DCR  B
  JNZ  SRCH2  ;LOOP TILL DONE
;
  LXI  H,DHEAD  ;SEARCH BUFFER
  MVI  B,17  ;16 MAX VALUES
  POP  PSW
  JZ  SRCH6  ;ASCII SEARCH
;
SRCH3  EQU  $  ;HEX SEARCH
  CALL  SCHR  ;GET VALUE
  JZ  SRCH7  ;IF EOL GO SEARCH
  PUSH  H  ;CONVERT
  CPI  '*'  ;IS IT A WILD CARD?
  JNZ  SRCH4  ;NO, GO CONVERT IT
  PUSH  D
  LXI  D,16
  DAD  D  ;POINT TO AUX BUFFER
  MVI  M,'*'  ;MOVE IN WILD CARD FLAG
  POP  D
  INX  D
  JMP  SRCH5
*
SRCH4 CALL  SHEX  ;CONVERT VALUE
  MOV  A,L  ;SAVE IN A
SRCH5 POP  H  ;GET POINTER BACK
  DCR  B  ;BUMP COUNT
  JZ  ERR1  ;TOO MANY
  MOV  M,A  ;PUT IN BUFFER
  INX  H  ;GET READY FOR NEXT
  JMP  SRCH3  ;GO GET IT
;
SRCH6  EQU  $  ;COUNT STRING LEN
  INX  D  ;BUMP PAST '"'
  LDAX  D
  CPI  22H  ;AT SECOND '"'?
  JZ  SRCH7  ;GO SEARCH
  DCR  B
  JZ  ERR1  ;TOO MANY
  MOV  M,A
  INX  H
  JMP  SRCH6
;
SRCH7  EQU  $
  POP  D  ;END ADDRESS
  LHLD  UIPRT  ;START ADDRESS
  MOV  A,B  ;CALCULATE STRING LENGTH
  CMA
  ADI  18  ;#  CHARACTERS
  MOV  B,A
  ORA  A
  RZ  .  ;ZERO LEN STRING
  MVI  C,1  ;GIVE CR/LF AT START
;
SRCH8  EQU  $
  PUSH  D  ;SAVE REGISTERS
  PUSH  B
  PUSH  H
  LXI  D,DHEAD  ;POINT TO BUFFER
  CALL  COMPS  ;COMPARE STRINGS
  POP  H  ;GET MEMORY ADDR
  JNZ  NADDR  ;NZ MEANS NO MATCH
  POP  B  ;GET ADDRS PER LINE
  DCR  C  ;DECREASE IT
  PUSH  B  ;SAVE IT
  JNZ  SRCH9
  CALL  CRLF  ;IF EOL GIVE CR/LF
  POP  B  ;RESET COUNT
  MVI  C,8  ;ADDRS PER LINE
  PUSH  B
SRCH9:  CALL  ADOUT  ;OUT ADDR IF MATCH
NADDR:  POP  B  ;RESTORE REGS
  POP  D
  CALL  CDEHL  ;SEE IF END OF SRARCH
  RNC  .  ;DONE
  INX  H  ;NEXT ADDR TO LOOK AT
  JMP  SRCH8  ;SEARCH AGAIN
;
COMPS  PUSH  D  ;COMPARE STRINGS
  MOV  A,E
  ADI  16  ;POINT TO AUX BUFFER
  MOV  E,A
  LDAX  D  ;GET THE FLAG
  CPI  '*'  ;WILD CARD?
  POP  D  ;POINT TO BUFFER
  JZ  CMPS1  ;IF "*" BYPASS COMPARE
  LDAX  D  ;GET CHAR FROM BUFFER
  CMP  M  ;COMPARE WITH MEMORY
  RNZ  .  ;RETURN IF NO MATCH
;
CMPS1:  DCR  B  ;CHECK IF END
  RZ  .
  INX  H  ;BUMP POINTERS
  INX  D
  JMP  COMPS
;
;  ***** COMPARE MEMORY COMMAND *****
;
;  SYNTAX:
;  CMEM <p1>,<p2> <p3>  ;From <p1>, <p2> bytes are
;                            compared starting at <p3>
;  CMEM <p1> <p2> <p3>  ;The segment from <p1> to <p2> is
;                            is compared to <p3>
;
COMPM  EQU  $
  CALL  GETPAR  ;GET PARAMETERS
  CALL  MOVE3  ;SUBTRACT P1 FROM P2
;
; B HAS # BYTES, D HAS FROM ADD, H HAS TO ADD
;
COMP2:  LDAX  D
  CMP  M
  JZ  COMP3
  PUSH  B
  PUSH  D
  PUSH  H
  PUSH  D
  CALL  CRLF
  POP  H
  CALL  ADOUT
  MOV  A,M
  CALL  HBOUT
  CALL  BOUT
  POP  H
  MOV  A,M
  CALL  HBOUT
  CALL  ADOUT
  POP  D
  POP  B
*
COMP3:  DCX  B
  MOV  A,C
  ORA  B
  JZ  COMND
  INX  D
  INX  H
  JMP  COMP2
;
;  ***** EXAMINE/DEPOSIT *****
;
;  SYNTAX:  ED <addr>
;  <addr> Is displayed with its contents.
;  The keyboard is read and if a 1 or 2 digit hex number
;  is input, that value will replace the current contents.
;  If a CR, space, slash, colon or a hex number larger than FF
;  is input, the current contents are unchanged.
;  The next memory location is then examined.
;  If a LF is typed the previous location is examined.
;  Escape or an error terminates the command.
;
EXDEP:  EQU  $
  CALL  SCONV  ;GET START ADDRESS
EXDP1:  CALL CRLF
  CALL  ADOUT  ;DISPLAY HL
  MOV  A,M
  CALL  HBOUT  ;DISPLAY (HL)
  PUSH  H
  CALL  GCLIN  ;GET INPUT LINE
  CALL  CREM  ;REMOVE CURSOR
  MVI  C,8
  CALL  VDAD2  ;GET SCREEN ADDRESS
  XCHG  .  ;TO DE
  LXI  H,8000H
  CALL  SHE1  ;CONVERT VALUE
  MOV  A,H
  ORA  A
  JNZ  NOCHG  ;INVALID OR NO INPUT
  MOV  A,L  ;GET VALUE
  POP  H
  MOV  M,A  ;DEPOSIT IT
  CMP  M  ;TEST MEMORY
  JNZ  ERR1  ;BAD MEMORY OR ROM
;
EXDP2:  IN  KDATA  ;SEE IF WE BACK UP
  CPI  LF  ;LF SAYS YES
  JNZ  EXDP3
  DCX  H
  DCX  H
EXDP3:  INX  H  ;NEXT
  JMP  EXDP1
;
NOCHG:  POP  H
  JMP  EXDP2
;
;  ***** HEX MATH COMMAND *****
;
;  Syntax:  HM  <value1> <value2>
;           HM  <hex value>
;
;  V2 is added to V1 then subtracted from V1.
;  Overflow or underflow is ignored.
;  If only one value is input, the decimal
;  equivalent is printed out.
;
HMATH:  CALL  GETADR  ;GET THE ARGUMENTS
  JZ  HMDC  ;No 2nd, convert to decimal
  PUSH  H
  LXI  H,HMMSG  ;PUT OUT THE FORMAT
  CALL  MEMT9
  POP  B  ;GET V2 TO BC
  LHLD  UIPRT  ;GET V1 TO HL
  PUSH  H
  PUSH  B
  DAD  B
  CALL  ADOUT
  POP  B
  POP  H
  CALL  CMB  ;COMPLEMENT B
  DAD  B  ;ADD BC HL
  MVI  B,'-'
  CALL  SOUT
  JMP  ADOUT
;
HMDC  LXI D,AUXBU  ;Buffer for decimal value
  MVI  A,' '  ;Load in format string
  STAX  D
  INX  D
  MVI  A,'='
  STAX  D
  INX  D
  MVI  A,' '
  STAX  D
  INX D
  XRA  A
  LXI  B,-10000  ;Now convert to decimal
  CALL  HMDIV
  LXI  B,-1000
  CALL  HMDIV
  LXI  B,-100
  CALL  HMDIV
  LXI  B,-10
  CALL  HMDIV
  LXI  B,-1
  CALL  HMDIV
  JNZ  HMOUT
  MVI  A,'0'  ;Default gets a zero
  STAX  D
  INX  D
  JMP  HMOUT
;
HMDIV  PUSH  D
  MVI  D,-1
HMD1  SHLD  UIPRT
  INR  D  ;D is decimal counter
  DAD  B  ;B holds divisor
  JC  HMD1
  LHLD  UIPRT  ;HL has hex value
  MOV  B,D
  POP  D
  ORA  B
  RZ  .  ;Supress leading zeros
  MVI  A,'0'  ;Base number value
  ADD  B  ;Add offset to it
  STAX  D  ;Store it in buffer
  INX  D
  RET
;
HMOUT  XRA  A  ;Mark end of string
  STAX  D
  LXI  H,AUXBU  ;Now print buffer
  JMP  MEMT9
;
HMMSG:  ASCZ  '  =  +'
;
;  ***** MEMORY TEST ROUTINE *****
;
;  Syntax:  TMEM
;           TMEM  <addr1>,<byte-count>
;           TMEM  <addr1>,<addr2>
;
;  TM will test all available memory up to the
;  first empty or ROM byte.  The message:
;  HI-MEM: <addr>  is printed to indicate the
;  first error address.  The test is non
;  destructive.
;
MEMT:  CALL  SBLK  ;LOOK FOR ARGS
  JNZ  MEMT4  ;WE FOUND SOME
  PUSH  PSW
;
MEMT1:  CALL  CRLF  ;NO ARGS
  POP  PSW
  LXI  H,0  START SIZING MEMORY FROM 0000H
  MVI  A,0AAH  ;THE TEST BYTE

MEMT2:  CALL  TLOOP
  JZ  MEMT2
  CMA  .  ;FLIP TEST BYTE
  PUSH  PSW  ;SAVE IT
;
  DCX  H
  DCX  H  ;THIS SETS HL TO HI MEM
  PUSH  H
  LXI  H,MSG2
  CALL  MEMT9  ;PUT OUT HI MEM ADDR
  POP  H
  CALL  ADOUT
  JMP  MEMT1  ;OVER & OVER
;
MEMT4:  CALL  SHEX  ;CONVERT 1ST ADDR
  PUSH  H  ;SAVE IT
  CALL  GETA1  ;GET 2ND
  INX  H
  POP  D
  XCHG  .
  CALL  CRLF
  MVI  A,0AAH  ;THE TEST BYTE
  PUSH  D  ;SAVE POINTERS
  PUSH  H
;
MEMT5:  POP  H  ;RESTORE  POINTERS
  POP  D
  PUSH  D  ;SAVE AGAIN
  PUSH  H
;
MEMT6:  CALL  TLOOP
  CMA  .  ;FLIP TEST BYTE
  PUSH  PSW
  CNZ  MEMT7  ;UH OH, ERROR!
  CALL  KSTAT
  CPI  ESC
  JZ  COMND
  POP  PSW
  MOV  C,A
  CALL  CDEHL
  MOV  A,C
  JC  MEMT6
  LXI  H,MSG3
  CALL  MEMT9
  MOV  A,C
  JMP  MEMT5
;
MEMT7:  PUSH  PSW
  DCX  H
  CALL  ADOUT
  CALL  BOUT
  POP  PSW
  CALL  HBOUT
  MOV  A,M
  CALL  HBOUT
  CALL  CRLF
  INX  H
  RET  .
;
TLOOP:  MOV  C,M  ;GET MEMORY CONTENTS
  MOV  M,A  ;MOVE IN TEST BYTE
  CMP  M  ;SAME?  IF NOT, ROM OR NO MEMORY
  MOV  M,C  ;REPLACE CONTENTS
  INX  H  ;BUMP POINTER
  RET  .
;
MEMT9:  XRA  A
  MOV  B,M
  ORA  B
  RZ  .
  CALL  SOUT
  INX  H
  JMP  MEMT9
;
MSG2:  ASCZ  '  HI MEMORY: '
MSG3:  ASC  'PASS COMPLETE'
  DB  0DH,0AH,0
;
ENDMARK  EQU  $  ;SHOW END OF ROM CODE
;
