Files
Server-scripts/work/compareStartUpScripts.py
2026-09-14 12:43:38 +02:00

280 lines
7.8 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import re
import pprint
import re
from collections import defaultdict
# =====================================================================
# Unified DynamicObject (replaces DynamicMObject + DynamicCppObject)
# =====================================================================
class DynamicObject(dict):
"""
A unified dynamic object that:
- Behaves like a dict
- Supports attribute access
- Auto-creates nested fields on demand
"""
def __getattr__(self, name):
if name not in self:
self[name] = DynamicObject()
return self[name]
def __setattr__(self, name, value):
self[name] = value
def ensure_path(self, path_parts):
obj = self
for part in path_parts:
if part not in obj:
obj[part] = DynamicObject()
obj = obj[part]
return obj
def __repr__(self):
return dict.__repr__(self)
# =====================================================================
# MATLAB FRD REG PARSER
# =====================================================================
def parse_oFRDReg_from_mfile(filename):
oFRDReg = DynamicObject()
# Regex to capture: oFRDReg.<path> = <value>;
pattern = re.compile(r"oFRDReg\.([A-Za-z0-9_.]+)\s*=\s*([^;]+);")
with open(filename, "r") as f:
for line in f:
match = pattern.search(line)
if match:
full_path = match.group(1)
value_raw = match.group(2).strip()
# Convert numeric/string values when possible
try:
value = eval(value_raw)
except:
value = value_raw
# Split path: e.g. MSI.vcm_sel → ["MSI", "vcm_sel"]
parts = full_path.split(".")
parts = [ p.upper() for p in parts ]
attr_name = parts[-1]
parent_path = parts[:-1]
# Create nested path
parent = oFRDReg.ensure_path(parent_path)
setattr(parent, attr_name, value)
return oFRDReg
# =====================================================================
# Macro expansion helper
# =====================================================================
def expand_macro_pattern(pattern, **kwargs):
"""
Expand a macro pattern containing tokens like:
CH1##_##address##_OFFSET
into the final register string.
kwargs maps token names → values, e.g. address="CFG".
"""
s = pattern
# Replace tokens inside patterns like address##_XYZ
for key, value in kwargs.items():
s = s.replace(key, value)
# Resolve concatenation '##'
s = s.replace("##", "")
# Clean up double underscores
while "__" in s:
s = s.replace("__", "_")
return s
# =====================================================================
# C MACRO PARSER
# =====================================================================
def remove_cpp_comments(text):
"""
Remove /* block comments */ and // line comments.
"""
# Remove multiline comments
text = re.sub(r"/\*.*?\*/", "", text, flags=re.DOTALL)
# Removedefines
text = re.sub(r"#define.*", "", text)
# Remove single-line comments
text = re.sub(r"//.*", "", text)
return text
def parse_c_macros(filename):
registers = DynamicObject()
# Macro → register expansion patterns
macro_definitions = {
# 3-argument write (slow/fast)
"SLOW_WRITE_FIELD": (
"CH1_##address##",
"CH1_##address##_##field##",
),
"FAST_WRITE_FIELD": (
"CH0_##address##",
"CH0_##address##_##field##",
),
# Read field, 2 arguments
"SLOW_READ_FIELD": (
"CH1_##address##",
"CH1_##address##_##field##",
),
"FAST_READ_FIELD": (
"CH0_##address##",
"CH0_##address##_##field##",
),
# Register read/write (1 or 2 arguments)
"SLOW_READ_REGISTER": (
"CH1_##address##",
),
"FAST_READ_REGISTER": (
"CH0_##address##",
),
"SLOW_WRITE_REGISTER": (
"CH1_##address##",
),
"FAST_WRITE_REGISTER": (
"CH0_##address##",
),
"FAST_WRITE_INHIBIT": (
"CH0##_##address1##_CH0_##address2##",
),
"SLOW_WRITE_INHIBIT": (
"CH1##_##address1##_CH0_##address2##",
)
}
# Generic regex for ALL macro calls (1–4 args)
call_regex = re.compile(
r"([A-Z_]+)\s*\(\s*([A-Za-z0-9_]+)" # FUN and arg1: address1
r"(?:\s*,\s*([A-Za-z0-9_]+))?" # arg2: field, address2
r"(?:\s*,\s*([A-Za-z0-9_+\-*/() ]+))?" # arg3: field, data
r"(?:\s*,\s*([A-Za-z0-9_+\-*/() ]+))?" # arg4: data (expression allowed)
r"\s*\)"
)
with open(filename, "r") as f:
text = f.read()
text = remove_cpp_comments(text)
for match in call_regex.finditer(text):
macro, a1, a2, a3, a4 = match.groups()
text = text.replace(match.group(0), "") # remove after processing
if macro not in macro_definitions or "READ" in macro:
continue
patterns = macro_definitions[macro]
# Build the macro variable map
kwargs = {}
if a4 == None:
if a1: kwargs["address"] = a1
if a2: kwargs["field"] = a2
if a3: kwargs["data"] = a3
else:
if a1: kwargs["address1"] = a1
if a2: kwargs["address2"] = a2
if a3: kwargs["field"] = a3
if a4: kwargs["data"] = a4
# Expand patterns into real register names
expanded = [expand_macro_pattern(p, **kwargs) for p in patterns]
# Store results
if a2 and a3: # WRITE_FIELD
registers[expanded[0].upper()] = {a2.upper(): a3}
else: # REGISTER read/write
registers[expanded[0].upper()] = a3
return registers
def upper_keys_recursive(d):
new_dict = {}
for k, v in d.items():
key_up = str(k).upper()
if isinstance(v, dict):
new_dict[key_up] = upper_keys_recursive(v)
else:
new_dict[key_up] = v
return new_dict
def diff_dicts(d1, d2, path="",dictnames = ["M","CPP"]):
"""
Recursively compare two dictionaries and print differences.
Shows:
- Keys only in d1
- Keys only in d2
- Keys in both where values differ
"""
# Keys present in both dictionaries
common_keys = d1.keys() & d2.keys()
# Keys only in first dict
only_d1 = d1.keys() - d2.keys()
for key in sorted(only_d1):
print(f"{path}{key}: only in {dictnames[0]}")
# Keys only in second dict
only_d2 = d2.keys() - d1.keys()
for key in sorted(only_d2):
print(f"{path}{key}: only in {dictnames[1]}")
# Compare common keys
for key in sorted(common_keys):
v1 = d1[key]
v2 = d2[key]
new_path = f"{path}{key}."
# If both values are dictionaries → recurse
if isinstance(v1, dict) and isinstance(v2, dict):
diff_dicts(v1, v2, new_path)
continue
# If values differ → print
if v1 != v2:
print(f"{path}{key}:")
print(f" {dictnames[0]} = {v1}")
print(f" {dictnames[1]} = {v2}")
# =====================================================================
# Example usage
# =====================================================================
# Example usage:
if __name__ == "__main__":
obj = parse_oFRDReg_from_mfile("startTau_generic_Generated.m")
pprint.pprint(obj)
regs = parse_c_macros("/home/lucas/git/mems_stable/trixel3_software/tic/source/trixel3_tic_mems_model_lbd001rrxab11.cpp")
pprint.pprint(regs)
diff_dicts(regs,obj)
print("Fin")