home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / jsage / znode3 / asm / myload.lbr / MYLOAD.ZZ0 / MYLOAD.Z80
Encoding:
Text File  |  1990-02-17  |  24.5 KB  |  841 lines

  1.     TITLE    "MYLOAD - Mload look-alike for ZCPR 3.x and NZ-COM"
  2. ;========================================================================
  3. ;  M Y L O A D  -  MLOAD for NZ-COM and ZCPR 3.x
  4. ;------------------------------------------------------------------------
  5. ; This program was developed out of frustration with other MLOAD programs
  6. ; which are supposed to overlay COM files with HEX overlays.  It senses
  7. ; an extended ZCPR3 Environment Descriptor and protects the CPR.  This
  8. ; somewhat limits the size of files which can be handled, but operates
  9. ; faster in most cases.
  10. ;                17 February 1990    Harold F. Bower
  11. ; Revisions:
  12. ;  17 Feb 90    1.0 - First Release version            HFB
  13. ;  16 Sep 89 to 17 Feb 90 - Test Versions 0.2 - 0.5        HFB
  14. ;------------------------------------------------------------------------
  15. ; The syntax for MYLOAD is:
  16.  
  17. ;   MYLOAD [dir][comfil[.com][=][dir][oldcom[.hex]][,fil1[.hex]][,...]
  18.  
  19. ; If no destination file is specified, the name of the first input file
  20. ; is taken for the output file.  If the first specified file is of type
  21. ; HEX, then a simple HEX load is assumed, followed by optional HEX over-
  22. ; lays.  Addresses are validated to insure that no HEX overlay specifies
  23. ; an address less than 100H (if overlaying COM) or the first HEX load
  24. ; address if loading a HEX file.
  25. ;=======================================================================
  26.  
  27. VER    EQU    10        ; First Test Version
  28. rev    equ    ' '        ; Bug fix version
  29.  
  30. ;.....
  31. ;  CP/M Equates
  32.  
  33. WBOOT    EQU    0
  34. BDOS    EQU    5
  35. FCB    EQU    005CH
  36. FCB2    EQU    006CH
  37. BUFF    EQU    0080H
  38.  
  39. ; Character and Miscellaneous Equates
  40.  
  41. BELL    EQU    07H
  42. CR    EQU    0DH
  43. FF    EQU    0CH
  44. LF    EQU    0AH
  45.  
  46. NO    EQU    0
  47. YES    EQU    NOT NO
  48.  
  49.  
  50. ; Set Public equates to "Fool" linkers into using BDOS instead of BIOS I/O
  51.  
  52.     PUBLIC    COUT, COUT7    ; BOUT call will be COUT to SYSLIB routines
  53.  
  54. ; From VLIB Get..
  55.  
  56.     EXT    Z3VINIT, VPRINT
  57.  
  58. ; From Z3LIB Get..
  59.  
  60.     EXT    Z3LOG, WHRENV, ZPRSFN, GETQUIET, @SDELM, DUTDIR
  61.  
  62. ; From SYSLIB Get..
  63.  
  64.     EXT    CODEND, RETUD, LOGUD, INITFCB, SETDMA
  65.     EXT    COMPBC, COMPHD, CIN, CAPS
  66.     EXT    BOUT, PFN2, CRLF, PAFDC, PHL4HC, PHLFDC
  67.     EXT    F$MAKE, F$OPEN, F$CLOSE, F$READ, F$WRITE, F$EXIST, F$DELETE
  68.  
  69. ;=====================================================================
  70. ;         S T A R T    T H E    P R O G R A M
  71. ;=====================================================================
  72.  
  73.     JP    START        ; Bypass header and start execution
  74.  
  75.     DEFB    'Z3ENV'        ; This is a ZCPR3 Utility
  76.     DEFB    1        ; External Environment Descriptor
  77. ENVADR:    DEFW    0001        ; Set Non-zero to force search
  78.     DEFW    0000        ; Filler for Type 4 Header
  79.     DEFB    'MYLOAD  '    ; Use this Configuration File w/ZCNFG
  80.  
  81. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  82. ;        C o n f i g u r a t i o n    S e c t i o n
  83. ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  84.  
  85. ZQUIET:    DEFB    YES        ; Set YES to use Z3 Quiet flag if ZCPR 3.x
  86.                 ;  Environment Descriptor located
  87. SILENT:    DEFB    NO        ; Set YES to be Quiet, NO to be verbose
  88. USEBEL:    DEFB    YES        ; Set YES to ring bell on Errors, Else NO
  89.  
  90. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  91. ; Begin program Execution
  92.  
  93. START:    LD    HL,OFCB        ; Clear workspace RAM
  94.     LD    E,L
  95.     LD    D,H
  96.     INC    DE
  97.     LD    BC,STACK+1-OFCB
  98.     LD    (HL),0
  99.     LDIR
  100.     LD    (STACK),SP    ; Save entry stack
  101.     LD    SP,STACK    ; .and set up a local one
  102.     CALL    RETUD        ; Get the current Drive and User
  103.     LD    (CUSER),BC    ; ..and save locally
  104.     LD    HL,(BDOS+1)    ; Get the BDOS entry address
  105.     CALL    WHRENV        ; .and try to locate an ENV above there
  106.     LD    (ENVADR),HL    ; ..save in header
  107.     LD    A,H
  108.     OR    L        ; Set Zero Flag based on ENV presence
  109.     LD    A,(SILENT)    ; .get local Silent flag
  110.     LD    (QUIET),A    ; ..and save as local Quiet flag
  111.     JR    Z,NOENV        ; Bypass next checks if No Env
  112.  
  113. ; We have a Z-System.  Initialize Libraries and maybe reset Quiet flag
  114.  
  115.     CALL    Z3VINIT        ; If we have an ENV, Initialize Lib routines
  116.     LD    A,(ZQUIET)    ; Should we use the Z3 Quiet Flag?
  117.     OR    A
  118.     JR    Z,NOZQT        ; ..jump if Not
  119.     CALL    GETQUIET    ; Else get the Z-System Quiet Flag
  120.     LD    (QUIET),A    ; ..and use that one
  121.  
  122. ; Test for extended Environment.  Return or calculate addresses
  123.  
  124. NOZQT:    EX    DE,HL        ; Put ENV addr in DE
  125.     LD    HL,8        ; .and offset to Extended flag
  126.     ADD    HL,DE
  127.     BIT    7,(HL)        ; Is it Extended?
  128.     JR    Z,NOENV        ; ..jump if not to calculate CPR Base
  129.     LD    HL,3FH        ; Else offset to CPR Base addr
  130.     ADD    HL,DE        ; Point to it
  131.     LD    E,(HL)        ; .and retrieve
  132.     INC    HL
  133.     LD    D,(HL)
  134.     EX    DE,HL        ; Move CPR Base addr to HL
  135.     JR    HAVBAS        ; ..and jump to save it
  136.  
  137. ; No Z3 Environment, calculate the base of CCP/CPR
  138.  
  139. NOENV:    LD    HL,(WBOOT+1)    ; Get Vector to BIOS WB vector
  140.     LD    DE,-1603H    ; .set negative offset to CPR Base
  141.     ADD    HL,DE        ; ..and calculate
  142. HAVBAS:    EX    DE,HL        ; Put the results in DE
  143.     LD    HL,(BDOS+1)    ; ..and see if RSX present
  144.     CALL    COMPHD        ; Is CPR Base above BDOS vector?
  145.     JR    C,HAVRSX    ; ..jump if so to save RSX entry vector
  146.     EX    DE,HL        ; Else put CPR base addr back in HL
  147. HAVRSX:    LD    (TOPADR),HL    ; Store the Base of OS (CPR or RSX)
  148.  
  149. ; Copy Default Command Buffer to local storage to save Command Tail
  150.  
  151.     CALL    CODEND        ; Get base of Buffer space
  152.     LD    E,L        ; .put to DE
  153.     LD    D,H
  154.     INC    H        ; ..offset by one sector worth
  155.     LD    (BASADR),HL    ; Save pointer to User base
  156.     LD    (WRKPTR),HL    ; .as base of Work Area
  157.     LD    (TOPFIL),HL    ; ..and as the top of Work Area
  158.     LD    HL,BUFF        ; Point source to Default Buffer
  159.     LD    BC,128
  160.     LDIR            ; ..and copy Command tail to buffer
  161.  
  162. ; Everything basically set up.  Initialize Terminal and print signon banner
  163.  
  164.     CALL    VPRINT
  165.     DEFB    CR,LF,1,'MYLOAD',2,'  Ver ',VER/10+'0','.',VER MOD 10 +'0',rev
  166.     DEFB    ' - by Harold F. Bower    17 Feb 90'
  167.     DEFB    CR,LF,LF,0
  168.  
  169. ; Check for Help Request
  170.  
  171.     LD    HL,FCB+1    ; Point to first FCB
  172.     LD    A,(HL)
  173.     CP    '/'        ; Is it a Help request?
  174.     JP    NZ,START0    ; ..jump if not
  175.  
  176. HELP:    CALL    VPRINT
  177.     DEFB    1,'Purpose:',2,'  Load Hex File, or Overlay COM with HEX '
  178.     DEFB    'file(s)',CR,LF,LF,1,' Syntax:',2,CR,LF
  179.     DEFB    '  (file specs may contain DU: or, with ZCPR3, DIR:)',CR,LF,LF
  180.     DEFB    '   MYLOAD //            <-- Print this message',CR,LF
  181.     DEFB    '   MYLOAD prog            <-- Load prog.HEX to prog.COM'
  182.     DEFB    CR,LF
  183.     DEFB    '   MYLOAD prog,prog1,..        '
  184.     DEFB    '<-- Overlay prog.COM w/prog1.HEX',CR,LF
  185.     DEFB    '                    or load prog.HEX then over-',CR,LF
  186.     DEFB    '                    lay with prog1.HEX',CR,LF
  187.     DEFB    '   MYLOAD prog2=prog1.prl,prog2,..    '
  188.     DEFB    '<-- Overlay prog1.PRL with',CR,LF
  189.     DEFB    '                    prog2.HEX forming prog2.COM'
  190.     DEFB    0
  191. EXIT:    CALL    CRLF        ; Give a New Line
  192.     LD    BC,(CUSER)    ; Get Current Drive and User
  193.     CALL    LOGUD        ; ..and restore
  194.     LD    SP,(STACK)
  195.     RET
  196.  
  197. ; Start program by printing some statistics
  198.  
  199. START0:    LD    A,(QUIET)    ; Operate Quietly?
  200.     OR    A
  201.     JR    NZ,STRT0V    ; ..don't print this if so
  202.     CALL    VPRINT
  203.     DEFB    '   Base of Output Buffer = ',0
  204.     LD    HL,(BASADR)
  205.     CALL    PHL4HC
  206.     CALL    CRLF
  207.     CALL    VPRINT
  208.     DEFB    '   Top of Output Buffer  = ',0
  209.     LD    HL,(TOPADR)
  210.     CALL    PHL4HC
  211.     CALL    CRLF        ; Give a couple of lines separation
  212.     CALL    CRLF
  213.  
  214. ; Zero the entire buffer for "cleanliness"
  215.  
  216. STRT0V:    LD    DE,(BASADR)    ; Get Beginning of Buffer
  217.     LD    HL,(TOPADR)    ; .and top address in Memory
  218.     OR    A
  219.     SBC    HL,DE        ; ..then calculate the Buffer space
  220.     LD    C,L        ; Move count to BC
  221.     LD    B,H
  222.     LD    L,E        ; .and starting Addr to HL
  223.     LD    H,D
  224.     DEC    BC        ; ..down one count
  225.     INC    DE        ; ...and dest up one
  226.     LD    (HL),0        ; Set first byte to Zero
  227.     LDIR            ; ..and move it along
  228.  
  229.     LD    DE,FCB        ; Set up to parse the Command Tail
  230.     CALL    INITFCB        ; .initialize the FCB
  231.     CALL    CODEND        ; Get start of Command Tail
  232.     INC    HL        ; ..bypassing the Count byte
  233.     CALL    SKWSP        ; Skip over "White Space"
  234.     JP    Z,HELP        ; ..jump to Help if No arguments
  235.     XOR    A        ; .do DIR before DU
  236.     CALL    ZPRSFN        ; Parse the next token
  237.     PUSH    HL        ; ..save ptr to delimiter
  238.     LD    DE,OFCB        ; .to the Output FCB
  239.     CALL    INITFCB        ; ..initializing it first
  240.     LD    HL,FCB        ; Move from this FCB
  241.     LD    BC,16        ; Move just first 16 bytes
  242.     LDIR
  243.     LD    DE,OFCB+9    ; Check the Output file type
  244.     POP    HL        ; Retrieve delimiter addr
  245.     PUSH    HL        ; ..keeping on stack
  246.     LD    A,(HL)
  247.     CP    '='        ; Explicit Output file specified?
  248.     LD    HL,COMTYP    ; .prepare to set to COM
  249.     LD    BC,3
  250.     JR    NZ,STRT1V    ; ..jump to set COM type if Not explicit
  251.     LD    A,(DE)        ; Else get first char of file name
  252.     CP    ' '        ; Anything entered?
  253.     JR    NZ,START1    ; ..accept specified type if so
  254. STRT1V:    LDIR            ; Else move COM type to Output file
  255. START1:    POP    HL        ; Restore pointer to delimiter
  256.     LD    A,(HL)        ; .get the delimiter
  257.     CP    '='        ; Is an explicit output file specified?
  258.     JR    NZ,START2    ; ..bypass first HEX read if Not (default out)
  259.     INC    HL        ; Else bypass equal sign
  260.     CALL    SKWSP        ; .and bypass any space chars
  261.     JR    Z,START3    ; ..jumping to simple Load if EOL
  262.     LD    DE,FCB        ; Set up to parse next file name
  263.     XOR    A        ; .do DIR before DU
  264.     CALL    ZPRSFN        ; Parse
  265.     LD    DE,OFCB+1    ; .point to first char of File Name
  266.     LD    A,(DE)
  267.     CP    ' '        ; Anything there?
  268.     JR    NZ,START3    ; ..jump if we have an output file name
  269.     PUSH    HL        ; Else save input line pointer
  270.     LD    HL,FCB+1    ; .point to second file name
  271.     LD    BC,8
  272.     LDIR            ; ..and move 8-char name
  273.     POP    HL        ; Restore input line pointer
  274.     JR    START3        ; ..and continue on
  275.  
  276. ; If we come here, same root name used for input and output.  Set output
  277. ; file to current DU, and use specified one for source
  278.  
  279. START2:    LD    BC,(CUSER)    ; Get Current DU
  280.     LD    A,B        ; Load Drive
  281.     INC    A        ; .setting base 1..16
  282.     LD    (OFCB),A    ; ..save in Output FCB
  283.     LD    A,C        ; Load User
  284.     LD    (OFCB+13),A    ; .and save in Output FCB also
  285.  
  286. ; Input and output files now all set up
  287.  
  288. START3:    LD    (SCNPTR),HL    ; Save pointer to scan line
  289.     LD    DE,FCB+9    ; Check for COM type of first Input file
  290.     LD    HL,HEXTYP
  291.     LD    BC,3
  292.     CALL    COMPBC        ; Input file of type COM?
  293.     JP    Z,STAR5A    ; ..jump if HEX
  294.     LD    HL,COMTYP    ; (load COM ptr in case)
  295.     LD    A,(DE)        ; Else..
  296.     CP    ' '        ; .Was any type explicitly entered?
  297.     JR    NZ,START4    ; ..jump to load if so
  298.     LDIR            ; ..else set it to COM
  299.  
  300. ; See if the specified Input File exists as COM
  301.  
  302. START4:    CALL    SRCHF        ; Does the first file exist?
  303.     JR    Z,START5    ; ..jump if COM Not found to check HEX
  304.     LD    HL,0100H    ; Use this offset for Later HEX overlays
  305.     LD    (HOFFST),HL
  306.     OR    0FFH        ; ..and show it is set
  307.     LD    (HFLAG1),A
  308.     CALL    OPENIN        ; Else Open the file for Reading
  309.     JP    NZ,OPNERR    ; ..Jump to error if Problem
  310.     CALL    LODMSG        ; Print Loading message
  311.     LD    HL,(WRKPTR)    ; Get Base address
  312.  
  313. INPLOP:    LD    (WRKPTR),HL    ; Save working ptr
  314.     LD    (TOPFIL),HL    ; ..and top-of-file pointer
  315.     CALL    SETDMA        ; Set the Transfer Address
  316.     CALL    RDSEC        ; Read a sector there
  317.     JR    NZ,READY    ; ..jump to close file if EOF or Error
  318.     LD    BC,128        ; Offset to next sector
  319.     ADD    HL,BC
  320.     CALL    CKOVFL        ; Will we go too far?  (abort on Err)
  321.     JR    INPLOP        ; .loop if not
  322.  
  323. ; See if the specified Input File exists as HEX
  324.  
  325. START5:    CALL    QPRINT        ; Space in a little
  326.     DEFB    '   ',0
  327.     INC    DE
  328.     LD    A,(QUIET)
  329.     OR    A
  330.     CALL    Z,PFN2        ; Print the file name if Not quiet
  331.     DEC    DE
  332.     CALL    QPRINT
  333.     DEFB    ' Not Found...changing to HEX..',CR,LF,0
  334.     LD    HL,9        ; Advance to Type
  335.     ADD    HL,DE
  336.     PUSH    DE        ; Save FCB pointer
  337.     EX    DE,HL
  338.     LD    HL,HEXTYP    ; Point to HEX file type
  339.     LD    BC,3
  340.     LDIR            ; ..and move type field
  341.     POP    DE        ; Restore FCB pointer
  342. STAR5A:    CALL    SRCHF        ; .and try to find Hex version
  343.     JR    NZ,START6    ; ..jump to continue if File Found
  344.     CALL    NFERR        ; Else print error
  345.     JP    EXIT        ; ..and abort
  346.  
  347. START6:    CALL    OPENIN        ; Else try to open it
  348.     JP    NZ,OPNERR    ; ..abort with error if unable to open
  349.  
  350.     CALL    LODMSG        ; Else program exists..Announce it
  351.     CALL    RDHEX        ; ..and Load the Hex file
  352.  
  353. ; This is the main loop for loading overlays.  loops here til done
  354.  
  355. READY:    CALL    CLOSIN        ; Close the Input file, restoring defaults
  356. READY0:    LD    DE,FCB
  357.     CALL    INITFCB        ; Initialize the FCB for any overlay
  358.     LD    HL,(SCNPTR)    ; Get pointer into argument line
  359.     CALL    SKWSP        ; Scan for text
  360.     JR    Z,DONE        ; ..jump to Closing code if no more
  361.     XOR    A
  362.     CALL    ZPRSFN        ; Else parse the filename
  363.     LD    (SCNPTR),HL    ; ..and save the delimiter address
  364.  
  365.     LD    HL,9        ; Advance to Type
  366.     ADD    HL,DE
  367.     LD    A,(HL)        ; Get the first char of Type
  368.     CP    ' '        ; Anything entered?
  369.     JR    NZ,HAVTYP    ; ..jump if we have user-entered type
  370.     PUSH    DE        ; Else save FCB pointer
  371.     EX    DE,HL
  372.     LD    HL,HEXTYP    ; .Point to HEX file type
  373.     LD    BC,3
  374.     LDIR            ; ..and move HEX type field
  375.     POP    DE        ; Restore FCB pointer
  376.  
  377. HAVTYP:    CALL    SRCHF        ; Does the file exist?
  378.     JR    NZ,READY1    ; ..jump if Ok
  379.     CALL    NFERR        ; Else print an error
  380.     CALL    RESTOR        ; .restore defaults
  381.     JR    READY0        ; ..and back for more
  382.  
  383. READY1:    CALL    OPENIN        ; Try to open the file
  384.     JP    NZ,OPNERR    ; ..jumping to error if a problem
  385.  
  386.     CALL    OVLMSG        ; Announce this file
  387.     CALL    RDHEX        ; .then load the file
  388.     JR    READY        ; ..and back for more
  389.  
  390. ; All loading is done at this point.  Finish up the effort
  391.  
  392. DONE:    CALL    VPRINT        ; Print another statistic
  393.     DEFB    CR,LF,' Done.',0
  394.     CALL    QPRINT
  395.     DEFB    '  Saving ',0
  396.     LD    HL,(TOPFIL)    ; Calculate size of new image
  397.     LD    DE,(BASADR)
  398.     OR    A
  399.     SBC    HL,DE        ; ..and Top of all loads
  400.     JP    Z,NULFIL    ; Jump to Error Exit if No contents
  401.     PUSH    HL        ; .(save)
  402.     LD    A,(QUIET)    ; Print permitted?
  403.     OR    A
  404.     CALL    Z,PHLFDC    ; Print in decimal if so
  405.     CALL    QPRINT
  406.     DEFB    ' (',0
  407.     CALL    QPRHEX        ; ..and hex
  408.     CALL    QPRINT
  409.     DEFB    'H) Bytes to : ',0
  410.     LD    DE,OFCB
  411.     CALL    PRNAME
  412.     POP    HL        ; Get the value back
  413.  
  414. ; Now calculate the number of sectors to write
  415.  
  416.     LD    A,L        ; Get Low byte to A
  417.     LD    L,H        ; Number of pages to L
  418.     LD    H,0        ; ..nulling Hi byte
  419.     ADD    A,A        ; Shift MSB to Carry
  420.     ADC    HL,HL        ; .Mult pages by 2 for records and shift
  421.                 ; ..Carry to LSB of L
  422.     LD    C,L        ; Put record count in BC
  423.     LD    B,H
  424.     OR    A        ; Partial page?
  425.     JR    Z,NOPART    ; ..jump if not
  426.     INC    BC        ; Else bump record count by one
  427. NOPART:    LD    DE,OFCB        ; Now attempt to locate the file
  428.     CALL    SRCHF0        ; Does it exist?
  429.     JR    Z,DONE0        ; ..jump if not to make it
  430.  
  431. ; A search for the file showed that it exists.  Ask for replacement
  432.  
  433.     CALL    RING        ; File exists...wake up the operator
  434.     CALL    VPRINT        ; ..then message
  435.     DEFB    '    +++ File Exists...Replace it? (Y/[N]) : ',0
  436.     CALL    CIN        ; Get the answer
  437.     CALL    CAPS        ; ..in uppercase
  438.     CALL    COUT        ; Echo it
  439.     CALL    CRLF        ; ..and go to new line
  440.     CP    'Y'        ; Was it a YES?
  441.     JP    NZ,EXIT        ; ..exit if Not
  442.     CALL    F$DELETE    ; Else delete the file, fall thru to Make
  443.  
  444. ; The Destination File does not exist.  Create it and write the buffer.
  445.  
  446. DONE0:    CALL    F$MAKE        ; Create the file in current DU:
  447.     INC    A        ; Any Error?  (FF-->0)
  448.     JP    Z,MAKERR    ; ..jump to error exit if No Dir space
  449.     LD    HL,(BASADR)    ; Get the starting address
  450. OUTLOP:    LD    (WRKPTR),HL    ; ..save top of file
  451.     CALL    SETDMA        ; Set the Transfer Address
  452.     CALL    F$WRITE        ; Write a sector from there
  453.     JR    NZ,DONE1    ; ..jump to close file if Error
  454.     PUSH    BC        ; Save count
  455.     LD    BC,128        ; Offset to next sector
  456.     ADD    HL,BC
  457.     POP    BC        ; restore count
  458.     DEC    BC        ; Count down sector count
  459.     LD    A,B
  460.     OR    C        ; Are we finished?
  461.     JR    NZ,OUTLOP    ; ..loop if Not
  462.  
  463. DONE1:    PUSH    AF        ; Save status (0=Ok, else Error)
  464.     CALL    F$CLOSE        ; .close the file (good or bad)
  465.     POP    BC        ; ..and check for Close or Write errors
  466.     OR    B
  467.     JR    Z,DONEOK    ; Jump if No errors
  468.  
  469.     CALL    RING        ; We had errors, notify operator
  470.     CALL    VPRINT
  471.     DEFB    '  +++ Write or Close Errors..Erasing file!',0
  472.     CALL    F$DELETE
  473.     JR    EXITV        ; ..and quit
  474.  
  475. DONEOK:    CALL    VPRINT        ; Give status
  476.     DEFB    '  ..Ok',0
  477. EXITV:    JP    EXIT        ; ..and exit properly
  478.  
  479. ;---------------------------------------------------------------------------
  480. ;             U T I L I T Y    R O U T I N E S
  481. ;---------------------------------------------------------------------------
  482.  
  483. COUT7:    AND    7FH        ; Mask off MSB of print
  484. COUT:    JP    BOUT        ; Use BOUT for all COUT references
  485.  
  486. ;.....
  487. ; Skip over "White Space" delimiter chars in string addressed by HL.
  488. ;  Return Zero if End-Of-Line.
  489.  
  490. SKWSP:    CALL    @SDELM        ; Use New Z3LIB routine
  491.     RET    NZ
  492.     OR    A
  493.     RET    Z        ; Return Zero Set if EOL
  494.     INC    HL        ; Not EOL, so advance
  495.     JR    SKWSP        ; ..and loop
  496.  
  497. ;.....
  498. ; Read a Hex input file to the memory area addressed by HL
  499.  
  500. RDHEX:    CALL    GETBIN        ; Get a raw byte
  501.     CP    ':'        ; Start of record?
  502.     JR    NZ,RDHEX    ; ..loop til we have it
  503.     LD    D,0        ; Initialize the Checksum reg
  504.     CALL    GETBYT        ; Then get the count byte
  505.     LD    B,A        ; Else store in reg
  506.     ADD    A,D        ; Update cksum
  507.     LD    D,A
  508.     CALL    GETBYT        ; .High Address
  509.     LD    H,A
  510.     ADD    A,D        ; Update cksum
  511.     LD    D,A
  512.     CALL    GETBYT        ; ..Low Address    
  513.     LD    L,A
  514.     ADD    A,D
  515.     LD    D,A
  516.  
  517. ; Check for End-of-file Record
  518.  
  519.     LD    A,B        ; Are Count..
  520.     OR    H        ; .Hi Addr
  521.     OR    L        ; ..and Lo Addr all Zero?
  522.     RET    Z        ; Return if End
  523.  
  524. ; Check for Address Offset and set if not already
  525.  
  526.     LD    A,(HFLAG1)    ; Get Flag
  527.     OR    A        ; Is it set?
  528.     JR    NZ,RDHEX0    ; ..jump if so
  529.     CPL            ; Else change to 0FFH
  530.     LD    (HFLAG1),A    ; .save flag
  531.     LD    (HOFFST),HL    ; ..and offset value
  532.  
  533. RDHEX0:    PUSH    DE        ; Save checksum
  534.     LD    DE,(HOFFST)    ; Get offset value for ORG
  535.     XOR    A
  536.     SBC    HL,DE        ; Subtract from this block
  537.     JR    C,RDHXER    ; ..jump to Error if reverse ORG
  538.  
  539.     LD    DE,(BASADR)    ; Get Base of Buffer area
  540.     ADD    HL,DE        ; ..and add this record's address
  541.     PUSH    HL        ; Save the real load addr
  542.     LD    E,B        ; .move the count down
  543.     LD    D,0
  544.     ADD    HL,DE        ; ..and calculate the end
  545.     CALL    CKOVFL        ; Will we go too far?  (abort if so)
  546.     POP    HL        ; Restore Load pointer
  547.     POP    DE        ; ..and Checksum
  548.  
  549.     CALL    GETBYT        ; Skip over Type byte
  550.     ADD    A,D
  551.     LD    D,A
  552. RDHEX1:    CALL    GETBYT        ; Get a data byte
  553.     LD    (HL),A        ; .store
  554.     INC    HL        ; ..bump pointer
  555.     ADD    A,D        ; Add this byte to Checksum
  556.     LD    D,A        ; ..and save
  557.     DJNZ    RDHEX1        ; Count down, loop til done
  558.     CALL    GETBYT        ; Get the checksum byte
  559.     ADD    A,D        ; Same?
  560.     JP    NZ,CKSERR    ; ..jump to Checksum Error if Bad
  561.  
  562.     LD    DE,(WRKPTR)    ; Get the current working Top of buffer
  563.     CALL    COMPHD        ; Have we exceeded the old top of used mem?
  564.     JR    C,RDHEX        ; .loop if not
  565.     LD    (WRKPTR),HL    ; ..else save new top
  566.     LD    DE,(TOPFIL)    ; Get old top of Used Memory
  567.     CALL    COMPHD        ; Have we expanded the Image size?
  568.     JR    C,RDHEX        ; .loop if not
  569.     LD    (TOPFIL),HL    ; ..else save new Top
  570.     JR    RDHEX        ; ...then loop
  571.  
  572. ;.....
  573. ; Error Exit from Hex load.
  574.  
  575. RDHXER:    CALL    RING        ; Ring bell if possible
  576.     CALL    QPRINT        ; Else Print an Error message
  577.     DEFB    '   +++ Lower Bound Exceeded +++',0
  578.     RET            ; ..and return
  579.  
  580. ;.....
  581. ; Convert Hex char in A to binary digit in range 0..15
  582.  
  583. HEX2BIN: SUB    '0'        ; Subtract numeric bias
  584.     CP    10        ; In range 0..9?
  585.     RET    C        ; ..return if so
  586.     SUB    7        ; Subtract difference between 9 and A
  587.     RET            ; ..and quit
  588.  
  589. ;.....
  590. ; Search for the file addressed by ZCPR3 style FCB in DE
  591.  
  592. SRCHF:    LD    DE,FCB        ; Use Input FCB if entered here
  593. SRCHF0:    CALL    Z3LOG        ; Log into DU for file
  594.     JP    F$EXIST
  595.  
  596. ;.....
  597. ; Read a sector of the file to the current DMA address
  598.  
  599. RDSEC:    LD    DE,FCB        ; Point to the Input FCB
  600.     JP    F$READ        ; ..and read a sector
  601.  
  602. ;.....
  603. ; Open the file at the Input FCB
  604.  
  605. OPENIN:    LD    DE,FCB        ; Point to the Input FCB
  606. OPENF:    CALL    F$OPEN        ; ..and Open it
  607.     LD    HL,BUFF+128    ; Set ptr to force read in GETBIN
  608.     LD    (INPTR),HL
  609.     RET
  610.  
  611. ;.....
  612. ; Close the file at the input FCB and restore the current DU:
  613.  
  614. CLOSIN:    LD    DE,FCB        ; Point to the Input FCB
  615. CLOSF:    CALL    F$CLOSE        ; ..and Close it
  616. RESTOR:    LD    HL,BUFF        ; Get default DMA buffer
  617.     CALL    SETDMA        ; ..and Set Transfer Addr
  618.     LD    BC,(CUSER)    ; Get current DU:
  619.     JP    LOGUD        ; ..log it and return
  620.  
  621. ;.....
  622. ; Print Null-Length Error message and exit
  623.  
  624. NULFIL:    CALL    RING
  625.     CALL    VPRINT
  626.     DEFB    '  +++ Nothing to Save +++',0
  627.     JP    EXIT
  628.  
  629. ;.....
  630. ; Print Overlaying message followed by File ID
  631.  
  632. OVLMSG:    CALL    QPRINT        ; Announce this file
  633.     DEFB    '  Overlaying --> ',0
  634.     JR    PRNAME        ; ..then print file name
  635.  
  636. ;.....
  637. ; Print File name with Drive and User from Z3 FCB addressed by DE
  638.  
  639. LODMSG:    CALL    QPRINT        ; Announce this file
  640.     DEFB    '  Loading    --> ',0
  641. PRNAME:    LD    A,(QUIET)    ; Print permitted?
  642.     OR    A
  643.     RET    NZ        ; ..exit here if Not
  644. PRNAM1:    LD    A,(DE)
  645.     OR    A        ; Default?
  646.     JR    NZ,PRNAM2    ; ..jump if not
  647.     LD    A,(CUSER+1)    ; Else get current
  648.     INC    A
  649. PRNAM2:    DEC    A
  650.     LD    B,A        ; Put in the correct reg
  651.     LD    HL,13        ; .offset to User
  652.     ADD    HL,DE
  653.     LD    C,(HL)        ; .and get to right reg
  654.     RES    7,C        ; ..clear any MSB
  655.     CALL    DUTDIR        ; Check for any named DIR
  656.     JR    Z,PRNAM3    ; ..jump if Not to print DU:
  657.     PUSH    DE        ; Save ptr to FCB
  658.     LD    E,8        ; ..and set count
  659. PRNAML:    LD    A,(HL)        ; Get a char
  660.     INC    HL        ; .bumping ptr
  661.     CP    ' '        ; Is it a space?
  662.     CALL    NZ,COUT        ; ..print if not
  663.     DEC    E        ; Count down
  664.     JR    NZ,PRNAML    ; .loop til done
  665.     POP    DE
  666.     JR    PRNAM4        ; ..then rejoin code
  667.  
  668. PRNAM3:    LD    A,B        ; Print DU: by first getting Drive #
  669.     ADD    A,'A'
  670.     CALL    COUT        ; Print Drive Letter
  671.     LD    A,C        ; Get User #
  672.     CALL    PAFDC        ; ..and Print
  673. PRNAM4:    LD    A,':'
  674.     CALL    COUT
  675.     INC    DE
  676.     CALL    PFN2        ; Print File Name & Type
  677.     DEC    DE
  678.     JP    CRLF        ; .go to new line
  679.  
  680. ;.....
  681. ; Print File Not Found Error and Exit
  682.  
  683. NFERR:    CALL    RING
  684.     CALL    QPRINT        ; Print Not Found error and abort
  685.     DEFB    '  -- Can''t find : ',0
  686.     JR    PRNAME        ; Print name, Drive, User and return
  687.  
  688. ;.....
  689. ; Check for overflow of Address in HL (HL > TOPADR) aborting if so
  690.  
  691. CKOVFL:    PUSH    DE        ; Preserve regs
  692.     LD    DE,(TOPADR)    ; Get the base of protected memory
  693.     CALL    COMPHD        ; Is DE still greater than HL?
  694.     POP    DE        ; .(restore regs)
  695.     RET    C        ; ..return if so
  696.     CALL    RING
  697.     CALL    QPRINT        ; Else print an error
  698.     DEFB    '   +++ Memory Overflow at : ',0
  699.     CALL    QPRHEX
  700.     JR    ERREX0        ; ..and exit
  701.  
  702. ;.....
  703. ; Print Checksum Error message and Exit
  704.  
  705. CKSERR:    CALL    RING
  706.     CALL    QPRINT
  707.     DEFB    CR,LF,'   +++ Checksum Error +++',0
  708. ERREX0:    JP    EXIT        ; ..abort
  709.  
  710. ;.....
  711. ; File Open Error on file described by FCB in DE
  712.  
  713. OPNERR:    CALL    RING
  714.     CALL    QPRINT
  715.     DEFB    CR,LF,'  Can''t Open : ',0
  716. ERREX:    CALL    PRNAME        ; Print Name, Drive & User
  717.     JR    ERREX0        ; ..and take error exit
  718.  
  719. ;.....
  720. ; File Read Error on file described by FCB in DE
  721.  
  722. RDERR:    CALL    RING
  723.     CALL    QPRINT
  724.     DEFB    CR,LF,'  Error or EOF Reading : ',0
  725.     LD    DE,FCB
  726.     JR    ERREX
  727.  
  728. ;.....
  729. ; File creation error on completion
  730.  
  731. MAKERR:    CALL    RING
  732.     CALL    QPRINT
  733.     DEFB    CR,LF,'  No Directory Space for : ',0
  734.     JR    ERREX
  735.  
  736. ;.....
  737. ; Get a byte (2 ascii Hex chars) from the Input file.
  738. ;  Jump to Read Error and Exit if Read Error or Read Past EOF
  739. ; Uses: A,C
  740.  
  741. GETBYT:    CALL    GETBIN        ; Get a Hex char
  742.     CP    ' '        ; Is it a Control char (ff,cr,lf..)?
  743.     JR    C,GETBYT    ; ..loop back for another if so
  744.     CALL    HEX2BIN        ; Convert Hex to Binary
  745.     RLCA            ; Rotate
  746.     RLCA            ; .to
  747.     RLCA            ; ..High
  748.     RLCA            ; ...Nybble
  749.     LD    C,A        ; Preserve
  750.     CALL    GETBIN        ; Get next Hex digit
  751.     CALL    HEX2BIN        ; Convert to Binary
  752.     ADD    A,C        ; .and add Hi Nybble
  753.     RET
  754.  
  755. ;.....
  756. ; Return the next available byte from Sector Buffer in the A register.
  757. ;  Carry Flag is Set if attempt to read past End-of-File or Read Error.
  758.  
  759. GETBIN:    PUSH    HL        ; Preserve all regs
  760.     LD    HL,(INPTR)    ; Check the pointer for disk read
  761.     LD    A,H        ; Has it overflowed?
  762.     OR    A
  763.     JR    Z,GETBI0    ; ..jump if not to get the byte
  764.     PUSH    DE        ; Save rest of the regs
  765.     PUSH    BC
  766.     CALL    RDSEC        ; Else Read the disk and reset pointer
  767.     POP    BC        ; Restore regs
  768.     POP    DE
  769.     JR    NZ,RDERR    ; .jump if Error
  770.     LD    HL,BUFF        ; ..else reset the pointer
  771. GETBI0:    LD    A,(HL)        ; Get the next byte
  772.     INC    HL        ; .bump pointer
  773.     LD    (INPTR),HL    ; ..save
  774.     POP    HL        ; Restore all regs
  775.     RET
  776.  
  777. ;.....
  778. ; Ring the bell if so configured
  779.  
  780. RING:    LD    A,(USEBEL)    ; Get the flag
  781.     OR    A        ; Ring?
  782.     RET    Z        ; ..return if Not
  783.     LD    A,BELL        ; Else set up the char
  784.     JP    COUT        ; ..and do it!
  785.  
  786. ;.....
  787. ; Print message only if the ZCPR3 Quiet (or Silent) Flags permit
  788.  
  789. QPRINT:    LD    A,(QUIET)    ; Get the local quiet flag
  790.     OR    A        ; Print permitted?
  791.     JP    Z,VPRINT    ; ..jump to do it if so
  792.     EX    (SP),HL        ; Else get the string addr
  793.     XOR    A        ; .scan for this char
  794. QPLOOP:    CP    (HL)
  795.     INC    HL        ; ..bumping ptr
  796.     JR    NZ,QPLOOP    ; ...til found
  797.     EX    (SP),HL        ; Then restore regs & stack
  798.     RET            ; ..and return
  799.  
  800. ;.....
  801. ; Print the value in HL as 4 Hex chars if the Quiet flag permits
  802.  
  803. QPRHEX:    LD    A,(QUIET)    ; Are we quiet?
  804.     OR    A
  805.     RET    NZ        ; ..exit here if so
  806.     JP    PHL4HC        ; Else go print it
  807.  
  808. ;---------------------------------------------------------------------------
  809. ;           S T R I N G S    A N D    C O N S T A N T S
  810. ;---------------------------------------------------------------------------
  811.  
  812. COMTYP:    DEFB    'COM'
  813. HEXTYP:    DEFB    'HEX'
  814.  
  815. ;---------------------------------------------------------------------------
  816. ;         U N I N I T I A L I Z E D    D A T A    A R E A
  817. ;---------------------------------------------------------------------------
  818.  
  819.     DSEG            ; Uninitialized Data goes here
  820.  
  821. OFCB:    DEFS    36        ; Output File Control Block
  822. HFLAG1:    DEFS    1        ; 0=Offset Not set, FF=Offset Set
  823. HOFFST:    DEFS    2        ; Offset in buffer for Hex ORG compensation
  824. QUIET:    DEFS    1        ; Flag to operate in Quiet Mode
  825. INPTR:    DEFS    2        ; Pointer into input file buffer
  826. CUSER:    DEFS    2        ; Current User and Drive
  827. TUSER:    DEFS    2        ; Temporary User and Drive for File IO
  828. SCNPTR:    DEFS    2        ; Scan pointer into Command Tail
  829.  
  830. ; Pointers relating to the Buffer Image and Area
  831.  
  832. BASADR:    DEFS    2        ; Base of available RAM for work space
  833. TOPADR:    DEFS    2        ; Top of available RAM protecting CPR
  834. TOPFIL:    DEFS    2        ; Top address of Output File
  835. WRKPTR:    DEFS    2        ; Working pointer
  836.  
  837.     DEFS    64        ; Space for a stack
  838. STACK:    DEFS    2        ; Storage for entry stack pointer
  839.  
  840.     END
  841.