Skip to content

Commit

Permalink
[dfg] Add clock file parser
Browse files Browse the repository at this point in the history
  • Loading branch information
salkinium committed Mar 3, 2019
1 parent 7e4d967 commit 5381b4b
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 11 deletions.
6 changes: 0 additions & 6 deletions tools/generator/dfg/input/xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,6 @@ def _openDeviceXML(self, filename):
return xmltree

def queryTree(self, query):
"""
This tries to apply the query to the device tree and returns either
- an array of element nodes,
- an array of strings or
- None, if the query failed.
"""
response = None
try:
response = self.tree.xpath(query)
Expand Down
127 changes: 127 additions & 0 deletions tools/generator/dfg/stm32/stm_clock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Niklas Hauser
# All rights reserved.

from os.path import commonprefix, basename
import re
import sys
import logging
import subprocess
import tempfile
import textwrap

from collections import defaultdict
from jinja2 import Environment
from pathlib import Path
from ..input.xml import XMLReader

from . import stm

LOGGER = logging.getLogger('dfg.stm32.clock')



class STMClock:
ROOT_PATH = Path(__file__).parents[2]
CLOCK_FILE_PATH = ROOT_PATH / "raw-device-data/stm32-devices/plugins/clock"
CACHE_CLOCK_TREE = {}

@staticmethod
def get(did, rcc_ip_file):
if rcc_ip_file.filename not in STMClock.CACHE_CLOCK_TREE:
STMClock.CACHE_CLOCK_TREE[rcc_ip_file.filename] = STMClock(did, rcc_ip_file)
return STMClock.CACHE_CLOCK_TREE[rcc_ip_file.filename]

def __init__(self, did, rcc_ip_file):
self.ip_file = rcc_ip_file
self.did = did

match = basename(self.ip_file.filename)
match = re.search(r"RCC-STM32(((..).?.?)E?)[_-]rcc", match)
ip_name = match.group(1)
rcc_name = match.group(2)
family = match.group(3)
# print(family, rcc_name, ip_name)
files = [c for c in STMClock.CLOCK_FILE_PATH.glob("*.xml") if str(c).endswith("{}.xml".format(rcc_name))]
if not files:
files = [c for c in STMClock.CLOCK_FILE_PATH.glob("*.xml") if rcc_name in str(c)]
if not files:
files = [c for c in STMClock.CLOCK_FILE_PATH.glob("*.xml") if str(c).endswith("{}.xml".format(family))]
if len(files) != 1:
LOGGER.error("Unknown clock file for device '{}' and IP file '{}': {}".format(did.string, self.ip_file, files))
return

self.clock_file = XMLReader(files[0])
# print(family, files[0])

self.params = {ref.get("Name"):ref for ref in self.ip_file.query("//RefParameter")}
self.nodes = {node.get("id"):node for node in self.clock_file.query("//Element")}
self.signals = {signal.get("id"):signal for signal in self.clock_file.query("//Signal")}
self.ips = {}
self.edges = {}
# ips = {ip.strip():ipn for ipn in self.ip_file.query("//@IP/..") for ip in ipn.get("IP").split(",")}
# signals = self.clock_file.query("//@signalId")

for edge in self.clock_file.query("//Input"):
name = "{}<-{}".format(edge.get("signalId"), edge.get("from"))
self.edges[name] = edge
for edge in self.clock_file.query("//Output"):
name = "{}->{}".format(edge.get("signalId"), edge.get("to"))
self.edges[name] = edge

def get_refs(node):
ref = self.params.get(node.get("refParameter", ""))
if ref is None: return {};
attrib = ref.attrib
if ref.get("Type", "") == "list":
values = [value.get("Value") for value in ref if value.get("Value") is not None]
if values:
prefix = commonprefix(values)
attrib["Values"] = "{}{{{}}}".format(prefix, ",".join(value.replace(prefix, "") for value in values))
attrib.pop("Visible", None)
attrib.pop("Display", None)
attrib.pop("Comment", None)
attrib.pop("Unit", None)
attrib.pop("Type", None)
nmin, ndef, nmax = attrib.pop("Min", ""), attrib.pop("DefaultValue", ""), attrib.pop("Max", "")
if nmin and nmax and nmin == nmax:
value = ndef
else:
value = ""
if nmin: value += "{} <= ".format(nmin);
if ndef: value += "({})".format(ndef);
if nmax: value += " <= {}".format(nmax);
attrib["Value"] = value

return attrib


import graphviz as gv
graph = gv.Digraph(format="svg",
node_attr={"style": "filled,solid", "shape": "box"})

for name, node in self.nodes.items():
refs = get_refs(node)
label = ["{} {}".format(name, node.get("type", ""))] + ["{}: {}".format(k, v) for k,v in refs.items() if k not in ["IP"]]
label = [textwrap.fill(l, width=50) for l in label]
graph.node(name, label="\n".join(label))
if name == "I2SClockSource":
print(self.edges.keys())
if "IP" in refs and not any(edge.startswith("{}->".format(name)) or edge.endswith("<-{}".format(name)) for edge in self.edges.keys()):
for ip in [ip.strip() for ip in refs["IP"].split(",") if ip.strip()]:
self.edges["{}->{}".format(name, ip)] = node
graph.node(ip, shape="egg")
self.ips[ip] = node

for name in set(self.signals) - set(self.nodes):
graph.node(name, shape="pentagon")

for name, edge in self.edges.items():
if "->" in name:
efrom, eto = name.split("->")
elif "<-" in name:
eto, efrom = name.split("<-")
graph.edge(efrom, eto, label=edge.get("refValue", ""))

outfile = Path("clock/{}.svg".format(ip_name))
outfile.write_text(graph.pipe().decode("utf-8"))
21 changes: 16 additions & 5 deletions tools/generator/dfg/stm32/stm_device_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
import os
import re
import logging
import networkx as nx

from ..device_tree import DeviceTree
from ..input.xml import XMLReader

from .stm_header import STMHeader
from .stm_identifier import STMIdentifier
from .stm_clock import STMClock
from . import stm
from . import stm_peripherals

Expand All @@ -25,6 +27,12 @@ class STMDeviceTree:
rootpath = os.path.join(os.path.dirname(__file__), "..", "..", "raw-device-data", "stm32-devices", "mcu")
familyFile = XMLReader(os.path.join(rootpath, "families.xml"))

@staticmethod
def getIpFile(device_file, peripheral):
ip_file = device_file.query('//IP[@Name="{}"]'.format(peripheral))[0].get("Version")
ip_file = os.path.join(STMDeviceTree.rootpath, "IP", "{}-{}_Modes.xml".format(peripheral, ip_file))
return XMLReader(ip_file)

@staticmethod
def getDevicesFromFamily(family):
rawDevices = STMDeviceTree.familyFile.query('//Family[@Name="{}"]/SubFamily/Mcu/@RefName'.format(family))
Expand Down Expand Up @@ -63,6 +71,10 @@ def _properties_from_partname(partname):

LOGGER.info("Parsing '{}'".format(did.string))

rccFile = STMDeviceTree.getIpFile(device_file, "RCC")
clock = STMClock.get(did, rccFile)
return None

# information about the core and architecture
core = device_file.query('//Core')[0].text.lower().replace("arm ", "")
if core.endswith("m4") or core.endswith("m7"):
Expand Down Expand Up @@ -157,8 +169,8 @@ def clean_up_version(version):
match = re.search("v[1-9]_[0-9x]", version.replace(".", "_"))
if match:
version = match.group(0).replace("_", ".")
else:
print(version)
# else:
# print(version)
return version

modules = []
Expand Down Expand Up @@ -195,9 +207,8 @@ def clean_up_version(version):
p["interrupts"] = stm_header.get_interrupt_table()

# lets load additional information about the GPIO IP
ip_file = device_file.query('//IP[@Name="GPIO"]')[0].get("Version")
ip_file = os.path.join(STMDeviceTree.rootpath, "IP", "GPIO-" + ip_file + "_Modes.xml")
gpioFile = XMLReader(ip_file)
gpioFile = STMDeviceTree.getIpFile(device_file, "GPIO")


pins = device_file.query('//Pin[@Type="I/O"][starts-with(@Name,"P")]')
def raw_pin_sort(p):
Expand Down

0 comments on commit 5381b4b

Please sign in to comment.