;
;  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
;
  IF  START-0F000H
  MVI  B,'>'  ;*** '>' FOR C000
  ENDF
;
  IF  START-0C000H
  MVI  B,']'  ;*** ']' FOR F000
  ENDF
;
  JMP  SOUT  ;PUT IT ON THE SCREEN
;
CRLF:  MVI  B,LF  ;LINEFEED
  CALL  SOUT
  MVI  B,CR  ;CARRIAGE RETURN
  JMP  SOUT
;
;  THE CTRL/P PRINT TOGGLE TURNS PRINTER
;  OUTPUT ON/OFF.  IT HAS IMMEDIATE EFFECT
;  EVEN WHILE THE VIDEO IS SCROLLING.
;
;  THE HEX/ASCII TOGGLE (MODE) IS AVAILABLE WITH
;  THE DUMP COMMAND.  TYPING MODE DURING A DUMP
;  WILL FLIP DISPLAY FORMAT.  TYPING MODE AFTER
;  A SPACE BAR HALT WILL BACK UP THE DUMP ADDRESS
;  (MAX 16 LINES) AND START OVER IN OPPOSITE FORMAT.
;
PRINT:  CPI  80H  ;IS IT MODE?
  JNZ  PRIN5
  PUSH  B  ;SAVE ALL REGISTERS
  PUSH  D
  PUSH  H
  LXI  H,VDMEM+4  ;POINT TO COL. 4 ON SCREEN
  LXI  D,64  ;LINE MODULUS
  LXI  B,1000H  ;COUNTER
  MVI  A,':'  ;THE DUMP DISCRIPTOR
PRIN1:  CMP  M  ;SEE IF DUMP ON SCREEN
  JNZ  PRIN2  ;NONE THIS LINE
  INR  C  ;FOUND ONE, BUMP COUNT
PRIN2:  DAD  D  ;POINT TO NEXT LINE
  DCR  B  ;SUBTRACT LINE COUNT
  JNZ  PRIN1  ;CHECK NEXT
  INR  C  ;MAKE SURE C NON ZERO
  LXI  D,0FFF0H  ;TWO'S COMP. 16
  LHLD  UIPRT  ;GET CURRENT DUMP ADDR
PRIN3:  DCR  C
  JZ  PRIN4
  DAD  D  ;SUBTRACT 16 BYTES PER LINE
  JMP  PRIN3
PRIN4:  SHLD  UIPRT  ;STORE RESULT
  POP  H  ;RESTORE REGISTERS
  POP  D
  POP  B
  LDA  PRTOG  ;GET PRINT TOGGLE BYTE
  ADI  80H  ;FLIP HEX/ASC BIT
  JMP  PRIN6
;
PRIN5:  CPI  'P'-40H  ;IS IT THE CONTROL-P?
  RNZ  .  ;GO BACK IF NOT
  LDA  FLGBYT  ;GET MODE BYTE
  ANI  PRTFLG  ;IS CTRL/P ENABLED?
  MVI  A,'P'-40H
  RNZ  .  ;NZ SAYS NO
  LDA  PRTOG  ;GET PRINT TOGGLE BYTE
  ADI  1
  ANI  81H  ;MAKE IT 1 OR 0
PRIN6:  STA  PRTOG
  JMP  SINP  ;GO BACK TO INPUT
;
; 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:  MVI  B,' '
  PUSH  B
  MOV  A,H  ;H FIRST
  CALL  HEOUT
  MOV  A,L  ;THEN L FOLLOWED BY A SPACE
  CALL  HEOUT
  POP  B
  JMP  SOUT
;
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  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 *****
;
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:  CALL  SCHR  ;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 *****
;
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,40H
  DAD  D  ;MOVE DOWN ONE LINE
  MOV  A,H
  CPI  <VDMEM+400H  ;WRAP?
  JNZ  ERR3  ;NO
  MVI  H,<VDMEM
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 INPUT DRIVER
;
SETIN:  EQU  $
  STA  IPORT
  RET  .
;
; SET OUTPUT DRIVER
;
SETOT:  EQU  $
  STA  OPORT
  RET  .
;
; SET THE MODE (STATUS) BYTE
;
SETMD:  EQU  $
  STA  FLGBYT
  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>
;
;  Note:  Hex/Ascii toggle (MODE key) is available
;  with DUMP.  Default is Hex.  Typing MODE after
;  space bar halt will back up dump address up to
;  16 lines.  MODE during scroll only flips format.
;
DUMP:  CALL  GETADR
  PUSH  H  ;SAVE THE VALUE
  POP  D  ;GET END
  LHLD  UIPRT  ;HL HAS START, DE HAS END
;
DLOOP:  SHLD  UIPRT  ;SAVE FOR HEX/ASC TOGGLE
  CALL  CRLF  ;GET READY FOR NEW LINE
  LHLD  UIPRT  ;GET LINE ADDRESS
  MVI  B,':'  ;MOVE IN THE DUMP DISCRIPTOR
  CALL  ADOUT+2  ;OUTPUT ADDRESS
  CALL  BOUT
  CALL  BOUT  ;TWO SPACES TO KEEP IT PRETTY
  MVI  C,16  ;VALUES PER LINE
  LDA  PRTOG  ;GET HEX/ASC FLAG
  RLC
  JC  PRASC  ;C MEANS ASCII DUMP
;
PRHEX:  MOV  A,M  ;GET THE CHAR
  PUSH  B  ;SAVE COUNT
  CALL  HBOUT
  POP  B
  CALL  PRSPC  ;CHECK FOR END
  JNZ  PRHEX  ;NOT ZERO IF MORE FOR THIS LINE
  JMP  DLOOP  ;DO A LF/CR BEFORE THE NEXT
;
PRASC:  MOV  A,M  ;GET THE CHAR
  RLC  .  ;SHIFT HIGH BIT LEFT
PRAS1:  MVI  B,' '  ;SET UP TO PRINT SPACE
  JNC  PRAS2  ;NO HIGH BIT
  MOV  A,M  ;GET CHAR BACK
  CPI  0FFH  ;NO DELETES!
  JZ  PRAS1
  CPI  0DFH  ;NO BACKSPACES EITHER
  JZ  PRAS1
  CPI  0A0H  ;THIS FILTERS CTRL CHARS
  CMC
  JNC  PRAS1
  MVI  B,'-'  ;SAY HIGH BIT SET
PRAS2:  CALL  SOUT  ;SEND IT OUT
  MOV  A,M  ;GET 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  BOUT  ;NOW A SPACE
  CALL  PRSPC  ;CHECK FOR END
  JNZ  PRASC
  JMP  DLOOP  3DO NEXT LINE
;
PRSPC:  CALL  CDEHL  ;COMPARE DE HL
  JNC  COMND  ;ALL DONE
  INX  H
  DCR  C  ;BUMP THE LINE 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
  JNC  COMND  ;DONE
  JMP  ZIP4
;
;  ***** SEARCH MEMORY COMMAND *****
;
;  SYNTAX:
;  SMEM <low-adr>  <high-adr>  <string>
;       <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
  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
  JZ  COMND  ;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
  JNC  COMND  ;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.
;  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:  INX  H  ;NEXT
  JMP  EXDP1
;
NOCHG:  POP  H
  JMP  EXDP2
;
;  ***** HEX MATH COMMAND *****
;
;  Syntax:  HMATH  <value1> <value2>
;  V2 is added to V1 then subtracted from V1.
;  Overflow or underflow is ignored.
;
HMATH:  CALL  GETADR  ;GET THE ARGUMENTS
  JZ  ERR1  ;NO SECOND ARGUMENT
  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
;
HMMSG:  ASCZ  '  =  +'
;
;  ***** MEMORY TEST ROUTINE *****
;
;  Syntax:  TMEM
;           TMEM <addr1>,<byte-count>
;           TMEM <addr1> <addr2>
;
;  TM with no arguments will test all available
;  memory. TMEM addr1 addr2 tests between addresses.
;  TMEM addr1,byte-count tests # of bytes from addr1.
;  After 4 passes a "COMPLETE" message is output.
;
MEMT:  CALL SBLK  ;LOOK FOR PARM
  JNZ  MEMT7  ;WE FOUND SOME
;
  LXI  H,0  START SIZING MEMORY FROM 0000H
  MVI  A,0AAH  ;TEST BYTE
MEMT0:  MVI  M,0AAH  ;MOVE IN TEST BYTE
  CMP  M  ;SAME?  IF NOT, ROM OR NO MEMORY
  INX  H  ;BUMP POINTER
  JZ  MEMT0
;
  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
  LXI  D,0  ;SET START TO ZERO
;
MEMT1:  XCHG  .  HL HAS START DE HAS END
  CALL  CRLF
;
MEMT2:  PUSH  PSW  ;SET UP TEST PATTERN
  POP  PSW
  INR  A
  ANI  3
  PUSH  PSW
  MOV  B,A
  MVI  C,4
  XRA  A
;
MEMT3:  RAL .  ;Rotate bits
  RAL  .  ;to form pattern
  ORA  B
  DCR  C
  JNZ  MEMT3
  MOV  C,A  ;00,55,AA,FF
  PUSH  H
  CALL  MEMT4
  MOV  A,C
  CPI  0FFH
  CZ  MEMT8  ;Put out "COMPLETE"
  CALL SINP
  CPI  1BH  ;ESCAPE ABORT
  JZ  COMND
  POP  H  ;GET START BACK
  JMP  MEMT2+1
;
MEMT4:  MOV  M,C  ;PASS LOOP
  MOV  A,M
  CMP  C
  CNZ  MEMT6
  CALL  CDEHL
  INX  H
  RNC  .
  JMP  MEMT4
;
MEMT5:  EQU  $
MEMT6:  PUSH B
  CALL  ADOUT  ;PUT OUT ERROR ADDRESS
  CALL  BOUT
  POP  B
  PUSH  B
  MOV  A,C
  CALL  HBOUT  ;NOW THE TEST BYTE
  MOV  A,M
  CALL  HBOUT  ;NOW ERROR BYTE
  CALL  CRLF
  POP  B
  RET  .
;
MEMT7:  CALL  SHEX  ;CONVERT 1ST ADDR
  PUSH  H
  CALL  GETA1  ;GET 2ND ADDR
  POP  D
  JMP  MEMT1
;
MEMT8:  LXI  H,MSG  ;COMPLETE
MEMT9:  XRA  A
  MOV  B,M
  ORA  B
  RZ  .
  CALL  SOUT
  INX  H
  JMP  MEMT9
;
MSG:  ASC  '  COMPLETE'
  DB  0AH,0DH,0
;
MSG2:  ASCZ  '  HI MEM: '
;
ENDMARK  EQU  $  ;SHOW END OF ROM CODE
;

