title Reverse HEXCOM name ('COMHEX') ; Program converts a binary COM file into INTEL hex format. ; This allows copying files via PIP from one host to another. ; On the receiver host this file must be converted to binary ; again with the HEXCOM utility. ; It also allows converting COM files for loading by MLOAD ; defining optional offset ; Copyright (c) Werner Cirsovius ; Hohe Weide 44 ; D-20253 Hamburg 20 ; Tel.: (+49) 040/4223247 ; Version 2.3, December 1994 ; To get program running type: ; COMHEX {-Ohex_offset} {-Lhex_length} {drv:}filename{.ext} ; A new file will with same name and extension .HEX will be ; created. The default extension of the input file is .COM ; Default offset is 0100h but may be set to any other value ; Length will be determined by record length of file but may ; be set to any length less then record length _VERS macro db '2.3' endm _PRG macro db 'COMHEX' endm Lbytes equ 16 MaxRec equ 512 ; Record limit for 64kByte file _MaxArg equ 3 ; Max arguments .string equ 9 maclib base80 ext open,close,string,delete,creatd,closef,ascbyt ext hexin,emplin,filnam,modrec,mulrec,crlf,dskget ext cmdarg,getver,fparse,filsiz,rdfcb,rdbuf,rdbfp ext rndred,setdma ; Error exit ; $ILL.CPU: db 'Requires Z80 CPU',eot $ILL.OS: db 'Requires CP/M 3.x',eot Error: ld c,.string call BDOS ; Tell a bit jp OS ; ; ################## ; ### MAIN ENTRY ### ; ################## ; COMHEX: sub a ; Test right machine ld de,$ILL.CPU jp pe,Error call getver ; .. and right OS ld de,$ILL.OS jr c,Error ld sp,LocStk ; Get our stack ld hl,$ARGV ld de,CCPlen ld b,_MaxArg call cmdarg ; Get arguments from line ld de,$HELP jp c,comstr ; .. empty line dec a ; Fix for file call nz,GetOpt ; Get option if more ld hl,($ARGV) ; Get file pointer ld (P.PB),hl ld de,P.PB call fparse ; Parse source file ld de,$ILL.PARSE jp c,comstr ; .. parse error push af ; Save dot indicator ld hl,FCB ld de,X.FCB ld bc,.fdrv+.fname+.fext ldir ; Unpack file name pop af dec a ; Test extension jr z,extok ; .. got dor ld hl,$COM ld de,xFCBex ld bc,.fext ldir ; Set .COM extok: ld hl,$HEX ld de,FCBext ld bc,.fext ldir ; Set .HEX ld de,X.FCB call open ; Open .COM file ld de,$NO.COM jp c,comstr ; Should be here ld de,FCB call creatd ; Create .HEX file ld de,$NO.HEX jp c,comstr ; Should be possible ld hl,X.FCB ld (rdfcb),hl ; Set FCB ld hl,X.DMA ld (rdbuf),hl ; .. and buffer ld de,X.FCB call filsiz ; Get size of file ld de,$ILL.LEN ld (FilLen),hl jp nz,comdel ; .. invalid ld a,l or h ; Zero is also bad jp z,comdel ld bc,MaxRec+1 or a ; Check max length sbc hl,bc jp nc,comdel ; .. file too big ld de,X.FCB call close ; Close .COM file call open ; .. and re-open it ld a,(LENG) cp TRUE ; Test length selected push af call z,ckLeng ; Check valid length pop af call nz,gtDefLn ; Get default length call ckBIAS ; Check for offset jp c,comdel ; .. error ; ; ### MAIN PROCESSING LOOP ### ; rdnew: ld hl,(Length) ; Fetch remaining length ld bc,Lbytes ; Set default length or a sbc hl,bc ; Test in range jr nc,More.. ; .. yeap ld bc,(Length) ; Get remaining length inc c ; Test zero dec c jr z,..last ; .. yeap, that's all More..: ld hl,(CurPC) add hl,bc push hl ; Save new PC ld b,c ; Unpack the length call OutPC ; Output length and current PC pop hl ld (CurPC),hl ; Set new PC rdlop: call dskget ; Get a byte ex de,hl ld de,$ILL.FORM jp c,comdel ; .. inavlid format ex de,hl ld hl,Temp ld (hl),a ; Save character add a,c ; Build checksum ld c,a call ascbyt ; Put to file djnz rdlop ; .. loop ld hl,Temp ld a,c neg ; Build checksum ld (hl),a call ascbyt ld hl,$EOL ld bc,EOLlen ldir ; Close line ld de,$HEX.LINE ld b,null call emplin ; Empty line jr c,wrter ; Oops, error writing file ld hl,(Length) ; Fetch remaining length ld bc,Lbytes ; Set default length or a sbc hl,bc ; Test more ld (Length),hl jr nc,rdnew ; .. yeap ..last: ld de,$LAST.LINE ld b,null call emplin ; Write last line call nc,closef ; Ok, close file jr c,wrter ; Impossible ld de,$CLS.ERR jr c,_comdel ; Oops, error ld de,$FILE.OK call Fmess ; Give final message jr .comstr wrter: ld de,$WR.ERR _comdel: call Fmess ; Give message jr _delfile comdel: call string ; Tell error _delfile: ld de,$NONE push de ld de,FCB call delete ; Delete file pop de comstr: call string ; Tell any message .comstr: call crlf jp OS ; Exit via warm boot ; ; ################### ; ### SUBROUTINES ### ; ################### ; ; Print message and give file name ; ENTRY Reg DE points to message ; Fmess: call string ; Give message ld de,FCBnam call filnam ; Tell file name ret ; ; Ouput current PC as ASCII. Note reverse order ; ENTRY Regs B and C hold length of line ; EXIT Reg C holds initial checksum ; OutPC: ld de,$HEX.LINE+1 ; Init line ld hl,Temp ld (hl),b ; Set length call ascbyt ; .. output it ld hl,CurPC+1 ; Get current PC call ascbyt ; Save it ld hl,CurPC ; Low as second byte call ascbyt ld hl,(CurPC) ld a,c add a,l ; Add PC to sum add a,h ld c,a inc de ; .. skip 00 inc de ret ; ; Get options from command line ; ENTRY Accu holds number of option arguments ; GetOpt: ld b,a ; Unpack count ..getOpt: push bc ld hl,($ARGV) ; Get current argument call TstOpt ; Test for option cp 'O' ; Test BIAS jr z,..BIAS cp 'L' ; Test length jr nz,IllOpt ; .. should be call gtLeng jr mv.arg ..BIAS: call z,gtBIAS mv.arg: ld hl,($ARGV+2) ; Unpack options ld ($ARGV),hl ld hl,($ARGV+4) ld ($ARGV+2),hl pop bc djnz ..getOpt ret IllOpt: ld de,$ILL.OPT ; Invalid jp comstr ; ; Test for option ; ENTRY Reg HL points to option ; EXIT Accu holds option ; TstOpt: ld a,(hl) ; Get character cp '-' ; Verify indicator inc hl ld a,(hl) ; Get option ret z ; .. well done ld de,$ILL.DEL ; .. invalid jp comstr ; ; Get length to be selected ; ENTRY Reg HL points to numeric string ; gtLeng: ld a,(LENG) or a ; Test length already set jr nz,IllLEN ; .. yeap call GetHEX ; Get hex value jr c,IllLEN ; .. inavlid ld (Length),hl ; Save it ld a,TRUE ld (LENG),a ; .. indicate length ret IllLEN: ld de,$ILL.LNG jp comstr ; Tell error ; ; Sample bias from input line ; ENTRY Reg HL points to numeric string ; gtBIAS: ld a,(BIAS) or a ; Test bias already set jr nz,IllBIAS ; .. yeap call GetHEX ; Get hex value jr c,IllBIAS ; .. invalid ld (CurPC),hl ; .. as start ld a,TRUE ld (BIAS),a ; .. indicate bias ret IllBIAS: ld de,$ILL.OFF jp comstr ; Tell error ; ; Get hex value from string ; ENTRY Reg HL points to numeric string ; EXIT Reg HL holds number ; Carry set on error ; GetHEX: ex de,hl ; .. get right pointer inc de ; .. skip option ld b,0 call hexin ; Get hex ret ; ; Get offset value and position file ; EXIT Carry set on error ; Reg DE holds error message ; ckBIAS: ld a,(BIAS) ; Test bias selected or a ret z ; .. nope ld hl,(CurPC) ; Get biased PC ld de,-tpa add hl,de ccf ld de,$ILL.ADR ; Test < TPA ret c ; .. error call modrec ; Divide by record length ld a,c ld (rdbfp),a ; Set byte position ld (xFCBrrn),hl ; Set random record position xor a ld (xFCBrrn+2),a ld de,X.DMA call setdma ; Set disk buffer ld de,X.FCB call rndred ; Read selected record ld de,$FILE.OFF ; .. possible error ret ; ; Get bias length ; EXIT Reg HL holds length ; BIASlen: ld a,(BIAS) ; Test BIAS or a ld hl,0 ret z ; .. nope ld hl,(CurPC) ; Get bias dec h ; .. less base offset 0100 ret ; ; Check valid selected length ; ckLeng: call BIASlen ; Get BIAS length ld de,(Length) ; Get selected length add hl,de ; .. make real length push hl ld hl,(FilLen) ; Get length of file call mulrec ; .. as bytes pop de or a sbc hl,de ret nc ; .. ok ld de,$ILL.LEN jp comstr ; .. error ; ; Get default byte length ; gtDefLn: call BIASlen ; Get BIAS length push hl ld hl,(FilLen) ; Get length of file call mulrec ; .. as bytes pop de or a sbc hl,de ; Fix length ld (Length),hl ret nc ld de,$ILL.OFF jp comdel ; .. invalid dseg ; ===== Data fields ===== $HELP: db cr,lf _PRG db ' V' _VERS db cr,lf,lf,'Program converts a binary COM file ' db 'into INTEL hex format.',cr,lf db 'This allows copying files via PIP from one ' db 'host to another.',cr,lf db 'On the receiver host this file must be ' db 'converted to binary',cr,lf db 'again with the HEXCOM utility.',cr,lf,lf db 'It also allows converting COM files for ' db 'loading by MLOAD',cr,lf db 'defining optional offset',cr,lf,lf db 'To get program running type:',cr,lf,lf,tab _PRG db ' {-Ohex_offset} {-Lhex_length} ' db '{drv:}filename{.ext}' db cr,lf,lf db 'A new file will with same name and extension' db ' .HEX will be',cr,lf db 'created. The default extension of the input ' db 'file is .COM',cr,lf,lf db 'Default offset is 0100h but may be set to any' db ' other value',cr,lf,lf db 'Length will be determined by record length of' db ' file but may',cr,lf db 'be set to any length less then record length' db cr,lf,eot $FILE.OFF: db 'Bias greater last file address',eot $ILL.ADR: db 'Bias less legal TPA (0100h)',eot $NO.COM: db 'Binary file not found',eot $NO.HEX: db 'Cannot create .HEX file',eot $FILE.OK: db 'Ready, created file ',eot $WR.ERR: db 'Cannot write file ',eot $CLS.ERR: db 'Cannot close file ' $NONE: db eot $ILL.PARSE: db 'Invalid file name',eot $ILL.LEN: db 'File too big - max is 64kByte',eot $ILL.OFF: db 'Invalid BIAS found',eot $ILL.LNG: db 'Invalid length found',eot $ILL.OPT: db 'Invalid option - select O or L',eot $ILL.DEL: db 'Option must start with ''-'' ',eot $ILL.FORM: db 'Invalid .COM file',eot $EOL: db cr,lf,null EOLlen equ $-$EOL $COM: db 'COM' $HEX: db 'HEX' $HEX.LINE: ; Special format line db ':10' ; Header and length of bytes db '0100' ; PC in hi-lo order db '00' ; Delimiter ds Lbytes*2 ; ASCII hex bytes db 'cc' ; Checksum db cr,lf,null $LAST.LINE: db ':0000000000',cr,lf,null P.PB: dw 0,FCB Temp: ds 1 ; Temporary byte CurPC: dw tpa ; Current PC BIAS: db FALSE ; Bias option FilLen: ds 2 Length: ds 2 ; File length LENG: db FALSE ; Length option $ARGV: ds 2*_MaxArg ; CCP argument array X.FCB: ds fcblen xFCBex equ X.FCB+.fdrv+.fname xFCBrrn equ X.FCB+.frrn X.DMA: ds reclng ds 32*2 ; 32 call levels LocStk: end COMHEX