StateMachine.py revision 9102
111666Stushar@ece.gatech.edu# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 211666Stushar@ece.gatech.edu# Copyright (c) 2009 The Hewlett-Packard Development Company 311666Stushar@ece.gatech.edu# All rights reserved. 411666Stushar@ece.gatech.edu# 511666Stushar@ece.gatech.edu# Redistribution and use in source and binary forms, with or without 611666Stushar@ece.gatech.edu# modification, are permitted provided that the following conditions are 711666Stushar@ece.gatech.edu# met: redistributions of source code must retain the above copyright 811666Stushar@ece.gatech.edu# notice, this list of conditions and the following disclaimer; 911666Stushar@ece.gatech.edu# redistributions in binary form must reproduce the above copyright 1011666Stushar@ece.gatech.edu# notice, this list of conditions and the following disclaimer in the 1111666Stushar@ece.gatech.edu# documentation and/or other materials provided with the distribution; 1211666Stushar@ece.gatech.edu# neither the name of the copyright holders nor the names of its 1311666Stushar@ece.gatech.edu# contributors may be used to endorse or promote products derived from 1411666Stushar@ece.gatech.edu# this software without specific prior written permission. 1511666Stushar@ece.gatech.edu# 1611666Stushar@ece.gatech.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1711666Stushar@ece.gatech.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1811666Stushar@ece.gatech.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1911666Stushar@ece.gatech.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2011666Stushar@ece.gatech.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2111666Stushar@ece.gatech.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2211666Stushar@ece.gatech.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2311666Stushar@ece.gatech.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2411666Stushar@ece.gatech.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2511666Stushar@ece.gatech.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2611666Stushar@ece.gatech.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2711666Stushar@ece.gatech.edu 2811666Stushar@ece.gatech.edufrom m5.util import orderdict 2911666Stushar@ece.gatech.edu 3011666Stushar@ece.gatech.edufrom slicc.symbols.Symbol import Symbol 3111666Stushar@ece.gatech.edufrom slicc.symbols.Var import Var 3211666Stushar@ece.gatech.eduimport slicc.generate.html as html 3311666Stushar@ece.gatech.eduimport re 3411666Stushar@ece.gatech.edu 3511666Stushar@ece.gatech.edupython_class_map = {"int": "Int", 3611666Stushar@ece.gatech.edu "std::string": "String", 3711666Stushar@ece.gatech.edu "bool": "Bool", 3811666Stushar@ece.gatech.edu "CacheMemory": "RubyCache", 3911666Stushar@ece.gatech.edu "WireBuffer": "RubyWireBuffer", 4011666Stushar@ece.gatech.edu "Sequencer": "RubySequencer", 4111666Stushar@ece.gatech.edu "DirectoryMemory": "RubyDirectoryMemory", 4211666Stushar@ece.gatech.edu "MemoryControl": "MemoryControl", 4311666Stushar@ece.gatech.edu "DMASequencer": "DMASequencer" 4411666Stushar@ece.gatech.edu } 4511666Stushar@ece.gatech.edu 4611666Stushar@ece.gatech.educlass StateMachine(Symbol): 4711666Stushar@ece.gatech.edu def __init__(self, symtab, ident, location, pairs, config_parameters): 4811666Stushar@ece.gatech.edu super(StateMachine, self).__init__(symtab, ident, location, pairs) 4911666Stushar@ece.gatech.edu self.table = None 5011666Stushar@ece.gatech.edu self.config_parameters = config_parameters 5111666Stushar@ece.gatech.edu 5211666Stushar@ece.gatech.edu for param in config_parameters: 5311666Stushar@ece.gatech.edu if param.pointer: 5411666Stushar@ece.gatech.edu var = Var(symtab, param.name, location, param.type_ast.type, 5511666Stushar@ece.gatech.edu "(*m_%s_ptr)" % param.name, {}, self) 5611666Stushar@ece.gatech.edu else: 5711666Stushar@ece.gatech.edu var = Var(symtab, param.name, location, param.type_ast.type, 5811666Stushar@ece.gatech.edu "m_%s" % param.name, {}, self) 5911666Stushar@ece.gatech.edu self.symtab.registerSym(param.name, var) 6011666Stushar@ece.gatech.edu 6111666Stushar@ece.gatech.edu self.states = orderdict() 6211666Stushar@ece.gatech.edu self.events = orderdict() 6311666Stushar@ece.gatech.edu self.actions = orderdict() 6411666Stushar@ece.gatech.edu self.transitions = [] 6511666Stushar@ece.gatech.edu self.in_ports = [] 6611666Stushar@ece.gatech.edu self.functions = [] 6711666Stushar@ece.gatech.edu self.objects = [] 6811666Stushar@ece.gatech.edu self.TBEType = None 6911666Stushar@ece.gatech.edu self.EntryType = None 7011666Stushar@ece.gatech.edu 7111666Stushar@ece.gatech.edu self.message_buffer_names = [] 7211666Stushar@ece.gatech.edu 7311666Stushar@ece.gatech.edu def __repr__(self): 7411666Stushar@ece.gatech.edu return "[StateMachine: %s]" % self.ident 7511666Stushar@ece.gatech.edu 7611666Stushar@ece.gatech.edu def addState(self, state): 7711666Stushar@ece.gatech.edu assert self.table is None 7811666Stushar@ece.gatech.edu self.states[state.ident] = state 7911666Stushar@ece.gatech.edu 8011666Stushar@ece.gatech.edu def addEvent(self, event): 8111666Stushar@ece.gatech.edu assert self.table is None 8211666Stushar@ece.gatech.edu self.events[event.ident] = event 8311666Stushar@ece.gatech.edu 8411666Stushar@ece.gatech.edu def addAction(self, action): 8511666Stushar@ece.gatech.edu assert self.table is None 8611666Stushar@ece.gatech.edu 8711666Stushar@ece.gatech.edu # Check for duplicate action 8811666Stushar@ece.gatech.edu for other in self.actions.itervalues(): 8911666Stushar@ece.gatech.edu if action.ident == other.ident: 9011666Stushar@ece.gatech.edu action.warning("Duplicate action definition: %s" % action.ident) 9111666Stushar@ece.gatech.edu action.error("Duplicate action definition: %s" % action.ident) 9211666Stushar@ece.gatech.edu if action.short == other.short: 9311666Stushar@ece.gatech.edu other.warning("Duplicate action shorthand: %s" % other.ident) 9411666Stushar@ece.gatech.edu other.warning(" shorthand = %s" % other.short) 9511666Stushar@ece.gatech.edu action.warning("Duplicate action shorthand: %s" % action.ident) 9611666Stushar@ece.gatech.edu action.error(" shorthand = %s" % action.short) 9711666Stushar@ece.gatech.edu 9811666Stushar@ece.gatech.edu self.actions[action.ident] = action 9911666Stushar@ece.gatech.edu 10011666Stushar@ece.gatech.edu def addTransition(self, trans): 10111666Stushar@ece.gatech.edu assert self.table is None 10211666Stushar@ece.gatech.edu self.transitions.append(trans) 10311666Stushar@ece.gatech.edu 10411666Stushar@ece.gatech.edu def addInPort(self, var): 10511666Stushar@ece.gatech.edu self.in_ports.append(var) 10611666Stushar@ece.gatech.edu 10711666Stushar@ece.gatech.edu def addFunc(self, func): 10811666Stushar@ece.gatech.edu # register func in the symbol table 10911666Stushar@ece.gatech.edu self.symtab.registerSym(str(func), func) 11011666Stushar@ece.gatech.edu self.functions.append(func) 11111666Stushar@ece.gatech.edu 11211666Stushar@ece.gatech.edu def addObject(self, obj): 11311666Stushar@ece.gatech.edu self.objects.append(obj) 11411666Stushar@ece.gatech.edu 11511666Stushar@ece.gatech.edu def addType(self, type): 11611666Stushar@ece.gatech.edu type_ident = '%s' % type.c_ident 11711666Stushar@ece.gatech.edu 11811666Stushar@ece.gatech.edu if type_ident == "%s_TBE" %self.ident: 11911666Stushar@ece.gatech.edu if self.TBEType != None: 12011666Stushar@ece.gatech.edu self.error("Multiple Transaction Buffer types in a " \ 12111666Stushar@ece.gatech.edu "single machine."); 12211666Stushar@ece.gatech.edu self.TBEType = type 12311666Stushar@ece.gatech.edu 12411666Stushar@ece.gatech.edu elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 12511666Stushar@ece.gatech.edu if self.EntryType != None: 12611666Stushar@ece.gatech.edu self.error("Multiple AbstractCacheEntry types in a " \ 12711666Stushar@ece.gatech.edu "single machine."); 12811666Stushar@ece.gatech.edu self.EntryType = type 12911666Stushar@ece.gatech.edu 13011666Stushar@ece.gatech.edu # Needs to be called before accessing the table 13111666Stushar@ece.gatech.edu def buildTable(self): 13211666Stushar@ece.gatech.edu assert self.table is None 13311666Stushar@ece.gatech.edu 13411666Stushar@ece.gatech.edu table = {} 13511666Stushar@ece.gatech.edu 13611666Stushar@ece.gatech.edu for trans in self.transitions: 13711666Stushar@ece.gatech.edu # Track which actions we touch so we know if we use them 13811666Stushar@ece.gatech.edu # all -- really this should be done for all symbols as 13911666Stushar@ece.gatech.edu # part of the symbol table, then only trigger it for 14011666Stushar@ece.gatech.edu # Actions, States, Events, etc. 14111666Stushar@ece.gatech.edu 14211666Stushar@ece.gatech.edu for action in trans.actions: 14311666Stushar@ece.gatech.edu action.used = True 14411666Stushar@ece.gatech.edu 14511666Stushar@ece.gatech.edu index = (trans.state, trans.event) 14611666Stushar@ece.gatech.edu if index in table: 14711666Stushar@ece.gatech.edu table[index].warning("Duplicate transition: %s" % table[index]) 14811666Stushar@ece.gatech.edu trans.error("Duplicate transition: %s" % trans) 14911666Stushar@ece.gatech.edu table[index] = trans 15011666Stushar@ece.gatech.edu 15111666Stushar@ece.gatech.edu # Look at all actions to make sure we used them all 15211666Stushar@ece.gatech.edu for action in self.actions.itervalues(): 15311666Stushar@ece.gatech.edu if not action.used: 15411666Stushar@ece.gatech.edu error_msg = "Unused action: %s" % action.ident 15511666Stushar@ece.gatech.edu if "desc" in action: 15611666Stushar@ece.gatech.edu error_msg += ", " + action.desc 15711666Stushar@ece.gatech.edu action.warning(error_msg) 15811666Stushar@ece.gatech.edu self.table = table 15911666Stushar@ece.gatech.edu 16011666Stushar@ece.gatech.edu def writeCodeFiles(self, path): 16111666Stushar@ece.gatech.edu self.printControllerPython(path) 16211666Stushar@ece.gatech.edu self.printControllerHH(path) 16311666Stushar@ece.gatech.edu self.printControllerCC(path) 16411666Stushar@ece.gatech.edu self.printCSwitch(path) 16511666Stushar@ece.gatech.edu self.printCWakeup(path) 16611666Stushar@ece.gatech.edu self.printProfilerCC(path) 16711666Stushar@ece.gatech.edu self.printProfilerHH(path) 16811666Stushar@ece.gatech.edu self.printProfileDumperCC(path) 16911666Stushar@ece.gatech.edu self.printProfileDumperHH(path) 17011666Stushar@ece.gatech.edu 17111666Stushar@ece.gatech.edu def printControllerPython(self, path): 17211666Stushar@ece.gatech.edu code = self.symtab.codeFormatter() 17311666Stushar@ece.gatech.edu ident = self.ident 17411666Stushar@ece.gatech.edu py_ident = "%s_Controller" % ident 17511666Stushar@ece.gatech.edu c_ident = "%s_Controller" % self.ident 17611666Stushar@ece.gatech.edu code(''' 17711666Stushar@ece.gatech.edufrom m5.params import * 17811666Stushar@ece.gatech.edufrom m5.SimObject import SimObject 17911666Stushar@ece.gatech.edufrom Controller import RubyController 18011666Stushar@ece.gatech.edu 18111666Stushar@ece.gatech.educlass $py_ident(RubyController): 18211666Stushar@ece.gatech.edu type = '$py_ident' 18311666Stushar@ece.gatech.edu''') 18411666Stushar@ece.gatech.edu code.indent() 18511666Stushar@ece.gatech.edu for param in self.config_parameters: 18611666Stushar@ece.gatech.edu dflt_str = '' 18711666Stushar@ece.gatech.edu if param.default is not None: 18811666Stushar@ece.gatech.edu dflt_str = str(param.default) + ', ' 18911666Stushar@ece.gatech.edu if python_class_map.has_key(param.type_ast.type.c_ident): 19011666Stushar@ece.gatech.edu python_type = python_class_map[param.type_ast.type.c_ident] 19111666Stushar@ece.gatech.edu code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 19211666Stushar@ece.gatech.edu else: 19311666Stushar@ece.gatech.edu self.error("Unknown c++ to python class conversion for c++ " \ 19411666Stushar@ece.gatech.edu "type: '%s'. Please update the python_class_map " \ 19511666Stushar@ece.gatech.edu "in StateMachine.py", param.type_ast.type.c_ident) 19611666Stushar@ece.gatech.edu code.dedent() 19711666Stushar@ece.gatech.edu code.write(path, '%s.py' % py_ident) 19811666Stushar@ece.gatech.edu 19911666Stushar@ece.gatech.edu 20011666Stushar@ece.gatech.edu def printControllerHH(self, path): 20111666Stushar@ece.gatech.edu '''Output the method declarations for the class declaration''' 20211666Stushar@ece.gatech.edu code = self.symtab.codeFormatter() 20311666Stushar@ece.gatech.edu ident = self.ident 20411666Stushar@ece.gatech.edu c_ident = "%s_Controller" % self.ident 20511666Stushar@ece.gatech.edu 20611666Stushar@ece.gatech.edu self.message_buffer_names = [] 20711666Stushar@ece.gatech.edu 20811666Stushar@ece.gatech.edu code(''' 20911666Stushar@ece.gatech.edu/** \\file $c_ident.hh 21011666Stushar@ece.gatech.edu * 21111666Stushar@ece.gatech.edu * Auto generated C++ code started by $__file__:$__line__ 21211666Stushar@ece.gatech.edu * Created by slicc definition of Module "${{self.short}}" 21311666Stushar@ece.gatech.edu */ 21411666Stushar@ece.gatech.edu 21511666Stushar@ece.gatech.edu#ifndef __${ident}_CONTROLLER_HH__ 21611666Stushar@ece.gatech.edu#define __${ident}_CONTROLLER_HH__ 21711666Stushar@ece.gatech.edu 21811666Stushar@ece.gatech.edu#include <iostream> 21911666Stushar@ece.gatech.edu#include <sstream> 22011666Stushar@ece.gatech.edu#include <string> 22111666Stushar@ece.gatech.edu 22211666Stushar@ece.gatech.edu#include "mem/protocol/${ident}_ProfileDumper.hh" 22311666Stushar@ece.gatech.edu#include "mem/protocol/${ident}_Profiler.hh" 22411666Stushar@ece.gatech.edu#include "mem/protocol/TransitionResult.hh" 22511666Stushar@ece.gatech.edu#include "mem/protocol/Types.hh" 22611666Stushar@ece.gatech.edu#include "mem/ruby/common/Consumer.hh" 22711666Stushar@ece.gatech.edu#include "mem/ruby/common/Global.hh" 22811666Stushar@ece.gatech.edu#include "mem/ruby/slicc_interface/AbstractController.hh" 22911666Stushar@ece.gatech.edu#include "params/$c_ident.hh" 23011666Stushar@ece.gatech.edu''') 23111666Stushar@ece.gatech.edu 23211666Stushar@ece.gatech.edu seen_types = set() 23311666Stushar@ece.gatech.edu for var in self.objects: 23411666Stushar@ece.gatech.edu if var.type.ident not in seen_types and not var.type.isPrimitive: 23511666Stushar@ece.gatech.edu code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 23611666Stushar@ece.gatech.edu seen_types.add(var.type.ident) 23711666Stushar@ece.gatech.edu 23811666Stushar@ece.gatech.edu # for adding information to the protocol debug trace 23911666Stushar@ece.gatech.edu code(''' 24011666Stushar@ece.gatech.eduextern std::stringstream ${ident}_transitionComment; 24111666Stushar@ece.gatech.edu 242class $c_ident : public AbstractController 243{ 244// the coherence checker needs to call isBlockExclusive() and isBlockShared() 245// making the Chip a friend class is an easy way to do this for now 246 247public: 248 typedef ${c_ident}Params Params; 249 $c_ident(const Params *p); 250 static int getNumControllers(); 251 void init(); 252 MessageBuffer* getMandatoryQueue() const; 253 const int & getVersion() const; 254 const std::string toString() const; 255 const std::string getName() const; 256 void stallBuffer(MessageBuffer* buf, Address addr); 257 void wakeUpBuffers(Address addr); 258 void wakeUpAllBuffers(); 259 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; } 260 void print(std::ostream& out) const; 261 void printConfig(std::ostream& out) const; 262 void wakeup(); 263 void printStats(std::ostream& out) const; 264 void clearStats(); 265 void blockOnQueue(Address addr, MessageBuffer* port); 266 void unblock(Address addr); 267 void recordCacheTrace(int cntrl, CacheRecorder* tr); 268 Sequencer* getSequencer() const; 269 270private: 271''') 272 273 code.indent() 274 # added by SS 275 for param in self.config_parameters: 276 if param.pointer: 277 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 278 else: 279 code('${{param.type_ast.type}} m_${{param.ident}};') 280 281 code(''' 282int m_number_of_TBEs; 283 284TransitionResult doTransition(${ident}_Event event, 285''') 286 287 if self.EntryType != None: 288 code(''' 289 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 290''') 291 if self.TBEType != None: 292 code(''' 293 ${{self.TBEType.c_ident}}* m_tbe_ptr, 294''') 295 296 code(''' 297 const Address& addr); 298 299TransitionResult doTransitionWorker(${ident}_Event event, 300 ${ident}_State state, 301 ${ident}_State& next_state, 302''') 303 304 if self.TBEType != None: 305 code(''' 306 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 307''') 308 if self.EntryType != None: 309 code(''' 310 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 311''') 312 313 code(''' 314 const Address& addr); 315 316std::string m_name; 317int m_transitions_per_cycle; 318int m_buffer_size; 319int m_recycle_latency; 320std::map<std::string, std::string> m_cfg; 321NodeID m_version; 322Network* m_net_ptr; 323MachineID m_machineID; 324bool m_is_blocking; 325std::map<Address, MessageBuffer*> m_block_map; 326typedef std::vector<MessageBuffer*> MsgVecType; 327typedef std::map< Address, MsgVecType* > WaitingBufType; 328WaitingBufType m_waiting_buffers; 329int m_max_in_port_rank; 330int m_cur_in_port_rank; 331static ${ident}_ProfileDumper s_profileDumper; 332${ident}_Profiler m_profiler; 333static int m_num_controllers; 334 335// Internal functions 336''') 337 338 for func in self.functions: 339 proto = func.prototype 340 if proto: 341 code('$proto') 342 343 if self.EntryType != None: 344 code(''' 345 346// Set and Reset for cache_entry variable 347void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 348void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 349''') 350 351 if self.TBEType != None: 352 code(''' 353 354// Set and Reset for tbe variable 355void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 356void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 357''') 358 359 code(''' 360 361// Actions 362''') 363 if self.TBEType != None and self.EntryType != None: 364 for action in self.actions.itervalues(): 365 code('/** \\brief ${{action.desc}} */') 366 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 367 elif self.TBEType != None: 368 for action in self.actions.itervalues(): 369 code('/** \\brief ${{action.desc}} */') 370 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);') 371 elif self.EntryType != None: 372 for action in self.actions.itervalues(): 373 code('/** \\brief ${{action.desc}} */') 374 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 375 else: 376 for action in self.actions.itervalues(): 377 code('/** \\brief ${{action.desc}} */') 378 code('void ${{action.ident}}(const Address& addr);') 379 380 # the controller internal variables 381 code(''' 382 383// Objects 384''') 385 for var in self.objects: 386 th = var.get("template_hack", "") 387 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 388 389 if var.type.ident == "MessageBuffer": 390 self.message_buffer_names.append("m_%s_ptr" % var.c_ident) 391 392 code.dedent() 393 code('};') 394 code('#endif // __${ident}_CONTROLLER_H__') 395 code.write(path, '%s.hh' % c_ident) 396 397 def printControllerCC(self, path): 398 '''Output the actions for performing the actions''' 399 400 code = self.symtab.codeFormatter() 401 ident = self.ident 402 c_ident = "%s_Controller" % self.ident 403 404 code(''' 405/** \\file $c_ident.cc 406 * 407 * Auto generated C++ code started by $__file__:$__line__ 408 * Created by slicc definition of Module "${{self.short}}" 409 */ 410 411#include <sys/types.h> 412#include <unistd.h> 413 414#include <cassert> 415#include <sstream> 416#include <string> 417 418#include "base/compiler.hh" 419#include "base/cprintf.hh" 420#include "debug/RubyGenerated.hh" 421#include "debug/RubySlicc.hh" 422#include "mem/protocol/${ident}_Controller.hh" 423#include "mem/protocol/${ident}_Event.hh" 424#include "mem/protocol/${ident}_State.hh" 425#include "mem/protocol/Types.hh" 426#include "mem/ruby/common/Global.hh" 427#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 428#include "mem/ruby/system/System.hh" 429 430using namespace std; 431''') 432 433 # include object classes 434 seen_types = set() 435 for var in self.objects: 436 if var.type.ident not in seen_types and not var.type.isPrimitive: 437 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 438 seen_types.add(var.type.ident) 439 440 code(''' 441$c_ident * 442${c_ident}Params::create() 443{ 444 return new $c_ident(this); 445} 446 447int $c_ident::m_num_controllers = 0; 448${ident}_ProfileDumper $c_ident::s_profileDumper; 449 450// for adding information to the protocol debug trace 451stringstream ${ident}_transitionComment; 452#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 453 454/** \\brief constructor */ 455$c_ident::$c_ident(const Params *p) 456 : AbstractController(p) 457{ 458 m_version = p->version; 459 m_transitions_per_cycle = p->transitions_per_cycle; 460 m_buffer_size = p->buffer_size; 461 m_recycle_latency = p->recycle_latency; 462 m_number_of_TBEs = p->number_of_TBEs; 463 m_is_blocking = false; 464 m_name = "${ident}"; 465''') 466 # 467 # max_port_rank is used to size vectors and thus should be one plus the 468 # largest port rank 469 # 470 max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1 471 code(' m_max_in_port_rank = $max_port_rank;') 472 code.indent() 473 474 # 475 # After initializing the universal machine parameters, initialize the 476 # this machines config parameters. Also detemine if these configuration 477 # params include a sequencer. This information will be used later for 478 # contecting the sequencer back to the L1 cache controller. 479 # 480 contains_dma_sequencer = False 481 sequencers = [] 482 for param in self.config_parameters: 483 if param.name == "dma_sequencer": 484 contains_dma_sequencer = True 485 elif re.compile("sequencer").search(param.name): 486 sequencers.append(param.name) 487 if param.pointer: 488 code('m_${{param.name}}_ptr = p->${{param.name}};') 489 else: 490 code('m_${{param.name}} = p->${{param.name}};') 491 492 # 493 # For the l1 cache controller, add the special atomic support which 494 # includes passing the sequencer a pointer to the controller. 495 # 496 if self.ident == "L1Cache": 497 if not sequencers: 498 self.error("The L1Cache controller must include the sequencer " \ 499 "configuration parameter") 500 501 for seq in sequencers: 502 code(''' 503m_${{seq}}_ptr->setController(this); 504 ''') 505 506 else: 507 for seq in sequencers: 508 code(''' 509m_${{seq}}_ptr->setController(this); 510 ''') 511 512 # 513 # For the DMA controller, pass the sequencer a pointer to the 514 # controller. 515 # 516 if self.ident == "DMA": 517 if not contains_dma_sequencer: 518 self.error("The DMA controller must include the sequencer " \ 519 "configuration parameter") 520 521 code(''' 522m_dma_sequencer_ptr->setController(this); 523''') 524 525 code('m_num_controllers++;') 526 for var in self.objects: 527 if var.ident.find("mandatoryQueue") >= 0: 528 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();') 529 530 code.dedent() 531 code(''' 532} 533 534void 535$c_ident::init() 536{ 537 MachineType machine_type; 538 int base; 539 540 m_machineID.type = MachineType_${ident}; 541 m_machineID.num = m_version; 542 543 // initialize objects 544 m_profiler.setVersion(m_version); 545 s_profileDumper.registerProfiler(&m_profiler); 546 547''') 548 549 code.indent() 550 for var in self.objects: 551 vtype = var.type 552 vid = "m_%s_ptr" % var.c_ident 553 if "network" not in var: 554 # Not a network port object 555 if "primitive" in vtype: 556 code('$vid = new ${{vtype.c_ident}};') 557 if "default" in var: 558 code('(*$vid) = ${{var["default"]}};') 559 else: 560 # Normal Object 561 # added by SS 562 if "factory" in var: 563 code('$vid = ${{var["factory"]}};') 564 elif var.ident.find("mandatoryQueue") < 0: 565 th = var.get("template_hack", "") 566 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 567 568 args = "" 569 if "non_obj" not in vtype and not vtype.isEnumeration: 570 if expr.find("TBETable") >= 0: 571 args = "m_number_of_TBEs" 572 else: 573 args = var.get("constructor_hack", "") 574 575 code('$expr($args);') 576 577 code('assert($vid != NULL);') 578 579 if "default" in var: 580 code('*$vid = ${{var["default"]}}; // Object default') 581 elif "default" in vtype: 582 comment = "Type %s default" % vtype.ident 583 code('*$vid = ${{vtype["default"]}}; // $comment') 584 585 # Set ordering 586 if "ordered" in var and "trigger_queue" not in var: 587 # A buffer 588 code('$vid->setOrdering(${{var["ordered"]}});') 589 590 # Set randomization 591 if "random" in var: 592 # A buffer 593 code('$vid->setRandomization(${{var["random"]}});') 594 595 # Set Priority 596 if vtype.isBuffer and \ 597 "rank" in var and "trigger_queue" not in var: 598 code('$vid->setPriority(${{var["rank"]}});') 599 600 else: 601 # Network port object 602 network = var["network"] 603 ordered = var["ordered"] 604 vnet = var["virtual_network"] 605 vnet_type = var["vnet_type"] 606 607 assert var.machine is not None 608 code(''' 609machine_type = string_to_MachineType("${{var.machine.ident}}"); 610base = MachineType_base_number(machine_type); 611$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type"); 612''') 613 614 code('assert($vid != NULL);') 615 616 # Set ordering 617 if "ordered" in var: 618 # A buffer 619 code('$vid->setOrdering(${{var["ordered"]}});') 620 621 # Set randomization 622 if "random" in var: 623 # A buffer 624 code('$vid->setRandomization(${{var["random"]}});') 625 626 # Set Priority 627 if "rank" in var: 628 code('$vid->setPriority(${{var["rank"]}})') 629 630 # Set buffer size 631 if vtype.isBuffer: 632 code(''' 633if (m_buffer_size > 0) { 634 $vid->resize(m_buffer_size); 635} 636''') 637 638 # set description (may be overriden later by port def) 639 code(''' 640$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]"); 641 642''') 643 644 if vtype.isBuffer: 645 if "recycle_latency" in var: 646 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});') 647 else: 648 code('$vid->setRecycleLatency(m_recycle_latency);') 649 650 651 # Set the queue consumers 652 code() 653 for port in self.in_ports: 654 code('${{port.code}}.setConsumer(this);') 655 656 # Set the queue descriptions 657 code() 658 for port in self.in_ports: 659 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");') 660 661 # Initialize the transition profiling 662 code() 663 for trans in self.transitions: 664 # Figure out if we stall 665 stall = False 666 for action in trans.actions: 667 if action.ident == "z_stall": 668 stall = True 669 670 # Only possible if it is not a 'z' case 671 if not stall: 672 state = "%s_State_%s" % (self.ident, trans.state.ident) 673 event = "%s_Event_%s" % (self.ident, trans.event.ident) 674 code('m_profiler.possibleTransition($state, $event);') 675 676 code.dedent() 677 code('}') 678 679 has_mandatory_q = False 680 for port in self.in_ports: 681 if port.code.find("mandatoryQueue_ptr") >= 0: 682 has_mandatory_q = True 683 684 if has_mandatory_q: 685 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 686 else: 687 mq_ident = "NULL" 688 689 seq_ident = "NULL" 690 for param in self.config_parameters: 691 if param.name == "sequencer": 692 assert(param.pointer) 693 seq_ident = "m_%s_ptr" % param.name 694 695 code(''' 696int 697$c_ident::getNumControllers() 698{ 699 return m_num_controllers; 700} 701 702MessageBuffer* 703$c_ident::getMandatoryQueue() const 704{ 705 return $mq_ident; 706} 707 708Sequencer* 709$c_ident::getSequencer() const 710{ 711 return $seq_ident; 712} 713 714const int & 715$c_ident::getVersion() const 716{ 717 return m_version; 718} 719 720const string 721$c_ident::toString() const 722{ 723 return "$c_ident"; 724} 725 726const string 727$c_ident::getName() const 728{ 729 return m_name; 730} 731 732void 733$c_ident::stallBuffer(MessageBuffer* buf, Address addr) 734{ 735 if (m_waiting_buffers.count(addr) == 0) { 736 MsgVecType* msgVec = new MsgVecType; 737 msgVec->resize(m_max_in_port_rank, NULL); 738 m_waiting_buffers[addr] = msgVec; 739 } 740 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf; 741} 742 743void 744$c_ident::wakeUpBuffers(Address addr) 745{ 746 if (m_waiting_buffers.count(addr) > 0) { 747 // 748 // Wake up all possible lower rank (i.e. lower priority) buffers that could 749 // be waiting on this message. 750 // 751 for (int in_port_rank = m_cur_in_port_rank - 1; 752 in_port_rank >= 0; 753 in_port_rank--) { 754 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) { 755 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr); 756 } 757 } 758 delete m_waiting_buffers[addr]; 759 m_waiting_buffers.erase(addr); 760 } 761} 762 763void 764$c_ident::wakeUpAllBuffers() 765{ 766 // 767 // Wake up all possible buffers that could be waiting on any message. 768 // 769 770 std::vector<MsgVecType*> wokeUpMsgVecs; 771 772 if(m_waiting_buffers.size() > 0) { 773 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin(); 774 buf_iter != m_waiting_buffers.end(); 775 ++buf_iter) { 776 for (MsgVecType::iterator vec_iter = buf_iter->second->begin(); 777 vec_iter != buf_iter->second->end(); 778 ++vec_iter) { 779 if (*vec_iter != NULL) { 780 (*vec_iter)->reanalyzeAllMessages(); 781 } 782 } 783 wokeUpMsgVecs.push_back(buf_iter->second); 784 } 785 786 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin(); 787 wb_iter != wokeUpMsgVecs.end(); 788 ++wb_iter) { 789 delete (*wb_iter); 790 } 791 792 m_waiting_buffers.clear(); 793 } 794} 795 796void 797$c_ident::blockOnQueue(Address addr, MessageBuffer* port) 798{ 799 m_is_blocking = true; 800 m_block_map[addr] = port; 801} 802 803void 804$c_ident::unblock(Address addr) 805{ 806 m_block_map.erase(addr); 807 if (m_block_map.size() == 0) { 808 m_is_blocking = false; 809 } 810} 811 812void 813$c_ident::print(ostream& out) const 814{ 815 out << "[$c_ident " << m_version << "]"; 816} 817 818void 819$c_ident::printConfig(ostream& out) const 820{ 821 out << "$c_ident config: " << m_name << endl; 822 out << " version: " << m_version << endl; 823 map<string, string>::const_iterator it; 824 for (it = m_cfg.begin(); it != m_cfg.end(); it++) 825 out << " " << it->first << ": " << it->second << endl; 826} 827 828void 829$c_ident::printStats(ostream& out) const 830{ 831''') 832 # 833 # Cache and Memory Controllers have specific profilers associated with 834 # them. Print out these stats before dumping state transition stats. 835 # 836 for param in self.config_parameters: 837 if param.type_ast.type.ident == "CacheMemory" or \ 838 param.type_ast.type.ident == "DirectoryMemory" or \ 839 param.type_ast.type.ident == "MemoryControl": 840 assert(param.pointer) 841 code(' m_${{param.ident}}_ptr->printStats(out);') 842 843 code(''' 844 if (m_version == 0) { 845 s_profileDumper.dumpStats(out); 846 } 847} 848 849void $c_ident::clearStats() { 850''') 851 # 852 # Cache and Memory Controllers have specific profilers associated with 853 # them. These stats must be cleared too. 854 # 855 for param in self.config_parameters: 856 if param.type_ast.type.ident == "CacheMemory" or \ 857 param.type_ast.type.ident == "MemoryControl": 858 assert(param.pointer) 859 code(' m_${{param.ident}}_ptr->clearStats();') 860 861 code(''' 862 m_profiler.clearStats(); 863} 864''') 865 866 if self.EntryType != None: 867 code(''' 868 869// Set and Reset for cache_entry variable 870void 871$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 872{ 873 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 874} 875 876void 877$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 878{ 879 m_cache_entry_ptr = 0; 880} 881''') 882 883 if self.TBEType != None: 884 code(''' 885 886// Set and Reset for tbe variable 887void 888$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 889{ 890 m_tbe_ptr = m_new_tbe; 891} 892 893void 894$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 895{ 896 m_tbe_ptr = NULL; 897} 898''') 899 900 code(''' 901 902void 903$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 904{ 905''') 906 # 907 # Record cache contents for all associated caches. 908 # 909 code.indent() 910 for param in self.config_parameters: 911 if param.type_ast.type.ident == "CacheMemory": 912 assert(param.pointer) 913 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 914 915 code.dedent() 916 code(''' 917} 918 919// Actions 920''') 921 if self.TBEType != None and self.EntryType != None: 922 for action in self.actions.itervalues(): 923 if "c_code" not in action: 924 continue 925 926 code(''' 927/** \\brief ${{action.desc}} */ 928void 929$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 930{ 931 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 932 ${{action["c_code"]}} 933} 934 935''') 936 elif self.TBEType != None: 937 for action in self.actions.itervalues(): 938 if "c_code" not in action: 939 continue 940 941 code(''' 942/** \\brief ${{action.desc}} */ 943void 944$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 945{ 946 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 947 ${{action["c_code"]}} 948} 949 950''') 951 elif self.EntryType != None: 952 for action in self.actions.itervalues(): 953 if "c_code" not in action: 954 continue 955 956 code(''' 957/** \\brief ${{action.desc}} */ 958void 959$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 960{ 961 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 962 ${{action["c_code"]}} 963} 964 965''') 966 else: 967 for action in self.actions.itervalues(): 968 if "c_code" not in action: 969 continue 970 971 code(''' 972/** \\brief ${{action.desc}} */ 973void 974$c_ident::${{action.ident}}(const Address& addr) 975{ 976 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 977 ${{action["c_code"]}} 978} 979 980''') 981 for func in self.functions: 982 code(func.generateCode()) 983 984 code.write(path, "%s.cc" % c_ident) 985 986 def printCWakeup(self, path): 987 '''Output the wakeup loop for the events''' 988 989 code = self.symtab.codeFormatter() 990 ident = self.ident 991 992 code(''' 993// Auto generated C++ code started by $__file__:$__line__ 994// ${ident}: ${{self.short}} 995 996#include <sys/types.h> 997#include <unistd.h> 998 999#include <cassert> 1000 1001#include "base/misc.hh" 1002#include "debug/RubySlicc.hh" 1003#include "mem/protocol/${ident}_Controller.hh" 1004#include "mem/protocol/${ident}_Event.hh" 1005#include "mem/protocol/${ident}_State.hh" 1006#include "mem/protocol/Types.hh" 1007#include "mem/ruby/common/Global.hh" 1008#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 1009#include "mem/ruby/system/System.hh" 1010 1011using namespace std; 1012 1013void 1014${ident}_Controller::wakeup() 1015{ 1016 int counter = 0; 1017 while (true) { 1018 // Some cases will put us into an infinite loop without this limit 1019 assert(counter <= m_transitions_per_cycle); 1020 if (counter == m_transitions_per_cycle) { 1021 // Count how often we are fully utilized 1022 g_system_ptr->getProfiler()->controllerBusy(m_machineID); 1023 1024 // Wakeup in another cycle and try again 1025 g_eventQueue_ptr->scheduleEvent(this, 1); 1026 break; 1027 } 1028''') 1029 1030 code.indent() 1031 code.indent() 1032 1033 # InPorts 1034 # 1035 for port in self.in_ports: 1036 code.indent() 1037 code('// ${ident}InPort $port') 1038 if port.pairs.has_key("rank"): 1039 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};') 1040 else: 1041 code('m_cur_in_port_rank = 0;') 1042 code('${{port["c_code_in_port"]}}') 1043 code.dedent() 1044 1045 code('') 1046 1047 code.dedent() 1048 code.dedent() 1049 code(''' 1050 break; // If we got this far, we have nothing left todo 1051 } 1052 // g_eventQueue_ptr->scheduleEvent(this, 1); 1053} 1054''') 1055 1056 code.write(path, "%s_Wakeup.cc" % self.ident) 1057 1058 def printCSwitch(self, path): 1059 '''Output switch statement for transition table''' 1060 1061 code = self.symtab.codeFormatter() 1062 ident = self.ident 1063 1064 code(''' 1065// Auto generated C++ code started by $__file__:$__line__ 1066// ${ident}: ${{self.short}} 1067 1068#include <cassert> 1069 1070#include "base/misc.hh" 1071#include "base/trace.hh" 1072#include "debug/ProtocolTrace.hh" 1073#include "debug/RubyGenerated.hh" 1074#include "mem/protocol/${ident}_Controller.hh" 1075#include "mem/protocol/${ident}_Event.hh" 1076#include "mem/protocol/${ident}_State.hh" 1077#include "mem/protocol/Types.hh" 1078#include "mem/ruby/common/Global.hh" 1079#include "mem/ruby/system/System.hh" 1080 1081#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1082 1083#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1084#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1085 1086TransitionResult 1087${ident}_Controller::doTransition(${ident}_Event event, 1088''') 1089 if self.EntryType != None: 1090 code(''' 1091 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1092''') 1093 if self.TBEType != None: 1094 code(''' 1095 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1096''') 1097 code(''' 1098 const Address &addr) 1099{ 1100''') 1101 if self.TBEType != None and self.EntryType != None: 1102 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1103 elif self.TBEType != None: 1104 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1105 elif self.EntryType != None: 1106 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1107 else: 1108 code('${ident}_State state = getState(addr);') 1109 1110 code(''' 1111 ${ident}_State next_state = state; 1112 1113 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1114 *this, 1115 g_eventQueue_ptr->getTime(), 1116 ${ident}_State_to_string(state), 1117 ${ident}_Event_to_string(event), 1118 addr); 1119 1120 TransitionResult result = 1121''') 1122 if self.TBEType != None and self.EntryType != None: 1123 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1124 elif self.TBEType != None: 1125 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1126 elif self.EntryType != None: 1127 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1128 else: 1129 code('doTransitionWorker(event, state, next_state, addr);') 1130 1131 code(''' 1132 if (result == TransitionResult_Valid) { 1133 DPRINTF(RubyGenerated, "next_state: %s\\n", 1134 ${ident}_State_to_string(next_state)); 1135 m_profiler.countTransition(state, event); 1136 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1137 curTick(), m_version, "${ident}", 1138 ${ident}_Event_to_string(event), 1139 ${ident}_State_to_string(state), 1140 ${ident}_State_to_string(next_state), 1141 addr, GET_TRANSITION_COMMENT()); 1142 1143 CLEAR_TRANSITION_COMMENT(); 1144''') 1145 if self.TBEType != None and self.EntryType != None: 1146 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1147 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1148 elif self.TBEType != None: 1149 code('setState(m_tbe_ptr, addr, next_state);') 1150 code('setAccessPermission(addr, next_state);') 1151 elif self.EntryType != None: 1152 code('setState(m_cache_entry_ptr, addr, next_state);') 1153 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1154 else: 1155 code('setState(addr, next_state);') 1156 code('setAccessPermission(addr, next_state);') 1157 1158 code(''' 1159 } else if (result == TransitionResult_ResourceStall) { 1160 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1161 curTick(), m_version, "${ident}", 1162 ${ident}_Event_to_string(event), 1163 ${ident}_State_to_string(state), 1164 ${ident}_State_to_string(next_state), 1165 addr, "Resource Stall"); 1166 } else if (result == TransitionResult_ProtocolStall) { 1167 DPRINTF(RubyGenerated, "stalling\\n"); 1168 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1169 curTick(), m_version, "${ident}", 1170 ${ident}_Event_to_string(event), 1171 ${ident}_State_to_string(state), 1172 ${ident}_State_to_string(next_state), 1173 addr, "Protocol Stall"); 1174 } 1175 1176 return result; 1177} 1178 1179TransitionResult 1180${ident}_Controller::doTransitionWorker(${ident}_Event event, 1181 ${ident}_State state, 1182 ${ident}_State& next_state, 1183''') 1184 1185 if self.TBEType != None: 1186 code(''' 1187 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1188''') 1189 if self.EntryType != None: 1190 code(''' 1191 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1192''') 1193 code(''' 1194 const Address& addr) 1195{ 1196 switch(HASH_FUN(state, event)) { 1197''') 1198 1199 # This map will allow suppress generating duplicate code 1200 cases = orderdict() 1201 1202 for trans in self.transitions: 1203 case_string = "%s_State_%s, %s_Event_%s" % \ 1204 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1205 1206 case = self.symtab.codeFormatter() 1207 # Only set next_state if it changes 1208 if trans.state != trans.nextState: 1209 ns_ident = trans.nextState.ident 1210 case('next_state = ${ident}_State_${ns_ident};') 1211 1212 actions = trans.actions 1213 1214 # Check for resources 1215 case_sorter = [] 1216 res = trans.resources 1217 for key,val in res.iteritems(): 1218 if key.type.ident != "DNUCAStopTable": 1219 val = ''' 1220if (!%s.areNSlotsAvailable(%s)) 1221 return TransitionResult_ResourceStall; 1222''' % (key.code, val) 1223 case_sorter.append(val) 1224 1225 1226 # Emit the code sequences in a sorted order. This makes the 1227 # output deterministic (without this the output order can vary 1228 # since Map's keys() on a vector of pointers is not deterministic 1229 for c in sorted(case_sorter): 1230 case("$c") 1231 1232 # Figure out if we stall 1233 stall = False 1234 for action in actions: 1235 if action.ident == "z_stall": 1236 stall = True 1237 break 1238 1239 if stall: 1240 case('return TransitionResult_ProtocolStall;') 1241 else: 1242 if self.TBEType != None and self.EntryType != None: 1243 for action in actions: 1244 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1245 elif self.TBEType != None: 1246 for action in actions: 1247 case('${{action.ident}}(m_tbe_ptr, addr);') 1248 elif self.EntryType != None: 1249 for action in actions: 1250 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1251 else: 1252 for action in actions: 1253 case('${{action.ident}}(addr);') 1254 case('return TransitionResult_Valid;') 1255 1256 case = str(case) 1257 1258 # Look to see if this transition code is unique. 1259 if case not in cases: 1260 cases[case] = [] 1261 1262 cases[case].append(case_string) 1263 1264 # Walk through all of the unique code blocks and spit out the 1265 # corresponding case statement elements 1266 for case,transitions in cases.iteritems(): 1267 # Iterative over all the multiple transitions that share 1268 # the same code 1269 for trans in transitions: 1270 code(' case HASH_FUN($trans):') 1271 code(' $case') 1272 1273 code(''' 1274 default: 1275 fatal("Invalid transition\\n" 1276 "%s time: %d addr: %s event: %s state: %s\\n", 1277 name(), g_eventQueue_ptr->getTime(), addr, event, state); 1278 } 1279 return TransitionResult_Valid; 1280} 1281''') 1282 code.write(path, "%s_Transitions.cc" % self.ident) 1283 1284 def printProfileDumperHH(self, path): 1285 code = self.symtab.codeFormatter() 1286 ident = self.ident 1287 1288 code(''' 1289// Auto generated C++ code started by $__file__:$__line__ 1290// ${ident}: ${{self.short}} 1291 1292#ifndef __${ident}_PROFILE_DUMPER_HH__ 1293#define __${ident}_PROFILE_DUMPER_HH__ 1294 1295#include <cassert> 1296#include <iostream> 1297#include <vector> 1298 1299#include "${ident}_Event.hh" 1300#include "${ident}_Profiler.hh" 1301 1302typedef std::vector<${ident}_Profiler *> ${ident}_profilers; 1303 1304class ${ident}_ProfileDumper 1305{ 1306 public: 1307 ${ident}_ProfileDumper(); 1308 void registerProfiler(${ident}_Profiler* profiler); 1309 void dumpStats(std::ostream& out) const; 1310 1311 private: 1312 ${ident}_profilers m_profilers; 1313}; 1314 1315#endif // __${ident}_PROFILE_DUMPER_HH__ 1316''') 1317 code.write(path, "%s_ProfileDumper.hh" % self.ident) 1318 1319 def printProfileDumperCC(self, path): 1320 code = self.symtab.codeFormatter() 1321 ident = self.ident 1322 1323 code(''' 1324// Auto generated C++ code started by $__file__:$__line__ 1325// ${ident}: ${{self.short}} 1326 1327#include "mem/protocol/${ident}_ProfileDumper.hh" 1328 1329${ident}_ProfileDumper::${ident}_ProfileDumper() 1330{ 1331} 1332 1333void 1334${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler) 1335{ 1336 m_profilers.push_back(profiler); 1337} 1338 1339void 1340${ident}_ProfileDumper::dumpStats(std::ostream& out) const 1341{ 1342 out << " --- ${ident} ---\\n"; 1343 out << " - Event Counts -\\n"; 1344 for (${ident}_Event event = ${ident}_Event_FIRST; 1345 event < ${ident}_Event_NUM; 1346 ++event) { 1347 out << (${ident}_Event) event << " ["; 1348 uint64 total = 0; 1349 for (int i = 0; i < m_profilers.size(); i++) { 1350 out << m_profilers[i]->getEventCount(event) << " "; 1351 total += m_profilers[i]->getEventCount(event); 1352 } 1353 out << "] " << total << "\\n"; 1354 } 1355 out << "\\n"; 1356 out << " - Transitions -\\n"; 1357 for (${ident}_State state = ${ident}_State_FIRST; 1358 state < ${ident}_State_NUM; 1359 ++state) { 1360 for (${ident}_Event event = ${ident}_Event_FIRST; 1361 event < ${ident}_Event_NUM; 1362 ++event) { 1363 if (m_profilers[0]->isPossible(state, event)) { 1364 out << (${ident}_State) state << " " 1365 << (${ident}_Event) event << " ["; 1366 uint64 total = 0; 1367 for (int i = 0; i < m_profilers.size(); i++) { 1368 out << m_profilers[i]->getTransitionCount(state, event) << " "; 1369 total += m_profilers[i]->getTransitionCount(state, event); 1370 } 1371 out << "] " << total << "\\n"; 1372 } 1373 } 1374 out << "\\n"; 1375 } 1376} 1377''') 1378 code.write(path, "%s_ProfileDumper.cc" % self.ident) 1379 1380 def printProfilerHH(self, path): 1381 code = self.symtab.codeFormatter() 1382 ident = self.ident 1383 1384 code(''' 1385// Auto generated C++ code started by $__file__:$__line__ 1386// ${ident}: ${{self.short}} 1387 1388#ifndef __${ident}_PROFILER_HH__ 1389#define __${ident}_PROFILER_HH__ 1390 1391#include <cassert> 1392#include <iostream> 1393 1394#include "mem/protocol/${ident}_Event.hh" 1395#include "mem/protocol/${ident}_State.hh" 1396#include "mem/ruby/common/TypeDefines.hh" 1397 1398class ${ident}_Profiler 1399{ 1400 public: 1401 ${ident}_Profiler(); 1402 void setVersion(int version); 1403 void countTransition(${ident}_State state, ${ident}_Event event); 1404 void possibleTransition(${ident}_State state, ${ident}_Event event); 1405 uint64 getEventCount(${ident}_Event event); 1406 bool isPossible(${ident}_State state, ${ident}_Event event); 1407 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 1408 void clearStats(); 1409 1410 private: 1411 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 1412 int m_event_counters[${ident}_Event_NUM]; 1413 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 1414 int m_version; 1415}; 1416 1417#endif // __${ident}_PROFILER_HH__ 1418''') 1419 code.write(path, "%s_Profiler.hh" % self.ident) 1420 1421 def printProfilerCC(self, path): 1422 code = self.symtab.codeFormatter() 1423 ident = self.ident 1424 1425 code(''' 1426// Auto generated C++ code started by $__file__:$__line__ 1427// ${ident}: ${{self.short}} 1428 1429#include <cassert> 1430 1431#include "mem/protocol/${ident}_Profiler.hh" 1432 1433${ident}_Profiler::${ident}_Profiler() 1434{ 1435 for (int state = 0; state < ${ident}_State_NUM; state++) { 1436 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1437 m_possible[state][event] = false; 1438 m_counters[state][event] = 0; 1439 } 1440 } 1441 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1442 m_event_counters[event] = 0; 1443 } 1444} 1445 1446void 1447${ident}_Profiler::setVersion(int version) 1448{ 1449 m_version = version; 1450} 1451 1452void 1453${ident}_Profiler::clearStats() 1454{ 1455 for (int state = 0; state < ${ident}_State_NUM; state++) { 1456 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1457 m_counters[state][event] = 0; 1458 } 1459 } 1460 1461 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1462 m_event_counters[event] = 0; 1463 } 1464} 1465void 1466${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1467{ 1468 assert(m_possible[state][event]); 1469 m_counters[state][event]++; 1470 m_event_counters[event]++; 1471} 1472void 1473${ident}_Profiler::possibleTransition(${ident}_State state, 1474 ${ident}_Event event) 1475{ 1476 m_possible[state][event] = true; 1477} 1478 1479uint64 1480${ident}_Profiler::getEventCount(${ident}_Event event) 1481{ 1482 return m_event_counters[event]; 1483} 1484 1485bool 1486${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event) 1487{ 1488 return m_possible[state][event]; 1489} 1490 1491uint64 1492${ident}_Profiler::getTransitionCount(${ident}_State state, 1493 ${ident}_Event event) 1494{ 1495 return m_counters[state][event]; 1496} 1497 1498''') 1499 code.write(path, "%s_Profiler.cc" % self.ident) 1500 1501 # ************************** 1502 # ******* HTML Files ******* 1503 # ************************** 1504 def frameRef(self, click_href, click_target, over_href, over_num, text): 1505 code = self.symtab.codeFormatter(fix_newlines=False) 1506 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1507 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1508 parent.frames[$over_num].location='$over_href' 1509 }\"> 1510 ${{html.formatShorthand(text)}} 1511 </A>""") 1512 return str(code) 1513 1514 def writeHTMLFiles(self, path): 1515 # Create table with no row hilighted 1516 self.printHTMLTransitions(path, None) 1517 1518 # Generate transition tables 1519 for state in self.states.itervalues(): 1520 self.printHTMLTransitions(path, state) 1521 1522 # Generate action descriptions 1523 for action in self.actions.itervalues(): 1524 name = "%s_action_%s.html" % (self.ident, action.ident) 1525 code = html.createSymbol(action, "Action") 1526 code.write(path, name) 1527 1528 # Generate state descriptions 1529 for state in self.states.itervalues(): 1530 name = "%s_State_%s.html" % (self.ident, state.ident) 1531 code = html.createSymbol(state, "State") 1532 code.write(path, name) 1533 1534 # Generate event descriptions 1535 for event in self.events.itervalues(): 1536 name = "%s_Event_%s.html" % (self.ident, event.ident) 1537 code = html.createSymbol(event, "Event") 1538 code.write(path, name) 1539 1540 def printHTMLTransitions(self, path, active_state): 1541 code = self.symtab.codeFormatter() 1542 1543 code(''' 1544<HTML> 1545<BODY link="blue" vlink="blue"> 1546 1547<H1 align="center">${{html.formatShorthand(self.short)}}: 1548''') 1549 code.indent() 1550 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1551 mid = machine.ident 1552 if i != 0: 1553 extra = " - " 1554 else: 1555 extra = "" 1556 if machine == self: 1557 code('$extra$mid') 1558 else: 1559 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1560 code.dedent() 1561 1562 code(""" 1563</H1> 1564 1565<TABLE border=1> 1566<TR> 1567 <TH> </TH> 1568""") 1569 1570 for event in self.events.itervalues(): 1571 href = "%s_Event_%s.html" % (self.ident, event.ident) 1572 ref = self.frameRef(href, "Status", href, "1", event.short) 1573 code('<TH bgcolor=white>$ref</TH>') 1574 1575 code('</TR>') 1576 # -- Body of table 1577 for state in self.states.itervalues(): 1578 # -- Each row 1579 if state == active_state: 1580 color = "yellow" 1581 else: 1582 color = "white" 1583 1584 click = "%s_table_%s.html" % (self.ident, state.ident) 1585 over = "%s_State_%s.html" % (self.ident, state.ident) 1586 text = html.formatShorthand(state.short) 1587 ref = self.frameRef(click, "Table", over, "1", state.short) 1588 code(''' 1589<TR> 1590 <TH bgcolor=$color>$ref</TH> 1591''') 1592 1593 # -- One column for each event 1594 for event in self.events.itervalues(): 1595 trans = self.table.get((state,event), None) 1596 if trans is None: 1597 # This is the no transition case 1598 if state == active_state: 1599 color = "#C0C000" 1600 else: 1601 color = "lightgrey" 1602 1603 code('<TD bgcolor=$color> </TD>') 1604 continue 1605 1606 next = trans.nextState 1607 stall_action = False 1608 1609 # -- Get the actions 1610 for action in trans.actions: 1611 if action.ident == "z_stall" or \ 1612 action.ident == "zz_recycleMandatoryQueue": 1613 stall_action = True 1614 1615 # -- Print out "actions/next-state" 1616 if stall_action: 1617 if state == active_state: 1618 color = "#C0C000" 1619 else: 1620 color = "lightgrey" 1621 1622 elif active_state and next.ident == active_state.ident: 1623 color = "aqua" 1624 elif state == active_state: 1625 color = "yellow" 1626 else: 1627 color = "white" 1628 1629 code('<TD bgcolor=$color>') 1630 for action in trans.actions: 1631 href = "%s_action_%s.html" % (self.ident, action.ident) 1632 ref = self.frameRef(href, "Status", href, "1", 1633 action.short) 1634 code(' $ref') 1635 if next != state: 1636 if trans.actions: 1637 code('/') 1638 click = "%s_table_%s.html" % (self.ident, next.ident) 1639 over = "%s_State_%s.html" % (self.ident, next.ident) 1640 ref = self.frameRef(click, "Table", over, "1", next.short) 1641 code("$ref") 1642 code("</TD>") 1643 1644 # -- Each row 1645 if state == active_state: 1646 color = "yellow" 1647 else: 1648 color = "white" 1649 1650 click = "%s_table_%s.html" % (self.ident, state.ident) 1651 over = "%s_State_%s.html" % (self.ident, state.ident) 1652 ref = self.frameRef(click, "Table", over, "1", state.short) 1653 code(''' 1654 <TH bgcolor=$color>$ref</TH> 1655</TR> 1656''') 1657 code(''' 1658<!- Column footer-> 1659<TR> 1660 <TH> </TH> 1661''') 1662 1663 for event in self.events.itervalues(): 1664 href = "%s_Event_%s.html" % (self.ident, event.ident) 1665 ref = self.frameRef(href, "Status", href, "1", event.short) 1666 code('<TH bgcolor=white>$ref</TH>') 1667 code(''' 1668</TR> 1669</TABLE> 1670</BODY></HTML> 1671''') 1672 1673 1674 if active_state: 1675 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1676 else: 1677 name = "%s_table.html" % self.ident 1678 code.write(path, name) 1679 1680__all__ = [ "StateMachine" ] 1681