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