diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/arch/arm/ArmSystem.py | 23 | ||||
-rw-r--r-- | src/python/SConscript | 1 | ||||
-rw-r--r-- | src/python/m5/SimObject.py | 16 | ||||
-rw-r--r-- | src/python/m5/util/fdthelper.py | 255 | ||||
-rw-r--r-- | src/sim/SubSystem.py | 4 |
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 |