mmiogrok/dvf/dvf2h.py

201 lines
8.0 KiB
Python
Raw Normal View History

2022-05-30 02:51:20 +00:00
#!/usr/bin/env python3
import argparse, sys
from typing import *
import dvfparse
from dvfparse import Dvf, DvfMI, DvfVN, DvfSN
def comment_lines(t: str, lines: Sequence[str]) -> Sequence[str]:
if t in ('c', 'gas-with-cpp', 'gas', 'ld-script'):
return ["/* ", *[" * " + l for l in lines], " */"]
else:
return ["; " + l for l in lines]
def format_define(t: str, pfix: str, name: str, addr: str, width: int, deref: bool) -> str:
name = name.upper()
if t == 'c':
return "#define %s%s (%s(volatile uint%d_t*)0x%04x)" % \
(pfix, name, "*" if deref else "", width, addr)
elif t in ('gas-with-cpp', 'gas', 'nasm'):
PFIX = {
'gas-with-cpp': '#',
'gas': '.',
'nasm': '%'
}
return "%cdefine %s%s 0x%04x" % (PFIX[t], pfix, name, addr)
elif t in ('nasm-equ', 'asxxxx', 'elflift'):
EQU = {
'nasm-equ': " equ ",
'asxxxx': " = ",
'elflift': "@",
}
return "%s%s%s0x%04x" % (pfix, name, EQU[t], addr)
else:
assert False, ("bad format type %s" % t)
def format_defines(t: str, pfixr: str, pfixv: str,
regs: List[DvfSN], vt: List[DvfVN]) -> str:
return '\n'.join(format_define(t, pfixr, reg.name, reg.address,
(reg.flg2 & 0xf) * 2, True) for reg in regs) \
+ '\n'.join(
format_define(t, pfixv, ev.name, ev.address, 16, False) for ev in vt) + '\n'
def format_mem_line(mi: DvfMI) -> str:
# FIXME: handle multiple of each existing
NAMES = {
DvfMI.MREG_FLASH: "flash",
DvfMI.MREG_RAM: "ram",
DvfMI.MREG_VECTOR: "vectors",
DvfMI.MREG_CALLT: "callt",
DvfMI.MREG_CALLF: "callf"
}
return "\t%s (%s%s%s) : ORIGIN = 0x%04x, LENGTH = 0x%04x" % \
(NAMES.get(mi.mreg_type, "//unk%02x"%mi.mreg_type),
"r" if (mi.access & 1) != 0 else "",
"w" if (mi.access & 2) != 0 else "",
"x" if (mi.access & 4) != 0 else "",
mi.addr_start, mi.addr_end - mi.addr_start + 1)
def format_linker_script(mi: List[DvfMI]) -> str:
useful_types = {
DvfMI.MREG_FLASH,
DvfMI.MREG_RAM,
DvfMI.MREG_VECTOR,
DvfMI.MREG_CALLT,
DvfMI.MREG_CALLF,
}
#mi = [m for m in mi if m.mreg_type in useful_types]
flashreg = [m for m in mi if m.mreg_type == DvfMI.MREG_FLASH]
flashreg.sort(key=lambda m: m.addr_start)
assert len(flashreg) > 0
flashreg = flashreg[0]
if not any(m.mreg_type == DvfMI.MREG_VECTOR for m in mi):
# let's guess something
lowest_next = [m for m in mi if m.addr_start > flashreg.addr_start]
lowest_next.sort(key=lambda m: m.addr_start)
assert len(lowest_next) > 0
if lowest_next[0].addr_start < flashreg.addr_end:
# we need a subregion of flash so this should be usable
mi.append(DvfMI(0, lowest_next[0].addr_start-1,
DvfMI.MREG_VECTOR, 1))
# now modify the flash so that it only starts AFTER the lowest_next
i = 0
oldorg = flashreg.addr_start
while any(m.addr_start == flashreg.addr_start
and m.mreg_type != DvfMI.MREG_FLASH for m in mi):
flashreg = flashreg._replace(addr_start = lowest_next[i].addr_end + 1)
i = i = 1
for i in range(len(mi)):
if mi[i].addr_start == oldorg and mi[i].mreg_type == DvfMI.MREG_FLASH:
mi[i] = flashreg
break
return "MEMORY {\n" + '\n'.join(format_mem_line(m) for m in mi) + "\n}\n"
if __name__ == '__main__':
parser = argparse.ArgumentParser(prog="dvf2h",
description="Convert NEC/Renesas Device "+\
"Files to C/asm defines and linker scripts")
parser.add_argument('-p', '--use-reg-prefix', dest='reg_prefix',
default=None, action='store_true',
help="Use a REG_ prefix in the names for registers. "+\
"Defaults to on for the 'c' output format, but off otherwise")
parser.add_argument('-P', '--no-use-reg-prefix', dest='reg_prefix',
default=None, action='store_false',
help="Don't use a REG_ prefix in the names for registers. "+\
"See the help for `--use-reg-prefix' for more info.")
parser.add_argument('-f', '--out-format', default="c",
choices=["c", "gas-with-cpp", "gas", "nasm-def",
"nasm-equ", "asxxxx", "elflift", "ld-script"],
help="Output format. 'c' is a C/C++ header (default), "+\
"'gas-with-cpp' is a GNU as-compatible header, "+\
"'gas' uses GNU as .define directives, "+\
"'nasm-def' outputs NASM %%define directives, "+\
"'nasm-equ' outputs defines using the EQU syntax, "+\
"'asxxxx' outputs ASxxxx-compatible include files, "+\
"'elflift' outputs an elflift-compatible symbol table, "+\
"'ld-script' outputs the MEMORY part of a GNU ld script.")
parser.add_argument('-o', '--output', type=str, default=None)
parser.add_argument('input', type=argparse.FileType('rb'))
args = parser.parse_args()
reg_prefix = args.reg_prefix or (args.out_format == 'c')
output = sys.stdout if args.output is None else open(args.output, 'w')
try:
dvf = Dvf.parse(args.input.read())
md = dvf.sections[dvfparse.name2int('MD')]
mi = dvf.sections[dvfparse.name2int('MI')]
sn = dvf.sections[dvfparse.name2int('SN')]
es = [v for k, v in dvf.sections.items() if k == dvfparse.name2int('ES')]
vn = dvf.sections[dvfparse.name2int('VN')]
assert len(md) == 1
md = md[0]
assert len(es) == 0 or len(es) == 1
es = es[0] if len(es) != 0 else None
# FIXME: do something about bitflags
# these are flags of another listed register, you have to find
# the non-1bit SN entry with the same address as this one to
# figure out the name of the register it belogs to
sn = [DvfSN(s.name, s.flg0, s.flg1, s.flg2, s.address, s.flg3, s.flg4)
for s in sn if (s.flg2 & 0xf) != 1]
if es is not None:
es = [DvfSN(s.name, s.flg0, s.flg1, s.flg2, s.address, s.flg3,
s.flg4) for s in es if (s.flg2 & 0xf) != 1]
if (dvf.mcutype & 0xF0) == Dvf.MCU_78K0R:
# FIXME: ugly hack
sn = [DvfSN(s.name, s.flg0, s.flg1, s.flg2,
s.address | 0xf0000, s.flg3, s.flg4) for s in sn]
if es is not None:
es = [DvfSN(s.name, s.flg0, s.flg1, s.flg2,
s.address | 0xf0000, s.flg3, s.flg4) for s in es]
output.write('\n'.join(comment_lines(args.out_format, [
"%s automatically generated by dvf2h.py" % \
("Linker script" if args.out_format == 'ld-script'
else "Register include file"),
"For the %s (%s)" % (dvf.chipname_sym, dvf.chipname_disp),
"",
"Original: DVF version %s from %s" % (md.version, md.timestamp),
dvf.copyright_notice
])))
output.write("\n\n")
if args.out_format == 'ld-script':
output.write(format_linker_script(mi))
else:
rpf = "REG_" if reg_prefix else ""
vpf = "VEC_" if reg_prefix else ""
output.write(format_defines(args.out_format, rpf, vpf, sn, []))
output.write("\n\n\n")
if es is not None:
output.write(format_defines(args.out_format, rpf, vpf, es, []))
output.write("\n\n\n")
output.write(format_defines(args.out_format, rpf, vpf, [], vn))
output.write("\n\n\n")
finally:
if args.output is not None:
output.close()