StateMachine.py revision 7056
13970Sgblack@eecs.umich.edu# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 23005Sstever@eecs.umich.edu# Copyright (c) 2009 The Hewlett-Packard Development Company 33005Sstever@eecs.umich.edu# All rights reserved. 43005Sstever@eecs.umich.edu# 53005Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without 63005Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are 73005Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright 83005Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer; 93005Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright 103005Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the 113005Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution; 123005Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its 133005Sstever@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 292889SN/A 302889SN/Afrom slicc.symbols.Symbol import Symbol 312710SN/Afrom slicc.symbols.Var import Var 322710SN/Aimport slicc.generate.html as html 332934SN/A 342934SN/Apython_class_map = {"int": "Int", 352549SN/A "std::string": "String", 362995SN/A "bool": "Bool", 373395Shsul@eecs.umich.edu "CacheMemory": "RubyCache", 383448Shsul@eecs.umich.edu "Sequencer": "RubySequencer", 392549SN/A "DirectoryMemory": "RubyDirectoryMemory", 403088Sstever@eecs.umich.edu "MemoryControl": "RubyMemoryControl", 413088Sstever@eecs.umich.edu "DMASequencer": "DMASequencer" 423088Sstever@eecs.umich.edu } 433444Sktlim@umich.edu 443444Sktlim@umich.educlass StateMachine(Symbol): 453444Sktlim@umich.edu def __init__(self, symtab, ident, location, pairs, config_parameters): 463444Sktlim@umich.edu super(StateMachine, self).__init__(symtab, ident, location, pairs) 472889SN/A self.table = None 482710SN/A self.config_parameters = config_parameters 493873Sbinkertn@umich.edu for param in config_parameters: 503873Sbinkertn@umich.edu if param.pointer: 513873Sbinkertn@umich.edu var = Var(symtab, param.name, location, param.type_ast.type, 523873Sbinkertn@umich.edu "(*m_%s_ptr)" % param.name, {}, self) 533322Shsul@eecs.umich.edu else: 542995SN/A var = Var(symtab, param.name, location, param.type_ast.type, 552995SN/A "m_%s" % param.name, {}, self) 562995SN/A self.symtab.registerSym(param.name, var) 572995SN/A 582995SN/A self.states = orderdict() 593143Shsul@eecs.umich.edu self.events = orderdict() 603322Shsul@eecs.umich.edu self.actions = orderdict() 613322Shsul@eecs.umich.edu self.transitions = [] 623025Ssaidi@eecs.umich.edu self.in_ports = [] 633143Shsul@eecs.umich.edu self.functions = [] 643143Shsul@eecs.umich.edu self.objects = [] 653322Shsul@eecs.umich.edu 663444Sktlim@umich.edu self.message_buffer_names = [] 673322Shsul@eecs.umich.edu 682710SN/A def __repr__(self): 692710SN/A return "[StateMachine: %s]" % self.ident 702710SN/A 712710SN/A def addState(self, state): 722710SN/A assert self.table is None 732710SN/A self.states[state.ident] = state 743322Shsul@eecs.umich.edu 753304Sstever@eecs.umich.edu def addEvent(self, event): 763322Shsul@eecs.umich.edu assert self.table is None 773322Shsul@eecs.umich.edu self.events[event.ident] = event 783304Sstever@eecs.umich.edu 793481Shsul@eecs.umich.edu def addAction(self, action): 803481Shsul@eecs.umich.edu assert self.table is None 812566SN/A 823322Shsul@eecs.umich.edu # Check for duplicate action 833322Shsul@eecs.umich.edu for other in self.actions.itervalues(): 842995SN/A if action.ident == other.ident: 852995SN/A action.warning("Duplicate action definition: %s" % action.ident) 863304Sstever@eecs.umich.edu action.error("Duplicate action definition: %s" % action.ident) 873304Sstever@eecs.umich.edu if action.short == other.short: 883304Sstever@eecs.umich.edu other.warning("Duplicate action shorthand: %s" % other.ident) 892995SN/A other.warning(" shorthand = %s" % other.short) 902995SN/A action.warning("Duplicate action shorthand: %s" % action.ident) 912995SN/A action.error(" shorthand = %s" % action.short) 922917SN/A 932995SN/A self.actions[action.ident] = action 943304Sstever@eecs.umich.edu 952995SN/A def addTransition(self, trans): 963304Sstever@eecs.umich.edu assert self.table is None 973304Sstever@eecs.umich.edu self.transitions.append(trans) 983819Shsul@eecs.umich.edu 993819Shsul@eecs.umich.edu def addInPort(self, var): 1005222Sksewell@umich.edu self.in_ports.append(var) 1015222Sksewell@umich.edu 1023819Shsul@eecs.umich.edu def addFunc(self, func): 1033819Shsul@eecs.umich.edu # register func in the symbol table 1045133Sgblack@eecs.umich.edu self.symtab.registerSym(str(func), func) 1055299Sgblack@eecs.umich.edu self.functions.append(func) 1063819Shsul@eecs.umich.edu 1073819Shsul@eecs.umich.edu def addObject(self, obj): 1083819Shsul@eecs.umich.edu self.objects.append(obj) 1093873Sbinkertn@umich.edu 1103873Sbinkertn@umich.edu # Needs to be called before accessing the table 1113873Sbinkertn@umich.edu def buildTable(self): 1123873Sbinkertn@umich.edu assert self.table is None 1133873Sbinkertn@umich.edu 1143873Sbinkertn@umich.edu table = {} 1153312Sstever@eecs.umich.edu 1163668Srdreslin@umich.edu for trans in self.transitions: 1173668Srdreslin@umich.edu # Track which actions we touch so we know if we use them 1183668Srdreslin@umich.edu # all -- really this should be done for all symbols as 1193668Srdreslin@umich.edu # part of the symbol table, then only trigger it for 1203668Srdreslin@umich.edu # Actions, States, Events, etc. 1213668Srdreslin@umich.edu 1223668Srdreslin@umich.edu for action in trans.actions: 1233322Shsul@eecs.umich.edu action.used = True 1245142Ssaidi@eecs.umich.edu 1255142Ssaidi@eecs.umich.edu index = (trans.state, trans.event) 1265142Ssaidi@eecs.umich.edu if index in table: 1275142Ssaidi@eecs.umich.edu table[index].warning("Duplicate transition: %s" % table[index]) 1285142Ssaidi@eecs.umich.edu trans.error("Duplicate transition: %s" % trans) 1295142Ssaidi@eecs.umich.edu table[index] = trans 1305142Ssaidi@eecs.umich.edu 1315142Ssaidi@eecs.umich.edu # Look at all actions to make sure we used them all 1325142Ssaidi@eecs.umich.edu for action in self.actions.itervalues(): 1333312Sstever@eecs.umich.edu if not action.used: 1343514Sktlim@umich.edu error_msg = "Unused action: %s" % action.ident 1353395Shsul@eecs.umich.edu if "desc" in action: 1363448Shsul@eecs.umich.edu error_msg += ", " + action.desc 1373668Srdreslin@umich.edu action.warning(error_msg) 1383668Srdreslin@umich.edu self.table = table 1393668Srdreslin@umich.edu 1403668Srdreslin@umich.edu def writeCodeFiles(self, path): 1413005Sstever@eecs.umich.edu self.printControllerPython(path) 1424968Sacolyte@umich.edu self.printControllerHH(path) 1434968Sacolyte@umich.edu self.printControllerCC(path) 1444968Sacolyte@umich.edu self.printCSwitch(path) 1455222Sksewell@umich.edu self.printCWakeup(path) 1465254Sksewell@umich.edu self.printProfilerCC(path) 1475222Sksewell@umich.edu self.printProfilerHH(path) 1483005Sstever@eecs.umich.edu 1493819Shsul@eecs.umich.edu for func in self.functions: 1503819Shsul@eecs.umich.edu func.writeCodeFiles(path) 1515222Sksewell@umich.edu 1525222Sksewell@umich.edu def printControllerPython(self, path): 1533819Shsul@eecs.umich.edu code = self.symtab.codeFormatter() 1543819Shsul@eecs.umich.edu ident = self.ident 1555133Sgblack@eecs.umich.edu py_ident = "%s_Controller" % ident 1565133Sgblack@eecs.umich.edu c_ident = "%s_Controller" % self.ident 1573322Shsul@eecs.umich.edu code(''' 1583322Shsul@eecs.umich.edufrom m5.params import * 1594968Sacolyte@umich.edufrom m5.SimObject import SimObject 1604968Sacolyte@umich.edufrom Controller import RubyController 1614837Ssaidi@eecs.umich.edu 1624837Ssaidi@eecs.umich.educlass $py_ident(RubyController): 1634837Ssaidi@eecs.umich.edu type = '$py_ident' 1643322Shsul@eecs.umich.edu''') 1653005Sstever@eecs.umich.edu code.indent() 1664167Sbinkertn@umich.edu for param in self.config_parameters: 1673005Sstever@eecs.umich.edu dflt_str = '' 1683005Sstever@eecs.umich.edu if param.default is not None: 1693005Sstever@eecs.umich.edu dflt_str = str(param.default) + ', ' 1702566SN/A if python_class_map.has_key(param.type_ast.type.c_ident): 1713481Shsul@eecs.umich.edu python_type = python_class_map[param.type_ast.type.c_ident] 172 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 173 else: 174 self.error("Unknown c++ to python class conversion for c++ " \ 175 "type: '%s'. Please update the python_class_map " \ 176 "in StateMachine.py", param.type_ast.type.c_ident) 177 code.dedent() 178 code.write(path, '%s.py' % py_ident) 179 180 181 def printControllerHH(self, path): 182 '''Output the method declarations for the class declaration''' 183 code = self.symtab.codeFormatter() 184 ident = self.ident 185 c_ident = "%s_Controller" % self.ident 186 187 self.message_buffer_names = [] 188 189 code(''' 190/** \\file $c_ident.hh 191 * 192 * Auto generated C++ code started by $__file__:$__line__ 193 * Created by slicc definition of Module "${{self.short}}" 194 */ 195 196#ifndef __${ident}_CONTROLLER_HH__ 197#define __${ident}_CONTROLLER_HH__ 198 199#include <iostream> 200#include <sstream> 201#include <string> 202 203#include "params/$c_ident.hh" 204 205#include "mem/ruby/common/Global.hh" 206#include "mem/ruby/common/Consumer.hh" 207#include "mem/ruby/slicc_interface/AbstractController.hh" 208#include "mem/protocol/TransitionResult.hh" 209#include "mem/protocol/Types.hh" 210#include "mem/protocol/${ident}_Profiler.hh" 211''') 212 213 seen_types = set() 214 for var in self.objects: 215 if var.type.ident not in seen_types and not var.type.isPrimitive: 216 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 217 seen_types.add(var.type.ident) 218 219 # for adding information to the protocol debug trace 220 code(''' 221extern std::stringstream ${ident}_transitionComment; 222 223class $c_ident : public AbstractController 224{ 225// the coherence checker needs to call isBlockExclusive() and isBlockShared() 226// making the Chip a friend class is an easy way to do this for now 227 228public: 229 typedef ${c_ident}Params Params; 230 $c_ident(const Params *p); 231 static int getNumControllers(); 232 void init(); 233 MessageBuffer* getMandatoryQueue() const; 234 const int & getVersion() const; 235 const std::string toString() const; 236 const std::string getName() const; 237 const MachineType getMachineType() const; 238 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; } 239 void print(std::ostream& out) const; 240 void printConfig(std::ostream& out) const; 241 void wakeup(); 242 void printStats(std::ostream& out) const; 243 void clearStats(); 244 void blockOnQueue(Address addr, MessageBuffer* port); 245 void unblock(Address addr); 246 247private: 248''') 249 250 code.indent() 251 # added by SS 252 for param in self.config_parameters: 253 if param.pointer: 254 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 255 else: 256 code('${{param.type_ast.type}} m_${{param.ident}};') 257 258 code(''' 259int m_number_of_TBEs; 260 261TransitionResult doTransition(${ident}_Event event, 262 ${ident}_State state, 263 const Address& addr); 264 265TransitionResult doTransitionWorker(${ident}_Event event, 266 ${ident}_State state, 267 ${ident}_State& next_state, 268 const Address& addr); 269 270std::string m_name; 271int m_transitions_per_cycle; 272int m_buffer_size; 273int m_recycle_latency; 274std::map<std::string, std::string> m_cfg; 275NodeID m_version; 276Network* m_net_ptr; 277MachineID m_machineID; 278bool m_is_blocking; 279std::map<Address, MessageBuffer*> m_block_map; 280${ident}_Profiler s_profiler; 281static int m_num_controllers; 282 283// Internal functions 284''') 285 286 for func in self.functions: 287 proto = func.prototype 288 if proto: 289 code('$proto') 290 291 code(''' 292 293// Actions 294''') 295 for action in self.actions.itervalues(): 296 code('/** \\brief ${{action.desc}} */') 297 code('void ${{action.ident}}(const Address& addr);') 298 299 # the controller internal variables 300 code(''' 301 302// Objects 303''') 304 for var in self.objects: 305 th = var.get("template_hack", "") 306 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 307 308 if var.type.ident == "MessageBuffer": 309 self.message_buffer_names.append("m_%s_ptr" % var.c_ident) 310 311 code.dedent() 312 code('};') 313 code('#endif // __${ident}_CONTROLLER_H__') 314 code.write(path, '%s.hh' % c_ident) 315 316 def printControllerCC(self, path): 317 '''Output the actions for performing the actions''' 318 319 code = self.symtab.codeFormatter() 320 ident = self.ident 321 c_ident = "%s_Controller" % self.ident 322 323 code(''' 324/** \\file $c_ident.cc 325 * 326 * Auto generated C++ code started by $__file__:$__line__ 327 * Created by slicc definition of Module "${{self.short}}" 328 */ 329 330#include <sstream> 331#include <string> 332 333#include "base/cprintf.hh" 334#include "mem/protocol/${ident}_Controller.hh" 335#include "mem/protocol/${ident}_State.hh" 336#include "mem/protocol/${ident}_Event.hh" 337#include "mem/protocol/Types.hh" 338#include "mem/ruby/common/Global.hh" 339#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 340#include "mem/ruby/system/System.hh" 341 342using namespace std; 343''') 344 345 # include object classes 346 seen_types = set() 347 for var in self.objects: 348 if var.type.ident not in seen_types and not var.type.isPrimitive: 349 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 350 seen_types.add(var.type.ident) 351 352 code(''' 353$c_ident * 354${c_ident}Params::create() 355{ 356 return new $c_ident(this); 357} 358 359int $c_ident::m_num_controllers = 0; 360 361// for adding information to the protocol debug trace 362stringstream ${ident}_transitionComment; 363#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 364 365/** \\brief constructor */ 366$c_ident::$c_ident(const Params *p) 367 : AbstractController(p) 368{ 369 m_version = p->version; 370 m_transitions_per_cycle = p->transitions_per_cycle; 371 m_buffer_size = p->buffer_size; 372 m_recycle_latency = p->recycle_latency; 373 m_number_of_TBEs = p->number_of_TBEs; 374 m_is_blocking = false; 375''') 376 code.indent() 377 378 # 379 # After initializing the universal machine parameters, initialize the 380 # this machines config parameters. Also detemine if these configuration 381 # params include a sequencer. This information will be used later for 382 # contecting the sequencer back to the L1 cache controller. 383 # 384 contains_sequencer = False 385 for param in self.config_parameters: 386 if param.name == "sequencer" or param.name == "dma_sequencer": 387 contains_sequencer = True 388 if param.pointer: 389 code('m_${{param.name}}_ptr = p->${{param.name}};') 390 else: 391 code('m_${{param.name}} = p->${{param.name}};') 392 393 # 394 # For the l1 cache controller, add the special atomic support which 395 # includes passing the sequencer a pointer to the controller. 396 # 397 if self.ident == "L1Cache": 398 if not contains_sequencer: 399 self.error("The L1Cache controller must include the sequencer " \ 400 "configuration parameter") 401 402 code(''' 403m_sequencer_ptr->setController(this); 404''') 405 # 406 # For the DMA controller, pass the sequencer a pointer to the 407 # controller. 408 # 409 if self.ident == "DMA": 410 if not contains_sequencer: 411 self.error("The DMA controller must include the sequencer " \ 412 "configuration parameter") 413 414 code(''' 415m_dma_sequencer_ptr->setController(this); 416''') 417 418 code('m_num_controllers++;') 419 for var in self.objects: 420 if var.ident.find("mandatoryQueue") >= 0: 421 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();') 422 423 code.dedent() 424 code(''' 425} 426 427void 428$c_ident::init() 429{ 430 MachineType machine_type; 431 int base; 432 433 m_machineID.type = MachineType_${ident}; 434 m_machineID.num = m_version; 435 436 // initialize objects 437 s_profiler.setVersion(m_version); 438 439''') 440 441 code.indent() 442 for var in self.objects: 443 vtype = var.type 444 vid = "m_%s_ptr" % var.c_ident 445 if "network" not in var: 446 # Not a network port object 447 if "primitive" in vtype: 448 code('$vid = new ${{vtype.c_ident}};') 449 if "default" in var: 450 code('(*$vid) = ${{var["default"]}};') 451 else: 452 # Normal Object 453 # added by SS 454 if "factory" in var: 455 code('$vid = ${{var["factory"]}};') 456 elif var.ident.find("mandatoryQueue") < 0: 457 th = var.get("template_hack", "") 458 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 459 460 args = "" 461 if "non_obj" not in vtype and not vtype.isEnumeration: 462 if expr.find("TBETable") >= 0: 463 args = "m_number_of_TBEs" 464 else: 465 args = var.get("constructor_hack", "") 466 467 code('$expr($args);') 468 469 code('assert($vid != NULL);') 470 471 if "default" in var: 472 code('*$vid = ${{var["default"]}}; // Object default') 473 elif "default" in vtype: 474 comment = "Type %s default" % vtype.ident 475 code('*$vid = ${{vtype["default"]}}; // $comment') 476 477 # Set ordering 478 if "ordered" in var and "trigger_queue" not in var: 479 # A buffer 480 code('$vid->setOrdering(${{var["ordered"]}});') 481 482 # Set randomization 483 if "random" in var: 484 # A buffer 485 code('$vid->setRandomization(${{var["random"]}});') 486 487 # Set Priority 488 if vtype.isBuffer and \ 489 "rank" in var and "trigger_queue" not in var: 490 code('$vid->setPriority(${{var["rank"]}});') 491 else: 492 # Network port object 493 network = var["network"] 494 ordered = var["ordered"] 495 vnet = var["virtual_network"] 496 497 assert var.machine is not None 498 code(''' 499machine_type = string_to_MachineType("${{var.machine.ident}}"); 500base = MachineType_base_number(machine_type); 501$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet); 502''') 503 504 code('assert($vid != NULL);') 505 506 # Set ordering 507 if "ordered" in var: 508 # A buffer 509 code('$vid->setOrdering(${{var["ordered"]}});') 510 511 # Set randomization 512 if "random" in var: 513 # A buffer 514 code('$vid->setRandomization(${{var["random"]}})') 515 516 # Set Priority 517 if "rank" in var: 518 code('$vid->setPriority(${{var["rank"]}})') 519 520 # Set buffer size 521 if vtype.isBuffer: 522 code(''' 523if (m_buffer_size > 0) { 524 $vid->setSize(m_buffer_size); 525} 526''') 527 528 # set description (may be overriden later by port def) 529 code(''' 530$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]"); 531 532''') 533 534 # Set the queue consumers 535 code.insert_newline() 536 for port in self.in_ports: 537 code('${{port.code}}.setConsumer(this);') 538 539 # Set the queue descriptions 540 code.insert_newline() 541 for port in self.in_ports: 542 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");') 543 544 # Initialize the transition profiling 545 code.insert_newline() 546 for trans in self.transitions: 547 # Figure out if we stall 548 stall = False 549 for action in trans.actions: 550 if action.ident == "z_stall": 551 stall = True 552 553 # Only possible if it is not a 'z' case 554 if not stall: 555 state = "%s_State_%s" % (self.ident, trans.state.ident) 556 event = "%s_Event_%s" % (self.ident, trans.event.ident) 557 code('s_profiler.possibleTransition($state, $event);') 558 559 # added by SS to initialize recycle_latency of message buffers 560 for buf in self.message_buffer_names: 561 code("$buf->setRecycleLatency(m_recycle_latency);") 562 563 code.dedent() 564 code('}') 565 566 has_mandatory_q = False 567 for port in self.in_ports: 568 if port.code.find("mandatoryQueue_ptr") >= 0: 569 has_mandatory_q = True 570 571 if has_mandatory_q: 572 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 573 else: 574 mq_ident = "NULL" 575 576 code(''' 577int 578$c_ident::getNumControllers() 579{ 580 return m_num_controllers; 581} 582 583MessageBuffer* 584$c_ident::getMandatoryQueue() const 585{ 586 return $mq_ident; 587} 588 589const int & 590$c_ident::getVersion() const 591{ 592 return m_version; 593} 594 595const string 596$c_ident::toString() const 597{ 598 return "$c_ident"; 599} 600 601const string 602$c_ident::getName() const 603{ 604 return m_name; 605} 606 607const MachineType 608$c_ident::getMachineType() const 609{ 610 return MachineType_${ident}; 611} 612 613void 614$c_ident::blockOnQueue(Address addr, MessageBuffer* port) 615{ 616 m_is_blocking = true; 617 m_block_map[addr] = port; 618} 619 620void 621$c_ident::unblock(Address addr) 622{ 623 m_block_map.erase(addr); 624 if (m_block_map.size() == 0) { 625 m_is_blocking = false; 626 } 627} 628 629void 630$c_ident::print(ostream& out) const 631{ 632 out << "[$c_ident " << m_version << "]"; 633} 634 635void 636$c_ident::printConfig(ostream& out) const 637{ 638 out << "$c_ident config: " << m_name << endl; 639 out << " version: " << m_version << endl; 640 map<string, string>::const_iterator it; 641 for (it = m_cfg.begin(); it != m_cfg.end(); it++) 642 out << " " << it->first << ": " << it->second << endl; 643} 644 645void 646$c_ident::printStats(ostream& out) const 647{ 648''') 649 # 650 # Cache and Memory Controllers have specific profilers associated with 651 # them. Print out these stats before dumping state transition stats. 652 # 653 for param in self.config_parameters: 654 if param.type_ast.type.ident == "CacheMemory" or \ 655 param.type_ast.type.ident == "DirectoryMemory" or \ 656 param.type_ast.type.ident == "MemoryControl": 657 assert(param.pointer) 658 code(' m_${{param.ident}}_ptr->printStats(out);') 659 660 code(''' 661 s_profiler.dumpStats(out); 662} 663 664void $c_ident::clearStats() { 665''') 666 # 667 # Cache and Memory Controllers have specific profilers associated with 668 # them. These stats must be cleared too. 669 # 670 for param in self.config_parameters: 671 if param.type_ast.type.ident == "CacheMemory" or \ 672 param.type_ast.type.ident == "MemoryControl": 673 assert(param.pointer) 674 code(' m_${{param.ident}}_ptr->clearStats();') 675 676 code(''' 677 s_profiler.clearStats(); 678} 679 680// Actions 681''') 682 683 for action in self.actions.itervalues(): 684 if "c_code" not in action: 685 continue 686 687 code(''' 688/** \\brief ${{action.desc}} */ 689void 690$c_ident::${{action.ident}}(const Address& addr) 691{ 692 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing"); 693 ${{action["c_code"]}} 694} 695 696''') 697 code.write(path, "%s.cc" % c_ident) 698 699 def printCWakeup(self, path): 700 '''Output the wakeup loop for the events''' 701 702 code = self.symtab.codeFormatter() 703 ident = self.ident 704 705 code(''' 706// Auto generated C++ code started by $__file__:$__line__ 707// ${ident}: ${{self.short}} 708 709#include "base/misc.hh" 710#include "mem/ruby/common/Global.hh" 711#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 712#include "mem/protocol/${ident}_Controller.hh" 713#include "mem/protocol/${ident}_State.hh" 714#include "mem/protocol/${ident}_Event.hh" 715#include "mem/protocol/Types.hh" 716#include "mem/ruby/system/System.hh" 717 718using namespace std; 719 720void 721${ident}_Controller::wakeup() 722{ 723 // DEBUG_EXPR(GENERATED_COMP, MedPrio, *this); 724 // DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime()); 725 726 int counter = 0; 727 while (true) { 728 // Some cases will put us into an infinite loop without this limit 729 assert(counter <= m_transitions_per_cycle); 730 if (counter == m_transitions_per_cycle) { 731 // Count how often we are fully utilized 732 g_system_ptr->getProfiler()->controllerBusy(m_machineID); 733 734 // Wakeup in another cycle and try again 735 g_eventQueue_ptr->scheduleEvent(this, 1); 736 break; 737 } 738''') 739 740 code.indent() 741 code.indent() 742 743 # InPorts 744 # 745 for port in self.in_ports: 746 code.indent() 747 code('// ${ident}InPort $port') 748 code('${{port["c_code_in_port"]}}') 749 code.dedent() 750 751 code('') 752 753 code.dedent() 754 code.dedent() 755 code(''' 756 break; // If we got this far, we have nothing left todo 757 } 758 // g_eventQueue_ptr->scheduleEvent(this, 1); 759 // DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 760} 761''') 762 763 code.write(path, "%s_Wakeup.cc" % self.ident) 764 765 def printCSwitch(self, path): 766 '''Output switch statement for transition table''' 767 768 code = self.symtab.codeFormatter() 769 ident = self.ident 770 771 code(''' 772// Auto generated C++ code started by $__file__:$__line__ 773// ${ident}: ${{self.short}} 774 775#include "mem/ruby/common/Global.hh" 776#include "mem/protocol/${ident}_Controller.hh" 777#include "mem/protocol/${ident}_State.hh" 778#include "mem/protocol/${ident}_Event.hh" 779#include "mem/protocol/Types.hh" 780#include "mem/ruby/system/System.hh" 781 782#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 783 784#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 785#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 786 787TransitionResult 788${ident}_Controller::doTransition(${ident}_Event event, 789 ${ident}_State state, 790 const Address &addr) 791{ 792 ${ident}_State next_state = state; 793 794 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 795 DEBUG_MSG(GENERATED_COMP, MedPrio, *this); 796 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime()); 797 DEBUG_EXPR(GENERATED_COMP, MedPrio,state); 798 DEBUG_EXPR(GENERATED_COMP, MedPrio,event); 799 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr); 800 801 TransitionResult result = 802 doTransitionWorker(event, state, next_state, addr); 803 804 if (result == TransitionResult_Valid) { 805 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state); 806 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 807 s_profiler.countTransition(state, event); 808 if (Debug::getProtocolTrace()) { 809 g_system_ptr->getProfiler()->profileTransition("${ident}", 810 m_version, addr, 811 ${ident}_State_to_string(state), 812 ${ident}_Event_to_string(event), 813 ${ident}_State_to_string(next_state), 814 GET_TRANSITION_COMMENT()); 815 } 816 CLEAR_TRANSITION_COMMENT(); 817 ${ident}_setState(addr, next_state); 818 819 } else if (result == TransitionResult_ResourceStall) { 820 if (Debug::getProtocolTrace()) { 821 g_system_ptr->getProfiler()->profileTransition("${ident}", 822 m_version, addr, 823 ${ident}_State_to_string(state), 824 ${ident}_Event_to_string(event), 825 ${ident}_State_to_string(next_state), 826 "Resource Stall"); 827 } 828 } else if (result == TransitionResult_ProtocolStall) { 829 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling"); 830 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 831 if (Debug::getProtocolTrace()) { 832 g_system_ptr->getProfiler()->profileTransition("${ident}", 833 m_version, addr, 834 ${ident}_State_to_string(state), 835 ${ident}_Event_to_string(event), 836 ${ident}_State_to_string(next_state), 837 "Protocol Stall"); 838 } 839 } 840 841 return result; 842} 843 844TransitionResult 845${ident}_Controller::doTransitionWorker(${ident}_Event event, 846 ${ident}_State state, 847 ${ident}_State& next_state, 848 const Address& addr) 849{ 850 switch(HASH_FUN(state, event)) { 851''') 852 853 # This map will allow suppress generating duplicate code 854 cases = orderdict() 855 856 for trans in self.transitions: 857 case_string = "%s_State_%s, %s_Event_%s" % \ 858 (self.ident, trans.state.ident, self.ident, trans.event.ident) 859 860 case = self.symtab.codeFormatter() 861 # Only set next_state if it changes 862 if trans.state != trans.nextState: 863 ns_ident = trans.nextState.ident 864 case('next_state = ${ident}_State_${ns_ident};') 865 866 actions = trans.actions 867 868 # Check for resources 869 case_sorter = [] 870 res = trans.resources 871 for key,val in res.iteritems(): 872 if key.type.ident != "DNUCAStopTable": 873 val = ''' 874if (!%s.areNSlotsAvailable(%s)) 875 return TransitionResult_ResourceStall; 876''' % (key.code, val) 877 case_sorter.append(val) 878 879 880 # Emit the code sequences in a sorted order. This makes the 881 # output deterministic (without this the output order can vary 882 # since Map's keys() on a vector of pointers is not deterministic 883 for c in sorted(case_sorter): 884 case("$c") 885 886 # Figure out if we stall 887 stall = False 888 for action in actions: 889 if action.ident == "z_stall": 890 stall = True 891 break 892 893 if stall: 894 case('return TransitionResult_ProtocolStall;') 895 else: 896 for action in actions: 897 case('${{action.ident}}(addr);') 898 case('return TransitionResult_Valid;') 899 900 case = str(case) 901 902 # Look to see if this transition code is unique. 903 if case not in cases: 904 cases[case] = [] 905 906 cases[case].append(case_string) 907 908 # Walk through all of the unique code blocks and spit out the 909 # corresponding case statement elements 910 for case,transitions in cases.iteritems(): 911 # Iterative over all the multiple transitions that share 912 # the same code 913 for trans in transitions: 914 code(' case HASH_FUN($trans):') 915 code(' $case') 916 917 code(''' 918 default: 919 WARN_EXPR(m_version); 920 WARN_EXPR(g_eventQueue_ptr->getTime()); 921 WARN_EXPR(addr); 922 WARN_EXPR(event); 923 WARN_EXPR(state); 924 ERROR_MSG(\"Invalid transition\"); 925 } 926 return TransitionResult_Valid; 927} 928''') 929 code.write(path, "%s_Transitions.cc" % self.ident) 930 931 def printProfilerHH(self, path): 932 code = self.symtab.codeFormatter() 933 ident = self.ident 934 935 code(''' 936// Auto generated C++ code started by $__file__:$__line__ 937// ${ident}: ${{self.short}} 938 939#ifndef __${ident}_PROFILER_HH_ 940#define __${ident}_PROFILER_HH_ 941 942#include <iostream> 943 944#include "mem/ruby/common/Global.hh" 945#include "mem/protocol/${ident}_State.hh" 946#include "mem/protocol/${ident}_Event.hh" 947 948class ${ident}_Profiler 949{ 950 public: 951 ${ident}_Profiler(); 952 void setVersion(int version); 953 void countTransition(${ident}_State state, ${ident}_Event event); 954 void possibleTransition(${ident}_State state, ${ident}_Event event); 955 void dumpStats(std::ostream& out) const; 956 void clearStats(); 957 958 private: 959 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 960 int m_event_counters[${ident}_Event_NUM]; 961 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 962 int m_version; 963}; 964 965#endif // __${ident}_PROFILER_HH__ 966''') 967 code.write(path, "%s_Profiler.hh" % self.ident) 968 969 def printProfilerCC(self, path): 970 code = self.symtab.codeFormatter() 971 ident = self.ident 972 973 code(''' 974// Auto generated C++ code started by $__file__:$__line__ 975// ${ident}: ${{self.short}} 976 977#include "mem/protocol/${ident}_Profiler.hh" 978 979${ident}_Profiler::${ident}_Profiler() 980{ 981 for (int state = 0; state < ${ident}_State_NUM; state++) { 982 for (int event = 0; event < ${ident}_Event_NUM; event++) { 983 m_possible[state][event] = false; 984 m_counters[state][event] = 0; 985 } 986 } 987 for (int event = 0; event < ${ident}_Event_NUM; event++) { 988 m_event_counters[event] = 0; 989 } 990} 991 992void 993${ident}_Profiler::setVersion(int version) 994{ 995 m_version = version; 996} 997 998void 999${ident}_Profiler::clearStats() 1000{ 1001 for (int state = 0; state < ${ident}_State_NUM; state++) { 1002 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1003 m_counters[state][event] = 0; 1004 } 1005 } 1006 1007 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1008 m_event_counters[event] = 0; 1009 } 1010} 1011void 1012${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1013{ 1014 assert(m_possible[state][event]); 1015 m_counters[state][event]++; 1016 m_event_counters[event]++; 1017} 1018void 1019${ident}_Profiler::possibleTransition(${ident}_State state, 1020 ${ident}_Event event) 1021{ 1022 m_possible[state][event] = true; 1023} 1024 1025void 1026${ident}_Profiler::dumpStats(std::ostream& out) const 1027{ 1028 using namespace std; 1029 1030 out << " --- ${ident} " << m_version << " ---" << endl; 1031 out << " - Event Counts -" << endl; 1032 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1033 int count = m_event_counters[event]; 1034 out << (${ident}_Event) event << " " << count << endl; 1035 } 1036 out << endl; 1037 out << " - Transitions -" << endl; 1038 for (int state = 0; state < ${ident}_State_NUM; state++) { 1039 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1040 if (m_possible[state][event]) { 1041 int count = m_counters[state][event]; 1042 out << (${ident}_State) state << " " 1043 << (${ident}_Event) event << " " << count; 1044 if (count == 0) { 1045 out << " <-- "; 1046 } 1047 out << endl; 1048 } 1049 } 1050 out << endl; 1051 } 1052} 1053''') 1054 code.write(path, "%s_Profiler.cc" % self.ident) 1055 1056 # ************************** 1057 # ******* HTML Files ******* 1058 # ************************** 1059 def frameRef(self, click_href, click_target, over_href, over_num, text): 1060 code = self.symtab.codeFormatter(fix_newlines=False) 1061 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1062 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1063 parent.frames[$over_num].location='$over_href' 1064 }\"> 1065 ${{html.formatShorthand(text)}} 1066 </A>""") 1067 return str(code) 1068 1069 def writeHTMLFiles(self, path): 1070 # Create table with no row hilighted 1071 self.printHTMLTransitions(path, None) 1072 1073 # Generate transition tables 1074 for state in self.states.itervalues(): 1075 self.printHTMLTransitions(path, state) 1076 1077 # Generate action descriptions 1078 for action in self.actions.itervalues(): 1079 name = "%s_action_%s.html" % (self.ident, action.ident) 1080 code = html.createSymbol(action, "Action") 1081 code.write(path, name) 1082 1083 # Generate state descriptions 1084 for state in self.states.itervalues(): 1085 name = "%s_State_%s.html" % (self.ident, state.ident) 1086 code = html.createSymbol(state, "State") 1087 code.write(path, name) 1088 1089 # Generate event descriptions 1090 for event in self.events.itervalues(): 1091 name = "%s_Event_%s.html" % (self.ident, event.ident) 1092 code = html.createSymbol(event, "Event") 1093 code.write(path, name) 1094 1095 def printHTMLTransitions(self, path, active_state): 1096 code = self.symtab.codeFormatter() 1097 1098 code(''' 1099<HTML> 1100<BODY link="blue" vlink="blue"> 1101 1102<H1 align="center">${{html.formatShorthand(self.short)}}: 1103''') 1104 code.indent() 1105 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1106 mid = machine.ident 1107 if i != 0: 1108 extra = " - " 1109 else: 1110 extra = "" 1111 if machine == self: 1112 code('$extra$mid') 1113 else: 1114 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1115 code.dedent() 1116 1117 code(""" 1118</H1> 1119 1120<TABLE border=1> 1121<TR> 1122 <TH> </TH> 1123""") 1124 1125 for event in self.events.itervalues(): 1126 href = "%s_Event_%s.html" % (self.ident, event.ident) 1127 ref = self.frameRef(href, "Status", href, "1", event.short) 1128 code('<TH bgcolor=white>$ref</TH>') 1129 1130 code('</TR>') 1131 # -- Body of table 1132 for state in self.states.itervalues(): 1133 # -- Each row 1134 if state == active_state: 1135 color = "yellow" 1136 else: 1137 color = "white" 1138 1139 click = "%s_table_%s.html" % (self.ident, state.ident) 1140 over = "%s_State_%s.html" % (self.ident, state.ident) 1141 text = html.formatShorthand(state.short) 1142 ref = self.frameRef(click, "Table", over, "1", state.short) 1143 code(''' 1144<TR> 1145 <TH bgcolor=$color>$ref</TH> 1146''') 1147 1148 # -- One column for each event 1149 for event in self.events.itervalues(): 1150 trans = self.table.get((state,event), None) 1151 if trans is None: 1152 # This is the no transition case 1153 if state == active_state: 1154 color = "#C0C000" 1155 else: 1156 color = "lightgrey" 1157 1158 code('<TD bgcolor=$color> </TD>') 1159 continue 1160 1161 next = trans.nextState 1162 stall_action = False 1163 1164 # -- Get the actions 1165 for action in trans.actions: 1166 if action.ident == "z_stall" or \ 1167 action.ident == "zz_recycleMandatoryQueue": 1168 stall_action = True 1169 1170 # -- Print out "actions/next-state" 1171 if stall_action: 1172 if state == active_state: 1173 color = "#C0C000" 1174 else: 1175 color = "lightgrey" 1176 1177 elif active_state and next.ident == active_state.ident: 1178 color = "aqua" 1179 elif state == active_state: 1180 color = "yellow" 1181 else: 1182 color = "white" 1183 1184 code('<TD bgcolor=$color>') 1185 for action in trans.actions: 1186 href = "%s_action_%s.html" % (self.ident, action.ident) 1187 ref = self.frameRef(href, "Status", href, "1", 1188 action.short) 1189 code(' $ref') 1190 if next != state: 1191 if trans.actions: 1192 code('/') 1193 click = "%s_table_%s.html" % (self.ident, next.ident) 1194 over = "%s_State_%s.html" % (self.ident, next.ident) 1195 ref = self.frameRef(click, "Table", over, "1", next.short) 1196 code("$ref") 1197 code("</TD>") 1198 1199 # -- Each row 1200 if state == active_state: 1201 color = "yellow" 1202 else: 1203 color = "white" 1204 1205 click = "%s_table_%s.html" % (self.ident, state.ident) 1206 over = "%s_State_%s.html" % (self.ident, state.ident) 1207 ref = self.frameRef(click, "Table", over, "1", state.short) 1208 code(''' 1209 <TH bgcolor=$color>$ref</TH> 1210</TR> 1211''') 1212 code(''' 1213<!- Column footer-> 1214<TR> 1215 <TH> </TH> 1216''') 1217 1218 for event in self.events.itervalues(): 1219 href = "%s_Event_%s.html" % (self.ident, event.ident) 1220 ref = self.frameRef(href, "Status", href, "1", event.short) 1221 code('<TH bgcolor=white>$ref</TH>') 1222 code(''' 1223</TR> 1224</TABLE> 1225</BODY></HTML> 1226''') 1227 1228 1229 if active_state: 1230 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1231 else: 1232 name = "%s_table.html" % self.ident 1233 code.write(path, name) 1234 1235__all__ = [ "StateMachine" ] 1236