diff options
author | Gabe Black <gblack@eecs.umich.edu> | 2009-08-17 00:21:57 -0700 |
---|---|---|
committer | Gabe Black <gblack@eecs.umich.edu> | 2009-08-17 00:21:57 -0700 |
commit | a43ae579dd3128a0ced2238532f26d99db197361 (patch) | |
tree | 271a90c0fdfde8b58180ee494c528a3fbec57588 /src | |
parent | 32c8514b450a7dda77a3963d00642fcc5de658da (diff) | |
parent | a6b39c07d9d03955382a0e930b363c6e6fd4b942 (diff) | |
download | gem5-a43ae579dd3128a0ced2238532f26d99db197361.tar.xz |
Merge with head.
Diffstat (limited to 'src')
20 files changed, 543 insertions, 106 deletions
diff --git a/src/mem/protocol/MOESI_CMP_directory-dir.sm b/src/mem/protocol/MOESI_CMP_directory-dir.sm index edd67707e..8d8ee7f8a 100644 --- a/src/mem/protocol/MOESI_CMP_directory-dir.sm +++ b/src/mem/protocol/MOESI_CMP_directory-dir.sm @@ -101,7 +101,7 @@ machine(Directory, "Directory protocol") } structure(TBE, desc="...") { - Address address, desc="Address for this entry"; + Address PhysicalAddress, desc="Physical address for this entry"; int Len, desc="Length of request"; DataBlock DataBlk, desc="DataBlk"; MachineID Requestor, desc="original requestor"; @@ -245,9 +245,9 @@ machine(Directory, "Directory protocol") } else if (in_msg.Type == CoherenceRequestType:PUTO_SHARERS) { trigger(Event:PUTO_SHARERS, in_msg.Address); } else if (in_msg.Type == CoherenceRequestType:DMA_READ) { - trigger(Event:DMA_READ, in_msg.Address); + trigger(Event:DMA_READ, makeLineAddress(in_msg.Address)); } else if (in_msg.Type == CoherenceRequestType:DMA_WRITE) { - trigger(Event:DMA_WRITE, in_msg.Address); + trigger(Event:DMA_WRITE, makeLineAddress(in_msg.Address)); } else { error("Invalid message"); } @@ -527,12 +527,15 @@ machine(Directory, "Directory protocol") } action(l_writeDMADataToMemoryFromTBE, "\ll", desc="Write data from a DMA_WRITE to memory") { - directory[address].DataBlk.copyPartial(TBEs[address].DataBlk, addressOffset(address), TBEs[address].Len); + directory[address].DataBlk.copyPartial(TBEs[address].DataBlk, + addressOffset(TBEs[address].PhysicalAddress), + TBEs[address].Len); } action(v_allocateTBE, "v", desc="Allocate TBE entry") { peek (requestQueue_in, RequestMsg) { TBEs.allocate(address); + TBEs[address].PhysicalAddress := in_msg.Address; TBEs[address].Len := in_msg.Len; TBEs[address].DataBlk := in_msg.DataBlk; TBEs[address].Requestor := in_msg.Requestor; @@ -695,7 +698,7 @@ machine(Directory, "Directory protocol") } - transition({MM, MO, MI, MIS, OS, OSS}, {GETS, GETX, PUTO, PUTO_SHARERS, PUTX, DMA_READ}) { + transition({MM, MO, MI, MIS, OS, OSS, XI_M, XI_U, OI_D}, {GETS, GETX, PUTO, PUTO_SHARERS, PUTX, DMA_READ, DMA_WRITE}) { zz_recycleRequest; } @@ -710,7 +713,7 @@ machine(Directory, "Directory protocol") j_popIncomingUnblockQueue; } - transition({IS, SS, OO}, {GETX, PUTO, PUTO_SHARERS, PUTX, DMA_READ}) { + transition({IS, SS, OO}, {GETX, PUTO, PUTO_SHARERS, PUTX, DMA_READ, DMA_WRITE}) { zz_recycleRequest; } diff --git a/src/mem/protocol/MOESI_CMP_directory-dma.sm b/src/mem/protocol/MOESI_CMP_directory-dma.sm index 74246c730..ae86e24da 100644 --- a/src/mem/protocol/MOESI_CMP_directory-dma.sm +++ b/src/mem/protocol/MOESI_CMP_directory-dma.sm @@ -83,9 +83,9 @@ machine(DMA, "DMA Controller") if (dmaRequestQueue_in.isReady()) { peek(dmaRequestQueue_in, SequencerMsg) { if (in_msg.Type == SequencerRequestType:LD ) { - trigger(Event:ReadRequest, in_msg.PhysicalAddress); + trigger(Event:ReadRequest, in_msg.LineAddress); } else if (in_msg.Type == SequencerRequestType:ST) { - trigger(Event:WriteRequest, in_msg.PhysicalAddress); + trigger(Event:WriteRequest, in_msg.LineAddress); } else { error("Invalid request type"); } @@ -97,11 +97,12 @@ machine(DMA, "DMA Controller") if (dmaResponseQueue_in.isReady()) { peek( dmaResponseQueue_in, ResponseMsg) { if (in_msg.Type == CoherenceResponseType:DMA_ACK) { - trigger(Event:DMA_Ack, in_msg.Address); - } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) { - trigger(Event:Data, in_msg.Address); + trigger(Event:DMA_Ack, makeLineAddress(in_msg.Address)); + } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE || + in_msg.Type == CoherenceResponseType:DATA) { + trigger(Event:Data, makeLineAddress(in_msg.Address)); } else if (in_msg.Type == CoherenceResponseType:ACK) { - trigger(Event:Inv_Ack, in_msg.Address); + trigger(Event:Inv_Ack, makeLineAddress(in_msg.Address)); } else { error("Invalid response type"); } @@ -125,7 +126,7 @@ machine(DMA, "DMA Controller") action(s_sendReadRequest, "s", desc="Send a DMA read request to memory") { peek(dmaRequestQueue_in, SequencerMsg) { enqueue(reqToDirectory_out, RequestMsg, latency=request_latency) { - out_msg.Address := address; + out_msg.Address := in_msg.PhysicalAddress; out_msg.Type := CoherenceRequestType:DMA_READ; out_msg.DataBlk := in_msg.DataBlk; out_msg.Len := in_msg.Len; @@ -139,7 +140,7 @@ machine(DMA, "DMA Controller") action(s_sendWriteRequest, "\s", desc="Send a DMA write request to memory") { peek(dmaRequestQueue_in, SequencerMsg) { enqueue(reqToDirectory_out, RequestMsg, latency=request_latency) { - out_msg.Address := address; + out_msg.Address := in_msg.PhysicalAddress; out_msg.Type := CoherenceRequestType:DMA_WRITE; out_msg.DataBlk := in_msg.DataBlk; out_msg.Len := in_msg.Len; diff --git a/src/mem/protocol/MOESI_CMP_token-L2cache.sm b/src/mem/protocol/MOESI_CMP_token-L2cache.sm index 21fbf0b95..0a58ed5cf 100644 --- a/src/mem/protocol/MOESI_CMP_token-L2cache.sm +++ b/src/mem/protocol/MOESI_CMP_token-L2cache.sm @@ -916,7 +916,7 @@ machine(L2Cache, "Token protocol") { action(uu_profileMiss, "\u", desc="Profile the demand miss") { peek(L1requestNetwork_in, RequestMsg) { // AccessModeType not implemented - profile_L2Cache_miss(convertToGenericType(in_msg.Type), in_msg.AccessMode, MessageSizeTypeToInt(in_msg.MessageSize), in_msg.Prefetch, machineIDToNodeID(in_msg.Requestor)); + //profile_L2Cache_miss(convertToGenericType(in_msg.Type), in_msg.AccessMode, MessageSizeTypeToInt(in_msg.MessageSize), in_msg.Prefetch, machineIDToNodeID(in_msg.Requestor)); } } diff --git a/src/mem/protocol/MSI_MOSI_CMP_directory-L2cache.sm b/src/mem/protocol/MSI_MOSI_CMP_directory-L2cache.sm index d68efc819..9f85e3a8f 100644 --- a/src/mem/protocol/MSI_MOSI_CMP_directory-L2cache.sm +++ b/src/mem/protocol/MSI_MOSI_CMP_directory-L2cache.sm @@ -978,7 +978,7 @@ machine(L2Cache, "MOSI Directory L2 Cache CMP") { action(uu_profileMiss, "\u", desc="Profile the demand miss") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { - profile_L2Cache_miss(convertToGenericType(in_msg.Type), in_msg.AccessMode, MessageSizeTypeToInt(in_msg.MessageSize), in_msg.Prefetch, L1CacheMachIDToProcessorNum(in_msg.RequestorMachId)); + //profile_L2Cache_miss(convertToGenericType(in_msg.Type), in_msg.AccessMode, MessageSizeTypeToInt(in_msg.MessageSize), in_msg.Prefetch, L1CacheMachIDToProcessorNum(in_msg.RequestorMachId)); } } diff --git a/src/mem/protocol/RubySlicc_Util.sm b/src/mem/protocol/RubySlicc_Util.sm index b37725402..312682bd7 100644 --- a/src/mem/protocol/RubySlicc_Util.sm +++ b/src/mem/protocol/RubySlicc_Util.sm @@ -37,7 +37,6 @@ Time zero_time(); NodeID intToID(int nodenum); int IDToInt(NodeID id); int addressToInt(Address addr); -int MessageSizeTypeToInt(MessageSizeType size_type); bool multicast_retry(); int numberOfNodes(); int numberOfL1CachePerChip(); diff --git a/src/mem/ruby/config/cfg.rb b/src/mem/ruby/config/cfg.rb index ffc36dd67..445bb4885 100644 --- a/src/mem/ruby/config/cfg.rb +++ b/src/mem/ruby/config/cfg.rb @@ -11,7 +11,7 @@ end def assert(condition,message) unless condition - raise AssertionFailure, "Assertion failed: #{message}" + raise AssertionFailure, "\n\nAssertion failed: \n\n #{message}\n\n" end end @@ -309,7 +309,7 @@ class CacheController < NetPort cache.controller = self } - if !@@total_cache_controllers.has_key?(mach_type) + if !@@total_cache_controllers.key?(mach_type) @@total_cache_controllers[mach_type] = 0 end @version = @@total_cache_controllers[mach_type] @@ -631,7 +631,7 @@ class Network < LibRubyObject vec += " buffer_size "+buffer_size.to_s vec += " link_latency "+adaptive_routing.to_s vec += " on_chip_latency "+on_chip_latency.to_s - + vec += " control_msg_size "+control_msg_size.to_s end def printTopology() diff --git a/src/mem/ruby/config/defaults.rb b/src/mem/ruby/config/defaults.rb index 4723df505..384abd119 100644 --- a/src/mem/ruby/config/defaults.rb +++ b/src/mem/ruby/config/defaults.rb @@ -39,7 +39,7 @@ class Debug < LibRubyObject default_param :protocol_trace, Boolean, false # a string for filtering debugging output (for all g_debug vars see Debug.h) - default_param :filter_string, String, "" + default_param :filter_string, String, "none" # filters debugging messages based on priority (low, med, high) default_param :verbosity_string, String, "none" @@ -82,6 +82,8 @@ class Network < LibRubyObject # on chip latency default_param :on_chip_latency, Integer, 1 + + default_param :control_msg_size, Integer, 8 end class GarnetNetwork < Network diff --git a/src/mem/ruby/network/Network.cc b/src/mem/ruby/network/Network.cc index cb3507471..984ec7ca8 100644 --- a/src/mem/ruby/network/Network.cc +++ b/src/mem/ruby/network/Network.cc @@ -26,9 +26,44 @@ void Network::init(const vector<string> & argv) m_adaptive_routing = (argv[i+1]=="true"); else if (argv[i] == "link_latency") m_link_latency = atoi(argv[i+1].c_str()); - + else if (argv[i] == "control_msg_size") + m_control_msg_size = atoi(argv[i+1].c_str()); } + + m_data_msg_size = RubySystem::getBlockSizeBytes() + m_control_msg_size; + assert(m_virtual_networks != 0); assert(m_topology_ptr != NULL); -// printf ("HERE \n"); +} + +int Network::MessageSizeType_to_int(MessageSizeType size_type) +{ + switch(size_type) { + case MessageSizeType_Undefined: + ERROR_MSG("Can't convert Undefined MessageSizeType to integer"); + break; + case MessageSizeType_Control: + case MessageSizeType_Request_Control: + case MessageSizeType_Reissue_Control: + case MessageSizeType_Response_Control: + case MessageSizeType_Writeback_Control: + case MessageSizeType_Forwarded_Control: + case MessageSizeType_Invalidate_Control: + case MessageSizeType_Unblock_Control: + case MessageSizeType_Persistent_Control: + case MessageSizeType_Completion_Control: + return m_control_msg_size; + break; + case MessageSizeType_Data: + case MessageSizeType_Response_Data: + case MessageSizeType_ResponseLocal_Data: + case MessageSizeType_ResponseL2hit_Data: + case MessageSizeType_Writeback_Data: + return m_data_msg_size; + break; + default: + ERROR_MSG("Invalid range for type MessageSizeType"); + break; + } + return 0; } diff --git a/src/mem/ruby/network/Network.hh b/src/mem/ruby/network/Network.hh index 17fbaab22..e7c86b6b2 100644 --- a/src/mem/ruby/network/Network.hh +++ b/src/mem/ruby/network/Network.hh @@ -71,6 +71,8 @@ public: int getEndpointBandwidth() { return m_endpoint_bandwidth; } bool getAdaptiveRouting() {return m_adaptive_routing; } int getLinkLatency() { return m_link_latency; } + int MessageSizeType_to_int(MessageSizeType size_type); + // returns the queue requested for the given component virtual MessageBuffer* getToNetQueue(NodeID id, bool ordered, int netNumber) = 0; @@ -107,6 +109,8 @@ protected: Topology* m_topology_ptr; bool m_adaptive_routing; int m_link_latency; + int m_control_msg_size; + int m_data_msg_size; }; // Output operator declaration @@ -123,41 +127,4 @@ ostream& operator<<(ostream& out, const Network& obj) return out; } -// Code to map network message size types to an integer number of bytes -const int CONTROL_MESSAGE_SIZE = 8; -const int DATA_MESSAGE_SIZE = (RubySystem::getBlockSizeBytes()+8); - -extern inline -int MessageSizeType_to_int(MessageSizeType size_type) -{ - switch(size_type) { - case MessageSizeType_Undefined: - ERROR_MSG("Can't convert Undefined MessageSizeType to integer"); - break; - case MessageSizeType_Control: - case MessageSizeType_Request_Control: - case MessageSizeType_Reissue_Control: - case MessageSizeType_Response_Control: - case MessageSizeType_Writeback_Control: - case MessageSizeType_Forwarded_Control: - case MessageSizeType_Invalidate_Control: - case MessageSizeType_Unblock_Control: - case MessageSizeType_Persistent_Control: - case MessageSizeType_Completion_Control: - return CONTROL_MESSAGE_SIZE; - break; - case MessageSizeType_Data: - case MessageSizeType_Response_Data: - case MessageSizeType_ResponseLocal_Data: - case MessageSizeType_ResponseL2hit_Data: - case MessageSizeType_Writeback_Data: - return DATA_MESSAGE_SIZE; - break; - default: - ERROR_MSG("Invalid range for type MessageSizeType"); - break; - } - return 0; -} - #endif //NETWORK_H diff --git a/src/mem/ruby/network/garnet-fixed-pipeline/NetworkInterface_d.cc b/src/mem/ruby/network/garnet-fixed-pipeline/NetworkInterface_d.cc index f75997757..3377ffd1d 100644 --- a/src/mem/ruby/network/garnet-fixed-pipeline/NetworkInterface_d.cc +++ b/src/mem/ruby/network/garnet-fixed-pipeline/NetworkInterface_d.cc @@ -114,7 +114,7 @@ bool NetworkInterface_d::flitisizeMessage(MsgPtr msg_ptr, int vnet) NetDest net_msg_dest = net_msg_ptr->getInternalDestination(); Vector<NodeID> dest_nodes = net_msg_dest.getAllDest(); // gets all the destinations associated with this message. - int num_flits = (int) ceil((double) MessageSizeType_to_int(net_msg_ptr->getMessageSize())/m_net_ptr->getNetworkConfig()->getFlitSize() ); // Number of flits is dependent on the link bandwidth available. This is expressed in terms of bytes/cycle or the flit size + int num_flits = (int) ceil((double) m_net_ptr->MessageSizeType_to_int(net_msg_ptr->getMessageSize())/m_net_ptr->getNetworkConfig()->getFlitSize() ); // Number of flits is dependent on the link bandwidth available. This is expressed in terms of bytes/cycle or the flit size for(int ctr = 0; ctr < dest_nodes.size(); ctr++) // loop because we will be converting all multicast messages into unicast messages { diff --git a/src/mem/ruby/network/garnet-flexible-pipeline/NetworkInterface.cc b/src/mem/ruby/network/garnet-flexible-pipeline/NetworkInterface.cc index 119f064d3..597c942b7 100644 --- a/src/mem/ruby/network/garnet-flexible-pipeline/NetworkInterface.cc +++ b/src/mem/ruby/network/garnet-flexible-pipeline/NetworkInterface.cc @@ -109,7 +109,7 @@ bool NetworkInterface::flitisizeMessage(MsgPtr msg_ptr, int vnet) NetworkMessage *net_msg_ptr = dynamic_cast<NetworkMessage*>(msg_ptr.ref()); NetDest net_msg_dest = net_msg_ptr->getInternalDestination(); Vector<NodeID> dest_nodes = net_msg_dest.getAllDest(); // gets all the destinations associated with this message. - int num_flits = (int) ceil((double) MessageSizeType_to_int(net_msg_ptr->getMessageSize())/m_net_ptr->getNetworkConfig()->getFlitSize() ); // Number of flits is dependent on the link bandwidth available. This is expressed in terms of bytes/cycle or the flit size + int num_flits = (int) ceil((double) m_net_ptr->MessageSizeType_to_int(net_msg_ptr->getMessageSize())/m_net_ptr->getNetworkConfig()->getFlitSize() ); // Number of flits is dependent on the link bandwidth available. This is expressed in terms of bytes/cycle or the flit size for(int ctr = 0; ctr < dest_nodes.size(); ctr++) // loop because we will be converting all multicast messages into unicast messages { diff --git a/src/mem/ruby/network/simple/Switch.cc b/src/mem/ruby/network/simple/Switch.cc index e3420ddae..87021471f 100644 --- a/src/mem/ruby/network/simple/Switch.cc +++ b/src/mem/ruby/network/simple/Switch.cc @@ -169,7 +169,7 @@ void Switch::printStats(ostream& out) const int sum = message_counts[type].sum(); if (sum != 0) { out << " outgoing_messages_switch_" << m_switch_id << "_link_" << link << "_" << type - << ": " << sum << " " << sum * MessageSizeType_to_int(type) + << ": " << sum << " " << sum * (RubySystem::getNetwork()->MessageSizeType_to_int(type)) << " " << message_counts[type] << " base_latency: " << throttle_ptr->getLatency() << endl; } } diff --git a/src/mem/ruby/network/simple/Throttle.cc b/src/mem/ruby/network/simple/Throttle.cc index 64cb2a33a..89d61f267 100644 --- a/src/mem/ruby/network/simple/Throttle.cc +++ b/src/mem/ruby/network/simple/Throttle.cc @@ -275,8 +275,8 @@ int network_message_to_size(NetworkMessage* net_msg_ptr) // Artificially increase the size of broadcast messages if (BROADCAST_SCALING > 1) { if (net_msg_ptr->getDestination().isBroadcast()) { - return (MessageSizeType_to_int(net_msg_ptr->getMessageSize()) * MESSAGE_SIZE_MULTIPLIER * BROADCAST_SCALING); + return (RubySystem::getNetwork()->MessageSizeType_to_int(net_msg_ptr->getMessageSize()) * MESSAGE_SIZE_MULTIPLIER * BROADCAST_SCALING); } } - return (MessageSizeType_to_int(net_msg_ptr->getMessageSize()) * MESSAGE_SIZE_MULTIPLIER); + return (RubySystem::getNetwork()->MessageSizeType_to_int(net_msg_ptr->getMessageSize()) * MESSAGE_SIZE_MULTIPLIER); } diff --git a/src/mem/ruby/slicc_interface/RubySlicc_Util.hh b/src/mem/ruby/slicc_interface/RubySlicc_Util.hh index 0ea5df08b..3d4fa3e5c 100644 --- a/src/mem/ruby/slicc_interface/RubySlicc_Util.hh +++ b/src/mem/ruby/slicc_interface/RubySlicc_Util.hh @@ -106,11 +106,6 @@ extern inline int addressToInt(Address addr) return (int) addr.getLineAddress(); } -extern inline int MessageSizeTypeToInt(MessageSizeType size_type) -{ - return MessageSizeType_to_int(size_type); -} - extern inline bool long_enough_ago(Time event) { return ((get_time() - event) > 200); diff --git a/src/python/SConscript b/src/python/SConscript index a767545ec..bb892f376 100644 --- a/src/python/SConscript +++ b/src/python/SConscript @@ -53,9 +53,12 @@ PySource('m5', 'm5/ticks.py') PySource('m5', 'm5/trace.py') PySource('m5.util', 'm5/util/__init__.py') PySource('m5.util', 'm5/util/attrdict.py') +PySource('m5.util', 'm5/util/code_formatter.py') +PySource('m5.util', 'm5/util/grammar.py') PySource('m5.util', 'm5/util/jobfile.py') PySource('m5.util', 'm5/util/misc.py') PySource('m5.util', 'm5/util/multidict.py') +PySource('m5.util', 'm5/util/orderdict.py') SwigSource('m5.internal', 'swig/core.i') SwigSource('m5.internal', 'swig/debug.i') diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py index 733258acf..c3512cd0d 100644 --- a/src/python/m5/__init__.py +++ b/src/python/m5/__init__.py @@ -103,8 +103,11 @@ try: except ImportError: internal = None -import defines -build_env.update(defines.buildEnv) +try: + import defines + build_env.update(defines.buildEnv) +except ImportError: + defines = None if internal: defines.compileDate = internal.core.compileDate @@ -120,4 +123,8 @@ if internal: import SimObject import params -import objects + +try: + import objects +except ImportError: + objects = None diff --git a/src/python/m5/util/__init__.py b/src/python/m5/util/__init__.py index 5c4a066c6..3930c8b6f 100644 --- a/src/python/m5/util/__init__.py +++ b/src/python/m5/util/__init__.py @@ -27,8 +27,10 @@ # Authors: Nathan Binkert from attrdict import attrdict, optiondict +from code_formatter import code_formatter from misc import * from multidict import multidict +from orderdict import orderdict import jobfile def print_list(items, indent=4): diff --git a/src/python/m5/util/code_formatter.py b/src/python/m5/util/code_formatter.py new file mode 100644 index 000000000..919a6423b --- /dev/null +++ b/src/python/m5/util/code_formatter.py @@ -0,0 +1,311 @@ +# Copyright (c) 2006-2009 Nathan Binkert <nate@binkert.org> +# All rights reserved. +# +# 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. + +import inspect +import os +import re +import string + +class lookup(object): + def __init__(self, formatter, frame, *args, **kwargs): + self.frame = frame + self.formatter = formatter + self.dict = self.formatter._dict + self.args = args + self.kwargs = kwargs + self.locals = {} + + def __setitem__(self, item, val): + self.locals[item] = val + + def __getitem__(self, item): + if item in self.locals: + return self.locals[item] + + if item in self.kwargs: + return self.kwargs[item] + + if item == '__file__': + return self.frame.f_code.co_filename + + if item == '__line__': + return self.frame.f_lineno + + if item in self.dict: + return self.dict[item] + + if self.formatter.locals or self.formatter.globals: + if self.formatter.locals and item in self.frame.f_locals: + return self.frame.f_locals[item] + + if self.formatter.globals and item in self.frame.f_globals: + return self.frame.f_globals[item] + + if item in __builtins__: + return __builtins__[item] + + try: + item = int(item) + return self.args[item] + except ValueError: + pass + raise IndexError, "Could not find '%s'" % item + +class code_formatter_meta(type): + pattern = r""" + (?: + %(delim)s(?P<escaped>%(delim)s) | # escaped delimiter + ^(?P<indent>[ ]*)%(delim)s(?P<lone>%(ident)s)$ | # lone identifier + %(delim)s(?P<ident>%(ident)s) | # identifier + %(delim)s%(lb)s(?P<b_ident>%(ident)s)%(rb)s | # braced identifier + %(delim)s(?P<pos>%(pos)s) | # positional parameter + %(delim)s%(lb)s(?P<b_pos>%(pos)s)%(rb)s | # braced positional + %(delim)s%(ldb)s(?P<eval>.*?)%(rdb)s | # double braced expression + %(delim)s(?P<invalid>) # ill-formed delimiter exprs + ) + """ + def __init__(cls, name, bases, dct): + super(code_formatter_meta, cls).__init__(name, bases, dct) + if 'pattern' in dct: + pat = cls.pattern + else: + # tuple expansion to ensure strings are proper length + lb,rb = cls.braced + lb1,lb2,rb2,rb1 = cls.double_braced + pat = code_formatter_meta.pattern % { + 'delim' : re.escape(cls.delim), + 'ident' : cls.ident, + 'pos' : cls.pos, + 'lb' : re.escape(lb), + 'rb' : re.escape(rb), + 'ldb' : re.escape(lb1+lb2), + 'rdb' : re.escape(rb2+rb1), + } + cls.pattern = re.compile(pat, re.VERBOSE | re.DOTALL | re.MULTILINE) + +class code_formatter(object): + __metaclass__ = code_formatter_meta + + delim = r'$' + ident = r'[_A-z]\w*' + pos = r'[0-9]+' + braced = r'{}' + double_braced = r'{{}}' + + globals = True + locals = True + fix_newlines = True + def __init__(self, *args, **kwargs): + self._data = [] + self._dict = {} + self._indent_level = 0 + self._indent_spaces = 4 + self.globals = kwargs.pop('globals',type(self).globals) + self.locals = kwargs.pop('locals', type(self).locals) + self._fix_newlines = \ + kwargs.pop('fix_newlines', type(self).fix_newlines) + + if args: + self.__call__(args) + + def indent(self): + self._indent_level += self._indent_spaces + + def dedent(self): + assert self._indent_level >= self._indent_spaces + self._indent_level -= self._indent_spaces + + def fix(self, status): + previous = self._fix_newlines + self._fix_newlines = status + return previous + + def nofix(self): + previous = self._fix_newlines + self._fix_newlines = False + return previous + + def clear(): + self._data = [] + + def write(self, *args): + f = file(os.path.join(*args), "w") + for data in self._data: + f.write(data) + f.close() + + def __str__(self): + data = string.join(self._data, '') + self._data = [ data ] + return data + + def __getitem__(self, item): + return self._dict[item] + + def __setitem__(self, item, value): + self._dict[item] = value + + def __delitem__(self, item): + del self._dict[item] + + def __contains__(self, item): + return item in self._dict + + def __iadd__(self, data): + self.append(data) + + def append(self, data): + if isinstance(data, code_formatter): + self._data.extend(data._data) + else: + self._append(str(data)) + + def _append(self, data): + if not self._fix_newlines: + self._data.append(data) + return + + initial_newline = not self._data or self._data[-1] == '\n' + for line in data.splitlines(): + if line: + if self._indent_level: + self._data.append(' ' * self._indent_level) + self._data.append(line) + + if line or not initial_newline: + self._data.append('\n') + + initial_newline = False + + def insert_newline(self): + self._data.append('\n') + + def __call__(self, format, *args, **kwargs): + frame = inspect.currentframe().f_back + + l = lookup(self, frame, *args, **kwargs) + def convert(match): + ident = match.group('lone') + # check for a lone identifier + if ident: + indent = match.group('indent') # must be spaces + lone = '%s' % (l[ident], ) + + def indent_lines(gen): + for line in gen: + yield indent + yield line + return ''.join(indent_lines(lone.splitlines(True))) + + # check for an identifier, braced or not + ident = match.group('ident') or match.group('b_ident') + if ident is not None: + return '%s' % (l[ident], ) + + # check for a positional parameter, braced or not + pos = match.group('pos') or match.group('b_pos') + if pos is not None: + pos = int(pos) + if pos > len(args): + raise ValueError \ + ('Positional parameter #%d not found in pattern' % pos, + code_formatter.pattern) + return '%s' % (args[int(pos)], ) + + # check for a double braced expression + eval_expr = match.group('eval') + if eval_expr is not None: + result = eval(eval_expr, {}, l) + return '%s' % (result, ) + + # check for an escaped delimiter + if match.group('escaped') is not None: + return '$' + + # At this point, we have to match invalid + if match.group('invalid') is None: + # didn't match invalid! + raise ValueError('Unrecognized named group in pattern', + code_formatter.pattern) + + i = match.start('invalid') + if i == 0: + colno = 1 + lineno = 1 + else: + lines = format[:i].splitlines(True) + colno = i - reduce(lambda x,y: x+y, (len(z) for z in lines)) + lineno = len(lines) + + raise ValueError('Invalid format string: line %d, col %d' % + (lineno, colno)) + + d = code_formatter.pattern.sub(convert, format) + self._append(d) + +__all__ = [ "code_formatter" ] + +if __name__ == '__main__': + from code_formatter import code_formatter + f = code_formatter() + + class Foo(dict): + def __init__(self, **kwargs): + self.update(kwargs) + def __getattr__(self, attr): + return self[attr] + + x = "this is a test" + l = [ [Foo(x=[Foo(y=9)])] ] + + y = code_formatter() + y(''' +{ + this_is_a_test(); +} +''') + f(' $y') + f('''$__file__:$__line__ +{''') + f("${{', '.join(str(x) for x in xrange(4))}}") + f('${x}') + f('$x') + f.indent() + for i in xrange(5): + f('$x') + f('$i') + f('$0', "zero") + f('$1 $0', "zero", "one") + f('${0}', "he went") + f('${0}asdf', "he went") + f.dedent() + + f(''' + ${{l[0][0]["x"][0].y}} +} +''', 1, 9) + + print f, diff --git a/src/python/m5/util/grammar.py b/src/python/m5/util/grammar.py new file mode 100644 index 000000000..93c2c84c4 --- /dev/null +++ b/src/python/m5/util/grammar.py @@ -0,0 +1,119 @@ +# Copyright (c) 2006-2009 Nathan Binkert <nate@binkert.org> +# All rights reserved. +# +# 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. + +from ply import lex, yacc + +class TokenError(lex.LexError): + def __init__(self, msg, t): + super(TokenError, self).__init__(msg) + self.token = t + +class ParseError(yacc.YaccError): + def __init__(self, message, token=None): + super(ParseError, self).__init__(message) + self.token = token + +class Tokenizer(object): + def __init__(self, lexer, data): + if isinstance(data, basestring): + indata = [ data ] + elif isinstance(data, file): + indata = data.xreadlines() + else: + indata = data + + def _input(): + for i,line in enumerate(indata): + lexer.lineno = i + 1 + lexer.input(line) + while True: + tok = lexer.token() + if not tok: + break + yield tok + self.input = _input() + + def next(self): + return self.input.next() + + def __iter__(self): + return self + + def token(self): + try: + return self.next() + except StopIteration: + return None + +class Grammar(object): + def __init__(self, output=None, debug=False): + self.yacc_args = {} + self.yacc_args['debug'] = debug + + if output: + import os + + dir,tab = os.path.split(output) + if not tab.endswith('.py'): + raise AttributeError, 'The output file must end with .py' + self.yacc_args['outputdir'] = dir + self.yacc_args['tabmodule'] = tab[:-3] + + def t_error(self, t): + raise lex.LexError("Illegal character %s @ %d:%d" % \ + (`t.value[0]`, t.lineno, t.lexpos), `t.value[0]`) + + def p_error(self, t): + if t: + msg = "Syntax error at %d:%d\n>>%s<<" % \ + (t.lineno, t.lexpos + 1, t.value) + else: + msg = "Syntax error at end of input" + raise ParseError(msg, t) + + def __getattr__(self, attr): + if attr == 'parser': + import ply.yacc + parser = ply.yacc.yacc(module=self, **self.yacc_args) + self.parser = parser + return parser + + if attr == 'lexer': + import ply.lex + lexer = ply.lex.lex(module=self) + self.lexer = lexer + return lexer + + raise AttributeError, "'%s' object has no attribute '%s'" % \ + (self.__class__.__name__, attr) + + def parse(self, stmt, **kwargs): + self.lexer.lineno = 1 + result = self.parser.parse(lexer=Tokenizer(self.lexer, stmt), **kwargs) + self.parser.restart() + + return result + diff --git a/src/python/m5/util/orderdict.py b/src/python/m5/util/orderdict.py index 3f755d299..1ffbca87a 100644 --- a/src/python/m5/util/orderdict.py +++ b/src/python/m5/util/orderdict.py @@ -28,17 +28,20 @@ __all__ = [ 'orderdict' ] -class orderdict(dict): - def __init__(self, d = {}): - self._keys = d.keys() - super(orderdict, self).__init__(d) +from UserDict import DictMixin + +class orderdict(dict, DictMixin): + def __init__(self, *args, **kwargs): + if len(args) > 1: + raise TypeError("expected at most one argument, got %d" % \ + len(args)) + self._keys = [] + self.update(*args, **kwargs) def __setitem__(self, key, item): - super(orderdict, self).__setitem__(key, item) - if not hasattr(self, '_keys'): - self._keys = [key,] - if key not in self._keys: + if key not in self: self._keys.append(key) + super(orderdict, self).__setitem__(key, item) def __delitem__(self, key): super(orderdict, self).__delitem__(key) @@ -48,33 +51,23 @@ class orderdict(dict): super(orderdict, self).clear() self._keys = [] - def items(self): - for i in self._keys: - yield i, self[i] + def iterkeys(self): + for key in self._keys: + yield key - def keys(self): - return self._keys + def itervalues(self): + for key in self._keys: + yield self[key] - def popitem(self): - if len(self._keys) == 0: - raise KeyError('dictionary is empty') - else: - key = self._keys[-1] - val = self[key] - del self[key] - return key, val + def iteritems(self): + for key in self._keys: + yield key, self[key] - def setdefault(self, key, failobj = None): - super(orderdict, self).setdefault(key, failobj) - if key not in self._keys: - self._keys.append(key) - - def update(self, d): - for key in d.keys(): - if not self.has_key(key): - self._keys.append(key) - super(orderdict, self).update(d) + def keys(self): + return self._keys[:] def values(self): - for i in self._keys: - yield self[i] + return [ self[key] for key in self._keys ] + + def items(self): + return [ (self[key],key) for key in self._keys ] |