1# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 2# Copyright (c) 2009 The Hewlett-Packard Development Company 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are 7# met: redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer; 9# redistributions in binary form must reproduce the above copyright 10# notice, this list of conditions and the following disclaimer in the 11# documentation and/or other materials provided with the distribution; 12# neither the name of the copyright holders nor the names of its 13# contributors may be used to endorse or promote products derived from 14# this software without specific prior written permission. 15# 16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28from m5.util import code_formatter, orderdict 29 30from slicc.symbols.Symbol import Symbol 31from slicc.symbols.Var import Var 32import slicc.generate.html as html 33 34class StateMachine(Symbol): 35 def __init__(self, symtab, ident, location, pairs, config_parameters): 36 super(StateMachine, self).__init__(symtab, ident, location, pairs) 37 self.table = None 38 self.config_parameters = config_parameters 39 for param in config_parameters: 40 var = Var(symtab, param.name, location, param.type_ast.type, 41 "m_%s" % param.name, {}, self) 42 self.symtab.registerSym(param.name, var) 43 44 self.states = orderdict() 45 self.events = orderdict() 46 self.actions = orderdict() 47 self.transitions = [] 48 self.in_ports = [] 49 self.functions = [] 50 self.objects = [] 51 52 self.message_buffer_names = [] 53 54 def __repr__(self): 55 return "[StateMachine: %s]" % self.ident 56 57 def addState(self, state): 58 assert self.table is None 59 self.states[state.ident] = state 60 61 def addEvent(self, event): 62 assert self.table is None 63 self.events[event.ident] = event 64 65 def addAction(self, action): 66 assert self.table is None 67 68 # Check for duplicate action 69 for other in self.actions.itervalues(): 70 if action.ident == other.ident: 71 action.warning("Duplicate action definition: %s" % action.ident) 72 action.error("Duplicate action definition: %s" % action.ident) 73 if action.short == other.short: 74 other.warning("Duplicate action shorthand: %s" % other.ident) 75 other.warning(" shorthand = %s" % other.short) 76 action.warning("Duplicate action shorthand: %s" % action.ident) 77 action.error(" shorthand = %s" % action.short) 78 79 self.actions[action.ident] = action 80 81 def addTransition(self, trans): 82 assert self.table is None 83 self.transitions.append(trans) 84 85 def addInPort(self, var): 86 self.in_ports.append(var) 87 88 def addFunc(self, func): 89 # register func in the symbol table 90 self.symtab.registerSym(str(func), func) 91 self.functions.append(func) 92 93 def addObject(self, obj): 94 self.objects.append(obj) 95 96 # Needs to be called before accessing the table 97 def buildTable(self): 98 assert self.table is None 99 100 table = {} 101 102 for trans in self.transitions: 103 # Track which actions we touch so we know if we use them 104 # all -- really this should be done for all symbols as 105 # part of the symbol table, then only trigger it for 106 # Actions, States, Events, etc. 107 108 for action in trans.actions: 109 action.used = True 110 111 index = (trans.state, trans.event) 112 if index in table: 113 table[index].warning("Duplicate transition: %s" % table[index]) 114 trans.error("Duplicate transition: %s" % trans) 115 table[index] = trans 116 117 # Look at all actions to make sure we used them all 118 for action in self.actions.itervalues(): 119 if not action.used: 120 error_msg = "Unused action: %s" % action.ident 121 if "desc" in action: 122 error_msg += ", " + action.desc 123 action.warning(error_msg) 124 self.table = table 125 126 def writeCodeFiles(self, path): 127 self.printControllerHH(path) 128 self.printControllerCC(path) 129 self.printCSwitch(path) 130 self.printCWakeup(path) 131 self.printProfilerCC(path) 132 self.printProfilerHH(path) 133 134 for func in self.functions: 135 func.writeCodeFiles(path) 136 137 def printControllerHH(self, path): 138 '''Output the method declarations for the class declaration''' 139 code = code_formatter() 140 ident = self.ident 141 c_ident = "%s_Controller" % self.ident 142 143 self.message_buffer_names = [] 144 145 code(''' 146/** \\file $ident.hh 147 * 148 * Auto generated C++ code started by $__file__:$__line__ 149 * Created by slicc definition of Module "${{self.short}}" 150 */ 151 152#ifndef ${ident}_CONTROLLER_H 153#define ${ident}_CONTROLLER_H 154 155#include "mem/ruby/common/Global.hh" 156#include "mem/ruby/common/Consumer.hh" 157#include "mem/ruby/slicc_interface/AbstractController.hh" 158#include "mem/protocol/TransitionResult.hh" 159#include "mem/protocol/Types.hh" 160#include "mem/protocol/${ident}_Profiler.hh" 161''') 162 163 seen_types = set() 164 for var in self.objects: 165 if var.type.ident not in seen_types and not var.type.isPrimitive: 166 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 167 seen_types.add(var.type.ident) 168 169 # for adding information to the protocol debug trace 170 code(''' 171extern stringstream ${ident}_transitionComment; 172 173class $c_ident : public AbstractController { 174#ifdef CHECK_COHERENCE 175#endif /* CHECK_COHERENCE */ 176public: 177 $c_ident(const string & name); 178 static int getNumControllers(); 179 void init(Network* net_ptr, const vector<string> & argv); 180 MessageBuffer* getMandatoryQueue() const; 181 const int & getVersion() const; 182 const string toString() const; 183 const string getName() const; 184 const MachineType getMachineType() const; 185 void print(ostream& out) const; 186 void printConfig(ostream& out) const; 187 void wakeup(); 188 void set_atomic(Address addr);
|
189 void started_writes();
190 void clear_atomic();
|
189 void clear_atomic(Address addr); 190 void reset_atomics(); |
191 void printStats(ostream& out) const { s_profiler.dumpStats(out); } 192 void clearStats() { s_profiler.clearStats(); } 193private: 194''') 195 196 code.indent() 197 # added by SS 198 for param in self.config_parameters: 199 code('int m_${{param.ident}};') 200 201 if self.ident == "L1Cache": 202 code(''' 203int servicing_atomic;
|
204bool started_receiving_writes;
|
204Address locked_read_request1; 205Address locked_read_request2; 206Address locked_read_request3; 207Address locked_read_request4; 208int read_counter; 209''') 210 211 code(''' 212int m_number_of_TBEs; 213 214TransitionResult doTransition(${ident}_Event event, ${ident}_State state, const Address& addr); // in ${ident}_Transitions.cc 215TransitionResult doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr); // in ${ident}_Transitions.cc 216string m_name; 217int m_transitions_per_cycle; 218int m_buffer_size; 219int m_recycle_latency; 220map< string, string > m_cfg; 221NodeID m_version; 222Network* m_net_ptr; 223MachineID m_machineID; 224${ident}_Profiler s_profiler; 225static int m_num_controllers; 226// Internal functions 227''') 228 229 for func in self.functions: 230 proto = func.prototype 231 if proto: 232 code('$proto') 233 234 code(''' 235 236// Actions 237''') 238 for action in self.actions.itervalues(): 239 code('/** \\brief ${{action.desc}} */') 240 code('void ${{action.ident}}(const Address& addr);') 241 242 # the controller internal variables 243 code(''' 244 245// Object 246''') 247 for var in self.objects: 248 th = var.get("template_hack", "") 249 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 250 251 if var.type.ident == "MessageBuffer": 252 self.message_buffer_names.append("m_%s_ptr" % var.c_ident) 253 254 code.dedent() 255 code('};') 256 code('#endif // ${ident}_CONTROLLER_H') 257 code.write(path, '%s.hh' % c_ident) 258 259 def printControllerCC(self, path): 260 '''Output the actions for performing the actions''' 261 262 code = code_formatter() 263 ident = self.ident 264 c_ident = "%s_Controller" % self.ident 265 266 code(''' 267/** \\file $ident.cc 268 * 269 * Auto generated C++ code started by $__file__:$__line__ 270 * Created by slicc definition of Module "${{self.short}}" 271 */ 272 273#include "mem/ruby/common/Global.hh" 274#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 275#include "mem/protocol/${ident}_Controller.hh" 276#include "mem/protocol/${ident}_State.hh" 277#include "mem/protocol/${ident}_Event.hh" 278#include "mem/protocol/Types.hh" 279#include "mem/ruby/system/System.hh" 280''') 281 282 # include object classes 283 seen_types = set() 284 for var in self.objects: 285 if var.type.ident not in seen_types and not var.type.isPrimitive: 286 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 287 seen_types.add(var.type.ident) 288 289 code(''' 290int $c_ident::m_num_controllers = 0; 291 292stringstream ${ident}_transitionComment; 293#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 294/** \\brief constructor */ 295$c_ident::$c_ident(const string &name) 296 : m_name(name) 297{ 298''') 299 code.indent() 300 if self.ident == "L1Cache": 301 code(''' 302servicing_atomic = 0;
|
304started_receiving_writes = false;
|
303locked_read_request1 = Address(-1); 304locked_read_request2 = Address(-1); 305locked_read_request3 = Address(-1); 306locked_read_request4 = Address(-1); 307read_counter = 0; 308''') 309 310 code('m_num_controllers++;') 311 for var in self.objects: 312 if var.ident.find("mandatoryQueue") >= 0: 313 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();') 314 315 code.dedent() 316 code(''' 317} 318 319void $c_ident::init(Network *net_ptr, const vector<string> &argv) 320{ 321 for (size_t i = 0; i < argv.size(); i += 2) { 322 if (argv[i] == "version") 323 m_version = atoi(argv[i+1].c_str()); 324 else if (argv[i] == "transitions_per_cycle") 325 m_transitions_per_cycle = atoi(argv[i+1].c_str()); 326 else if (argv[i] == "buffer_size") 327 m_buffer_size = atoi(argv[i+1].c_str()); 328 else if (argv[i] == "recycle_latency") 329 m_recycle_latency = atoi(argv[i+1].c_str()); 330 else if (argv[i] == "number_of_TBEs") 331 m_number_of_TBEs = atoi(argv[i+1].c_str()); 332''') 333 334 code.indent() 335 code.indent() 336 for param in self.config_parameters: 337 code('else if (argv[i] == "${{param.name}}")') 338 if param.type_ast.type.ident == "int": 339 code(' m_${{param.name}} = atoi(argv[i+1].c_str());') 340 elif param.type_ast.type.ident == "bool": 341 code(' m_${{param.name}} = string_to_bool(argv[i+1]);') 342 else: 343 self.error("only int and bool parameters are "\ 344 "currently supported") 345 code.dedent() 346 code.dedent() 347 code(''' 348 } 349 350 m_net_ptr = net_ptr; 351 m_machineID.type = MachineType_${ident}; 352 m_machineID.num = m_version; 353 for (size_t i = 0; i < argv.size(); i += 2) { 354 if (argv[i] != "version") 355 m_cfg[argv[i]] = argv[i+1]; 356 } 357 358 // Objects 359 s_profiler.setVersion(m_version); 360''') 361 362 code.indent() 363 for var in self.objects: 364 vtype = var.type 365 vid = "m_%s_ptr" % var.c_ident 366 if "network" not in var: 367 # Not a network port object 368 if "primitive" in vtype: 369 code('$vid = new ${{vtype.c_ident}};') 370 if "default" in var: 371 code('(*$vid) = ${{var["default"]}};') 372 else: 373 # Normal Object 374 # added by SS 375 if "factory" in var: 376 code('$vid = ${{var["factory"]}};') 377 elif var.ident.find("mandatoryQueue") < 0: 378 th = var.get("template_hack", "") 379 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 380 381 args = "" 382 if "non_obj" not in vtype and not vtype.isEnumeration: 383 if expr.find("TBETable") >= 0: 384 args = "m_number_of_TBEs" 385 else: 386 args = var.get("constructor_hack", "") 387 args = "(%s)" % args 388 389 code('$expr$args;') 390 else: 391 code(';') 392 393 code('assert($vid != NULL);') 394 395 if "default" in var: 396 code('(*$vid) = ${{var["default"]}}; // Object default') 397 elif "default" in vtype: 398 code('(*$vid) = ${{vtype["default"]}}; // Type ${{vtype.ident}} default') 399 400 # Set ordering 401 if "ordered" in var and "trigger_queue" not in var: 402 # A buffer 403 code('$vid->setOrdering(${{var["ordered"]}});') 404 405 # Set randomization 406 if "random" in var: 407 # A buffer 408 code('$vid->setRandomization(${{var["random"]}});') 409 410 # Set Priority 411 if vtype.isBuffer and \ 412 "rank" in var and "trigger_queue" not in var: 413 code('$vid->setPriority(${{var["rank"]}});') 414 else: 415 # Network port object 416 network = var["network"] 417 ordered = var["ordered"] 418 vnet = var["virtual_network"] 419 420 assert var.machine is not None 421 code(''' 422$vid = m_net_ptr->get${network}NetQueue(m_version+MachineType_base_number(string_to_MachineType("${{var.machine.ident}}")), $ordered, $vnet); 423''') 424 425 code('assert($vid != NULL);') 426 427 # Set ordering 428 if "ordered" in var: 429 # A buffer 430 code('$vid->setOrdering(${{var["ordered"]}});') 431 432 # Set randomization 433 if "random" in var: 434 # A buffer 435 code('$vid->setRandomization(${{var["random"]}})') 436 437 # Set Priority 438 if "rank" in var: 439 code('$vid->setPriority(${{var["rank"]}})') 440 441 # Set buffer size 442 if vtype.isBuffer: 443 code(''' 444if (m_buffer_size > 0) { 445 $vid->setSize(m_buffer_size); 446} 447''') 448 449 # set description (may be overriden later by port def) 450 code('$vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");') 451 452 # Set the queue consumers 453 code.insert_newline() 454 for port in self.in_ports: 455 code('${{port.code}}.setConsumer(this);') 456 457 # Set the queue descriptions 458 code.insert_newline() 459 for port in self.in_ports: 460 code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");') 461 462 # Initialize the transition profiling 463 code.insert_newline() 464 for trans in self.transitions: 465 # Figure out if we stall 466 stall = False 467 for action in trans.actions: 468 if action.ident == "z_stall": 469 stall = True 470 471 # Only possible if it is not a 'z' case 472 if not stall: 473 state = "%s_State_%s" % (self.ident, trans.state.ident) 474 event = "%s_Event_%s" % (self.ident, trans.event.ident) 475 code('s_profiler.possibleTransition($state, $event);') 476 477 # added by SS to initialize recycle_latency of message buffers 478 for buf in self.message_buffer_names: 479 code("$buf->setRecycleLatency(m_recycle_latency);") 480 481 code.dedent() 482 code('}') 483 484 has_mandatory_q = False 485 for port in self.in_ports: 486 if port.code.find("mandatoryQueue_ptr") >= 0: 487 has_mandatory_q = True 488 489 if has_mandatory_q: 490 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 491 else: 492 mq_ident = "NULL" 493 494 code(''' 495int $c_ident::getNumControllers() { 496 return m_num_controllers; 497} 498 499MessageBuffer* $c_ident::getMandatoryQueue() const { 500 return $mq_ident; 501} 502 503const int & $c_ident::getVersion() const{ 504 return m_version; 505} 506 507const string $c_ident::toString() const{ 508 return "$c_ident"; 509} 510 511const string $c_ident::getName() const{ 512 return m_name; 513} 514const MachineType $c_ident::getMachineType() const{ 515 return MachineType_${ident}; 516} 517 518void $c_ident::print(ostream& out) const { out << "[$c_ident " << m_version << "]"; } 519 520void $c_ident::printConfig(ostream& out) const { 521 out << "$c_ident config: " << m_name << endl; 522 out << " version: " << m_version << endl; 523 for (map<string, string>::const_iterator it = m_cfg.begin(); it != m_cfg.end(); it++) { 524 out << " " << (*it).first << ": " << (*it).second << endl; 525 } 526} 527 528// Actions 529''') 530 531 for action in self.actions.itervalues(): 532 if "c_code" not in action: 533 continue 534 535 code(''' 536/** \\brief ${{action.desc}} */ 537void $c_ident::${{action.ident}}(const Address& addr) 538{ 539 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing"); 540 ${{action["c_code"]}} 541} 542 543''') 544 code.write(path, "%s.cc" % c_ident) 545 546 def printCWakeup(self, path): 547 '''Output the wakeup loop for the events''' 548 549 code = code_formatter() 550 ident = self.ident 551 552 code(''' 553// Auto generated C++ code started by $__file__:$__line__ 554// ${ident}: ${{self.short}} 555 556#include "mem/ruby/common/Global.hh" 557#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 558#include "mem/protocol/${ident}_Controller.hh" 559#include "mem/protocol/${ident}_State.hh" 560#include "mem/protocol/${ident}_Event.hh" 561#include "mem/protocol/Types.hh" 562#include "mem/ruby/system/System.hh" 563 564void ${ident}_Controller::wakeup() 565{ 566 567 int counter = 0; 568 while (true) { 569 // Some cases will put us into an infinite loop without this limit 570 assert(counter <= m_transitions_per_cycle); 571 if (counter == m_transitions_per_cycle) { 572 g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we\'re fully utilized 573 g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again 574 break; 575 } 576''') 577 578 code.indent() 579 code.indent() 580 581 # InPorts 582 # 583 # Find the position of the mandatory queue in the vector so 584 # that we can print it out first 585 586 mandatory_q = None 587 if self.ident == "L1Cache": 588 for i,port in enumerate(self.in_ports): 589 assert "c_code_in_port" in port 590 if str(port).find("mandatoryQueue_in") >= 0: 591 assert mandatory_q is None 592 mandatory_q = port 593 594 assert mandatory_q is not None 595 596 # print out the mandatory queue here 597 port = mandatory_q 598 code('// ${ident}InPort $port') 599 output = port["c_code_in_port"] 600
|
603 pos = output.find("TransitionResult result = doTransition((L1Cache_mandatory_request_type_to_event(((*in_msg_ptr)).m_Type)), L1Cache_getState(addr), addr);")
604 assert pos >= 0
605 atomics_string = '''
606if ((((*in_msg_ptr)).m_Type) == CacheRequestType_ATOMIC) {
607 if (servicing_atomic == 0) {
608 if (locked_read_request1 == Address(-1)) {
609 assert(read_counter == 0);
610 locked_read_request1 = addr;
611 assert(read_counter == 0);
612 read_counter++;
613 }
614 else if (addr == locked_read_request1) {
615 ; // do nothing
616 }
617 else {
618 assert(0); // should never be here if servicing one request at a time
619 }
620 }
621 else if (!started_receiving_writes) {
622 if (servicing_atomic == 1) {
623 if (locked_read_request2 == Address(-1)) {
624 assert(locked_read_request1 != Address(-1));
625 assert(read_counter == 1);
626 locked_read_request2 = addr;
627 assert(read_counter == 1);
628 read_counter++;
629 }
630 else if (addr == locked_read_request2) {
631 ; // do nothing
632 }
633 else {
634 assert(0); // should never be here if servicing one request at a time
635 }
636 }
637 else if (servicing_atomic == 2) {
638 if (locked_read_request3 == Address(-1)) {
639 assert(locked_read_request1 != Address(-1));
640 assert(locked_read_request2 != Address(-1));
641 assert(read_counter == 1);
642 locked_read_request3 = addr;
643 assert(read_counter == 2);
644 read_counter++;
645 }
646 else if (addr == locked_read_request3) {
647 ; // do nothing
648 }
649 else {
650 assert(0); // should never be here if servicing one request at a time
651 }
652 }
653 else if (servicing_atomic == 3) {
654 if (locked_read_request4 == Address(-1)) {
655 assert(locked_read_request1 != Address(-1));
656 assert(locked_read_request2 != Address(-1));
657 assert(locked_read_request3 != Address(-1));
658 assert(read_counter == 1);
659 locked_read_request4 = addr;
660 assert(read_counter == 3);
661 read_counter++;
662 }
663 else if (addr == locked_read_request4) {
664 ; // do nothing
665 }
666 else {
667 assert(0); // should never be here if servicing one request at a time
668 }
669 }
670 else {
671 assert(0);
672 }
673 }
674}
675else {
676 if (servicing_atomic > 0) {
677 // reset
678 servicing_atomic = 0;
679 read_counter = 0;
680 started_receiving_writes = false;
681 locked_read_request1 = Address(-1);
682 locked_read_request2 = Address(-1);
683 locked_read_request3 = Address(-1);
684 locked_read_request4 = Address(-1);
685 }
686}
687'''
688
689 output = output[:pos] + atomics_string + output[pos:]
|
601 code('$output') 602 603 for port in self.in_ports: 604 # don't print out mandatory queue twice 605 if port == mandatory_q: 606 continue 607 608 if ident == "L1Cache":
|
698 if str(port).find("forwardRequestNetwork_in") >= 0:
|
609 if (str(port).find("forwardRequestNetwork_in") >= 0 or str(port).find("requestNetwork_in") >= 0 or str(port).find("requestIntraChipL1Network_in") >= 0): |
610 code(''' 611bool postpone = false; 612if ((((*m_L1Cache_forwardToCache_ptr)).isReady())) { 613 const RequestMsg* in_msg_ptr; 614 in_msg_ptr = dynamic_cast<const RequestMsg*>(((*m_L1Cache_forwardToCache_ptr)).peek());
|
704 if ((((servicing_atomic == 1) && (locked_read_request1 == ((*in_msg_ptr)).m_Address)) ||
705 ((servicing_atomic == 2) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address)) ||
706 ((servicing_atomic == 3) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address || locked_read_request3 == ((*in_msg_ptr)).m_Address)) ||
707 ((servicing_atomic == 4) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address || locked_read_request3 == ((*in_msg_ptr)).m_Address || locked_read_request1 == ((*in_msg_ptr)).m_Address)))) {
708 postpone = true;
|
615 if ((((servicing_atomic > 0) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address || locked_read_request3 == ((*in_msg_ptr)).m_Address || locked_read_request1 == ((*in_msg_ptr)).m_Address)))) { 616 postpone = true; |
617 } 618} 619if (!postpone) { 620''') 621 code.indent() 622 code('// ${ident}InPort $port') 623 code('${{port["c_code_in_port"]}}') 624 code.dedent() 625 626 if ident == "L1Cache":
|
719 if str(port).find("forwardRequestNetwork_in") >= 0:
|
627 if (str(port).find("forwardRequestNetwork_in") >= 0 or str(port).find("requestNetwork_in") >= 0 or str(port).find("requestIntraChipL1Network_in") >= 0): |
628 code.dedent() 629 code('}') 630 code.indent() 631 code('') 632 633 code.dedent() 634 code.dedent() 635 code(''' 636 break; // If we got this far, we have nothing left todo 637 } 638} 639''') 640 641 if self.ident == "L1Cache": 642 code(''' 643void ${ident}_Controller::set_atomic(Address addr) 644{ 645 servicing_atomic++;
|
646 switch (servicing_atomic) { 647 case(1): 648 assert(locked_read_request1 == Address(-1)); 649 locked_read_request1 = addr; 650 break; 651 case(2): 652 assert(locked_read_request2 == Address(-1)); 653 locked_read_request2 = addr; 654 break; 655 case(3): 656 assert(locked_read_request3 == Address(-1)); 657 locked_read_request3 = addr; 658 break; 659 case(4): 660 assert(locked_read_request4 == Address(-1)); 661 locked_read_request4 = addr; 662 break; 663 default: 664 assert(0); 665 666 } |
667} 668
|
740void ${ident}_Controller::started_writes()
|
669void ${ident}_Controller::clear_atomic(Address addr) |
670{
|
742 started_receiving_writes = true;
|
671 672 assert(servicing_atomic > 0); 673 if (addr == locked_read_request1) 674 locked_read_request1 = Address(-1); 675 else if (addr == locked_read_request2) 676 locked_read_request2 = Address(-1); 677 else if (addr == locked_read_request3) 678 locked_read_request3 = Address(-1); 679 else if (addr == locked_read_request4) 680 locked_read_request4 = Address(-1); 681 else 682 assert(0); 683 servicing_atomic--; 684 |
685} 686
|
745void ${ident}_Controller::clear_atomic()
|
687void ${ident}_Controller::reset_atomics() |
688{
|
747 assert(servicing_atomic > 0);
748 read_counter--;
749 servicing_atomic--;
750 if (read_counter == 0) {
751 servicing_atomic = 0;
752 started_receiving_writes = false;
753 locked_read_request1 = Address(-1);
754 locked_read_request2 = Address(-1);
755 locked_read_request3 = Address(-1);
756 locked_read_request4 = Address(-1);
757 }
|
689 690 servicing_atomic = 0; 691 locked_read_request1 = Address(-1); 692 locked_read_request2 = Address(-1); 693 locked_read_request3 = Address(-1); 694 locked_read_request4 = Address(-1); 695 |
696}
|
697 |
698''') 699 else: 700 code('''
|
762void ${ident}_Controller::started_writes()
|
701void ${ident}_Controller::reset_atomics() |
702{ 703 assert(0); 704} 705 706void ${ident}_Controller::set_atomic(Address addr) 707{ 708 assert(0); 709} 710
|
772void ${ident}_Controller::clear_atomic()
|
711void ${ident}_Controller::clear_atomic(Address addr) |
712{ 713 assert(0); 714} 715''') 716 717 718 code.write(path, "%s_Wakeup.cc" % self.ident) 719 720 def printCSwitch(self, path): 721 '''Output switch statement for transition table''' 722 723 code = code_formatter() 724 ident = self.ident 725 726 code(''' 727// Auto generated C++ code started by $__file__:$__line__ 728// ${ident}: ${{self.short}} 729 730#include "mem/ruby/common/Global.hh" 731#include "mem/protocol/${ident}_Controller.hh" 732#include "mem/protocol/${ident}_State.hh" 733#include "mem/protocol/${ident}_Event.hh" 734#include "mem/protocol/Types.hh" 735#include "mem/ruby/system/System.hh" 736 737#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 738 739#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 740#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 741 742TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, ${ident}_State state, const Address& addr 743) 744{ 745 ${ident}_State next_state = state; 746 747 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 748 DEBUG_MSG(GENERATED_COMP, MedPrio, *this); 749 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime()); 750 DEBUG_EXPR(GENERATED_COMP, MedPrio,state); 751 DEBUG_EXPR(GENERATED_COMP, MedPrio,event); 752 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr); 753 754 TransitionResult result = doTransitionWorker(event, state, next_state, addr); 755 756 if (result == TransitionResult_Valid) { 757 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state); 758 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 759 s_profiler.countTransition(state, event); 760 if (Debug::getProtocolTrace()) { 761 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 762 ${ident}_State_to_string(state), 763 ${ident}_Event_to_string(event), 764 ${ident}_State_to_string(next_state), GET_TRANSITION_COMMENT()); 765 } 766 CLEAR_TRANSITION_COMMENT(); 767 ${ident}_setState(addr, next_state); 768 769 } else if (result == TransitionResult_ResourceStall) { 770 if (Debug::getProtocolTrace()) { 771 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 772 ${ident}_State_to_string(state), 773 ${ident}_Event_to_string(event), 774 ${ident}_State_to_string(next_state), 775 "Resource Stall"); 776 } 777 } else if (result == TransitionResult_ProtocolStall) { 778 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling"); 779 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 780 if (Debug::getProtocolTrace()) { 781 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 782 ${ident}_State_to_string(state), 783 ${ident}_Event_to_string(event), 784 ${ident}_State_to_string(next_state), 785 "Protocol Stall"); 786 } 787 } 788 789 return result; 790} 791 792TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr 793) 794{ 795 switch(HASH_FUN(state, event)) { 796''') 797 798 # This map will allow suppress generating duplicate code 799 cases = orderdict() 800 801 for trans in self.transitions: 802 case_string = "%s_State_%s, %s_Event_%s" % \ 803 (self.ident, trans.state.ident, self.ident, trans.event.ident) 804 805 case = code_formatter() 806 # Only set next_state if it changes 807 if trans.state != trans.nextState: 808 ns_ident = trans.nextState.ident 809 case('next_state = ${ident}_State_${ns_ident};') 810 811 actions = trans.actions 812 813 # Check for resources 814 case_sorter = [] 815 res = trans.resources 816 for key,val in res.iteritems(): 817 if key.type.ident != "DNUCAStopTable": 818 val = ''' 819if (!%s.areNSlotsAvailable(%s)) { 820 return TransitionResult_ResourceStall; 821} 822''' % (key.code, val) 823 case_sorter.append(val) 824 825 826 # Emit the code sequences in a sorted order. This makes the 827 # output deterministic (without this the output order can vary 828 # since Map's keys() on a vector of pointers is not deterministic 829 for c in sorted(case_sorter): 830 case("$c") 831 832 # Figure out if we stall 833 stall = False 834 for action in actions: 835 if action.ident == "z_stall": 836 stall = True 837 break 838 839 if stall: 840 case('return TransitionResult_ProtocolStall;') 841 else: 842 for action in actions: 843 case('${{action.ident}}(addr);') 844 case('return TransitionResult_Valid;') 845 846 case = str(case) 847 848 # Look to see if this transition code is unique. 849 if case not in cases: 850 cases[case] = [] 851 852 cases[case].append(case_string) 853 854 # Walk through all of the unique code blocks and spit out the 855 # corresponding case statement elements 856 for case,transitions in cases.iteritems(): 857 # Iterative over all the multiple transitions that share 858 # the same code 859 for trans in transitions: 860 code(' case HASH_FUN($trans):') 861 code(' {') 862 code(' $case') 863 code(' }') 864 865 code(''' 866 default: 867 WARN_EXPR(m_version); 868 WARN_EXPR(g_eventQueue_ptr->getTime()); 869 WARN_EXPR(addr); 870 WARN_EXPR(event); 871 WARN_EXPR(state); 872 ERROR_MSG(\"Invalid transition\"); 873 } 874 return TransitionResult_Valid; 875} 876''') 877 code.write(path, "%s_Transitions.cc" % self.ident) 878 879 def printProfilerHH(self, path): 880 code = code_formatter() 881 ident = self.ident 882 883 code(''' 884// Auto generated C++ code started by $__file__:$__line__ 885// ${ident}: ${{self.short}} 886 887#ifndef ${ident}_PROFILER_H 888#define ${ident}_PROFILER_H 889 890#include "mem/ruby/common/Global.hh" 891#include "mem/protocol/${ident}_State.hh" 892#include "mem/protocol/${ident}_Event.hh" 893 894class ${ident}_Profiler { 895 public: 896 ${ident}_Profiler(); 897 void setVersion(int version); 898 void countTransition(${ident}_State state, ${ident}_Event event); 899 void possibleTransition(${ident}_State state, ${ident}_Event event); 900 void dumpStats(ostream& out) const; 901 void clearStats(); 902 903 private: 904 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 905 int m_event_counters[${ident}_Event_NUM]; 906 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 907 int m_version; 908}; 909 910#endif // ${ident}_PROFILER_H 911''') 912 code.write(path, "%s_Profiler.hh" % self.ident) 913 914 def printProfilerCC(self, path): 915 code = code_formatter() 916 ident = self.ident 917 918 code(''' 919// Auto generated C++ code started by $__file__:$__line__ 920// ${ident}: ${{self.short}} 921 922#include "mem/protocol/${ident}_Profiler.hh" 923 924${ident}_Profiler::${ident}_Profiler() 925{ 926 for (int state = 0; state < ${ident}_State_NUM; state++) { 927 for (int event = 0; event < ${ident}_Event_NUM; event++) { 928 m_possible[state][event] = false; 929 m_counters[state][event] = 0; 930 } 931 } 932 for (int event = 0; event < ${ident}_Event_NUM; event++) { 933 m_event_counters[event] = 0; 934 } 935} 936void ${ident}_Profiler::setVersion(int version) 937{ 938 m_version = version; 939} 940void ${ident}_Profiler::clearStats() 941{ 942 for (int state = 0; state < ${ident}_State_NUM; state++) { 943 for (int event = 0; event < ${ident}_Event_NUM; event++) { 944 m_counters[state][event] = 0; 945 } 946 } 947 948 for (int event = 0; event < ${ident}_Event_NUM; event++) { 949 m_event_counters[event] = 0; 950 } 951} 952void ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 953{ 954 assert(m_possible[state][event]); 955 m_counters[state][event]++; 956 m_event_counters[event]++; 957} 958void ${ident}_Profiler::possibleTransition(${ident}_State state, ${ident}_Event event) 959{ 960 m_possible[state][event] = true; 961} 962void ${ident}_Profiler::dumpStats(ostream& out) const 963{ 964 out << " --- ${ident} " << m_version << " ---" << endl; 965 out << " - Event Counts -" << endl; 966 for (int event = 0; event < ${ident}_Event_NUM; event++) { 967 int count = m_event_counters[event]; 968 out << (${ident}_Event) event << " " << count << endl; 969 } 970 out << endl; 971 out << " - Transitions -" << endl; 972 for (int state = 0; state < ${ident}_State_NUM; state++) { 973 for (int event = 0; event < ${ident}_Event_NUM; event++) { 974 if (m_possible[state][event]) { 975 int count = m_counters[state][event]; 976 out << (${ident}_State) state << " " << (${ident}_Event) event << " " << count; 977 if (count == 0) { 978 out << " <-- "; 979 } 980 out << endl; 981 } 982 } 983 out << endl; 984 } 985} 986''') 987 code.write(path, "%s_Profiler.cc" % self.ident) 988 989 # ************************** 990 # ******* HTML Files ******* 991 # ************************** 992 def frameRef(self, click_href, click_target, over_href, over_target_num, 993 text): 994 code = code_formatter(fix_newlines=False) 995 code("""<A href=\"$click_href\" target=\"$click_target\" onMouseOver=\"if (parent.frames[$over_target_num].location != parent.location + '$over_href') { parent.frames[$over_target_num].location='$over_href' }\" >${{html.formatShorthand(text)}}</A>""") 996 return str(code) 997 998 def writeHTMLFiles(self, path): 999 # Create table with no row hilighted 1000 self.printHTMLTransitions(path, None) 1001 1002 # Generate transition tables 1003 for state in self.states.itervalues(): 1004 self.printHTMLTransitions(path, state) 1005 1006 # Generate action descriptions 1007 for action in self.actions.itervalues(): 1008 name = "%s_action_%s.html" % (self.ident, action.ident) 1009 code = html.createSymbol(action, "Action") 1010 code.write(path, name) 1011 1012 # Generate state descriptions 1013 for state in self.states.itervalues(): 1014 name = "%s_State_%s.html" % (self.ident, state.ident) 1015 code = html.createSymbol(state, "State") 1016 code.write(path, name) 1017 1018 # Generate event descriptions 1019 for event in self.events.itervalues(): 1020 name = "%s_Event_%s.html" % (self.ident, event.ident) 1021 code = html.createSymbol(event, "Event") 1022 code.write(path, name) 1023 1024 def printHTMLTransitions(self, path, active_state): 1025 code = code_formatter() 1026 1027 code(''' 1028<HTML><BODY link="blue" vlink="blue"> 1029 1030<H1 align="center">${{html.formatShorthand(self.short)}}: 1031''') 1032 code.indent() 1033 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1034 mid = machine.ident 1035 if i != 0: 1036 extra = " - " 1037 else: 1038 extra = "" 1039 if machine == self: 1040 code('$extra$mid') 1041 else: 1042 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1043 code.dedent() 1044 1045 code(""" 1046</H1> 1047 1048<TABLE border=1> 1049<TR> 1050 <TH> </TH> 1051""") 1052 1053 for event in self.events.itervalues(): 1054 href = "%s_Event_%s.html" % (self.ident, event.ident) 1055 ref = self.frameRef(href, "Status", href, "1", event.short) 1056 code('<TH bgcolor=white>$ref</TH>') 1057 1058 code('</TR>') 1059 # -- Body of table 1060 for state in self.states.itervalues(): 1061 # -- Each row 1062 if state == active_state: 1063 color = "yellow" 1064 else: 1065 color = "white" 1066 1067 click = "%s_table_%s.html" % (self.ident, state.ident) 1068 over = "%s_State_%s.html" % (self.ident, state.ident) 1069 text = html.formatShorthand(state.short) 1070 ref = self.frameRef(click, "Table", over, "1", state.short) 1071 code(''' 1072<TR> 1073 <TH bgcolor=$color>$ref</TH> 1074''') 1075 1076 # -- One column for each event 1077 for event in self.events.itervalues(): 1078 trans = self.table.get((state,event), None) 1079 if trans is None: 1080 # This is the no transition case 1081 if state == active_state: 1082 color = "#C0C000" 1083 else: 1084 color = "lightgrey" 1085 1086 code('<TD bgcolor=$color> </TD>') 1087 continue 1088 1089 next = trans.nextState 1090 stall_action = False 1091 1092 # -- Get the actions 1093 for action in trans.actions: 1094 if action.ident == "z_stall" or \ 1095 action.ident == "zz_recycleMandatoryQueue": 1096 stall_action = True 1097 1098 # -- Print out "actions/next-state" 1099 if stall_action: 1100 if state == active_state: 1101 color = "#C0C000" 1102 else: 1103 color = "lightgrey" 1104 1105 elif active_state and next.ident == active_state.ident: 1106 color = "aqua" 1107 elif state == active_state: 1108 color = "yellow" 1109 else: 1110 color = "white" 1111 1112 fix = code.nofix() 1113 code('<TD bgcolor=$color>') 1114 for action in trans.actions: 1115 href = "%s_action_%s.html" % (self.ident, action.ident) 1116 ref = self.frameRef(href, "Status", href, "1", 1117 action.short) 1118 code(' $ref\n') 1119 if next != state: 1120 if trans.actions: 1121 code('/') 1122 click = "%s_table_%s.html" % (self.ident, next.ident) 1123 over = "%s_State_%s.html" % (self.ident, next.ident) 1124 ref = self.frameRef(click, "Table", over, "1", next.short) 1125 code("$ref") 1126 code("</TD>\n") 1127 code.fix(fix) 1128 1129 # -- Each row 1130 if state == active_state: 1131 color = "yellow" 1132 else: 1133 color = "white" 1134 1135 click = "%s_table_%s.html" % (self.ident, state.ident) 1136 over = "%s_State_%s.html" % (self.ident, state.ident) 1137 ref = self.frameRef(click, "Table", over, "1", state.short) 1138 code(''' 1139 <TH bgcolor=$color>$ref</TH> 1140</TR> 1141''') 1142 code(''' 1143<TR> 1144 <TH> </TH> 1145''') 1146 1147 for event in self.events.itervalues(): 1148 href = "%s_Event_%s.html" % (self.ident, event.ident) 1149 ref = self.frameRef(href, "Status", href, "1", event.short) 1150 code('<TH bgcolor=white>$ref</TH>') 1151 code(''' 1152</TR> 1153</TABLE> 1154</BODY></HTML> 1155''') 1156 1157 1158 if active_state: 1159 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1160 else: 1161 name = "%s_table.html" % self.ident 1162 code.write(path, name) 1163 1164__all__ = [ "StateMachine" ]
|