#!/usr/bin/env python
|
#!/usr/bin/env python
|
"""
|
"""
|
build_rom.py: Create VHDL package with ROM initialization constant from
|
build_rom.py: Create VHDL package with ROM initialization constant from
|
Intel-HEX object code file.
|
Intel-HEX object code file.
|
|
Please use with --help to get some brief usage instructions.
|
"""
|
"""
|
__author__ = "Jose A. Ruiz"
|
__author__ = "Jose A. Ruiz"
|
__license__ = "LGPL"
|
__license__ = "LGPL"
|
|
|
|
|
"""
|
"""
|
Please see the usage instructions and the comments for function 'main'.
|
Please see the usage instructions and the comments for function 'main'.
|
"""
|
"""
|
|
|
|
|
import sys
|
import sys
|
import getopt
|
import getopt
|
|
|
|
|
|
|
def usage():
|
def usage():
|
"""Print usage instructions"""
|
"""Print usage instructions"""
|
print ""
|
print ""
|
print "usage:"
|
print "usage:"
|
print "python build_rom.py [arguments]\n"
|
print "python build_rom.py [arguments]\n"
|
print "Builds VHDL ROM constant from template and Intel HEX object file.\n"
|
print "Builds VHDL ROM constant from template and Intel HEX object file.\n"
|
print "ALL of the following arguments should be given, in any order:"
|
print "ALL of the following arguments should be given, in any order:"
|
print "{f|file} <filename> Object code file name"
|
print "{f|file} <filename> Object code file name"
|
print "{c|constant} <name> Name of target VHDL constant"
|
|
print "{p|package} <name> Name of target VHDL package"
|
|
print "{n|name} <name> Name of project (used only in comment)"
|
|
print "{o|output} <filename> Target VHDL file name"
|
|
print ""
|
print ""
|
print "Additionally, any of these arguments can be given:"
|
print "Additionally, any of these arguments can be given:"
|
|
print "{h|help} Show help string and exit"
|
|
print "{c|constant} <name> Name of target VHDL object code constant"
|
|
print "{p|package} <name> Name of target VHDL package"
|
|
print "{n|name} <name> Name of project (used only in comments)"
|
|
print "{o|output} <filename> Target VHDL file name"
|
|
print "{xcode} <number> Size of XCODE memory in bytes"
|
|
print " (defaults to 2048)"
|
|
print "{xdata} <number> Size of XDATA memory in bytes"
|
|
print " (defaults to 0)"
|
print "{v|vhdl} <filename> VHDL template"
|
print "{v|vhdl} <filename> VHDL template"
|
print " (defaults to templates/obj_code_kg_template.vhdl)"
|
print " (defaults to templates/obj_code_kg_template.vhdl)"
|
print "{i|indent} <number> Indentation in VHDL tables (decimal)"
|
print "{i|indent} <number> Indentation in VHDL tables (decimal)"
|
print " (defaults to 4)"
|
print " (defaults to 4)"
|
|
|
|
|
|
|
def help():
|
def help():
|
"""Print help message a bit longer than usage message."""
|
"""Print help message a bit longer than usage message."""
|
print "\nPurpose:\n"
|
print "\nPurpose:\n"
|
print "Reads the code and data binary files and 'slices' them in byte"
|
print "Builds initialization package for Light52 MCU core."
|
print "columns."
|
print "The object code bytes are converted to VHDL strings and then inserted"
|
print "The data columns are converted to VHDL strings and then inserted"
|
print "into the vhdl template, in place of tag @code_bytes@.\n"
|
print "into the vhdl template, in place of tags @code0@ .. @code3@ and "
|
|
print "@data0@ .. @data3@. Column 0 is LSB and column3 is MSB.\n"
|
|
print "Tags like @data31@ and @data20@ etc. can be used to initialize"
|
|
print "memories in 16-bit buses, also split in byte columns.\n"
|
|
print "Template tags are replaced as follows:"
|
print "Template tags are replaced as follows:"
|
print "@obj_pkg_name@ : Name of package in target vhdl file."
|
print "@obj_pkg_name@ : Name of package in target vhdl file."
|
print "@const_name@ : Name of constant (VHDL table)."
|
print "@const_name@ : Name of object code constant (VHDL table)."
|
print "@obj_size@ : Total size of code table in bytes."
|
print "@obj_size@ : Total size of code table in bytes."
|
print "@project@ : Project name."
|
print "@obj_bytes@ : Array of object code bytes."
|
|
print "@project_name@ : Project name."
|
print "@xcode_size@ : Size of XCODE memory."
|
print "@xcode_size@ : Size of XCODE memory."
|
print "@xdata_size@ : Size of XDATA memory."
|
print "@xdata_size@ : Size of XDATA memory."
|
|
|
def parse_hex_line(line):
|
def parse_hex_line(line):
|
"""Parse code line in HEX object file."""
|
"""Parse code line in HEX object file."""
|
line = line.strip()
|
line = line.strip()
|
slen = int(line[1:3],16)
|
slen = int(line[1:3],16)
|
sloc = int(line[3:7],16)
|
sloc = int(line[3:7],16)
|
stype = line[7:9]
|
stype = line[7:9]
|
sdata = line[9:len(line)-2]
|
sdata = line[9:len(line)-2]
|
schk = int(line[len(line)-2:],16)
|
schk = int(line[len(line)-2:],16)
|
|
|
csum = slen + int(sloc / 256) + (sloc % 256) + int(stype,16)
|
csum = slen + int(sloc / 256) + (sloc % 256) + int(stype,16)
|
bytes = [0, ] * slen
|
bytes = [0, ] * slen
|
for i in range(slen):
|
for i in range(slen):
|
sbyte = int(sdata[i*2:i*2+2],16)
|
sbyte = int(sdata[i*2:i*2+2],16)
|
bytes[i] = sbyte;
|
bytes[i] = sbyte;
|
csum = csum + sbyte
|
csum = csum + sbyte
|
|
|
csum = ~csum
|
csum = ~csum
|
csum = csum + 1
|
csum = csum + 1
|
csum = csum % 256
|
csum = csum % 256
|
if csum != schk:
|
if csum != schk:
|
return (None, None)
|
return (None, None)
|
|
|
return (sloc, bytes)
|
return (sloc, bytes)
|
|
|
|
|
def read_ihex_file(ihex_filename):
|
def read_ihex_file(ihex_filename):
|
"""
|
"""
|
Read Intel HEX file into a 64KB array.
|
Read Intel HEX file into a 64KB array.
|
The file is assumed not to have any object code outside the 64K boundary.
|
The file is assumed not to have any object code outside the 64K boundary.
|
Return the 64K array plus the size and bounds of the read data.
|
Return the 64K array plus the size and bounds of the read data.
|
"""
|
"""
|
|
|
# CODE array, initialized to 64K of zeros...
|
# CODE array, initialized to 64K of zeros...
|
xcode = [0, ] * 65536
|
xcode = [0, ] * 65536
|
# ...and code boundaries, initialized out of range.
|
# ...and code boundaries, initialized out of range.
|
bottom = 100000
|
bottom = 100000
|
top = -1
|
top = -1
|
(xcode, top, bottom)
|
(xcode, top, bottom)
|
|
|
# Read the whole file to a list of lines...
|
# Read the whole file to a list of lines...
|
fin = open(ihex_filename, "r")
|
fin = open(ihex_filename, "r")
|
ihex_lines = fin.readlines()
|
ihex_lines = fin.readlines()
|
fin.close()
|
fin.close()
|
|
|
# ...and parse the lines one by one.
|
# ...and parse the lines one by one.
|
total_bytes = 0
|
total_bytes = 0
|
for line in ihex_lines:
|
for line in ihex_lines:
|
(address, bytes) = parse_hex_line(line)
|
(address, bytes) = parse_hex_line(line)
|
if address == None:
|
if address == None:
|
print "Checksum error!"
|
print "Checksum error!"
|
sys.exit(1)
|
sys.exit(1)
|
total_bytes = total_bytes + len(bytes)
|
total_bytes = total_bytes + len(bytes)
|
for i in range(len(bytes)):
|
for i in range(len(bytes)):
|
xcode[address + i] = bytes[i]
|
xcode[address + i] = bytes[i]
|
|
|
if address < bottom:
|
if address < bottom:
|
bottom = address
|
bottom = address
|
|
|
if (address + len(bytes)) > top:
|
if (address + len(bytes)) > top:
|
top = (address + len(bytes))
|
top = (address + len(bytes))
|
|
|
print "Read %d bytes from file '%s'" % (total_bytes, ihex_filename)
|
print "Read %d bytes from file '%s'" % (total_bytes, ihex_filename)
|
print "Code range %04xh to %04xh" % (bottom, top)
|
print "Code range %04xh to %04xh" % (bottom, top)
|
return (xcode, total_bytes, bottom, top)
|
return (xcode, total_bytes, bottom, top)
|
|
|
|
|
def build_vhdl_code(params, xcode, obj_size):
|
def build_vhdl_code(params, xcode, obj_size):
|
"""
|
"""
|
Read VHDL template file and replace all the tags with the values given in
|
Read VHDL template file and replace all the tags with the values given in
|
the command line parameters.
|
the command line parameters.
|
Return the new file contents as a string.
|
Return the new file contents as a string.
|
"""
|
"""
|
|
|
# The resulting VHDL text will be stored here.
|
# The resulting VHDL text will be stored here.
|
vhdl_code = ""
|
vhdl_code = ""
|
|
|
|
|
# Open file and read it into a list of lines.
|
# Open file and read it into a list of lines.
|
fin = open(params['template'], "r")
|
fin = open(params['template'], "r")
|
lines = fin.readlines()
|
lines = fin.readlines()
|
fin.close()
|
fin.close()
|
|
|
# Now process the template lines one by one.
|
# Now process the template lines one by one.
|
for line in lines:
|
for line in lines:
|
line = line.strip()
|
line = line.strip()
|
|
|
if line.rfind("@obj_bytes@") >= 0:
|
if line.rfind("@obj_bytes@") >= 0:
|
# insert object code as list of byte literals.
|
# insert object code as list of byte literals.
|
obj_str = " "
|
obj_str = " "
|
for i in range(obj_size):
|
for i in range(obj_size):
|
if i != (obj_size-1):
|
if i != (obj_size-1):
|
sbyte = "X\"%02x\", " % xcode[i]
|
sbyte = "X\"%02x\", " % xcode[i]
|
else:
|
else:
|
sbyte = "X\"%02x\" " % xcode[i]
|
sbyte = "X\"%02x\" " % xcode[i]
|
obj_str = obj_str + sbyte
|
obj_str = obj_str + sbyte
|
if (i % 8) == 7:
|
if (i % 8) == 7:
|
obj_str = obj_str + "\n "
|
obj_str = obj_str + "\n "
|
|
|
line = line.replace("@obj_bytes@",obj_str)
|
line = line.replace("@obj_bytes@",obj_str)
|
|
|
elif line.rfind("@obj_size@") >= 0:
|
elif line.rfind("@obj_size@") >= 0:
|
# Insert object code size (not necessarily equal to xcode_size)
|
# Insert object code size (not necessarily equal to xcode_size)
|
line = line.replace("@obj_size@","%d" % (obj_size-1))
|
line = line.replace("@obj_size@","%d" % (obj_size-1))
|
|
|
elif line.rfind("@xcode_size@") >= 0:
|
elif line.rfind("@xcode_size@") >= 0:
|
# Insert XCODE memory
|
# Insert XCODE memory
|
line = line.replace("@xcode_size@","%d" % (params['xcode_size']))
|
line = line.replace("@xcode_size@","%d" % (params['xcode_size']))
|
|
|
elif line.rfind("@xdata_size@") >= 0:
|
elif line.rfind("@xdata_size@") >= 0:
|
# Insert XDATA memory
|
# Insert XDATA memory
|
line = line.replace("@xdata_size@","%d" % (params['xdata_size']))
|
line = line.replace("@xdata_size@","%d" % (params['xdata_size']))
|
|
|
elif line.rfind("@obj_pkg_name@") >= 0:
|
elif line.rfind("@obj_pkg_name@") >= 0:
|
# Insert package name: hardwired
|
# Insert package name: hardwired
|
line = line.replace("@obj_pkg_name@",params['package'])
|
line = line.replace("@obj_pkg_name@",params['package'])
|
|
|
elif line.rfind("@project_name@") >= 0:
|
elif line.rfind("@project_name@") >= 0:
|
# Insert project name
|
# Insert project name
|
line = line.replace("@project_name@",params['project'])
|
line = line.replace("@project_name@",params['project'])
|
|
|
|
|
vhdl_code = vhdl_code + line + "\n"
|
vhdl_code = vhdl_code + line + "\n"
|
|
|
return vhdl_code
|
return vhdl_code
|
|
|
|
|
def main(argv):
|
def main(argv):
|
"""Main body of the program."""
|
"""Main body of the program."""
|
|
|
# Parse command line parameters using GetOpt
|
# Parse command line parameters using GetOpt
|
try:
|
try:
|
opts, args = getopt.getopt(argv, "hf:n:p:c:o:i:v:",
|
opts, args = getopt.getopt(argv, "hf:n:p:c:o:i:v:",
|
["help", "file=", "name=", "package=", "constant=",
|
["help", "file=", "name=", "package=", "constant=",
|
"output=", "indent=", "vhdl=", "xcode=", "xdata=" ])
|
"output=", "indent=", "vhdl=", "xcode=", "xdata=" ])
|
except getopt.GetoptError, err:
|
except getopt.GetoptError, err:
|
print ""
|
print ""
|
print err
|
print err
|
usage()
|
usage()
|
sys.exit(2)
|
sys.exit(2)
|
|
|
# Command line parameters, initialized to their default values
|
# Command line parameters, initialized to their default values
|
params = {'project': '<unknown>',
|
params = {'project': '<unknown>',
|
'package': 'obj_code_pkg',
|
'package': 'obj_code_pkg',
|
'indent': 4,
|
'indent': 4,
|
'constant': 'obj_code',
|
'constant': 'obj_code',
|
'target': 'obj_code_pkg.vhdl',
|
'target': 'obj_code_pkg.vhdl',
|
'hex': '',
|
'hex': '',
|
'xcode_size': 2048,
|
'xcode_size': 2048,
|
'xdata_size': 0,
|
'xdata_size': 0,
|
'template': "./templates/obj_code_pkg_template.vhdl"
|
'template': "./templates/obj_code_pkg_template.vhdl"
|
}
|
}
|
|
|
|
|
# Parse coommand line parameters
|
# Parse coommand line parameters
|
for opt, arg in opts:
|
for opt, arg in opts:
|
if opt in ("-h", "--help"):
|
if opt in ("-h", "--help"):
|
usage()
|
usage()
|
help()
|
help()
|
exit(1)
|
exit(1)
|
if opt in ("-v", "--vhdl"):
|
if opt in ("-v", "--vhdl"):
|
params['template'] = arg
|
params['template'] = arg
|
elif opt in ("-o", "--output"):
|
elif opt in ("-o", "--output"):
|
params['target'] = arg
|
params['target'] = arg
|
elif opt in ("-c", "--constant"):
|
elif opt in ("-c", "--constant"):
|
params['constant'] = arg
|
params['constant'] = arg
|
elif opt in ("-f", "--file"):
|
elif opt in ("-f", "--file"):
|
params['hex'] = arg
|
params['hex'] = arg
|
elif opt in ("-p", "--package"):
|
elif opt in ("-p", "--package"):
|
params['package'] = arg
|
params['package'] = arg
|
elif opt in ("-n", "--name"):
|
elif opt in ("-n", "--name"):
|
params['project'] = arg
|
params['project'] = arg
|
elif opt in ("-i", "--indent"):
|
elif opt in ("-i", "--indent"):
|
params['indent'] = int(arg)
|
params['indent'] = int(arg)
|
elif opt in ("--xcode"):
|
elif opt in ("--xcode"):
|
params['xcode_size'] = int(arg)
|
params['xcode_size'] = int(arg)
|
elif opt in ("--xdata"):
|
elif opt in ("--xdata"):
|
params['xdata_size'] = int(arg)
|
params['xdata_size'] = int(arg)
|
|
|
# Ok, now
|
# Ok, now read and parse the input Intel HEX object code file.
|
if params['hex']:
|
if params['hex']:
|
(xcode, total_bytes, bottom, top) = read_ihex_file(params['hex']);
|
(xcode, total_bytes, bottom, top) = read_ihex_file(params['hex']);
|
else:
|
else:
|
print "Object HEX file name missing.";
|
print "Object HEX file name missing.";
|
usage()
|
usage()
|
return 1
|
return 1
|
|
|
|
|
# Make sure the object code fits the implemented XCODE space.
|
# Make sure the object code fits into the implemented XCODE space.
|
# If it doesn't, print a warning and let the user deal with it.
|
# If it doesn't, print a warning and let the user deal with it.
|
# Assuming that XCODE starts at address zero -- that's how the core works.
|
# Assuming that XCODE starts at address zero -- that's how the core works.
|
if params['xcode_size'] < top:
|
if params['xcode_size'] < top:
|
print "\nWARNING: Object code does not fit XCODE space!\n"
|
print "\nWARNING: Object code does not fit XCODE space!\n"
|
|
|
|
|
# Build the package source...
|
# Build the package source...
|
vhdl_code = build_vhdl_code(params, xcode, top);
|
vhdl_code = build_vhdl_code(params, xcode, top);
|
|
|
# ...and write it to the target file.
|
# ...and write it to the target file.
|
fout = None
|
fout = None
|
try:
|
try:
|
fout = open(params['target'], "w")
|
fout = open(params['target'], "w")
|
fout.write(vhdl_code)
|
fout.write(vhdl_code)
|
fout.close()
|
fout.close()
|
print "VHDL code table written to %s" % params['target']
|
print "VHDL code table written to %s" % params['target']
|
except:
|
except:
|
print "Trouble opening %s for output" % params['target']
|
print "Trouble opening %s for output" % params['target']
|
finally:
|
finally:
|
if fout: fout.close()
|
if fout: fout.close()
|
|
|
|
|
if __name__ == "__main__":
|
if __name__ == "__main__":
|
main(sys.argv[1:])
|
main(sys.argv[1:])
|
sys.exit(0)
|
sys.exit(0)
|
|
|
|
|