# # Kimptp - converts a variety of file formats to the KIM-1 Papertape format # # Author: Carl Myerholtz W9OMS Nov 2020 # # Usage: KIMPTP.py file.ext (starting address) # # If invoked without arguments it will ask for a filename and if the extension is .bin # it will ask for a starting address in hex. # # Optimized for use with the Charles Bond CBA65 6502 assembler # # Typical usage is to create a makeproject.bat file containing # CBA65 project.cba # KIMPTP.py project.h65 # # Then execute the makefile from a CMD window # # Consists of four separate fuctions to process each file format # binhex(filename, startaddress) converts a binary file with a .bin extension. # Also needs a starting address for the binary # intelhex(filename) converts an Intel Hex format text file with a .hex extension # h65hex(filename) converts a h65 file generated by the Charles Bond CBA65 assembler # with a .h65 extension # moshex(filename) converts a Moshex file generated by the Charles Bond CBA65 assembler # with a .mos extension. The CBA moshex output does not match the KIM-1 papertape # exactly. It has an extra byte (00) after the address in each record and an # incorrect end record. I do not know if this is an error or if there is really # a difference bewteen the moshex format and the KIM-1 papertape format. # This function strips out the extra 00 byte and appends the correct end record. # Use with caution with .mos files from other sources # # The print() statements that have been commented out will display the text # while also generating the output file. # # #------------------------------------------------------------------------------- # Binary format # def binhex(infile, address): try: fin = open(infile, "rb") except: print('File not found:') exit() outfname = infile[:infile.find('.')] + '.kpt' fout = open(outfname, 'w') binary = bytearray(fin.read()) length = len(binary) fullrec = int(length/24) partrec = length - (fullrec *24) # address = 0x2000 # print (length, fullrec, partrec, address) # # Generate mostly 24 byte records # index = 0 linecnt = 0 while linecnt < fullrec: out = ';18' + format(address, '04X') bytecnt=0 chksum=24+(address>>8&0xff)+(address&0xff) while bytecnt < 24: out = out + format(binary[index], '02X') chksum = chksum + binary[index] index = index + 1 bytecnt = bytecnt +1 out = out + format(chksum, '04X') # print(out) fout.write(out + '\n') address = address + 24 linecnt = linecnt +1 # # Generate final partial record if there is one # if partrec > 0: out = ';' + format(partrec, '02X') + format(address, '04X') bytecnt=0 chksum=partrec+(address>>8&0xff)+(address&0xff) while bytecnt < partrec: out = out + format(binary[index], '02X') chksum = chksum + binary[index] index = index + 1 bytecnt = bytecnt +1 out = out + format(chksum, '04X') # print(out) fout.write(out + '\n') linecnt = linecnt +1 # # Generate end of file record with number of lines # chksum = 0 index = 0 out = format(linecnt, '04X') data = bytearray.fromhex(out) while index < len(data): chksum = chksum + data[index] index = index + 1 out = ';00' + out + format(chksum, '04X') + '\n' # print(out) fout.write(out) fout.close() # #------------------------------------------------------------------------------- # # Intel Hex format # def intelhex(infile): try: fin = open(infile, "r") except: print('File not found:') exit() outfname = infile[:infile.find('.')] + '.kpt' fout = open(outfname, 'w') linecnt = 0 for line in fin: if line[1:3] == '00': break line = line[1:] line = line[:6] + line[8:] linecnt=linecnt+1 data = bytearray.fromhex(line) datalen = len(data) - 1 out = ';' chksum = 0 index = 0 while index < datalen: chksum = chksum + data[index] out = out + format(data[index], '02X') index = index + 1 out = out + format(chksum, '04X') # print(out) fout.write(out + '\n') chksum = 0 index = 0 out = format(linecnt, '04X') data = bytearray.fromhex(out) while index < len(data): chksum = chksum + data[index] index = index + 1 out = ';00' + out + format(chksum, '04X') + '\n' # print(out) fout.write(out) fout.close() # #------------------------------------------------------------------------------ # # def h65hex(infile): try: fin = open(infile, "r") except: print('File not found:') exit() outfname = infile[:infile.find('.')] + '.kpt' fout = open(outfname, 'w') linecnt = 0 for line in fin: linecnt=linecnt+1 data = bytearray.fromhex(line) datalen = len(data) - 2 out = ';' + format(datalen, '02X') chksum = datalen index = 0 while index < len(data): chksum = chksum + data[index] out = out + format(data[index], '02X') index = index + 1 out = out + format(chksum, '04X') print(out) fout.write(out + '\n') chksum = 0 index = 0 out = format(linecnt, '04X') data = bytearray.fromhex(out) while index < len(data): chksum = chksum + data[index] index = index + 1 out = ';00' + out + format(chksum, '04X') # print(out) fout.write(out + '\n') fout.close() # #------------------------------------------------------------------------------- # # Mos Hex format # def moshex(infile): try: fin = open(infile, "r") except: print('File not found:') exit() outfname = infile[:infile.find('.')] + '.kpt' fout = open(outfname, 'w') linecnt = 0 for line in fin: if line[1:3] == '00': break out = line[:7] + line[9:] # print(out) fout.write(out) linecnt = linecnt + 1 chksum = 0 index = 0 out = format(linecnt, '04X') data = bytearray.fromhex(out) while index < len(data): chksum = chksum + data[index] index = index + 1 out = ';00' + out + format(chksum, '04X') + '\n' # print(out) fout.write(out) fout.close() # #------------------------------------------------------------------------------ # # main code # # import sys numargs = len(sys.argv) if numargs > 1: fname = sys.argv[1] else: fname = input('Enter file name: ') fext = fname[fname.find('.')+1:].lower() if fext == "bin": if numargs == 3: start = sys.argv[2] else: start=input('Enter starting address (hex): ') address=int(start, 16) binhex(fname, address) elif fext == "hex": intelhex(fname) elif fext == "h65": h65hex(fname) elif fext == "mos": moshex(fname) else: print("Unrecognized file extension ", fext)