Skip to content

Instantly share code, notes, and snippets.

@skeletozaure
Created March 8, 2023 17:13
Show Gist options
  • Save skeletozaure/7356738b16cfb738fdd8e9edaa62b4b9 to your computer and use it in GitHub Desktop.
Save skeletozaure/7356738b16cfb738fdd8e9edaa62b4b9 to your computer and use it in GitHub Desktop.
Hex2Bas.py : Convert Intel Hex file to Basic for Mattel Aquarius
#
# HEX2BAS - Convert an Intel HEX file to a BASIC program for Mattel Aquarius computer
# Author: Cédric LEBOCQ
# Date: 2023-03-08
# Version: 1.0
#
import sys
def create_basic_program(hex_file_lines, base_address):
bytes = []
data = ""
try:
# process each line of the Intel HEX file and convert it to a BASIC program
for line in hex_file_lines:
# get the record length
record_length = int(line[1:3], 16)
# get the record type
record_type = int(line[7:9], 16)
# get the data
data_line = line[9:9+record_length*2]
# check if the record type is 00 (data record)
if record_type == 0:
# process each byte of the data
for i in range(0, record_length):
# get the byte
byte = int(data_line[i*2:i*2+2], 16)
bytes.append(byte)
except Exception as e:
print(f"Error processing Intel HEX file: {e}")
return None
# if there are bytes to process
if len(bytes) > 0:
try:
# create a DATA list with the bytes, 8 bytes per line
# and the remaining bytes on the last line
num_line = 10
for i in range(0, len(bytes), 8):
if i == 0:
data += f"{num_line} DATA "
else:
num_line += 10
data += f"\n{num_line} DATA "
for j in range(i, i+8):
if j < len(bytes):
data += str(bytes[j])
if j < i+7:
data += ","
else:
break
# if the last char of data is a comma, remove it
if data[-1] == ",":
data = data[:-1]
# now create the POKE LOOP to write the bytes to memory
num_line += 10
bas_template = f"{num_line} FORX={base_address}TO{base_address+len(bytes)-1}:READA:POKEX,A:NEXT"
data += f"\n{bas_template}"
mem_hi, mem_lo = divmod(base_address, 256)
num_line += 10
data += f"\n{num_line} POKE14340,{mem_lo}:POKE14341,{mem_hi}"
# call the ASM routine
num_line += 10
data += f"\n{num_line} X=USR(0)"
except Exception as e:
print(f"Error creating BASIC program: {e}")
return None
return data
def main():
try:
# get input file name
input_file_name = sys.argv[1]
except IndexError:
print("Usage: python script.py <input_file> <output_file>")
print("If output_file is not specified, the BASIC program will be written to the console")
return
try:
# get output file name
output_file_name = sys.argv[2]
except:
print("No output file specified, the BASIC program will be written to the console")
output_file_name = ""
# read Intel HEX file
try:
with open(input_file_name, "r") as hex_file:
hex_file_lines = hex_file.readlines()
except FileNotFoundError:
print(f"File not found: {input_file_name}")
return
# get the base address from the first line of the Intel HEX file
try:
base_address = int(hex_file_lines[0][3:7], 16)
except (ValueError, IndexError):
print("Invalid Intel HEX file format")
return
# create the BASIC program
data = create_basic_program(hex_file_lines, base_address)
# write the BASIC program to the output file
if output_file_name != "":
with open(output_file_name, "w") as output_file:
output_file.write(data)
# write the BASIC program to the console
print("BASIC program:")
print(data)
if __name__ == "__main__":
main()
# What is the Intel HEX file format :
# -----------------------------------
# The Intel HEX file is an ASCII text file with lines of text that follow the Intel HEX file format. Each line in an Intel HEX file contains one HEX record.
# These records are made up of hexadecimal numbers that represent machine language code and/or constant data.
# An Intel HEX file is composed of any number of HEX records. Each record is made up of five fields that are arranged in the following format:
# :llaaaatt[dd...]cc
# Where:
# - : is the colon character that indicates the start of a HEX record.
# - ll is the record length field that indicates the number of data bytes (dd) in the record.
# - aaaa is the address field that represents the starting address for subsequent data.
# - tt is the record type field that indicates the meaning of the data field.
# - dd is a data field that represents a sequence of ll bytes of data.
# - cc is the checksum field that provides a simple method of detecting errors in the data field.
#
# tt is the field that represents the HEX record type, which may be one of the following:
# - 00 - data record
# - 01 - end-of-file record
# - 02 - extended segment address record
# - 04 - extended linear address record
# - 05 - start linear address record (MDK-ARM only)
#
# dd is a data field that represents one byte of data. A record may have multiple data bytes.
# The number of data bytes in the record must match the number specified by the ll field.
#
# cc is the checksum field that represents the checksum of the record.
# The checksum is calculated by summing the values of all hexadecimal digit pairs in the record modulo 256 and taking the two's complement.
#
# Example of an Intel HEX file :
# :107D00003E08D3F73E0FD3F63E00D3F73E5DD3F6E1
# :107D10003E01D3F73E00D3F63E07D3F73E3ED3F6FF
# :017D2000C999
# :00000001FF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment