stuff
This commit is contained in:
commit
303da594c4
|
@ -0,0 +1,3 @@
|
|||
t/
|
||||
__pycache__/
|
||||
*.pyc
|
|
@ -0,0 +1,200 @@
|
|||
#!/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()
|
||||
|
|
@ -0,0 +1,301 @@
|
|||
|
||||
from __future__ import annotations
|
||||
import argparse, os, os.path, struct, sys
|
||||
from typing import *
|
||||
|
||||
def name2int(s: Union[str, bytes]):
|
||||
if isinstance(s, str): return ord(s[0]) + ord(s[1])*256
|
||||
else:
|
||||
assert isinstance(s, bytes)
|
||||
return s[0] + s[1]*256
|
||||
|
||||
# supported section types:
|
||||
# * SN: SFRs
|
||||
# * VN: vectors
|
||||
# * MI: memory layout
|
||||
# * ES: 2nd SFR
|
||||
# * MD: probably "metadata", version & timestam
|
||||
#
|
||||
# can be parsed:
|
||||
# * SC: something with SFRs
|
||||
# * FL: flash stuff
|
||||
# * OD: debug stuff
|
||||
#
|
||||
# I know about their existence:
|
||||
# * CG, XD, CT, QB, EV, EM, BS, UE, PC
|
||||
#
|
||||
# I have no clue:
|
||||
# * VI, MC, SS, IO, PT, MK, MT, ID, BI, LD, PL, PI, SI, CI, SX, PE, PS
|
||||
|
||||
class DvfSN(NamedTuple):
|
||||
name: str
|
||||
flg0: int
|
||||
flg1: int
|
||||
flg2: int
|
||||
address: int
|
||||
flg3: int
|
||||
flg4: int
|
||||
|
||||
def parse(b: bytes) -> 'DvfSN':
|
||||
name, flg0, flg1, flg2, addr, nul1, flg3, flg4, nulls = struct.unpack(
|
||||
'<16sH2HHH2H10s', b)
|
||||
name = name.rstrip(b'\0').decode('utf-8')
|
||||
assert nul1 == 0
|
||||
assert all(n == 0 for n in nulls)
|
||||
|
||||
return DvfSN(name, flg0, flg1, flg2, addr, flg3, flg4)
|
||||
|
||||
DvfES = DvfSN
|
||||
|
||||
class DvfVN(NamedTuple):
|
||||
name: str
|
||||
address: int
|
||||
int_type: int
|
||||
enable_reg_addr: int
|
||||
enable_bit_flag: int
|
||||
|
||||
def parse(b: bytes) -> DvfVN:
|
||||
name, addr, ityp, enrg, enbt = struct.unpack('<16sHHHH', b)
|
||||
name = name.rstrip(b'\0').decode('utf-8')
|
||||
|
||||
return DvfVN(name, addr, ityp, enrg, enbt)
|
||||
|
||||
class DvfMI(NamedTuple):
|
||||
ACCESS_R = 1
|
||||
ACCESS_W = 2
|
||||
ACCESS_X = 4
|
||||
ACCESS_RSV = 8 # reserved
|
||||
|
||||
MREG_FLASH = 0x00
|
||||
MREG_RAM = 0x01
|
||||
# TODO: rama again? (0x2)
|
||||
# TODO: 0..ffffe, 0..fffff regions (0xb, 0xc)
|
||||
MREG_RESERVED = 0x0e
|
||||
MREG_CPUREGS = 0x0f
|
||||
MREG_SFR = 0x10
|
||||
# TODO ffd0..ffdf (0x11)
|
||||
MREG_VECTOR = 0x12
|
||||
MREG_CALLT = 0x13
|
||||
MREG_CALLF = 0x14
|
||||
MREG_SHORT = 0x16 # "short direct addressing" in instruction set
|
||||
MREG_SHORT_SFR = 0x18 # above + is SFR
|
||||
MREG_SFR2 = 0x24
|
||||
MREG_ROM_ENTRY = 0x25
|
||||
MREG_MIRROR = 0x26
|
||||
MREG_PRIVRAM = 0x27
|
||||
MREG_ROM = 0x28
|
||||
|
||||
addr_start: int
|
||||
addr_end: int
|
||||
mreg_type: int
|
||||
access: int
|
||||
|
||||
def parse(b: bytes) -> DvfMI:
|
||||
start, end, typ, acc, zeros = struct.unpack('<IIHHI', b)
|
||||
assert zeros == 0
|
||||
return DvfMI(start, end, typ, acc)
|
||||
|
||||
class DvfMD(NamedTuple):
|
||||
version: str # file format version?
|
||||
timestamp: str # also includes author
|
||||
|
||||
def parse(b: bytes) -> DvfMD:
|
||||
assert len(b) >= 40
|
||||
ver, ts = b[:8], b[8:]
|
||||
ver = ver.rstrip(b'\0').decode('utf-8')
|
||||
ts = ts.rstrip( b'\0').decode('utf-8')
|
||||
return DvfMD(ver, ts)
|
||||
|
||||
class DvfSC(NamedTuple):
|
||||
name: str
|
||||
addr1: int
|
||||
addr2: int
|
||||
|
||||
def parse(b: bytes) -> DvfSC:
|
||||
name, a1, a2 = struct.unpack('<16sII', b)
|
||||
name = name.rstrip(b'\0').decode('utf-8')
|
||||
return DvfSC(name, a1, a2)
|
||||
|
||||
class DvfFL(NamedTuple):
|
||||
FL_TYPE_NBLOCKS = 1
|
||||
FL_TYPE_BLOCK = 2
|
||||
|
||||
fl_type: int
|
||||
index: int
|
||||
address: int
|
||||
extra: int
|
||||
|
||||
def parse(b: bytes) -> DvfFL:
|
||||
typ, ind, addr, ex = struct.unpack('<HHHH', b)
|
||||
return DvfFL(typ, ind, addr, ex)
|
||||
|
||||
class DvfOD(NamedTuple):
|
||||
index: int
|
||||
subindex: int
|
||||
value: int
|
||||
|
||||
def parse(b: bytes) -> DvfOD:
|
||||
ind, subind, val = struct.unpack('<HHI', b)
|
||||
return DvfOD(ind, subind, val)
|
||||
|
||||
class DvfSect(NamedTuple):
|
||||
SN = name2int("SN")
|
||||
VN = name2int("VN")
|
||||
MI = name2int("MI")
|
||||
ES = name2int("ES")
|
||||
MD = name2int("MD")
|
||||
|
||||
SC = name2int("SC")
|
||||
FL = name2int("FL")
|
||||
OD = name2int("OD")
|
||||
|
||||
def ENTSIZE(dvftype: int) -> Dict[int, int]:
|
||||
return {
|
||||
name2int(b'SN'):40,
|
||||
name2int(b'VN'):24,
|
||||
name2int(b'MI'):16,
|
||||
name2int(b'CG'):80,
|
||||
name2int(b'ES'):40, # 78K0R only?
|
||||
name2int(b'XD'):12, # 78K0R only?
|
||||
name2int(b'CT'):96,
|
||||
name2int(b'SC'):24,
|
||||
name2int(b'QB'):136 if (dvftype & 0xF0) == 0x10 else 108,
|
||||
name2int(b'EV'):8,
|
||||
name2int(b'FL'):8,
|
||||
name2int(b'OD'):8,
|
||||
name2int(b'AF'):16,
|
||||
name2int(b'SD'):16,
|
||||
name2int(b'EM'):12,
|
||||
name2int(b'MD'):48,
|
||||
name2int(b'BS'):16, # 78K0 only?
|
||||
name2int(b'UE'):12, # RL78 only?
|
||||
name2int(b'PC'):20, # idk
|
||||
}
|
||||
|
||||
TYPES = {
|
||||
name2int('SN'): DvfSN,
|
||||
name2int('ES'): DvfES,
|
||||
name2int('VN'): DvfVN,
|
||||
name2int('MI'): DvfMI,
|
||||
name2int('MD'): DvfMD,
|
||||
name2int('SC'): DvfSC,
|
||||
name2int('FL'): DvfFL,
|
||||
name2int('OD'): DvfOD
|
||||
}
|
||||
|
||||
name: int
|
||||
nentries: int
|
||||
offset: int
|
||||
|
||||
class Dvf(NamedTuple):
|
||||
MAGIC = 0x1a
|
||||
|
||||
# TODO: add support for V850/RH850, RX
|
||||
MCU_78K0 = 0
|
||||
MCU_78K0R = 0x10
|
||||
MCU_RL78x1y = 0x20
|
||||
MCU_RL78x2y = 0x30
|
||||
|
||||
IDK_KNOWN_78K0 = {
|
||||
b'\0\01\x02!\x02\0\0H\x11', # Kx2
|
||||
b'\0\01\x02\0\x01\0\0H\x11', # Kx2-A, uPD78F8039
|
||||
b'\0\01\x02\x01\x01\0\0H\x11', # Fx2
|
||||
b'\0\01\x02\x01\x02\0\0H\x11', # Kx2-L
|
||||
b'\0\01\x02\x10\x01\0\0H\x11', # misc (Ix2, KC2-A, uPD78F0730)
|
||||
b'\0\01\x02\x11\x01\0\0H\x11', # FC2
|
||||
b'\0\01\x02\x12\x01\0\0H\x11', # Lx3
|
||||
b'\0\02\x02\0\x01\0\0H\x11', # misc (uPD78F8077, Dx2, Kx2-C, uPD78F8039)
|
||||
b'\0\02\x02\x02\x01\0\0H\x11', # Fx2-L
|
||||
b'\0\02\x02\x10\x01\0\0H\x11', # Lx3-M
|
||||
}
|
||||
IDK_KNOWN_78K0R = {
|
||||
b'\x0b\0\0\x03 \x02\0\0H\x11', # KC3-L
|
||||
b'\x0b\0\0\x03!\x01\0\0H\x11', # Lx3
|
||||
b'\x0b\0\0\x03\0\x01\0\0H\x11', # misc (Kx3-L(USB), Hx3, LG3-M, uPD78F80xx)
|
||||
b'\x0b\0\0\x03\0\x02\0\0H\x11', # Kx3-L, Ix3
|
||||
b'\x0b\0\0\x03\0\x03\0\0H\x11', # Kx3
|
||||
b'\x0b\0\0\x03\x01\x01\0\0H\x11', # Fx3, Kx3-C
|
||||
b'\x0b\0\0\x03\x01\x02\0\0H\x11', # Kx3-L
|
||||
b'\x0b\0\0\x03\x10\x01\0\0H\x11', # Lx3, Kx3-A
|
||||
b'\x0b\0\0\x03\x10\x02\0\0H\x11', # Kx3-L
|
||||
b'\x0b\0\0\x03\x11\x01\0\0H\x11', # KF3-C
|
||||
}
|
||||
IDK_KNOWN_RL78x1y = {
|
||||
b'\x0c\0\0\x03 \x01\0\0H\x11', # G11, G1D
|
||||
b'\x0c\0\0\x03!\x01\0\0H\x11', # I1A, L1C
|
||||
b'\x0c\0\0\x030\x02\0\0H\x11', # G14
|
||||
b'\x0c\0\0\x03\0\x01\0\0H\x11', # misc (G13A, G1H, F15, I1E, H1D, I1C)
|
||||
b'\x0c\0\0\x03\x01\x01\0\0H\x11', # misc (L1A, I1D, G1G, G1A, L13, I1C, D1A, G1F, F1A)
|
||||
b'\x0c\0\0\x03\x01\x02\0\0H\x11', # G1E
|
||||
b'\x0c\0\0\x03\x02\x01\0\0H\x11', # I1B, F12
|
||||
b'\x0c\0\0\x03\x03\x01\0\0H\x11', # G10, L12
|
||||
b'\x0c\0\0\x03\x10\x01\0\0H\x11', # misc (G1N, F1E, G1P, G1C, D1A, G1M, G1K)
|
||||
b'\x0c\0\0\x03\x11\x01\0\0H\x11', # L1C, F13, F14
|
||||
b'\x0c\0\0\x03\x12\x01\0\0H\x11', # G12
|
||||
b'\x0c\0\0\x03\x14\x01\0\0H\x11', # G13
|
||||
}
|
||||
IDK_KNOWN_RL78x2y = {
|
||||
b'\x0c\0 \x03\0\x01\0\0H\x11', # F24
|
||||
b'\x0c\0\0\x030\x02\0\0H\x11', # FGIC
|
||||
b'\x0c\0\0\x03\x02\x01\0\0H\x11', # FGIC
|
||||
b'\x0c\0\x10\x03\x10\x01\0\0H\x11', # G23
|
||||
}
|
||||
|
||||
magic: int
|
||||
copyright_notice: str
|
||||
idk: bytes
|
||||
chipname_disp: str
|
||||
chipname_sym: str
|
||||
|
||||
mcutype: int
|
||||
sections: Dict[int, Any]
|
||||
sections_raw: List[DvfSect]
|
||||
|
||||
@staticmethod
|
||||
def parse(data: bytes, mcutype = None) -> Dvf:
|
||||
magic, crnot, idk, name_disp, name_sym, nsect = struct.unpack(
|
||||
'<B35s16s16s8sI', data[:80])
|
||||
assert magic == Dvf.MAGIC
|
||||
assert idk[14:16] in { b"\x02\0", b"\x03\0", b"\x04\0" }, str(idk)
|
||||
crnot = crnot.rstrip(b'\0').decode('utf-8')
|
||||
name_disp = name_disp.rstrip(b'\0').decode('utf-8')
|
||||
name_sym = name_sym.rstrip(b'\0').decode('utf-8')
|
||||
|
||||
#mcutype = None
|
||||
if mcutype is None:
|
||||
idkfix = idk[0:10]
|
||||
if idkfix in Dvf.IDK_KNOWN_78K0: mcutype = Dvf.MCU_78K0
|
||||
elif idkfix in Dvf.IDK_KNOWN_78K0R: mcutype = Dvf.MCU_78K0R
|
||||
elif idkfix in Dvf.IDK_KNOWN_RL78x1y: mcutype = Dvf.MCU_RL78x1y
|
||||
elif idkfix in Dvf.IDK_KNOWN_RL78x2y: mcutype = Dvf.MCU_RL78x2y
|
||||
else: assert False, ("unknown MCU type", idk)
|
||||
|
||||
sects = {}
|
||||
sraw = []
|
||||
for i in range(nsect):
|
||||
shblob = data[(80+i*12):(80+(i+1)*12)]
|
||||
name, nentries, offset, zeros = struct.unpack('<HHH6s', shblob)
|
||||
if not all(z == 0 for z in zeros):
|
||||
continue # idk
|
||||
|
||||
sraw.append(DvfSect(name, nentries, offset))
|
||||
if nentries == 0: continue
|
||||
|
||||
#print("%c%c" % (chr(name&0xff),chr(name>>8)))
|
||||
entsize = DvfSect.ENTSIZE(mcutype)[name]
|
||||
|
||||
sdblob = data[offset:(offset+entsize*nentries)]
|
||||
|
||||
styp = DvfSect.TYPES.get(name)
|
||||
if styp is None: sects[name] = sdblob
|
||||
else:
|
||||
l = []
|
||||
for j in range(nentries):
|
||||
sdiblob = sdblob[(j*entsize):((j+1)*entsize)]
|
||||
#if name == name2int("MD"):
|
||||
# print("esz",entsize,"j",j,"blob",sdiblob)
|
||||
l.append(DvfSect.TYPES[name].parse(sdiblob))
|
||||
sects[name] = l
|
||||
|
||||
return Dvf(magic, crnot, idk, name_disp, name_sym, mcutype, sects, sraw)
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os, struct, sys
|
||||
import json, xml, xml.etree
|
||||
import xml.etree.ElementTree as ET
|
||||
from typing import *
|
||||
|
||||
import dvfparse
|
||||
from dvfparse import Dvf, DvfMI, DvfVN, DvfSN
|
||||
|
||||
|
||||
class DRec(NamedTuple):
|
||||
path: str
|
||||
magic: bytes
|
||||
name: str
|
||||
bromsize: int
|
||||
|
||||
class XRec(NamedTuple):
|
||||
#path: str # is mostly prodname anyway
|
||||
nickname: str # "product series"
|
||||
prodname: str
|
||||
proddispname: str
|
||||
dvfname: str
|
||||
romsz: int
|
||||
ramsz: int
|
||||
npins: int
|
||||
dvf: DRec
|
||||
|
||||
|
||||
def get_common_masks(l: List[bytes]) -> (bytes, bytes):
|
||||
#return (l[:10], l[:10])
|
||||
bits = 16*8
|
||||
mask = (1<<bits)-1
|
||||
negb = mask
|
||||
posb = mask
|
||||
|
||||
for b in l:
|
||||
i = int.from_bytes(b, byteorder='big')
|
||||
posb = posb & i
|
||||
negb = (negb & ~i) & mask
|
||||
|
||||
negb = (~negb & mask).to_bytes(16, byteorder='big')
|
||||
posb = posb.to_bytes(16, byteorder='big')
|
||||
#negb = ''.join("%02x"%x for x in negb)
|
||||
#posb = ''.join("%02x"%x for x in posb)
|
||||
return (negb, posb)
|
||||
|
||||
|
||||
def parsedvf(path: str, is78k: bool) -> DRec:
|
||||
typ = Dvf.MCU_RL78G13
|
||||
if is78k: typ = Dvf.MCU_78K0R if "78K0R" in path else Dvf.MCU_78K0
|
||||
|
||||
data = None
|
||||
with open(path, "rb") as f: data = f.read()
|
||||
magic = data[0x24:0x34]
|
||||
name = data[0x34:0x44]
|
||||
name = name.strip(b'\0').decode('utf-8')
|
||||
|
||||
#print(filename)
|
||||
dvf = Dvf.parse(data, typ)
|
||||
mi = dvf.sections[dvfparse.name2int('MI')]
|
||||
|
||||
brom_size = None
|
||||
for m in mi:
|
||||
if m.mreg_type == 0x28: # bootrom
|
||||
brom_size = m.addr_end - m.addr_start + 1
|
||||
break
|
||||
|
||||
#mag1 = ''.join("%02x"%x for x in magic[:10])
|
||||
#mag2 = ''.join("%02x"%x for x in magic[10:])
|
||||
#d2 = stuff.setdefault(mag1, {})
|
||||
#d3 = d2.setdefault(name[:6], {})
|
||||
#d3.setdefault(mag2, []).append((name, brom_size))
|
||||
|
||||
#magic = ''.join("%02x"%x for x in magic)
|
||||
return DRec(os.path.split(path)[-1], magic, name, brom_size)
|
||||
|
||||
|
||||
def parsexml(basepath: str, is78k: bool) -> Sequence[XRec]:
|
||||
xmlfile = basepath + "_Productlist.xml"
|
||||
|
||||
xmlroot = ET.parse(xmlfile).getroot()
|
||||
|
||||
curnick, curprod, curproddisp, curdvf, currom, curram, curpins = \
|
||||
None, None, None, None, None, None, None
|
||||
for node in xmlroot[1]:
|
||||
if node.tag == 'Nickname':
|
||||
if curnick is not None:
|
||||
ext = "78K" if is78k else "DVF"
|
||||
if is78k:
|
||||
if "78K0R" in curnick:
|
||||
root2 = basepath + "0R"
|
||||
elif "78K0" in curnick:
|
||||
root2 = basepath + "0"
|
||||
else: assert False, curnick
|
||||
else: root2 = basepath
|
||||
dvfdir = root2 + "/Devicefile/"
|
||||
|
||||
assert curprod
|
||||
filename = "%s_common.xml" % curprod
|
||||
filepath = "%s/%s" % (root2, filename)
|
||||
if curdvf is not None:
|
||||
pass#assert curdvf in {"DFR5F100", "DF780495", "DF780547", "DF780893", "DF780893", "DF780893__V110", "DF781009", "DF781009__V101"}, curdvf
|
||||
#if curdvf is None or curdvf == 'DFR5F100':
|
||||
#try:
|
||||
xml2 = ET.parse(filepath).getroot()
|
||||
dvfi = xml2.find("DEVICEFILEINFORMATION")
|
||||
folder = dvfi.find("DeviceFileInformationFolderName").text
|
||||
filen = dvfi.find("DeviceFileInformationFileName").text
|
||||
folder = folder or "Devicefile"
|
||||
|
||||
curdvf = "%s/%s/%s" % (root2, folder, filen)
|
||||
#print("curdvf:%s"% curdvf)
|
||||
#except Exception: curdvf = None
|
||||
if curdvf is None:
|
||||
#print("curprod: %s"%curprod)
|
||||
curdvf = "%s/D%s.%s" % (dvfdir, curprod, ext) # shrug
|
||||
#else:
|
||||
# if is78k:
|
||||
# if "78K0R" in curnick: pass
|
||||
# elif "78K0" in curnick: curdvf = curdvf.replace("DF78", "DF")
|
||||
# print("curdvf k:%s"% curdvf, locals())
|
||||
# curdvf = "%s/%s.%s" % (dvfdir, curdvf, ext)
|
||||
yield XRec(curnick, curprod, curproddisp,
|
||||
os.path.split(curdvf)[-1], currom, curram, curpins,
|
||||
parsedvf(curdvf, is78k))
|
||||
curnick, curprod, curproddisp, curdvf, currom, curram, curpins = \
|
||||
None, None, None, None, None, None, None
|
||||
curnick = node.text
|
||||
else: curnick = node.text
|
||||
if node.tag == 'ProductName': curprod = node.text
|
||||
if node.tag == 'ROMSize': currom = int(node.text or "0")
|
||||
if node.tag == 'RAMSize': curram = int(node.text or "0")
|
||||
if node.tag == 'DeviceFileProductName': curdvf = node.text
|
||||
if node.tag == 'ProductDisplayName': curproddisp = node.text
|
||||
if node.tag == 'PinCount': curpins = int(node.text or "0")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
root_rl = sys.argv[1]
|
||||
xmls_rl = list(parsexml(root_rl, False))
|
||||
xmls_rl.append(XRec("RL78/L1C", "R5F111PJ", "R5F111PJ", None, 256, 16*1024, 100,
|
||||
parsedvf(root_rl+"/Devicefile/DR5F111PJ.DVF", False)))
|
||||
xmld_rl = {}
|
||||
for x in xmls_rl:
|
||||
l = xmld_rl.setdefault(x.nickname, []).append(x)
|
||||
|
||||
root_k = sys.argv[2]
|
||||
xmls_k = list(parsexml(root_k, True))
|
||||
xmls_k.append(XRec('78K0R/UPD78F8069', "UPD78F806964", "UPD78F8069_64", None, 128+16, 8*1024, 64,
|
||||
parsedvf(root_k+"0R/Devicefile/DF806964.78K", True)))
|
||||
xmld_k = {}
|
||||
for x in xmls_k:
|
||||
l = xmld_k.setdefault(x.nickname, []).append(x)
|
||||
|
||||
#print(json.dumps(xmld_rl, sort_keys=True, indent=4))
|
||||
#print(json.dumps(xmld_k , sort_keys=True, indent=4))
|
||||
|
||||
# verify that all DVF files on disk are used!
|
||||
|
||||
def dictl(ps, useset: bool=False):
|
||||
if useset:
|
||||
d = {}
|
||||
for x, y in ps: d.setdefault(x, set()).add(y)
|
||||
return dict((x, list(y)) for x, y in d.items())
|
||||
else:
|
||||
d = {}
|
||||
for x, y in ps: d.setdefault(x, []).append(y)
|
||||
return d
|
||||
|
||||
"""
|
||||
unk_rl, unk_k0, unk_k0r = [], [], []
|
||||
for entry in os.scandir(root_rl+"/Devicefile"):
|
||||
if not any(any(entry.name == y.dvf.path for y in x) for x in xmld_rl.values()):
|
||||
unk_rl.append(entry.name)
|
||||
for entry in os.scandir(root_k+"0/Devicefile"):
|
||||
if not any(any(entry.name == y.dvf.path for y in x) for x in xmld_k.values()):
|
||||
unk_k0.append(entry.name)
|
||||
for entry in os.scandir(root_k+"0R/Devicefile"):
|
||||
if not any(any(entry.name == y.dvf.path for y in x) for x in xmld_k.values()):
|
||||
unk_k0r.append(entry.name)
|
||||
print(unk_rl)
|
||||
print(unk_k0)
|
||||
print(unk_k0r)
|
||||
"""
|
||||
|
||||
"""
|
||||
maskd = {}
|
||||
for k, l in xmld_k.items():
|
||||
mask = get_common_masks([x.dvf.magic for x in l])
|
||||
maskd.setdefault(str(mask[1][:10]), []).append(k)
|
||||
for k, l in xmld_rl.items():
|
||||
mask = get_common_masks([x.dvf.magic for x in l])
|
||||
maskd.setdefault(str(mask[1][:10]), []).append(k)
|
||||
print(json.dumps(maskd, sort_keys=True, indent=4))
|
||||
"""
|
||||
|
||||
"""
|
||||
print()
|
||||
|
||||
k78k0_bytes = sum([[l.dvf.magic for l in v] for k, v in xmld_k.items() if "78K0R" not in k], start=[])
|
||||
k78k0r_bytes = sum([[l.dvf.magic for l in v] for k, v in xmld_k.items() if "78K0R" in k], start=[])
|
||||
k78k_bytes = sum([[l.dvf.magic for l in v] for k, v in xmld_k.items()], start=[])
|
||||
rl78s1_bytes = sum([[l.dvf.magic for l in v] for k, v in xmld_rl.items() if all(x not in k for x in {"G23","F24","FGIC"})], start=[])
|
||||
rl78s2_bytes = sum([[l.dvf.magic for l in v] for k, v in xmld_rl.items() if any(x in k for x in {"G23","F24","FGIC"})], start=[])
|
||||
rl78_bytes = sum([[l.dvf.magic for l in v] for k, v in xmld_rl.items()], start=[])
|
||||
|
||||
print("78K0", get_common_masks(k78k0_bytes))
|
||||
print("78K0R", get_common_masks(k78k0r_bytes))
|
||||
print("78K", get_common_masks(k78k_bytes))
|
||||
print("RL78/x1y", get_common_masks(rl78s1_bytes))
|
||||
print("RL78/x2y", get_common_masks(rl78s2_bytes))
|
||||
print("RL78", get_common_masks(rl78_bytes))
|
||||
"""
|
||||
|
||||
k78k0_bytes = dictl(sum([[(repr(l.dvf.magic[:10]), l.nickname) for l in v] for k, v in xmld_k.items() if "78K0R" not in k], start=[]), True)
|
||||
k78k0r_bytes = dictl(sum([[(repr(l.dvf.magic[:10]), l.nickname) for l in v] for k, v in xmld_k.items() if "78K0R" in k], start=[]), True)
|
||||
k78k_bytes = dictl(sum([[(repr(l.dvf.magic[:10]), l.nickname) for l in v] for k, v in xmld_k.items()], start=[]), True)
|
||||
rl78s1_bytes = dictl(sum([[(repr(l.dvf.magic[:10]), l.nickname) for l in v] for k, v in xmld_rl.items() if all(x not in k for x in {"G23","F24","FGIC"})], start=[]), True)
|
||||
rl78s2_bytes = dictl(sum([[(repr(l.dvf.magic[:10]), l.nickname) for l in v] for k, v in xmld_rl.items() if any(x in k for x in {"G23","F24","FGIC"})], start=[]), True)
|
||||
rl78_bytes = dictl(sum([[(repr(l.dvf.magic[:10]), l.nickname) for l in v] for k, v in xmld_rl.items()], start=[]), True)
|
||||
|
||||
print("78K0", json.dumps(k78k0_bytes, sort_keys=True, indent=4))
|
||||
print("78K0R", json.dumps(k78k0r_bytes, sort_keys=True, indent=4))
|
||||
#print("78K", json.dumps(k78k_bytes, sort_keys=True, indent=4))
|
||||
print("RL78/x1y", json.dumps(rl78s1_bytes, sort_keys=True, indent=4))
|
||||
print("RL78/x2y", json.dumps(rl78s2_bytes, sort_keys=True, indent=4))
|
||||
#print("RL78", json.dumps(rl78_bytes, sort_keys=True, indent=4))
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
|
||||
from typing import *
|
||||
|
||||
|
||||
SvdEndian = Literal["little", "big", "selectable", "other"]
|
||||
SvdSauAccess = Literal["n", "c", "s"]
|
||||
SvdProtection = Literal["s", "n", "p"]
|
||||
SvdAddressUsage = Literal["registers", "buffer", "reserved"]
|
||||
SvdUsage = Literal["read", "write", "read-write"]
|
||||
SvdDataType = Literal[
|
||||
"uint8_t","uint16_t","uint32_t","uint64_t",
|
||||
"int8_t","int16_t","int32_t","int64_t",
|
||||
"uint8_t*","uint16_t*","uint32_t*","uint64_t*",
|
||||
"int8_t*","int16_t*","int32_t*","int64_t*"
|
||||
]
|
||||
SvdModifiedWriteValues = Literal[
|
||||
"oneToClear", "oneToSet", "oneToToggle",
|
||||
"zeroToSet", "zeroToClear", "zeroToToggle",
|
||||
"clear", "set", "modify"
|
||||
]
|
||||
SvdReadAction = Literal["clear", "set", "modify", "modifyExternal"]
|
||||
SvdAccess = Literal["read-only", "write-only", "read-write", "writeOnce", "read-writeOnce"]
|
||||
|
||||
|
||||
class SvdSauRegion(NamedTuple):
|
||||
enabled: bool
|
||||
name: str
|
||||
base: int
|
||||
limit: int
|
||||
access: SvdSauAccess
|
||||
|
||||
|
||||
class SvdSauRegionsConfig(NamedTuple):
|
||||
enabled: bool
|
||||
protectionWhenDisabled: SvdSauAccess
|
||||
regions: Sequence[SvdSauRegion]
|
||||
|
||||
|
||||
class SvdCpu(NamedTuple):
|
||||
name: str # explicitly not restricting to standard CMSIS names, because we'll be doing non-ARM stuff anyway
|
||||
revision: Tuple[int, int]
|
||||
endian: SvdEndian
|
||||
mpuPresent: bool
|
||||
fpuPresent: bool
|
||||
fpuDP: bool
|
||||
dspPresent: bool
|
||||
icachePresent: bool
|
||||
dcachePresent: bool
|
||||
itcmPresent: bool
|
||||
dtcmPresent: bool
|
||||
vtorPresent: bool
|
||||
nvicPrioBits: int
|
||||
vendorSystickConfig: bool
|
||||
deviceNumInterrupts: int
|
||||
sauNumRegions: int
|
||||
sauRegionsConfig: SvdSauRegionsConfig
|
||||
|
||||
|
||||
class SvdRegisterProperties(NamedTuple):
|
||||
size: int
|
||||
access: SvdAccess
|
||||
protection: SvdProtection
|
||||
resetValue: int
|
||||
resetMask: int
|
||||
|
||||
|
||||
class SvdEnumeratedValue(NamedTuple):
|
||||
name: str
|
||||
description: str
|
||||
value: int
|
||||
isDefault: bool
|
||||
|
||||
|
||||
class SvdEnumeratedValues(NamedTuple):
|
||||
derivedFrom: str
|
||||
name: str
|
||||
usage: SvdUsage
|
||||
enumeratedValue: Sequence[SvdEnumeratedValue]
|
||||
|
||||
|
||||
class SvdDimArrayIndex(NamedTuple):
|
||||
headerEnumName: str
|
||||
enumeratedValue: SvdEnumeratedValue
|
||||
|
||||
|
||||
class SvdDimElement(NamedTuple):
|
||||
dim: int
|
||||
dimIncrement: int
|
||||
dimIndex: int
|
||||
dimName: str
|
||||
dimArrayIndex: SvdDimArrayIndex
|
||||
|
||||
|
||||
class SvdAddressBlock(NamedTuple):
|
||||
offset: int
|
||||
size: int
|
||||
usage: SvdAddressUsage
|
||||
protection: SvdProtection
|
||||
|
||||
|
||||
class SvdInterrupt(NamedTuple):
|
||||
name: str
|
||||
description: str
|
||||
value: int
|
||||
|
||||
|
||||
class SvdCluster(NamedTuple):
|
||||
derivedFrom: str
|
||||
dimElement: SvdDimElement
|
||||
name: str
|
||||
description: str
|
||||
alternateCluster: str
|
||||
headerStructName: str
|
||||
addressOffset: int
|
||||
registerProperties: SvdRegisterProperties
|
||||
register: Sequence[Any]
|
||||
cluster: Sequence[Any]
|
||||
|
||||
|
||||
class SvdWriteConstraintRange(NamedTuple):
|
||||
min: int
|
||||
max: int
|
||||
|
||||
class SvdWriteConstraint(NamedTuple):
|
||||
writeAsRead: bool
|
||||
useEnumeratedValues: bool
|
||||
range: SvdWriteConstraintRange
|
||||
|
||||
|
||||
class SvdBitRangeLsbMsb(NamedTuple):
|
||||
lsb: int
|
||||
msb: int
|
||||
class SvdBitRangeOffsetWidth(NamedTuple):
|
||||
bitOffset: int
|
||||
bitWidth: int
|
||||
|
||||
|
||||
SvdBitRangePattern = str
|
||||
|
||||
|
||||
class SvdField(NamedTuple):
|
||||
derivedFrom: str
|
||||
dimElement: SvdDimElement
|
||||
name: str
|
||||
description: str
|
||||
bitRange: Union[SvdBitRangeLsbMsb, SvdBitRangeOffsetWidth, SvdBitRangePattern]
|
||||
access: SvdAccess
|
||||
modifiedWriteValues: SvdModifiedWriteValues
|
||||
writeConstraint: SvdWriteConstraint
|
||||
readAction: SvdReadAction
|
||||
enumeratedValues: SvdEnumeratedValues
|
||||
|
||||
|
||||
class SvdRegister(NamedTuple):
|
||||
derivedFrom: str
|
||||
dimElement: SvdDimElement
|
||||
name: str
|
||||
displayName: str
|
||||
description: str
|
||||
alternateGroup: str
|
||||
alternateRegister: str
|
||||
addressOffset: int
|
||||
registerProperties: SvdRegisterProperties
|
||||
dataType: SvdDataType
|
||||
modifiedWriteValues: SvdModifiedWriteValues
|
||||
writeConstraint: SvdWriteConstraint
|
||||
readAction: SvdReadAction
|
||||
fields: Sequence[SvdField]
|
||||
|
||||
|
||||
class SvdPeripheral(NamedTuple):
|
||||
derivedFrom: str
|
||||
name: str
|
||||
version: str
|
||||
description: str
|
||||
alternatePeripheral: str
|
||||
groupName: str
|
||||
prependToName: str
|
||||
appendToName: str
|
||||
headerStructName: str
|
||||
disableCondition: str
|
||||
baseAddress: int
|
||||
registerProperties: SvdRegisterProperties
|
||||
addressBlock: SvdAddressBlock
|
||||
interrupt: SvdInterrupt
|
||||
registers: Sequence[Union[SvdRegister, SvdCluster]]
|
||||
|
||||
|
||||
class SvdDevice(NamedTuple):
|
||||
vendor: str
|
||||
vendorID: str
|
||||
name: str
|
||||
series: str
|
||||
version: str
|
||||
description: str
|
||||
licenseText: str
|
||||
cpu: SvdCpu
|
||||
headerSystemFilename: str
|
||||
headerDefinitionsPrefix: str
|
||||
addressUnitBits: int
|
||||
width: int
|
||||
registerProperties: SvdRegisterProperties
|
||||
peripherals: Sequence[SvdPeripheral]
|
||||
vendorExtensions: Any
|
||||
|
||||
# TODO: functions for expanding registerproperties, dimelements and derivedfrom?
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
|
||||
import xml, xml.etree
|
||||
import xml.etree.ElementTree as ET
|
||||
import typing
|
||||
|
||||
from svd import *
|
||||
from typing import get_type_hints
|
||||
|
||||
|
||||
def parse_one(ch, t):
|
||||
k, v = None, None
|
||||
if isinstance(ch, ET.Element):
|
||||
k, v = ch.tag, ch
|
||||
else:
|
||||
k, v = ch
|
||||
|
||||
field = get_type_hints(t)[k]
|
||||
#print("%s -> %s [%s]" %(k, v, repr(field)))
|
||||
|
||||
known_types = {
|
||||
SvdDevice: parse_device,
|
||||
SvdCpu: parse_cpu,
|
||||
SvdPeripheral: parse_peripheral,
|
||||
SvdRegister: parse_register,
|
||||
SvdField: parse_field,
|
||||
SvdEnumeratedValues: parse_enumeratedValues,
|
||||
SvdCluster: parse_cluster,
|
||||
SvdSauRegionsConfig: parse_sauRegionsConfig,
|
||||
SvdWriteConstraint: parse_writeConstraint,
|
||||
SvdEnumeratedValue: parse_enumeratedValue,
|
||||
SvdWriteConstraintRange: parse_writeConstraintRange,
|
||||
SvdInterrupt: parse_interrupt,
|
||||
SvdAddressBlock: parse_addressBlock,
|
||||
SvdSauRegion: parse_sauRegion,
|
||||
}
|
||||
|
||||
vv = known_types.get(field)
|
||||
if vv:
|
||||
return vv(v)
|
||||
elif isinstance(ch, ET.Element):
|
||||
v = ch.text
|
||||
|
||||
if field == int:
|
||||
return int(v, 0)
|
||||
elif field == bool:
|
||||
assert v in {'true','false','1','0'}, ("invalid boolean value %s"%v)
|
||||
return v in {'true','1'}
|
||||
elif field == str or field.__origin__ == typing.Literal:
|
||||
return v
|
||||
elif field.__origin__ == tuple:
|
||||
if k == 'revision':
|
||||
return tuple(int(x) for x in v[1:].split('p'))
|
||||
else:
|
||||
assert False, ("unknown Tuple type %s for field %s" % (field, k))
|
||||
elif field.__origin__ == typing.Union:
|
||||
return v # good enough for now
|
||||
else:
|
||||
assert False, ("unknown type %s for field %s" % (field, k))
|
||||
|
||||
|
||||
REG_PROP_NAMES = {'size', 'access', 'protection', 'resetValue', 'resetMask'}
|
||||
DIM_ELEM_NAMES = {'dim','dimIncrement','dimIndex','dimName','dimArrayIndex'}
|
||||
|
||||
def try_parse_registerProperties(xd, part, dimElem) -> SvdRegisterProperties:
|
||||
d = dict((n, None) for n in SvdRegisterProperties._fields)
|
||||
for ch in xd:
|
||||
if ch.tag in d:
|
||||
d[ch.tag] = parse_one(ch, SvdRegisterProperties)
|
||||
else:
|
||||
assert ch.tag in part._fields or (dimElem and ch.tag in DIM_ELEM_NAMES), \
|
||||
("unknown child %s" % repr(ch))
|
||||
|
||||
return SvdRegisterProperties(**d)
|
||||
|
||||
def try_parse_dimElement(xd, part, regProp) -> SvdDimElement:
|
||||
d = dict((n, None) for n in SvdDimElement._fields)
|
||||
for ch in xd:
|
||||
if ch.tag == 'dimArrayIndex':
|
||||
d[ch.tag] = parse_dimArrayIndex(ch)
|
||||
elif ch.tag in d:
|
||||
d[ch.tag] = parse_one(ch, SvdDimElement)
|
||||
else:
|
||||
assert ch.tag in part._fields or (regProp and ch.tag in REG_PROP_NAMES), \
|
||||
("unknown child %s" % repr(ch))
|
||||
|
||||
return SvdDimElement(**d)
|
||||
|
||||
|
||||
def parse_generic(xd, T: type, tag: str,
|
||||
hasRegProps: bool = False, hasAttrib: bool = False,
|
||||
hasDimElem: bool = False, specials: Dict[str, Any] = None,
|
||||
lists: Dict[str, Any] = None):
|
||||
assert xd.tag == tag, ("expected %s, got %s" % (tag, xd.tag))
|
||||
d = dict((n, None) for n in T._fields)
|
||||
|
||||
if hasRegProps:
|
||||
d['registerProperties'] = try_parse_registerProperties(xd, T, hasDimElem)
|
||||
if hasDimElem:
|
||||
d['dimElement'] = try_parse_dimElement(xd, T, hasRegProps)
|
||||
if hasAttrib == True:
|
||||
for k, v in xd.attrib.items():
|
||||
if k in d:
|
||||
d[k] = v
|
||||
else:
|
||||
assert False, ("unknown attrib %s" % repr((k, v)))
|
||||
elif hasAttrib == False:
|
||||
assert len(xd.attrib) == 0
|
||||
|
||||
for ch in xd:
|
||||
if lists and ch.tag in lists:
|
||||
if d[ch.tag] == None: d[ch.tag] = []
|
||||
d[ch.tag].append(lists[ch.tag](ch))
|
||||
elif specials and ch.tag in specials:
|
||||
d[ch.tag] = specials[ch.tag](ch)
|
||||
elif ch.tag in d:
|
||||
d[ch.tag] = parse_one(ch, T)
|
||||
else:
|
||||
assert (hasRegProps and ch.tag in REG_PROP_NAMES) \
|
||||
or (hasDimElem and ch.tag in DIM_ELEM_NAMES), \
|
||||
("unknown child %s" % repr(ch))
|
||||
|
||||
return T(**d)
|
||||
|
||||
|
||||
def parse_sauRegion(xd): return parse_generic(xd, SvdSauRegion, 'region')
|
||||
def parse_addressBlock(xd): return parse_generic(xd, SvdAddressBlock, 'addressBlock')
|
||||
def parse_interrupt(xd): return parse_generic(xd, SvdInterrupt, 'interrupt')
|
||||
def parse_writeConstraintRange(xd): return parse_generic(xd, SvdWriteConstraintRange, 'range')
|
||||
def parse_enumeratedValue(xd): return parse_generic(xd, SvdEnumeratedValue, 'enumeratedValue')
|
||||
def parse_writeConstraint(xd):
|
||||
return parse_writeConstraint(xd, SvdWriteConstraint, 'writeConstraint')
|
||||
def parse_dimArrayIndex(xd): return parse_generic(xd, SvdDimArrayIndex, 'dimArrayIndex')
|
||||
|
||||
|
||||
def parse_sauRegionsConfig(xd):
|
||||
return parse_generic(xd, SvdSauRegionsConfig, 'sauRegionsConfig', lists={
|
||||
'regions': parse_sauRegion,
|
||||
})
|
||||
|
||||
|
||||
def parse_cluster(xd) -> SvdCluster:
|
||||
return parse_generic(xd, SvdCluster, 'cluster', True, True, True, lists={
|
||||
'register': parse_register,
|
||||
'cluster': parse_cluster,
|
||||
})
|
||||
|
||||
|
||||
def parse_enumeratedValues(xd) -> SvdEnumeratedValues:
|
||||
return parse_generic(xd, SvdEnumeratedValues, 'enumeratedValues', hasAttrib=True, lists={
|
||||
'enumeratedValue': parse_enumeratedValue,
|
||||
})
|
||||
|
||||
|
||||
def parse_cpu(xd): return parse_generic(xd, SvdCpu, 'cpu')
|
||||
def parse_field(xd): return parse_generic(xd, SvdField, 'field', False, True, True)
|
||||
|
||||
|
||||
def parse_register(xd) -> SvdRegister:
|
||||
return parse_generic(xd, SvdRegister, 'register', True, True, True, {
|
||||
'writeConstraint': parse_writeConstraint,
|
||||
'fields': (lambda ch: [parse_field(xch) for xch in ch])
|
||||
})
|
||||
|
||||
|
||||
def parse_registers(xd) -> Sequence[Union[SvdCluster, SvdRegister]]:
|
||||
rr = []
|
||||
for ch in xd:
|
||||
if ch.tag == 'cluster':
|
||||
rr.append(parse_cluster(ch))
|
||||
elif ch.tag == 'register':
|
||||
rr.append(parse_register(ch))
|
||||
else:
|
||||
assert False, ("expected cluster or register, got %s"%ch)
|
||||
|
||||
|
||||
def parse_peripheral(xd) -> SvdPeripheral:
|
||||
return parse_generic(xd, SvdPeripheral, 'peripheral', True, True, False, {
|
||||
'registers': parse_registers, # FIXME
|
||||
})
|
||||
|
||||
|
||||
def parse_device(xd) -> SvdDevice:
|
||||
return parse_generic(xd, SvdDevice, 'device', True, 2, False, {
|
||||
'cpu': parse_cpu,
|
||||
'peripherals': (lambda ch: [parse_peripheral(xch) for xch in ch]),
|
||||
'vendorExtensions': (lambda ch: ch)
|
||||
})
|
||||
|
||||
|
||||
def parse(path) -> SvdDevice:
|
||||
xmlroot = ET.parse(path).getroot()
|
||||
|
||||
return parse_device(xmlroot)
|
||||
|
Loading…
Reference in New Issue