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