; HEXLOAD - Load a Hex file anywhere in memory ; TITLE 'HEXLOAD - Load a hex file, (1-12/17/82)' PAGE 60 ; ; This program will load a hex file at its org address, ; wherever this is in memory, as long as it does not overlay ; HLOAD itself. Usage is: ; ; HLOAD file-name ; ; If no file type is given, HEX is assumed. If the file is ; not found, the file (with the HEX type) is looked for on the ; A drive. After the file is loaded, control is returned to ; CP/M without a warm-start. ; ; HLOAD differs from the LOAD command of CP/M in that it does ; not create a .COM file, and it does not expect the .HEX file ; to be ORGed at 100H. It is useful for loading memory ; outside the normal CP/M boundaries. For example, I use it ; to load an extended CBIOS, by including the command ; ; HLOAD CBIOSOVR ; ; as my auto-start-up command. ; ; ; This program requires MAC and MACRO.LIB to assemble. ; ; ; Author: ; Don McClimans ; Inti Electronics Corporation ; 41 Washburn Pk. ; Rochester, NY 14620 ; 716-271-6280 ; ; Send all comments, bugs, etc. to the author at the above ; address. ; ; This program is in the public domain, and may be freely ; copied or used for any purpose. ; ; ; Revision List (reverse order): ; 1 12/17/82 Original design by DPM ; ; The standard Intel Hex format consists of lines like this: ; ; :nnaaaa00xxxxxxxx...xxkk ; ; where nn is the number of data bytes on the line, aaaa is ; the address to load at, xx are series of data bytes, and kk ; is a checksum. The checksum (kk) is formed by subtracting ; each byte of the line (including nn and each half of the ; address aaaa), in 8-bit arithmetic, from zero (thus the sum ; including kk should be zero). The final line of a file ; should contain a byte count of zero - the address field in ; this line gives the starting address, which is ignored by ; this program. ; ; ; Load Macro file ; MACLIB MACRO ;DR Standard MACRO library ; ; ; Start of Program ; ORG 100H START: LXI H,0 ;Get system stack pointer DAD SP LXI SP,STACK ;Set to use local stack PUSH H ;Preserve system stack pointer ; ; Try to open the file ; DISKIO OPEN,FCB ;Open file name as given CPI 0FFH ;Was open good JNZ FILEOPEN ;Yes - go process ;No - try same name with HEX MOVE HEXTYPE,FCBTYPE,3 ;file type DISKIO OPEN,FCB ;Try to open it again CPI 0FFH ;Was open good? JNZ FILEOPEN ;Yes - go process ;No - try same name, with HEX MVI A,1 ; on the A drive STA FCBDRIVE DISKIO OPEN,FCB ;Try to open it again CPI 0FFH ;Was open good? JNZ FILEOPEN ;Yes - go process ; PRINT 'File Not Found' ;Give errror message PRINT JMP RETCPM ; ; Entry here when file is open ; FILEOPEN: MVI A,0 ;Initialize variables STA LINENUM STA LINENUM+1 LXI H,BUFR+128 SHLD BUFPTR ; ; Entry here to start reading a new line ; Skip leading CR, LF, and blanks ; Quit on EOF (Ctrl-Z) ; NEWLINE: XRA A ;Zero the checksum STA CHECKSUM LXI H,LINENUM INR M ;Increment line number JNC SKIPTOCOLON INX H INR M SKIPTOCOLON: CALL READBYTE CPI CR JZ SKIPTOCOLON CPI LF JZ NEWLINE CPI ' ' JZ SKIPTOCOLON CPI EOFCH ;Is it ctrl-Z? JZ CLOSEFILE ;Yes - quit CPI STARTCH ;Is it a colon? JZ GETLENGTH ;Yes - go process BADNUM: PRINT 'HLOAD: Error in line ' DECOUT LINENUM PRINT JMP CLOSEFILE ; ; Entry here after colon read - get the number of data bytes ; GETLENGTH: CALL READBYTE STA NUMBUFF CALL READBYTE STA NUMBUFF+1 XRA A ;zero the third byte STA NUMBUFF+2 HEXIN NUMBUFF JC BADNUM ;Quit if errror CALL ADDTOCHECK STA NUMBYTES ANA A ;Was number of bytes zero? JZ CLOSEFILE ;Yes - we are done ; ; Length has been read - get the address to load at. ; CALL READBYTE STA NUMBUFF CALL READBYTE STA NUMBUFF+1 CALL READBYTE STA NUMBUFF+2 CALL READBYTE STA NUMBUFF+3 XRA A ;zero the fifth byte STA NUMBUFF+4 HEXIN NUMBUFF JC BADNUM ;Quit if errror SHLD LOADADR CALL ADDTOCHECK MOV A,H CALL ADDTOCHECK ; ; Address has ben read. Read the next two zero's, and throw ; away. ; CALL READBYTE CALL READBYTE ; ; Read all the data bytes and store them. ; ; Entry here to read the next byte and store it in the correct ; memory location. The NUMBYTES counter is decremented till ; it reaches zero ; NEXTBYTE: CALL READBYTE STA NUMBUFF CALL READBYTE STA NUMBUFF+1 XRA A ;zero the third byte STA NUMBUFF+2 HEXIN NUMBUFF JC BADNUM ;Quit if errror PUSH PSW ;Preserve registers LHLD LOADADR ;Get load address MOV A,H ;And check that it is not ANA A ;in HLOAD memory image JZ LOADOK ;High byte 00, so below HLOAD LXI D,HLOADEND ;Subtract last address of HLOAD DAD D JC LOADOK ; PRINT 'HLOAD: Load address overlays HLOAD in line ' DECOUT LINENUM PRINT POP PSW JMP CLOSEFILE ; LOADOK: POP PSW ;Restore byte LHLD LOADADR MOV M,A ;Store into memory INX H SHLD LOADADR CALL ADDTOCHECK LXI H,NUMBYTES ;Decrement Counter DCR M JNZ NEXTBYTE ;Loop till Zero ; ; Entry here when all bytes read ; Get the checksum and add it in - then check for zero ; checksum ; CALL READBYTE STA NUMBUFF CALL READBYTE STA NUMBUFF+1 XRA A ;Zero the third byte STA NUMBUFF+2 HEXIN NUMBUFF JC BADNUM CALL ADDTOCHECK LDA CHECKSUM ANA A JZ NEWLINE ; ; Entry here with checksum error ; PRINT 'HLOAD: Checksum error in line ' DECOUT LINENUM PRINT ;Fall into CLOSEFILE ; ; Entry here to close the file and return to CP/M ; CLOSEFILE: DISKIO CLOSE,FCB ; ; Entry here to return to CPM ; RETCPM: POP H ;Get system stack SPHL RET ; ; ; SUBROUTINES: ; ; READBYTE: Read a byte from the file. Return Ctrl-Z for all ; EOF's. Byte returned in A register - Uses all regs ; READBYTE: LHLD BUFPTR ;Get buffer pointer MOV A,H ;See if at 100H (past end) DCR A JNZ NOREAD ;No - so get next byte ; ;Yes - so read a sector DISKIO READ,FCB ORA A ;Read errors? JZ READOK ;No - go process sector DCR A ;Was A 1 meaning EOF? JNZ RDERR ;No - go process error MVI A,EOFCH ;Yes - return eof character RET ;and return ; RDERR: PRINT 'Read error at line' DECOUT LINENUM ;Print error message PRINT MVI A,EOFCH ;and return eof character RET ; READOK: LXI H,BUFR ;Start at beginning of buffer ; NOREAD: MOV A,M ;Get next byte INX H ;Increment pointer SHLD BUFPTR RET ; ; ADDTOCHECH - Add A register to CHECKSUM ; All registers preserved ; ADDTOCHECK: PUSH H PUSH PSW LXI H,CHECKSUM ADD M MOV M,A POP PSW POP H RET ; ; ; Equates ; STARTCH: EQU ':' ;Colon EOFCH: EQU 26 ;Ctrl-Z FCB: EQU 05CH ;Address of default FCB FCBTYPE: EQU 065H ;Address of type in FCB FCBDRIVE: EQU 05CH ;Address of drive number in FCB BUFR: EQU 080H ;Standard "DMA" buffer BDOS: EQU 5 ;BDOS call location ; ; Constants ; HEXTYPE: DB 'HEX' ;Default file type ; ; Variables ; DS 80H ;Local stack STACK: EQU $ LINENUM: DS 2 ;Number of lines read NUMBUFF: DS 5 ;Buffer for number conversion NUMBYTES: DS 1 ;Number of data bytes on line LOADADR: DS 2 ;Address to load next byte at CHECKSUM: DS 1 ;Working checksum BUFPTR: DS 2 ;Pointer into BUFR HLOADEND: EQU 1-$ ; ; End of program ; END START