begin "appleb" require "{}{}" delimiters; define ! = {comment}; ! take a hex file produced by the CROSS compiler, and convert it to a bin file suitable for direct KERMIT uploading to APPLEs. author: Peter Trei, OC.TREI%CU20B@COLUMBIA-20 Phone: 212-5692371 (home) 212-8153711 (work) ; define lf = {(10 & null)}; ! line feed; define crlf = {(13 & 10)}; ! carriage return / line feed; define halt = {start!code haltf end}; ! neat way to finish; integer array mem[-4:65536]; ! This integer array will be filled with an image of the binary file. It is large enough to hold the Apples entire address space, with room to include the starting address and length of a file which begins at zero.; integer infile, firstpos, lastpos, filelength; ! *****************************************************; procedure dohelp; begin "dohelp" string c; print("Need help? "); c := intty; if (c="y") or (c="Y") THEN begin "dohelp" print( " This program takes a *.HEX file output by the CROSS compiler, and produces an 8-bit byte file suitable to directly upload to an Apple running KERMIT under DOS 3.3. It also gives the starting address and length in both hexadecimal and base 10. Such a HEX file may be produced (for the source file APPLEK.M65) by : @KER:CROSS * APPLEK.HEX/PTP:KIM=KER:APPLEK.M65/M65 ^C @ You then run this program, and give it the .HEX file as the input filespec, and (in this case) APPLEK.BIN as the output filespec. This file may then be directly uploaded to your Apple using KERMIT-65, with FILE-TYPE set to BINARY, and FILE-BYTE-SIZE set to EIGHT.",crlf,crlf); end; end "dohelp"; ! *****************************************************; procedure getname(reference integer infile); ! returns jfn of the source data file; begin "getname" print("Input filespec : "); infile := openfile("","RO"); end "getname"; ! *****************************************************; procedure conshx (string data; reference integer sum); ! convert a hex string to an integer. Could probably be replaced with NIN; begin "conshx" integer factor, part, len, x; len := length(data); factor := 1; sum := 0; for x := len step -1 until 1 do begin string byte; byte := data[x to x]; if ((byte <= "9") and (byte >= "0")) then part := cvd(byte) else if ((byte <= "F") and (byte >= "A")) then part := (byte - "A") + 10 else part := -1; if part >= 0 then begin sum := sum+ (part*factor); factor := factor * 16; end end end "conshx"; ! *****************************************************; procedure printhex(integer num); ! print the input number as a hexadecimal string. For some mysterious reason this seems to trash some numbers, so dont use it if you intend to reuse the value.; begin "printhex" start!code movei 1, '101; move 2, num; movei 3, '500004000020; nout; end; end "printhex"; ! *****************************************************; procedure readata(integer infile; reference integer firstpos; reference integer lastpos; reference integer filelength); ! scan through the file, and determine the start address and end address, and ! filelength. ! Place byte values into the mem array as integers; ! Precede with the appropriatly arranged bytes of the length and start; ! Return the first and last positions in the array to write, and filelength; begin "readata" string incrstr, addrstr, line, byte; integer addr, incr, junk, eofv, brchr, pos, linepos, final, startaddress; setinput(infile,junk,brchr,eofv); startaddress :=66000; lastpos :=0; ! set start address and end address to impossibly extreme values, to ensure; ! that they get reset.; arrclr(mem); ! set the array to zero.; while not eofv do ! while not end of file do; begin line := sini(infile,200,lf);! get a line from the file; incrstr := line[2 TO 3]; ! bytes 2-3 hold number of data bytes in line.; addrstr := line[4 TO 7]; ! bytes 4-7 hold the lines' starting address; conshx(addrstr,addr); ! convert the hex address to an integer; conshx(incrstr,incr); ! convert the hex byte count to an integer; if incr > 0 then ! if there is data in this line then...; begin ! deal with posible resetting of memory bounds for this file; if addr < startaddress then startaddress := addr; final := addr + incr-1; if final > lastpos then lastpos := final; linepos := 8; ! data bytes start at position 8; FOR pos := addr STEP 1 UNTIL final DO BEGIN byte := line[linepos FOR 2]; ! get bytes worth of hex chars; ! convert to an integer and store in the memory array; conshx(byte,mem[pos]); linepos := linepos + 2; ! move forward to next byte in line.; END; end; END; filelength := lastpos-startaddress+1; ! A file in BINARY format under DOS 3.3 has at its begginning, a two byte starting address, followed by a 2 byte length. These two parameters are stored with the high-order byte PRECEDING the low order byte.; mem[startaddress-1] := filelength div 256; mem[startaddress-2] := filelength LAND 255; mem[startaddress-3] := startaddress div 256; mem[startaddress-4] := startaddress LAND 255; firstpos := startaddress - 4; end "readata"; ! *****************************************************; procedure dobout(reference integer byte, channel); ! perform the BOUT jsys to output 8 bit bytes to the file open on channel; begin "dobout" start!code move 1, channel; move 2, byte; bout; END; end "dobout"; ! *****************************************************; procedure writebinary(integer firstpos,lastpos); ! open a file in 8 bit bytes, and output the data to it.; begin "writebinary" integer outfile, pos, pointer, mempos; print("Output filespec : "); outfile := gtjfn("",1); openf(outfile,'100000100000); ! open in 8-bit output mode; ! now write each byte to the output file.; for pos := firstpos step 1 until lastpos do dobout(mem[pos],outfile); closf(outfile); ! close the file; rljfn(outfile); ! release the jfn; END "writebinary"; ! *****************************************************; ! main program; dohelp; ! check if the user wants help; getname(infile); ! get the input file name; readata(infile,firstpos,lastpos,filelength); ! read its data into memory; writebinary(firstpos,lastpos); ! write it out to a binary file; ! print the start address and length in base 10; print(crlf); print("Base 10:",crlf); print("Start address = ",firstpos+4,crlf); print("Length = ",filelength,crlf); ! and base 16; print(crlf); print("Hexadecimal:",crlf); print("Start address = $"); printhex(firstpos+4); print(crlf); print("Length = $"); printhex(filelength); print(crlf); halt; ! quit; end "appleb";