home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / old / misc / cpmtools / mload.asm < prev    next >
Assembly Source File  |  2020-01-01  |  35KB  |  1,453 lines

  1.     TITLE    'MLOAD MULTI-FILE HEX LOAD UTILITY'
  2. ;
  3. ;         *********************************
  4. ;        *          MLOAD.ASM        *
  5. ;        *   MULTI-FILE HEX LOAD UTILITY *
  6. ;        *          FOR CP/M        *
  7. ;        *********************************
  8. ;
  9. ;
  10. ;    REPLACEMENT FOR THE CP/M "LOAD" PROGRAM: THIS PROGRAM
  11. ;    FIXES MANY OF THE PROBLEMS ASSOCIATED WITH THE "CP/M"
  12. ;    LOAD PROGRAM, AND ADDS MANY NEW FEATURES.
  13. ;
  14. ; ----------------
  15. ;
  16. ;    REV 2.1
  17. ;    03/08/84
  18. ;    WRITTEN BY RON FOWLER, FORT ATKINSON, WI
  19. ;
  20. ; ----------------
  21. ;
  22. ; MODIFICATION HISTORY:
  23. ;
  24. ; 2.1   (RGF)   FIXED PROBLEM ON DISK-FULL WHEN WRITING OUTPUT FILE
  25. ;        (MLOAD PREVIOUSLY DIDN'T ERROR OUT ON A FULL DISK)
  26. ; 2.0   (RGF)   ADDED THE ABILITY TO PRE-LOAD A NON-HEX FILE, ALLOWING
  27. ;        MLOAD TO BE USED TO LOAD HEX FILE PATCHES (OBVIATING ANY
  28. ;        NEED TO USE DDT).  THE NORMAL MLOAD SYNTAX IS PRESERVED.
  29. ;        THE FIRST (AND ONLY THE FIRST) FILESPEC (AFTER THE "=",
  30. ;        IF USED) MAY BE NON-HEX; THE FILETYPE MUST BE SPECIFIED.
  31. ;        EXAMPLES:
  32. ;
  33. ;            1)    MLOAD WS.COM,WSPATCH
  34. ;            2)    MLOAD MDM7TEST=MDM720.COM,MDM7US
  35. ;            3)    MLOAD WS.OVR,OVRPATCH
  36. ;
  37. ;        THE FIRST EXAMPLE LOADS WS.COM, OVERLAYS IT WITH
  38. ;        WSPATCH.HEX, AND WRITES THE OUTPUT TO WS.COM.  THE
  39. ;        SECOND EXAMPLE LOADS MDM720.COM, OVERLAYS IT WITH
  40. ;        MDM7US.HEX, AND WRITES THE OUTPUT FILE TO MDM7TEST.COM.
  41. ;        (NOTE THAT THE SECOND EXAMPLE IS THE RECOMMENDED TECHNIQUE,
  42. ;        SINCE IT PRESERVES THE ORIGINAL FILE). THE THIRD EXAMPLE
  43. ;        LOADS WS.OVR AND PATCHES IT WITH THE FILE "OVRPATCH.HEX".
  44. ;
  45. ;        ALSO ADDED THIS REV: ZCPR2-STYLE DU SPECS ARE NOW FULLY
  46. ;        SUPPORTED, FOR BOTH INPUT AND OUTPUT FILES.  THUS, THE
  47. ;        FOLLOWING COMMAND LINES ARE PERMISSABLE:
  48. ;
  49. ;            B3>MLOAD A4:MYFILE.COM=0:BIGFIL,B6:PATCH1,C9:PATCH2
  50. ;            A6>MLOAD B5:=C3:MDM717.COM,MDMPATCH
  51. ;
  52. ;        AFTER LOADING, AN ADDITIONAL INFORMATION LINE IS NOW PRINTED
  53. ;        IN THE STATISTICS REPORT, WHICH DISPLAYS THE TRUE SIZE OF THE
  54. ;        SAVED IMAGE (THE PREVIOUS REPORT WAS TECHNICALLY CORRECT, BUT
  55. ;        COULD RESULT IN CONFUSION FOR CERTAIN KINDS OF FILES WITH
  56. ;        IMBEDDED "DS" AND "ORG" STATEMENTS IN THE ORIGINAL SOURCE CODE).
  57. ;        
  58. ; 1.0 - 1.4    (RGF) CHANGE LOG REMOVED TO CONSERVE SPACE
  59. ;
  60. ;    ORIGINALLY WRITTEN BY RON FOWLER, FORT ATKINSON, WISCONSIN
  61. ;
  62. ;
  63. ;
  64. ; FOR ASSEMBLY WITH ASM.COM OR MAC (DELETE ABOVE TITLE LINE IF
  65. ; ASSEMBLING WITH ASM.COM)
  66. ;
  67. ; THIS PROGRAM IS A REPLACEMENT FOR THE CP/M "LOAD" PROGRAM.
  68. ; WHY REPLACE "LOAD"?  WELL... LOAD.COM HAS A FEW DEFICIENCIES.
  69. ; FOR EXAMPLE, IF YOUR HEX FILE'S ORIGIN IS ABOVE 100H, LOAD.COM
  70. ; PREPENDS BLANK SPACE TO THE OUTPUT FILE TO INSURE IT WILL WORK
  71. ; AS A CP/M TRANSIENT.  IT CARES NOT IF THE FILE IS NOT INTENDED
  72. ; AS A CP/M TRANSIENT.  IT ALSO DOESN'T LIKE HEX RECORDS WITH MIXED
  73. ; LOAD ADDRESSES  (FOR EXAMPLE, ONE THAT LOADS BELOW A PREVIOUS RECORD --
  74. ; WHICH IS A PERFECTLY LEGITIMATE HAPPENSTANCE).  ALSO, LOAD.COM
  75. ; CAN LOAD ONLY ONE PROGRAM AT A TIME, AND HAS NO PROVISION FOR
  76. ; A LOAD BIAS IN THE COMMAND SPECIFICATION. FINALLY, THERE IS NO
  77. ; PROVISION FOR USER SPECIFICATION OF OUTPUT FILE NAME.
  78. ;
  79. ;
  80. ; HENCE, THIS PROGRAM....
  81. ;
  82. ;------------------------------------------------------------
  83. ;
  84. ; SYNTAX IS AS FOLLOWS:
  85. ;
  86. ;    MLOAD [<OUTNAM=] <FILENAME>[,<FILENAME>...] [BIAS]
  87. ;
  88. ; WHERE <OUTNAM IS THE (OPTIONAL!;) OUTPUT FILE NAME (ONLY THE DRIVE
  89. ; SPEC AND PRIMARY FILENAME MAY BE SPECIFIED; THE OUTPUT FILETYPE IS
  90. ; DERIVED EXCLUSIVELY FROM THE 3-BYTE STRING AT 103H WITHIN MLOAD),
  91. ; <FILENAME> SPECIFIES FILES TO LOAD AND <BIAS> IS THE OFFSET WITHIN
  92. ; THE SAVED IMAGE TO APPLY WHEN LOADING THE FILE.
  93. ;
  94. ; MLOAD WITH NO ARGUMENTS PRINTS A SMALL HELP MESSAGE -- THIS MESSAGE
  95. ; IS ALSO PRINTED WHENEVER A COMMAND LINE SYNTAX ERROR OCCURS.
  96. ;
  97. ; FILENAMES MAY CONTAIN DRIVE SPECS, AND MUST NOT CONTAIN WILDCARDS.
  98. ; INPUT FILENAMES MUST BE SEPARATED BY COMMAS, AND A SPACE IS REQUIRED
  99. ; BETWEEN THE LAST FILENAME AND THE OPTIONAL BIAS.
  100. ;
  101. ; A LOAD INFORMATION SUMMARY IS PRINTED AT THE SUCCESSFUL CONCLUSION
  102. ; OF THE LOAD.  ANY ERRORS IN LOADING WILL GENERALLY INCLUDE THE NAME
  103. ; OF THE FILE IN QUESTION.
  104. ;
  105. ; IF NO OUTPUT FILENAME IS SPECIFIED, IT WILL BE DERIVED FROM THE FIRST
  106. ; INPUT FILENAME, WITH FILETYPE OF 'COM', IF NOT OTHERWISE SPECIFIED
  107. ; (THIS DEFAULT FILETYPE MAY BE PATCHED DIRECTLY INTO MLOAD VIA DDT
  108. ; -- ITS LOCATION IS AT 103H IN MLOAD.COM). NOTE THAT A COMMAND LINE OF
  109. ; THE FORM "C:=<FILENAME>" WILL PLACE THE OUTPUT FILE ON THE "C" DRIVE
  110. ; WITH THE SAME PRIMARY FILENAME AS THE INPUT FILE.
  111. ;
  112. ; IN ITS SIMPLEST FORM, MLOAD'S SYNTAX IS IDENTICAL TO LOAD.COM; THUS
  113. ; THERE SHOULD BE NO PROBLEM IN LEARNING TO USE THE NEW PROGRAM.  THE
  114. ; ONLY SIGNIFICANT DIFFERENCE HERE IS THAT, UNDER LOAD.COM, ALL FILES
  115. ; ARE OUTPUT STARTING AT 100H, EVEN IF THEY ORIGINATE ELSEWHERE.  MLOAD
  116. ; OUTPUTS STARTING AT THE HEX FILE ORIGIN (ACTUALLY, THE FIRST HEXT REC-
  117. ; ORD SPECIFIES THE OUTPUT LOAD ADDRESS).  THE BIAS OPTION MAY BE USED
  118. ; TO OVERRIDE THIS.
  119. ;
  120. ; AN EXAMPLE SHOULD CLARIFY THIS.  SUPPOSE YOU HAVE A FILE THAT LOADS
  121. ; AT 1000H.  LOAD.COM WOULD SAVE AN OUTPUT FILE THAT BEGINS AT 100H AND
  122. ; LOADS PAST 1000H (TO WHEREVER THE PROGRAM ENDS).  MLOAD WILL SAVE AN
  123. ; OUTPUT FILE STARTING FROM 1000H ONLY.  IF, FOR SOME REASON YOU NEED THE
  124. ; FILE TO START AT 100H IN SPITE OF ITS 1000H ORIGIN (I CAN THINK OF SEV-
  125. ; ERAL CIRCUMSTANCES WHERE THIS WOULD BE NECESSARY), YOU'D HAVE TO SPECIFY
  126. ; A BIAS TO MLOAD.  THUS, USING THIS EXAMPLE, "MLOAD MYFILE 0F00" WOULD DO.
  127. ;
  128. ; NOTE THAT THIS PROGRAM RE-INITIALIZES ITSELF EACH TIME IT IS RUN.
  129. ; THUS, IF YOUR SYSTEM SUPPORTS A DIRECT BRANCH TO THE TPA (VIA A ZERO-LENGTH
  130. ; .COM FILE, OR THE ZCPR "GO" COMMAND), YOU MAY SAFELY RE-EXECUTE MLOAD.
  131. ;
  132. ; PLEASE REPORT ANY BUGS, BUG FIXES, OR ENHANCEMENTS TO ME AT:
  133. ;
  134. ;        "FORT FONE FILE FOLDER" RCPM/CBBS
  135. ;        FORT ATKINSON, WISCONSIN
  136. ;        (414) 563-9932 (NO RING BACK)
  137. ;
  138. ;                --RON FOWLER
  139. ;                  03/08/84
  140. ;------------------------------------------------------------
  141. ;
  142. ; CP/M EQUATES
  143. ;
  144. WARMBT    EQU    0        ;WARM BOOT
  145. SYSTEM    EQU    5        ;SYSTEM ENTRY (ALSO TOP OF MEM PNTR)
  146. DFCB    EQU    5CH        ;DEFAULT FILE CONTROL BLOCK
  147. FT    EQU    9        ;FCB OFFSET TO FILETYPE
  148. TBUF    EQU    80H        ;DEFAULT BUFFER
  149. TPA    EQU    100H        ;TRANSIENT PROGRAM AREA
  150. EOF    EQU    1AH        ;CP/M END-OF-FILE MARK
  151. FCBSIZ    EQU    33        ;SIZE OF FILE CONTROL BLOCK
  152. ;
  153. ; CP/M SYSTEM CALLS
  154. ;
  155. PCHARF    EQU    2        ;PRINT CHAR
  156. SELDF    EQU    14        ;SELECT DISK DRIVE
  157. OPENF    EQU    15        ;OPEN FILE
  158. CLOSEF    EQU    16        ;CLOSE FILE
  159. FSRCHF    EQU    17        ;SEARCH FOR FIRST
  160. FSRCHN    EQU    18        ;SEARCH FOR NEXT
  161. ERASEF    EQU    19        ;DELETE FILE
  162. READF    EQU    20        ;READ RECORD
  163. WRITEF    EQU    21        ;WRITE RECORD
  164. CREATF    EQU    22        ;CREATE FILE
  165. GETDRF    EQU    25        ;RETURN DFLT DRIVE #
  166. SDMAF    EQU    26        ;SET DMA ADDRESS
  167. GSUSER    EQU    32        ;GET/SET USER #
  168. RRAND    EQU    33        ;READ RANDOM
  169. WRAND    EQU    34        ;WRITE RANDOM
  170. FILSZF    EQU    35        ;COMPUTE FILE SIZE
  171. SRAND    EQU    36        ;SET RANDOM
  172. ;
  173. ; ASCII CHARACTER CONSTANTS
  174. ;
  175. CR    EQU    13
  176. LF    EQU    10
  177. BEL    EQU    7
  178. TAB    EQU    9
  179. ;
  180. ; WITHOUT FURTHER ADO...
  181. ;
  182.     ORG    TPA
  183. ;
  184.     JMP    BEGIN        ;JUMP OVER DEFAULT OUTPUT FILETYPE
  185. ;
  186. ; THE DEFAULT OUTPUT FILETYPE IS LOCATED AT 103H FOR EASY PATCHING
  187. ;
  188. OUTTYP:    DB    'COM'
  189. ;
  190. BEGIN:    LXI    H,0        ;SAVE SYSTEM STACKPOINTER
  191.     DAD    SP
  192.     SHLD    SPSAVE
  193.     LXI    SP,STACK    ;LOAD LOCAL STACK
  194.     CALL    ILPRNT        ;SIGN ON
  195.     DB    'MLOAD ver. 2.1   Copyright (C) 1983,1984 by Ronald G. Fowler'
  196.     DB    CR,LF,0
  197.     CALL    SETUP        ;INITIALIZE
  198. MAIN:    CALL    NXTFIL        ;PARSE AND READ NEXT INPUT FILE
  199.     JC    DONE        ;NO MORE...
  200.     CALL    LODFIL        ;YEP, LOAD IT
  201.     CALL    CLOSFL        ;CLOSE IT (IN CASE MP/M)
  202.     JMP    MAIN        ;MAYBE MORE
  203. DONE:    CALL    WRTFIL        ;WRITE THE OUTPUT FILE
  204. ;
  205. ; EXIT TO CP/M
  206. ;
  207. EXIT:    LXI    D,TBUF        ;RESTORE DMA ADDRESS
  208.     MVI    C,SDMAF
  209.     CALL    BDOS
  210.     LDA    SYSTEM+2    ;GET TOP OF MEMORY POINTER
  211.     SUI    9        ;ALLOW FOR CCP+SLOP
  212.     LXI    H,HILOAD+1    ;HIGHEST LOAD ADDRESS
  213.     SUB    M        ;ABOVE CCP?
  214.     JC    WARMBT        ;THEN WARM-BOOT
  215.     LHLD    SPSAVE        ;NOPE, CCP STILL IN MEMORY
  216.     SPHL            ;RESTORE ITS STACK
  217.     RET            ;RETURN TO CCP
  218. ;
  219. ; LOAD PROGRAM INITIALIZATION
  220. ;
  221. SETUP:    LXI    H,VARSET    ;INITIALIZE VARIABLES
  222.     LXI    D,VARS
  223.     MVI    B,VARLEN    ;BY MOVING IN DEFAULT VALUES
  224.     CALL    MOVE
  225.     LHLD    CMDPTR        ;GET FIRST FREE MEM POINTER
  226.     XCHG            ;IN DE
  227.     LXI    H,TBUF        ;POINT TO COMMAND TAIL BUFR
  228.     MOV    A,M        ;GET ITS LENGTH
  229.     INX    H
  230.     ORA    A        ;DOES IT HAVE ANY LENGTH?
  231.     JZ    HELP        ;NOPE, GO GIVE USAGE HELP
  232.     MOV    B,A        ;YEP, GET LENGTH TO B
  233.     CALL    MOVE        ;MOVE CMD TAIL TO BUFFER
  234.     XCHG            ;END OF DEST TO HL
  235.     MVI    M,0        ;STUFF A TERMINATOR
  236.     INX    H        ;POINT TO FIRST FREE MEMORY
  237.     SHLD    FILBUF        ;SET UP FILE BUFFER
  238.     XCHG            ;FILE BUFR ADRS TO DE
  239.     LHLD    SYSTEM+1    ;GET TOP OF MEMORY POINTER
  240.     MOV    A,L        ;COMPUTE SIZE OF FILE BUFFER
  241.     SUB    E
  242.     MOV    C,A        ;WITH RESULT IN BC
  243.     MOV    A,H
  244.     SUI    9        ;ALLOW FOR CCP
  245.     SBB    D
  246.     MOV    B,A
  247.     XCHG            ;BUFFER POINTER TO HL
  248. NITMEM:    MVI    M,0        ;CLEAR BUFFER
  249.     INX    H
  250.     DCX    B
  251.     MOV    A,B
  252.     ORA    C
  253.     JNZ    NITMEM
  254. ;
  255. ; LOOK FOR A BIAS SPECIFICATION IN COMMAND LINE
  256. ;
  257.     LHLD    CMDPTR        ;POINT TO COMMAND BUFFER-1
  258.     DCX    H
  259.     CALL    SCANBK        ;SCAN PAST BLANKS
  260.     ORA    A        ;NO NON-BLANK CHARS?
  261.     JZ    HELP        ;THEN GO PRINT HELP TEXT
  262. FNDSPC:    INX    H        ;POINT TO NEXT
  263.     MOV    A,M        ;FETCH IT
  264.     ORA    A        ;TEST IT
  265.     RZ            ;LINE ENDED, RETURN
  266.     CPI    ' '        ;NOPE, TEST FOR BLANK
  267.     JNZ    FNDSPC        ;NOT BLANK, CONTINUE
  268.     CALL    SCANBK        ;SKIP BLANKS
  269.     ORA    A        ;END-OF-LINE?
  270.     RZ            ;RETURN IF SO
  271. ;
  272. ; HL POINTS TO BIAS IN COMMAND LINE
  273. ;
  274.     LXI    D,0        ;INIT BIAS
  275.     CALL    HEXDIG        ;INSURE A HEX DIGIT
  276.     JC    SYNERR        ;BAD...
  277. HEXLP:    MOV    A,M        ;NO.  GET NEXT CHAR
  278.     INX    H        ;SKIP OVER IT
  279.     CALL    HEXDIG        ;TEST FOR HEX DIGIT
  280.     JNC    DIGOK        ;JUMP IF GOOD HEX DIGIT
  281.     ORA    A        ;MUST END ON NULL TERMINATOR
  282.     JNZ    SYNERR
  283.     XCHG            ;GOOD END, GET BIAS TO HL
  284.     SHLD    BIAS        ;STUFF IT
  285.     RET            ;DONE
  286. DIGOK:    XCHG            ;BIAS TO HL
  287.     DAD    H        ;SKIFT LEFT 4 TO MAKE ROOM
  288.     DAD    H        ;   FOR NEW HEX DIGIT
  289.     DAD    H
  290.     DAD    H
  291.     XCHG            ;BACK TO DE
  292.     ADD    E        ;ADD IN NEW DIGIT
  293.     MOV    E,A
  294.     JNC    HEXLP        ;JUMP IF NO 8-BIT OVFL
  295.     INR    D        ;CARRY
  296.     JMP    HEXLP
  297. ;
  298. ; PARSE NEXT INPUT NAME, AND OPEN RESULTANT FILE
  299. ;
  300. NXTFIL:    LHLD    CMDPTR        ;GET COMMAND LINE POINTER
  301. NEXT2:    LXI    D,DFCB        ;DESTINATION FCB
  302.     CALL    FPARSE        ;PARSE A FILENAME
  303.     CPI    '='        ;STOPPED ON OUTPUT SPECIFIER?
  304.     JNZ    NOTEQ
  305.     LDA    OUTNAM+2    ;INSURE NO NAME YET SPECIFIED
  306.     CPI    ' '
  307.     JNZ    SYNERR        ;SYNTAX ERROR IF ALREADY NAMED
  308.     LDA    OUTFLG        ;ALREADY BEEN HERE?
  309.     ORA    A
  310.     JNZ    SYNERR        ;CAN'T BE HERE TWICE
  311.     INR    A        ;FLAG THAT WE'VE BEEN HERE
  312.     STA    OUTFLG
  313.     INR    B        ;INSURE NO AMBIGUOUS OUTPUT NAME
  314.     DCR    B
  315.     JNZ    AFNERR
  316.     INX    H        ;SKIP OVER '='
  317.     PUSH    H        ;SAVE CMD LINE POINTER
  318.     LXI    H,DFCB-1    ;MOVE THE NAME TO OUTPUT NAME HOLD
  319.     LXI    D,OUTNAM
  320.     MVI    B,13        ;DRIVE SPEC TOO
  321.     CALL    MOVE
  322.     POP    H        ;RESTORE COMMAND LINE POINTER
  323.     JMP    NEXT2        ;GO PARSE ANOTHER
  324. NOTEQ:    CPI    ','        ;STOPPED ON COMMA?
  325.     JZ    GCOMMA        ;JUMP IF SO
  326.     MVI    M,0        ;NOPE, INSURE END OF INPUT
  327.     JMP    NXT2        ;DON'T ADVANCE OVER FAKE END
  328. GCOMMA:    INX    H        ;SKIP OVER COMMA
  329. NXT2:    SHLD    CMDPTR        ;SAVE NEW COMMAND LINE PNTR
  330.     MOV    A,B        ;GET AMBIG CHAR COUNT
  331.     ORA    A        ;TEST IT
  332.     JNZ    AFNERR        ;ALLOW NO AMBIG CHARACTERS
  333.     STA    BUFPTR        ;FORCE A DISK READ
  334.     LXI    D,DFCB+1    ;LOOK AT PARSED FILENAME
  335.     LDAX    D
  336.     CPI    ' '        ;BLANK? (INPUT ENDED?)
  337.     STC            ;GET CARRY READY IN CASE SO
  338.     RZ            ;RETURN CY IF INPUT GONE
  339.     DCX    D        ;NOPE, POINT DE TO START OF FCB
  340. OPEN2:    PUSH    D        ;TRY TO OPEN THE FILE
  341.     MVI    C,OPENF
  342.     CALL    BDOS
  343.     POP    D
  344.     INR    A        ;RETURN=0FFH?
  345.     JNZ    OPENOK        ;JUMP IF NOT
  346. ;
  347. ; FILE NOT FOUND: IF FILETYPE BLANK, SET TO 'HEX' AND TRY AGAIN
  348. ;
  349.     LXI    H,DFCB+FT    ;POINT TO FILE TYPE
  350.     MOV    A,M        ;ANYTHING THERE?
  351.     CPI    ' '
  352.     JNZ    FNFERR        ;YES, SO FILE NOT FOUND
  353.     MVI    M,'H'        ;NOPE, FILL IN 'HEX'
  354.     INX    H
  355.     MVI    M,'E'
  356.     INX    H
  357.     MVI    M,'X'
  358.     JMP    OPEN2        ;GO TRY AGAIN
  359. ;
  360. ; HERE AFTER A GOOD FILE OPEN
  361. ;
  362. OPENOK:    CALL    HEXCHK        ;IS THIS A HEX FILE?
  363.     RZ            ;IF SO, ALL DONE
  364.     LXI    H,COMFLG    ;NO, GET POINTER TO FLAG
  365.     MOV    A,M        ;LOADING FIRST FILE?
  366.     ORA    A
  367.     RNZ            ;IF NOT, IGNORE TYPE, CONSIDER HEX
  368.     INR    M        ;ELSE, SET THE FLAG
  369.     RET
  370. ;
  371. ; LOAD CURRENT FILE
  372. ;
  373. LODFIL:    LXI    H,COMFLG    ;LOADING A COM FILE?
  374.     MOV    A,M        ;GET FLAG
  375.     ANI    1
  376.     JNZ    LODCOM        ;JUMP IF SO
  377.     LHLD    BIAS        ;ELSE GET BIAS ON TOP OF STACK
  378.     PUSH    H
  379. ;
  380. ; LOAD A HEX RECORD
  381. ;
  382. LOADLP:    CALL    GNB        ;GET NEXT FILE BYTE
  383.     SBI    ':'        ;LOOK FOR START-RECORD MARK
  384.     JNZ    LOADLP        ;SCAN UNTIL FOUND
  385.     STA    CKSUM        ;GOT IT, INIT CHECKSUM TO ZERO
  386.     MOV    D,A        ;UPPER BYTE OF REC CNT=0
  387.     POP    B        ;RETRIEVE BIAS ADRS
  388.     PUSH    B        ;SAVE IT AGAIN
  389.     CALL    GHBCKS        ;GET HEX BYTE W/CHECKSUM
  390.     MOV    E,A        ;DE NOW HAS RECORD LENGTH
  391.     ORA    A        ;TEST IT
  392.     JNZ    NOTEND        ;JUMP IF LEN<>0 (NOT EOF REC)
  393.     POP    H        ;ALL DONE
  394.     RET
  395. NOTEND:    CALL    GHBCKS        ;HI BYTE OF REC LD ADRS
  396.     MOV    H,A        ;ACCUMULATE IN HL
  397.     CALL    GHBCKS        ;GET LO BYTE
  398.     MOV    L,A        ;PUT LO IN L
  399.     LDA    LODFLG        ;TEST LOAD FLAG
  400.     ORA    A
  401.     CZ    LODNIT        ;NOT FIRST RECORD, INITIALIZE
  402.     PUSH    H        ;SAVE LOAD ADDRESS
  403.     DAD    D        ;ADD IN RECORD LENGTH
  404.     DCX    H        ;MAKE HIGHEST, NOT NEXT
  405.     LDA    HIPC        ;A NEW HIGH?
  406.     SUB    L
  407.     LDA    HIPC+1
  408.     SBB    H
  409.     JNC    NOTGT        ;JUMP IF NOT
  410.     SHLD    HIPC        ;YEP, UPDATE HIPC
  411.     PUSH    D        ;SAVE RECLEN
  412.     XCHG            ;LOAD ADRS TO DE
  413.     LHLD    OFFSET        ;GET OFFSET TO FORM TRUE MEMORY ADRS
  414.     DAD    D        ;ADD IN OFFSET
  415.     DAD    B        ;AND BIAS
  416.     SHLD    HILOAD        ;MARK HIGHEST TRUE MEMORY LOAD ADRS
  417.     LDA    SYSTEM+2    ;VALIDATE AGAINST TOP-MEM POINTER
  418.     CMP    H
  419.     JC    MEMFUL        ;JUMP IF OUT OF MEMORY
  420.     POP    D        ;RESTORE RECLEN
  421. NOTGT:    POP    H        ;RESTORE LOAD ADDRESS
  422.     DAD    B        ;ADD BIAS TO LOAD ADRS
  423.     PUSH    D        ;SAVE RECORD LENGTH
  424.     PUSH    H
  425.     LHLD    BYTCNT        ;ADD RECORD LENGTH TO BYTE COUNT
  426.     DAD    D
  427.     SHLD    BYTCNT
  428.     POP    H
  429.     XCHG
  430.     LHLD    OFFSET        ;CALCULATE TRUE MEMORY ADRS
  431.     DAD    D        ;HL=TRUE LOADING ADRS
  432.     POP    D        ;RESTORE RECORD LENGTH
  433.     CALL    GHBCKS        ;SKIP UNUSED BYTE OF INTEL FORMAT
  434. ;
  435. ; MOVE THE RECORD INTO MEMORY
  436. ;
  437. RECLP:    CALL    GHBCKS        ;GET HEX BYTE
  438.     MOV    M,A        ;STORE IT IN BUFFER
  439.     INX    H        ;POINT TO NEXT
  440.     DCR    E        ;COUNT DOWN
  441.     JNZ    RECLP        ;UNTIL RECORD ALL READ
  442.     CALL    GHBCKS        ;GET CHECKSUM BYTE
  443.     JNZ    CSERR        ;FINAL ADD CKSUM SHOULD SUM 0
  444.     JMP    LOADLP        ;GOOD LOAD, GO DO NXT RECORD
  445. ;
  446. ; GET NEXT HEX BYTE FROM INPUT, AND
  447. ; ACCUMULATE A CHECKSUM
  448. ;
  449. GHBCKS: PUSH    B        ;SAVE EM ALL
  450.     PUSH    H
  451.     PUSH    D
  452.     CALL    HEXIN        ;GET HEX BYTE
  453.     MOV    B,A        ;SAVE IN B
  454.     LXI    H,CKSUM        ;ADD TO CHECKSUM
  455.     MOV    A,M
  456.     ADD    B
  457.     MOV    M,A
  458.     MOV    A,B        ;GET BYTE BACK
  459.     POP    D        ;RESTORE CHECKSUM
  460.     POP    H        ;RESTORE OTHER REGS
  461.     POP    B
  462.     RET
  463. ;
  464. ; ROUTINE TO GET NEXT BYTE FROM INPUT...FORMS
  465. ; BYTE FROM TWO ASCII HEX CHARACTERS
  466. ;
  467. HEXIN:    CALL    GNB        ;GET NEXT INPUT FILE BYTE
  468.     CALL    HEXVAL        ;CONVERT TO BINARY W/VALIDATION
  469.     RLC            ;MOVE INTO MS NYBBLE
  470.     RLC
  471.     RLC
  472.     RLC
  473.     ANI    0F0H        ;KILL POSSIBLE GARBAGE
  474.     PUSH    PSW        ;SAVE IT
  475.     CALL    GNB        ;GET NEXT BYTE
  476.     CALL    HEXVAL        ;CONVERT IT, W/VALIDATION
  477.     POP    B        ;GET BACK FIRST
  478.     ORA    B        ;OR IN SECOND
  479.     RET            ;GOOD BYTE IN A
  480. ;
  481. ; GNB - UTILITY SUBROUTINE TO GET NEXT
  482. ;    BYTE FROM DISK FILE
  483. GNB:    PUSH    H        ;SAVE ALL REGS
  484.     PUSH    D
  485.     PUSH    B
  486.     LDA    BUFPTR        ;GET INPUT BUFR POINTER
  487.     ANI    7FH        ;WOUND BACK TO 0?
  488.     JZ    DISKRD        ;GO READ SECTOR IF SO
  489. GNB1:    MVI    D,0        ;ELSE FORM 16 BIT OFFSET
  490.     MOV    E,A
  491.     LXI    H,TBUF        ;FROM TBUF
  492.     DAD    D        ;ADD IN OFFSET
  493.     MOV    A,M        ;GET NEXT BYTE
  494.     CPI    EOF        ;END OF FILE?
  495.     JZ    EOFERR        ;ERROR IF SO
  496.     LXI    H,BUFPTR     ;ELSE BUMP BUF PTR
  497.     INR    M
  498.     ORA    A        ;RETURN CARRY CLEAR
  499.     POP    B        ;RESTORE AND RETURN
  500.     POP    D
  501.     POP    H
  502.     RET
  503. ;
  504. ; READ NEXT SECTOR FROM DISK
  505. ;
  506. DISKRD: MVI    C,READF        ;BDOS "READ SEC" FUNCTION
  507.     LXI    D,DFCB
  508.     CALL    BDOS        ;READ SECTOR
  509.     ORA    A
  510.     JNZ    EOFERR        ;ERROR IF PHYS END OF FILE
  511.     STA    BUFPTR        ;STORE 0 AS NEW BUF PTR
  512.     JMP    GNB1        ;GO RE-JOIN GNB CODE
  513. ;
  514. ; LOAD A COM FILE
  515. ;
  516. LODCOM:    INR    M        ;BUMP THE COMFILE FLAG
  517.     LXI    H,TPA        ;SET ORIGIN
  518.     CALL    LODNIT        ;AND INITIALIZE
  519.     XCHG            ;LOAD ADDRESS IN DE
  520.     LHLD    BIAS        ;ADD IN BIAS
  521.     DAD    D
  522.     XCHG
  523.     LHLD    OFFSET        ;AND OFFSET
  524.     DAD    D
  525.     XCHG            ;DE HAS ABSOLUTE MEM ADRS OF LOAD
  526. ;
  527. COMLP:    LXI    H,128        ;CALCULATE NEXT DMA
  528.     DAD    D
  529.     LDA    SYSTEM+2    ;CHECK FOR SPACE
  530.     CMP    H
  531.     JC    MEMFUL        ;JUMP IF NONE
  532.     PUSH    H        ;ELSE SAVE NEXT DMA
  533.     PUSH    D        ;AND THIS DMA
  534.     MVI    C,SDMAF        ;SET THIS DMA
  535.     CALL    BDOS
  536.     LXI    D,DFCB        ;READ NEXT RECORD
  537.     MVI    C,READF
  538.     CALL    BDOS
  539.     POP    H        ;RECALL THIS DMA
  540.     POP    D        ;DE=NEXT DMA
  541.     ORA    A        ;END OF READ?
  542.     JNZ    LODEND        ;JUMP IF SO
  543.     LHLD    COMSIZ        ;NO, ADVANCE COM BYTE COUNT
  544.     LXI    B,128
  545.     DAD    B
  546.     SHLD    COMSIZ
  547.     JMP    COMLP        ;CONTINUE
  548. ;
  549. LODEND:    DCX    H        ;ONE LESS BYTE IS HIGHEST
  550.     SHLD    HILOAD        ;SET A NEW HIGH
  551.     LHLD    COMSIZ        ;HI PC=BYTECOUNT+100H
  552.     LXI    D,TPA
  553.     DAD    D
  554.     XCHG            ;TO DE
  555.     LHLD    BIAS        ;ADD IN BIAS
  556.     DAD    D
  557.     SHLD    HIPC
  558.     LXI    D,TBUF        ;RESET DMA FOR HEX FILES
  559.     MVI    C,SDMAF
  560.     CALL    BDOS
  561.     RET
  562. ;
  563. ; WRITE OUTPUT FILE
  564. ;
  565. WRTFIL:    LXI    D,DFCB        ;POINT TO FCB
  566.     PUSH    D        ;SAVE 2 COPIES OF POINTER
  567.     PUSH    D
  568.     CALL    NITFCB        ;INITIALIZE OUTPUT FCB
  569.     LXI    H,OUTNAM    ;MOVE OUTPUT NAME IN
  570.     DCX    D        ;POINT TO USER # (PRIOR TO FCB)
  571.     MVI    B,10        ;MOVE USER, DRIVE, PRIMARY NAME
  572.     CALL    MOVE
  573.     MOV    A,M        ;OUTPUT TYPE BLANK?
  574.     CPI    ' '
  575.     JNZ    WRTNB        ;JUMP IF NOT
  576.     LXI    H,OUTTYP    ;YES, MOVE DFLT OUTPUT FILETYPE IN
  577. WRTNB:    MVI    B,3
  578.     CALL    MOVE
  579.     POP    D        ;RESTORE FCB POINTER
  580.     MVI    C,ERASEF    ;ERASE ANY EXISTING FILE
  581.     CALL    BDOS
  582.     POP    D        ;RESTORE FCB POINTER
  583.     MVI    C,CREATF    ;CREATE A NEW FILE
  584.     CALL    BDOS
  585.     INR    A        ;GOOD CREATE?
  586.     JZ    DIRFUL        ;GOTO DIRECTORY FULL ERROR IF NOT
  587.     LHLD    HILOAD        ;YEP, GET TOP OF BUFR PNTR
  588.     XCHG            ;IN DE
  589.     LHLD    FILBUF        ;GET START OF BUFR ADRS
  590.     MOV    A,E        ;CALCULATE OUTPUT FILE SIZE
  591.     SUB    L
  592.     MOV    C,A        ;WITH RESULT IN BC
  593.     MOV    A,D
  594.     SBB    H
  595.     MOV    B,A
  596.     MOV    A,B        ;TEST LENGTH
  597.     ORA    C
  598.     JZ    LODERR        ;NOTHING TO WRITE???
  599.     LXI    D,DFCB        ;GET FCB POINTER
  600. WRLP:    PUSH    B        ;SAVE COUNT
  601.     PUSH    D        ;AND FCB POINTER
  602.     XCHG            ;GET MEMORY POINTER TO DE
  603.     LXI    H,128        ;ADD IN SECTOR LENGTH FOR NEXT PASS
  604.     DAD    D
  605.     XTHL            ;SAVE NEXT DMA
  606.     PUSH    H        ;ABOVE FCB
  607.     MVI    C,SDMAF        ;SET TRANSFER ADDRESS
  608.     CALL    BDOS
  609.     POP    D        ;FETCH FCB POINTER
  610.     PUSH    D        ;SAVE IT AGAIN
  611.     MVI    C,WRITEF    ;WRITE A SECTOR
  612.     CALL    BDOS
  613.     ORA    A        ;TEST RESULT
  614.     JNZ    DSKFUL        ;DISK FULL ERROR...
  615.     LHLD    RECCNT        ;NO,INCREMENT COUNT OF RECORDS
  616.     INX    H
  617.     SHLD    RECCNT
  618.     POP    D        ;RESTORE FCB POINTER
  619.     POP    H        ;AND MEMORY WRITE POINTER
  620.     POP    B        ;AND COUNT
  621.     MOV    A,C        ;SUBTRACT 128 (SEC SIZE) FROM COUNT
  622.     SUI    128
  623.     MOV    C,A
  624.     JNC    WRLP        ;JUMP IF SOME LEFT
  625.     MOV    A,B        ;HI-ORDER BORROW
  626.     SUI    1        ;DO IT (CAN'T "DCR B", DOESN'T AFFECT CY)
  627.     MOV    B,A        ;RESTORE
  628.     JNC    WRLP        ;JUMP IF MORE LEFT
  629.     CALL    CLOSFL        ;CLOSE OUTPUT FILE
  630. ;
  631. ; REPORT STATISTICS TO CONSOLE
  632. ;
  633.     CALL    ILPRNT
  634.     DB    'Loaded ',0
  635.     LHLD    BYTCNT        ;PRINT # BYTES
  636.     CALL    DECOUT
  637.     CALL    ILPRNT
  638.     DB    ' bytes (',0
  639.     CALL    HEXOUT
  640.     CALL    ILPRNT
  641.     DB    'H)',0
  642.     CALL    ILPRNT
  643.     DB    ' to file %',0
  644.     LDA    COMFLG        ;DID WE LOAD A COMFILE TOO?
  645.     ORA    A
  646.     JZ    NOTCOM        ;JUMP IF NOT
  647.     CALL    ILPRNT
  648.     DB    CR,LF,'Over a ',0
  649.     LHLD    COMSIZ
  650.     CALL    DECOUT
  651.     CALL    ILPRNT
  652.     DB    ' byte binary file',0
  653. NOTCOM:    CALL    ILPRNT
  654.     DB    CR,LF,'Start address: ',0
  655.     LHLD    LODADR        ;PRINT LOADING ADDRESS
  656.     CALL    HEXOUT
  657.     CALL    ILPRNT
  658.     DB    'H  Ending address: ',0
  659.     LHLD    HIPC        ;PRINT ENDING LOAD ADDRESS
  660.     CALL    HEXOUT
  661.     CALL    ILPRNT
  662.     DB    'H  Bias: ',0
  663.     LHLD    BIAS
  664.     CALL    HEXOUT
  665.     CALL    ILPRNT
  666.     DB    'H',CR,LF,0
  667.     CALL    ILPRNT
  668.     DB    'Saved image size: ',0
  669.     LHLD    RECCNT        ;GET COUNT OF IMAGE RECORDS
  670.     PUSH    H        ;SAVE IT
  671.     MVI    B,7        ;CONVERT TO BYTES
  672. XLP:    DAD    H
  673.     DCR    B
  674.     JNZ    XLP
  675.     CALL    DECOUT        ;PRINT IT
  676.     CALL    ILPRNT
  677.     DB    ' bytes (',0
  678.     CALL    HEXOUT        ;NOW IN HEX
  679.     CALL    ILPRNT
  680.     DB    'H, - ',0
  681.     POP    H        ;RECALL RECORD COUNT
  682.     CALL    DECOUT        ;PRINT IT
  683.     CALL    ILPRNT
  684.     DB    ' records)',CR,LF,0
  685.     LHLD    LODADR        ;FETCH LOADING ADDRESS
  686.     MOV    A,L        ;TEST IF =TPA
  687.     ORA    A
  688.     JNZ    NOTTPA        ;TPA ALWAYS ON PAGE BOUNDARY
  689.     MOV    A,H        ;LO OK, TEST HI
  690.     CPI    (TPA SHR 8) AND 0FFH
  691.     RZ            ;RETURN IF TPA
  692. NOTTPA:    CALL    ILPRNT        ;NOT, SO PRINT WARNING MSG
  693.     DB    CR,LF,BEL
  694.     DB    '++ Warning: program origin NOT at 100H ++'
  695.     DB    CR,LF,0
  696.     RET            ;DONE
  697. ;
  698. ;    ***********************
  699. ;    * UTILITY SUBROUTINES *
  700. ;    ***********************
  701. ;
  702. ;
  703. ; ROUTINE TO CLOSE ANY OPEN FILE
  704. ;
  705. CLOSFL:    LXI    D,DFCB
  706.     MVI    C,CLOSEF
  707.     CALL    BDOS
  708.     INR    A        ;TEST CLOSE RESULT
  709.     JZ    CLSERR        ;JUMP IF ERROR
  710.     RET
  711. ;
  712. ; PRINT MESSAGE IN-LINE WITH CODE
  713. ;
  714. ILPRNT:    XTHL            ;MESSAGE PNTR TO HL
  715.     CALL    PRATHL        ;PRINT IT
  716.     XTHL            ;RESTORE AND RETURN
  717.     RET
  718. ;
  719. ; PRINT MSG POINTED TO BY HL UNTIL NULL.  EXPAND
  720. ; '%' CHAR TO CURRENT FILENAME.
  721. ;
  722. PRATHL:    MOV    A,M        ;FETCH CHAR
  723.     INX    H        ;POINT TO NEXT
  724.     ORA    A        ;TERMINATOR?
  725.     RZ            ;THEN DONE
  726.     CPI    '%'        ;WANT FILENAME?
  727.     JZ    PRTFN        ;GO DO IT IF SO
  728.     CALL    TYPE        ;NOPE, JUST PRINT CHAR
  729.     JMP    PRATHL        ;CONTINUE
  730. ;
  731. PRTFN:    PUSH    H        ;SAVE POINTER
  732.     PUSH    B
  733.     LDA    DFCB        ;FETCH DR FIELD OF DFCB
  734.     ORA    A        ;DEFAULT DRIVE?
  735.     JNZ    PRNDF        ;JUMP IF NOT
  736.     CALL    GETDSK        ;GET LOGGED-IN DRIVE #
  737.     INR    A        ;MAKE IT ONE-RELATIVE (AS IN FCB)
  738. PRNDF:    ADI    'A'-1        ;MAKE DRIVE NAME PRINTABLE
  739.     CALL    TYPE        ;PRINT IT
  740.     LDA    DFCB-1        ;GET USER #
  741.     CPI    0FFH        ;NULL?
  742.     CZ    GETUSR        ;IFF SO, GET CURRENT USER    
  743.     MOV    L,A        ;TO HL
  744.     MVI    H,0
  745.     CALL    DECOUT        ;PRINT IT
  746.     MVI    A,':'        ;DRIVE NAMES FOLLOWED BY COLON
  747.     CALL    TYPE
  748.     LXI    H,DFCB+1    ;SETUP FOR NAME
  749.     MVI    B,8        ;PRINT UP TO 8
  750.     CALL    PRTNAM
  751.     MVI    A,'.'        ;PRINT DOT
  752.     CALL    TYPE
  753.     MVI    B,3        ;PRINT FILETYPE FIELD
  754.     CALL    PRTNAM
  755.     POP    B
  756.     POP    H        ;RESTORE AND CONTINUE
  757.     JMP    PRATHL
  758. ;
  759. ; PRINT FILE NAME @HL MAX LENGTH IN B.  DON'T PRINT SPACES
  760. ;
  761. PRTNAM:    MOV    A,M        ;FETCH A CHAR
  762.     CPI    ' '        ;BLANK?
  763.     JZ    PWIND        ;GO WIND IF SO
  764.     INX    H        ;NOPE, MOVE TO NEXT
  765.     CALL    TYPE        ;PRINT IT
  766.     DCR    B        ;COUNT DOWN
  767.     JNZ    PRTNAM        ;CONTINUE
  768.     RET
  769. PWIND:    INX    H        ;SKIP REMAINDER OF BLANK NAME
  770.     DCR    B
  771.     JNZ    PWIND
  772.     RET
  773. ;
  774. ; PRINT HL IN DECIMAL ON CONSOLE
  775. ;
  776. DECOUT:    PUSH    H        ;SAVE EVERYBODY
  777.     PUSH    D
  778.     PUSH    B
  779.     LXI    B,-10        ;CONVERSION RADIX
  780.     LXI    D,-1
  781. DECLP:    DAD    B
  782.     INX    D
  783.     JC    DECLP
  784.     LXI    B,10
  785.     DAD    B
  786.     XCHG
  787.     MOV    A,H
  788.     ORA    L
  789.     CNZ    DECOUT        ;THIS IS RECURSIVE
  790.     MOV    A,E
  791.     ADI    '0'
  792.     CALL    TYPE
  793.     POP    B
  794.     POP    D
  795.     POP    H
  796.     RET
  797. ;
  798. ; NEWLINE ON CONSOLE
  799. ;
  800. CRLF:    MVI    A,CR
  801.     CALL    TYPE
  802.     MVI    A,LF
  803.     JMP    TYPE
  804. ;
  805. ; PRINT HL ON CONSOLE IN HEX
  806. ;
  807. HEXOUT:    MOV    A,H        ;GET HI
  808.     CALL    HEXBYT        ;PRINT IT
  809.     MOV    A,L        ;GET LO, FALL INTO HEXBYT
  810. ;
  811. ; TYPE ACCUMULATOR ON CONSOLE IN HEX
  812. ;
  813. HEXBYT: PUSH    PSW        ;SAVE BYTE
  814.     RAR            ;GET MS NYBBLE..
  815.     RAR            ;..INTO LO 4 BITS
  816.     RAR
  817.     RAR
  818.     CALL    NYBBLE
  819.     POP    PSW        ;GET BACK BYTE
  820. NYBBLE:    ANI    0FH        ;MASK MS NYBBLE
  821.     ADI    90H        ;ADD OFFSET
  822.     DAA            ;DECIMAL ADJUST A-REG
  823.     ACI    40H        ;ADD OFFSET
  824.     DAA            ;FALL INTO TYPE
  825. ;
  826. ; TYPE CHAR IN A ON CONSOLE
  827. ;
  828. TYPE:    PUSH    H        ;SAVE ALL
  829.     PUSH    D
  830.     PUSH    B
  831.     MOV    E,A        ;CP/M OUTPUTS FROM E
  832.     MVI    C,PCHARF
  833.     CALL    BDOS
  834.     POP    B
  835.     POP    D
  836.     POP    H
  837.     RET
  838. ;
  839. ; MOVE: FROM @HL TO @DE, COUNT IN B
  840. ;
  841. MOVE:    INR    B        ;UP ONE
  842. MOVLP:    DCR    B        ;COUNT DOWN
  843.     RZ            ;RETURN IF DONE
  844.     MOV    A,M        ;NOT DONE, CONTINUE
  845.     STAX    D
  846.     INX    H        ;POINTERS=POINTERS+1
  847.     INX    D
  848.     JMP    MOVLP
  849. ;
  850. ; SCAN TO FIRST NON-BLANK CHAR IN STRING @HL
  851. ;
  852. SCANBK:    INX    H        ;NEXT
  853.     MOV    A,M        ;FETCH IT
  854.     CPI    ' '
  855.     JZ    SCANBK
  856.     RET
  857. ;
  858. ; GET HEX DIGIT AND VALIDATE
  859. ;
  860. HEXVAL:    CALL    HEXDIG        ;GET HEX DIGIT
  861.     JC    FORMERR        ;JUMP IF BAD
  862.     RET
  863. ;
  864. ; GET HEX DIGIT, RETURN CY=1 IF BAD DIGIT
  865. ;
  866. HEXDIG:    CPI    '0'        ;LO BOUNDARY TEST
  867.     RC            ;BAD ALREADY?
  868.     CPI    '9'+1        ;NO, TEST HI
  869.     JC    HEXCVT        ;JUMP IF NUMERIC
  870.     CPI    'A'        ;TEST ALPHA
  871.     RC            ;BAD?
  872.     CPI    'F'+1        ;NO, UPPER ALPHA BOUND
  873.     CMC            ;PERVERT CARRY
  874.     RC            ;BAD?
  875.     SUI    7        ;NO, ADJUST TO 0-F
  876. HEXCVT:    ANI    0FH        ;MAKE IT BINARY
  877.     RET
  878. ;
  879. ;    ******************
  880. ;    * ERROR HANDLERS *
  881. ;    ******************
  882. ;
  883. SYNERR:    CALL    CRLF
  884.     CALL    ILPRNT
  885.     DB    '      Command line syntax error',CR,LF,CR,LF,0
  886.     JMP    HELP        ;GIVE HELP MSG TOO
  887. ;
  888. AFNERR:    CALL    ERRXIT        ;EXIT WITH MESSAGE
  889.     DB    'Ambiguous file name: % not allowed.',0
  890. ;
  891. FNFERR:    CALL    ERRXIT
  892.     DB    'File % not found.',0
  893. ;
  894. DSKFUL:    CALL    ERRXIT
  895.     DB    'Disk full.',0
  896. ;
  897. DIRFUL:    CALL    ERRXIT
  898.     DB    'Directory full.',0
  899. ;
  900. EOFERR:    CALL    ERRXIT
  901.     DB    'Premature end-of-file in %',0
  902. ;
  903. CSERR:    CALL    ERRXIT
  904.     DB    'Checksum error in %',0
  905. ;
  906. CLSERR:    CALL    ERRXIT
  907.     DB    'Can''t close %',0
  908. ;
  909. MEMFUL:    CALL    ERRXIT
  910.     DB    'Memory full while loading %',0
  911. ;
  912. FORMERR:CALL    ERRXIT
  913.     DB    'Format error in file %',0
  914. ;
  915. LODERR:    CALL    ERRXIT
  916.     DB    'Writing %, nothing loaded',0
  917. ;
  918. HELP:    CALL    ERRXIT        ;PRINT HELP TEXT
  919.     DB    'MLOAD syntax:',CR,LF,CR,LF
  920.     DB    'MLOAD [<OUTFIL>=] <FILE1>[,<FILE2>...] [<BIAS>]',CR,LF
  921.     DB    TAB,'    (brackets denote optional items)',CR,LF,CR,LF
  922.     DB    TAB,'<OUTFIL> is the optional output filename',CR,LF
  923.     DB    TAB,'<FILEn>  are input file(s)',CR,LF
  924.     DB    TAB,'<BIAS>   is a hex load offset within the output file'
  925.     DB    CR,LF,CR,LF
  926.     DB    TAB,'<FILE1> may be an optional non-HEX file to be patched',CR,LF
  927.     DB    TAB,'by subsequently named HEX files (specifying',CR,LF
  928.     DB    TAB,'The filetype enables this function).'
  929.     DB    CR,LF,CR,LF
  930.     DB    'Note that ZCPR2-style drive/user notation may be used in all'
  931.     DB    CR,LF
  932.     DB    'file specifications (e.g., "B3:MYFILE.COM, "A14:MDM7.HEX").'
  933.     DB    CR,LF,0
  934. ;
  935. ; GENERAL ERROR HANDLER
  936. ;
  937. ERRXIT:    CALL    CRLF        ;NEW LINE
  938.     POP    H        ;FETCH ERROR MSG POINTER
  939.     CALL    PRATHL        ;PRINT IT
  940.     CALL    CRLF
  941.     JMP    EXIT        ;DONE
  942. ; INITIALIZE LOAD PARAMETERS
  943. ;
  944. LODNIT:    MVI    A,1        ;FIRST RECORD, SET LOAD FLAG
  945.     STA    LODFLG
  946.     SHLD    LODADR        ;SAVE LOAD ADDRESS
  947.     SHLD    HIPC        ;AND HI LOAD
  948.     PUSH    D        ;SAVE RECORD LENGTH
  949.     XCHG            ;DE=LOAD ADDRESS
  950.     LHLD    FILBUF        ;GET ADDRESS OF FILE BUFFER
  951.     MOV    A,L        ;SUBTRACT LOAD ADRS FROM FILE BUFFER
  952.     SUB    E
  953.     MOV    L,A
  954.     MOV    A,H
  955.     SBB    D
  956.     MOV    H,A
  957.     SHLD    OFFSET        ;SAVE AS LOAD OFFSET
  958.     PUSH    D        ;SAVE LOAD ADDRESS ON STACK
  959.     PUSH    B        ;SAVE BIAS
  960.     LXI    D,OUTNAM+2    ;CHECK OUTPUT FILENAME
  961.     LDAX    D        ;(FIRST CHAR)
  962.     CPI    ' '
  963.     JNZ    NAMSKP        ;JUMP IF SO
  964.     LXI    H,DFCB+1    ;GET FIRST NAME POINTER
  965.     MVI    B,8        ;(DON'T INCLUDE DRIVE SPEC)
  966.     CALL    MOVE
  967. ;
  968. ; CHECK FOR OUTFLG=1 (PRESENCE OF AN "=").  NOTE THAT THE
  969. ; FILENAME MAY WELL BE BLANK, AND YET OUTFLG <>0, FOR EXAMPLE
  970. ; IN THE CASE OF "A:=<FILENAME>" OR "C4:=<FILENAME>". IN 
  971. ; THIS CASE, WE WANT TO REMEMBER THE DRIVE/USER SPECIFIED, BUT
  972. ; USE THE FIRST INPUT FILE TO FORM THE OUTPUT NAME. OTHERWISE,
  973. ; WE USE THE CURRENT DRIVE/USER.
  974. ;
  975.     LDA    OUTFLG        ;WAS THERE AN "="?
  976.     ORA    A
  977.     JNZ    NAMSKP        ;JUMP IF SO
  978.     LXI    H,OUTNAM    ;GET DESTINATION POINTER
  979.     CALL    GETUSR        ;GET CURRENT USER #
  980.     MOV    M,A
  981.     INX    H        ;POINT TO DRIVE
  982.     CALL    GETDSK        ;GET IT
  983.     INR    A        ;FCB'S DRIVE IS 1-RELATIVE
  984.     MOV    M,A
  985. NAMSKP:    MVI    A,1        ;INSURE "=" CANNOT OCCUR ANYMORE
  986.     STA    OUTFLG
  987.     POP    B        ;RESTORE BIAS
  988.     POP    H        ;LOAD ADDRESS TO HL
  989.     POP    D        ;RESTORE RECORD LENGTH
  990.     RET
  991. ;
  992. ;    *********************************
  993. ;    * FILE NAME PARSING SUBROUTINES *
  994. ;    *********************************
  995. ;
  996. ; CREDIT WHERE CREDIT'S DUE:
  997. ; --------------------------
  998. ; THESE ROUTINES WERE LIFTED FROM BOB VAN VALZAH'S
  999. ; "FAST" PROGRAM.
  1000. ;
  1001. ;
  1002. ;    *********************************
  1003. ;    * FILE NAME PARSING SUBROUTINES *
  1004. ;    *********************************
  1005. ;
  1006. ;
  1007. ; GETFN GETS A FILE NAME FROM TEXT POINTED TO BY REG HL INTO
  1008. ; AN FCB POINTED TO BY REG DE.    LEADING DELIMETERS ARE 
  1009. ; IGNORED. ALLOWS DRIVE SPEC OF THE FORM <DU:> (DRIVE/USER).
  1010. ; THIS ROUTINE FORMATS ALL 33 BYTES OF THE FCB (BUT NOT RAN REC).
  1011. ;
  1012. ; ENTRY DE    FIRST BYTE OF FCB
  1013. ; EXIT B=# OF '?' IN NAME
  1014. ; FCB-1= USER # PARSED (IF SPECIFIED) OR 255
  1015. ;
  1016. ;
  1017. FPARSE:    CALL    NITFCB        ;INIT 1ST HALF OF FCB
  1018.     CALL    GSTART        ;SCAN TO FIRST CHARACTER OF NAME
  1019.     CALL    GETDRV        ;GET DRIVE/USER SPEC. IF PRESENT
  1020.      MOV    A,B        ;GET USER # OR 255
  1021.     CPI    0FFH        ;255?
  1022.     JZ    FPARS1        ;JUMP IF SO
  1023.     DCX    D        ;BACK UP TO BYTE PRECEEDING FCB
  1024.     DCX    D
  1025.     STAX    D        ;STUFF USER #
  1026.     INX    D        ;ONWARD
  1027.     INX    D
  1028. FPARS1:    CALL    GETPS        ;GET PRIMARY AND SECONDARY NAME
  1029.     RET
  1030. ;
  1031. ; NITFCB FILLS THE FCB WITH DFLT INFO - 0 IN DRIVE FIELD
  1032. ; ALL-BLANK IN NAME FIELD, AND 0 IN EX,S1,S2,RC, DISK
  1033. ; ALLOCATION MAP, AND RANDOM RECORD # FIELDS
  1034. ;
  1035. NITFCB:    PUSH    H
  1036.     PUSH    D
  1037.     CALL    GETUSR        ;INIT USER FIELD
  1038.     POP    D
  1039.     POP    H
  1040.     PUSH    D        ;SAVE FCB LOC
  1041.     DCX    D
  1042.     STAX    D        ;INIT USER # TO CURRNT USER #
  1043.     INX    D
  1044.     XCHG            ;MOVE IT TO HL
  1045.     MVI    M,0        ;DRIVE=DEFAULT
  1046.     INX    H        ;BUMP TO NAME FIELD
  1047.     MVI    B,11        ;ZAP ALL OF NAME FLD
  1048. NITLP:    MVI    M,' '
  1049.     INX    H
  1050.     DCR    B
  1051.     JNZ    NITLP
  1052.     MVI    B,33-11        ;ZERO OTHERS, UP TO NR FIELD
  1053. ZLP:    MVI    M,0
  1054.     INX    H
  1055.     DCR    B
  1056.     JNZ    ZLP
  1057.     XCHG            ;RESTORE HL
  1058.     POP    D        ;RESTORE FCB POINTER
  1059.     RET
  1060. ;
  1061. ; GSTART ADVANCES THE TEXT POINTER (REG HL) TO THE FIRST
  1062. ; NON DELIMITER CHARACTER (I.E. IGNORES BLANKS).  RETURNS A
  1063. ; FLAG IF END OF LINE (00H OR ';') IS FOUND WHILE SCANING.
  1064. ; EXIT    HL    POINTING TO FIRST NON DELIMITER
  1065. ;    A    CLOBBERED
  1066. ;    ZERO    SET IF END OF LINE WAS FOUND
  1067. ;
  1068. GSTART: CALL    GETCH        ;SEE IF POINTING TO DELIM?
  1069.     RNZ            ;NOPE - RETURN
  1070.     ORA    A        ;PHYSICAL END?
  1071.     RZ            ;YES - RETURN W/FLAG
  1072.     INX    H        ;NOPE - MOVE OVER IT
  1073.     JMP    GSTART         ;AND TRY NEXT CHAR
  1074. ;
  1075. ; GETDRV CHECKS FOR THE PRESENCE OF A DU: SPEC AT THE TEXT
  1076. ; POINTER, AND IF PRESENT FORMATS DRIVE INTO FCB AND RETURNS
  1077. ; USER # IN B.
  1078. ;
  1079. ; ENTRY HL    TEXT POINTER
  1080. ;    DE    POINTER TO FIRST BYTE OF FCB
  1081. ; EXIT    HL    POSSIBLY UPDATED TEXT POINTER
  1082. ;    DE    POINTER TO SECOND (PRIMARY NAME) BYTE OF FCB
  1083. ;    B    USER # IF SPECIFIED OR 0FFH
  1084. ;
  1085. GETDRV:    MVI    B,0FFH        ;DEFAULT NO USER #
  1086.     PUSH    H        ;SAVE TEXT POINTER
  1087. DSCAN:    CALL    GETCH        ;GET NEXT CHAR
  1088.     INX    H        ;SKIP POINTER OVER IT
  1089.     JNZ    DSCAN        ;SCAN UNTIL DELIMITER
  1090.     CPI    ':'        ;DELIMITER A COLON?
  1091.     INX    D        ;SKIP DR FIELD IN FCB IN CASE NOT
  1092.     POP    H        ;AND RESTORE TEXT POINTER
  1093.     RNZ            ;RETURN IF NO DU: SPEC
  1094.     MOV    A,M        ;GOT ONE, GET FIRST CHAR
  1095.     CALL    CVTUC        ;MAY BE DRIVE NAME, CVT TO UPPER CASE
  1096.     CPI    'A'        ;ALPHA?
  1097.     JC    ISNUM        ;JUMP TO GET USER # IF NOT
  1098.     SUI    'A'-1        ;YES, CONVERT FROM ASCII TO #
  1099.     DCX    D        ;BACK UP FCB POINTER TO DR FIELD
  1100.     STAX    D        ;STORE DRIVE # INTO FCB
  1101.     INX    D        ;PASS POINTER OVER DRV
  1102.     INX    H        ;SKIP DRIVE SPEC IN TEXT
  1103. ISNUM:    MOV    A,M        ;FETCH NEXT
  1104.     INX    H
  1105.            CPI    ':'        ;DU DELIMITER?
  1106.     RZ            ;DONE THEN
  1107.     DCX    H        ;NOPE, BACK UP TEXT POINTER
  1108.     MVI    B,0        ;GOT A DIGIT, INIT USER VALUE
  1109. ULOOP:    MOV    A,B        ;GET ACCUMULATED USER #
  1110.     ADD    A        ;* 10 FOR NEW DIGIT
  1111.     ADD    A
  1112.     ADD    B
  1113.     ADD    A
  1114.     MOV    B,A        ;BACK TO B
  1115.     MOV    A,M        ;GET TEXT CHAR
  1116.     SUI    '0'        ;MAKE BINARY
  1117.     ADD    B        ;ADD TO USER #
  1118.     MOV    B,A        ;UPDATED USER #
  1119.     INX    H        ;SKIP OVER IT
  1120.     MOV    A,M        ;GET NEXT
  1121.     CPI    ':'        ;END OF SPEC?
  1122.     JNZ    ULOOP        ;JUMP IF NOT
  1123.     INX    H        ;YEP, RETURN TXT POINTER PAST DU:
  1124.     RET
  1125. ;
  1126. ; GETPS GETS THE PRIMARY AND SECONDARY NAMES INTO THE FCB.
  1127. ; ENTRY HL    TEXT POINTER
  1128. ; EXIT    HL    CHARACTER FOLLOWING SECONDARY NAME (IF PRESENT)
  1129. ;
  1130. GETPS:    MVI    C,8        ;MAX LENGTH OF PRIMARY NAME
  1131.     MVI    B,0        ;INIT COUNT OF '?'
  1132.     CALL    GETNAM        ;PACK PRIMARY NAME INTO FCB
  1133.     MOV    A,M        ;SEE IF TERMINATED BY A PERIOD
  1134.     CPI    '.'
  1135.     RNZ            ;NOPE - SECONDARY NAME NOT GIVEN
  1136.                 ;RETURN DEFAULT (BLANKS)
  1137.     INX    H        ;YUP - MOVE TEXT POINTER OVER PERIOD
  1138. FTPOINT:MOV    A,C        ;YUP - UPDATE FCB POINTER TO SECONDARY
  1139.     ORA    A
  1140.     JZ    GETFT
  1141.     INX    D
  1142.     DCR    C
  1143.     JMP    FTPOINT
  1144. GETFT:    MVI    C,3        ;MAX LENGTH OF SECONDARY NAME
  1145.     CALL    GETNAM        ;PACK SECONDARY NAME INTO FCB
  1146.     RET
  1147. ;
  1148. ; GETNAM COPIES A NAME FROM THE TEXT POINTER INTO THE FCB FOR
  1149. ; A GIVEN MAXIMUM LENGTH OR UNTIL A DELIMITER IS FOUND, WHICH
  1150. ; EVER OCCURS FIRST.  IF MORE THAN THE MAXIMUM NUMBER OF
  1151. ; CHARACTERS IS PRESENT, CHARACTER ARE IGNORED UNTIL A
  1152. ; A DELIMITER IS FOUND.
  1153. ; ENTRY HL    FIRST CHARACTER OF NAME TO BE SCANNED
  1154. ;    DE    POINTER INTO FCB NAME FIELD
  1155. ;    C    MAXIMUM LENGTH
  1156. ; EXIT    HL    POINTING TO TERMINATING DELIMITER
  1157. ;    DE    NEXT EMPTY BYTE IN FCB NAME FIELD
  1158. ;    C    MAX LENGTH - NUMBER OF CHARACTERS TRANSFERED
  1159. ;
  1160. GETNAM: CALL    GETCH        ;ARE WE POINTING TO A DELIMITER YET?
  1161.     RZ            ;IF SO, NAME IS TRANSFERED
  1162.     INX    H        ;IF NOT, MOVE OVER CHARACTER
  1163.     CPI    '*'        ;AMBIGIOUS FILE REFERENCE?
  1164.     JZ    AMBIG        ;IF SO, FILL THE REST OF FIELD WITH '?'
  1165.     CPI    '?'        ;AFN REFERENCE?
  1166.     JNZ    NOTQM        ;SKIP IF NOT
  1167.     INR    B        ;ELSE BUMP AFN COUNT
  1168. NOTQM:    CALL    CVTUC        ;IF NOT, CONVERT TO UPPER CASE
  1169.     STAX    D        ;AND COPY INTO NAME FIELD
  1170.     INX    D        ;INCREMENT NAME FIELD POINTER
  1171.     DCR    C        ;IF NAME FIELD FULL?
  1172.     JNZ    GETNAM        ;NOPE - KEEP FILLING
  1173.     JMP    GETDEL        ;YUP - IGNORE UNTIL DELIMITER
  1174. AMBIG:    MVI    A,'?'        ;FILL CHARACTER FOR WILD CARD MATCH
  1175. FILLQ:    STAX    D        ;FILL UNTIL FIELD IS FULL
  1176.     INX    D
  1177.     INR    B        ;INCREMENT COUNT OF '?'
  1178.     DCR    C
  1179.     JNZ    FILLQ        ;FALL THRU TO INGORE REST OF NAME
  1180. GETDEL: CALL    GETCH        ;POINTING TO A DELIMITER?
  1181.     RZ            ;YUP - ALL DONE
  1182.     INX    H        ;NOPE - IGNORE ANTOHER ONE
  1183.     JMP    GETDEL
  1184. ;
  1185. ; GETCH GETS THE CHARACTER POINTED TO BY THE TEXT POINTER
  1186. ; AND SETS THE ZERO FLAG IF IT IS A DELIMITER.
  1187. ; ENTRY HL    TEXT POINTER
  1188. ; EXIT    HL    PRESERVED
  1189. ;    A    CHARACTER AT TEXT POINTER
  1190. ;    Z    SET IF A DELIMITER
  1191. ;
  1192. GETCH:    MOV    A,M        ;GET THE CHARACTER, TEST FOR DELIM
  1193. ;
  1194. ; GLOBAL ENTRY: TEST CHAR IN A FOR FILENAME DELIMITER
  1195. ;
  1196. FNDELM:    CPI    '/'
  1197.     RZ
  1198.     CPI    '.'
  1199.     RZ
  1200.     CPI    ','
  1201.     RZ      
  1202.     CPI    ' '
  1203.     RZ
  1204.     CPI    ':'
  1205.     RZ
  1206.     CPI    '='
  1207.     RZ
  1208.     ORA    A        ;SET ZERO FLAG ON END OF TEXT
  1209.     RET
  1210. ;
  1211. ; BDOS ENTRY: PRESERVES BC, DE.  IF SYSTEM CALL IS A FILE
  1212. ;           FUNCTION, THIS ROUTINE LOGS INTO THE DRIVE/
  1213. ;          USER AREA SPECIFIED, THEN LOGS BACK AFTER
  1214. ;          THE CALL.
  1215. ;
  1216. BDOS:    CALL    FILFCK        ;CHECK FOR A FILE FUNCTION
  1217.     JNZ    BDOS1        ;JUMP IF NOT A FILE FUNCTION
  1218.     CALL    GETDU        ;GET DRIVE/USER
  1219.     SHLD    SAVEDU
  1220.     LDAX    D        ;GET FCB'S DRIVE
  1221.     STA    FCBDRV        ;SAVE IT
  1222.     DCR    A        ;MAKE 0-RELATIVE
  1223.     JM    BDOS0        ;IF NOT DEFAULT DRIVE, JUMP
  1224.     MOV    H,A        ;COPY TO H
  1225. BDOS0:    XRA    A        ;SET FCB TO DEFAULT
  1226.     STAX    D
  1227.     DCX    D        ;GET FCB'S USER #
  1228.     LDAX    D
  1229.     MOV    L,A
  1230.     INX    D        ;RESTORE DE
  1231.     CALL    SETDU        ;SET FCB'S USER
  1232. ;
  1233. ; NOTE THAT UNSPECIFIED USER # (VALUE=0FFH) BECOMES
  1234. ; A GETUSR CALL, PREVENTING AMBIGUITY.
  1235.     CALL    BDOS1        ;DO USER'S SYSTEM CALL
  1236.     PUSH    PSW        ;SAVE RESULT
  1237.     PUSH    H
  1238.     LDA    FCBDRV        ;RESTORE FCB'S DRIVE
  1239.     STAX    D
  1240.     LHLD    SAVEDU        ;RESTORE PRIOR DRIVE/USER
  1241.     CALL    SETDU
  1242.     POP    H        ;RESTORE BDOS RESULT REGISTERS
  1243.     POP    PSW
  1244.     RET
  1245. ;
  1246. ; LOCAL VARIABLES FOR BDOS REPLACEMENT ROUTINE
  1247. ;
  1248. SAVEDU:    DW    0        ;SAVED DRIVE,USER
  1249. FCBDRV:    DB    0        ;FCB'S DRIVE
  1250. DMADR:    DW    80H        ;CURRENT DMA ADRS
  1251. ;
  1252. BDOS1:    PUSH    D
  1253.     PUSH    B
  1254.     MOV    A,C        ;DOING SETDMA?
  1255.     CPI    SDMAF
  1256.     JNZ    BDOS1A        ;JUMP IF NOT
  1257.     XCHG            ;YEP, KEEP A RECORD OF DMA ADDRESSES
  1258.     SHLD    DMADR
  1259.     XCHG
  1260. BDOS1A:    CALL    SYSTEM
  1261.     POP    B
  1262.     POP    D
  1263.     RET
  1264. ;
  1265. ; GET DRIVE, USER: H=DRV, L=USER
  1266. ;
  1267. GETDU:    PUSH    B        ;DON'T MODIFY BC
  1268.     PUSH    D
  1269.     MVI    C,GSUSER    ;GET USER #
  1270.     MVI    E,0FFH
  1271.     CALL    BDOS1
  1272.     PUSH    PSW        ;SAVE IT
  1273.     MVI    C,GETDRF    ;GET DRIVE
  1274.     CALL    BDOS1
  1275.     MOV    H,A        ;DRIVE RETURNED IN H
  1276.     POP    PSW
  1277.     MOV    L,A        ;USER IN L
  1278.     POP    D
  1279.     POP    B        ;RESTORE CALLER'S BC
  1280.     RET
  1281. ;
  1282. ; SET DRIVE, USER: H=DRV, L=USER
  1283. ;
  1284. SETDU:    PUSH    B        ;DON'T MODIFY BC
  1285.     PUSH    D
  1286.     PUSH    H        ;SAVE INFO
  1287.     MOV    E,H        ;DRIVE TO E
  1288.     MVI    C,SELDF        ;SET IT
  1289.     CALL    BDOS1
  1290.     POP    H        ;RECALL INFO
  1291.     PUSH    H
  1292.     MOV    E,L        ;USER # TO E
  1293.     MVI    C,GSUSER
  1294.     CALL    BDOS1        ;SET IT
  1295.     POP    H
  1296.     POP    D
  1297.     POP    B
  1298.     RET
  1299. ;
  1300. ; CHECK FOR FILE-FUNCTION: OPEN, CLOSE, READ RANDOM, WRITE
  1301. ;    RANDOM, READ SEQUENTIAL, WRITE SEQUENTIAL.
  1302. ;            
  1303. FILFCK:    MOV    A,C        ;GET FUNCTION #
  1304.     CPI    OPENF
  1305.     RZ
  1306.     RC            ;IGNORE LOWER FUNCTION #'S
  1307.     CPI    CLOSEF        ;(THEY'RE NOT FILE-RELATED)
  1308.     RZ
  1309.     CPI    READF
  1310.     RZ
  1311.     CPI    WRITEF
  1312.     RZ
  1313.     CPI    RRAND
  1314.     RZ
  1315.     CPI    WRAND
  1316.     RZ
  1317.     CPI    FSRCHF
  1318.     RZ
  1319.     CPI    FSRCHN
  1320.     RZ
  1321.     CPI    ERASEF
  1322.     RZ
  1323.     CPI    CREATF
  1324.     RZ
  1325.     CPI    FILSZF
  1326.     RZ
  1327.     CPI    SRAND
  1328.     RET
  1329. ;
  1330. ; CONVERT CHAR TO UPPER CASE
  1331. ;
  1332. CVTUC:    CPI    'a'        ;CHECK LO BOUND
  1333.     RC
  1334.     CPI    'z'+1        ;CHECK HI
  1335.     RNC
  1336.     SUI    20H        ;CONVERT
  1337.     RET
  1338. ;
  1339. ; CHECK FOR HEX FILETYPE IN FCB NAME
  1340. ;
  1341. HEXCHK:    PUSH    H
  1342.     PUSH    D
  1343.     PUSH    B
  1344.     MVI    B,3        ;TYPE IS 3 CHARS
  1345.     LXI    D,DFCB+9    ;POINT DE TO TYPE FIELD
  1346.     LXI    H,HEXTYP    ;POINT HL TO "COM"
  1347. HEXLOP:    LDAX    D
  1348.     ANI    7FH        ;IGNORE ATTRIBUTES
  1349.     CMP    M
  1350.     INX    H
  1351.     INX    D
  1352.     JNZ    HEXIT        ;JUMP IF NOT COM
  1353.     DCR    B
  1354.     JNZ    HEXLOP
  1355. HEXIT:    POP    B        ;Z REG HAS RESULT
  1356.     POP    D
  1357.     POP    H
  1358.     RET
  1359. ;
  1360. HEXTYP:    DB    'HEX'
  1361. ;
  1362. ; ROUTINE TO RETURN USER # WITHOUT DISTURBING REGISTERS
  1363. ;
  1364. GETUSR:    PUSH    H
  1365.     PUSH    D
  1366.     PUSH    B
  1367.     MVI    C,GSUSER
  1368.     MVI    E,0FFH
  1369.     CALL    BDOS
  1370.     POP    B
  1371.     POP    D
  1372.     POP    H
  1373.     RET
  1374. ;
  1375. ; ROUTINE TO RETURN DRIVE # WITHOUT DISTURBING REGISTERS
  1376. ;
  1377. GETDSK:    PUSH    H
  1378.     PUSH    D
  1379.     PUSH    B
  1380.     MVI    C,GETDRF
  1381.     CALL    BDOS
  1382.     POP    B
  1383.     POP    D
  1384.     POP    H
  1385.     RET
  1386. ;
  1387. ; THESE ARE THE INITIAL VALUES OF THE VARIABLES, AND
  1388. ; ARE MOVED INTO THE VARIABLES AREA BY THE SETUP ROUTINE.
  1389. ; IF YOU ADD VARIABLES, BE SURE TO ADD THEIR INTIAL VALUE
  1390. ; INTO THIS TABLE IN THE ORDER CORRESPONDING TO THEIR
  1391. ; OCCURANCE IN THE VARIABLES SECTION.
  1392. ;
  1393. VARSET:    DW    0            ;BIAS
  1394.     DW    0            ;HILOAD
  1395.     DW    0            ;HIPC
  1396.     DB    0            ;CKSUM
  1397.     DW    CMDBUF            ;CMDPTR
  1398.     DB    0            ;BUFPTR
  1399.     DB    0            ;LODFLG
  1400.     DW    CMDBUF            ;FILBUF
  1401.     DW    0            ;OFFSET
  1402.     DW    0            ;LODADR
  1403.     DB    0,0,'           '    ;OUTNAM
  1404.     DW    0            ;RECCNT
  1405.     DW    0            ;BYTCNT
  1406.     DB    0            ;COMFLG
  1407.     DW    0            ;COMSIZ
  1408.     DB    0            ;OUTFLG
  1409. ;
  1410. VARLEN    EQU    $-VARSET    ;DEFINE LENGTH OF INIT TABLE
  1411. ;
  1412. ; WORKING VARIABLES
  1413. ;
  1414. VARS    EQU    $        ;DEFINE VARIABLES AREA START
  1415. ;
  1416. BIAS:    DS    2        ;LOAD OFFSET
  1417. HILOAD:    DS    2        ;HIGHEST TRUE LOAD ADDRESS
  1418. HIPC:    DS    2        ;HIGHEST PC
  1419. CKSUM:    DS    1        ;RECORD CHECKSUM
  1420. CMDPTR:    DS    2        ;COMMAND LINE POINTER
  1421. BUFPTR:    DS    1        ;INPUT BUFFER POINTER
  1422. LODFLG:    DS    1        ;SOMETHING-LOADED FLAG
  1423. FILBUF:    DS    2        ;FILE BUFFER LOCATION
  1424. OFFSET:    DS    2        ;LOAD OFFSET INTO BUFFER
  1425. LODADR:    DS    2        ;LOAD ADDRESS
  1426. OUTNAM:    DS    13        ;OUTPUT DRIVE+NAME
  1427. RECCNT:    DS    2        ;OUTPUT FILE RECORD COUNT
  1428. BYTCNT:    DS    2        ;OUTPUT FILE BYTES LOADED  COUNT
  1429. COMFLG:    DS    1        ;FLAGS COM FILE ENCOUNTERED
  1430. COMSIZ:    DS    2        ;SIZE OF A LOADED COM FILE
  1431. OUTFLG:    DS    1        ;FLAGS AN "=" PRESENT IN CMD LINE
  1432. ;
  1433. ; END OF WORKING VARIABLES
  1434. ;
  1435. ;
  1436. ;
  1437. ; STACK STUFF
  1438. ;
  1439. SPSAVE:    DS    2        ;SYSTEM STACK PNTR SAVE
  1440. ;
  1441. ;
  1442.     DS    100        ;50-LEVEL STACK
  1443. ;
  1444. STACK    EQU    $
  1445. CMDBUF    EQU    $        ;COMMAND BUFFER LOCATION
  1446. ;
  1447. ;
  1448.     END
  1449.