File size: 3,973 Bytes
4344b33 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | # src/data/core_parser.py — FuseSoC .core file parser
from __future__ import annotations
from typing import Any, Dict, List, Optional
import yaml
from src.data.preprocessor import SpecPreprocessor
class CoreParser:
"""Parses FuseSoC .core files into the internal DesignSpec-compatible dict.
The .core format (YAML) describes IP cores with:
- name / version / description
- parameters
- interfaces (each with signals, type, bus standard)
- registers (address, access, fields with bit positions)
- clock_reset
- filesets, targets
"""
ACCESS_MAP = {
"ro": "read-only",
"wo": "write-only",
"rw": "read-write",
"rc": "read-clear",
"rs": "read-set",
"w1c": "write-1-to-clear",
}
def parse(self, content: str) -> Dict[str, Any]:
raw = yaml.safe_load(content)
spec: Dict[str, Any] = {}
spec["design_name"] = self._extract_name(raw)
spec["clock_reset"] = self._extract_clock_reset(raw)
spec["interfaces"] = self._extract_interfaces(raw)
spec["registers"] = self._extract_registers(raw)
spec["parameters"] = self._extract_parameters(raw)
return SpecPreprocessor().preprocess(spec)
@staticmethod
def _extract_name(raw: Dict[str, Any]) -> str:
name = raw.get("name", "unknown")
if isinstance(name, str):
return name.strip().lower()
return "unknown"
@staticmethod
def _extract_clock_reset(raw: Dict[str, Any]) -> Dict[str, Any]:
cr = raw.get("clock_reset")
if cr:
return {
"clock": cr.get("clock", "clk"),
"reset": cr.get("reset", "rst_n"),
"reset_active": cr.get("reset_active", 0),
}
return {"clock": "clk", "reset": "rst_n", "reset_active": 0}
@staticmethod
def _extract_interfaces(raw: Dict[str, Any]) -> List[Dict[str, Any]]:
interfaces = raw.get("interfaces", [])
result: List[Dict[str, Any]] = []
for iface in interfaces:
entry: Dict[str, Any] = {
"name": iface.get("name", "bus"),
"signals": [],
}
for sig in iface.get("signals", []):
entry["signals"].append({
"name": sig.get("name", "sig"),
"direction": sig.get("direction", "input"),
"width": sig.get("width", 1),
})
result.append(entry)
return result
@staticmethod
def _extract_registers(raw: Dict[str, Any]) -> List[Dict[str, Any]]:
registers = raw.get("registers", [])
result: List[Dict[str, Any]] = []
seen = set()
for reg in registers:
name = reg.get("name", f"reg_{len(result)}")
if name in seen:
name = f"{name}_{len(result)}"
seen.add(name)
entry: Dict[str, Any] = {
"name": name,
"address": reg.get("address", "0x00"),
"description": reg.get("description", ""),
"access": reg.get("access", "rw"),
"fields": [],
}
for fld in reg.get("fields", []):
entry["fields"].append({
"name": fld.get("name", "field"),
"bits": fld.get("bits", "0"),
"description": fld.get("description", ""),
})
result.append(entry)
return result
@staticmethod
def _extract_parameters(raw: Dict[str, Any]) -> Dict[str, Any]:
params = raw.get("parameters", {})
return {k: v.get("default") if isinstance(v, dict) else v for k, v in params.items()}
def parse_core_file(path: str) -> Dict[str, Any]:
"""Convenience: read .core file and return DesignSpec-compatible dict."""
with open(path, "r") as f:
return CoreParser().parse(f.read())
|