| from __future__ import annotations |
|
|
| import re |
| from typing import Any, Dict, List, Optional |
|
|
|
|
| PROTOCOL_SIGNATURES = { |
| "uart": {"tx", "rx", "baud"}, |
| "spi": {"mosi", "miso", "sclk", "ss_n", "cs"}, |
| "i2c": {"scl", "sda"}, |
| "axi4lite": {"awvalid", "awready", "arvalid", "arready", |
| "wvalid", "wready", "rvalid", "rready", |
| "bvalid", "bready"}, |
| "apb": {"psel", "penable", "paddr", "pwrite", "pready"}, |
| "wishbone": {"wb_cyc", "wb_stb", "wb_we", "wb_ack", "wb_addr"}, |
| } |
|
|
|
|
| class SpecPreprocessor: |
| def preprocess(self, raw: Dict[str, Any]) -> Dict[str, Any]: |
| raw = self._normalise_names(raw) |
| raw = self._default_clock_reset(raw) |
| raw = self._expand_signals(raw) |
| raw = self._validate_address_formats(raw) |
| raw = self._detect_protocol(raw) |
| return raw |
|
|
| @staticmethod |
| def _normalise_names(raw: Dict[str, Any]) -> Dict[str, Any]: |
| if "design_name" in raw: |
| raw["design_name"] = re.sub(r"[^a-zA-Z0-9_]", "_", raw["design_name"]).lower() |
| return raw |
|
|
| @staticmethod |
| def _default_clock_reset(raw: Dict[str, Any]) -> Dict[str, Any]: |
| raw.setdefault("clock_reset", {"clock": "clk", "reset": "rst_n", "reset_active": 0}) |
| return raw |
|
|
| @staticmethod |
| def _expand_signals(raw: Dict[str, Any]) -> Dict[str, Any]: |
| for iface in raw.get("interfaces", []): |
| for sig in iface.get("signals", []): |
| sig.setdefault("width", 1) |
| return raw |
|
|
| @staticmethod |
| def _validate_address_formats(raw: Dict[str, Any]) -> Dict[str, Any]: |
| for reg in raw.get("registers", []): |
| addr = reg.get("address", "0x00") |
| if not isinstance(addr, str) or not addr.startswith("0x"): |
| reg["address"] = f"0x{int(addr):02X}" if isinstance(addr, int) else f"0x{addr}" |
| for field in reg.get("fields", []): |
| bits = field.get("bits") |
| if bits is not None and not isinstance(bits, str): |
| field["bits"] = str(bits) |
| return raw |
|
|
| @staticmethod |
| def _detect_protocol(raw: Dict[str, Any]) -> Dict[str, Any]: |
| signal_names = set() |
| for iface in raw.get("interfaces", []): |
| for sig in iface.get("signals", []): |
| signal_names.add(sig.get("name", "").lower()) |
|
|
| if raw.get("protocol"): |
| return raw |
|
|
| detected = None |
| rank = 0 |
| for proto, sigs in PROTOCOL_SIGNATURES.items(): |
| matches = sum(1 for kw in sigs if any(kw in s for s in signal_names)) |
| if matches > rank: |
| rank = matches |
| detected = proto |
|
|
| if detected and rank >= 2: |
| raw["protocol"] = detected |
| elif not raw.get("protocol"): |
| raw["protocol"] = "wishbone" |
|
|
| return raw |
|
|