Merge zizzer.eecs.umich.edu:/z/m5/Bitkeeper/newmem
into zizzer.eecs.umich.edu:/z/stever/bk/newmem-head --HG-- extra : convert_revision : 8a1cd7ff43aa4ebbfce0ff174d2f4ba3f095dd47
This commit is contained in:
commit
f06d508af0
25 changed files with 477 additions and 376 deletions
|
@ -129,17 +129,7 @@ class BaseTsunami(Tsunami):
|
|||
ethernet = NSGigE(configdata=NSGigEPciData(),
|
||||
pci_bus=0, pci_dev=1, pci_func=0)
|
||||
etherint = NSGigEInt(device=Parent.ethernet)
|
||||
# ethernet = Sinic(configdata=SinicPciData(),
|
||||
# pci_bus=0, pci_dev=1, pci_func=0)
|
||||
# etherint = SinicInt(device=Parent.ethernet)
|
||||
console = AlphaConsole(pio_addr=0x80200000000, disk=Parent.simple_disk)
|
||||
# bridge = PciFake(configdata=BridgePciData(), pci_bus=0, pci_dev=2, pci_func=0)
|
||||
|
||||
#class FreeBSDTsunami(BaseTsunami):
|
||||
# disk0 = FreeBSDRootDisk(delay='0us', driveID='master')
|
||||
# ide = IdeController(disks=[Parent.disk0],
|
||||
# configdata=IdeControllerPciData(),
|
||||
# pci_func=0, pci_dev=0, pci_bus=0)
|
||||
|
||||
class LinuxTsunami(BaseTsunami):
|
||||
disk0 = LinuxRootDisk(driveID='master')
|
||||
|
@ -149,45 +139,45 @@ class LinuxTsunami(BaseTsunami):
|
|||
configdata=IdeControllerPciData(),
|
||||
pci_func=0, pci_dev=0, pci_bus=0)
|
||||
|
||||
class LinuxAlphaSystem(LinuxAlphaSystem):
|
||||
class MyLinuxAlphaSystem(LinuxAlphaSystem):
|
||||
magicbus = Bus(bus_id=0)
|
||||
magicbus2 = Bus(bus_id=1)
|
||||
bridge = Bridge()
|
||||
physmem = PhysicalMemory(range = AddrRange('128MB'))
|
||||
c0a = Connector(side_a=Parent.magicbus, side_b=Parent.bridge, side_b_name="side_a")
|
||||
c0b = Connector(side_a=Parent.magicbus2, side_b=Parent.bridge, side_b_name="side_b")
|
||||
c1 = Connector(side_a=Parent.physmem, side_b=Parent.magicbus2)
|
||||
bridge.side_a = magicbus.port
|
||||
bridge.side_b = magicbus2.port
|
||||
physmem.port = magicbus2.port
|
||||
tsunami = LinuxTsunami()
|
||||
c2 = Connector(side_a=Parent.tsunami.cchip, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c3 = Connector(side_a=Parent.tsunami.pchip, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c4 = Connector(side_a=Parent.tsunami.pciconfig, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c5 = Connector(side_a=Parent.tsunami.fake_sm_chip, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c6 = Connector(side_a=Parent.tsunami.ethernet, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c6a = Connector(side_a=Parent.tsunami.ethernet, side_a_name='dma', side_b=Parent.magicbus)
|
||||
c7 = Connector(side_a=Parent.tsunami.fake_uart1, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c8 = Connector(side_a=Parent.tsunami.fake_uart2, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c9 = Connector(side_a=Parent.tsunami.fake_uart3, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c10 = Connector(side_a=Parent.tsunami.fake_uart4, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c11 = Connector(side_a=Parent.tsunami.ide, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c13 = Connector(side_a=Parent.tsunami.ide, side_a_name='dma', side_b=Parent.magicbus)
|
||||
c12 = Connector(side_a=Parent.tsunami.fake_ppc, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c14 = Connector(side_a=Parent.tsunami.fake_OROM, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c16 = Connector(side_a=Parent.tsunami.fake_pnp_addr, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c17 = Connector(side_a=Parent.tsunami.fake_pnp_write, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c18 = Connector(side_a=Parent.tsunami.fake_pnp_read0, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c19 = Connector(side_a=Parent.tsunami.fake_pnp_read1, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c20 = Connector(side_a=Parent.tsunami.fake_pnp_read2, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c21 = Connector(side_a=Parent.tsunami.fake_pnp_read3, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c22 = Connector(side_a=Parent.tsunami.fake_pnp_read4, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c23 = Connector(side_a=Parent.tsunami.fake_pnp_read5, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c24 = Connector(side_a=Parent.tsunami.fake_pnp_read6, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c25 = Connector(side_a=Parent.tsunami.fake_pnp_read7, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c27 = Connector(side_a=Parent.tsunami.fake_ata0, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c28 = Connector(side_a=Parent.tsunami.fake_ata1, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c30 = Connector(side_a=Parent.tsunami.fb, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c31 = Connector(side_a=Parent.tsunami.io, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c32 = Connector(side_a=Parent.tsunami.uart, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c33 = Connector(side_a=Parent.tsunami.console, side_a_name='pio', side_b=Parent.magicbus)
|
||||
tsunami.cchip.pio = magicbus.port
|
||||
tsunami.pchip.pio = magicbus.port
|
||||
tsunami.pciconfig.pio = magicbus.port
|
||||
tsunami.fake_sm_chip.pio = magicbus.port
|
||||
tsunami.ethernet.pio = magicbus.port
|
||||
tsunami.ethernet.dma = magicbus.port
|
||||
tsunami.fake_uart1.pio = magicbus.port
|
||||
tsunami.fake_uart2.pio = magicbus.port
|
||||
tsunami.fake_uart3.pio = magicbus.port
|
||||
tsunami.fake_uart4.pio = magicbus.port
|
||||
tsunami.ide.pio = magicbus.port
|
||||
tsunami.ide.dma = magicbus.port
|
||||
tsunami.fake_ppc.pio = magicbus.port
|
||||
tsunami.fake_OROM.pio = magicbus.port
|
||||
tsunami.fake_pnp_addr.pio = magicbus.port
|
||||
tsunami.fake_pnp_write.pio = magicbus.port
|
||||
tsunami.fake_pnp_read0.pio = magicbus.port
|
||||
tsunami.fake_pnp_read1.pio = magicbus.port
|
||||
tsunami.fake_pnp_read2.pio = magicbus.port
|
||||
tsunami.fake_pnp_read3.pio = magicbus.port
|
||||
tsunami.fake_pnp_read4.pio = magicbus.port
|
||||
tsunami.fake_pnp_read5.pio = magicbus.port
|
||||
tsunami.fake_pnp_read6.pio = magicbus.port
|
||||
tsunami.fake_pnp_read7.pio = magicbus.port
|
||||
tsunami.fake_ata0.pio = magicbus.port
|
||||
tsunami.fake_ata1.pio = magicbus.port
|
||||
tsunami.fb.pio = magicbus.port
|
||||
tsunami.io.pio = magicbus.port
|
||||
tsunami.uart.pio = magicbus.port
|
||||
tsunami.console.pio = magicbus.port
|
||||
raw_image = RawDiskImage(image_file=disk('linux-latest.img'),
|
||||
read_only=True)
|
||||
simple_disk = SimpleDisk(disk=Parent.raw_image)
|
||||
|
@ -196,7 +186,7 @@ class LinuxAlphaSystem(LinuxAlphaSystem):
|
|||
cpu = TimingSimpleCPU()
|
||||
else:
|
||||
cpu = AtomicSimpleCPU()
|
||||
cpu.mem = Parent.magicbus2
|
||||
cpu.mem = magicbus2
|
||||
cpu.itb = AlphaITB()
|
||||
cpu.dtb = AlphaDTB()
|
||||
sim_console = SimConsole(listener=ConsoleListener(port=3456))
|
||||
|
@ -224,11 +214,12 @@ def DualRoot(clientSystem, serverSystem):
|
|||
self.clock = '5GHz'
|
||||
return self
|
||||
|
||||
root = DualRoot(LinuxAlphaSystem(readfile=script('netperf-stream-nt-client.rcS')),
|
||||
LinuxAlphaSystem(readfile=script('netperf-server.rcS')))
|
||||
root = DualRoot(
|
||||
MyLinuxAlphaSystem(readfile=script('netperf-stream-nt-client.rcS')),
|
||||
MyLinuxAlphaSystem(readfile=script('netperf-server.rcS')))
|
||||
|
||||
m5.instantiate(root)
|
||||
|
||||
exit_event = m5.simulate()
|
||||
|
||||
print 'Exiting @', m5.curTick(), 'because', exit_event.getCause()
|
||||
print 'Exiting @ cycle', m5.curTick(), 'because', exit_event.getCause()
|
||||
|
|
|
@ -41,7 +41,7 @@ cpu.workload = process
|
|||
cpu.mem = magicbus
|
||||
|
||||
system = System(physmem = mem, cpu = cpu)
|
||||
system.c1 = Connector(side_a = mem, side_b = magicbus)
|
||||
mem.port = magicbus.port
|
||||
root = Root(system = system)
|
||||
|
||||
# instantiate configuration
|
||||
|
|
|
@ -97,14 +97,12 @@ base_sources = Split('''
|
|||
|
||||
mem/bridge.cc
|
||||
mem/bus.cc
|
||||
mem/connector.cc
|
||||
mem/mem_object.cc
|
||||
mem/packet.cc
|
||||
mem/physical.cc
|
||||
mem/port.cc
|
||||
|
||||
sim/builder.cc
|
||||
sim/configfile.cc
|
||||
sim/debug.cc
|
||||
sim/eventq.cc
|
||||
sim/faults.cc
|
||||
|
|
|
@ -247,7 +247,7 @@ class PioDevice : public MemObject
|
|||
|
||||
virtual void init();
|
||||
|
||||
virtual Port *getPort(const std::string &if_name)
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1)
|
||||
{
|
||||
if (if_name == "pio") {
|
||||
if (pioPort != NULL)
|
||||
|
@ -309,7 +309,7 @@ class DmaDevice : public PioDevice
|
|||
|
||||
bool dmaPending() { return dmaPort->dmaPending(); }
|
||||
|
||||
virtual Port *getPort(const std::string &if_name)
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1)
|
||||
{
|
||||
if (if_name == "pio") {
|
||||
if (pioPort != NULL)
|
||||
|
|
|
@ -59,7 +59,7 @@ Bridge::Bridge(const std::string &n, int qsa, int qsb,
|
|||
}
|
||||
|
||||
Port *
|
||||
Bridge::getPort(const std::string &if_name)
|
||||
Bridge::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
BridgePort *port;
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ class Bridge : public MemObject
|
|||
public:
|
||||
|
||||
/** A function used to return the port associated with this bus object. */
|
||||
virtual Port *getPort(const std::string &if_name);
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1);
|
||||
|
||||
virtual void init();
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#include "sim/builder.hh"
|
||||
|
||||
Port *
|
||||
Bus::getPort(const std::string &if_name)
|
||||
Bus::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
// if_name ignored? forced to be empty?
|
||||
int id = interfaces.size();
|
||||
|
|
|
@ -161,7 +161,7 @@ class Bus : public MemObject
|
|||
public:
|
||||
|
||||
/** A function used to return the port associated with this bus object. */
|
||||
virtual Port *getPort(const std::string &if_name);
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1);
|
||||
|
||||
virtual void init();
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ class MemObject : public SimObject
|
|||
|
||||
public:
|
||||
/** Additional function to return the Port of a memory object. */
|
||||
virtual Port *getPort(const std::string &if_name) = 0;
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1) = 0;
|
||||
};
|
||||
|
||||
#endif //__MEM_MEM_OBJECT_HH__
|
||||
|
|
|
@ -173,9 +173,9 @@ PhysicalMemory::doFunctionalAccess(Packet *pkt)
|
|||
}
|
||||
|
||||
Port *
|
||||
PhysicalMemory::getPort(const std::string &if_name)
|
||||
PhysicalMemory::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
if (if_name == "") {
|
||||
if (if_name == "port" && idx == -1) {
|
||||
if (port != NULL)
|
||||
panic("PhysicalMemory::getPort: additional port requested to memory!");
|
||||
port = new MemoryPort(name() + "-port", this);
|
||||
|
|
|
@ -108,7 +108,7 @@ class PhysicalMemory : public MemObject
|
|||
public:
|
||||
int deviceBlockSize();
|
||||
void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop);
|
||||
virtual Port *getPort(const std::string &if_name);
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1);
|
||||
void virtual init();
|
||||
|
||||
// fast back-door memory access for vtophys(), remote gdb, etc.
|
||||
|
|
|
@ -103,6 +103,12 @@ build_env.update(defines.m5_build_env)
|
|||
env = smartdict.SmartDict()
|
||||
env.update(os.environ)
|
||||
|
||||
|
||||
# Function to provide to C++ so it can look up instances based on paths
|
||||
def resolveSimObject(name):
|
||||
obj = config.instanceDict[name]
|
||||
return obj.getCCObject()
|
||||
|
||||
# The final hook to generate .ini files. Called from the user script
|
||||
# once the config is built.
|
||||
def instantiate(root):
|
||||
|
@ -112,7 +118,10 @@ def instantiate(root):
|
|||
root.print_ini()
|
||||
sys.stdout.close() # close config.ini
|
||||
sys.stdout = sys.__stdout__ # restore to original
|
||||
main.initialize() # load config.ini into C++ and process it
|
||||
main.loadIniFile(resolveSimObject) # load config.ini into C++
|
||||
root.createCCObject()
|
||||
root.connectPorts()
|
||||
main.finalInit()
|
||||
noDot = True # temporary until we fix dot
|
||||
if not noDot:
|
||||
dot = pydot.Dot()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2004-2005 The Regents of The University of Michigan
|
||||
# Copyright (c) 2004-2006 The Regents of The University of Michigan
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
|
@ -27,7 +27,7 @@
|
|||
# Authors: Steve Reinhardt
|
||||
# Nathan Binkert
|
||||
|
||||
import os, re, sys, types, inspect
|
||||
import os, re, sys, types, inspect, copy
|
||||
|
||||
import m5
|
||||
from m5 import panic
|
||||
|
@ -84,65 +84,22 @@ class Singleton(type):
|
|||
#
|
||||
# Once a set of Python objects have been instantiated in a hierarchy,
|
||||
# calling 'instantiate(obj)' (where obj is the root of the hierarchy)
|
||||
# will generate a .ini file. See simple-4cpu.py for an example
|
||||
# (corresponding to m5-test/simple-4cpu.ini).
|
||||
# will generate a .ini file.
|
||||
#
|
||||
#####################################################################
|
||||
|
||||
#####################################################################
|
||||
#
|
||||
# ConfigNode/SimObject classes
|
||||
#
|
||||
# The Python class hierarchy rooted by ConfigNode (which is the base
|
||||
# class of SimObject, which in turn is the base class of all other M5
|
||||
# SimObject classes) has special attribute behavior. In general, an
|
||||
# object in this hierarchy has three categories of attribute-like
|
||||
# things:
|
||||
#
|
||||
# 1. Regular Python methods and variables. These must start with an
|
||||
# underscore to be treated normally.
|
||||
#
|
||||
# 2. SimObject parameters. These values are stored as normal Python
|
||||
# attributes, but all assignments to these attributes are checked
|
||||
# against the pre-defined set of parameters stored in the class's
|
||||
# _params dictionary. Assignments to attributes that do not
|
||||
# correspond to predefined parameters, or that are not of the correct
|
||||
# type, incur runtime errors.
|
||||
#
|
||||
# 3. Hierarchy children. The child nodes of a ConfigNode are stored
|
||||
# in the node's _children dictionary, but can be accessed using the
|
||||
# Python attribute dot-notation (just as they are printed out by the
|
||||
# simulator). Children cannot be created using attribute assigment;
|
||||
# they must be added by specifying the parent node in the child's
|
||||
# constructor or using the '+=' operator.
|
||||
# dict to look up SimObjects based on path
|
||||
instanceDict = {}
|
||||
|
||||
# The SimObject parameters are the most complex, for a few reasons.
|
||||
# First, both parameter descriptions and parameter values are
|
||||
# inherited. Thus parameter description lookup must go up the
|
||||
# inheritance chain like normal attribute lookup, but this behavior
|
||||
# must be explicitly coded since the lookup occurs in each class's
|
||||
# _params attribute. Second, because parameter values can be set
|
||||
# on SimObject classes (to implement default values), the parameter
|
||||
# checking behavior must be enforced on class attribute assignments as
|
||||
# well as instance attribute assignments. Finally, because we allow
|
||||
# class specialization via inheritance (e.g., see the L1Cache class in
|
||||
# the simple-4cpu.py example), we must do parameter checking even on
|
||||
# class instantiation. To provide all these features, we use a
|
||||
# metaclass to define most of the SimObject parameter behavior for
|
||||
# this class hierarchy.
|
||||
#############################
|
||||
#
|
||||
#####################################################################
|
||||
# Utility methods
|
||||
#
|
||||
#############################
|
||||
|
||||
def isSimObject(value):
|
||||
return isinstance(value, SimObject)
|
||||
|
||||
def isSimObjectClass(value):
|
||||
try:
|
||||
return issubclass(value, SimObject)
|
||||
except TypeError:
|
||||
# happens if value is not a class at all
|
||||
return False
|
||||
|
||||
def isSimObjectSequence(value):
|
||||
if not isinstance(value, (list, tuple)) or len(value) == 0:
|
||||
return False
|
||||
|
@ -153,22 +110,9 @@ def isSimObjectSequence(value):
|
|||
|
||||
return True
|
||||
|
||||
def isSimObjectClassSequence(value):
|
||||
if not isinstance(value, (list, tuple)) or len(value) == 0:
|
||||
return False
|
||||
|
||||
for val in value:
|
||||
if not isNullPointer(val) and not isSimObjectClass(val):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def isSimObjectOrSequence(value):
|
||||
return isSimObject(value) or isSimObjectSequence(value)
|
||||
|
||||
def isSimObjectClassOrSequence(value):
|
||||
return isSimObjectClass(value) or isSimObjectClassSequence(value)
|
||||
|
||||
def isNullPointer(value):
|
||||
return isinstance(value, NullSimObject)
|
||||
|
||||
|
@ -188,40 +132,36 @@ def applyOrMap(objOrSeq, meth, *args, **kwargs):
|
|||
return [applyMethod(o, meth, *args, **kwargs) for o in objOrSeq]
|
||||
|
||||
|
||||
# The metaclass for ConfigNode (and thus for everything that derives
|
||||
# from ConfigNode, including SimObject). This class controls how new
|
||||
# classes that derive from ConfigNode are instantiated, and provides
|
||||
# inherited class behavior (just like a class controls how instances
|
||||
# of that class are instantiated, and provides inherited instance
|
||||
# behavior).
|
||||
# The metaclass for SimObject. This class controls how new classes
|
||||
# that derive from SimObject are instantiated, and provides inherited
|
||||
# class behavior (just like a class controls how instances of that
|
||||
# class are instantiated, and provides inherited instance behavior).
|
||||
class MetaSimObject(type):
|
||||
# Attributes that can be set only at initialization time
|
||||
init_keywords = { 'abstract' : types.BooleanType,
|
||||
'type' : types.StringType }
|
||||
# Attributes that can be set any time
|
||||
keywords = { 'check' : types.FunctionType,
|
||||
'children' : types.ListType }
|
||||
keywords = { 'check' : types.FunctionType }
|
||||
|
||||
# __new__ is called before __init__, and is where the statements
|
||||
# in the body of the class definition get loaded into the class's
|
||||
# __dict__. We intercept this to filter out parameter assignments
|
||||
# __dict__. We intercept this to filter out parameter & port assignments
|
||||
# and only allow "private" attributes to be passed to the base
|
||||
# __new__ (starting with underscore).
|
||||
def __new__(mcls, name, bases, dict):
|
||||
if dict.has_key('_init_dict'):
|
||||
# must have been called from makeSubclass() rather than
|
||||
# via Python class declaration; bypass filtering process.
|
||||
cls_dict = dict
|
||||
else:
|
||||
# Copy "private" attributes (including special methods
|
||||
# such as __new__) to the official dict. Everything else
|
||||
# goes in _init_dict to be filtered in __init__.
|
||||
cls_dict = {}
|
||||
for key,val in dict.items():
|
||||
if key.startswith('_'):
|
||||
cls_dict[key] = val
|
||||
del dict[key]
|
||||
cls_dict['_init_dict'] = dict
|
||||
# Copy "private" attributes, functions, and classes to the
|
||||
# official dict. Everything else goes in _init_dict to be
|
||||
# filtered in __init__.
|
||||
cls_dict = {}
|
||||
value_dict = {}
|
||||
for key,val in dict.items():
|
||||
if key.startswith('_') or isinstance(val, (types.FunctionType,
|
||||
types.TypeType)):
|
||||
cls_dict[key] = val
|
||||
else:
|
||||
# must be a param/port setting
|
||||
value_dict[key] = val
|
||||
cls_dict['_value_dict'] = value_dict
|
||||
return super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
|
||||
|
||||
# subclass initialization
|
||||
|
@ -231,10 +171,15 @@ class MetaSimObject(type):
|
|||
super(MetaSimObject, cls).__init__(name, bases, dict)
|
||||
|
||||
# initialize required attributes
|
||||
cls._params = multidict()
|
||||
cls._values = multidict()
|
||||
cls._instantiated = False # really instantiated or subclassed
|
||||
cls._anon_subclass_counter = 0
|
||||
|
||||
# class-only attributes
|
||||
cls._params = multidict() # param descriptions
|
||||
cls._ports = multidict() # port descriptions
|
||||
|
||||
# class or instance attributes
|
||||
cls._values = multidict() # param values
|
||||
cls._port_map = multidict() # port bindings
|
||||
cls._instantiated = False # really instantiated, cloned, or subclassed
|
||||
|
||||
# We don't support multiple inheritance. If you want to, you
|
||||
# must fix multidict to deal with it properly.
|
||||
|
@ -243,22 +188,34 @@ class MetaSimObject(type):
|
|||
|
||||
base = bases[0]
|
||||
|
||||
# the only time the following is not true is when we define
|
||||
# the SimObject class itself
|
||||
# Set up general inheritance via multidicts. A subclass will
|
||||
# inherit all its settings from the base class. The only time
|
||||
# the following is not true is when we define the SimObject
|
||||
# class itself (in which case the multidicts have no parent).
|
||||
if isinstance(base, MetaSimObject):
|
||||
cls._params.parent = base._params
|
||||
cls._ports.parent = base._ports
|
||||
cls._values.parent = base._values
|
||||
cls._port_map.parent = base._port_map
|
||||
# mark base as having been subclassed
|
||||
base._instantiated = True
|
||||
|
||||
# now process the _init_dict items
|
||||
for key,val in cls._init_dict.items():
|
||||
if isinstance(val, (types.FunctionType, types.TypeType)):
|
||||
type.__setattr__(cls, key, val)
|
||||
|
||||
# Now process the _value_dict items. They could be defining
|
||||
# new (or overriding existing) parameters or ports, setting
|
||||
# class keywords (e.g., 'abstract'), or setting parameter
|
||||
# values or port bindings. The first 3 can only be set when
|
||||
# the class is defined, so we handle them here. The others
|
||||
# can be set later too, so just emulate that by calling
|
||||
# setattr().
|
||||
for key,val in cls._value_dict.items():
|
||||
# param descriptions
|
||||
elif isinstance(val, ParamDesc):
|
||||
if isinstance(val, ParamDesc):
|
||||
cls._new_param(key, val)
|
||||
|
||||
# port objects
|
||||
elif isinstance(val, Port):
|
||||
cls._ports[key] = val
|
||||
|
||||
# init-time-only keywords
|
||||
elif cls.init_keywords.has_key(key):
|
||||
cls._set_keyword(key, val, cls.init_keywords[key])
|
||||
|
@ -267,27 +224,6 @@ class MetaSimObject(type):
|
|||
else:
|
||||
setattr(cls, key, val)
|
||||
|
||||
# Pull the deep-copy memoization dict out of the class dict if
|
||||
# it's there...
|
||||
memo = cls.__dict__.get('_memo', {})
|
||||
|
||||
# Handle SimObject values
|
||||
for key,val in cls._values.iteritems():
|
||||
# SimObject instances need to be promoted to classes.
|
||||
# Existing classes should not have any instance values, so
|
||||
# these can only occur at the lowest level dict (the
|
||||
# parameters just being set in this class definition).
|
||||
if isSimObjectOrSequence(val):
|
||||
assert(val == cls._values.local[key])
|
||||
cls._values[key] = applyOrMap(val, 'makeClass', memo)
|
||||
# SimObject classes need to be subclassed so that
|
||||
# parameters that get set at this level only affect this
|
||||
# level and derivatives.
|
||||
elif isSimObjectClassOrSequence(val):
|
||||
assert(not cls._values.local.has_key(key))
|
||||
cls._values[key] = applyOrMap(val, 'makeSubclass', {}, memo)
|
||||
|
||||
|
||||
def _set_keyword(cls, keyword, val, kwtype):
|
||||
if not isinstance(val, kwtype):
|
||||
raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
|
||||
|
@ -313,15 +249,19 @@ class MetaSimObject(type):
|
|||
cls._set_keyword(attr, value, cls.keywords[attr])
|
||||
return
|
||||
|
||||
# must be SimObject param
|
||||
param = cls._params.get(attr, None)
|
||||
if param:
|
||||
# It's ok: set attribute by delegating to 'object' class.
|
||||
if isSimObjectOrSequence(value) and cls._instantiated:
|
||||
raise AttributeError, \
|
||||
"Cannot set SimObject parameter '%s' after\n" \
|
||||
if cls._ports.has_key(attr):
|
||||
self._ports[attr].connect(self, attr, value)
|
||||
return
|
||||
|
||||
if isSimObjectOrSequence(value) and cls._instantiated:
|
||||
raise RuntimeError, \
|
||||
"cannot set SimObject parameter '%s' after\n" \
|
||||
" class %s has been instantiated or subclassed" \
|
||||
% (attr, cls.__name__)
|
||||
|
||||
# check for param
|
||||
param = cls._params.get(attr, None)
|
||||
if param:
|
||||
try:
|
||||
cls._values[attr] = param.convert(value)
|
||||
except Exception, e:
|
||||
|
@ -329,9 +269,9 @@ class MetaSimObject(type):
|
|||
(e, cls.__name__, attr, value)
|
||||
e.args = (msg, )
|
||||
raise
|
||||
# I would love to get rid of this
|
||||
elif isSimObjectOrSequence(value):
|
||||
cls._values[attr] = value
|
||||
# if RHS is a SimObject, it's an implicit child assignment
|
||||
cls._values[attr] = value
|
||||
else:
|
||||
raise AttributeError, \
|
||||
"Class %s has no parameter %s" % (cls.__name__, attr)
|
||||
|
@ -343,23 +283,7 @@ class MetaSimObject(type):
|
|||
raise AttributeError, \
|
||||
"object '%s' has no attribute '%s'" % (cls.__name__, attr)
|
||||
|
||||
# Create a subclass of this class. Basically a function interface
|
||||
# to the standard Python class definition mechanism, primarily for
|
||||
# internal use. 'memo' dict param supports "deep copy" (really
|
||||
# "deep subclass") operations... within a given operation,
|
||||
# multiple references to a class should result in a single
|
||||
# subclass object with multiple references to it (as opposed to
|
||||
# mutiple unique subclasses).
|
||||
def makeSubclass(cls, init_dict, memo = {}):
|
||||
subcls = memo.get(cls)
|
||||
if not subcls:
|
||||
name = cls.__name__ + '_' + str(cls._anon_subclass_counter)
|
||||
cls._anon_subclass_counter += 1
|
||||
subcls = MetaSimObject(name, (cls,),
|
||||
{ '_init_dict': init_dict, '_memo': memo })
|
||||
return subcls
|
||||
|
||||
# The ConfigNode class is the root of the special hierarchy. Most of
|
||||
# The SimObject class is the root of the special hierarchy. Most of
|
||||
# the code in this class deals with the configuration hierarchy itself
|
||||
# (parent/child node relationships).
|
||||
class SimObject(object):
|
||||
|
@ -367,82 +291,79 @@ class SimObject(object):
|
|||
# get this metaclass.
|
||||
__metaclass__ = MetaSimObject
|
||||
|
||||
# __new__ operator allocates new instances of the class. We
|
||||
# override it here just to support "deep instantiation" operation
|
||||
# via the _memo dict. When recursively instantiating an object
|
||||
# hierarchy we want to make sure that each class is instantiated
|
||||
# only once, and that if there are multiple references to the same
|
||||
# original class, we end up with the corresponding instantiated
|
||||
# references all pointing to the same instance.
|
||||
def __new__(cls, _memo = None, **kwargs):
|
||||
if _memo is not None and _memo.has_key(cls):
|
||||
# return previously instantiated object
|
||||
assert(len(kwargs) == 0)
|
||||
return _memo[cls]
|
||||
else:
|
||||
# Need a new one... if it needs to be memoized, this will
|
||||
# happen in __init__. We defer the insertion until then
|
||||
# so __init__ can use the memo dict to tell whether or not
|
||||
# to perform the initialization.
|
||||
return super(SimObject, cls).__new__(cls, **kwargs)
|
||||
# Initialize new instance. For objects with SimObject-valued
|
||||
# children, we need to recursively clone the classes represented
|
||||
# by those param values as well in a consistent "deep copy"-style
|
||||
# fashion. That is, we want to make sure that each instance is
|
||||
# cloned only once, and that if there are multiple references to
|
||||
# the same original object, we end up with the corresponding
|
||||
# cloned references all pointing to the same cloned instance.
|
||||
def __init__(self, **kwargs):
|
||||
ancestor = kwargs.get('_ancestor')
|
||||
memo_dict = kwargs.get('_memo')
|
||||
if memo_dict is None:
|
||||
# prepare to memoize any recursively instantiated objects
|
||||
memo_dict = {}
|
||||
elif ancestor:
|
||||
# memoize me now to avoid problems with recursive calls
|
||||
memo_dict[ancestor] = self
|
||||
|
||||
# Initialize new instance previously allocated by __new__. For
|
||||
# objects with SimObject-valued params, we need to recursively
|
||||
# instantiate the classes represented by those param values as
|
||||
# well (in a consistent "deep copy"-style fashion; see comment
|
||||
# above).
|
||||
def __init__(self, _memo = None, **kwargs):
|
||||
if _memo is not None:
|
||||
# We're inside a "deep instantiation"
|
||||
assert(isinstance(_memo, dict))
|
||||
assert(len(kwargs) == 0)
|
||||
if _memo.has_key(self.__class__):
|
||||
# __new__ returned an existing, already initialized
|
||||
# instance, so there's nothing to do here
|
||||
assert(_memo[self.__class__] == self)
|
||||
return
|
||||
# no pre-existing object, so remember this one here
|
||||
_memo[self.__class__] = self
|
||||
else:
|
||||
# This is a new top-level instantiation... don't memoize
|
||||
# this objcet, but prepare to memoize any recursively
|
||||
# instantiated objects.
|
||||
_memo = {}
|
||||
|
||||
self.__class__._instantiated = True
|
||||
if not ancestor:
|
||||
ancestor = self.__class__
|
||||
ancestor._instantiated = True
|
||||
|
||||
# initialize required attributes
|
||||
self._parent = None
|
||||
self._children = {}
|
||||
self._ccObject = None # pointer to C++ object
|
||||
self._instantiated = False # really "cloned"
|
||||
|
||||
# Inherit parameter values from class using multidict so
|
||||
# individual value settings can be overridden.
|
||||
self._values = multidict(self.__class__._values)
|
||||
# For SimObject-valued parameters, the class should have
|
||||
# classes (not instances) for the values. We need to
|
||||
# instantiate these classes rather than just inheriting the
|
||||
# class object.
|
||||
for key,val in self.__class__._values.iteritems():
|
||||
if isSimObjectClass(val):
|
||||
setattr(self, key, val(_memo))
|
||||
elif isSimObjectClassSequence(val) and len(val):
|
||||
setattr(self, key, [ v(_memo) for v in val ])
|
||||
self._values = multidict(ancestor._values)
|
||||
# clone SimObject-valued parameters
|
||||
for key,val in ancestor._values.iteritems():
|
||||
if isSimObject(val):
|
||||
setattr(self, key, val(_memo=memo_dict))
|
||||
elif isSimObjectSequence(val) and len(val):
|
||||
setattr(self, key, [ v(_memo=memo_dict) for v in val ])
|
||||
# clone port references. no need to use a multidict here
|
||||
# since we will be creating new references for all ports.
|
||||
self._port_map = {}
|
||||
for key,val in ancestor._port_map.iteritems():
|
||||
self._port_map[key] = applyOrMap(val, 'clone', memo_dict)
|
||||
# apply attribute assignments from keyword args, if any
|
||||
for key,val in kwargs.iteritems():
|
||||
setattr(self, key, val)
|
||||
|
||||
# Use this instance as a template to create a new class.
|
||||
def makeClass(self, memo = {}):
|
||||
cls = memo.get(self)
|
||||
if not cls:
|
||||
cls = self.__class__.makeSubclass(self._values.local)
|
||||
memo[self] = cls
|
||||
return cls
|
||||
|
||||
# Direct instantiation of instances (cloning) is no longer
|
||||
# allowed; must generate class from instance first.
|
||||
# "Clone" the current instance by creating another instance of
|
||||
# this instance's class, but that inherits its parameter values
|
||||
# and port mappings from the current instance. If we're in a
|
||||
# "deep copy" recursive clone, check the _memo dict to see if
|
||||
# we've already cloned this instance.
|
||||
def __call__(self, **kwargs):
|
||||
raise TypeError, "cannot instantiate SimObject; "\
|
||||
"use makeClass() to make class first"
|
||||
memo_dict = kwargs.get('_memo')
|
||||
if memo_dict is None:
|
||||
# no memo_dict: must be top-level clone operation.
|
||||
# this is only allowed at the root of a hierarchy
|
||||
if self._parent:
|
||||
raise RuntimeError, "attempt to clone object %s " \
|
||||
"not at the root of a tree (parent = %s)" \
|
||||
% (self, self._parent)
|
||||
# create a new dict and use that.
|
||||
memo_dict = {}
|
||||
kwargs['_memo'] = memo_dict
|
||||
elif memo_dict.has_key(self):
|
||||
# clone already done & memoized
|
||||
return memo_dict[self]
|
||||
return self.__class__(_ancestor = self, **kwargs)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if self._ports.has_key(attr):
|
||||
# return reference that can be assigned to another port
|
||||
# via __setattr__
|
||||
return self._ports[attr].makeRef(self, attr)
|
||||
|
||||
if self._values.has_key(attr):
|
||||
return self._values[attr]
|
||||
|
||||
|
@ -457,10 +378,19 @@ class SimObject(object):
|
|||
object.__setattr__(self, attr, value)
|
||||
return
|
||||
|
||||
if self._ports.has_key(attr):
|
||||
# set up port connection
|
||||
self._ports[attr].connect(self, attr, value)
|
||||
return
|
||||
|
||||
if isSimObjectOrSequence(value) and self._instantiated:
|
||||
raise RuntimeError, \
|
||||
"cannot set SimObject parameter '%s' after\n" \
|
||||
" instance been cloned %s" % (attr, `self`)
|
||||
|
||||
# must be SimObject param
|
||||
param = self._params.get(attr, None)
|
||||
if param:
|
||||
# It's ok: set attribute by delegating to 'object' class.
|
||||
try:
|
||||
value = param.convert(value)
|
||||
except Exception, e:
|
||||
|
@ -468,7 +398,6 @@ class SimObject(object):
|
|||
(e, self.__class__.__name__, attr, value)
|
||||
e.args = (msg, )
|
||||
raise
|
||||
# I would love to get rid of this
|
||||
elif isSimObjectOrSequence(value):
|
||||
pass
|
||||
else:
|
||||
|
@ -507,13 +436,13 @@ class SimObject(object):
|
|||
self._children[name] = value
|
||||
|
||||
def set_path(self, parent, name):
|
||||
if not hasattr(self, '_parent'):
|
||||
if not self._parent:
|
||||
self._parent = parent
|
||||
self._name = name
|
||||
parent.add_child(name, self)
|
||||
|
||||
def path(self):
|
||||
if not hasattr(self, '_parent'):
|
||||
if not self._parent:
|
||||
return 'root'
|
||||
ppath = self._parent.path()
|
||||
if ppath == 'root':
|
||||
|
@ -554,6 +483,8 @@ class SimObject(object):
|
|||
def print_ini(self):
|
||||
print '[' + self.path() + ']' # .ini section header
|
||||
|
||||
instanceDict[self.path()] = self
|
||||
|
||||
if hasattr(self, 'type') and not isinstance(self, ParamContext):
|
||||
print 'type=%s' % self.type
|
||||
|
||||
|
@ -585,6 +516,33 @@ class SimObject(object):
|
|||
for child in child_names:
|
||||
self._children[child].print_ini()
|
||||
|
||||
# Call C++ to create C++ object corresponding to this object and
|
||||
# (recursively) all its children
|
||||
def createCCObject(self):
|
||||
self.getCCObject() # force creation
|
||||
for child in self._children.itervalues():
|
||||
child.createCCObject()
|
||||
|
||||
# Get C++ object corresponding to this object, calling C++ if
|
||||
# necessary to construct it. Does *not* recursively create
|
||||
# children.
|
||||
def getCCObject(self):
|
||||
if not self._ccObject:
|
||||
self._ccObject = -1 # flag to catch cycles in recursion
|
||||
self._ccObject = m5.main.createSimObject(self.path())
|
||||
elif self._ccObject == -1:
|
||||
raise RuntimeError, "%s: recursive call to getCCObject()" \
|
||||
% self.path()
|
||||
return self._ccObject
|
||||
|
||||
# Create C++ port connections corresponding to the connections in
|
||||
# _port_map (& recursively for all children)
|
||||
def connectPorts(self):
|
||||
for portRef in self._port_map.itervalues():
|
||||
applyOrMap(portRef, 'ccConnect')
|
||||
for child in self._children.itervalues():
|
||||
child.connectPorts()
|
||||
|
||||
# generate output file for 'dot' to display as a pretty graph.
|
||||
# this code is currently broken.
|
||||
def outputDot(self, dot):
|
||||
|
@ -675,9 +633,9 @@ class BaseProxy(object):
|
|||
|
||||
if self._search_up:
|
||||
while not done:
|
||||
try: obj = obj._parent
|
||||
except: break
|
||||
|
||||
obj = obj._parent
|
||||
if not obj:
|
||||
break
|
||||
result, done = self.find(obj)
|
||||
|
||||
if not done:
|
||||
|
@ -793,16 +751,16 @@ Self = ProxyFactory(search_self = True, search_up = False)
|
|||
#
|
||||
# Parameter description classes
|
||||
#
|
||||
# The _params dictionary in each class maps parameter names to
|
||||
# either a Param or a VectorParam object. These objects contain the
|
||||
# The _params dictionary in each class maps parameter names to either
|
||||
# a Param or a VectorParam object. These objects contain the
|
||||
# parameter description string, the parameter type, and the default
|
||||
# value (loaded from the PARAM section of the .odesc files). The
|
||||
# _convert() method on these objects is used to force whatever value
|
||||
# is assigned to the parameter to the appropriate type.
|
||||
# value (if any). The convert() method on these objects is used to
|
||||
# force whatever value is assigned to the parameter to the appropriate
|
||||
# type.
|
||||
#
|
||||
# Note that the default values are loaded into the class's attribute
|
||||
# space when the parameter dictionary is initialized (in
|
||||
# MetaConfigNode._setparams()); after that point they aren't used.
|
||||
# MetaSimObject._new_param()); after that point they aren't used.
|
||||
#
|
||||
#####################################################################
|
||||
|
||||
|
@ -1419,6 +1377,107 @@ MaxAddr = Addr.max
|
|||
MaxTick = Tick.max
|
||||
AllMemory = AddrRange(0, MaxAddr)
|
||||
|
||||
|
||||
#####################################################################
|
||||
#
|
||||
# Port objects
|
||||
#
|
||||
# Ports are used to interconnect objects in the memory system.
|
||||
#
|
||||
#####################################################################
|
||||
|
||||
# Port reference: encapsulates a reference to a particular port on a
|
||||
# particular SimObject.
|
||||
class PortRef(object):
|
||||
def __init__(self, simobj, name, isVec):
|
||||
assert(isSimObject(simobj))
|
||||
self.simobj = simobj
|
||||
self.name = name
|
||||
self.index = -1
|
||||
self.isVec = isVec # is this a vector port?
|
||||
self.peer = None # not associated with another port yet
|
||||
self.ccConnected = False # C++ port connection done?
|
||||
|
||||
# Set peer port reference. Called via __setattr__ as a result of
|
||||
# a port assignment, e.g., "obj1.port1 = obj2.port2".
|
||||
def setPeer(self, other):
|
||||
if self.isVec:
|
||||
curMap = self.simobj._port_map.get(self.name, [])
|
||||
self.index = len(curMap)
|
||||
curMap.append(other)
|
||||
else:
|
||||
curMap = self.simobj._port_map.get(self.name)
|
||||
if curMap and not self.isVec:
|
||||
print "warning: overwriting port", self.simobj, self.name
|
||||
curMap = other
|
||||
self.simobj._port_map[self.name] = curMap
|
||||
self.peer = other
|
||||
|
||||
def clone(self, memo):
|
||||
newRef = copy.copy(self)
|
||||
assert(isSimObject(newRef.simobj))
|
||||
newRef.simobj = newRef.simobj(_memo=memo)
|
||||
# Tricky: if I'm the *second* PortRef in the pair to be
|
||||
# cloned, then my peer is still in the middle of its clone
|
||||
# method, and thus hasn't returned to its owner's
|
||||
# SimObject.__init__ to get installed in _port_map. As a
|
||||
# result I have no way of finding the *new* peer object. So I
|
||||
# mark myself as "waiting" for my peer, and I let the *first*
|
||||
# PortRef clone call set up both peer pointers after I return.
|
||||
newPeer = newRef.simobj._port_map.get(self.name)
|
||||
if newPeer:
|
||||
if self.isVec:
|
||||
assert(self.index != -1)
|
||||
newPeer = newPeer[self.index]
|
||||
# other guy is all set up except for his peer pointer
|
||||
assert(newPeer.peer == -1) # peer must be waiting for handshake
|
||||
newPeer.peer = newRef
|
||||
newRef.peer = newPeer
|
||||
else:
|
||||
# other guy is in clone; just wait for him to do the work
|
||||
newRef.peer = -1 # mark as waiting for handshake
|
||||
return newRef
|
||||
|
||||
# Call C++ to create corresponding port connection between C++ objects
|
||||
def ccConnect(self):
|
||||
if self.ccConnected: # already done this
|
||||
return
|
||||
peer = self.peer
|
||||
m5.main.connectPorts(self.simobj.getCCObject(), self.name, self.index,
|
||||
peer.simobj.getCCObject(), peer.name, peer.index)
|
||||
self.ccConnected = True
|
||||
peer.ccConnected = True
|
||||
|
||||
# Port description object. Like a ParamDesc object, this represents a
|
||||
# logical port in the SimObject class, not a particular port on a
|
||||
# SimObject instance. The latter are represented by PortRef objects.
|
||||
class Port(object):
|
||||
def __init__(self, desc):
|
||||
self.desc = desc
|
||||
self.isVec = False
|
||||
|
||||
# Generate a PortRef for this port on the given SimObject with the
|
||||
# given name
|
||||
def makeRef(self, simobj, name):
|
||||
return PortRef(simobj, name, self.isVec)
|
||||
|
||||
# Connect an instance of this port (on the given SimObject with
|
||||
# the given name) with the port described by the supplied PortRef
|
||||
def connect(self, simobj, name, ref):
|
||||
if not isinstance(ref, PortRef):
|
||||
raise TypeError, \
|
||||
"assigning non-port reference port '%s'" % name
|
||||
myRef = self.makeRef(simobj, name)
|
||||
myRef.setPeer(ref)
|
||||
ref.setPeer(myRef)
|
||||
|
||||
# VectorPort description object. Like Port, but represents a vector
|
||||
# of connections (e.g., as on a Bus).
|
||||
class VectorPort(Port):
|
||||
def __init__(self, desc):
|
||||
Port.__init__(self, desc)
|
||||
self.isVec = True
|
||||
|
||||
#####################################################################
|
||||
|
||||
# __all__ defines the list of symbols that get exported when
|
||||
|
@ -1436,5 +1495,6 @@ __all__ = ['SimObject', 'ParamContext', 'Param', 'VectorParam',
|
|||
'NetworkBandwidth', 'MemoryBandwidth',
|
||||
'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory',
|
||||
'Null', 'NULL',
|
||||
'NextEthernetAddr']
|
||||
'NextEthernetAddr',
|
||||
'Port', 'VectorPort']
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ from MemObject import MemObject
|
|||
|
||||
class Bridge(MemObject):
|
||||
type = 'Bridge'
|
||||
side_a = Port('Side A port')
|
||||
side_b = Port('Side B port')
|
||||
queue_size_a = Param.Int(16, "The number of requests to buffer")
|
||||
queue_size_b = Param.Int(16, "The number of requests to buffer")
|
||||
delay = Param.Latency('0ns', "The latency of this bridge")
|
||||
|
|
|
@ -3,4 +3,5 @@ from MemObject import MemObject
|
|||
|
||||
class Bus(MemObject):
|
||||
type = 'Bus'
|
||||
port = VectorPort("vector port for connecting devices")
|
||||
bus_id = Param.Int(0, "blah")
|
||||
|
|
|
@ -4,6 +4,7 @@ from MemObject import MemObject
|
|||
class PioDevice(MemObject):
|
||||
type = 'PioDevice'
|
||||
abstract = True
|
||||
pio = Port("Programmed I/O port")
|
||||
platform = Param.Platform(Parent.any, "Platform this device is part of")
|
||||
system = Param.System(Parent.any, "System this device is part of")
|
||||
|
||||
|
@ -16,3 +17,4 @@ class BasicPioDevice(PioDevice):
|
|||
class DmaDevice(PioDevice):
|
||||
type = 'DmaDevice'
|
||||
abstract = True
|
||||
dma = Port("DMA port")
|
||||
|
|
|
@ -3,6 +3,7 @@ from MemObject import *
|
|||
|
||||
class PhysicalMemory(MemObject):
|
||||
type = 'PhysicalMemory'
|
||||
port = Port("the access port")
|
||||
range = Param.AddrRange("Device Address")
|
||||
file = Param.String('', "memory mapped file")
|
||||
latency = Param.Latency(Parent.clock, "latency of an access")
|
||||
|
|
|
@ -33,17 +33,14 @@
|
|||
#include "base/inifile.hh"
|
||||
#include "base/misc.hh"
|
||||
#include "sim/builder.hh"
|
||||
#include "sim/configfile.hh"
|
||||
#include "sim/config_node.hh"
|
||||
#include "sim/host.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
#include "sim/root.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
SimObjectBuilder::SimObjectBuilder(ConfigNode *_configNode)
|
||||
: ParamContext(_configNode->getPath(), NoAutoInit),
|
||||
configNode(_configNode)
|
||||
SimObjectBuilder::SimObjectBuilder(const std::string &_iniSection)
|
||||
: ParamContext(_iniSection, NoAutoInit)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -78,8 +75,7 @@ SimObjectBuilder::parseParams(IniFile &iniFile)
|
|||
void
|
||||
SimObjectBuilder::printErrorProlog(ostream &os)
|
||||
{
|
||||
ccprintf(os, "Error creating object '%s' of type '%s':\n",
|
||||
iniSection, configNode->getType());
|
||||
ccprintf(os, "Error creating object '%s':\n", iniSection);
|
||||
}
|
||||
|
||||
|
||||
|
@ -112,9 +108,13 @@ SimObjectClass::SimObjectClass(const string &className, CreateFunc createFunc)
|
|||
//
|
||||
//
|
||||
SimObject *
|
||||
SimObjectClass::createObject(IniFile &configDB, ConfigNode *configNode)
|
||||
SimObjectClass::createObject(IniFile &configDB, const std::string &iniSection)
|
||||
{
|
||||
const string &type = configNode->getType();
|
||||
string type;
|
||||
if (!configDB.find(iniSection, "type", type)) {
|
||||
// no C++ type associated with this object
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// look up className to get appropriate createFunc
|
||||
if (classMap->find(type) == classMap->end())
|
||||
|
@ -125,7 +125,7 @@ SimObjectClass::createObject(IniFile &configDB, ConfigNode *configNode)
|
|||
|
||||
// call createFunc with config hierarchy node to get object
|
||||
// builder instance (context with parameters for object creation)
|
||||
SimObjectBuilder *objectBuilder = (*createFunc)(configNode);
|
||||
SimObjectBuilder *objectBuilder = (*createFunc)(iniSection);
|
||||
|
||||
assert(objectBuilder != NULL);
|
||||
|
||||
|
@ -166,7 +166,7 @@ SimObjectClass::describeAllClasses(ostream &os)
|
|||
os << "[" << className << "]\n";
|
||||
|
||||
// create dummy object builder just to instantiate parameters
|
||||
SimObjectBuilder *objectBuilder = (*createFunc)(NULL);
|
||||
SimObjectBuilder *objectBuilder = (*createFunc)("");
|
||||
|
||||
// now get the object builder to describe ite params
|
||||
objectBuilder->describeParams(os);
|
||||
|
|
|
@ -55,14 +55,8 @@ class SimObject;
|
|||
//
|
||||
class SimObjectBuilder : public ParamContext
|
||||
{
|
||||
private:
|
||||
// The corresponding node in the configuration hierarchy.
|
||||
// (optional: may be null if the created object is not in the
|
||||
// hierarchy)
|
||||
ConfigNode *configNode;
|
||||
|
||||
public:
|
||||
SimObjectBuilder(ConfigNode *_configNode);
|
||||
SimObjectBuilder(const std::string &_iniSection);
|
||||
|
||||
virtual ~SimObjectBuilder();
|
||||
|
||||
|
@ -77,9 +71,6 @@ class SimObjectBuilder : public ParamContext
|
|||
// configuration hierarchy node label and position)
|
||||
virtual const std::string &getInstanceName() { return iniSection; }
|
||||
|
||||
// return the configuration hierarchy node for this context.
|
||||
virtual ConfigNode *getConfigNode() { return configNode; }
|
||||
|
||||
// Create the actual SimObject corresponding to the parameter
|
||||
// values in this context. This function is overridden in derived
|
||||
// classes to call a specific constructor for a particular
|
||||
|
@ -125,7 +116,7 @@ class SimObjectClass
|
|||
// for the object (specified by the second string argument), and
|
||||
// an optional config hierarchy node (specified by the third
|
||||
// argument). A pointer to the new SimObjectBuilder is returned.
|
||||
typedef SimObjectBuilder *(*CreateFunc)(ConfigNode *configNode);
|
||||
typedef SimObjectBuilder *(*CreateFunc)(const std::string &iniSection);
|
||||
|
||||
static std::map<std::string,CreateFunc> *classMap;
|
||||
|
||||
|
@ -137,7 +128,8 @@ class SimObjectClass
|
|||
|
||||
// create SimObject given name of class and pointer to
|
||||
// configuration hierarchy node
|
||||
static SimObject *createObject(IniFile &configDB, ConfigNode *configNode);
|
||||
static SimObject *createObject(IniFile &configDB,
|
||||
const std::string &iniSection);
|
||||
|
||||
// print descriptions of all parameters registered with all
|
||||
// SimObject classes
|
||||
|
@ -156,15 +148,15 @@ class OBJ_CLASS##Builder : public SimObjectBuilder \
|
|||
|
||||
#define END_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \
|
||||
\
|
||||
OBJ_CLASS##Builder(ConfigNode *configNode); \
|
||||
OBJ_CLASS##Builder(const std::string &iniSection); \
|
||||
virtual ~OBJ_CLASS##Builder() {} \
|
||||
\
|
||||
OBJ_CLASS *create(); \
|
||||
};
|
||||
|
||||
#define BEGIN_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
|
||||
OBJ_CLASS##Builder::OBJ_CLASS##Builder(ConfigNode *configNode) \
|
||||
: SimObjectBuilder(configNode),
|
||||
OBJ_CLASS##Builder::OBJ_CLASS##Builder(const std::string &iSec) \
|
||||
: SimObjectBuilder(iSec),
|
||||
|
||||
|
||||
#define END_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
|
||||
|
@ -176,9 +168,9 @@ OBJ_CLASS *OBJ_CLASS##Builder::create()
|
|||
|
||||
#define REGISTER_SIM_OBJECT(CLASS_NAME, OBJ_CLASS) \
|
||||
SimObjectBuilder * \
|
||||
new##OBJ_CLASS##Builder(ConfigNode *configNode) \
|
||||
new##OBJ_CLASS##Builder(const std::string &iniSection) \
|
||||
{ \
|
||||
return new OBJ_CLASS##Builder(configNode); \
|
||||
return new OBJ_CLASS##Builder(iniSection); \
|
||||
} \
|
||||
\
|
||||
SimObjectClass the##OBJ_CLASS##Class(CLASS_NAME, \
|
||||
|
|
115
src/sim/main.cc
115
src/sim/main.cc
|
@ -57,9 +57,10 @@
|
|||
#include "base/time.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/smt.hh"
|
||||
#include "mem/mem_object.hh"
|
||||
#include "mem/port.hh"
|
||||
#include "sim/async.hh"
|
||||
#include "sim/builder.hh"
|
||||
#include "sim/configfile.hh"
|
||||
#include "sim/host.hh"
|
||||
#include "sim/sim_events.hh"
|
||||
#include "sim/sim_exit.hh"
|
||||
|
@ -296,26 +297,109 @@ main(int argc, char **argv)
|
|||
Py_Finalize();
|
||||
}
|
||||
|
||||
IniFile inifile;
|
||||
|
||||
/// Initialize C++ configuration. Exported to Python via SWIG; invoked
|
||||
/// from m5.instantiate().
|
||||
void
|
||||
initialize()
|
||||
SimObject *
|
||||
createSimObject(const string &name)
|
||||
{
|
||||
return SimObjectClass::createObject(inifile, name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pointer to the Python function that maps names to SimObjects.
|
||||
*/
|
||||
PyObject *resolveFunc = NULL;
|
||||
|
||||
/**
|
||||
* Convert a pointer to the Python object that SWIG wraps around a C++
|
||||
* SimObject pointer back to the actual C++ pointer. See main.i.
|
||||
*/
|
||||
extern "C" SimObject *convertSwigSimObjectPtr(PyObject *);
|
||||
|
||||
|
||||
SimObject *
|
||||
resolveSimObject(const string &name)
|
||||
{
|
||||
PyObject *pyPtr = PyEval_CallFunction(resolveFunc, "(s)", name.c_str());
|
||||
if (pyPtr == NULL) {
|
||||
PyErr_Print();
|
||||
panic("resolveSimObject: failure on call to Python for %s", name);
|
||||
}
|
||||
|
||||
SimObject *simObj = convertSwigSimObjectPtr(pyPtr);
|
||||
if (simObj == NULL)
|
||||
panic("resolveSimObject: failure on pointer conversion for %s", name);
|
||||
|
||||
return simObj;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load config.ini into C++ database. Exported to Python via SWIG;
|
||||
* invoked from m5.instantiate().
|
||||
*/
|
||||
void
|
||||
loadIniFile(PyObject *_resolveFunc)
|
||||
{
|
||||
resolveFunc = _resolveFunc;
|
||||
configStream = simout.find("config.out");
|
||||
|
||||
// The configuration database is now complete; start processing it.
|
||||
IniFile inifile;
|
||||
inifile.load("config.ini");
|
||||
|
||||
// Initialize statistics database
|
||||
Stats::InitSimStats();
|
||||
}
|
||||
|
||||
// Now process the configuration hierarchy and create the SimObjects.
|
||||
ConfigHierarchy configHierarchy(inifile);
|
||||
configHierarchy.build();
|
||||
configHierarchy.createSimObjects();
|
||||
|
||||
/**
|
||||
* Look up a MemObject port. Helper function for connectPorts().
|
||||
*/
|
||||
Port *
|
||||
lookupPort(SimObject *so, const std::string &name, int i)
|
||||
{
|
||||
MemObject *mo = dynamic_cast<MemObject *>(so);
|
||||
if (mo == NULL) {
|
||||
warn("error casting SimObject %s to MemObject", so->name());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Port *p = mo->getPort(name, i);
|
||||
if (p == NULL)
|
||||
warn("error looking up port %s on object %s", name, so->name());
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Connect the described MemObject ports. Called from Python via SWIG.
|
||||
*/
|
||||
int
|
||||
connectPorts(SimObject *o1, const std::string &name1, int i1,
|
||||
SimObject *o2, const std::string &name2, int i2)
|
||||
{
|
||||
Port *p1 = lookupPort(o1, name1, i1);
|
||||
Port *p2 = lookupPort(o2, name2, i2);
|
||||
|
||||
if (p1 == NULL || p2 == NULL) {
|
||||
warn("connectPorts: port lookup error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
p1->setPeer(p2);
|
||||
p2->setPeer(p1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do final initialization steps after object construction but before
|
||||
* start of simulation.
|
||||
*/
|
||||
void
|
||||
finalInit()
|
||||
{
|
||||
// Parse and check all non-config-hierarchy parameters.
|
||||
ParamContext::parseAllContexts(inifile);
|
||||
ParamContext::checkAllContexts();
|
||||
|
@ -323,20 +407,13 @@ initialize()
|
|||
// Echo all parameter settings to stats file as well.
|
||||
ParamContext::showAllContexts(*configStream);
|
||||
|
||||
// Any objects that can't connect themselves until after construction should
|
||||
// do so now
|
||||
SimObject::connectAll();
|
||||
|
||||
// Do a second pass to finish initializing the sim objects
|
||||
SimObject::initAll();
|
||||
|
||||
// Restore checkpointed state, if any.
|
||||
#if 0
|
||||
configHierarchy.unserializeSimObjects();
|
||||
|
||||
// Done processing the configuration database.
|
||||
// Check for unreferenced entries.
|
||||
if (inifile.printUnreferenced())
|
||||
panic("unreferenced sections/entries in the intermediate ini file");
|
||||
#endif
|
||||
|
||||
SimObject::regAllStats();
|
||||
|
||||
|
|
|
@ -39,8 +39,6 @@
|
|||
#include "base/range.hh"
|
||||
#include "base/str.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "sim/config_node.hh"
|
||||
#include "sim/configfile.hh"
|
||||
#include "sim/param.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
|
@ -521,7 +519,9 @@ parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value)
|
|||
obj = NULL;
|
||||
}
|
||||
else {
|
||||
obj = context->resolveSimObject(s);
|
||||
// defined in main.cc
|
||||
extern SimObject *resolveSimObject(const string &);
|
||||
obj = resolveSimObject(s);
|
||||
|
||||
if (obj == NULL)
|
||||
return false;
|
||||
|
@ -695,22 +695,6 @@ ParamContext::printErrorProlog(ostream &os)
|
|||
os << "Parameter error in section [" << iniSection << "]: " << endl;
|
||||
}
|
||||
|
||||
//
|
||||
// Resolve an object name to a SimObject pointer. The object will be
|
||||
// created as a side-effect if necessary. If the name contains a
|
||||
// colon (e.g., "iq:IQ"), then the object is local (invisible to
|
||||
// outside this context). If there is no colon, the name needs to be
|
||||
// resolved through the configuration hierarchy (only possible for
|
||||
// SimObjectBuilder objects, which return non-NULL for configNode()).
|
||||
//
|
||||
SimObject *
|
||||
ParamContext::resolveSimObject(const string &name)
|
||||
{
|
||||
ConfigNode *n = getConfigNode();
|
||||
return n ? n->resolveSimObject(name) : NULL;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// static method: call parseParams() on all registered contexts
|
||||
//
|
||||
|
|
|
@ -36,10 +36,10 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "sim/configfile.hh"
|
||||
#include "sim/startup.hh"
|
||||
|
||||
// forward decls
|
||||
class IniFile;
|
||||
class BaseParam;
|
||||
class SimObject;
|
||||
|
||||
|
@ -132,18 +132,10 @@ class ParamContext : protected StartupCallback
|
|||
// print context information for parameter error
|
||||
virtual void printErrorProlog(std::ostream &);
|
||||
|
||||
// resolve a SimObject name in this context to an object pointer.
|
||||
virtual SimObject *resolveSimObject(const std::string &name);
|
||||
|
||||
// generate the name for this instance of this context (used as a
|
||||
// prefix to create unique names in resolveSimObject()
|
||||
virtual const std::string &getInstanceName() { return iniSection; }
|
||||
|
||||
// return the configuration hierarchy node for this context. Bare
|
||||
// ParamContext objects have no corresponding node, so the default
|
||||
// implementation returns NULL.
|
||||
virtual ConfigNode *getConfigNode() { return NULL; }
|
||||
|
||||
// Parse all parameters registered with all ParamContext objects.
|
||||
static void parseAllContexts(IniFile &iniFile);
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
#include "base/output.hh"
|
||||
#include "base/str.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "sim/config_node.hh"
|
||||
#include "sim/eventq.hh"
|
||||
#include "sim/param.hh"
|
||||
#include "sim/serialize.hh"
|
||||
|
@ -442,9 +441,8 @@ Serializable::create(Checkpoint *cp, const std::string §ion)
|
|||
}
|
||||
|
||||
|
||||
Checkpoint::Checkpoint(const std::string &cpt_dir, const std::string &path,
|
||||
const ConfigNode *_configNode)
|
||||
: db(new IniFile), basePath(path), configNode(_configNode), cptDir(cpt_dir)
|
||||
Checkpoint::Checkpoint(const std::string &cpt_dir, const std::string &path)
|
||||
: db(new IniFile), basePath(path), cptDir(cpt_dir)
|
||||
{
|
||||
string filename = cpt_dir + "/" + Checkpoint::baseFilename;
|
||||
if (!db->load(filename)) {
|
||||
|
@ -470,9 +468,6 @@ Checkpoint::findObj(const std::string §ion, const std::string &entry,
|
|||
if (!db->find(section, entry, path))
|
||||
return false;
|
||||
|
||||
if ((value = configNode->resolveSimObject(path)) != NULL)
|
||||
return true;
|
||||
|
||||
if ((value = objMap[path]) != NULL)
|
||||
return true;
|
||||
|
||||
|
|
|
@ -42,8 +42,8 @@
|
|||
#include <map>
|
||||
|
||||
#include "sim/host.hh"
|
||||
#include "sim/configfile.hh"
|
||||
|
||||
class IniFile;
|
||||
class Serializable;
|
||||
class Checkpoint;
|
||||
|
||||
|
@ -177,7 +177,7 @@ class SerializableClass
|
|||
// an optional config hierarchy node (specified by the third
|
||||
// argument). A pointer to the new SerializableBuilder is returned.
|
||||
typedef Serializable *(*CreateFunc)(Checkpoint *cp,
|
||||
const std::string §ion);
|
||||
const std::string §ion);
|
||||
|
||||
static std::map<std::string,CreateFunc> *classMap;
|
||||
|
||||
|
@ -191,7 +191,7 @@ class SerializableClass
|
|||
// create Serializable given name of class and pointer to
|
||||
// configuration hierarchy node
|
||||
static Serializable *createObject(Checkpoint *cp,
|
||||
const std::string §ion);
|
||||
const std::string §ion);
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -209,12 +209,10 @@ class Checkpoint
|
|||
|
||||
IniFile *db;
|
||||
const std::string basePath;
|
||||
const ConfigNode *configNode;
|
||||
std::map<std::string, Serializable*> objMap;
|
||||
|
||||
public:
|
||||
Checkpoint(const std::string &cpt_dir, const std::string &path,
|
||||
const ConfigNode *_configNode);
|
||||
Checkpoint(const std::string &cpt_dir, const std::string &path);
|
||||
|
||||
const std::string cptDir;
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include "base/trace.hh"
|
||||
#include "base/stats/events.hh"
|
||||
#include "base/serializer.hh"
|
||||
#include "sim/configfile.hh"
|
||||
#include "sim/host.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
#include "sim/stats.hh"
|
||||
|
|
Loading…
Reference in a new issue