Skip to content

Commit

Permalink
improve topology-to-graphviz output
Browse files Browse the repository at this point in the history
  • Loading branch information
algrant-arm committed Jan 13, 2023
1 parent 5601461 commit 2dba577
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 23 deletions.
31 changes: 19 additions & 12 deletions coresight-tools/cs_topology.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@

# CoreSight Device Type indicates the generic function of the device.
# It does not indicate the specific programming model of the device.
# Defined in CoreSight Architecture, under DEVTYPE.
# This is only a rough guide. For example, a TMC configured as a router
# is (1,2), "buffer", not either of the codes listed as "router".
CS_DEVTYPE_MISC = (0,0)
CS_DEVTYPE_PORT = (1,1)
CS_DEVTYPE_BUFFER = (1,2)
CS_DEVTYPE_ROUTER = (1,3)
CS_DEVTYPE_FUNNEL = (2,1)
CS_DEVTYPE_REPLICATOR = (2,2)
CS_DEVTYPE_FIFO = (2,3)
CS_DEVTYPE_ROUTER = (1,3) # "Basic trace router"
CS_DEVTYPE_FUNNEL = (2,1) # "Trace Funnel, Router"
CS_DEVTYPE_REPLICATOR = (2,2) # "Filter" - includes replicators whether filtering or not
CS_DEVTYPE_FIFO = (2,3) # "FIFO, Large Buffer"
CS_DEVTYPE_TRACE_CORE = (3,1)
CS_DEVTYPE_TRACE_BUS = (3,4)
CS_DEVTYPE_TRACE_SW = (3,6)
Expand Down Expand Up @@ -116,6 +119,8 @@ def __init__(self, platform, device_type, is_hidden=False, name=None, type_name=
assert (not is_hidden) or (device_type in [CS_DEVTYPE_FUNNEL, CS_DEVTYPE_REPLICATOR])
if name is not None:
self.set_name(name)
else:
self.name = None
self.type_name = type_name
self.part_vendor = None
self.part_number = None # e.g. 0x906
Expand Down Expand Up @@ -144,14 +149,18 @@ def __init__(self, platform, device_type, is_hidden=False, name=None, type_name=
platform.check()
self.sysfs_path = None # Device path in Linux sysfs or equivalent

def type_str(self):
if self.type in devtype_str:
return devtype_str[self.type]
else:
return str(self.type)

def __str__(self):
s = ""
if self.name is not None:
s = self.name
elif self.type in devtype_str:
s += "<%s>" % devtype_str[self.type]
else:
s += "<%s>" % str(self.type)
s += "<%s>" % self.type_str()
if self.is_memory_mapped():
s += "@" + self.address_str()
return s
Expand Down Expand Up @@ -541,11 +550,7 @@ def show(self):
name = None
print("%20s " % d.address_str(), end="")
print(" %20s" % name, end="")
if d.type in devtype_str:
tstr = devtype_str[d.type]
else:
tstr = str(d.type)
print(" %12s" % (tstr), end="")
print(" %12s" % (d.type_str()), end="")
if d.is_affine_to_cpu():
if d.affine_cpu is not None:
print("%5s" % str(d.affine_cpu), end="")
Expand Down Expand Up @@ -597,6 +602,8 @@ def jaddr(s):
arch = jd["architecture"]
if arch[0] == "ETM":
d.etm_architecture = int(arch[1])
if "ram_size" in jd:
d.ram_size = jd["ram_size"]
for jl in jp["links"]:
def jport(p, port):
if isinstance(port, list):
Expand Down
43 changes: 33 additions & 10 deletions coresight-tools/cs_topology_dot.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@
from __future__ import print_function

import cs_topology
import sys


def memory_size_str(sz):
if sz >= 1024*1024:
return "%uM" % (sz // (1024*1024))
elif sz >= 1024:
return "%uK" % (sz // 1024)
else:
return "%u" % sz


def generate_dot(p):
Expand All @@ -33,7 +43,9 @@ def generate_dot(p):
for d in p:
seq += 1
d.dotid = "D%u" % seq
d.dotshow = False
d.dotshow = False # set when device is connected to a link
if d.name is None:
d.name = "%s_%u" % (d.type_str(), seq)
for ln in p.links:
if ln.linktype == cs_topology.CS_LINK_CTI:
continue
Expand All @@ -47,9 +59,8 @@ def generate_dot(p):
ln.slave.dotshow = True
for d in p:
if not d.dotshow:
print("ignoring unconnected device: %s" % (d), file=sys.stderr)
continue
if d.name is None:
d.name = "d_%u" % seq
# The type of the device is in most cases obvious from the name it was given in the SDF file.
if d.type == cs_topology.CS_DEVTYPE_FUNNEL:
shape = "invtrapezium"
Expand All @@ -62,7 +73,7 @@ def generate_dot(p):
# ETF and ETB
try:
name += "\\n%uK" % (d.ram_size_bytes / 1024)
except:
except (AttributeError, TypeError):
pass
if d.type == cs_topology.CS_DEVTYPE_BUFFER:
name += "\\nbuffer"
Expand All @@ -71,17 +82,25 @@ def generate_dot(p):
# Funnels
try:
name += "\\n%u ports" % (d.port_count)
except:
except (AttributeError, TypeError):
pass
# ETMs
try:
name += "\\n%s" % (d.version_string)
except:
except (AttributeError, TypeError):
pass
# All devices should have a part number
try:
name += "\\n%03X" % (d.part_number)
except:
except (AttributeError, TypeError):
pass
try:
name += "\\n%s" % (memory_size_str(d.ram_size))
except (AttributeError, TypeError):
pass
try:
name += "\\n%s" % (d.address_str())
except (AttributeError, TypeError):
pass
else:
name = ""
Expand All @@ -90,14 +109,14 @@ def generate_dot(p):
print(" %sAXI [label=\"AXI\" shape=\"circle\"];" % (d.dotid))
try:
lab = "%u bits" % d.mem_width_bits
except:
except AttributeError:
lab = ""
print(" %s -> %sAXI [label=\"%s\"];" % (d.dotid, d.dotid, lab))
elif d.type == cs_topology.CS_DEVTYPE_PORT:
lab = "port"
try:
lab += "\\n%s bits" % d.port_sizes
except:
except (AttributeError, TypeError):
pass
print(" %sPORT [label=\"%s\"];" % (d.dotid, lab))
print(" %s -> %sPORT;" % (d.dotid, d.dotid))
Expand All @@ -117,7 +136,7 @@ def rank_all(x):
rank_all([d for d in p if d.type[0] == 1])


def generate_digraph(p, size="8,11", label="None"):
def generate_digraph(p, size="7,10", label="None"):
"""
Generate a complete digraph to standard output.
The caller can concatenate these to form a multipage document.
Expand All @@ -130,3 +149,7 @@ def generate_digraph(p, size="8,11", label="None"):
generate_dot(p)
print("}")


if __name__ == "__main__":
p = cs_topology.load("topology.json")
generate_digraph(p)
32 changes: 31 additions & 1 deletion coresight-tools/csscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,9 @@ def is_replicator(self):
def is_cti(self):
return self.is_arm_architecture(ARM_ARCHID_CTI) or self.is_arm_part_number(0x906) or self.is_arm_part_number(0x9ED)

def is_tmc(self):
return self.arm_part_number() in [0x961, 0x9e8, 0x9e9, 0x9ea]

def cs_device_type_name(self):
devtype = self.coresight_device_type()
(major, minor) = devtype
Expand Down Expand Up @@ -1332,6 +1335,7 @@ def show_coresight_device(d):
print(" scrambler", end="")
print(" groupwidth=%u" % ((bits(devid1,8,8)+1)*8), end="")
if bits(devid2,8,8):
# comparator width may be smaller than group width
print(" compwidth=%u" % ((bits(devid2,8,8)+1)*8), end="")
else:
pass # COMP_WIDTH == GRP_WIDTH
Expand Down Expand Up @@ -1363,7 +1367,7 @@ def show_coresight_device(d):
elif d.is_arm_part_number(0x907):
# CoreSight ETB - predating the TMC-ETB
print(" ETB size:%u" % (d.read32(0x004)*4), end="")
elif d.arm_part_number() in [0x961, 0x9e8, 0x9e9, 0x9ea]:
elif d.is_tmc():
# CoreSight TMC (SoC400 generation, or SoC600)
# TMC Configuration (ETB/ETR/ETF/ETS) is selected at RTL build time, and is indicated in DEVID.
# For pre-SoC600 TMC, the part number is 0x961 irrespective of configuration.
Expand Down Expand Up @@ -2480,6 +2484,24 @@ def topology_detection_cti(devices, topo):
d.detect()


def device_ram_bytes(d):
if d.is_arm_part_number(0x907):
# ETB
return d.read32(0x004) * 4
elif d.is_tmc():
devid = d.read32(0xFC8)
tmcconfigtype = bits(devid,6,2)
if tmcconfigtype != 1:
return d.read32(0x004) * 4
elif d.is_arm_architecture(ARM_ARCHID_ELA):
devid = d.read32(0xFC8)
devid1 = d.read32(0xFC4)
ram_addr_width = bits(devid,8,8) # SRAM address width in bits, e.g. 6 bits => 64 entries
groupwidth_bytes = (bits(devid1,8,8)+1)
return (1 << ram_addr_width) * groupwidth_bytes
return None


def scan_rom(c, table_addr, recurse=True, detect_topology=False, detect_topology_cti=False, enable_timestamps=False):
"""
Scan a ROM Table recursively, showing devices as we go.
Expand Down Expand Up @@ -2543,6 +2565,11 @@ def get_etm_architecture(d):
elif d.is_arm_architecture(ARM_ARCHID_STM):
# STM: we should add the memory-mapped stimulus base address and size.
pass
if d.is_arm_part_number():
dd["part_number"] = ("0x%03x" % d.part_number)
ram_size = device_ram_bytes(d)
if ram_size is not None:
dd["ram_size"] = ram_size
topo["devices"].append(dd)
if detect_topology:
topology_detection_atb(atb_devices, topo)
Expand Down Expand Up @@ -2650,6 +2677,9 @@ def enable_devmemd(remote):
enable_devmemd(arg[9:])
elif arg == "--top-only":
o_top_only = True
elif arg == "--help":
help()
sys.exit()
else:
if o_verbose >= 2:
disable_stdout_buffering()
Expand Down

0 comments on commit 2dba577

Please sign in to comment.