#!/usr/bin/env python3

# Tool for converting width of verilog hex files

import sys
import argparse
import re

# Assume little-endian, and that widths are multiples of 4

def width_convert(ilines, width, base):
	olines = []
	pad_fmt = "{:>0" + str(width // 4) + "}"
	accum = ""
	for l in ilines:
		if l.startswith("@"):
			if len(accum):
				olines.append(pad_fmt.format(accum))
				accum = ""
			# TODO: address scaling wrong if input not byte-sized:
			olines.append("@{:x}".format((int(l[1:], 16) - base) // (width // 8)))
			continue
		for num in re.findall(r"[0-9a-fA-F]+", l):
			accum = num + accum
			while len(accum) >= width // 4:
				olines.append(accum[len(accum) - width // 4 :])
				accum = accum[:len(accum) - width // 4]
	if len(accum):
		olines.append(pad_fmt.format(accum))
	return olines

def parseint(arg, name, default):
	if arg is None:
		arg = default
	try:
		if type(arg) is str and arg.startswith("0x"):
			arg = int(arg, 16)
		else:
			arg = int(arg)
	except ValueError:
		sys.exit("Invalid value for {}: {}".format(name, arg))
	return arg

if __name__ == "__main__":
	parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
	parser.add_argument("input", help="Input file name")
	parser.add_argument("--width", "-w", help="Output hex width (default 32)")
	parser.add_argument("--base", "-b", help="Base address for @ commands (subtracted)")
	parser.add_argument("--output", "-o", help="Output file name")
	args = parser.parse_args()
	if args.output is None:
		ofile = sys.stdout
	else:
		ofile = open(args.output, "w")
	if args.input is None:
		ifile = sys.stdin
	else:
		ifile = open(args.input)
	width = parseint(args.width, "width", 32)
	base = parseint(args.base, "base", 0)
	olines = width_convert(ifile, width, base)
	for l in olines:
		ofile.write(l + "\n")