StateMachine.py revision 8478
18926Sandreas.hansson@arm.com# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 27586SAli.Saidi@arm.com# Copyright (c) 2009 The Hewlett-Packard Development Company 37586SAli.Saidi@arm.com# All rights reserved. 47586SAli.Saidi@arm.com# 57586SAli.Saidi@arm.com# Redistribution and use in source and binary forms, with or without 67586SAli.Saidi@arm.com# modification, are permitted provided that the following conditions are 77586SAli.Saidi@arm.com# met: redistributions of source code must retain the above copyright 87586SAli.Saidi@arm.com# notice, this list of conditions and the following disclaimer; 97586SAli.Saidi@arm.com# redistributions in binary form must reproduce the above copyright 107586SAli.Saidi@arm.com# notice, this list of conditions and the following disclaimer in the 117586SAli.Saidi@arm.com# documentation and/or other materials provided with the distribution; 127586SAli.Saidi@arm.com# neither the name of the copyright holders nor the names of its 133970Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from 143005Sstever@eecs.umich.edu# this software without specific prior written permission. 153005Sstever@eecs.umich.edu# 163005Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173005Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183005Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193005Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203005Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213005Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223005Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233005Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243005Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253005Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263005Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273005Sstever@eecs.umich.edu 283005Sstever@eecs.umich.edufrom m5.util import orderdict 293005Sstever@eecs.umich.edu 303005Sstever@eecs.umich.edufrom slicc.symbols.Symbol import Symbol 313005Sstever@eecs.umich.edufrom slicc.symbols.Var import Var 323005Sstever@eecs.umich.eduimport slicc.generate.html as html 333005Sstever@eecs.umich.eduimport re 343005Sstever@eecs.umich.edu 353005Sstever@eecs.umich.edupython_class_map = {"int": "Int", 363005Sstever@eecs.umich.edu "std::string": "String", 373005Sstever@eecs.umich.edu "bool": "Bool", 383005Sstever@eecs.umich.edu "CacheMemory": "RubyCache", 393005Sstever@eecs.umich.edu "WireBuffer": "RubyWireBuffer", 403005Sstever@eecs.umich.edu "Sequencer": "RubySequencer", 416654Snate@binkert.org "DirectoryMemory": "RubyDirectoryMemory", 426654Snate@binkert.org "MemoryControl": "RubyMemoryControl", 432889SN/A "DMASequencer": "DMASequencer" 442710SN/A } 456654Snate@binkert.org 466654Snate@binkert.orgclass StateMachine(Symbol): 476654Snate@binkert.org def __init__(self, symtab, ident, location, pairs, config_parameters): 485457Ssaidi@eecs.umich.edu super(StateMachine, self).__init__(symtab, ident, location, pairs) 496654Snate@binkert.org self.table = None 506654Snate@binkert.org self.config_parameters = config_parameters 512934SN/A 522549SN/A for param in config_parameters: 532995SN/A if param.pointer: 543395Shsul@eecs.umich.edu var = Var(symtab, param.name, location, param.type_ast.type, 556981SLisa.Hsu@amd.com "(*m_%s_ptr)" % param.name, {}, self) 563448Shsul@eecs.umich.edu else: 578920Snilay@cs.wisc.edu var = Var(symtab, param.name, location, param.type_ast.type, 583444Sktlim@umich.edu "m_%s" % param.name, {}, self) 592889SN/A self.symtab.registerSym(param.name, var) 608920Snilay@cs.wisc.edu 618920Snilay@cs.wisc.edu self.states = orderdict() 623322Shsul@eecs.umich.edu self.events = orderdict() 632710SN/A self.actions = orderdict() 642710SN/A self.transitions = [] 652710SN/A self.in_ports = [] 662710SN/A self.functions = [] 672710SN/A self.objects = [] 682710SN/A self.TBEType = None 693322Shsul@eecs.umich.edu self.EntryType = None 703304Sstever@eecs.umich.edu 713322Shsul@eecs.umich.edu self.message_buffer_names = [] 723322Shsul@eecs.umich.edu 733304Sstever@eecs.umich.edu def __repr__(self): 743481Shsul@eecs.umich.edu return "[StateMachine: %s]" % self.ident 753481Shsul@eecs.umich.edu 762566SN/A def addState(self, state): 779129Sandreas.hansson@arm.com assert self.table is None 789129Sandreas.hansson@arm.com self.states[state.ident] = state 792995SN/A 802995SN/A def addEvent(self, event): 813304Sstever@eecs.umich.edu assert self.table is None 823304Sstever@eecs.umich.edu self.events[event.ident] = event 833304Sstever@eecs.umich.edu 842995SN/A def addAction(self, action): 852995SN/A assert self.table is None 862995SN/A 872917SN/A # Check for duplicate action 882995SN/A for other in self.actions.itervalues(): 898956Sjayneel@cs.wisc.edu if action.ident == other.ident: 902995SN/A action.warning("Duplicate action definition: %s" % action.ident) 918956Sjayneel@cs.wisc.edu action.error("Duplicate action definition: %s" % action.ident) 923304Sstever@eecs.umich.edu if action.short == other.short: 936135Sgblack@eecs.umich.edu other.warning("Duplicate action shorthand: %s" % other.ident) 946135Sgblack@eecs.umich.edu other.warning(" shorthand = %s" % other.short) 956654Snate@binkert.org action.warning("Duplicate action shorthand: %s" % action.ident) 963819Shsul@eecs.umich.edu action.error(" shorthand = %s" % action.short) 976654Snate@binkert.org 985222Sksewell@umich.edu self.actions[action.ident] = action 996654Snate@binkert.org 1003819Shsul@eecs.umich.edu def addTransition(self, trans): 1016654Snate@binkert.org assert self.table is None 1027925Sgblack@eecs.umich.edu self.transitions.append(trans) 1037586SAli.Saidi@arm.com 1048061SAli.Saidi@ARM.com def addInPort(self, var): 1058061SAli.Saidi@ARM.com self.in_ports.append(var) 1068061SAli.Saidi@ARM.com 1073819Shsul@eecs.umich.edu def addFunc(self, func): 1089059Snilay@cs.wisc.edu # register func in the symbol table 1093819Shsul@eecs.umich.edu self.symtab.registerSym(str(func), func) 1103873Sbinkertn@umich.edu self.functions.append(func) 1113873Sbinkertn@umich.edu 1123873Sbinkertn@umich.edu def addObject(self, obj): 1133873Sbinkertn@umich.edu self.objects.append(obj) 1143873Sbinkertn@umich.edu 1153873Sbinkertn@umich.edu def addType(self, type): 1168659SAli.Saidi@ARM.com type_ident = '%s' % type.c_ident 1178659SAli.Saidi@ARM.com 1186995Sgblack@eecs.umich.edu if type_ident == "%s_TBE" %self.ident: 1193668Srdreslin@umich.edu if self.TBEType != None: 1208713Sandreas.hansson@arm.com self.error("Multiple Transaction Buffer types in a " \ 1218713Sandreas.hansson@arm.com "single machine."); 1228713Sandreas.hansson@arm.com self.TBEType = type 1238713Sandreas.hansson@arm.com 1246636Ssteve.reinhardt@amd.com elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 1258894Ssaidi@eecs.umich.edu if self.EntryType != None: 1268839Sandreas.hansson@arm.com self.error("Multiple AbstractCacheEntry types in a " \ 1278839Sandreas.hansson@arm.com "single machine."); 1288713Sandreas.hansson@arm.com self.EntryType = type 1299164Sandreas.hansson@arm.com 1308839Sandreas.hansson@arm.com # Needs to be called before accessing the table 1318839Sandreas.hansson@arm.com def buildTable(self): 1325142Ssaidi@eecs.umich.edu assert self.table is None 1338926Sandreas.hansson@arm.com 1348926Sandreas.hansson@arm.com table = {} 1358926Sandreas.hansson@arm.com 1368926Sandreas.hansson@arm.com for trans in self.transitions: 1373312Sstever@eecs.umich.edu # Track which actions we touch so we know if we use them 1384968Sacolyte@umich.edu # all -- really this should be done for all symbols as 1398926Sandreas.hansson@arm.com # part of the symbol table, then only trigger it for 1408887Sgeoffrey.blake@arm.com # Actions, States, Events, etc. 1418887Sgeoffrey.blake@arm.com 1428887Sgeoffrey.blake@arm.com for action in trans.actions: 1438887Sgeoffrey.blake@arm.com action.used = True 1444968Sacolyte@umich.edu 1453005Sstever@eecs.umich.edu index = (trans.state, trans.event) 1466654Snate@binkert.org if index in table: 1473819Shsul@eecs.umich.edu table[index].warning("Duplicate transition: %s" % table[index]) 1486654Snate@binkert.org trans.error("Duplicate transition: %s" % trans) 1495222Sksewell@umich.edu table[index] = trans 1506654Snate@binkert.org 1513819Shsul@eecs.umich.edu # Look at all actions to make sure we used them all 1526654Snate@binkert.org for action in self.actions.itervalues(): 1536135Sgblack@eecs.umich.edu if not action.used: 1547586SAli.Saidi@arm.com error_msg = "Unused action: %s" % action.ident 1558661SAli.Saidi@ARM.com if "desc" in action: 1568661SAli.Saidi@ARM.com error_msg += ", " + action.desc 1573322Shsul@eecs.umich.edu action.warning(error_msg) 1588863Snilay@cs.wisc.edu self.table = table 1597876Sgblack@eecs.umich.edu 1604968Sacolyte@umich.edu def writeCodeFiles(self, path): 1618926Sandreas.hansson@arm.com self.printControllerPython(path) 1624837Ssaidi@eecs.umich.edu self.printControllerHH(path) 1634837Ssaidi@eecs.umich.edu self.printControllerCC(path) 1649164Sandreas.hansson@arm.com self.printCSwitch(path) 1659164Sandreas.hansson@arm.com self.printCWakeup(path) 1668845Sandreas.hansson@arm.com self.printProfilerCC(path) 1678845Sandreas.hansson@arm.com self.printProfilerHH(path) 1684837Ssaidi@eecs.umich.edu self.printProfileDumperCC(path) 1698659SAli.Saidi@ARM.com self.printProfileDumperHH(path) 1708801Sgblack@eecs.umich.edu 1713005Sstever@eecs.umich.edu def printControllerPython(self, path): 1728801Sgblack@eecs.umich.edu code = self.symtab.codeFormatter() 1733005Sstever@eecs.umich.edu ident = self.ident 1743005Sstever@eecs.umich.edu py_ident = "%s_Controller" % ident 1753005Sstever@eecs.umich.edu c_ident = "%s_Controller" % self.ident 1762566SN/A code(''' 1777861Sgblack@eecs.umich.edufrom m5.params import * 1787861Sgblack@eecs.umich.edufrom m5.SimObject import SimObject 1797861Sgblack@eecs.umich.edufrom Controller import RubyController 1808635Schris.emmons@arm.com 1818635Schris.emmons@arm.comclass $py_ident(RubyController): 1828635Schris.emmons@arm.com type = '$py_ident' 1839061Snilay@cs.wisc.edu''') 1843481Shsul@eecs.umich.edu code.indent() 185 for param in self.config_parameters: 186 dflt_str = '' 187 if param.default is not None: 188 dflt_str = str(param.default) + ', ' 189 if python_class_map.has_key(param.type_ast.type.c_ident): 190 python_type = python_class_map[param.type_ast.type.c_ident] 191 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 192 else: 193 self.error("Unknown c++ to python class conversion for c++ " \ 194 "type: '%s'. Please update the python_class_map " \ 195 "in StateMachine.py", param.type_ast.type.c_ident) 196 code.dedent() 197 code.write(path, '%s.py' % py_ident) 198 199 200 def printControllerHH(self, path): 201 '''Output the method declarations for the class declaration''' 202 code = self.symtab.codeFormatter() 203 ident = self.ident 204 c_ident = "%s_Controller" % self.ident 205 206 self.message_buffer_names = [] 207 208 code(''' 209/** \\file $c_ident.hh 210 * 211 * Auto generated C++ code started by $__file__:$__line__ 212 * Created by slicc definition of Module "${{self.short}}" 213 */ 214 215#ifndef __${ident}_CONTROLLER_HH__ 216#define __${ident}_CONTROLLER_HH__ 217 218#include <iostream> 219#include <sstream> 220#include <string> 221 222#include "mem/protocol/${ident}_ProfileDumper.hh" 223#include "mem/protocol/${ident}_Profiler.hh" 224#include "mem/protocol/TransitionResult.hh" 225#include "mem/protocol/Types.hh" 226#include "mem/ruby/common/Consumer.hh" 227#include "mem/ruby/common/Global.hh" 228#include "mem/ruby/slicc_interface/AbstractController.hh" 229#include "params/$c_ident.hh" 230''') 231 232 seen_types = set() 233 for var in self.objects: 234 if var.type.ident not in seen_types and not var.type.isPrimitive: 235 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 236 seen_types.add(var.type.ident) 237 238 # for adding information to the protocol debug trace 239 code(''' 240extern std::stringstream ${ident}_transitionComment; 241 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 const MachineType getMachineType() const; 257 void stallBuffer(MessageBuffer* buf, Address addr); 258 void wakeUpBuffers(Address addr); 259 void wakeUpAllBuffers(); 260 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; } 261 void print(std::ostream& out) const; 262 void printConfig(std::ostream& out) const; 263 void wakeup(); 264 void printStats(std::ostream& out) const; 265 void clearStats(); 266 void blockOnQueue(Address addr, MessageBuffer* port); 267 void unblock(Address addr); 268 269private: 270''') 271 272 code.indent() 273 # added by SS 274 for param in self.config_parameters: 275 if param.pointer: 276 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 277 else: 278 code('${{param.type_ast.type}} m_${{param.ident}};') 279 280 code(''' 281int m_number_of_TBEs; 282 283TransitionResult doTransition(${ident}_Event event, 284''') 285 286 if self.EntryType != None: 287 code(''' 288 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 289''') 290 if self.TBEType != None: 291 code(''' 292 ${{self.TBEType.c_ident}}* m_tbe_ptr, 293''') 294 295 code(''' 296 const Address& addr); 297 298TransitionResult doTransitionWorker(${ident}_Event event, 299 ${ident}_State state, 300 ${ident}_State& next_state, 301''') 302 303 if self.TBEType != None: 304 code(''' 305 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 306''') 307 if self.EntryType != None: 308 code(''' 309 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 310''') 311 312 code(''' 313 const Address& addr); 314 315std::string m_name; 316int m_transitions_per_cycle; 317int m_buffer_size; 318int m_recycle_latency; 319std::map<std::string, std::string> m_cfg; 320NodeID m_version; 321Network* m_net_ptr; 322MachineID m_machineID; 323bool m_is_blocking; 324std::map<Address, MessageBuffer*> m_block_map; 325typedef std::vector<MessageBuffer*> MsgVecType; 326typedef m5::hash_map< Address, MsgVecType* > WaitingBufType; 327WaitingBufType m_waiting_buffers; 328int m_max_in_port_rank; 329int m_cur_in_port_rank; 330static ${ident}_ProfileDumper s_profileDumper; 331${ident}_Profiler m_profiler; 332static int m_num_controllers; 333 334// Internal functions 335''') 336 337 for func in self.functions: 338 proto = func.prototype 339 if proto: 340 code('$proto') 341 342 if self.EntryType != None: 343 code(''' 344 345// Set and Reset for cache_entry variable 346void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 347void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 348''') 349 350 if self.TBEType != None: 351 code(''' 352 353// Set and Reset for tbe variable 354void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 355void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 356''') 357 358 code(''' 359 360// Actions 361''') 362 if self.TBEType != None and self.EntryType != None: 363 for action in self.actions.itervalues(): 364 code('/** \\brief ${{action.desc}} */') 365 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 366 elif self.TBEType != None: 367 for action in self.actions.itervalues(): 368 code('/** \\brief ${{action.desc}} */') 369 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);') 370 elif self.EntryType != None: 371 for action in self.actions.itervalues(): 372 code('/** \\brief ${{action.desc}} */') 373 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 374 else: 375 for action in self.actions.itervalues(): 376 code('/** \\brief ${{action.desc}} */') 377 code('void ${{action.ident}}(const Address& addr);') 378 379 # the controller internal variables 380 code(''' 381 382// Objects 383''') 384 for var in self.objects: 385 th = var.get("template_hack", "") 386 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 387 388 if var.type.ident == "MessageBuffer": 389 self.message_buffer_names.append("m_%s_ptr" % var.c_ident) 390 391 code.dedent() 392 code('};') 393 code('#endif // __${ident}_CONTROLLER_H__') 394 code.write(path, '%s.hh' % c_ident) 395 396 def printControllerCC(self, path): 397 '''Output the actions for performing the actions''' 398 399 code = self.symtab.codeFormatter() 400 ident = self.ident 401 c_ident = "%s_Controller" % self.ident 402 403 code(''' 404/** \\file $c_ident.cc 405 * 406 * Auto generated C++ code started by $__file__:$__line__ 407 * Created by slicc definition of Module "${{self.short}}" 408 */ 409 410#include <cassert> 411#include <sstream> 412#include <string> 413 414#include "base/cprintf.hh" 415#include "debug/RubyGenerated.hh" 416#include "debug/RubySlicc.hh" 417#include "mem/protocol/${ident}_Controller.hh" 418#include "mem/protocol/${ident}_Event.hh" 419#include "mem/protocol/${ident}_State.hh" 420#include "mem/protocol/Types.hh" 421#include "mem/ruby/common/Global.hh" 422#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 423#include "mem/ruby/system/System.hh" 424 425using namespace std; 426''') 427 428 # include object classes 429 seen_types = set() 430 for var in self.objects: 431 if var.type.ident not in seen_types and not var.type.isPrimitive: 432 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 433 seen_types.add(var.type.ident) 434 435 code(''' 436$c_ident * 437${c_ident}Params::create() 438{ 439 return new $c_ident(this); 440} 441 442int $c_ident::m_num_controllers = 0; 443${ident}_ProfileDumper $c_ident::s_profileDumper; 444 445// for adding information to the protocol debug trace 446stringstream ${ident}_transitionComment; 447#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 448 449/** \\brief constructor */ 450$c_ident::$c_ident(const Params *p) 451 : AbstractController(p) 452{ 453 m_version = p->version; 454 m_transitions_per_cycle = p->transitions_per_cycle; 455 m_buffer_size = p->buffer_size; 456 m_recycle_latency = p->recycle_latency; 457 m_number_of_TBEs = p->number_of_TBEs; 458 m_is_blocking = false; 459''') 460 # 461 # max_port_rank is used to size vectors and thus should be one plus the 462 # largest port rank 463 # 464 max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1 465 code(' m_max_in_port_rank = $max_port_rank;') 466 code.indent() 467 468 # 469 # After initializing the universal machine parameters, initialize the 470 # this machines config parameters. Also detemine if these configuration 471 # params include a sequencer. This information will be used later for 472 # contecting the sequencer back to the L1 cache controller. 473 # 474 contains_dma_sequencer = False 475 sequencers = [] 476 for param in self.config_parameters: 477 if param.name == "dma_sequencer": 478 contains_dma_sequencer = True 479 elif re.compile("sequencer").search(param.name): 480 sequencers.append(param.name) 481 if param.pointer: 482 code('m_${{param.name}}_ptr = p->${{param.name}};') 483 else: 484 code('m_${{param.name}} = p->${{param.name}};') 485 486 # 487 # For the l1 cache controller, add the special atomic support which 488 # includes passing the sequencer a pointer to the controller. 489 # 490 if self.ident == "L1Cache": 491 if not sequencers: 492 self.error("The L1Cache controller must include the sequencer " \ 493 "configuration parameter") 494 495 for seq in sequencers: 496 code(''' 497m_${{seq}}_ptr->setController(this); 498 ''') 499 # 500 # For the DMA controller, pass the sequencer a pointer to the 501 # controller. 502 # 503 if self.ident == "DMA": 504 if not contains_dma_sequencer: 505 self.error("The DMA controller must include the sequencer " \ 506 "configuration parameter") 507 508 code(''' 509m_dma_sequencer_ptr->setController(this); 510''') 511 512 code('m_num_controllers++;') 513 for var in self.objects: 514 if var.ident.find("mandatoryQueue") >= 0: 515 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();') 516 517 code.dedent() 518 code(''' 519} 520 521void 522$c_ident::init() 523{ 524 MachineType machine_type; 525 int base; 526 527 m_machineID.type = MachineType_${ident}; 528 m_machineID.num = m_version; 529 530 // initialize objects 531 m_profiler.setVersion(m_version); 532 s_profileDumper.registerProfiler(&m_profiler); 533 534''') 535 536 code.indent() 537 for var in self.objects: 538 vtype = var.type 539 vid = "m_%s_ptr" % var.c_ident 540 if "network" not in var: 541 # Not a network port object 542 if "primitive" in vtype: 543 code('$vid = new ${{vtype.c_ident}};') 544 if "default" in var: 545 code('(*$vid) = ${{var["default"]}};') 546 else: 547 # Normal Object 548 # added by SS 549 if "factory" in var: 550 code('$vid = ${{var["factory"]}};') 551 elif var.ident.find("mandatoryQueue") < 0: 552 th = var.get("template_hack", "") 553 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 554 555 args = "" 556 if "non_obj" not in vtype and not vtype.isEnumeration: 557 if expr.find("TBETable") >= 0: 558 args = "m_number_of_TBEs" 559 else: 560 args = var.get("constructor_hack", "") 561 562 code('$expr($args);') 563 564 code('assert($vid != NULL);') 565 566 if "default" in var: 567 code('*$vid = ${{var["default"]}}; // Object default') 568 elif "default" in vtype: 569 comment = "Type %s default" % vtype.ident 570 code('*$vid = ${{vtype["default"]}}; // $comment') 571 572 # Set ordering 573 if "ordered" in var and "trigger_queue" not in var: 574 # A buffer 575 code('$vid->setOrdering(${{var["ordered"]}});') 576 577 # Set randomization 578 if "random" in var: 579 # A buffer 580 code('$vid->setRandomization(${{var["random"]}});') 581 582 # Set Priority 583 if vtype.isBuffer and \ 584 "rank" in var and "trigger_queue" not in var: 585 code('$vid->setPriority(${{var["rank"]}});') 586 587 else: 588 # Network port object 589 network = var["network"] 590 ordered = var["ordered"] 591 vnet = var["virtual_network"] 592 vnet_type = var["vnet_type"] 593 594 assert var.machine is not None 595 code(''' 596machine_type = string_to_MachineType("${{var.machine.ident}}"); 597base = MachineType_base_number(machine_type); 598$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type"); 599''') 600 601 code('assert($vid != NULL);') 602 603 # Set ordering 604 if "ordered" in var: 605 # A buffer 606 code('$vid->setOrdering(${{var["ordered"]}});') 607 608 # Set randomization 609 if "random" in var: 610 # A buffer 611 code('$vid->setRandomization(${{var["random"]}});') 612 613 # Set Priority 614 if "rank" in var: 615 code('$vid->setPriority(${{var["rank"]}})') 616 617 # Set buffer size 618 if vtype.isBuffer: 619 code(''' 620if (m_buffer_size > 0) { 621 $vid->resize(m_buffer_size); 622} 623''') 624 625 # set description (may be overriden later by port def) 626 code(''' 627$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]"); 628 629''') 630 631 if vtype.isBuffer: 632 if "recycle_latency" in var: 633 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});') 634 else: 635 code('$vid->setRecycleLatency(m_recycle_latency);') 636 637 638 # Set the queue consumers 639 code() 640 for port in self.in_ports: 641 code('${{port.code}}.setConsumer(this);') 642 643 # Set the queue descriptions 644 code() 645 for port in self.in_ports: 646 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");') 647 648 # Initialize the transition profiling 649 code() 650 for trans in self.transitions: 651 # Figure out if we stall 652 stall = False 653 for action in trans.actions: 654 if action.ident == "z_stall": 655 stall = True 656 657 # Only possible if it is not a 'z' case 658 if not stall: 659 state = "%s_State_%s" % (self.ident, trans.state.ident) 660 event = "%s_Event_%s" % (self.ident, trans.event.ident) 661 code('m_profiler.possibleTransition($state, $event);') 662 663 code.dedent() 664 code('}') 665 666 has_mandatory_q = False 667 for port in self.in_ports: 668 if port.code.find("mandatoryQueue_ptr") >= 0: 669 has_mandatory_q = True 670 671 if has_mandatory_q: 672 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 673 else: 674 mq_ident = "NULL" 675 676 code(''' 677int 678$c_ident::getNumControllers() 679{ 680 return m_num_controllers; 681} 682 683MessageBuffer* 684$c_ident::getMandatoryQueue() const 685{ 686 return $mq_ident; 687} 688 689const int & 690$c_ident::getVersion() const 691{ 692 return m_version; 693} 694 695const string 696$c_ident::toString() const 697{ 698 return "$c_ident"; 699} 700 701const string 702$c_ident::getName() const 703{ 704 return m_name; 705} 706 707const MachineType 708$c_ident::getMachineType() const 709{ 710 return MachineType_${ident}; 711} 712 713void 714$c_ident::stallBuffer(MessageBuffer* buf, Address addr) 715{ 716 if (m_waiting_buffers.count(addr) == 0) { 717 MsgVecType* msgVec = new MsgVecType; 718 msgVec->resize(m_max_in_port_rank, NULL); 719 m_waiting_buffers[addr] = msgVec; 720 } 721 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf; 722} 723 724void 725$c_ident::wakeUpBuffers(Address addr) 726{ 727 if (m_waiting_buffers.count(addr) > 0) { 728 // 729 // Wake up all possible lower rank (i.e. lower priority) buffers that could 730 // be waiting on this message. 731 // 732 for (int in_port_rank = m_cur_in_port_rank - 1; 733 in_port_rank >= 0; 734 in_port_rank--) { 735 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) { 736 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr); 737 } 738 } 739 delete m_waiting_buffers[addr]; 740 m_waiting_buffers.erase(addr); 741 } 742} 743 744void 745$c_ident::wakeUpAllBuffers() 746{ 747 // 748 // Wake up all possible buffers that could be waiting on any message. 749 // 750 751 std::vector<MsgVecType*> wokeUpMsgVecs; 752 753 if(m_waiting_buffers.size() > 0) { 754 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin(); 755 buf_iter != m_waiting_buffers.end(); 756 ++buf_iter) { 757 for (MsgVecType::iterator vec_iter = buf_iter->second->begin(); 758 vec_iter != buf_iter->second->end(); 759 ++vec_iter) { 760 if (*vec_iter != NULL) { 761 (*vec_iter)->reanalyzeAllMessages(); 762 } 763 } 764 wokeUpMsgVecs.push_back(buf_iter->second); 765 } 766 767 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin(); 768 wb_iter != wokeUpMsgVecs.end(); 769 ++wb_iter) { 770 delete (*wb_iter); 771 } 772 773 m_waiting_buffers.clear(); 774 } 775} 776 777void 778$c_ident::blockOnQueue(Address addr, MessageBuffer* port) 779{ 780 m_is_blocking = true; 781 m_block_map[addr] = port; 782} 783 784void 785$c_ident::unblock(Address addr) 786{ 787 m_block_map.erase(addr); 788 if (m_block_map.size() == 0) { 789 m_is_blocking = false; 790 } 791} 792 793void 794$c_ident::print(ostream& out) const 795{ 796 out << "[$c_ident " << m_version << "]"; 797} 798 799void 800$c_ident::printConfig(ostream& out) const 801{ 802 out << "$c_ident config: " << m_name << endl; 803 out << " version: " << m_version << endl; 804 map<string, string>::const_iterator it; 805 for (it = m_cfg.begin(); it != m_cfg.end(); it++) 806 out << " " << it->first << ": " << it->second << endl; 807} 808 809void 810$c_ident::printStats(ostream& out) const 811{ 812''') 813 # 814 # Cache and Memory Controllers have specific profilers associated with 815 # them. Print out these stats before dumping state transition stats. 816 # 817 for param in self.config_parameters: 818 if param.type_ast.type.ident == "CacheMemory" or \ 819 param.type_ast.type.ident == "DirectoryMemory" or \ 820 param.type_ast.type.ident == "MemoryControl": 821 assert(param.pointer) 822 code(' m_${{param.ident}}_ptr->printStats(out);') 823 824 code(''' 825 if (m_version == 0) { 826 s_profileDumper.dumpStats(out); 827 } 828} 829 830void $c_ident::clearStats() { 831''') 832 # 833 # Cache and Memory Controllers have specific profilers associated with 834 # them. These stats must be cleared too. 835 # 836 for param in self.config_parameters: 837 if param.type_ast.type.ident == "CacheMemory" or \ 838 param.type_ast.type.ident == "MemoryControl": 839 assert(param.pointer) 840 code(' m_${{param.ident}}_ptr->clearStats();') 841 842 code(''' 843 m_profiler.clearStats(); 844} 845''') 846 847 if self.EntryType != None: 848 code(''' 849 850// Set and Reset for cache_entry variable 851void 852$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 853{ 854 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 855} 856 857void 858$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 859{ 860 m_cache_entry_ptr = 0; 861} 862''') 863 864 if self.TBEType != None: 865 code(''' 866 867// Set and Reset for tbe variable 868void 869$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 870{ 871 m_tbe_ptr = m_new_tbe; 872} 873 874void 875$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 876{ 877 m_tbe_ptr = NULL; 878} 879''') 880 881 code(''' 882 883// Actions 884''') 885 if self.TBEType != None and self.EntryType != None: 886 for action in self.actions.itervalues(): 887 if "c_code" not in action: 888 continue 889 890 code(''' 891/** \\brief ${{action.desc}} */ 892void 893$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 894{ 895 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 896 ${{action["c_code"]}} 897} 898 899''') 900 elif self.TBEType != None: 901 for action in self.actions.itervalues(): 902 if "c_code" not in action: 903 continue 904 905 code(''' 906/** \\brief ${{action.desc}} */ 907void 908$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 909{ 910 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 911 ${{action["c_code"]}} 912} 913 914''') 915 elif self.EntryType != None: 916 for action in self.actions.itervalues(): 917 if "c_code" not in action: 918 continue 919 920 code(''' 921/** \\brief ${{action.desc}} */ 922void 923$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 924{ 925 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 926 ${{action["c_code"]}} 927} 928 929''') 930 else: 931 for action in self.actions.itervalues(): 932 if "c_code" not in action: 933 continue 934 935 code(''' 936/** \\brief ${{action.desc}} */ 937void 938$c_ident::${{action.ident}}(const Address& addr) 939{ 940 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 941 ${{action["c_code"]}} 942} 943 944''') 945 for func in self.functions: 946 code(func.generateCode()) 947 948 code.write(path, "%s.cc" % c_ident) 949 950 def printCWakeup(self, path): 951 '''Output the wakeup loop for the events''' 952 953 code = self.symtab.codeFormatter() 954 ident = self.ident 955 956 code(''' 957// Auto generated C++ code started by $__file__:$__line__ 958// ${ident}: ${{self.short}} 959 960#include <cassert> 961 962#include "base/misc.hh" 963#include "debug/RubySlicc.hh" 964#include "mem/protocol/${ident}_Controller.hh" 965#include "mem/protocol/${ident}_Event.hh" 966#include "mem/protocol/${ident}_State.hh" 967#include "mem/protocol/Types.hh" 968#include "mem/ruby/common/Global.hh" 969#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 970#include "mem/ruby/system/System.hh" 971 972using namespace std; 973 974void 975${ident}_Controller::wakeup() 976{ 977 int counter = 0; 978 while (true) { 979 // Some cases will put us into an infinite loop without this limit 980 assert(counter <= m_transitions_per_cycle); 981 if (counter == m_transitions_per_cycle) { 982 // Count how often we are fully utilized 983 g_system_ptr->getProfiler()->controllerBusy(m_machineID); 984 985 // Wakeup in another cycle and try again 986 g_eventQueue_ptr->scheduleEvent(this, 1); 987 break; 988 } 989''') 990 991 code.indent() 992 code.indent() 993 994 # InPorts 995 # 996 for port in self.in_ports: 997 code.indent() 998 code('// ${ident}InPort $port') 999 if port.pairs.has_key("rank"): 1000 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};') 1001 else: 1002 code('m_cur_in_port_rank = 0;') 1003 code('${{port["c_code_in_port"]}}') 1004 code.dedent() 1005 1006 code('') 1007 1008 code.dedent() 1009 code.dedent() 1010 code(''' 1011 break; // If we got this far, we have nothing left todo 1012 } 1013 // g_eventQueue_ptr->scheduleEvent(this, 1); 1014} 1015''') 1016 1017 code.write(path, "%s_Wakeup.cc" % self.ident) 1018 1019 def printCSwitch(self, path): 1020 '''Output switch statement for transition table''' 1021 1022 code = self.symtab.codeFormatter() 1023 ident = self.ident 1024 1025 code(''' 1026// Auto generated C++ code started by $__file__:$__line__ 1027// ${ident}: ${{self.short}} 1028 1029#include <cassert> 1030 1031#include "base/misc.hh" 1032#include "base/trace.hh" 1033#include "debug/ProtocolTrace.hh" 1034#include "debug/RubyGenerated.hh" 1035#include "mem/protocol/${ident}_Controller.hh" 1036#include "mem/protocol/${ident}_Event.hh" 1037#include "mem/protocol/${ident}_State.hh" 1038#include "mem/protocol/Types.hh" 1039#include "mem/ruby/common/Global.hh" 1040#include "mem/ruby/system/System.hh" 1041 1042#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1043 1044#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1045#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1046 1047TransitionResult 1048${ident}_Controller::doTransition(${ident}_Event event, 1049''') 1050 if self.EntryType != None: 1051 code(''' 1052 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1053''') 1054 if self.TBEType != None: 1055 code(''' 1056 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1057''') 1058 code(''' 1059 const Address &addr) 1060{ 1061''') 1062 if self.TBEType != None and self.EntryType != None: 1063 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1064 elif self.TBEType != None: 1065 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1066 elif self.EntryType != None: 1067 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1068 else: 1069 code('${ident}_State state = getState(addr);') 1070 1071 code(''' 1072 ${ident}_State next_state = state; 1073 1074 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1075 *this, 1076 g_eventQueue_ptr->getTime(), 1077 ${ident}_State_to_string(state), 1078 ${ident}_Event_to_string(event), 1079 addr); 1080 1081 TransitionResult result = 1082''') 1083 if self.TBEType != None and self.EntryType != None: 1084 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1085 elif self.TBEType != None: 1086 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1087 elif self.EntryType != None: 1088 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1089 else: 1090 code('doTransitionWorker(event, state, next_state, addr);') 1091 1092 code(''' 1093 if (result == TransitionResult_Valid) { 1094 DPRINTF(RubyGenerated, "next_state: %s\\n", 1095 ${ident}_State_to_string(next_state)); 1096 m_profiler.countTransition(state, event); 1097 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1098 curTick(), m_version, "${ident}", 1099 ${ident}_Event_to_string(event), 1100 ${ident}_State_to_string(state), 1101 ${ident}_State_to_string(next_state), 1102 addr, GET_TRANSITION_COMMENT()); 1103 1104 CLEAR_TRANSITION_COMMENT(); 1105''') 1106 if self.TBEType != None and self.EntryType != None: 1107 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1108 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1109 elif self.TBEType != None: 1110 code('setState(m_tbe_ptr, addr, next_state);') 1111 code('setAccessPermission(addr, next_state);') 1112 elif self.EntryType != None: 1113 code('setState(m_cache_entry_ptr, addr, next_state);') 1114 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1115 else: 1116 code('setState(addr, next_state);') 1117 code('setAccessPermission(addr, next_state);') 1118 1119 code(''' 1120 } else if (result == TransitionResult_ResourceStall) { 1121 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1122 curTick(), m_version, "${ident}", 1123 ${ident}_Event_to_string(event), 1124 ${ident}_State_to_string(state), 1125 ${ident}_State_to_string(next_state), 1126 addr, "Resource Stall"); 1127 } else if (result == TransitionResult_ProtocolStall) { 1128 DPRINTF(RubyGenerated, "stalling\\n"); 1129 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1130 curTick(), m_version, "${ident}", 1131 ${ident}_Event_to_string(event), 1132 ${ident}_State_to_string(state), 1133 ${ident}_State_to_string(next_state), 1134 addr, "Protocol Stall"); 1135 } 1136 1137 return result; 1138} 1139 1140TransitionResult 1141${ident}_Controller::doTransitionWorker(${ident}_Event event, 1142 ${ident}_State state, 1143 ${ident}_State& next_state, 1144''') 1145 1146 if self.TBEType != None: 1147 code(''' 1148 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1149''') 1150 if self.EntryType != None: 1151 code(''' 1152 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1153''') 1154 code(''' 1155 const Address& addr) 1156{ 1157 switch(HASH_FUN(state, event)) { 1158''') 1159 1160 # This map will allow suppress generating duplicate code 1161 cases = orderdict() 1162 1163 for trans in self.transitions: 1164 case_string = "%s_State_%s, %s_Event_%s" % \ 1165 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1166 1167 case = self.symtab.codeFormatter() 1168 # Only set next_state if it changes 1169 if trans.state != trans.nextState: 1170 ns_ident = trans.nextState.ident 1171 case('next_state = ${ident}_State_${ns_ident};') 1172 1173 actions = trans.actions 1174 1175 # Check for resources 1176 case_sorter = [] 1177 res = trans.resources 1178 for key,val in res.iteritems(): 1179 if key.type.ident != "DNUCAStopTable": 1180 val = ''' 1181if (!%s.areNSlotsAvailable(%s)) 1182 return TransitionResult_ResourceStall; 1183''' % (key.code, val) 1184 case_sorter.append(val) 1185 1186 1187 # Emit the code sequences in a sorted order. This makes the 1188 # output deterministic (without this the output order can vary 1189 # since Map's keys() on a vector of pointers is not deterministic 1190 for c in sorted(case_sorter): 1191 case("$c") 1192 1193 # Figure out if we stall 1194 stall = False 1195 for action in actions: 1196 if action.ident == "z_stall": 1197 stall = True 1198 break 1199 1200 if stall: 1201 case('return TransitionResult_ProtocolStall;') 1202 else: 1203 if self.TBEType != None and self.EntryType != None: 1204 for action in actions: 1205 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1206 elif self.TBEType != None: 1207 for action in actions: 1208 case('${{action.ident}}(m_tbe_ptr, addr);') 1209 elif self.EntryType != None: 1210 for action in actions: 1211 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1212 else: 1213 for action in actions: 1214 case('${{action.ident}}(addr);') 1215 case('return TransitionResult_Valid;') 1216 1217 case = str(case) 1218 1219 # Look to see if this transition code is unique. 1220 if case not in cases: 1221 cases[case] = [] 1222 1223 cases[case].append(case_string) 1224 1225 # Walk through all of the unique code blocks and spit out the 1226 # corresponding case statement elements 1227 for case,transitions in cases.iteritems(): 1228 # Iterative over all the multiple transitions that share 1229 # the same code 1230 for trans in transitions: 1231 code(' case HASH_FUN($trans):') 1232 code(' $case') 1233 1234 code(''' 1235 default: 1236 fatal("Invalid transition\\n" 1237 "%s time: %d addr: %s event: %s state: %s\\n", 1238 name(), g_eventQueue_ptr->getTime(), addr, event, state); 1239 } 1240 return TransitionResult_Valid; 1241} 1242''') 1243 code.write(path, "%s_Transitions.cc" % self.ident) 1244 1245 def printProfileDumperHH(self, path): 1246 code = self.symtab.codeFormatter() 1247 ident = self.ident 1248 1249 code(''' 1250// Auto generated C++ code started by $__file__:$__line__ 1251// ${ident}: ${{self.short}} 1252 1253#ifndef __${ident}_PROFILE_DUMPER_HH__ 1254#define __${ident}_PROFILE_DUMPER_HH__ 1255 1256#include <cassert> 1257#include <iostream> 1258#include <vector> 1259 1260#include "${ident}_Event.hh" 1261#include "${ident}_Profiler.hh" 1262 1263typedef std::vector<${ident}_Profiler *> ${ident}_profilers; 1264 1265class ${ident}_ProfileDumper 1266{ 1267 public: 1268 ${ident}_ProfileDumper(); 1269 void registerProfiler(${ident}_Profiler* profiler); 1270 void dumpStats(std::ostream& out) const; 1271 1272 private: 1273 ${ident}_profilers m_profilers; 1274}; 1275 1276#endif // __${ident}_PROFILE_DUMPER_HH__ 1277''') 1278 code.write(path, "%s_ProfileDumper.hh" % self.ident) 1279 1280 def printProfileDumperCC(self, path): 1281 code = self.symtab.codeFormatter() 1282 ident = self.ident 1283 1284 code(''' 1285// Auto generated C++ code started by $__file__:$__line__ 1286// ${ident}: ${{self.short}} 1287 1288#include "mem/protocol/${ident}_ProfileDumper.hh" 1289 1290${ident}_ProfileDumper::${ident}_ProfileDumper() 1291{ 1292} 1293 1294void 1295${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler) 1296{ 1297 m_profilers.push_back(profiler); 1298} 1299 1300void 1301${ident}_ProfileDumper::dumpStats(std::ostream& out) const 1302{ 1303 out << " --- ${ident} ---\\n"; 1304 out << " - Event Counts -\\n"; 1305 for (${ident}_Event event = ${ident}_Event_FIRST; 1306 event < ${ident}_Event_NUM; 1307 ++event) { 1308 out << (${ident}_Event) event << " ["; 1309 uint64 total = 0; 1310 for (int i = 0; i < m_profilers.size(); i++) { 1311 out << m_profilers[i]->getEventCount(event) << " "; 1312 total += m_profilers[i]->getEventCount(event); 1313 } 1314 out << "] " << total << "\\n"; 1315 } 1316 out << "\\n"; 1317 out << " - Transitions -\\n"; 1318 for (${ident}_State state = ${ident}_State_FIRST; 1319 state < ${ident}_State_NUM; 1320 ++state) { 1321 for (${ident}_Event event = ${ident}_Event_FIRST; 1322 event < ${ident}_Event_NUM; 1323 ++event) { 1324 if (m_profilers[0]->isPossible(state, event)) { 1325 out << (${ident}_State) state << " " 1326 << (${ident}_Event) event << " ["; 1327 uint64 total = 0; 1328 for (int i = 0; i < m_profilers.size(); i++) { 1329 out << m_profilers[i]->getTransitionCount(state, event) << " "; 1330 total += m_profilers[i]->getTransitionCount(state, event); 1331 } 1332 out << "] " << total << "\\n"; 1333 } 1334 } 1335 out << "\\n"; 1336 } 1337} 1338''') 1339 code.write(path, "%s_ProfileDumper.cc" % self.ident) 1340 1341 def printProfilerHH(self, path): 1342 code = self.symtab.codeFormatter() 1343 ident = self.ident 1344 1345 code(''' 1346// Auto generated C++ code started by $__file__:$__line__ 1347// ${ident}: ${{self.short}} 1348 1349#ifndef __${ident}_PROFILER_HH__ 1350#define __${ident}_PROFILER_HH__ 1351 1352#include <cassert> 1353#include <iostream> 1354 1355#include "mem/protocol/${ident}_Event.hh" 1356#include "mem/protocol/${ident}_State.hh" 1357#include "mem/ruby/common/Global.hh" 1358 1359class ${ident}_Profiler 1360{ 1361 public: 1362 ${ident}_Profiler(); 1363 void setVersion(int version); 1364 void countTransition(${ident}_State state, ${ident}_Event event); 1365 void possibleTransition(${ident}_State state, ${ident}_Event event); 1366 uint64 getEventCount(${ident}_Event event); 1367 bool isPossible(${ident}_State state, ${ident}_Event event); 1368 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 1369 void clearStats(); 1370 1371 private: 1372 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 1373 int m_event_counters[${ident}_Event_NUM]; 1374 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 1375 int m_version; 1376}; 1377 1378#endif // __${ident}_PROFILER_HH__ 1379''') 1380 code.write(path, "%s_Profiler.hh" % self.ident) 1381 1382 def printProfilerCC(self, path): 1383 code = self.symtab.codeFormatter() 1384 ident = self.ident 1385 1386 code(''' 1387// Auto generated C++ code started by $__file__:$__line__ 1388// ${ident}: ${{self.short}} 1389 1390#include <cassert> 1391 1392#include "mem/protocol/${ident}_Profiler.hh" 1393 1394${ident}_Profiler::${ident}_Profiler() 1395{ 1396 for (int state = 0; state < ${ident}_State_NUM; state++) { 1397 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1398 m_possible[state][event] = false; 1399 m_counters[state][event] = 0; 1400 } 1401 } 1402 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1403 m_event_counters[event] = 0; 1404 } 1405} 1406 1407void 1408${ident}_Profiler::setVersion(int version) 1409{ 1410 m_version = version; 1411} 1412 1413void 1414${ident}_Profiler::clearStats() 1415{ 1416 for (int state = 0; state < ${ident}_State_NUM; state++) { 1417 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1418 m_counters[state][event] = 0; 1419 } 1420 } 1421 1422 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1423 m_event_counters[event] = 0; 1424 } 1425} 1426void 1427${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1428{ 1429 assert(m_possible[state][event]); 1430 m_counters[state][event]++; 1431 m_event_counters[event]++; 1432} 1433void 1434${ident}_Profiler::possibleTransition(${ident}_State state, 1435 ${ident}_Event event) 1436{ 1437 m_possible[state][event] = true; 1438} 1439 1440uint64 1441${ident}_Profiler::getEventCount(${ident}_Event event) 1442{ 1443 return m_event_counters[event]; 1444} 1445 1446bool 1447${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event) 1448{ 1449 return m_possible[state][event]; 1450} 1451 1452uint64 1453${ident}_Profiler::getTransitionCount(${ident}_State state, 1454 ${ident}_Event event) 1455{ 1456 return m_counters[state][event]; 1457} 1458 1459''') 1460 code.write(path, "%s_Profiler.cc" % self.ident) 1461 1462 # ************************** 1463 # ******* HTML Files ******* 1464 # ************************** 1465 def frameRef(self, click_href, click_target, over_href, over_num, text): 1466 code = self.symtab.codeFormatter(fix_newlines=False) 1467 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1468 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1469 parent.frames[$over_num].location='$over_href' 1470 }\"> 1471 ${{html.formatShorthand(text)}} 1472 </A>""") 1473 return str(code) 1474 1475 def writeHTMLFiles(self, path): 1476 # Create table with no row hilighted 1477 self.printHTMLTransitions(path, None) 1478 1479 # Generate transition tables 1480 for state in self.states.itervalues(): 1481 self.printHTMLTransitions(path, state) 1482 1483 # Generate action descriptions 1484 for action in self.actions.itervalues(): 1485 name = "%s_action_%s.html" % (self.ident, action.ident) 1486 code = html.createSymbol(action, "Action") 1487 code.write(path, name) 1488 1489 # Generate state descriptions 1490 for state in self.states.itervalues(): 1491 name = "%s_State_%s.html" % (self.ident, state.ident) 1492 code = html.createSymbol(state, "State") 1493 code.write(path, name) 1494 1495 # Generate event descriptions 1496 for event in self.events.itervalues(): 1497 name = "%s_Event_%s.html" % (self.ident, event.ident) 1498 code = html.createSymbol(event, "Event") 1499 code.write(path, name) 1500 1501 def printHTMLTransitions(self, path, active_state): 1502 code = self.symtab.codeFormatter() 1503 1504 code(''' 1505<HTML> 1506<BODY link="blue" vlink="blue"> 1507 1508<H1 align="center">${{html.formatShorthand(self.short)}}: 1509''') 1510 code.indent() 1511 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1512 mid = machine.ident 1513 if i != 0: 1514 extra = " - " 1515 else: 1516 extra = "" 1517 if machine == self: 1518 code('$extra$mid') 1519 else: 1520 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1521 code.dedent() 1522 1523 code(""" 1524</H1> 1525 1526<TABLE border=1> 1527<TR> 1528 <TH> </TH> 1529""") 1530 1531 for event in self.events.itervalues(): 1532 href = "%s_Event_%s.html" % (self.ident, event.ident) 1533 ref = self.frameRef(href, "Status", href, "1", event.short) 1534 code('<TH bgcolor=white>$ref</TH>') 1535 1536 code('</TR>') 1537 # -- Body of table 1538 for state in self.states.itervalues(): 1539 # -- Each row 1540 if state == active_state: 1541 color = "yellow" 1542 else: 1543 color = "white" 1544 1545 click = "%s_table_%s.html" % (self.ident, state.ident) 1546 over = "%s_State_%s.html" % (self.ident, state.ident) 1547 text = html.formatShorthand(state.short) 1548 ref = self.frameRef(click, "Table", over, "1", state.short) 1549 code(''' 1550<TR> 1551 <TH bgcolor=$color>$ref</TH> 1552''') 1553 1554 # -- One column for each event 1555 for event in self.events.itervalues(): 1556 trans = self.table.get((state,event), None) 1557 if trans is None: 1558 # This is the no transition case 1559 if state == active_state: 1560 color = "#C0C000" 1561 else: 1562 color = "lightgrey" 1563 1564 code('<TD bgcolor=$color> </TD>') 1565 continue 1566 1567 next = trans.nextState 1568 stall_action = False 1569 1570 # -- Get the actions 1571 for action in trans.actions: 1572 if action.ident == "z_stall" or \ 1573 action.ident == "zz_recycleMandatoryQueue": 1574 stall_action = True 1575 1576 # -- Print out "actions/next-state" 1577 if stall_action: 1578 if state == active_state: 1579 color = "#C0C000" 1580 else: 1581 color = "lightgrey" 1582 1583 elif active_state and next.ident == active_state.ident: 1584 color = "aqua" 1585 elif state == active_state: 1586 color = "yellow" 1587 else: 1588 color = "white" 1589 1590 code('<TD bgcolor=$color>') 1591 for action in trans.actions: 1592 href = "%s_action_%s.html" % (self.ident, action.ident) 1593 ref = self.frameRef(href, "Status", href, "1", 1594 action.short) 1595 code(' $ref') 1596 if next != state: 1597 if trans.actions: 1598 code('/') 1599 click = "%s_table_%s.html" % (self.ident, next.ident) 1600 over = "%s_State_%s.html" % (self.ident, next.ident) 1601 ref = self.frameRef(click, "Table", over, "1", next.short) 1602 code("$ref") 1603 code("</TD>") 1604 1605 # -- Each row 1606 if state == active_state: 1607 color = "yellow" 1608 else: 1609 color = "white" 1610 1611 click = "%s_table_%s.html" % (self.ident, state.ident) 1612 over = "%s_State_%s.html" % (self.ident, state.ident) 1613 ref = self.frameRef(click, "Table", over, "1", state.short) 1614 code(''' 1615 <TH bgcolor=$color>$ref</TH> 1616</TR> 1617''') 1618 code(''' 1619<!- Column footer-> 1620<TR> 1621 <TH> </TH> 1622''') 1623 1624 for event in self.events.itervalues(): 1625 href = "%s_Event_%s.html" % (self.ident, event.ident) 1626 ref = self.frameRef(href, "Status", href, "1", event.short) 1627 code('<TH bgcolor=white>$ref</TH>') 1628 code(''' 1629</TR> 1630</TABLE> 1631</BODY></HTML> 1632''') 1633 1634 1635 if active_state: 1636 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1637 else: 1638 name = "%s_table.html" % self.ident 1639 code.write(path, name) 1640 1641__all__ = [ "StateMachine" ] 1642