Created
March 8, 2023 17:13
-
-
Save skeletozaure/7356738b16cfb738fdd8e9edaa62b4b9 to your computer and use it in GitHub Desktop.
Hex2Bas.py : Convert Intel Hex file to Basic for Mattel Aquarius
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# 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