summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/arm/ArmSystem.py23
-rw-r--r--src/python/SConscript1
-rw-r--r--src/python/m5/SimObject.py16
-rw-r--r--src/python/m5/util/fdthelper.py255
-rw-r--r--src/sim/SubSystem.py4
5 files changed, 298 insertions, 1 deletions
diff --git a/src/arch/arm/ArmSystem.py b/src/arch/arm/ArmSystem.py
index b42f219ef..245ac55df 100644
--- a/src/arch/arm/ArmSystem.py
+++ b/src/arch/arm/ArmSystem.py
@@ -34,9 +34,11 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Ali Saidi
+# Glenn Bergmans
from m5.params import *
from m5.SimObject import *
+from m5.util.fdthelper import *
from System import System
@@ -79,6 +81,27 @@ class ArmSystem(System):
"Base of the 64KiB PA range used for memory-mapped m5ops. Set to 0 "
"to disable.")
+ def generateDeviceTree(self, state):
+ # Generate a device tree root node for the system by creating the root
+ # node and adding the generated subnodes of all children.
+ # When a child needs to add multiple nodes, this is done by also
+ # creating a node called '/' which will then be merged with the
+ # root instead of appended.
+
+ root = FdtNode('/')
+ root.append(state.addrCellsProperty())
+ root.append(state.sizeCellsProperty())
+
+ for node in self.recurseDeviceTree(state):
+ # Merge root nodes instead of adding them (for children
+ # that need to add multiple root level nodes)
+ if node.get_name() == root.get_name():
+ root.merge(node)
+ else:
+ root.append(node)
+
+ return root
+
class GenericArmSystem(ArmSystem):
type = 'GenericArmSystem'
cxx_header = "arch/arm/system.hh"
diff --git a/src/python/SConscript b/src/python/SConscript
index c974238cd..19fb38608 100644
--- a/src/python/SConscript
+++ b/src/python/SConscript
@@ -60,6 +60,7 @@ PySource('m5.util', 'm5/util/smartdict.py')
PySource('m5.util', 'm5/util/sorteddict.py')
PySource('m5.util', 'm5/util/terminal.py')
PySource('m5.util', 'm5/util/pybind.py')
+PySource('m5.util', 'm5/util/fdthelper.py')
PySource('m5.internal', 'm5/internal/__init__.py')
PySource('m5.internal', 'm5/internal/params.py')
diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py
index cff818c66..919c0e852 100644
--- a/src/python/m5/SimObject.py
+++ b/src/python/m5/SimObject.py
@@ -51,6 +51,9 @@ import inspect
import m5
from m5.util import *
from m5.util.pybind import *
+# Use the pyfdt and not the helper class, because the fdthelper
+# relies on the SimObject definition
+from m5.ext.pyfdt import pyfdt
# Have to import params up top since Param is referenced on initial
# load (when SimObject class references Param to create a class
@@ -1495,6 +1498,19 @@ class SimObject(object):
for (attr, portRef) in sorted(self._port_refs.iteritems()):
portRef.ccConnect()
+ # Default function for generating the device structure.
+ # Can be overloaded by the inheriting class
+ def generateDeviceTree(self, state):
+ return # return without yielding anything
+ yield # make this function a (null) generator
+
+ def recurseDeviceTree(self, state):
+ for child in [getattr(self, c) for c in self._children]:
+ for item in child: # For looping over SimObjectVectors
+ if isinstance(item, SimObject):
+ for dt in item.generateDeviceTree(state):
+ yield dt
+
# Function to provide to C++ so it can look up instances based on paths
def resolveSimObject(name):
obj = instanceDict[name]
diff --git a/src/python/m5/util/fdthelper.py b/src/python/m5/util/fdthelper.py
new file mode 100644
index 000000000..bd04b4154
--- /dev/null
+++ b/src/python/m5/util/fdthelper.py
@@ -0,0 +1,255 @@
+# Copyright (c) 2016 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder. You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Author: Glenn Bergmans
+
+from m5.ext.pyfdt import pyfdt
+import re
+import os
+from m5.SimObject import SimObject
+
+class FdtProperty(pyfdt.FdtProperty):
+ """Create a property without values."""
+ pass
+
+class FdtPropertyWords(pyfdt.FdtPropertyWords):
+ """Create a property with word (32-bit unsigned) values."""
+ def __init__(self, name, words):
+ if type(words) != list:
+ words = [words]
+ # Make sure all values are ints (use automatic base detection if the
+ # type is str)
+ words = [long(w, base=0) if type(w) == str else long(w) for w in words]
+ super(FdtPropertyWords, self).__init__(name, words)
+
+class FdtPropertyStrings(pyfdt.FdtPropertyStrings):
+ """Create a property with string values."""
+
+ def __init__(self, name, strings):
+ if type(strings) == str:
+ strings = [strings]
+ strings = [str(string) for string in strings] # Make all values strings
+ super(FdtPropertyStrings, self).__init__(name, strings)
+
+class FdtPropertyBytes(pyfdt.FdtPropertyBytes):
+ """Create a property with integer (8-bit signed) values."""
+
+ def __init__(self, name, values):
+ if type(values) != list:
+ values = [values]
+ # Make sure all values are ints (use automatic base detection if the
+ # type is str)
+ values = [int(v, base=0)
+ if isinstance(v, str) else int(v) for v in values]
+ super(FdtPropertyBytes, self).__init__(name, values)
+
+class FdtState(object):
+ """Class for maintaining state while recursively generating a flattened
+ device tree. The state tracks address, size and CPU address cell sizes, and
+ maintains a dictionary of allocated phandles."""
+
+ phandle_counter = 0
+ phandles = dict()
+
+ def __init__(self, addr_cells, size_cells, cpu_cells):
+ """Instantiate values of this state. The state can only be initialized
+ once."""
+
+ self.addr_cells = addr_cells
+ self.size_cells = size_cells
+ self.cpu_cells = cpu_cells
+
+ def phandle(self, obj):
+ """Return a unique phandle number for a key. The key can be a SimObject
+ or any value that is castable to a string. If the phandle doesn't exist
+ a new one is created, otherwise the existing one is returned."""
+
+ if isinstance(obj, SimObject):
+ key = str(id(obj))
+ else:
+ try:
+ key = str(obj)
+ except ValueError:
+ raise ValueError('Phandle keys must be castable to str')
+
+ if not key in FdtState.phandles:
+ FdtState.phandle_counter += 1
+
+ return FdtState.phandles.setdefault(key, FdtState.phandle_counter)
+
+ def resetPhandles(self):
+ FdtState.phandle_counter = 0
+ FdtState.phandles = dict()
+
+ def int_to_cells(self, value, cells):
+ """Helper function for: generates a list of 32 bit cells from an int,
+ used to split up addresses in appropriate 32 bit chunks."""
+ value = long(value)
+
+ if (value >> (32 * cells)) != 0:
+ fatal("Value %d doesn't fit in %d cells" % (value, cells))
+
+ return [(value >> 32*(x-1)) & 0xFFFFFFFF for x in range(cells, 0, -1)]
+
+ def addrCells(self, addr):
+ """Format an integer type according to the address_cells value of this
+ state."""
+ return self.int_to_cells(addr, self.addr_cells)
+
+ def CPUAddrCells(self, addr):
+ """Format an integer type according to the cpu_cells value of this
+ state."""
+ return self.int_to_cells(addr, self.cpu_cells)
+
+ def sizeCells(self, size):
+ """Format an integer type according to the size_cells value of this
+ state."""
+ return self.int_to_cells(size, self.size_cells)
+
+ def addrCellsProperty(self):
+ """Return an #address-cells property with the value of this state."""
+ return FdtPropertyWords("#address-cells", self.addr_cells)
+
+ def sizeCellsProperty(self):
+ """Return an #size-cells property with the value of this state."""
+ return FdtPropertyWords("#size-cells", self.size_cells)
+
+ def CPUCellsProperty(self):
+ """Return an #address-cells property for cpu nodes with the value
+ of this state."""
+ return FdtPropertyWords("#address-cells", self.cpu_cells)
+
+class FdtNop(pyfdt.FdtNop):
+ """Create an empty node."""
+ pass
+
+class FdtNode(pyfdt.FdtNode):
+ def __init__(self, name, obj=None):
+ """Create a new node and immediately set the phandle property, if obj
+ is supplied"""
+ super(FdtNode, self).__init__(name)
+ if obj != None:
+ self.appendPhandle(obj)
+
+ def append(self, subnodes):
+ """Change the behavior of the normal append to override if a node with
+ the same name already exists or merge if the name exists and is a node
+ type. Can also take a list of subnodes, that each get appended."""
+ if not hasattr(subnodes, '__iter__'):
+ subnodes = [subnodes]
+
+ for subnode in subnodes:
+ try:
+ if not issubclass(type(subnode), pyfdt.FdtNop):
+ index = self.index(subnode.name)
+ item = self.pop(index)
+ else:
+ item = None
+ except ValueError:
+ item = None
+
+ if isinstance(item, pyfdt.FdtNode) and \
+ isinstance(subnode, pyfdt.FdtNode):
+ item.merge(subnode)
+ subnode = item
+
+ super(FdtNode, self).append(subnode)
+
+ def appendList(self, subnode_list):
+ """Append all properties/nodes in the iterable."""
+ for subnode in subnode_list:
+ self.append(subnode)
+
+ def appendCompatible(self, compatible):
+ """Append a compatible property with the supplied compatibility
+ strings."""
+ if isinstance(compatible, str):
+ compatible = [compatible]
+ self.append(FdtPropertyStrings('compatible', compatible))
+
+ def appendPhandle(self, obj):
+ """Append a phandle property to this node with the phandle of the
+ supplied object."""
+ # Create a bogus state because we only need the Phandle dictionary
+ state = FdtState(addr_cells=1, size_cells=1, cpu_cells=1)
+
+ phandle = state.phandle(obj)
+ self.append(FdtPropertyWords("phandle", [phandle]))
+
+class Fdt(pyfdt.Fdt):
+ def sortNodes(self, node):
+ """Move all properties to the beginning and subnodes to the end
+ while maintaining the order of the subnodes. DTB files require the
+ properties to go before the nodes, but the PyFdt doesn't account for
+ defining nodes and properties in a random order."""
+ properties = FdtNode(node.name)
+ subnodes = FdtNode(node.name)
+
+ while len(node):
+ subnode = node.pop(0)
+ if issubclass(type(subnode), pyfdt.FdtNode):
+ subnode = self.sortNodes(subnode)
+ subnodes.append(subnode)
+ else:
+ properties.append(subnode)
+
+ properties.merge(subnodes)
+
+ return properties
+
+ def add_rootnode(self, rootnode, prenops=None, postnops=None):
+ """First sort the device tree, so that properties are before nodes."""
+ rootnode = self.sortNodes(rootnode)
+ super(Fdt, self).add_rootnode(rootnode, prenops, postnops)
+
+ def writeDtbFile(self, filename):
+ """Convert the device tree to DTB and write to a file."""
+ filename = os.path.realpath(filename)
+ try:
+ with open(filename, 'wb') as f:
+ f.write(self.to_dtb())
+ return filename
+ except IOError:
+ raise RuntimeError("Failed to open DTB output file")
+
+ def writeDtsFile(self, filename):
+ """Convert the device tree to DTS and write to a file."""
+ filename = os.path.realpath(filename)
+ try:
+ with open(filename, 'w') as f:
+ f.write(self.to_dts())
+ return filename
+ except IOError:
+ raise RuntimeError("Failed to open DTS output file")
diff --git a/src/sim/SubSystem.py b/src/sim/SubSystem.py
index 47e9d4d6f..50e7dbd40 100644
--- a/src/sim/SubSystem.py
+++ b/src/sim/SubSystem.py
@@ -52,6 +52,8 @@ class SubSystem(SimObject):
cxx_header = "sim/sub_system.hh"
abstract = False
- # Thermal doamin associated to this object, inheriting the parent's
+ # Thermal domain associated to this object, inheriting the parent's
# clock domain by default
thermal_domain = Param.ThermalDomain(NULL, "Thermal domain")
+
+ generateDeviceTree = SimObject.recurseDeviceTree