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(' 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(' DvfOD: ind, subind, val = struct.unpack(' 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\x001\x02!\x02\0\0H\x11', # Kx2 b'\0\x001\x02\0\x01\0\0H\x11', # Kx2-A, uPD78F8039 b'\0\x001\x02\x01\x01\0\0H\x11', # Fx2 b'\0\x001\x02\x01\x02\0\0H\x11', # Kx2-L b'\0\x001\x02\x10\x01\0\0H\x11', # misc (Ix2, KC2-A, uPD78F0730) b'\0\x001\x02\x11\x01\0\0H\x11', # FC2 b'\0\x001\x02\x12\x01\0\0H\x11', # Lx3 b'\0\x002\x02\0\x01\0\0H\x11', # misc (uPD78F8077, Dx2, Kx2-C, uPD78F8039) b'\0\x002\x02\x02\x01\0\0H\x11', # Fx2-L b'\0\x002\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( '>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)