49 50class StateMachine(Symbol): 51 def __init__(self, symtab, ident, location, pairs, config_parameters): 52 super(StateMachine, self).__init__(symtab, ident, location, pairs) 53 self.table = None 54 self.config_parameters = config_parameters 55 self.prefetchers = [] 56 57 for param in config_parameters: 58 if param.pointer: 59 var = Var(symtab, param.name, location, param.type_ast.type, 60 "(*m_%s_ptr)" % param.name, {}, self) 61 else: 62 var = Var(symtab, param.name, location, param.type_ast.type, 63 "m_%s" % param.name, {}, self) 64 self.symtab.registerSym(param.name, var) 65 if str(param.type_ast.type) == "Prefetcher": 66 self.prefetchers.append(var) 67 68 self.states = orderdict() 69 self.events = orderdict() 70 self.actions = orderdict() 71 self.request_types = orderdict() 72 self.transitions = [] 73 self.in_ports = [] 74 self.functions = [] 75 self.objects = [] 76 self.TBEType = None 77 self.EntryType = None 78 self.message_buffer_names = [] 79 80 81 def __repr__(self): 82 return "[StateMachine: %s]" % self.ident 83 84 def addState(self, state): 85 assert self.table is None 86 self.states[state.ident] = state 87 88 def addEvent(self, event): 89 assert self.table is None 90 self.events[event.ident] = event 91 92 def addAction(self, action): 93 assert self.table is None 94 95 # Check for duplicate action 96 for other in self.actions.itervalues(): 97 if action.ident == other.ident: 98 action.warning("Duplicate action definition: %s" % action.ident) 99 action.error("Duplicate action definition: %s" % action.ident) 100 if action.short == other.short: 101 other.warning("Duplicate action shorthand: %s" % other.ident) 102 other.warning(" shorthand = %s" % other.short) 103 action.warning("Duplicate action shorthand: %s" % action.ident) 104 action.error(" shorthand = %s" % action.short) 105 106 self.actions[action.ident] = action 107 108 def addRequestType(self, request_type): 109 assert self.table is None 110 self.request_types[request_type.ident] = request_type 111 112 def addTransition(self, trans): 113 assert self.table is None 114 self.transitions.append(trans) 115 116 def addInPort(self, var): 117 self.in_ports.append(var) 118 119 def addFunc(self, func): 120 # register func in the symbol table 121 self.symtab.registerSym(str(func), func) 122 self.functions.append(func) 123 124 def addObject(self, obj): 125 self.objects.append(obj) 126 127 def addType(self, type): 128 type_ident = '%s' % type.c_ident 129 130 if type_ident == "%s_TBE" %self.ident: 131 if self.TBEType != None: 132 self.error("Multiple Transaction Buffer types in a " \ 133 "single machine."); 134 self.TBEType = type 135 136 elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 137 if self.EntryType != None: 138 self.error("Multiple AbstractCacheEntry types in a " \ 139 "single machine."); 140 self.EntryType = type 141 142 # Needs to be called before accessing the table 143 def buildTable(self): 144 assert self.table is None 145 146 table = {} 147 148 for trans in self.transitions: 149 # Track which actions we touch so we know if we use them 150 # all -- really this should be done for all symbols as 151 # part of the symbol table, then only trigger it for 152 # Actions, States, Events, etc. 153 154 for action in trans.actions: 155 action.used = True 156 157 index = (trans.state, trans.event) 158 if index in table: 159 table[index].warning("Duplicate transition: %s" % table[index]) 160 trans.error("Duplicate transition: %s" % trans) 161 table[index] = trans 162 163 # Look at all actions to make sure we used them all 164 for action in self.actions.itervalues(): 165 if not action.used: 166 error_msg = "Unused action: %s" % action.ident 167 if "desc" in action: 168 error_msg += ", " + action.desc 169 action.warning(error_msg) 170 self.table = table 171 172 def writeCodeFiles(self, path, includes): 173 self.printControllerPython(path) 174 self.printControllerHH(path) 175 self.printControllerCC(path, includes) 176 self.printCSwitch(path) 177 self.printCWakeup(path, includes) 178 self.printProfilerCC(path) 179 self.printProfilerHH(path) 180 self.printProfileDumperCC(path) 181 self.printProfileDumperHH(path) 182 183 def printControllerPython(self, path): 184 code = self.symtab.codeFormatter() 185 ident = self.ident 186 py_ident = "%s_Controller" % ident 187 c_ident = "%s_Controller" % self.ident 188 code(''' 189from m5.params import * 190from m5.SimObject import SimObject 191from Controller import RubyController 192 193class $py_ident(RubyController): 194 type = '$py_ident' 195 cxx_header = 'mem/protocol/${c_ident}.hh' 196''') 197 code.indent() 198 for param in self.config_parameters: 199 dflt_str = '' 200 if param.default is not None: 201 dflt_str = str(param.default) + ', ' 202 if python_class_map.has_key(param.type_ast.type.c_ident): 203 python_type = python_class_map[param.type_ast.type.c_ident] 204 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 205 else: 206 self.error("Unknown c++ to python class conversion for c++ " \ 207 "type: '%s'. Please update the python_class_map " \ 208 "in StateMachine.py", param.type_ast.type.c_ident) 209 code.dedent() 210 code.write(path, '%s.py' % py_ident) 211 212 213 def printControllerHH(self, path): 214 '''Output the method declarations for the class declaration''' 215 code = self.symtab.codeFormatter() 216 ident = self.ident 217 c_ident = "%s_Controller" % self.ident 218 219 self.message_buffer_names = [] 220 221 code(''' 222/** \\file $c_ident.hh 223 * 224 * Auto generated C++ code started by $__file__:$__line__ 225 * Created by slicc definition of Module "${{self.short}}" 226 */ 227 228#ifndef __${ident}_CONTROLLER_HH__ 229#define __${ident}_CONTROLLER_HH__ 230 231#include <iostream> 232#include <sstream> 233#include <string> 234 235#include "mem/protocol/${ident}_ProfileDumper.hh" 236#include "mem/protocol/${ident}_Profiler.hh" 237#include "mem/protocol/TransitionResult.hh" 238#include "mem/protocol/Types.hh" 239#include "mem/ruby/common/Consumer.hh" 240#include "mem/ruby/common/Global.hh" 241#include "mem/ruby/slicc_interface/AbstractController.hh" 242#include "params/$c_ident.hh" 243''') 244 245 seen_types = set() 246 for var in self.objects: 247 if var.type.ident not in seen_types and not var.type.isPrimitive: 248 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 249 seen_types.add(var.type.ident) 250 251 # for adding information to the protocol debug trace 252 code(''' 253extern std::stringstream ${ident}_transitionComment; 254 255class $c_ident : public AbstractController 256{ 257 public: 258 typedef ${c_ident}Params Params; 259 $c_ident(const Params *p); 260 static int getNumControllers(); 261 void init(); 262 MessageBuffer* getMandatoryQueue() const; 263 const int & getVersion() const; 264 const std::string toString() const; 265 const std::string getName() const; 266 void stallBuffer(MessageBuffer* buf, Address addr); 267 void wakeUpBuffers(Address addr); 268 void wakeUpAllBuffers(); 269 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; } 270 void print(std::ostream& out) const; 271 void wakeup(); 272 void printStats(std::ostream& out) const; 273 void clearStats(); 274 void blockOnQueue(Address addr, MessageBuffer* port); 275 void unblock(Address addr); 276 void recordCacheTrace(int cntrl, CacheRecorder* tr); 277 Sequencer* getSequencer() const; 278 279 bool functionalReadBuffers(PacketPtr&); 280 uint32_t functionalWriteBuffers(PacketPtr&); 281 282private: 283''') 284 285 code.indent() 286 # added by SS 287 for param in self.config_parameters: 288 if param.pointer: 289 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 290 else: 291 code('${{param.type_ast.type}} m_${{param.ident}};') 292 293 code(''' 294TransitionResult doTransition(${ident}_Event event, 295''') 296 297 if self.EntryType != None: 298 code(''' 299 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 300''') 301 if self.TBEType != None: 302 code(''' 303 ${{self.TBEType.c_ident}}* m_tbe_ptr, 304''') 305 306 code(''' 307 const Address& addr); 308 309TransitionResult doTransitionWorker(${ident}_Event event, 310 ${ident}_State state, 311 ${ident}_State& next_state, 312''') 313 314 if self.TBEType != None: 315 code(''' 316 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 317''') 318 if self.EntryType != None: 319 code(''' 320 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 321''') 322 323 code(''' 324 const Address& addr); 325 326static ${ident}_ProfileDumper s_profileDumper; 327${ident}_Profiler m_profiler; 328static int m_num_controllers; 329 330// Internal functions 331''') 332 333 for func in self.functions: 334 proto = func.prototype 335 if proto: 336 code('$proto') 337 338 if self.EntryType != None: 339 code(''' 340 341// Set and Reset for cache_entry variable 342void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 343void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 344''') 345 346 if self.TBEType != None: 347 code(''' 348 349// Set and Reset for tbe variable 350void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 351void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 352''') 353 354 code(''' 355 356// Actions 357''') 358 if self.TBEType != None and self.EntryType != None: 359 for action in self.actions.itervalues(): 360 code('/** \\brief ${{action.desc}} */') 361 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 362 elif self.TBEType != 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, const Address& addr);') 366 elif self.EntryType != None: 367 for action in self.actions.itervalues(): 368 code('/** \\brief ${{action.desc}} */') 369 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 370 else: 371 for action in self.actions.itervalues(): 372 code('/** \\brief ${{action.desc}} */') 373 code('void ${{action.ident}}(const Address& addr);') 374 375 # the controller internal variables 376 code(''' 377 378// Objects 379''') 380 for var in self.objects: 381 th = var.get("template", "") 382 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 383 384 if var.type.ident == "MessageBuffer": 385 self.message_buffer_names.append("m_%s_ptr" % var.c_ident) 386 387 code.dedent() 388 code('};') 389 code('#endif // __${ident}_CONTROLLER_H__') 390 code.write(path, '%s.hh' % c_ident) 391 392 def printControllerCC(self, path, includes): 393 '''Output the actions for performing the actions''' 394 395 code = self.symtab.codeFormatter() 396 ident = self.ident 397 c_ident = "%s_Controller" % self.ident 398 399 code(''' 400/** \\file $c_ident.cc 401 * 402 * Auto generated C++ code started by $__file__:$__line__ 403 * Created by slicc definition of Module "${{self.short}}" 404 */ 405 406#include <sys/types.h> 407#include <unistd.h> 408 409#include <cassert> 410#include <sstream> 411#include <string> 412 413#include "base/compiler.hh" 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/system/System.hh" 423''') 424 for include_path in includes: 425 code('#include "${{include_path}}"') 426 427 code(''' 428 429using namespace std; 430''') 431 432 # include object classes 433 seen_types = set() 434 for var in self.objects: 435 if var.type.ident not in seen_types and not var.type.isPrimitive: 436 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 437 seen_types.add(var.type.ident) 438 439 code(''' 440$c_ident * 441${c_ident}Params::create() 442{ 443 return new $c_ident(this); 444} 445 446int $c_ident::m_num_controllers = 0; 447${ident}_ProfileDumper $c_ident::s_profileDumper; 448 449// for adding information to the protocol debug trace 450stringstream ${ident}_transitionComment; 451#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 452 453/** \\brief constructor */ 454$c_ident::$c_ident(const Params *p) 455 : AbstractController(p) 456{ 457 m_name = "${ident}"; 458''') 459 # 460 # max_port_rank is used to size vectors and thus should be one plus the 461 # largest port rank 462 # 463 max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1 464 code(' m_max_in_port_rank = $max_port_rank;') 465 code.indent() 466 467 # 468 # After initializing the universal machine parameters, initialize the 469 # this machines config parameters. Also detemine if these configuration 470 # params include a sequencer. This information will be used later for 471 # contecting the sequencer back to the L1 cache controller. 472 # 473 contains_dma_sequencer = False 474 sequencers = [] 475 for param in self.config_parameters: 476 if param.name == "dma_sequencer": 477 contains_dma_sequencer = True 478 elif re.compile("sequencer").search(param.name): 479 sequencers.append(param.name) 480 if param.pointer: 481 code('m_${{param.name}}_ptr = p->${{param.name}};') 482 else: 483 code('m_${{param.name}} = p->${{param.name}};') 484 485 # 486 # For the l1 cache controller, add the special atomic support which 487 # includes passing the sequencer a pointer to the controller. 488 # 489 if self.ident == "L1Cache": 490 if not sequencers: 491 self.error("The L1Cache controller must include the sequencer " \ 492 "configuration parameter") 493 494 for seq in sequencers: 495 code(''' 496m_${{seq}}_ptr->setController(this); 497 ''') 498 499 else: 500 for seq in sequencers: 501 code(''' 502m_${{seq}}_ptr->setController(this); 503 ''') 504 505 # 506 # For the DMA controller, pass the sequencer a pointer to the 507 # controller. 508 # 509 if self.ident == "DMA": 510 if not contains_dma_sequencer: 511 self.error("The DMA controller must include the sequencer " \ 512 "configuration parameter") 513 514 code(''' 515m_dma_sequencer_ptr->setController(this); 516''') 517 518 code('m_num_controllers++;') 519 for var in self.objects: 520 if var.ident.find("mandatoryQueue") >= 0: 521 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();') 522 523 code.dedent() 524 code(''' 525} 526 527void 528$c_ident::init() 529{ 530 MachineType machine_type; 531 int base; 532 machine_type = string_to_MachineType("${{var.machine.ident}}"); 533 base = MachineType_base_number(machine_type); 534 535 m_machineID.type = MachineType_${ident}; 536 m_machineID.num = m_version; 537 538 // initialize objects 539 m_profiler.setVersion(m_version); 540 s_profileDumper.registerProfiler(&m_profiler); 541 542''') 543 544 code.indent() 545 for var in self.objects: 546 vtype = var.type 547 vid = "m_%s_ptr" % var.c_ident 548 if "network" not in var: 549 # Not a network port object 550 if "primitive" in vtype: 551 code('$vid = new ${{vtype.c_ident}};') 552 if "default" in var: 553 code('(*$vid) = ${{var["default"]}};') 554 else: 555 # Normal Object 556 # added by SS 557 if "factory" in var: 558 code('$vid = ${{var["factory"]}};') 559 elif var.ident.find("mandatoryQueue") < 0: 560 th = var.get("template", "") 561 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 562 args = "" 563 if "non_obj" not in vtype and not vtype.isEnumeration: 564 args = var.get("constructor", "") 565 code('$expr($args);') 566 567 code('assert($vid != NULL);') 568 569 if "default" in var: 570 code('*$vid = ${{var["default"]}}; // Object default') 571 elif "default" in vtype: 572 comment = "Type %s default" % vtype.ident 573 code('*$vid = ${{vtype["default"]}}; // $comment') 574 575 # Set ordering 576 if "ordered" in var and "trigger_queue" not in var: 577 # A buffer 578 code('$vid->setOrdering(${{var["ordered"]}});') 579 580 # Set randomization 581 if "random" in var: 582 # A buffer 583 code('$vid->setRandomization(${{var["random"]}});') 584 585 # Set Priority 586 if vtype.isBuffer and \ 587 "rank" in var and "trigger_queue" not in var: 588 code('$vid->setPriority(${{var["rank"]}});') 589 590 else: 591 # Network port object 592 network = var["network"] 593 ordered = var["ordered"] 594 vnet = var["virtual_network"] 595 vnet_type = var["vnet_type"] 596 597 assert var.machine is not None 598 code(''' 599$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type"); 600''') 601 602 code('assert($vid != NULL);') 603 604 # Set ordering 605 if "ordered" in var: 606 # A buffer 607 code('$vid->setOrdering(${{var["ordered"]}});') 608 609 # Set randomization 610 if "random" in var: 611 # A buffer 612 code('$vid->setRandomization(${{var["random"]}});') 613 614 # Set Priority 615 if "rank" in var: 616 code('$vid->setPriority(${{var["rank"]}})') 617 618 # Set buffer size 619 if vtype.isBuffer: 620 code(''' 621if (m_buffer_size > 0) { 622 $vid->resize(m_buffer_size); 623} 624''') 625 626 # set description (may be overriden later by port def) 627 code(''' 628$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]"); 629 630''') 631 632 if vtype.isBuffer: 633 if "recycle_latency" in var:
|
1062 break; 1063 } 1064''') 1065 1066 code.indent() 1067 code.indent() 1068 1069 # InPorts 1070 # 1071 for port in self.in_ports: 1072 code.indent() 1073 code('// ${ident}InPort $port') 1074 if port.pairs.has_key("rank"): 1075 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};') 1076 else: 1077 code('m_cur_in_port_rank = 0;') 1078 code('${{port["c_code_in_port"]}}') 1079 code.dedent() 1080 1081 code('') 1082 1083 code.dedent() 1084 code.dedent() 1085 code(''' 1086 break; // If we got this far, we have nothing left todo 1087 } 1088} 1089''') 1090 1091 code.write(path, "%s_Wakeup.cc" % self.ident) 1092 1093 def printCSwitch(self, path): 1094 '''Output switch statement for transition table''' 1095 1096 code = self.symtab.codeFormatter() 1097 ident = self.ident 1098 1099 code(''' 1100// Auto generated C++ code started by $__file__:$__line__ 1101// ${ident}: ${{self.short}} 1102 1103#include <cassert> 1104 1105#include "base/misc.hh" 1106#include "base/trace.hh" 1107#include "debug/ProtocolTrace.hh" 1108#include "debug/RubyGenerated.hh" 1109#include "mem/protocol/${ident}_Controller.hh" 1110#include "mem/protocol/${ident}_Event.hh" 1111#include "mem/protocol/${ident}_State.hh" 1112#include "mem/protocol/Types.hh" 1113#include "mem/ruby/common/Global.hh" 1114#include "mem/ruby/system/System.hh" 1115 1116#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1117 1118#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1119#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1120 1121TransitionResult 1122${ident}_Controller::doTransition(${ident}_Event event, 1123''') 1124 if self.EntryType != None: 1125 code(''' 1126 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1127''') 1128 if self.TBEType != None: 1129 code(''' 1130 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1131''') 1132 code(''' 1133 const Address &addr) 1134{ 1135''') 1136 if self.TBEType != None and self.EntryType != None: 1137 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1138 elif self.TBEType != None: 1139 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1140 elif self.EntryType != None: 1141 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1142 else: 1143 code('${ident}_State state = getState(addr);') 1144 1145 code(''' 1146 ${ident}_State next_state = state; 1147 1148 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1149 *this, curCycle(), ${ident}_State_to_string(state), 1150 ${ident}_Event_to_string(event), addr); 1151 1152 TransitionResult result = 1153''') 1154 if self.TBEType != None and self.EntryType != None: 1155 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1156 elif self.TBEType != None: 1157 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1158 elif self.EntryType != None: 1159 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1160 else: 1161 code('doTransitionWorker(event, state, next_state, addr);') 1162 1163 code(''' 1164 if (result == TransitionResult_Valid) { 1165 DPRINTF(RubyGenerated, "next_state: %s\\n", 1166 ${ident}_State_to_string(next_state)); 1167 m_profiler.countTransition(state, event); 1168 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1169 curTick(), m_version, "${ident}", 1170 ${ident}_Event_to_string(event), 1171 ${ident}_State_to_string(state), 1172 ${ident}_State_to_string(next_state), 1173 addr, GET_TRANSITION_COMMENT()); 1174 1175 CLEAR_TRANSITION_COMMENT(); 1176''') 1177 if self.TBEType != None and self.EntryType != None: 1178 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1179 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1180 elif self.TBEType != None: 1181 code('setState(m_tbe_ptr, addr, next_state);') 1182 code('setAccessPermission(addr, next_state);') 1183 elif self.EntryType != None: 1184 code('setState(m_cache_entry_ptr, addr, next_state);') 1185 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1186 else: 1187 code('setState(addr, next_state);') 1188 code('setAccessPermission(addr, next_state);') 1189 1190 code(''' 1191 } else if (result == TransitionResult_ResourceStall) { 1192 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1193 curTick(), m_version, "${ident}", 1194 ${ident}_Event_to_string(event), 1195 ${ident}_State_to_string(state), 1196 ${ident}_State_to_string(next_state), 1197 addr, "Resource Stall"); 1198 } else if (result == TransitionResult_ProtocolStall) { 1199 DPRINTF(RubyGenerated, "stalling\\n"); 1200 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1201 curTick(), m_version, "${ident}", 1202 ${ident}_Event_to_string(event), 1203 ${ident}_State_to_string(state), 1204 ${ident}_State_to_string(next_state), 1205 addr, "Protocol Stall"); 1206 } 1207 1208 return result; 1209} 1210 1211TransitionResult 1212${ident}_Controller::doTransitionWorker(${ident}_Event event, 1213 ${ident}_State state, 1214 ${ident}_State& next_state, 1215''') 1216 1217 if self.TBEType != None: 1218 code(''' 1219 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1220''') 1221 if self.EntryType != None: 1222 code(''' 1223 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1224''') 1225 code(''' 1226 const Address& addr) 1227{ 1228 switch(HASH_FUN(state, event)) { 1229''') 1230 1231 # This map will allow suppress generating duplicate code 1232 cases = orderdict() 1233 1234 for trans in self.transitions: 1235 case_string = "%s_State_%s, %s_Event_%s" % \ 1236 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1237 1238 case = self.symtab.codeFormatter() 1239 # Only set next_state if it changes 1240 if trans.state != trans.nextState: 1241 ns_ident = trans.nextState.ident 1242 case('next_state = ${ident}_State_${ns_ident};') 1243 1244 actions = trans.actions 1245 request_types = trans.request_types 1246 1247 # Check for resources 1248 case_sorter = [] 1249 res = trans.resources 1250 for key,val in res.iteritems(): 1251 if key.type.ident != "DNUCAStopTable": 1252 val = ''' 1253if (!%s.areNSlotsAvailable(%s)) 1254 return TransitionResult_ResourceStall; 1255''' % (key.code, val) 1256 case_sorter.append(val) 1257 1258 # Check all of the request_types for resource constraints 1259 for request_type in request_types: 1260 val = ''' 1261if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1262 return TransitionResult_ResourceStall; 1263} 1264''' % (self.ident, request_type.ident) 1265 case_sorter.append(val) 1266 1267 # Emit the code sequences in a sorted order. This makes the 1268 # output deterministic (without this the output order can vary 1269 # since Map's keys() on a vector of pointers is not deterministic 1270 for c in sorted(case_sorter): 1271 case("$c") 1272 1273 # Record access types for this transition 1274 for request_type in request_types: 1275 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1276 1277 # Figure out if we stall 1278 stall = False 1279 for action in actions: 1280 if action.ident == "z_stall": 1281 stall = True 1282 break 1283 1284 if stall: 1285 case('return TransitionResult_ProtocolStall;') 1286 else: 1287 if self.TBEType != None and self.EntryType != None: 1288 for action in actions: 1289 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1290 elif self.TBEType != None: 1291 for action in actions: 1292 case('${{action.ident}}(m_tbe_ptr, addr);') 1293 elif self.EntryType != None: 1294 for action in actions: 1295 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1296 else: 1297 for action in actions: 1298 case('${{action.ident}}(addr);') 1299 case('return TransitionResult_Valid;') 1300 1301 case = str(case) 1302 1303 # Look to see if this transition code is unique. 1304 if case not in cases: 1305 cases[case] = [] 1306 1307 cases[case].append(case_string) 1308 1309 # Walk through all of the unique code blocks and spit out the 1310 # corresponding case statement elements 1311 for case,transitions in cases.iteritems(): 1312 # Iterative over all the multiple transitions that share 1313 # the same code 1314 for trans in transitions: 1315 code(' case HASH_FUN($trans):') 1316 code(' $case') 1317 1318 code(''' 1319 default: 1320 fatal("Invalid transition\\n" 1321 "%s time: %d addr: %s event: %s state: %s\\n", 1322 name(), curCycle(), addr, event, state); 1323 } 1324 return TransitionResult_Valid; 1325} 1326''') 1327 code.write(path, "%s_Transitions.cc" % self.ident) 1328 1329 def printProfileDumperHH(self, path): 1330 code = self.symtab.codeFormatter() 1331 ident = self.ident 1332 1333 code(''' 1334// Auto generated C++ code started by $__file__:$__line__ 1335// ${ident}: ${{self.short}} 1336 1337#ifndef __${ident}_PROFILE_DUMPER_HH__ 1338#define __${ident}_PROFILE_DUMPER_HH__ 1339 1340#include <cassert> 1341#include <iostream> 1342#include <vector> 1343 1344#include "${ident}_Event.hh" 1345#include "${ident}_Profiler.hh" 1346 1347typedef std::vector<${ident}_Profiler *> ${ident}_profilers; 1348 1349class ${ident}_ProfileDumper 1350{ 1351 public: 1352 ${ident}_ProfileDumper(); 1353 void registerProfiler(${ident}_Profiler* profiler); 1354 void dumpStats(std::ostream& out) const; 1355 1356 private: 1357 ${ident}_profilers m_profilers; 1358}; 1359 1360#endif // __${ident}_PROFILE_DUMPER_HH__ 1361''') 1362 code.write(path, "%s_ProfileDumper.hh" % self.ident) 1363 1364 def printProfileDumperCC(self, path): 1365 code = self.symtab.codeFormatter() 1366 ident = self.ident 1367 1368 code(''' 1369// Auto generated C++ code started by $__file__:$__line__ 1370// ${ident}: ${{self.short}} 1371 1372#include "mem/protocol/${ident}_ProfileDumper.hh" 1373 1374${ident}_ProfileDumper::${ident}_ProfileDumper() 1375{ 1376} 1377 1378void 1379${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler) 1380{ 1381 m_profilers.push_back(profiler); 1382} 1383 1384void 1385${ident}_ProfileDumper::dumpStats(std::ostream& out) const 1386{ 1387 out << " --- ${ident} ---\\n"; 1388 out << " - Event Counts -\\n"; 1389 for (${ident}_Event event = ${ident}_Event_FIRST; 1390 event < ${ident}_Event_NUM; 1391 ++event) { 1392 out << (${ident}_Event) event << " ["; 1393 uint64 total = 0; 1394 for (int i = 0; i < m_profilers.size(); i++) { 1395 out << m_profilers[i]->getEventCount(event) << " "; 1396 total += m_profilers[i]->getEventCount(event); 1397 } 1398 out << "] " << total << "\\n"; 1399 } 1400 out << "\\n"; 1401 out << " - Transitions -\\n"; 1402 for (${ident}_State state = ${ident}_State_FIRST; 1403 state < ${ident}_State_NUM; 1404 ++state) { 1405 for (${ident}_Event event = ${ident}_Event_FIRST; 1406 event < ${ident}_Event_NUM; 1407 ++event) { 1408 if (m_profilers[0]->isPossible(state, event)) { 1409 out << (${ident}_State) state << " " 1410 << (${ident}_Event) event << " ["; 1411 uint64 total = 0; 1412 for (int i = 0; i < m_profilers.size(); i++) { 1413 out << m_profilers[i]->getTransitionCount(state, event) << " "; 1414 total += m_profilers[i]->getTransitionCount(state, event); 1415 } 1416 out << "] " << total << "\\n"; 1417 } 1418 } 1419 out << "\\n"; 1420 } 1421} 1422''') 1423 code.write(path, "%s_ProfileDumper.cc" % self.ident) 1424 1425 def printProfilerHH(self, path): 1426 code = self.symtab.codeFormatter() 1427 ident = self.ident 1428 1429 code(''' 1430// Auto generated C++ code started by $__file__:$__line__ 1431// ${ident}: ${{self.short}} 1432 1433#ifndef __${ident}_PROFILER_HH__ 1434#define __${ident}_PROFILER_HH__ 1435 1436#include <cassert> 1437#include <iostream> 1438 1439#include "mem/protocol/${ident}_Event.hh" 1440#include "mem/protocol/${ident}_State.hh" 1441#include "mem/ruby/common/TypeDefines.hh" 1442 1443class ${ident}_Profiler 1444{ 1445 public: 1446 ${ident}_Profiler(); 1447 void setVersion(int version); 1448 void countTransition(${ident}_State state, ${ident}_Event event); 1449 void possibleTransition(${ident}_State state, ${ident}_Event event); 1450 uint64 getEventCount(${ident}_Event event); 1451 bool isPossible(${ident}_State state, ${ident}_Event event); 1452 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 1453 void clearStats(); 1454 1455 private: 1456 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 1457 int m_event_counters[${ident}_Event_NUM]; 1458 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 1459 int m_version; 1460}; 1461 1462#endif // __${ident}_PROFILER_HH__ 1463''') 1464 code.write(path, "%s_Profiler.hh" % self.ident) 1465 1466 def printProfilerCC(self, path): 1467 code = self.symtab.codeFormatter() 1468 ident = self.ident 1469 1470 code(''' 1471// Auto generated C++ code started by $__file__:$__line__ 1472// ${ident}: ${{self.short}} 1473 1474#include <cassert> 1475 1476#include "mem/protocol/${ident}_Profiler.hh" 1477 1478${ident}_Profiler::${ident}_Profiler() 1479{ 1480 for (int state = 0; state < ${ident}_State_NUM; state++) { 1481 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1482 m_possible[state][event] = false; 1483 m_counters[state][event] = 0; 1484 } 1485 } 1486 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1487 m_event_counters[event] = 0; 1488 } 1489} 1490 1491void 1492${ident}_Profiler::setVersion(int version) 1493{ 1494 m_version = version; 1495} 1496 1497void 1498${ident}_Profiler::clearStats() 1499{ 1500 for (int state = 0; state < ${ident}_State_NUM; state++) { 1501 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1502 m_counters[state][event] = 0; 1503 } 1504 } 1505 1506 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1507 m_event_counters[event] = 0; 1508 } 1509} 1510void 1511${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1512{ 1513 assert(m_possible[state][event]); 1514 m_counters[state][event]++; 1515 m_event_counters[event]++; 1516} 1517void 1518${ident}_Profiler::possibleTransition(${ident}_State state, 1519 ${ident}_Event event) 1520{ 1521 m_possible[state][event] = true; 1522} 1523 1524uint64 1525${ident}_Profiler::getEventCount(${ident}_Event event) 1526{ 1527 return m_event_counters[event]; 1528} 1529 1530bool 1531${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event) 1532{ 1533 return m_possible[state][event]; 1534} 1535 1536uint64 1537${ident}_Profiler::getTransitionCount(${ident}_State state, 1538 ${ident}_Event event) 1539{ 1540 return m_counters[state][event]; 1541} 1542 1543''') 1544 code.write(path, "%s_Profiler.cc" % self.ident) 1545 1546 # ************************** 1547 # ******* HTML Files ******* 1548 # ************************** 1549 def frameRef(self, click_href, click_target, over_href, over_num, text): 1550 code = self.symtab.codeFormatter(fix_newlines=False) 1551 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1552 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1553 parent.frames[$over_num].location='$over_href' 1554 }\"> 1555 ${{html.formatShorthand(text)}} 1556 </A>""") 1557 return str(code) 1558 1559 def writeHTMLFiles(self, path): 1560 # Create table with no row hilighted 1561 self.printHTMLTransitions(path, None) 1562 1563 # Generate transition tables 1564 for state in self.states.itervalues(): 1565 self.printHTMLTransitions(path, state) 1566 1567 # Generate action descriptions 1568 for action in self.actions.itervalues(): 1569 name = "%s_action_%s.html" % (self.ident, action.ident) 1570 code = html.createSymbol(action, "Action") 1571 code.write(path, name) 1572 1573 # Generate state descriptions 1574 for state in self.states.itervalues(): 1575 name = "%s_State_%s.html" % (self.ident, state.ident) 1576 code = html.createSymbol(state, "State") 1577 code.write(path, name) 1578 1579 # Generate event descriptions 1580 for event in self.events.itervalues(): 1581 name = "%s_Event_%s.html" % (self.ident, event.ident) 1582 code = html.createSymbol(event, "Event") 1583 code.write(path, name) 1584 1585 def printHTMLTransitions(self, path, active_state): 1586 code = self.symtab.codeFormatter() 1587 1588 code(''' 1589<HTML> 1590<BODY link="blue" vlink="blue"> 1591 1592<H1 align="center">${{html.formatShorthand(self.short)}}: 1593''') 1594 code.indent() 1595 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1596 mid = machine.ident 1597 if i != 0: 1598 extra = " - " 1599 else: 1600 extra = "" 1601 if machine == self: 1602 code('$extra$mid') 1603 else: 1604 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1605 code.dedent() 1606 1607 code(""" 1608</H1> 1609 1610<TABLE border=1> 1611<TR> 1612 <TH> </TH> 1613""") 1614 1615 for event in self.events.itervalues(): 1616 href = "%s_Event_%s.html" % (self.ident, event.ident) 1617 ref = self.frameRef(href, "Status", href, "1", event.short) 1618 code('<TH bgcolor=white>$ref</TH>') 1619 1620 code('</TR>') 1621 # -- Body of table 1622 for state in self.states.itervalues(): 1623 # -- Each row 1624 if state == active_state: 1625 color = "yellow" 1626 else: 1627 color = "white" 1628 1629 click = "%s_table_%s.html" % (self.ident, state.ident) 1630 over = "%s_State_%s.html" % (self.ident, state.ident) 1631 text = html.formatShorthand(state.short) 1632 ref = self.frameRef(click, "Table", over, "1", state.short) 1633 code(''' 1634<TR> 1635 <TH bgcolor=$color>$ref</TH> 1636''') 1637 1638 # -- One column for each event 1639 for event in self.events.itervalues(): 1640 trans = self.table.get((state,event), None) 1641 if trans is None: 1642 # This is the no transition case 1643 if state == active_state: 1644 color = "#C0C000" 1645 else: 1646 color = "lightgrey" 1647 1648 code('<TD bgcolor=$color> </TD>') 1649 continue 1650 1651 next = trans.nextState 1652 stall_action = False 1653 1654 # -- Get the actions 1655 for action in trans.actions: 1656 if action.ident == "z_stall" or \ 1657 action.ident == "zz_recycleMandatoryQueue": 1658 stall_action = True 1659 1660 # -- Print out "actions/next-state" 1661 if stall_action: 1662 if state == active_state: 1663 color = "#C0C000" 1664 else: 1665 color = "lightgrey" 1666 1667 elif active_state and next.ident == active_state.ident: 1668 color = "aqua" 1669 elif state == active_state: 1670 color = "yellow" 1671 else: 1672 color = "white" 1673 1674 code('<TD bgcolor=$color>') 1675 for action in trans.actions: 1676 href = "%s_action_%s.html" % (self.ident, action.ident) 1677 ref = self.frameRef(href, "Status", href, "1", 1678 action.short) 1679 code(' $ref') 1680 if next != state: 1681 if trans.actions: 1682 code('/') 1683 click = "%s_table_%s.html" % (self.ident, next.ident) 1684 over = "%s_State_%s.html" % (self.ident, next.ident) 1685 ref = self.frameRef(click, "Table", over, "1", next.short) 1686 code("$ref") 1687 code("</TD>") 1688 1689 # -- Each row 1690 if state == active_state: 1691 color = "yellow" 1692 else: 1693 color = "white" 1694 1695 click = "%s_table_%s.html" % (self.ident, state.ident) 1696 over = "%s_State_%s.html" % (self.ident, state.ident) 1697 ref = self.frameRef(click, "Table", over, "1", state.short) 1698 code(''' 1699 <TH bgcolor=$color>$ref</TH> 1700</TR> 1701''') 1702 code(''' 1703<!- Column footer-> 1704<TR> 1705 <TH> </TH> 1706''') 1707 1708 for event in self.events.itervalues(): 1709 href = "%s_Event_%s.html" % (self.ident, event.ident) 1710 ref = self.frameRef(href, "Status", href, "1", event.short) 1711 code('<TH bgcolor=white>$ref</TH>') 1712 code(''' 1713</TR> 1714</TABLE> 1715</BODY></HTML> 1716''') 1717 1718 1719 if active_state: 1720 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1721 else: 1722 name = "%s_table.html" % self.ident 1723 code.write(path, name) 1724 1725__all__ = [ "StateMachine" ]
|