title BASIC Data Generator name ('HEX2DATA') maclib base80 ; Program converts INTEL HEX format to BASIC data statements ; ; Call it: ; HEX2DATA [-opt] source[.HEX] [dest[.BAS]] ; ; With options: ; ; -Lline Start line, defaults to 10000 ; -Iinc Increment, defaults to 10 ; -Bbc Byte count, defaults to set up by source file ; -H Produce header for POKEing data ; -C Turn on consistency check, default: OFF ; ; Without a destination file, conversion results in file 'source.BAS'. ; ; Format of HEX file: ; ; :<08> <0100> <00> <00 00 00 08 31 32 33 34> <25> ; ll adr ty --- data --- ck ; ; Checksum 'ck' is -(ll+adr+ty+..data..> ; ; :<00> <0000> <01> ; ; Copyright (c) Werner Cirsovius ; Hohe Weide 44 ; D-20253 Hamburg ; Phone +49-40-4223247 ; ; Version 2.0, January 1995 ext fillin,emplin,rdbuf,wrbuf,rdbfp,wrbfp ext close,delete,closef,open,creatd,rename ext strcn0,filnam,conchd,crlf ext parse,multip,strapp,@leng,getver,cmdarg,indexa ext hexout,decout,decin entry $memry _PRG_ macro db 'HEX2DATA' endm _VERS_ macro db '2.0' endm _maxarg equ 7 ; Options and file(s) _minarg equ 1 ; One file mandatory _maxfil equ 2 ; Max files _LSTART equ 10000 dseg $ILL.CPU: db 'Requires Z80 CPU',eot $ILL.OS: db 'Requires CP/M 3.x',eot $HELP: _PRG_ db ', v' _VERS_ db cr,lf db 'Program converts INTEL HEX format to BASIC ' db 'data statements' db cr,lf,lf db 'Call it:',cr,lf db tab _PRG_ db ' [-opt] source[.HEX] [dest[.BAS]]' db cr,lf,lf db 'With options:',cr,lf,lf db tab,'-Lline' db tab,'Start line, defaults to 10000' db cr,lf db tab,'-Iinc' db tab,'Increment, defaults to 10' db cr,lf db tab,'-Bbc' db tab,'Byte count, ' db 'defaults to set up by source file' db cr,lf db tab,'-H' db tab,'Produce header for POKEing data' db cr,lf db tab,'-C' db tab,'Turn on consistency check, default: OFF' db cr,lf,lf db 'Without a destination file, conversion ' db 'results in file ''source.BAS''.' db cr,lf,eot $FIN1: db cr,lf,'Finished, ',null $FIN2: db ' ->> ',null $FIN3: db '(Last line: ',null $FIN4: db ' - Bytes processed: ',null $FIN5: db ')',cr,lf,null $FIN6: db '(From 0x' $F.FIRST: db 'XXXX to 0x' $F.LAST: db 'XXXX)',cr,lf,null $IN.EXT: db 'HEX' $OUT.EXT: db 'BAS' $OUT.$$$: db '$$$' $OPT: db 'BILHC' OptLen equ $-$OPT OptExe: dw B.opt,I.opt,L.opt,H.opt,C.opt FileExe: dw Sfile,SDfile $MISS.FILE: db 'Missing source file name',cr,lf,eot $MAX.FILE: db 'Too many file arguments',cr,lf,eot $ILL.OPT: db 'Invalid option',cr,lf,eot $NO.FILE: db 'Cannot find file ',null $NO.CREC: db 'Cannot create file ',null $ILL.NUM: db 'Invalid number in: ',null $DATA: db ' DATA ',null $ILL.HEX: db 'Invalid hex byte',null $ILL.STRT: db 'Invalid start of line',null $ILL.LEN: db 'Invalid length',null $WRT.ERR: db 'Write error on DATA file',null $CLS.ERR: db 'Close error on DATA file',null $ILL.CKS: db 'Invalid checksum',null $ERROR: db 'Invalid coded HEX file: ',null $EMPTY: db 'Empty HEX file',null $ARROW: db '^',cr,lf,null $INCONS: db cr,lf db 'WARNING: Source file is inconsistent' db cr,lf db ' Check file for incremental addresses' db cr,lf,null ; ; Lines for header ; $HD.1: db ' RESTORE ' $REST: db '65535',cr,lf,null ; $HD.2: db ' FOR adr=&H' $FIRST: db 'xxxx TO &H' $LAST: db 'xxxx',cr,lf,null ; $HD.3: db ' READ a$',cr,lf,null ; $HD.4: db ' POKE adr,VAL("&H"+a$)',cr,lf,null ; $HD.5: db ' NEXT adr',cr,lf,null ; $HD.6: db ' RETURN',cr,lf,null ; HD.arr: dw $HD.1,$HD.2,$HD.3,$HD.4,$HD.5,$HD.6 HDlines equ ($ - HD.arr) / 2 ; BASline: ds 2 HexLine: ds 2 ; ds 2 ; Buffer pointer db reclng ; Record pointer FIN: ds 2 ; FCB ; ds 2 ; dtto. db 0 FOUT: ds 2 ; _FIN: ds .fname+.fext _FOUT: ds .fname+.fext ; RLine: ds 2 RESTLine: ds 2 HLine: dw _LSTART Line: dw _LSTART ; Start line NumInc: dw 10 ; Line increment BPL: ; \ db 0 ; | Bytes per line BPL?: ; | db FALSE ; / _HEAD_: db FALSE ; No header request _CHECK_: db FALSE ; No consistency request $memry: dw 0 Heap: ds 2 HLen: ds 2 OHLen: ds 1 _HLen: ds 1 Count: dw 0 Lptr: ds 2 Hptr: ds 2 Empty: ds 1 CKS: ds 2 ARGC: ds 1 ARGV: ds 2*_maxarg PB: dw 0,FCB First?: db TRUE ; Indicate first line read FirstAdr: ds 2 LastAdr: ds 2 PrevAdr: ds 2 PLen: ds 2 cseg ; ; Prepare header lines if any ; prep.Header: ld a,(_HEAD_) ; Test request or a ret z ; .. nope ld hl,(NumInc) ld de,HDlines call multip ; Get offset ld de,(Line) add hl,de ld (Line),hl ; Change start line ld (RESTLine),hl ; .. set RESTORE ret ; ; Parse file ; ENTRY Reg C holds parameter index ; _parse: ld a,c ; Get index ld hl,ARGV call indexa ; Get name pointer ld (PB),de ; .. save address ld de,PB call parse ; .. parse file ret ; ; Print integer in HL on console ; pr.int: ld de,(Heap) ; Get free memory push de ld b,null call decout ; Convert number pop de call strcn0 ; .. print ret ; ; Print hex word in HL on console ; pr.hex: ld de,(Heap) ; Get free memory push de call hexout ; Convert number ex de,hl ld (hl),null ; .. close line pop de call strcn0 ; .. print ret ; ; Initialize memory ; inimem: ld hl,($memry) ; Get free space ld de,FCBlen ld (FIN),hl ; Init FCB pointers add hl,de ld (FOUT),hl add hl,de ld de,reclng ld (FIN-3),hl ; Init disk buffers add hl,de ld (FOUT-3),hl add hl,de ld de,255 ld (hl),255 ; Set max input inc hl ld (HexLine),hl add hl,de ld (hl),255 inc hl ld (BASline),hl add hl,de ld (Heap),hl ; .. save top ret ; ; Close output file ; FileClose: call _closef ; Close file ld a,(_HEAD_) ; Test header request or a ret z ; .. nope ; ld de,$REST ld hl,(RESTLine) ld b,cr call decout ; Give RESTORE ex de,hl ld (hl),lf ; .. close line inc hl ld (hl),null ; ld hl,(FirstAdr) ld de,$FIRST call hexout ; Set loop values ; ld hl,(LastAdr) dec hl ld de,$LAST call hexout ; ld de,(FIN) ld hl,(FOUT) push hl ld bc,.fdrv+.fname+.fext ldir ; Unpack file pop hl ld bc,.fdrv+.fname add hl,bc ; Position to extension ex de,hl ld hl,$OUT.$$$ ld bc,.fext ldir ; Set $$$ extension xor a ld (wrbfp),a ; Prepare pointers ld a,reclng ld (rdbfp),a ld de,(FOUT) call ..make ; Create file ld hl,(HLine) ld (Line),hl ; Init start line ld b,HDlines ; Init line pointers ld hl,HD.arr PrfxLoop: push bc push hl ld de,(BASline) ; Point to line push de ld hl,(Line) ; .. get line number ld b,null call decout ; Get ASCII line number pop de exx pop hl ; Get line message pointer ld e,(hl) ; .. fetch pointer inc hl ld d,(hl) inc hl push hl push de exx pop hl call strapp ; Append message to line number call ..LIProc ; Write line pop hl pop bc djnz PrfxLoop ; ld de,(FIN) call open ; Open old file Copy: ld de,(BASline) ; Point to line dec de ld b,null call fillin ; Get line from file jr c,closedst ; .. eof call ..LProc ; Write line jr Copy ; .. copy closedst: call _closef ; Close file ld de,(FIN) push de call delete ; Delete source file pop de ld bc,(FOUT) ld hl,16 add hl,bc ; Point to 2nd file ex de,hl push bc ld bc,16 ldir ; Unpack for ename pop de call rename ; Rename file ret ; ; Set default extension of standard FCB ; ENTRY Reg HL points to extension field ; defExt: ld de,FCB+.fdrv+.fname ld a,(de) ; Test extension cp ' ' ret nz ; .. got it ld bc,.fext ldir ; .. set default extension ret ; ; Copy file name ; ENTRY Reg DE holds destination ; move$FN: push de ld hl,FCB ld bc,.fdrv+.fname+.fext ldir ; Unpack FCB pop de ret ; ; Open source file ; GetFile: ld hl,$IN.EXT call defExt ; Set default extension ld hl,FIN-3 ld de,rdbuf ld bc,5 ldir ; Set input file ld de,(FIN) call move$FN ; Unpack file call open ; .. open it ret nc ; .. ok push de ld de,$NO.FILE jr file.err ; ; Create output file ; MakeFile: ld hl,$OUT.EXT call defExt ; Set extension ld hl,FOUT-3 ld de,wrbuf ld bc,5 ldir ; Set output file ld de,(FOUT) call move$FN ; Unpack file ..make: call creatd ; .. create it ret nc ; .. ok push de file.err: ld de,$NO.CREC call strcn0 ; Give error message pop de inc de call filnam jp OS ; ; Fetch options ; ENTRY Accu holds number of arguments ; EXIT Reg B holds non option arguments ; Reg C holds index to first name of file ; getopt: ld b,a ; .. set for loop ld c,0 ; .. clear index _getopt: ld a,c ld hl,ARGV call indexa ; Get pointer ld a,(de) ; Test option cp '-' ret nz ; .. nope, remainder are files inc de ; Skip option sign push bc call do.opt ; .. process option pop bc inc c djnz _getopt ret ; ; Process option ; ENTRY Reg DE points to option ; do.opt: ld a,(de) ; Get option inc de ; .. skip it push de ld bc,OptLen ld hl,$OPT+OptLen-1 cpdr ; .. find it ld de,$ILL.OPT jp nz,Error ; .. invalid one ld hl,OptExe ld a,c call indexa ; Get address ex de,hl pop de jp (hl) ; .. go ; ; -->> Option -C ; C.opt: ld a,TRUE ld (_CHECK_),a ; Set consistency request ret ; ; -->> Option -H ; H.opt: ld a,TRUE ld (_HEAD_),a ; Set header request ret ; ; -->> Option -Iincrement ; I.opt: call atoi ; Get increment ld (NumInc),hl ; .. save ret ; ; -->> Option -Lstart_line ; L.opt: call atoi ; Get number ld (Line),hl ; .. save ld (HLine),hl ret ; ; -->> Option -Bbytes_per_line ; B.opt: call atoi ; Get count inc h dec h ; Verify max 255 jr nz,NumErr ld h,TRUE ld (BPL),hl ; .. save ret ; ; Convert string to number ; ENTRY Reg DE points to string ; EXIT Reg HL holds number ; atoi: push de ld b,-1 call decin ; Fetch number pop de jr c,NumErr ; .. error ld a,l or h ; Verify > 0 ret nz NumErr: push de ; .. save pointer ld de,$ILL.NUM call strcn0 ; Tell invalid number pop de dec de ; Fix for option dec de call strcn0 ; .. give error line jp OS ; .. break ; ; Store current address ; ENTRY Reg HL holds address ; St.Adr: ld (LastAdr),hl ; .. save address ld a,(First?) ; Test 1st request or a jr z,Consist ; .. nope ld (FirstAdr),hl ; .. set 1st address ld (PrevAdr),hl ld hl,(HLen) ld (PLen),hl ; Save length xor a ld (First?),a ; .. satisfy request ret Consist: ld a,(_CHECK_) ; Test check requested or a ret z ; .. nope push hl ; Save address ld hl,(PrevAdr) ; Get previous one ld de,(PLen) ; .. and length add hl,de pop de ld (PrevAdr),de ; .. set new sbc hl,de ; .. verify same ld de,(HLen) ld (PLen),de ; .. unpack length ret z ld de,$INCONS call strcn0 ; Give warnung xor a ld (_CHECK_),a ; Disable checking ret ; ; Read new line from hex file ; EXIT Carry set on end of file ; ReadLine: ld de,(HexLine) ; Get pointer dec de ld b,null call fillin ; Get line from file ret c ; .. eof call HEXlen ; Check length > 0 jr z,ReadLine ; .. nope, try read again call HEXchar ; Get address push bc ; .. save hi call HEXchar pop hl ld l,b ; .. save lo call St.Adr ; Store address call HEXchar ; Skip type ld a,(HLen) ; Get length of line ld b,a ld c,a ..chk.loop: push bc call HEXchar ; Get characters for checking pop bc djnz ..chk.loop push bc call CheckCKS ; Verify checksum pop bc ld hl,BPL? ld a,(hl) cp TRUE ; Test own definition ld a,c jr nz,..len.get dec hl ld a,(hl) ; .. get definition ..len.get: ld (OHLen),a ; .. set BASIC line length ld hl,(HexLine) ld de,9 add hl,de ld (Hptr),hl ; Init string pointer xor a ; Set success ret ; ; Process error ; ENTRY Reg DE holds additional error message ; IllHEX: push de ld de,$ERROR call strcn0 ; Give message pop de call strcn0 call crlf ld de,(HexLine) call strcn0 ; Print error line ld a,(Lptr) dec a dec a ld b,a ld e,' ' call nz,conchd ; .. print blanks ld de,$ARROW _EraseF: call strcn0 EraseF: ld de,(FOUT) call close ; Close file call delete ; .. and delete it jp OS ; ; Convert hex character to byte ; ENTRY Reg C holds character ; Reg B holds old byte ; EXIT Reg B holds new byte ; Carry set on error ; ..atoi: ld a,b ; Get old add a,a ; * 16 add a,a add a,a add a,a ld b,a ld a,c ; Get character cp '0' ; Test range ret c ; .. error cp 'F'+1 ccf ret c cp '9'+1 ; Test 0..9 jr c,..ato0..9 cp 'A' ret c ; .. error sub 7 ; .. fix hex ..ato0..9: sub '0' ; Strip off offset add a,b ; .. combine ld b,a ret ; ; Convert ASCII to byte ; ENTRY Reg HL holds two character ASCII ; EXIT Accu holds byte ; CnvHex: ld b,0 ; Init result ld c,l ; Get first character call ..atoi ; .. convert ld c,h ; Get second character call nc,..atoi ld a,b ret nc ld de,$ILL.HEX jp IllHEX ; .. error ; ; Get next character pair ; EXIT Reg DE holds pair ; Reg B holds hex value ; HEXchar: ld de,(HexLine) ; Get base ld hl,(Lptr) ; .. and current push hl inc hl inc hl ld (Lptr),hl ; .. set new pop hl add hl,de ; Position pointer ld e,(hl) ; Get characters inc hl ld d,(hl) push de ex de,hl call CnvHex ; Get hex pop de ld b,a ld a,(CKS) add a,b ; Get checksum ld (CKS),a ret ; ; Get byte from line ; EXIT Reg HL holds byte ; CnvByte: call HEXchar ; Get characters ex de,hl call CnvHex ; Convert to byte ld l,a ld h,0 ret ; ; Get length of HEX item ; EXIT Accu holds length ; Zero set if length zero ; HEXlen: ld hl,2-1 ld (Lptr),hl ; Init pointer ld hl,0 ld (CKS),hl ; .. and checksum ld hl,(HexLine) ld a,(hl) ; Validate start cp ':' ld de,$ILL.STRT jp nz,IllHEX ; .. invalid call CnvByte ; Get length ld (HLen),hl ; .. save ld hl,(HexLine) ; Get line call @leng ; .. get length sub 11+2 ; Strip off header and NL srl a ; .. divide by two ld b,a ld a,(HLen) cp b ; .. compare ld de,$ILL.LEN jp nz,IllHEX or a ; Test zero ret ; ; Bump to next line ; IncLine: ld hl,(Line) ld de,(NumInc) add hl,de ; .. bump ld (Line),hl ret ; ; Bump to previous line ; DecLine: ld hl,(Line) ld de,(NumInc) or a sbc hl,de ; .. fix ld (Line),hl ret ; ; Verify correct checksum ; CheckCKS: ld hl,(CKS) ; Get current checksum push hl ; .. save call CnvByte ; Get checksum expected pop de add hl,de inc l dec l ; Verify zero ret z ld de,$ILL.CKS jp IllHex ; .. error ; ; Load next two characters from buffer ; EXII Reg DE holds pair ; Carry set on end of file ; ld.HEXchar: ld a,(HLen) ; Get length or a call z,ReadLine ; Read new line ret c ; .. end of file ld a,(HLen) ; Get length dec a ; .. count down ld (HLen),a ld hl,(Hptr) ; Get pointer ld e,(hl) ; Get characters inc hl ld d,(hl) inc hl ld (Hptr),hl ; .. set new pointer ld hl,(Count) inc hl ; Bump byte count ld (Count),hl or a ret ; ; Process one BASIC line ; EXIT Carry set on end of file ; ProcLine: ld a,(OHLen) ld (_HLen),a ; .. set BASIC line length ld de,(BASline) ; Point to line push de ld hl,(Line) ; .. get line number ld b,null call decout ; Get ASCII line number pop de ld hl,$DATA call strapp ; Init BASIC data line push de xor a ld (Empty),a ; .. set empty line ld a,(_HLen) ; Get length of line ld b,a pop hl ; Get back pointer ..ProcLoop: push bc push hl call ld.HEXchar ; Get characters pop hl pop bc ld c,1 jr c,..eof ; .. end of file ld (hl),e ; .. save inc hl ld (hl),d inc hl ld a,',' ld (hl),a ld (Empty),a ; .. set none empty line inc hl ld de,(LastAdr) inc de ; Bump address ld (LastAdr),de djnz ..ProcLoop ld c,0 ; Reset end of file condition ..eof: ld a,(Empty) ; Test any in line or a jr z,..skp.eol ; .. nope dec hl ld (hl),cr ; .. close line inc hl ld (hl),lf inc hl ld (hl),null ..LIProc: call IncLine ; Get next line ..LProc: ld de,(BASline) ; Point to line ld b,null call emplin ; .. write line ret nc ld de,$WRT.ERR WrERR: call strcn0 jp EraseF ..skp.eol: call DecLine ; Get previous line back srl c ; Set read result ret ; ; Close output file ; _closef: call closef ; Close file ret nc ld de,$CLS.ERR jr WrERR ; .. process error ; ; Save environment for later report ; SavEnv: ld hl,(Line) ; Save last line ld (RLine),hl ld hl,(FIN) inc hl ld de,_FIN ld bc,.fname+.fext ldir ; .. and files ld hl,(FOUT) inc hl ld bc,.fname+.fext ldir ret ; ; Give final messages ; Report: ld de,$FIN1 call strcn0 ; .. simple be verbose ld de,_FIN call filnam ld de,$FIN2 call strcn0 ld de,_FOUT call filnam call crlf ld de,$FIN3 call strcn0 ld hl,(RLine) call pr.int ld de,$FIN4 call strcn0 ld hl,(Count) call pr.int ld de,$FIN5 call strcn0 ld hl,(FirstAdr) ld de,$F.FIRST call hexout ld hl,(LastAdr) dec hl ld de,$F.LAST call hexout ld de,$FIN6 call strcn0 ret ; ; Process simple message ^DE and exit ; Error: ld c,.string call BDOS ; Print jp OS ; ; ######################## ; ### START OF PROGRAM ### ; ######################## ; MAIN: sub a ; Verify Z80 processor ld de,$ILL.CPU jp pe,Error call getver ; .. and right OS ld de,$ILL.OS jr c,Error ld sp,(TPAtop) ; Get stack call inimem ; Init memory ld hl,ARGV ld de,CCPlen ld b,_maxarg call cmdarg ; Fetch arguments ld (ARGC),a ; .. save count ld de,$HELP jr c,Error ; .. invalid cp _minarg jr c,Error ; .. invalid call getopt ; .. fetch option(s) ld de,$MISS.FILE ld a,b or a ; Test any file jr z,Error ; .. nope ld de,$MAX.FILE cp _maxfil+1 ; Test files in range jr nc,Error ld hl,FileExe-2 call indexa ; Get routine ex de,hl jp (hl) ; .. go ; ; Reset file for read ; ENTRY Reg C holds parameter index ; Reset: call _parse ; .. parse file call GetFile ; Open source file ret ; ; Got source file ; Sfile: call Reset ; Open source file ld a,' ' ; Force default extension ld (FCB+.fdrv+.fname),a jr BegHEX ; .. and create file ; ; Got source and destination file ; SDfile: push bc ; Save index call Reset ; Open source file pop bc ; Get back index inc c call _parse ; .. parse file BegHEX: call MakeFile ; .. and create file call prep.Header ; Prepare header lines if any call ReadLine ; Read 1st line ld de,$EMPTY jp c,_EraseF ; .. should not be empty ; ; Main loop ; ..loop: call ProcLine ; Process line jr nc,..loop ; .. till end ; call SavEnv call FileClose ; Close file call Report ; Give final messages jp OS end MAIN