33 34python_class_map = {"int": "Int", 35 "std::string": "String", 36 "bool": "Bool", 37 "CacheMemory": "RubyCache", 38 "Sequencer": "RubySequencer", 39 "DirectoryMemory": "RubyDirectoryMemory", 40 "MemoryControl": "RubyMemoryControl", 41 "DMASequencer": "DMASequencer" 42 } 43 44class StateMachine(Symbol): 45 def __init__(self, symtab, ident, location, pairs, config_parameters): 46 super(StateMachine, self).__init__(symtab, ident, location, pairs) 47 self.table = None 48 self.config_parameters = config_parameters 49 50 for param in config_parameters: 51 if param.pointer: 52 var = Var(symtab, param.name, location, param.type_ast.type, 53 "(*m_%s_ptr)" % param.name, {}, self) 54 else: 55 var = Var(symtab, param.name, location, param.type_ast.type, 56 "m_%s" % param.name, {}, self) 57 self.symtab.registerSym(param.name, var) 58 59 self.states = orderdict() 60 self.events = orderdict() 61 self.actions = orderdict() 62 self.transitions = [] 63 self.in_ports = [] 64 self.functions = [] 65 self.objects = [] 66 self.TBEType = None 67 self.EntryType = None 68 69 self.message_buffer_names = [] 70 71 def __repr__(self): 72 return "[StateMachine: %s]" % self.ident 73 74 def addState(self, state): 75 assert self.table is None 76 self.states[state.ident] = state 77 78 def addEvent(self, event): 79 assert self.table is None 80 self.events[event.ident] = event 81 82 def addAction(self, action): 83 assert self.table is None 84 85 # Check for duplicate action 86 for other in self.actions.itervalues(): 87 if action.ident == other.ident: 88 action.warning("Duplicate action definition: %s" % action.ident) 89 action.error("Duplicate action definition: %s" % action.ident) 90 if action.short == other.short: 91 other.warning("Duplicate action shorthand: %s" % other.ident) 92 other.warning(" shorthand = %s" % other.short) 93 action.warning("Duplicate action shorthand: %s" % action.ident) 94 action.error(" shorthand = %s" % action.short) 95 96 self.actions[action.ident] = action 97 98 def addTransition(self, trans): 99 assert self.table is None 100 self.transitions.append(trans) 101 102 def addInPort(self, var): 103 self.in_ports.append(var) 104 105 def addFunc(self, func): 106 # register func in the symbol table 107 self.symtab.registerSym(str(func), func) 108 self.functions.append(func) 109 110 def addObject(self, obj): 111 self.objects.append(obj) 112 113 def addType(self, type): 114 type_ident = '%s' % type.c_ident 115 116 if type_ident == "%s_TBE" %self.ident: 117 if self.TBEType != None: 118 self.error("Multiple Transaction Buffer types in a " \ 119 "single machine."); 120 self.TBEType = type 121 122 elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 123 if self.EntryType != None: 124 self.error("Multiple AbstractCacheEntry types in a " \ 125 "single machine."); 126 self.EntryType = type 127 128 # Needs to be called before accessing the table 129 def buildTable(self): 130 assert self.table is None 131 132 table = {} 133 134 for trans in self.transitions: 135 # Track which actions we touch so we know if we use them 136 # all -- really this should be done for all symbols as 137 # part of the symbol table, then only trigger it for 138 # Actions, States, Events, etc. 139 140 for action in trans.actions: 141 action.used = True 142 143 index = (trans.state, trans.event) 144 if index in table: 145 table[index].warning("Duplicate transition: %s" % table[index]) 146 trans.error("Duplicate transition: %s" % trans) 147 table[index] = trans 148 149 # Look at all actions to make sure we used them all 150 for action in self.actions.itervalues(): 151 if not action.used: 152 error_msg = "Unused action: %s" % action.ident 153 if "desc" in action: 154 error_msg += ", " + action.desc 155 action.warning(error_msg) 156 self.table = table 157 158 def writeCodeFiles(self, path): 159 self.printControllerPython(path) 160 self.printControllerHH(path) 161 self.printControllerCC(path) 162 self.printCSwitch(path) 163 self.printCWakeup(path) 164 self.printProfilerCC(path) 165 self.printProfilerHH(path) 166 self.printProfileDumperCC(path) 167 self.printProfileDumperHH(path) 168 169 for func in self.functions: 170 func.writeCodeFiles(path) 171 172 def printControllerPython(self, path): 173 code = self.symtab.codeFormatter() 174 ident = self.ident 175 py_ident = "%s_Controller" % ident 176 c_ident = "%s_Controller" % self.ident 177 code(''' 178from m5.params import * 179from m5.SimObject import SimObject 180from Controller import RubyController 181 182class $py_ident(RubyController): 183 type = '$py_ident' 184''') 185 code.indent() 186 for param in self.config_parameters: 187 dflt_str = '' 188 if param.default is not None: 189 dflt_str = str(param.default) + ', ' 190 if python_class_map.has_key(param.type_ast.type.c_ident): 191 python_type = python_class_map[param.type_ast.type.c_ident] 192 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 193 else: 194 self.error("Unknown c++ to python class conversion for c++ " \ 195 "type: '%s'. Please update the python_class_map " \ 196 "in StateMachine.py", param.type_ast.type.c_ident) 197 code.dedent() 198 code.write(path, '%s.py' % py_ident) 199 200 201 def printControllerHH(self, path): 202 '''Output the method declarations for the class declaration''' 203 code = self.symtab.codeFormatter() 204 ident = self.ident 205 c_ident = "%s_Controller" % self.ident 206 207 self.message_buffer_names = [] 208 209 code(''' 210/** \\file $c_ident.hh 211 * 212 * Auto generated C++ code started by $__file__:$__line__ 213 * Created by slicc definition of Module "${{self.short}}" 214 */ 215 216#ifndef __${ident}_CONTROLLER_HH__ 217#define __${ident}_CONTROLLER_HH__ 218 219#include <iostream> 220#include <sstream> 221#include <string> 222 223#include "params/$c_ident.hh" 224 225#include "mem/ruby/common/Global.hh" 226#include "mem/ruby/common/Consumer.hh" 227#include "mem/ruby/slicc_interface/AbstractController.hh" 228#include "mem/protocol/TransitionResult.hh" 229#include "mem/protocol/Types.hh" 230#include "mem/protocol/${ident}_Profiler.hh" 231#include "mem/protocol/${ident}_ProfileDumper.hh" 232''') 233 234 seen_types = set() 235 for var in self.objects: 236 if var.type.ident not in seen_types and not var.type.isPrimitive: 237 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 238 seen_types.add(var.type.ident) 239 240 # for adding information to the protocol debug trace 241 code(''' 242extern std::stringstream ${ident}_transitionComment; 243 244class $c_ident : public AbstractController 245{ 246// the coherence checker needs to call isBlockExclusive() and isBlockShared() 247// making the Chip a friend class is an easy way to do this for now 248 249public: 250 typedef ${c_ident}Params Params; 251 $c_ident(const Params *p); 252 static int getNumControllers(); 253 void init(); 254 MessageBuffer* getMandatoryQueue() const; 255 const int & getVersion() const; 256 const std::string toString() const; 257 const std::string getName() const; 258 const MachineType getMachineType() const; 259 void stallBuffer(MessageBuffer* buf, Address addr); 260 void wakeUpBuffers(Address addr); 261 void wakeUpAllBuffers(); 262 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; } 263 void print(std::ostream& out) const; 264 void printConfig(std::ostream& out) const; 265 void wakeup(); 266 void printStats(std::ostream& out) const; 267 void clearStats(); 268 void blockOnQueue(Address addr, MessageBuffer* port); 269 void unblock(Address addr); 270 271private: 272''') 273 274 code.indent() 275 # added by SS 276 for param in self.config_parameters: 277 if param.pointer: 278 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 279 else: 280 code('${{param.type_ast.type}} m_${{param.ident}};') 281 282 code(''' 283int m_number_of_TBEs; 284 285TransitionResult doTransition(${ident}_Event event, 286''') 287 288 if self.EntryType != None: 289 code(''' 290 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 291''') 292 if self.TBEType != None: 293 code(''' 294 ${{self.TBEType.c_ident}}* m_tbe_ptr, 295''') 296 297 code(''' 298 const Address& addr); 299 300TransitionResult doTransitionWorker(${ident}_Event event, 301 ${ident}_State state, 302 ${ident}_State& next_state, 303''') 304 305 if self.TBEType != None: 306 code(''' 307 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 308''') 309 if self.EntryType != None: 310 code(''' 311 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 312''') 313 314 code(''' 315 const Address& addr); 316 317std::string m_name; 318int m_transitions_per_cycle; 319int m_buffer_size; 320int m_recycle_latency; 321std::map<std::string, std::string> m_cfg; 322NodeID m_version; 323Network* m_net_ptr; 324MachineID m_machineID; 325bool m_is_blocking; 326std::map<Address, MessageBuffer*> m_block_map; 327typedef std::vector<MessageBuffer*> MsgVecType; 328typedef m5::hash_map< Address, MsgVecType* > WaitingBufType; 329WaitingBufType m_waiting_buffers; 330int m_max_in_port_rank; 331int m_cur_in_port_rank; 332static ${ident}_ProfileDumper s_profileDumper; 333${ident}_Profiler m_profiler; 334static int m_num_controllers; 335 336// Internal functions 337''') 338 339 for func in self.functions: 340 proto = func.prototype 341 if proto: 342 code('$proto') 343 344 if self.EntryType != None: 345 code(''' 346 347// Set and Reset for cache_entry variable 348void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 349void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 350// Set permissions for the cache_entry 351void set_permission(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AccessPermission perm); 352''') 353 354 if self.TBEType != None: 355 code(''' 356 357// Set and Reset for tbe variable 358void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 359void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 360''') 361 362 code(''' 363 364// Actions 365''') 366 if self.TBEType != None and self.EntryType != None: 367 for action in self.actions.itervalues(): 368 code('/** \\brief ${{action.desc}} */') 369 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 370 elif self.TBEType != None: 371 for action in self.actions.itervalues(): 372 code('/** \\brief ${{action.desc}} */') 373 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);') 374 elif self.EntryType != None: 375 for action in self.actions.itervalues(): 376 code('/** \\brief ${{action.desc}} */') 377 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 378 else: 379 for action in self.actions.itervalues(): 380 code('/** \\brief ${{action.desc}} */') 381 code('void ${{action.ident}}(const Address& addr);') 382 383 # the controller internal variables 384 code(''' 385 386// Objects 387''') 388 for var in self.objects: 389 th = var.get("template_hack", "") 390 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 391 392 if var.type.ident == "MessageBuffer": 393 self.message_buffer_names.append("m_%s_ptr" % var.c_ident) 394 395 code.dedent() 396 code('};') 397 code('#endif // __${ident}_CONTROLLER_H__') 398 code.write(path, '%s.hh' % c_ident) 399 400 def printControllerCC(self, path): 401 '''Output the actions for performing the actions''' 402 403 code = self.symtab.codeFormatter() 404 ident = self.ident 405 c_ident = "%s_Controller" % self.ident 406 407 code(''' 408/** \\file $c_ident.cc 409 * 410 * Auto generated C++ code started by $__file__:$__line__ 411 * Created by slicc definition of Module "${{self.short}}" 412 */ 413 414#include <cassert> 415#include <sstream> 416#include <string> 417 418#include "base/cprintf.hh" 419#include "mem/protocol/${ident}_Controller.hh" 420#include "mem/protocol/${ident}_State.hh" 421#include "mem/protocol/${ident}_Event.hh" 422#include "mem/protocol/Types.hh" 423#include "mem/ruby/common/Global.hh" 424#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 425#include "mem/ruby/system/System.hh" 426 427using namespace std; 428''') 429 430 # include object classes 431 seen_types = set() 432 for var in self.objects: 433 if var.type.ident not in seen_types and not var.type.isPrimitive: 434 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 435 seen_types.add(var.type.ident) 436 437 code(''' 438$c_ident * 439${c_ident}Params::create() 440{ 441 return new $c_ident(this); 442} 443 444int $c_ident::m_num_controllers = 0; 445${ident}_ProfileDumper $c_ident::s_profileDumper; 446 447// for adding information to the protocol debug trace 448stringstream ${ident}_transitionComment; 449#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 450 451/** \\brief constructor */ 452$c_ident::$c_ident(const Params *p) 453 : AbstractController(p) 454{ 455 m_version = p->version; 456 m_transitions_per_cycle = p->transitions_per_cycle; 457 m_buffer_size = p->buffer_size; 458 m_recycle_latency = p->recycle_latency; 459 m_number_of_TBEs = p->number_of_TBEs; 460 m_is_blocking = false; 461''') 462 # 463 # max_port_rank is used to size vectors and thus should be one plus the 464 # largest port rank 465 # 466 max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1 467 code(' m_max_in_port_rank = $max_port_rank;') 468 code.indent() 469 470 # 471 # After initializing the universal machine parameters, initialize the 472 # this machines config parameters. Also detemine if these configuration 473 # params include a sequencer. This information will be used later for 474 # contecting the sequencer back to the L1 cache controller. 475 #
| 34 35python_class_map = {"int": "Int", 36 "std::string": "String", 37 "bool": "Bool", 38 "CacheMemory": "RubyCache", 39 "Sequencer": "RubySequencer", 40 "DirectoryMemory": "RubyDirectoryMemory", 41 "MemoryControl": "RubyMemoryControl", 42 "DMASequencer": "DMASequencer" 43 } 44 45class StateMachine(Symbol): 46 def __init__(self, symtab, ident, location, pairs, config_parameters): 47 super(StateMachine, self).__init__(symtab, ident, location, pairs) 48 self.table = None 49 self.config_parameters = config_parameters 50 51 for param in config_parameters: 52 if param.pointer: 53 var = Var(symtab, param.name, location, param.type_ast.type, 54 "(*m_%s_ptr)" % param.name, {}, self) 55 else: 56 var = Var(symtab, param.name, location, param.type_ast.type, 57 "m_%s" % param.name, {}, self) 58 self.symtab.registerSym(param.name, var) 59 60 self.states = orderdict() 61 self.events = orderdict() 62 self.actions = orderdict() 63 self.transitions = [] 64 self.in_ports = [] 65 self.functions = [] 66 self.objects = [] 67 self.TBEType = None 68 self.EntryType = None 69 70 self.message_buffer_names = [] 71 72 def __repr__(self): 73 return "[StateMachine: %s]" % self.ident 74 75 def addState(self, state): 76 assert self.table is None 77 self.states[state.ident] = state 78 79 def addEvent(self, event): 80 assert self.table is None 81 self.events[event.ident] = event 82 83 def addAction(self, action): 84 assert self.table is None 85 86 # Check for duplicate action 87 for other in self.actions.itervalues(): 88 if action.ident == other.ident: 89 action.warning("Duplicate action definition: %s" % action.ident) 90 action.error("Duplicate action definition: %s" % action.ident) 91 if action.short == other.short: 92 other.warning("Duplicate action shorthand: %s" % other.ident) 93 other.warning(" shorthand = %s" % other.short) 94 action.warning("Duplicate action shorthand: %s" % action.ident) 95 action.error(" shorthand = %s" % action.short) 96 97 self.actions[action.ident] = action 98 99 def addTransition(self, trans): 100 assert self.table is None 101 self.transitions.append(trans) 102 103 def addInPort(self, var): 104 self.in_ports.append(var) 105 106 def addFunc(self, func): 107 # register func in the symbol table 108 self.symtab.registerSym(str(func), func) 109 self.functions.append(func) 110 111 def addObject(self, obj): 112 self.objects.append(obj) 113 114 def addType(self, type): 115 type_ident = '%s' % type.c_ident 116 117 if type_ident == "%s_TBE" %self.ident: 118 if self.TBEType != None: 119 self.error("Multiple Transaction Buffer types in a " \ 120 "single machine."); 121 self.TBEType = type 122 123 elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 124 if self.EntryType != None: 125 self.error("Multiple AbstractCacheEntry types in a " \ 126 "single machine."); 127 self.EntryType = type 128 129 # Needs to be called before accessing the table 130 def buildTable(self): 131 assert self.table is None 132 133 table = {} 134 135 for trans in self.transitions: 136 # Track which actions we touch so we know if we use them 137 # all -- really this should be done for all symbols as 138 # part of the symbol table, then only trigger it for 139 # Actions, States, Events, etc. 140 141 for action in trans.actions: 142 action.used = True 143 144 index = (trans.state, trans.event) 145 if index in table: 146 table[index].warning("Duplicate transition: %s" % table[index]) 147 trans.error("Duplicate transition: %s" % trans) 148 table[index] = trans 149 150 # Look at all actions to make sure we used them all 151 for action in self.actions.itervalues(): 152 if not action.used: 153 error_msg = "Unused action: %s" % action.ident 154 if "desc" in action: 155 error_msg += ", " + action.desc 156 action.warning(error_msg) 157 self.table = table 158 159 def writeCodeFiles(self, path): 160 self.printControllerPython(path) 161 self.printControllerHH(path) 162 self.printControllerCC(path) 163 self.printCSwitch(path) 164 self.printCWakeup(path) 165 self.printProfilerCC(path) 166 self.printProfilerHH(path) 167 self.printProfileDumperCC(path) 168 self.printProfileDumperHH(path) 169 170 for func in self.functions: 171 func.writeCodeFiles(path) 172 173 def printControllerPython(self, path): 174 code = self.symtab.codeFormatter() 175 ident = self.ident 176 py_ident = "%s_Controller" % ident 177 c_ident = "%s_Controller" % self.ident 178 code(''' 179from m5.params import * 180from m5.SimObject import SimObject 181from Controller import RubyController 182 183class $py_ident(RubyController): 184 type = '$py_ident' 185''') 186 code.indent() 187 for param in self.config_parameters: 188 dflt_str = '' 189 if param.default is not None: 190 dflt_str = str(param.default) + ', ' 191 if python_class_map.has_key(param.type_ast.type.c_ident): 192 python_type = python_class_map[param.type_ast.type.c_ident] 193 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 194 else: 195 self.error("Unknown c++ to python class conversion for c++ " \ 196 "type: '%s'. Please update the python_class_map " \ 197 "in StateMachine.py", param.type_ast.type.c_ident) 198 code.dedent() 199 code.write(path, '%s.py' % py_ident) 200 201 202 def printControllerHH(self, path): 203 '''Output the method declarations for the class declaration''' 204 code = self.symtab.codeFormatter() 205 ident = self.ident 206 c_ident = "%s_Controller" % self.ident 207 208 self.message_buffer_names = [] 209 210 code(''' 211/** \\file $c_ident.hh 212 * 213 * Auto generated C++ code started by $__file__:$__line__ 214 * Created by slicc definition of Module "${{self.short}}" 215 */ 216 217#ifndef __${ident}_CONTROLLER_HH__ 218#define __${ident}_CONTROLLER_HH__ 219 220#include <iostream> 221#include <sstream> 222#include <string> 223 224#include "params/$c_ident.hh" 225 226#include "mem/ruby/common/Global.hh" 227#include "mem/ruby/common/Consumer.hh" 228#include "mem/ruby/slicc_interface/AbstractController.hh" 229#include "mem/protocol/TransitionResult.hh" 230#include "mem/protocol/Types.hh" 231#include "mem/protocol/${ident}_Profiler.hh" 232#include "mem/protocol/${ident}_ProfileDumper.hh" 233''') 234 235 seen_types = set() 236 for var in self.objects: 237 if var.type.ident not in seen_types and not var.type.isPrimitive: 238 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 239 seen_types.add(var.type.ident) 240 241 # for adding information to the protocol debug trace 242 code(''' 243extern std::stringstream ${ident}_transitionComment; 244 245class $c_ident : public AbstractController 246{ 247// the coherence checker needs to call isBlockExclusive() and isBlockShared() 248// making the Chip a friend class is an easy way to do this for now 249 250public: 251 typedef ${c_ident}Params Params; 252 $c_ident(const Params *p); 253 static int getNumControllers(); 254 void init(); 255 MessageBuffer* getMandatoryQueue() const; 256 const int & getVersion() const; 257 const std::string toString() const; 258 const std::string getName() const; 259 const MachineType getMachineType() const; 260 void stallBuffer(MessageBuffer* buf, Address addr); 261 void wakeUpBuffers(Address addr); 262 void wakeUpAllBuffers(); 263 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; } 264 void print(std::ostream& out) const; 265 void printConfig(std::ostream& out) const; 266 void wakeup(); 267 void printStats(std::ostream& out) const; 268 void clearStats(); 269 void blockOnQueue(Address addr, MessageBuffer* port); 270 void unblock(Address addr); 271 272private: 273''') 274 275 code.indent() 276 # added by SS 277 for param in self.config_parameters: 278 if param.pointer: 279 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 280 else: 281 code('${{param.type_ast.type}} m_${{param.ident}};') 282 283 code(''' 284int m_number_of_TBEs; 285 286TransitionResult doTransition(${ident}_Event event, 287''') 288 289 if self.EntryType != None: 290 code(''' 291 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 292''') 293 if self.TBEType != None: 294 code(''' 295 ${{self.TBEType.c_ident}}* m_tbe_ptr, 296''') 297 298 code(''' 299 const Address& addr); 300 301TransitionResult doTransitionWorker(${ident}_Event event, 302 ${ident}_State state, 303 ${ident}_State& next_state, 304''') 305 306 if self.TBEType != None: 307 code(''' 308 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 309''') 310 if self.EntryType != None: 311 code(''' 312 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 313''') 314 315 code(''' 316 const Address& addr); 317 318std::string m_name; 319int m_transitions_per_cycle; 320int m_buffer_size; 321int m_recycle_latency; 322std::map<std::string, std::string> m_cfg; 323NodeID m_version; 324Network* m_net_ptr; 325MachineID m_machineID; 326bool m_is_blocking; 327std::map<Address, MessageBuffer*> m_block_map; 328typedef std::vector<MessageBuffer*> MsgVecType; 329typedef m5::hash_map< Address, MsgVecType* > WaitingBufType; 330WaitingBufType m_waiting_buffers; 331int m_max_in_port_rank; 332int m_cur_in_port_rank; 333static ${ident}_ProfileDumper s_profileDumper; 334${ident}_Profiler m_profiler; 335static int m_num_controllers; 336 337// Internal functions 338''') 339 340 for func in self.functions: 341 proto = func.prototype 342 if proto: 343 code('$proto') 344 345 if self.EntryType != None: 346 code(''' 347 348// Set and Reset for cache_entry variable 349void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 350void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 351// Set permissions for the cache_entry 352void set_permission(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AccessPermission perm); 353''') 354 355 if self.TBEType != None: 356 code(''' 357 358// Set and Reset for tbe variable 359void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 360void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 361''') 362 363 code(''' 364 365// Actions 366''') 367 if self.TBEType != None and self.EntryType != None: 368 for action in self.actions.itervalues(): 369 code('/** \\brief ${{action.desc}} */') 370 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 371 elif self.TBEType != None: 372 for action in self.actions.itervalues(): 373 code('/** \\brief ${{action.desc}} */') 374 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);') 375 elif self.EntryType != None: 376 for action in self.actions.itervalues(): 377 code('/** \\brief ${{action.desc}} */') 378 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 379 else: 380 for action in self.actions.itervalues(): 381 code('/** \\brief ${{action.desc}} */') 382 code('void ${{action.ident}}(const Address& addr);') 383 384 # the controller internal variables 385 code(''' 386 387// Objects 388''') 389 for var in self.objects: 390 th = var.get("template_hack", "") 391 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 392 393 if var.type.ident == "MessageBuffer": 394 self.message_buffer_names.append("m_%s_ptr" % var.c_ident) 395 396 code.dedent() 397 code('};') 398 code('#endif // __${ident}_CONTROLLER_H__') 399 code.write(path, '%s.hh' % c_ident) 400 401 def printControllerCC(self, path): 402 '''Output the actions for performing the actions''' 403 404 code = self.symtab.codeFormatter() 405 ident = self.ident 406 c_ident = "%s_Controller" % self.ident 407 408 code(''' 409/** \\file $c_ident.cc 410 * 411 * Auto generated C++ code started by $__file__:$__line__ 412 * Created by slicc definition of Module "${{self.short}}" 413 */ 414 415#include <cassert> 416#include <sstream> 417#include <string> 418 419#include "base/cprintf.hh" 420#include "mem/protocol/${ident}_Controller.hh" 421#include "mem/protocol/${ident}_State.hh" 422#include "mem/protocol/${ident}_Event.hh" 423#include "mem/protocol/Types.hh" 424#include "mem/ruby/common/Global.hh" 425#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 426#include "mem/ruby/system/System.hh" 427 428using namespace std; 429''') 430 431 # include object classes 432 seen_types = set() 433 for var in self.objects: 434 if var.type.ident not in seen_types and not var.type.isPrimitive: 435 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 436 seen_types.add(var.type.ident) 437 438 code(''' 439$c_ident * 440${c_ident}Params::create() 441{ 442 return new $c_ident(this); 443} 444 445int $c_ident::m_num_controllers = 0; 446${ident}_ProfileDumper $c_ident::s_profileDumper; 447 448// for adding information to the protocol debug trace 449stringstream ${ident}_transitionComment; 450#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 451 452/** \\brief constructor */ 453$c_ident::$c_ident(const Params *p) 454 : AbstractController(p) 455{ 456 m_version = p->version; 457 m_transitions_per_cycle = p->transitions_per_cycle; 458 m_buffer_size = p->buffer_size; 459 m_recycle_latency = p->recycle_latency; 460 m_number_of_TBEs = p->number_of_TBEs; 461 m_is_blocking = false; 462''') 463 # 464 # max_port_rank is used to size vectors and thus should be one plus the 465 # largest port rank 466 # 467 max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1 468 code(' m_max_in_port_rank = $max_port_rank;') 469 code.indent() 470 471 # 472 # After initializing the universal machine parameters, initialize the 473 # this machines config parameters. Also detemine if these configuration 474 # params include a sequencer. This information will be used later for 475 # contecting the sequencer back to the L1 cache controller. 476 #
|
503 self.error("The DMA controller must include the sequencer " \ 504 "configuration parameter") 505 506 code(''' 507m_dma_sequencer_ptr->setController(this); 508''') 509 510 code('m_num_controllers++;') 511 for var in self.objects: 512 if var.ident.find("mandatoryQueue") >= 0: 513 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();') 514 515 code.dedent() 516 code(''' 517} 518 519void 520$c_ident::init() 521{ 522 MachineType machine_type; 523 int base; 524 525 m_machineID.type = MachineType_${ident}; 526 m_machineID.num = m_version; 527 528 // initialize objects 529 m_profiler.setVersion(m_version); 530 s_profileDumper.registerProfiler(&m_profiler); 531 532''') 533 534 code.indent() 535 for var in self.objects: 536 vtype = var.type 537 vid = "m_%s_ptr" % var.c_ident 538 if "network" not in var: 539 # Not a network port object 540 if "primitive" in vtype: 541 code('$vid = new ${{vtype.c_ident}};') 542 if "default" in var: 543 code('(*$vid) = ${{var["default"]}};') 544 else: 545 # Normal Object 546 # added by SS 547 if "factory" in var: 548 code('$vid = ${{var["factory"]}};') 549 elif var.ident.find("mandatoryQueue") < 0: 550 th = var.get("template_hack", "") 551 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 552 553 args = "" 554 if "non_obj" not in vtype and not vtype.isEnumeration: 555 if expr.find("TBETable") >= 0: 556 args = "m_number_of_TBEs" 557 else: 558 args = var.get("constructor_hack", "") 559 560 code('$expr($args);') 561 562 code('assert($vid != NULL);') 563 564 if "default" in var: 565 code('*$vid = ${{var["default"]}}; // Object default') 566 elif "default" in vtype: 567 comment = "Type %s default" % vtype.ident 568 code('*$vid = ${{vtype["default"]}}; // $comment') 569 570 # Set ordering 571 if "ordered" in var and "trigger_queue" not in var: 572 # A buffer 573 code('$vid->setOrdering(${{var["ordered"]}});') 574 575 # Set randomization 576 if "random" in var: 577 # A buffer 578 code('$vid->setRandomization(${{var["random"]}});') 579 580 # Set Priority 581 if vtype.isBuffer and \ 582 "rank" in var and "trigger_queue" not in var: 583 code('$vid->setPriority(${{var["rank"]}});') 584 585 else: 586 # Network port object 587 network = var["network"] 588 ordered = var["ordered"] 589 vnet = var["virtual_network"] 590 591 assert var.machine is not None 592 code(''' 593machine_type = string_to_MachineType("${{var.machine.ident}}"); 594base = MachineType_base_number(machine_type); 595$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet); 596''') 597 598 code('assert($vid != NULL);') 599 600 # Set ordering 601 if "ordered" in var: 602 # A buffer 603 code('$vid->setOrdering(${{var["ordered"]}});') 604 605 # Set randomization 606 if "random" in var: 607 # A buffer 608 code('$vid->setRandomization(${{var["random"]}});') 609 610 # Set Priority 611 if "rank" in var: 612 code('$vid->setPriority(${{var["rank"]}})') 613 614 # Set buffer size 615 if vtype.isBuffer: 616 code(''' 617if (m_buffer_size > 0) { 618 $vid->resize(m_buffer_size); 619} 620''') 621 622 # set description (may be overriden later by port def) 623 code(''' 624$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]"); 625 626''') 627 628 if vtype.isBuffer: 629 if "recycle_latency" in var: 630 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});') 631 else: 632 code('$vid->setRecycleLatency(m_recycle_latency);') 633 634 635 # Set the queue consumers 636 code() 637 for port in self.in_ports: 638 code('${{port.code}}.setConsumer(this);') 639 640 # Set the queue descriptions 641 code() 642 for port in self.in_ports: 643 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");') 644 645 # Initialize the transition profiling 646 code() 647 for trans in self.transitions: 648 # Figure out if we stall 649 stall = False 650 for action in trans.actions: 651 if action.ident == "z_stall": 652 stall = True 653 654 # Only possible if it is not a 'z' case 655 if not stall: 656 state = "%s_State_%s" % (self.ident, trans.state.ident) 657 event = "%s_Event_%s" % (self.ident, trans.event.ident) 658 code('m_profiler.possibleTransition($state, $event);') 659 660 code.dedent() 661 code('}') 662 663 has_mandatory_q = False 664 for port in self.in_ports: 665 if port.code.find("mandatoryQueue_ptr") >= 0: 666 has_mandatory_q = True 667 668 if has_mandatory_q: 669 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 670 else: 671 mq_ident = "NULL" 672 673 code(''' 674int 675$c_ident::getNumControllers() 676{ 677 return m_num_controllers; 678} 679 680MessageBuffer* 681$c_ident::getMandatoryQueue() const 682{ 683 return $mq_ident; 684} 685 686const int & 687$c_ident::getVersion() const 688{ 689 return m_version; 690} 691 692const string 693$c_ident::toString() const 694{ 695 return "$c_ident"; 696} 697 698const string 699$c_ident::getName() const 700{ 701 return m_name; 702} 703 704const MachineType 705$c_ident::getMachineType() const 706{ 707 return MachineType_${ident}; 708} 709 710void 711$c_ident::stallBuffer(MessageBuffer* buf, Address addr) 712{ 713 if (m_waiting_buffers.count(addr) == 0) { 714 MsgVecType* msgVec = new MsgVecType; 715 msgVec->resize(m_max_in_port_rank, NULL); 716 m_waiting_buffers[addr] = msgVec; 717 } 718 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf; 719} 720 721void 722$c_ident::wakeUpBuffers(Address addr) 723{ 724 if (m_waiting_buffers.count(addr) > 0) { 725 // 726 // Wake up all possible lower rank (i.e. lower priority) buffers that could 727 // be waiting on this message. 728 // 729 for (int in_port_rank = m_cur_in_port_rank - 1; 730 in_port_rank >= 0; 731 in_port_rank--) { 732 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) { 733 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr); 734 } 735 } 736 delete m_waiting_buffers[addr]; 737 m_waiting_buffers.erase(addr); 738 } 739} 740 741void 742$c_ident::wakeUpAllBuffers() 743{ 744 // 745 // Wake up all possible buffers that could be waiting on any message. 746 // 747 748 std::vector<MsgVecType*> wokeUpMsgVecs; 749 750 if(m_waiting_buffers.size() > 0) { 751 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin(); 752 buf_iter != m_waiting_buffers.end(); 753 ++buf_iter) { 754 for (MsgVecType::iterator vec_iter = buf_iter->second->begin(); 755 vec_iter != buf_iter->second->end(); 756 ++vec_iter) { 757 if (*vec_iter != NULL) { 758 (*vec_iter)->reanalyzeAllMessages(); 759 } 760 } 761 wokeUpMsgVecs.push_back(buf_iter->second); 762 } 763 764 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin(); 765 wb_iter != wokeUpMsgVecs.end(); 766 ++wb_iter) { 767 delete (*wb_iter); 768 } 769 770 m_waiting_buffers.clear(); 771 } 772} 773 774void 775$c_ident::blockOnQueue(Address addr, MessageBuffer* port) 776{ 777 m_is_blocking = true; 778 m_block_map[addr] = port; 779} 780 781void 782$c_ident::unblock(Address addr) 783{ 784 m_block_map.erase(addr); 785 if (m_block_map.size() == 0) { 786 m_is_blocking = false; 787 } 788} 789 790void 791$c_ident::print(ostream& out) const 792{ 793 out << "[$c_ident " << m_version << "]"; 794} 795 796void 797$c_ident::printConfig(ostream& out) const 798{ 799 out << "$c_ident config: " << m_name << endl; 800 out << " version: " << m_version << endl; 801 map<string, string>::const_iterator it; 802 for (it = m_cfg.begin(); it != m_cfg.end(); it++) 803 out << " " << it->first << ": " << it->second << endl; 804} 805 806void 807$c_ident::printStats(ostream& out) const 808{ 809''') 810 # 811 # Cache and Memory Controllers have specific profilers associated with 812 # them. Print out these stats before dumping state transition stats. 813 # 814 for param in self.config_parameters: 815 if param.type_ast.type.ident == "CacheMemory" or \ 816 param.type_ast.type.ident == "DirectoryMemory" or \ 817 param.type_ast.type.ident == "MemoryControl": 818 assert(param.pointer) 819 code(' m_${{param.ident}}_ptr->printStats(out);') 820 821 code(''' 822 if (m_version == 0) { 823 s_profileDumper.dumpStats(out); 824 } 825} 826 827void $c_ident::clearStats() { 828''') 829 # 830 # Cache and Memory Controllers have specific profilers associated with 831 # them. These stats must be cleared too. 832 # 833 for param in self.config_parameters: 834 if param.type_ast.type.ident == "CacheMemory" or \ 835 param.type_ast.type.ident == "MemoryControl": 836 assert(param.pointer) 837 code(' m_${{param.ident}}_ptr->clearStats();') 838 839 code(''' 840 m_profiler.clearStats(); 841} 842''') 843 844 if self.EntryType != None: 845 code(''' 846 847// Set and Reset for cache_entry variable 848void 849$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 850{ 851 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 852} 853 854void 855$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 856{ 857 m_cache_entry_ptr = 0; 858} 859 860void 861$c_ident::set_permission(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 862 AccessPermission perm) 863{ 864 if (m_cache_entry_ptr != NULL) { 865 m_cache_entry_ptr->changePermission(perm); 866 } 867} 868''') 869 870 if self.TBEType != None: 871 code(''' 872 873// Set and Reset for tbe variable 874void 875$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 876{ 877 m_tbe_ptr = m_new_tbe; 878} 879 880void 881$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 882{ 883 m_tbe_ptr = NULL; 884} 885''') 886 887 code(''' 888 889// Actions 890''') 891 if self.TBEType != None and self.EntryType != None: 892 for action in self.actions.itervalues(): 893 if "c_code" not in action: 894 continue 895 896 code(''' 897/** \\brief ${{action.desc}} */ 898void 899$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 900{ 901 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 902 ${{action["c_code"]}} 903} 904 905''') 906 elif self.TBEType != None: 907 for action in self.actions.itervalues(): 908 if "c_code" not in action: 909 continue 910 911 code(''' 912/** \\brief ${{action.desc}} */ 913void 914$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 915{ 916 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 917 ${{action["c_code"]}} 918} 919 920''') 921 elif self.EntryType != None: 922 for action in self.actions.itervalues(): 923 if "c_code" not in action: 924 continue 925 926 code(''' 927/** \\brief ${{action.desc}} */ 928void 929$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 930{ 931 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 932 ${{action["c_code"]}} 933} 934 935''') 936 else: 937 for action in self.actions.itervalues(): 938 if "c_code" not in action: 939 continue 940 941 code(''' 942/** \\brief ${{action.desc}} */ 943void 944$c_ident::${{action.ident}}(const Address& addr) 945{ 946 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 947 ${{action["c_code"]}} 948} 949 950''') 951 code.write(path, "%s.cc" % c_ident) 952 953 def printCWakeup(self, path): 954 '''Output the wakeup loop for the events''' 955 956 code = self.symtab.codeFormatter() 957 ident = self.ident 958 959 code(''' 960// Auto generated C++ code started by $__file__:$__line__ 961// ${ident}: ${{self.short}} 962 963#include <cassert> 964 965#include "base/misc.hh" 966#include "mem/ruby/common/Global.hh" 967#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 968#include "mem/protocol/${ident}_Controller.hh" 969#include "mem/protocol/${ident}_State.hh" 970#include "mem/protocol/${ident}_Event.hh" 971#include "mem/protocol/Types.hh" 972#include "mem/ruby/system/System.hh" 973 974using namespace std; 975 976void 977${ident}_Controller::wakeup() 978{ 979 int counter = 0; 980 while (true) { 981 // Some cases will put us into an infinite loop without this limit 982 assert(counter <= m_transitions_per_cycle); 983 if (counter == m_transitions_per_cycle) { 984 // Count how often we are fully utilized 985 g_system_ptr->getProfiler()->controllerBusy(m_machineID); 986 987 // Wakeup in another cycle and try again 988 g_eventQueue_ptr->scheduleEvent(this, 1); 989 break; 990 } 991''') 992 993 code.indent() 994 code.indent() 995 996 # InPorts 997 # 998 for port in self.in_ports: 999 code.indent() 1000 code('// ${ident}InPort $port') 1001 if port.pairs.has_key("rank"): 1002 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};') 1003 else: 1004 code('m_cur_in_port_rank = 0;') 1005 code('${{port["c_code_in_port"]}}') 1006 code.dedent() 1007 1008 code('') 1009 1010 code.dedent() 1011 code.dedent() 1012 code(''' 1013 break; // If we got this far, we have nothing left todo 1014 } 1015 // g_eventQueue_ptr->scheduleEvent(this, 1); 1016} 1017''') 1018 1019 code.write(path, "%s_Wakeup.cc" % self.ident) 1020 1021 def printCSwitch(self, path): 1022 '''Output switch statement for transition table''' 1023 1024 code = self.symtab.codeFormatter() 1025 ident = self.ident 1026 1027 code(''' 1028// Auto generated C++ code started by $__file__:$__line__ 1029// ${ident}: ${{self.short}} 1030 1031#include <cassert> 1032 1033#include "base/misc.hh" 1034#include "base/trace.hh" 1035#include "mem/ruby/common/Global.hh" 1036#include "mem/protocol/${ident}_Controller.hh" 1037#include "mem/protocol/${ident}_State.hh" 1038#include "mem/protocol/${ident}_Event.hh" 1039#include "mem/protocol/Types.hh" 1040#include "mem/ruby/system/System.hh" 1041 1042#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1043 1044#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1045#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1046 1047TransitionResult 1048${ident}_Controller::doTransition(${ident}_Event event, 1049''') 1050 if self.EntryType != None: 1051 code(''' 1052 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1053''') 1054 if self.TBEType != None: 1055 code(''' 1056 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1057''') 1058 code(''' 1059 const Address &addr) 1060{ 1061''') 1062 if self.TBEType != None and self.EntryType != None: 1063 code('${ident}_State state = ${ident}_getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1064 elif self.TBEType != None: 1065 code('${ident}_State state = ${ident}_getState(m_tbe_ptr, addr);') 1066 elif self.EntryType != None: 1067 code('${ident}_State state = ${ident}_getState(m_cache_entry_ptr, addr);') 1068 else: 1069 code('${ident}_State state = ${ident}_getState(addr);') 1070 1071 code(''' 1072 ${ident}_State next_state = state; 1073 1074 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1075 *this, 1076 g_eventQueue_ptr->getTime(), 1077 ${ident}_State_to_string(state), 1078 ${ident}_Event_to_string(event), 1079 addr); 1080 1081 TransitionResult result = 1082''') 1083 if self.TBEType != None and self.EntryType != None: 1084 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1085 elif self.TBEType != None: 1086 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1087 elif self.EntryType != None: 1088 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1089 else: 1090 code('doTransitionWorker(event, state, next_state, addr);') 1091 1092 code(''' 1093 if (result == TransitionResult_Valid) { 1094 DPRINTF(RubyGenerated, "next_state: %s\\n", 1095 ${ident}_State_to_string(next_state)); 1096 m_profiler.countTransition(state, event); 1097 DPRINTFR(ProtocolTrace, "%7d %3s %10s%20s %6s>%-6s %s %s\\n", 1098 g_eventQueue_ptr->getTime(), m_version, "${ident}", 1099 ${ident}_Event_to_string(event), 1100 ${ident}_State_to_string(state), 1101 ${ident}_State_to_string(next_state), 1102 addr, GET_TRANSITION_COMMENT()); 1103 1104 CLEAR_TRANSITION_COMMENT(); 1105''') 1106 if self.TBEType != None and self.EntryType != None: 1107 code('${ident}_setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1108 code('set_permission(m_cache_entry_ptr, ${ident}_State_to_permission(next_state));') 1109 elif self.TBEType != None: 1110 code('${ident}_setState(m_tbe_ptr, addr, next_state);') 1111 elif self.EntryType != None: 1112 code('${ident}_setState(m_cache_entry_ptr, addr, next_state);') 1113 code('set_permission(m_cache_entry_ptr, ${ident}_State_to_permission(next_state));') 1114 else: 1115 code('${ident}_setState(addr, next_state);') 1116 1117 code(''' 1118 } else if (result == TransitionResult_ResourceStall) { 1119 DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n", 1120 g_eventQueue_ptr->getTime(), m_version, "${ident}", 1121 ${ident}_Event_to_string(event), 1122 ${ident}_State_to_string(state), 1123 ${ident}_State_to_string(next_state), 1124 addr, "Resource Stall"); 1125 } else if (result == TransitionResult_ProtocolStall) { 1126 DPRINTF(RubyGenerated, "stalling\\n"); 1127 DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n", 1128 g_eventQueue_ptr->getTime(), m_version, "${ident}", 1129 ${ident}_Event_to_string(event), 1130 ${ident}_State_to_string(state), 1131 ${ident}_State_to_string(next_state), 1132 addr, "Protocol Stall"); 1133 } 1134 1135 return result; 1136} 1137 1138TransitionResult 1139${ident}_Controller::doTransitionWorker(${ident}_Event event, 1140 ${ident}_State state, 1141 ${ident}_State& next_state, 1142''') 1143 1144 if self.TBEType != None: 1145 code(''' 1146 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1147''') 1148 if self.EntryType != None: 1149 code(''' 1150 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1151''') 1152 code(''' 1153 const Address& addr) 1154{ 1155 switch(HASH_FUN(state, event)) { 1156''') 1157 1158 # This map will allow suppress generating duplicate code 1159 cases = orderdict() 1160 1161 for trans in self.transitions: 1162 case_string = "%s_State_%s, %s_Event_%s" % \ 1163 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1164 1165 case = self.symtab.codeFormatter() 1166 # Only set next_state if it changes 1167 if trans.state != trans.nextState: 1168 ns_ident = trans.nextState.ident 1169 case('next_state = ${ident}_State_${ns_ident};') 1170 1171 actions = trans.actions 1172 1173 # Check for resources 1174 case_sorter = [] 1175 res = trans.resources 1176 for key,val in res.iteritems(): 1177 if key.type.ident != "DNUCAStopTable": 1178 val = ''' 1179if (!%s.areNSlotsAvailable(%s)) 1180 return TransitionResult_ResourceStall; 1181''' % (key.code, val) 1182 case_sorter.append(val) 1183 1184 1185 # Emit the code sequences in a sorted order. This makes the 1186 # output deterministic (without this the output order can vary 1187 # since Map's keys() on a vector of pointers is not deterministic 1188 for c in sorted(case_sorter): 1189 case("$c") 1190 1191 # Figure out if we stall 1192 stall = False 1193 for action in actions: 1194 if action.ident == "z_stall": 1195 stall = True 1196 break 1197 1198 if stall: 1199 case('return TransitionResult_ProtocolStall;') 1200 else: 1201 if self.TBEType != None and self.EntryType != None: 1202 for action in actions: 1203 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1204 elif self.TBEType != None: 1205 for action in actions: 1206 case('${{action.ident}}(m_tbe_ptr, addr);') 1207 elif self.EntryType != None: 1208 for action in actions: 1209 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1210 else: 1211 for action in actions: 1212 case('${{action.ident}}(addr);') 1213 case('return TransitionResult_Valid;') 1214 1215 case = str(case) 1216 1217 # Look to see if this transition code is unique. 1218 if case not in cases: 1219 cases[case] = [] 1220 1221 cases[case].append(case_string) 1222 1223 # Walk through all of the unique code blocks and spit out the 1224 # corresponding case statement elements 1225 for case,transitions in cases.iteritems(): 1226 # Iterative over all the multiple transitions that share 1227 # the same code 1228 for trans in transitions: 1229 code(' case HASH_FUN($trans):') 1230 code(' $case') 1231 1232 code(''' 1233 default: 1234 fatal("Invalid transition\\n" 1235 "%s time: %d addr: %s event: %s state: %s\\n", 1236 name(), g_eventQueue_ptr->getTime(), addr, event, state); 1237 } 1238 return TransitionResult_Valid; 1239} 1240''') 1241 code.write(path, "%s_Transitions.cc" % self.ident) 1242 1243 def printProfileDumperHH(self, path): 1244 code = self.symtab.codeFormatter() 1245 ident = self.ident 1246 1247 code(''' 1248// Auto generated C++ code started by $__file__:$__line__ 1249// ${ident}: ${{self.short}} 1250 1251#ifndef __${ident}_PROFILE_DUMPER_HH__ 1252#define __${ident}_PROFILE_DUMPER_HH__ 1253 1254#include <cassert> 1255#include <iostream> 1256#include <vector> 1257 1258#include "${ident}_Profiler.hh" 1259#include "${ident}_Event.hh" 1260 1261typedef std::vector<${ident}_Profiler *> ${ident}_profilers; 1262 1263class ${ident}_ProfileDumper 1264{ 1265 public: 1266 ${ident}_ProfileDumper(); 1267 void registerProfiler(${ident}_Profiler* profiler); 1268 void dumpStats(std::ostream& out) const; 1269 1270 private: 1271 ${ident}_profilers m_profilers; 1272}; 1273 1274#endif // __${ident}_PROFILE_DUMPER_HH__ 1275''') 1276 code.write(path, "%s_ProfileDumper.hh" % self.ident) 1277 1278 def printProfileDumperCC(self, path): 1279 code = self.symtab.codeFormatter() 1280 ident = self.ident 1281 1282 code(''' 1283// Auto generated C++ code started by $__file__:$__line__ 1284// ${ident}: ${{self.short}} 1285 1286#include "mem/protocol/${ident}_ProfileDumper.hh" 1287 1288${ident}_ProfileDumper::${ident}_ProfileDumper() 1289{ 1290} 1291 1292void 1293${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler) 1294{ 1295 m_profilers.push_back(profiler); 1296} 1297 1298void 1299${ident}_ProfileDumper::dumpStats(std::ostream& out) const 1300{ 1301 out << " --- ${ident} ---\\n"; 1302 out << " - Event Counts -\\n"; 1303 for (${ident}_Event event = ${ident}_Event_FIRST; 1304 event < ${ident}_Event_NUM; 1305 ++event) { 1306 out << (${ident}_Event) event << " ["; 1307 uint64 total = 0; 1308 for (int i = 0; i < m_profilers.size(); i++) { 1309 out << m_profilers[i]->getEventCount(event) << " "; 1310 total += m_profilers[i]->getEventCount(event); 1311 } 1312 out << "] " << total << "\\n"; 1313 } 1314 out << "\\n"; 1315 out << " - Transitions -\\n"; 1316 for (${ident}_State state = ${ident}_State_FIRST; 1317 state < ${ident}_State_NUM; 1318 ++state) { 1319 for (${ident}_Event event = ${ident}_Event_FIRST; 1320 event < ${ident}_Event_NUM; 1321 ++event) { 1322 if (m_profilers[0]->isPossible(state, event)) { 1323 out << (${ident}_State) state << " " 1324 << (${ident}_Event) event << " ["; 1325 uint64 total = 0; 1326 for (int i = 0; i < m_profilers.size(); i++) { 1327 out << m_profilers[i]->getTransitionCount(state, event) << " "; 1328 total += m_profilers[i]->getTransitionCount(state, event); 1329 } 1330 out << "] " << total << "\\n"; 1331 } 1332 } 1333 out << "\\n"; 1334 } 1335} 1336''') 1337 code.write(path, "%s_ProfileDumper.cc" % self.ident) 1338 1339 def printProfilerHH(self, path): 1340 code = self.symtab.codeFormatter() 1341 ident = self.ident 1342 1343 code(''' 1344// Auto generated C++ code started by $__file__:$__line__ 1345// ${ident}: ${{self.short}} 1346 1347#ifndef __${ident}_PROFILER_HH__ 1348#define __${ident}_PROFILER_HH__ 1349 1350#include <cassert> 1351#include <iostream> 1352 1353#include "mem/ruby/common/Global.hh" 1354#include "mem/protocol/${ident}_State.hh" 1355#include "mem/protocol/${ident}_Event.hh" 1356 1357class ${ident}_Profiler 1358{ 1359 public: 1360 ${ident}_Profiler(); 1361 void setVersion(int version); 1362 void countTransition(${ident}_State state, ${ident}_Event event); 1363 void possibleTransition(${ident}_State state, ${ident}_Event event); 1364 uint64 getEventCount(${ident}_Event event); 1365 bool isPossible(${ident}_State state, ${ident}_Event event); 1366 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 1367 void clearStats(); 1368 1369 private: 1370 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 1371 int m_event_counters[${ident}_Event_NUM]; 1372 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 1373 int m_version; 1374}; 1375 1376#endif // __${ident}_PROFILER_HH__ 1377''') 1378 code.write(path, "%s_Profiler.hh" % self.ident) 1379 1380 def printProfilerCC(self, path): 1381 code = self.symtab.codeFormatter() 1382 ident = self.ident 1383 1384 code(''' 1385// Auto generated C++ code started by $__file__:$__line__ 1386// ${ident}: ${{self.short}} 1387 1388#include <cassert> 1389 1390#include "mem/protocol/${ident}_Profiler.hh" 1391 1392${ident}_Profiler::${ident}_Profiler() 1393{ 1394 for (int state = 0; state < ${ident}_State_NUM; state++) { 1395 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1396 m_possible[state][event] = false; 1397 m_counters[state][event] = 0; 1398 } 1399 } 1400 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1401 m_event_counters[event] = 0; 1402 } 1403} 1404 1405void 1406${ident}_Profiler::setVersion(int version) 1407{ 1408 m_version = version; 1409} 1410 1411void 1412${ident}_Profiler::clearStats() 1413{ 1414 for (int state = 0; state < ${ident}_State_NUM; state++) { 1415 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1416 m_counters[state][event] = 0; 1417 } 1418 } 1419 1420 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1421 m_event_counters[event] = 0; 1422 } 1423} 1424void 1425${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1426{ 1427 assert(m_possible[state][event]); 1428 m_counters[state][event]++; 1429 m_event_counters[event]++; 1430} 1431void 1432${ident}_Profiler::possibleTransition(${ident}_State state, 1433 ${ident}_Event event) 1434{ 1435 m_possible[state][event] = true; 1436} 1437 1438uint64 1439${ident}_Profiler::getEventCount(${ident}_Event event) 1440{ 1441 return m_event_counters[event]; 1442} 1443 1444bool 1445${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event) 1446{ 1447 return m_possible[state][event]; 1448} 1449 1450uint64 1451${ident}_Profiler::getTransitionCount(${ident}_State state, 1452 ${ident}_Event event) 1453{ 1454 return m_counters[state][event]; 1455} 1456 1457''') 1458 code.write(path, "%s_Profiler.cc" % self.ident) 1459 1460 # ************************** 1461 # ******* HTML Files ******* 1462 # ************************** 1463 def frameRef(self, click_href, click_target, over_href, over_num, text): 1464 code = self.symtab.codeFormatter(fix_newlines=False) 1465 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1466 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1467 parent.frames[$over_num].location='$over_href' 1468 }\"> 1469 ${{html.formatShorthand(text)}} 1470 </A>""") 1471 return str(code) 1472 1473 def writeHTMLFiles(self, path): 1474 # Create table with no row hilighted 1475 self.printHTMLTransitions(path, None) 1476 1477 # Generate transition tables 1478 for state in self.states.itervalues(): 1479 self.printHTMLTransitions(path, state) 1480 1481 # Generate action descriptions 1482 for action in self.actions.itervalues(): 1483 name = "%s_action_%s.html" % (self.ident, action.ident) 1484 code = html.createSymbol(action, "Action") 1485 code.write(path, name) 1486 1487 # Generate state descriptions 1488 for state in self.states.itervalues(): 1489 name = "%s_State_%s.html" % (self.ident, state.ident) 1490 code = html.createSymbol(state, "State") 1491 code.write(path, name) 1492 1493 # Generate event descriptions 1494 for event in self.events.itervalues(): 1495 name = "%s_Event_%s.html" % (self.ident, event.ident) 1496 code = html.createSymbol(event, "Event") 1497 code.write(path, name) 1498 1499 def printHTMLTransitions(self, path, active_state): 1500 code = self.symtab.codeFormatter() 1501 1502 code(''' 1503<HTML> 1504<BODY link="blue" vlink="blue"> 1505 1506<H1 align="center">${{html.formatShorthand(self.short)}}: 1507''') 1508 code.indent() 1509 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1510 mid = machine.ident 1511 if i != 0: 1512 extra = " - " 1513 else: 1514 extra = "" 1515 if machine == self: 1516 code('$extra$mid') 1517 else: 1518 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1519 code.dedent() 1520 1521 code(""" 1522</H1> 1523 1524<TABLE border=1> 1525<TR> 1526 <TH> </TH> 1527""") 1528 1529 for event in self.events.itervalues(): 1530 href = "%s_Event_%s.html" % (self.ident, event.ident) 1531 ref = self.frameRef(href, "Status", href, "1", event.short) 1532 code('<TH bgcolor=white>$ref</TH>') 1533 1534 code('</TR>') 1535 # -- Body of table 1536 for state in self.states.itervalues(): 1537 # -- Each row 1538 if state == active_state: 1539 color = "yellow" 1540 else: 1541 color = "white" 1542 1543 click = "%s_table_%s.html" % (self.ident, state.ident) 1544 over = "%s_State_%s.html" % (self.ident, state.ident) 1545 text = html.formatShorthand(state.short) 1546 ref = self.frameRef(click, "Table", over, "1", state.short) 1547 code(''' 1548<TR> 1549 <TH bgcolor=$color>$ref</TH> 1550''') 1551 1552 # -- One column for each event 1553 for event in self.events.itervalues(): 1554 trans = self.table.get((state,event), None) 1555 if trans is None: 1556 # This is the no transition case 1557 if state == active_state: 1558 color = "#C0C000" 1559 else: 1560 color = "lightgrey" 1561 1562 code('<TD bgcolor=$color> </TD>') 1563 continue 1564 1565 next = trans.nextState 1566 stall_action = False 1567 1568 # -- Get the actions 1569 for action in trans.actions: 1570 if action.ident == "z_stall" or \ 1571 action.ident == "zz_recycleMandatoryQueue": 1572 stall_action = True 1573 1574 # -- Print out "actions/next-state" 1575 if stall_action: 1576 if state == active_state: 1577 color = "#C0C000" 1578 else: 1579 color = "lightgrey" 1580 1581 elif active_state and next.ident == active_state.ident: 1582 color = "aqua" 1583 elif state == active_state: 1584 color = "yellow" 1585 else: 1586 color = "white" 1587 1588 code('<TD bgcolor=$color>') 1589 for action in trans.actions: 1590 href = "%s_action_%s.html" % (self.ident, action.ident) 1591 ref = self.frameRef(href, "Status", href, "1", 1592 action.short) 1593 code(' $ref') 1594 if next != state: 1595 if trans.actions: 1596 code('/') 1597 click = "%s_table_%s.html" % (self.ident, next.ident) 1598 over = "%s_State_%s.html" % (self.ident, next.ident) 1599 ref = self.frameRef(click, "Table", over, "1", next.short) 1600 code("$ref") 1601 code("</TD>") 1602 1603 # -- Each row 1604 if state == active_state: 1605 color = "yellow" 1606 else: 1607 color = "white" 1608 1609 click = "%s_table_%s.html" % (self.ident, state.ident) 1610 over = "%s_State_%s.html" % (self.ident, state.ident) 1611 ref = self.frameRef(click, "Table", over, "1", state.short) 1612 code(''' 1613 <TH bgcolor=$color>$ref</TH> 1614</TR> 1615''') 1616 code(''' 1617<!- Column footer-> 1618<TR> 1619 <TH> </TH> 1620''') 1621 1622 for event in self.events.itervalues(): 1623 href = "%s_Event_%s.html" % (self.ident, event.ident) 1624 ref = self.frameRef(href, "Status", href, "1", event.short) 1625 code('<TH bgcolor=white>$ref</TH>') 1626 code(''' 1627</TR> 1628</TABLE> 1629</BODY></HTML> 1630''') 1631 1632 1633 if active_state: 1634 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1635 else: 1636 name = "%s_table.html" % self.ident 1637 code.write(path, name) 1638 1639__all__ = [ "StateMachine" ]
| 508 self.error("The DMA controller must include the sequencer " \ 509 "configuration parameter") 510 511 code(''' 512m_dma_sequencer_ptr->setController(this); 513''') 514 515 code('m_num_controllers++;') 516 for var in self.objects: 517 if var.ident.find("mandatoryQueue") >= 0: 518 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();') 519 520 code.dedent() 521 code(''' 522} 523 524void 525$c_ident::init() 526{ 527 MachineType machine_type; 528 int base; 529 530 m_machineID.type = MachineType_${ident}; 531 m_machineID.num = m_version; 532 533 // initialize objects 534 m_profiler.setVersion(m_version); 535 s_profileDumper.registerProfiler(&m_profiler); 536 537''') 538 539 code.indent() 540 for var in self.objects: 541 vtype = var.type 542 vid = "m_%s_ptr" % var.c_ident 543 if "network" not in var: 544 # Not a network port object 545 if "primitive" in vtype: 546 code('$vid = new ${{vtype.c_ident}};') 547 if "default" in var: 548 code('(*$vid) = ${{var["default"]}};') 549 else: 550 # Normal Object 551 # added by SS 552 if "factory" in var: 553 code('$vid = ${{var["factory"]}};') 554 elif var.ident.find("mandatoryQueue") < 0: 555 th = var.get("template_hack", "") 556 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 557 558 args = "" 559 if "non_obj" not in vtype and not vtype.isEnumeration: 560 if expr.find("TBETable") >= 0: 561 args = "m_number_of_TBEs" 562 else: 563 args = var.get("constructor_hack", "") 564 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 596 assert var.machine is not None 597 code(''' 598machine_type = string_to_MachineType("${{var.machine.ident}}"); 599base = MachineType_base_number(machine_type); 600$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet); 601''') 602 603 code('assert($vid != NULL);') 604 605 # Set ordering 606 if "ordered" in var: 607 # A buffer 608 code('$vid->setOrdering(${{var["ordered"]}});') 609 610 # Set randomization 611 if "random" in var: 612 # A buffer 613 code('$vid->setRandomization(${{var["random"]}});') 614 615 # Set Priority 616 if "rank" in var: 617 code('$vid->setPriority(${{var["rank"]}})') 618 619 # Set buffer size 620 if vtype.isBuffer: 621 code(''' 622if (m_buffer_size > 0) { 623 $vid->resize(m_buffer_size); 624} 625''') 626 627 # set description (may be overriden later by port def) 628 code(''' 629$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]"); 630 631''') 632 633 if vtype.isBuffer: 634 if "recycle_latency" in var: 635 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});') 636 else: 637 code('$vid->setRecycleLatency(m_recycle_latency);') 638 639 640 # Set the queue consumers 641 code() 642 for port in self.in_ports: 643 code('${{port.code}}.setConsumer(this);') 644 645 # Set the queue descriptions 646 code() 647 for port in self.in_ports: 648 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");') 649 650 # Initialize the transition profiling 651 code() 652 for trans in self.transitions: 653 # Figure out if we stall 654 stall = False 655 for action in trans.actions: 656 if action.ident == "z_stall": 657 stall = True 658 659 # Only possible if it is not a 'z' case 660 if not stall: 661 state = "%s_State_%s" % (self.ident, trans.state.ident) 662 event = "%s_Event_%s" % (self.ident, trans.event.ident) 663 code('m_profiler.possibleTransition($state, $event);') 664 665 code.dedent() 666 code('}') 667 668 has_mandatory_q = False 669 for port in self.in_ports: 670 if port.code.find("mandatoryQueue_ptr") >= 0: 671 has_mandatory_q = True 672 673 if has_mandatory_q: 674 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 675 else: 676 mq_ident = "NULL" 677 678 code(''' 679int 680$c_ident::getNumControllers() 681{ 682 return m_num_controllers; 683} 684 685MessageBuffer* 686$c_ident::getMandatoryQueue() const 687{ 688 return $mq_ident; 689} 690 691const int & 692$c_ident::getVersion() const 693{ 694 return m_version; 695} 696 697const string 698$c_ident::toString() const 699{ 700 return "$c_ident"; 701} 702 703const string 704$c_ident::getName() const 705{ 706 return m_name; 707} 708 709const MachineType 710$c_ident::getMachineType() const 711{ 712 return MachineType_${ident}; 713} 714 715void 716$c_ident::stallBuffer(MessageBuffer* buf, Address addr) 717{ 718 if (m_waiting_buffers.count(addr) == 0) { 719 MsgVecType* msgVec = new MsgVecType; 720 msgVec->resize(m_max_in_port_rank, NULL); 721 m_waiting_buffers[addr] = msgVec; 722 } 723 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf; 724} 725 726void 727$c_ident::wakeUpBuffers(Address addr) 728{ 729 if (m_waiting_buffers.count(addr) > 0) { 730 // 731 // Wake up all possible lower rank (i.e. lower priority) buffers that could 732 // be waiting on this message. 733 // 734 for (int in_port_rank = m_cur_in_port_rank - 1; 735 in_port_rank >= 0; 736 in_port_rank--) { 737 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) { 738 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr); 739 } 740 } 741 delete m_waiting_buffers[addr]; 742 m_waiting_buffers.erase(addr); 743 } 744} 745 746void 747$c_ident::wakeUpAllBuffers() 748{ 749 // 750 // Wake up all possible buffers that could be waiting on any message. 751 // 752 753 std::vector<MsgVecType*> wokeUpMsgVecs; 754 755 if(m_waiting_buffers.size() > 0) { 756 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin(); 757 buf_iter != m_waiting_buffers.end(); 758 ++buf_iter) { 759 for (MsgVecType::iterator vec_iter = buf_iter->second->begin(); 760 vec_iter != buf_iter->second->end(); 761 ++vec_iter) { 762 if (*vec_iter != NULL) { 763 (*vec_iter)->reanalyzeAllMessages(); 764 } 765 } 766 wokeUpMsgVecs.push_back(buf_iter->second); 767 } 768 769 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin(); 770 wb_iter != wokeUpMsgVecs.end(); 771 ++wb_iter) { 772 delete (*wb_iter); 773 } 774 775 m_waiting_buffers.clear(); 776 } 777} 778 779void 780$c_ident::blockOnQueue(Address addr, MessageBuffer* port) 781{ 782 m_is_blocking = true; 783 m_block_map[addr] = port; 784} 785 786void 787$c_ident::unblock(Address addr) 788{ 789 m_block_map.erase(addr); 790 if (m_block_map.size() == 0) { 791 m_is_blocking = false; 792 } 793} 794 795void 796$c_ident::print(ostream& out) const 797{ 798 out << "[$c_ident " << m_version << "]"; 799} 800 801void 802$c_ident::printConfig(ostream& out) const 803{ 804 out << "$c_ident config: " << m_name << endl; 805 out << " version: " << m_version << endl; 806 map<string, string>::const_iterator it; 807 for (it = m_cfg.begin(); it != m_cfg.end(); it++) 808 out << " " << it->first << ": " << it->second << endl; 809} 810 811void 812$c_ident::printStats(ostream& out) const 813{ 814''') 815 # 816 # Cache and Memory Controllers have specific profilers associated with 817 # them. Print out these stats before dumping state transition stats. 818 # 819 for param in self.config_parameters: 820 if param.type_ast.type.ident == "CacheMemory" or \ 821 param.type_ast.type.ident == "DirectoryMemory" or \ 822 param.type_ast.type.ident == "MemoryControl": 823 assert(param.pointer) 824 code(' m_${{param.ident}}_ptr->printStats(out);') 825 826 code(''' 827 if (m_version == 0) { 828 s_profileDumper.dumpStats(out); 829 } 830} 831 832void $c_ident::clearStats() { 833''') 834 # 835 # Cache and Memory Controllers have specific profilers associated with 836 # them. These stats must be cleared too. 837 # 838 for param in self.config_parameters: 839 if param.type_ast.type.ident == "CacheMemory" or \ 840 param.type_ast.type.ident == "MemoryControl": 841 assert(param.pointer) 842 code(' m_${{param.ident}}_ptr->clearStats();') 843 844 code(''' 845 m_profiler.clearStats(); 846} 847''') 848 849 if self.EntryType != None: 850 code(''' 851 852// Set and Reset for cache_entry variable 853void 854$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 855{ 856 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 857} 858 859void 860$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 861{ 862 m_cache_entry_ptr = 0; 863} 864 865void 866$c_ident::set_permission(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 867 AccessPermission perm) 868{ 869 if (m_cache_entry_ptr != NULL) { 870 m_cache_entry_ptr->changePermission(perm); 871 } 872} 873''') 874 875 if self.TBEType != None: 876 code(''' 877 878// Set and Reset for tbe variable 879void 880$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 881{ 882 m_tbe_ptr = m_new_tbe; 883} 884 885void 886$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 887{ 888 m_tbe_ptr = NULL; 889} 890''') 891 892 code(''' 893 894// Actions 895''') 896 if self.TBEType != None and self.EntryType != None: 897 for action in self.actions.itervalues(): 898 if "c_code" not in action: 899 continue 900 901 code(''' 902/** \\brief ${{action.desc}} */ 903void 904$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 905{ 906 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 907 ${{action["c_code"]}} 908} 909 910''') 911 elif self.TBEType != None: 912 for action in self.actions.itervalues(): 913 if "c_code" not in action: 914 continue 915 916 code(''' 917/** \\brief ${{action.desc}} */ 918void 919$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 920{ 921 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 922 ${{action["c_code"]}} 923} 924 925''') 926 elif self.EntryType != None: 927 for action in self.actions.itervalues(): 928 if "c_code" not in action: 929 continue 930 931 code(''' 932/** \\brief ${{action.desc}} */ 933void 934$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 935{ 936 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 937 ${{action["c_code"]}} 938} 939 940''') 941 else: 942 for action in self.actions.itervalues(): 943 if "c_code" not in action: 944 continue 945 946 code(''' 947/** \\brief ${{action.desc}} */ 948void 949$c_ident::${{action.ident}}(const Address& addr) 950{ 951 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 952 ${{action["c_code"]}} 953} 954 955''') 956 code.write(path, "%s.cc" % c_ident) 957 958 def printCWakeup(self, path): 959 '''Output the wakeup loop for the events''' 960 961 code = self.symtab.codeFormatter() 962 ident = self.ident 963 964 code(''' 965// Auto generated C++ code started by $__file__:$__line__ 966// ${ident}: ${{self.short}} 967 968#include <cassert> 969 970#include "base/misc.hh" 971#include "mem/ruby/common/Global.hh" 972#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 973#include "mem/protocol/${ident}_Controller.hh" 974#include "mem/protocol/${ident}_State.hh" 975#include "mem/protocol/${ident}_Event.hh" 976#include "mem/protocol/Types.hh" 977#include "mem/ruby/system/System.hh" 978 979using namespace std; 980 981void 982${ident}_Controller::wakeup() 983{ 984 int counter = 0; 985 while (true) { 986 // Some cases will put us into an infinite loop without this limit 987 assert(counter <= m_transitions_per_cycle); 988 if (counter == m_transitions_per_cycle) { 989 // Count how often we are fully utilized 990 g_system_ptr->getProfiler()->controllerBusy(m_machineID); 991 992 // Wakeup in another cycle and try again 993 g_eventQueue_ptr->scheduleEvent(this, 1); 994 break; 995 } 996''') 997 998 code.indent() 999 code.indent() 1000 1001 # InPorts 1002 # 1003 for port in self.in_ports: 1004 code.indent() 1005 code('// ${ident}InPort $port') 1006 if port.pairs.has_key("rank"): 1007 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};') 1008 else: 1009 code('m_cur_in_port_rank = 0;') 1010 code('${{port["c_code_in_port"]}}') 1011 code.dedent() 1012 1013 code('') 1014 1015 code.dedent() 1016 code.dedent() 1017 code(''' 1018 break; // If we got this far, we have nothing left todo 1019 } 1020 // g_eventQueue_ptr->scheduleEvent(this, 1); 1021} 1022''') 1023 1024 code.write(path, "%s_Wakeup.cc" % self.ident) 1025 1026 def printCSwitch(self, path): 1027 '''Output switch statement for transition table''' 1028 1029 code = self.symtab.codeFormatter() 1030 ident = self.ident 1031 1032 code(''' 1033// Auto generated C++ code started by $__file__:$__line__ 1034// ${ident}: ${{self.short}} 1035 1036#include <cassert> 1037 1038#include "base/misc.hh" 1039#include "base/trace.hh" 1040#include "mem/ruby/common/Global.hh" 1041#include "mem/protocol/${ident}_Controller.hh" 1042#include "mem/protocol/${ident}_State.hh" 1043#include "mem/protocol/${ident}_Event.hh" 1044#include "mem/protocol/Types.hh" 1045#include "mem/ruby/system/System.hh" 1046 1047#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1048 1049#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1050#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1051 1052TransitionResult 1053${ident}_Controller::doTransition(${ident}_Event event, 1054''') 1055 if self.EntryType != None: 1056 code(''' 1057 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1058''') 1059 if self.TBEType != None: 1060 code(''' 1061 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1062''') 1063 code(''' 1064 const Address &addr) 1065{ 1066''') 1067 if self.TBEType != None and self.EntryType != None: 1068 code('${ident}_State state = ${ident}_getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1069 elif self.TBEType != None: 1070 code('${ident}_State state = ${ident}_getState(m_tbe_ptr, addr);') 1071 elif self.EntryType != None: 1072 code('${ident}_State state = ${ident}_getState(m_cache_entry_ptr, addr);') 1073 else: 1074 code('${ident}_State state = ${ident}_getState(addr);') 1075 1076 code(''' 1077 ${ident}_State next_state = state; 1078 1079 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1080 *this, 1081 g_eventQueue_ptr->getTime(), 1082 ${ident}_State_to_string(state), 1083 ${ident}_Event_to_string(event), 1084 addr); 1085 1086 TransitionResult result = 1087''') 1088 if self.TBEType != None and self.EntryType != None: 1089 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1090 elif self.TBEType != None: 1091 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1092 elif self.EntryType != None: 1093 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1094 else: 1095 code('doTransitionWorker(event, state, next_state, addr);') 1096 1097 code(''' 1098 if (result == TransitionResult_Valid) { 1099 DPRINTF(RubyGenerated, "next_state: %s\\n", 1100 ${ident}_State_to_string(next_state)); 1101 m_profiler.countTransition(state, event); 1102 DPRINTFR(ProtocolTrace, "%7d %3s %10s%20s %6s>%-6s %s %s\\n", 1103 g_eventQueue_ptr->getTime(), m_version, "${ident}", 1104 ${ident}_Event_to_string(event), 1105 ${ident}_State_to_string(state), 1106 ${ident}_State_to_string(next_state), 1107 addr, GET_TRANSITION_COMMENT()); 1108 1109 CLEAR_TRANSITION_COMMENT(); 1110''') 1111 if self.TBEType != None and self.EntryType != None: 1112 code('${ident}_setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1113 code('set_permission(m_cache_entry_ptr, ${ident}_State_to_permission(next_state));') 1114 elif self.TBEType != None: 1115 code('${ident}_setState(m_tbe_ptr, addr, next_state);') 1116 elif self.EntryType != None: 1117 code('${ident}_setState(m_cache_entry_ptr, addr, next_state);') 1118 code('set_permission(m_cache_entry_ptr, ${ident}_State_to_permission(next_state));') 1119 else: 1120 code('${ident}_setState(addr, next_state);') 1121 1122 code(''' 1123 } else if (result == TransitionResult_ResourceStall) { 1124 DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n", 1125 g_eventQueue_ptr->getTime(), m_version, "${ident}", 1126 ${ident}_Event_to_string(event), 1127 ${ident}_State_to_string(state), 1128 ${ident}_State_to_string(next_state), 1129 addr, "Resource Stall"); 1130 } else if (result == TransitionResult_ProtocolStall) { 1131 DPRINTF(RubyGenerated, "stalling\\n"); 1132 DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n", 1133 g_eventQueue_ptr->getTime(), m_version, "${ident}", 1134 ${ident}_Event_to_string(event), 1135 ${ident}_State_to_string(state), 1136 ${ident}_State_to_string(next_state), 1137 addr, "Protocol Stall"); 1138 } 1139 1140 return result; 1141} 1142 1143TransitionResult 1144${ident}_Controller::doTransitionWorker(${ident}_Event event, 1145 ${ident}_State state, 1146 ${ident}_State& next_state, 1147''') 1148 1149 if self.TBEType != None: 1150 code(''' 1151 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1152''') 1153 if self.EntryType != None: 1154 code(''' 1155 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1156''') 1157 code(''' 1158 const Address& addr) 1159{ 1160 switch(HASH_FUN(state, event)) { 1161''') 1162 1163 # This map will allow suppress generating duplicate code 1164 cases = orderdict() 1165 1166 for trans in self.transitions: 1167 case_string = "%s_State_%s, %s_Event_%s" % \ 1168 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1169 1170 case = self.symtab.codeFormatter() 1171 # Only set next_state if it changes 1172 if trans.state != trans.nextState: 1173 ns_ident = trans.nextState.ident 1174 case('next_state = ${ident}_State_${ns_ident};') 1175 1176 actions = trans.actions 1177 1178 # Check for resources 1179 case_sorter = [] 1180 res = trans.resources 1181 for key,val in res.iteritems(): 1182 if key.type.ident != "DNUCAStopTable": 1183 val = ''' 1184if (!%s.areNSlotsAvailable(%s)) 1185 return TransitionResult_ResourceStall; 1186''' % (key.code, val) 1187 case_sorter.append(val) 1188 1189 1190 # Emit the code sequences in a sorted order. This makes the 1191 # output deterministic (without this the output order can vary 1192 # since Map's keys() on a vector of pointers is not deterministic 1193 for c in sorted(case_sorter): 1194 case("$c") 1195 1196 # Figure out if we stall 1197 stall = False 1198 for action in actions: 1199 if action.ident == "z_stall": 1200 stall = True 1201 break 1202 1203 if stall: 1204 case('return TransitionResult_ProtocolStall;') 1205 else: 1206 if self.TBEType != None and self.EntryType != None: 1207 for action in actions: 1208 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1209 elif self.TBEType != None: 1210 for action in actions: 1211 case('${{action.ident}}(m_tbe_ptr, addr);') 1212 elif self.EntryType != None: 1213 for action in actions: 1214 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1215 else: 1216 for action in actions: 1217 case('${{action.ident}}(addr);') 1218 case('return TransitionResult_Valid;') 1219 1220 case = str(case) 1221 1222 # Look to see if this transition code is unique. 1223 if case not in cases: 1224 cases[case] = [] 1225 1226 cases[case].append(case_string) 1227 1228 # Walk through all of the unique code blocks and spit out the 1229 # corresponding case statement elements 1230 for case,transitions in cases.iteritems(): 1231 # Iterative over all the multiple transitions that share 1232 # the same code 1233 for trans in transitions: 1234 code(' case HASH_FUN($trans):') 1235 code(' $case') 1236 1237 code(''' 1238 default: 1239 fatal("Invalid transition\\n" 1240 "%s time: %d addr: %s event: %s state: %s\\n", 1241 name(), g_eventQueue_ptr->getTime(), addr, event, state); 1242 } 1243 return TransitionResult_Valid; 1244} 1245''') 1246 code.write(path, "%s_Transitions.cc" % self.ident) 1247 1248 def printProfileDumperHH(self, path): 1249 code = self.symtab.codeFormatter() 1250 ident = self.ident 1251 1252 code(''' 1253// Auto generated C++ code started by $__file__:$__line__ 1254// ${ident}: ${{self.short}} 1255 1256#ifndef __${ident}_PROFILE_DUMPER_HH__ 1257#define __${ident}_PROFILE_DUMPER_HH__ 1258 1259#include <cassert> 1260#include <iostream> 1261#include <vector> 1262 1263#include "${ident}_Profiler.hh" 1264#include "${ident}_Event.hh" 1265 1266typedef std::vector<${ident}_Profiler *> ${ident}_profilers; 1267 1268class ${ident}_ProfileDumper 1269{ 1270 public: 1271 ${ident}_ProfileDumper(); 1272 void registerProfiler(${ident}_Profiler* profiler); 1273 void dumpStats(std::ostream& out) const; 1274 1275 private: 1276 ${ident}_profilers m_profilers; 1277}; 1278 1279#endif // __${ident}_PROFILE_DUMPER_HH__ 1280''') 1281 code.write(path, "%s_ProfileDumper.hh" % self.ident) 1282 1283 def printProfileDumperCC(self, path): 1284 code = self.symtab.codeFormatter() 1285 ident = self.ident 1286 1287 code(''' 1288// Auto generated C++ code started by $__file__:$__line__ 1289// ${ident}: ${{self.short}} 1290 1291#include "mem/protocol/${ident}_ProfileDumper.hh" 1292 1293${ident}_ProfileDumper::${ident}_ProfileDumper() 1294{ 1295} 1296 1297void 1298${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler) 1299{ 1300 m_profilers.push_back(profiler); 1301} 1302 1303void 1304${ident}_ProfileDumper::dumpStats(std::ostream& out) const 1305{ 1306 out << " --- ${ident} ---\\n"; 1307 out << " - Event Counts -\\n"; 1308 for (${ident}_Event event = ${ident}_Event_FIRST; 1309 event < ${ident}_Event_NUM; 1310 ++event) { 1311 out << (${ident}_Event) event << " ["; 1312 uint64 total = 0; 1313 for (int i = 0; i < m_profilers.size(); i++) { 1314 out << m_profilers[i]->getEventCount(event) << " "; 1315 total += m_profilers[i]->getEventCount(event); 1316 } 1317 out << "] " << total << "\\n"; 1318 } 1319 out << "\\n"; 1320 out << " - Transitions -\\n"; 1321 for (${ident}_State state = ${ident}_State_FIRST; 1322 state < ${ident}_State_NUM; 1323 ++state) { 1324 for (${ident}_Event event = ${ident}_Event_FIRST; 1325 event < ${ident}_Event_NUM; 1326 ++event) { 1327 if (m_profilers[0]->isPossible(state, event)) { 1328 out << (${ident}_State) state << " " 1329 << (${ident}_Event) event << " ["; 1330 uint64 total = 0; 1331 for (int i = 0; i < m_profilers.size(); i++) { 1332 out << m_profilers[i]->getTransitionCount(state, event) << " "; 1333 total += m_profilers[i]->getTransitionCount(state, event); 1334 } 1335 out << "] " << total << "\\n"; 1336 } 1337 } 1338 out << "\\n"; 1339 } 1340} 1341''') 1342 code.write(path, "%s_ProfileDumper.cc" % self.ident) 1343 1344 def printProfilerHH(self, path): 1345 code = self.symtab.codeFormatter() 1346 ident = self.ident 1347 1348 code(''' 1349// Auto generated C++ code started by $__file__:$__line__ 1350// ${ident}: ${{self.short}} 1351 1352#ifndef __${ident}_PROFILER_HH__ 1353#define __${ident}_PROFILER_HH__ 1354 1355#include <cassert> 1356#include <iostream> 1357 1358#include "mem/ruby/common/Global.hh" 1359#include "mem/protocol/${ident}_State.hh" 1360#include "mem/protocol/${ident}_Event.hh" 1361 1362class ${ident}_Profiler 1363{ 1364 public: 1365 ${ident}_Profiler(); 1366 void setVersion(int version); 1367 void countTransition(${ident}_State state, ${ident}_Event event); 1368 void possibleTransition(${ident}_State state, ${ident}_Event event); 1369 uint64 getEventCount(${ident}_Event event); 1370 bool isPossible(${ident}_State state, ${ident}_Event event); 1371 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 1372 void clearStats(); 1373 1374 private: 1375 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 1376 int m_event_counters[${ident}_Event_NUM]; 1377 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 1378 int m_version; 1379}; 1380 1381#endif // __${ident}_PROFILER_HH__ 1382''') 1383 code.write(path, "%s_Profiler.hh" % self.ident) 1384 1385 def printProfilerCC(self, path): 1386 code = self.symtab.codeFormatter() 1387 ident = self.ident 1388 1389 code(''' 1390// Auto generated C++ code started by $__file__:$__line__ 1391// ${ident}: ${{self.short}} 1392 1393#include <cassert> 1394 1395#include "mem/protocol/${ident}_Profiler.hh" 1396 1397${ident}_Profiler::${ident}_Profiler() 1398{ 1399 for (int state = 0; state < ${ident}_State_NUM; state++) { 1400 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1401 m_possible[state][event] = false; 1402 m_counters[state][event] = 0; 1403 } 1404 } 1405 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1406 m_event_counters[event] = 0; 1407 } 1408} 1409 1410void 1411${ident}_Profiler::setVersion(int version) 1412{ 1413 m_version = version; 1414} 1415 1416void 1417${ident}_Profiler::clearStats() 1418{ 1419 for (int state = 0; state < ${ident}_State_NUM; state++) { 1420 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1421 m_counters[state][event] = 0; 1422 } 1423 } 1424 1425 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1426 m_event_counters[event] = 0; 1427 } 1428} 1429void 1430${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1431{ 1432 assert(m_possible[state][event]); 1433 m_counters[state][event]++; 1434 m_event_counters[event]++; 1435} 1436void 1437${ident}_Profiler::possibleTransition(${ident}_State state, 1438 ${ident}_Event event) 1439{ 1440 m_possible[state][event] = true; 1441} 1442 1443uint64 1444${ident}_Profiler::getEventCount(${ident}_Event event) 1445{ 1446 return m_event_counters[event]; 1447} 1448 1449bool 1450${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event) 1451{ 1452 return m_possible[state][event]; 1453} 1454 1455uint64 1456${ident}_Profiler::getTransitionCount(${ident}_State state, 1457 ${ident}_Event event) 1458{ 1459 return m_counters[state][event]; 1460} 1461 1462''') 1463 code.write(path, "%s_Profiler.cc" % self.ident) 1464 1465 # ************************** 1466 # ******* HTML Files ******* 1467 # ************************** 1468 def frameRef(self, click_href, click_target, over_href, over_num, text): 1469 code = self.symtab.codeFormatter(fix_newlines=False) 1470 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1471 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1472 parent.frames[$over_num].location='$over_href' 1473 }\"> 1474 ${{html.formatShorthand(text)}} 1475 </A>""") 1476 return str(code) 1477 1478 def writeHTMLFiles(self, path): 1479 # Create table with no row hilighted 1480 self.printHTMLTransitions(path, None) 1481 1482 # Generate transition tables 1483 for state in self.states.itervalues(): 1484 self.printHTMLTransitions(path, state) 1485 1486 # Generate action descriptions 1487 for action in self.actions.itervalues(): 1488 name = "%s_action_%s.html" % (self.ident, action.ident) 1489 code = html.createSymbol(action, "Action") 1490 code.write(path, name) 1491 1492 # Generate state descriptions 1493 for state in self.states.itervalues(): 1494 name = "%s_State_%s.html" % (self.ident, state.ident) 1495 code = html.createSymbol(state, "State") 1496 code.write(path, name) 1497 1498 # Generate event descriptions 1499 for event in self.events.itervalues(): 1500 name = "%s_Event_%s.html" % (self.ident, event.ident) 1501 code = html.createSymbol(event, "Event") 1502 code.write(path, name) 1503 1504 def printHTMLTransitions(self, path, active_state): 1505 code = self.symtab.codeFormatter() 1506 1507 code(''' 1508<HTML> 1509<BODY link="blue" vlink="blue"> 1510 1511<H1 align="center">${{html.formatShorthand(self.short)}}: 1512''') 1513 code.indent() 1514 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1515 mid = machine.ident 1516 if i != 0: 1517 extra = " - " 1518 else: 1519 extra = "" 1520 if machine == self: 1521 code('$extra$mid') 1522 else: 1523 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1524 code.dedent() 1525 1526 code(""" 1527</H1> 1528 1529<TABLE border=1> 1530<TR> 1531 <TH> </TH> 1532""") 1533 1534 for event in self.events.itervalues(): 1535 href = "%s_Event_%s.html" % (self.ident, event.ident) 1536 ref = self.frameRef(href, "Status", href, "1", event.short) 1537 code('<TH bgcolor=white>$ref</TH>') 1538 1539 code('</TR>') 1540 # -- Body of table 1541 for state in self.states.itervalues(): 1542 # -- Each row 1543 if state == active_state: 1544 color = "yellow" 1545 else: 1546 color = "white" 1547 1548 click = "%s_table_%s.html" % (self.ident, state.ident) 1549 over = "%s_State_%s.html" % (self.ident, state.ident) 1550 text = html.formatShorthand(state.short) 1551 ref = self.frameRef(click, "Table", over, "1", state.short) 1552 code(''' 1553<TR> 1554 <TH bgcolor=$color>$ref</TH> 1555''') 1556 1557 # -- One column for each event 1558 for event in self.events.itervalues(): 1559 trans = self.table.get((state,event), None) 1560 if trans is None: 1561 # This is the no transition case 1562 if state == active_state: 1563 color = "#C0C000" 1564 else: 1565 color = "lightgrey" 1566 1567 code('<TD bgcolor=$color> </TD>') 1568 continue 1569 1570 next = trans.nextState 1571 stall_action = False 1572 1573 # -- Get the actions 1574 for action in trans.actions: 1575 if action.ident == "z_stall" or \ 1576 action.ident == "zz_recycleMandatoryQueue": 1577 stall_action = True 1578 1579 # -- Print out "actions/next-state" 1580 if stall_action: 1581 if state == active_state: 1582 color = "#C0C000" 1583 else: 1584 color = "lightgrey" 1585 1586 elif active_state and next.ident == active_state.ident: 1587 color = "aqua" 1588 elif state == active_state: 1589 color = "yellow" 1590 else: 1591 color = "white" 1592 1593 code('<TD bgcolor=$color>') 1594 for action in trans.actions: 1595 href = "%s_action_%s.html" % (self.ident, action.ident) 1596 ref = self.frameRef(href, "Status", href, "1", 1597 action.short) 1598 code(' $ref') 1599 if next != state: 1600 if trans.actions: 1601 code('/') 1602 click = "%s_table_%s.html" % (self.ident, next.ident) 1603 over = "%s_State_%s.html" % (self.ident, next.ident) 1604 ref = self.frameRef(click, "Table", over, "1", next.short) 1605 code("$ref") 1606 code("</TD>") 1607 1608 # -- Each row 1609 if state == active_state: 1610 color = "yellow" 1611 else: 1612 color = "white" 1613 1614 click = "%s_table_%s.html" % (self.ident, state.ident) 1615 over = "%s_State_%s.html" % (self.ident, state.ident) 1616 ref = self.frameRef(click, "Table", over, "1", state.short) 1617 code(''' 1618 <TH bgcolor=$color>$ref</TH> 1619</TR> 1620''') 1621 code(''' 1622<!- Column footer-> 1623<TR> 1624 <TH> </TH> 1625''') 1626 1627 for event in self.events.itervalues(): 1628 href = "%s_Event_%s.html" % (self.ident, event.ident) 1629 ref = self.frameRef(href, "Status", href, "1", event.short) 1630 code('<TH bgcolor=white>$ref</TH>') 1631 code(''' 1632</TR> 1633</TABLE> 1634</BODY></HTML> 1635''') 1636 1637 1638 if active_state: 1639 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1640 else: 1641 name = "%s_table.html" % self.ident 1642 code.write(path, name) 1643 1644__all__ = [ "StateMachine" ]
|