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 = { 36 "int": "Int", 37 "uint32_t" : "UInt32", 38 "std::string": "String", 39 "bool": "Bool", 40 "CacheMemory": "RubyCache", 41 "WireBuffer": "RubyWireBuffer", 42 "Sequencer": "RubySequencer", 43 "DirectoryMemory": "RubyDirectoryMemory", 44 "MemoryControl": "MemoryControl", 45 "DMASequencer": "DMASequencer", 46 "Prefetcher":"Prefetcher", 47 "Cycles":"Cycles", 48 } 49 50class StateMachine(Symbol): 51 def __init__(self, symtab, ident, location, pairs, config_parameters): 52 super(StateMachine, self).__init__(symtab, ident, location, pairs) 53 self.table = None 54 self.config_parameters = config_parameters 55 self.prefetchers = [] 56 57 for param in config_parameters: 58 if param.pointer: 59 var = Var(symtab, param.name, location, param.type_ast.type, 60 "(*m_%s_ptr)" % param.name, {}, self) 61 else: 62 var = Var(symtab, param.name, location, param.type_ast.type, 63 "m_%s" % param.name, {}, self) 64 self.symtab.registerSym(param.name, var) 65 if str(param.type_ast.type) == "Prefetcher": 66 self.prefetchers.append(var) 67 68 self.states = orderdict() 69 self.events = orderdict() 70 self.actions = orderdict() 71 self.request_types = orderdict() 72 self.transitions = [] 73 self.in_ports = [] 74 self.functions = [] 75 self.objects = [] 76 self.TBEType = None 77 self.EntryType = None 78 79 def __repr__(self): 80 return "[StateMachine: %s]" % self.ident 81 82 def addState(self, state): 83 assert self.table is None 84 self.states[state.ident] = state 85 86 def addEvent(self, event): 87 assert self.table is None 88 self.events[event.ident] = event 89 90 def addAction(self, action): 91 assert self.table is None 92 93 # Check for duplicate action 94 for other in self.actions.itervalues(): 95 if action.ident == other.ident: 96 action.warning("Duplicate action definition: %s" % action.ident) 97 action.error("Duplicate action definition: %s" % action.ident) 98 if action.short == other.short: 99 other.warning("Duplicate action shorthand: %s" % other.ident) 100 other.warning(" shorthand = %s" % other.short) 101 action.warning("Duplicate action shorthand: %s" % action.ident) 102 action.error(" shorthand = %s" % action.short) 103 104 self.actions[action.ident] = action 105 106 def addRequestType(self, request_type): 107 assert self.table is None 108 self.request_types[request_type.ident] = request_type 109 110 def addTransition(self, trans): 111 assert self.table is None 112 self.transitions.append(trans) 113 114 def addInPort(self, var): 115 self.in_ports.append(var) 116 117 def addFunc(self, func): 118 # register func in the symbol table 119 self.symtab.registerSym(str(func), func) 120 self.functions.append(func) 121 122 def addObject(self, obj): 123 self.objects.append(obj) 124 125 def addType(self, type): 126 type_ident = '%s' % type.c_ident 127 128 if type_ident == "%s_TBE" %self.ident: 129 if self.TBEType != None: 130 self.error("Multiple Transaction Buffer types in a " \ 131 "single machine."); 132 self.TBEType = type 133 134 elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 135 if self.EntryType != None: 136 self.error("Multiple AbstractCacheEntry types in a " \ 137 "single machine."); 138 self.EntryType = type 139 140 # Needs to be called before accessing the table 141 def buildTable(self): 142 assert self.table is None 143 144 table = {} 145 146 for trans in self.transitions: 147 # Track which actions we touch so we know if we use them 148 # all -- really this should be done for all symbols as 149 # part of the symbol table, then only trigger it for 150 # Actions, States, Events, etc. 151 152 for action in trans.actions: 153 action.used = True 154 155 index = (trans.state, trans.event) 156 if index in table: 157 table[index].warning("Duplicate transition: %s" % table[index]) 158 trans.error("Duplicate transition: %s" % trans) 159 table[index] = trans 160 161 # Look at all actions to make sure we used them all 162 for action in self.actions.itervalues(): 163 if not action.used: 164 error_msg = "Unused action: %s" % action.ident 165 if "desc" in action: 166 error_msg += ", " + action.desc 167 action.warning(error_msg) 168 self.table = table 169 170 def writeCodeFiles(self, path, includes): 171 self.printControllerPython(path) 172 self.printControllerHH(path) 173 self.printControllerCC(path, includes) 174 self.printCSwitch(path) 175 self.printCWakeup(path, includes) 176 177 def printControllerPython(self, path): 178 code = self.symtab.codeFormatter() 179 ident = self.ident 180 py_ident = "%s_Controller" % ident 181 c_ident = "%s_Controller" % self.ident 182 code(''' 183from m5.params import * 184from m5.SimObject import SimObject 185from Controller import RubyController 186 187class $py_ident(RubyController): 188 type = '$py_ident' 189 cxx_header = 'mem/protocol/${c_ident}.hh' 190''') 191 code.indent() 192 for param in self.config_parameters: 193 dflt_str = '' 194 if param.default is not None: 195 dflt_str = str(param.default) + ', ' 196 if python_class_map.has_key(param.type_ast.type.c_ident): 197 python_type = python_class_map[param.type_ast.type.c_ident] 198 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 199 else: 200 self.error("Unknown c++ to python class conversion for c++ " \ 201 "type: '%s'. Please update the python_class_map " \ 202 "in StateMachine.py", param.type_ast.type.c_ident) 203 code.dedent() 204 code.write(path, '%s.py' % py_ident) 205 206 207 def printControllerHH(self, path): 208 '''Output the method declarations for the class declaration''' 209 code = self.symtab.codeFormatter() 210 ident = self.ident 211 c_ident = "%s_Controller" % self.ident 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/TransitionResult.hh" 228#include "mem/protocol/Types.hh" 229#include "mem/ruby/common/Consumer.hh" 230#include "mem/ruby/common/Global.hh" 231#include "mem/ruby/slicc_interface/AbstractController.hh" 232#include "params/$c_ident.hh" 233''') 234 235 seen_types = set() 236 has_peer = False 237 for var in self.objects: 238 if var.type.ident not in seen_types and not var.type.isPrimitive: 239 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 240 if "network" in var and "physical_network" in var: 241 has_peer = True 242 seen_types.add(var.type.ident) 243 244 # for adding information to the protocol debug trace 245 code(''' 246extern std::stringstream ${ident}_transitionComment; 247 248class $c_ident : public AbstractController 249{ 250 public: 251 typedef ${c_ident}Params Params; 252 $c_ident(const Params *p); 253 static int getNumControllers(); 254 void init(); 255 MessageBuffer* getMandatoryQueue() const; 256 const std::string toString() const; 257 258 void print(std::ostream& out) const; 259 void wakeup(); 260 void resetStats(); 261 void regStats(); 262 void collateStats(); 263 264 void recordCacheTrace(int cntrl, CacheRecorder* tr); 265 Sequencer* getSequencer() const; 266 267 bool functionalReadBuffers(PacketPtr&); 268 uint32_t functionalWriteBuffers(PacketPtr&); 269 270 void countTransition(${ident}_State state, ${ident}_Event event); 271 void possibleTransition(${ident}_State state, ${ident}_Event event); 272 uint64 getEventCount(${ident}_Event event); 273 bool isPossible(${ident}_State state, ${ident}_Event event); 274 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 275 276private: 277''') 278 279 code.indent() 280 # added by SS 281 for param in self.config_parameters: 282 if param.pointer: 283 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 284 else: 285 code('${{param.type_ast.type}} m_${{param.ident}};') 286 287 code(''' 288TransitionResult doTransition(${ident}_Event event, 289''') 290 291 if self.EntryType != None: 292 code(''' 293 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 294''') 295 if self.TBEType != None: 296 code(''' 297 ${{self.TBEType.c_ident}}* m_tbe_ptr, 298''') 299 300 code(''' 301 const Address addr); 302 303TransitionResult doTransitionWorker(${ident}_Event event, 304 ${ident}_State state, 305 ${ident}_State& next_state, 306''') 307 308 if self.TBEType != None: 309 code(''' 310 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 311''') 312 if self.EntryType != None: 313 code(''' 314 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 315''') 316 317 code(''' 318 const Address& addr); 319 320int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 321int m_event_counters[${ident}_Event_NUM]; 322bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 323 324static std::vector<Stats::Vector *> eventVec; 325static std::vector<std::vector<Stats::Vector *> > transVec; 326static int m_num_controllers; 327 328// Internal functions 329''') 330 331 for func in self.functions: 332 proto = func.prototype 333 if proto: 334 code('$proto') 335 336 if has_peer: 337 code('void getQueuesFromPeer(AbstractController *);') 338 if self.EntryType != None: 339 code(''' 340 341// Set and Reset for cache_entry variable 342void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 343void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 344''') 345 346 if self.TBEType != None: 347 code(''' 348 349// Set and Reset for tbe variable 350void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 351void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 352''') 353
| 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 = { 36 "int": "Int", 37 "uint32_t" : "UInt32", 38 "std::string": "String", 39 "bool": "Bool", 40 "CacheMemory": "RubyCache", 41 "WireBuffer": "RubyWireBuffer", 42 "Sequencer": "RubySequencer", 43 "DirectoryMemory": "RubyDirectoryMemory", 44 "MemoryControl": "MemoryControl", 45 "DMASequencer": "DMASequencer", 46 "Prefetcher":"Prefetcher", 47 "Cycles":"Cycles", 48 } 49 50class StateMachine(Symbol): 51 def __init__(self, symtab, ident, location, pairs, config_parameters): 52 super(StateMachine, self).__init__(symtab, ident, location, pairs) 53 self.table = None 54 self.config_parameters = config_parameters 55 self.prefetchers = [] 56 57 for param in config_parameters: 58 if param.pointer: 59 var = Var(symtab, param.name, location, param.type_ast.type, 60 "(*m_%s_ptr)" % param.name, {}, self) 61 else: 62 var = Var(symtab, param.name, location, param.type_ast.type, 63 "m_%s" % param.name, {}, self) 64 self.symtab.registerSym(param.name, var) 65 if str(param.type_ast.type) == "Prefetcher": 66 self.prefetchers.append(var) 67 68 self.states = orderdict() 69 self.events = orderdict() 70 self.actions = orderdict() 71 self.request_types = orderdict() 72 self.transitions = [] 73 self.in_ports = [] 74 self.functions = [] 75 self.objects = [] 76 self.TBEType = None 77 self.EntryType = None 78 79 def __repr__(self): 80 return "[StateMachine: %s]" % self.ident 81 82 def addState(self, state): 83 assert self.table is None 84 self.states[state.ident] = state 85 86 def addEvent(self, event): 87 assert self.table is None 88 self.events[event.ident] = event 89 90 def addAction(self, action): 91 assert self.table is None 92 93 # Check for duplicate action 94 for other in self.actions.itervalues(): 95 if action.ident == other.ident: 96 action.warning("Duplicate action definition: %s" % action.ident) 97 action.error("Duplicate action definition: %s" % action.ident) 98 if action.short == other.short: 99 other.warning("Duplicate action shorthand: %s" % other.ident) 100 other.warning(" shorthand = %s" % other.short) 101 action.warning("Duplicate action shorthand: %s" % action.ident) 102 action.error(" shorthand = %s" % action.short) 103 104 self.actions[action.ident] = action 105 106 def addRequestType(self, request_type): 107 assert self.table is None 108 self.request_types[request_type.ident] = request_type 109 110 def addTransition(self, trans): 111 assert self.table is None 112 self.transitions.append(trans) 113 114 def addInPort(self, var): 115 self.in_ports.append(var) 116 117 def addFunc(self, func): 118 # register func in the symbol table 119 self.symtab.registerSym(str(func), func) 120 self.functions.append(func) 121 122 def addObject(self, obj): 123 self.objects.append(obj) 124 125 def addType(self, type): 126 type_ident = '%s' % type.c_ident 127 128 if type_ident == "%s_TBE" %self.ident: 129 if self.TBEType != None: 130 self.error("Multiple Transaction Buffer types in a " \ 131 "single machine."); 132 self.TBEType = type 133 134 elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 135 if self.EntryType != None: 136 self.error("Multiple AbstractCacheEntry types in a " \ 137 "single machine."); 138 self.EntryType = type 139 140 # Needs to be called before accessing the table 141 def buildTable(self): 142 assert self.table is None 143 144 table = {} 145 146 for trans in self.transitions: 147 # Track which actions we touch so we know if we use them 148 # all -- really this should be done for all symbols as 149 # part of the symbol table, then only trigger it for 150 # Actions, States, Events, etc. 151 152 for action in trans.actions: 153 action.used = True 154 155 index = (trans.state, trans.event) 156 if index in table: 157 table[index].warning("Duplicate transition: %s" % table[index]) 158 trans.error("Duplicate transition: %s" % trans) 159 table[index] = trans 160 161 # Look at all actions to make sure we used them all 162 for action in self.actions.itervalues(): 163 if not action.used: 164 error_msg = "Unused action: %s" % action.ident 165 if "desc" in action: 166 error_msg += ", " + action.desc 167 action.warning(error_msg) 168 self.table = table 169 170 def writeCodeFiles(self, path, includes): 171 self.printControllerPython(path) 172 self.printControllerHH(path) 173 self.printControllerCC(path, includes) 174 self.printCSwitch(path) 175 self.printCWakeup(path, includes) 176 177 def printControllerPython(self, path): 178 code = self.symtab.codeFormatter() 179 ident = self.ident 180 py_ident = "%s_Controller" % ident 181 c_ident = "%s_Controller" % self.ident 182 code(''' 183from m5.params import * 184from m5.SimObject import SimObject 185from Controller import RubyController 186 187class $py_ident(RubyController): 188 type = '$py_ident' 189 cxx_header = 'mem/protocol/${c_ident}.hh' 190''') 191 code.indent() 192 for param in self.config_parameters: 193 dflt_str = '' 194 if param.default is not None: 195 dflt_str = str(param.default) + ', ' 196 if python_class_map.has_key(param.type_ast.type.c_ident): 197 python_type = python_class_map[param.type_ast.type.c_ident] 198 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 199 else: 200 self.error("Unknown c++ to python class conversion for c++ " \ 201 "type: '%s'. Please update the python_class_map " \ 202 "in StateMachine.py", param.type_ast.type.c_ident) 203 code.dedent() 204 code.write(path, '%s.py' % py_ident) 205 206 207 def printControllerHH(self, path): 208 '''Output the method declarations for the class declaration''' 209 code = self.symtab.codeFormatter() 210 ident = self.ident 211 c_ident = "%s_Controller" % self.ident 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/TransitionResult.hh" 228#include "mem/protocol/Types.hh" 229#include "mem/ruby/common/Consumer.hh" 230#include "mem/ruby/common/Global.hh" 231#include "mem/ruby/slicc_interface/AbstractController.hh" 232#include "params/$c_ident.hh" 233''') 234 235 seen_types = set() 236 has_peer = False 237 for var in self.objects: 238 if var.type.ident not in seen_types and not var.type.isPrimitive: 239 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 240 if "network" in var and "physical_network" in var: 241 has_peer = True 242 seen_types.add(var.type.ident) 243 244 # for adding information to the protocol debug trace 245 code(''' 246extern std::stringstream ${ident}_transitionComment; 247 248class $c_ident : public AbstractController 249{ 250 public: 251 typedef ${c_ident}Params Params; 252 $c_ident(const Params *p); 253 static int getNumControllers(); 254 void init(); 255 MessageBuffer* getMandatoryQueue() const; 256 const std::string toString() const; 257 258 void print(std::ostream& out) const; 259 void wakeup(); 260 void resetStats(); 261 void regStats(); 262 void collateStats(); 263 264 void recordCacheTrace(int cntrl, CacheRecorder* tr); 265 Sequencer* getSequencer() const; 266 267 bool functionalReadBuffers(PacketPtr&); 268 uint32_t functionalWriteBuffers(PacketPtr&); 269 270 void countTransition(${ident}_State state, ${ident}_Event event); 271 void possibleTransition(${ident}_State state, ${ident}_Event event); 272 uint64 getEventCount(${ident}_Event event); 273 bool isPossible(${ident}_State state, ${ident}_Event event); 274 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 275 276private: 277''') 278 279 code.indent() 280 # added by SS 281 for param in self.config_parameters: 282 if param.pointer: 283 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 284 else: 285 code('${{param.type_ast.type}} m_${{param.ident}};') 286 287 code(''' 288TransitionResult doTransition(${ident}_Event event, 289''') 290 291 if self.EntryType != None: 292 code(''' 293 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 294''') 295 if self.TBEType != None: 296 code(''' 297 ${{self.TBEType.c_ident}}* m_tbe_ptr, 298''') 299 300 code(''' 301 const Address addr); 302 303TransitionResult doTransitionWorker(${ident}_Event event, 304 ${ident}_State state, 305 ${ident}_State& next_state, 306''') 307 308 if self.TBEType != None: 309 code(''' 310 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 311''') 312 if self.EntryType != None: 313 code(''' 314 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 315''') 316 317 code(''' 318 const Address& addr); 319 320int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 321int m_event_counters[${ident}_Event_NUM]; 322bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 323 324static std::vector<Stats::Vector *> eventVec; 325static std::vector<std::vector<Stats::Vector *> > transVec; 326static int m_num_controllers; 327 328// Internal functions 329''') 330 331 for func in self.functions: 332 proto = func.prototype 333 if proto: 334 code('$proto') 335 336 if has_peer: 337 code('void getQueuesFromPeer(AbstractController *);') 338 if self.EntryType != None: 339 code(''' 340 341// Set and Reset for cache_entry variable 342void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 343void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 344''') 345 346 if self.TBEType != None: 347 code(''' 348 349// Set and Reset for tbe variable 350void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 351void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 352''') 353
|
705 seq_ident = "NULL" 706 for param in self.config_parameters: 707 if param.name == "sequencer": 708 assert(param.pointer) 709 seq_ident = "m_%s_ptr" % param.name 710 711 code(''' 712 713void 714$c_ident::regStats() 715{ 716 AbstractController::regStats(); 717 718 if (m_version == 0) { 719 for (${ident}_Event event = ${ident}_Event_FIRST; 720 event < ${ident}_Event_NUM; ++event) { 721 Stats::Vector *t = new Stats::Vector(); 722 t->init(m_num_controllers); 723 t->name(g_system_ptr->name() + ".${c_ident}." + 724 ${ident}_Event_to_string(event)); 725 t->flags(Stats::pdf | Stats::total | Stats::oneline | 726 Stats::nozero); 727 728 eventVec.push_back(t); 729 } 730 731 for (${ident}_State state = ${ident}_State_FIRST; 732 state < ${ident}_State_NUM; ++state) { 733 734 transVec.push_back(std::vector<Stats::Vector *>()); 735 736 for (${ident}_Event event = ${ident}_Event_FIRST; 737 event < ${ident}_Event_NUM; ++event) { 738 739 Stats::Vector *t = new Stats::Vector(); 740 t->init(m_num_controllers); 741 t->name(g_system_ptr->name() + ".${c_ident}." + 742 ${ident}_State_to_string(state) + 743 "." + ${ident}_Event_to_string(event)); 744 745 t->flags(Stats::pdf | Stats::total | Stats::oneline | 746 Stats::nozero); 747 transVec[state].push_back(t); 748 } 749 } 750 } 751} 752 753void 754$c_ident::collateStats() 755{ 756 for (${ident}_Event event = ${ident}_Event_FIRST; 757 event < ${ident}_Event_NUM; ++event) { 758 for (unsigned int i = 0; i < m_num_controllers; ++i) { 759 std::map<uint32_t, AbstractController *>::iterator it = 760 g_abs_controls[MachineType_${ident}].find(i); 761 assert(it != g_abs_controls[MachineType_${ident}].end()); 762 (*eventVec[event])[i] = 763 (($c_ident *)(*it).second)->getEventCount(event); 764 } 765 } 766 767 for (${ident}_State state = ${ident}_State_FIRST; 768 state < ${ident}_State_NUM; ++state) { 769 770 for (${ident}_Event event = ${ident}_Event_FIRST; 771 event < ${ident}_Event_NUM; ++event) { 772 773 for (unsigned int i = 0; i < m_num_controllers; ++i) { 774 std::map<uint32_t, AbstractController *>::iterator it = 775 g_abs_controls[MachineType_${ident}].find(i); 776 assert(it != g_abs_controls[MachineType_${ident}].end()); 777 (*transVec[state][event])[i] = 778 (($c_ident *)(*it).second)->getTransitionCount(state, event); 779 } 780 } 781 } 782} 783 784void 785$c_ident::countTransition(${ident}_State state, ${ident}_Event event) 786{ 787 assert(m_possible[state][event]); 788 m_counters[state][event]++; 789 m_event_counters[event]++; 790} 791void 792$c_ident::possibleTransition(${ident}_State state, 793 ${ident}_Event event) 794{ 795 m_possible[state][event] = true; 796} 797 798uint64 799$c_ident::getEventCount(${ident}_Event event) 800{ 801 return m_event_counters[event]; 802} 803 804bool 805$c_ident::isPossible(${ident}_State state, ${ident}_Event event) 806{ 807 return m_possible[state][event]; 808} 809 810uint64 811$c_ident::getTransitionCount(${ident}_State state, 812 ${ident}_Event event) 813{ 814 return m_counters[state][event]; 815} 816 817int 818$c_ident::getNumControllers() 819{ 820 return m_num_controllers; 821} 822 823MessageBuffer* 824$c_ident::getMandatoryQueue() const 825{ 826 return $mq_ident; 827} 828 829Sequencer* 830$c_ident::getSequencer() const 831{ 832 return $seq_ident; 833} 834 835const string 836$c_ident::toString() const 837{ 838 return "$c_ident"; 839} 840 841void 842$c_ident::print(ostream& out) const 843{ 844 out << "[$c_ident " << m_version << "]"; 845} 846 847void $c_ident::resetStats() 848{ 849 for (int state = 0; state < ${ident}_State_NUM; state++) { 850 for (int event = 0; event < ${ident}_Event_NUM; event++) { 851 m_counters[state][event] = 0; 852 } 853 } 854 855 for (int event = 0; event < ${ident}_Event_NUM; event++) { 856 m_event_counters[event] = 0; 857 } 858 859 AbstractController::resetStats(); 860} 861''') 862 863 if self.EntryType != None: 864 code(''' 865 866// Set and Reset for cache_entry variable 867void 868$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 869{ 870 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 871} 872 873void 874$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 875{ 876 m_cache_entry_ptr = 0; 877} 878''') 879 880 if self.TBEType != None: 881 code(''' 882 883// Set and Reset for tbe variable 884void 885$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 886{ 887 m_tbe_ptr = m_new_tbe; 888} 889 890void 891$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 892{ 893 m_tbe_ptr = NULL; 894} 895''') 896 897 code(''' 898 899void 900$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 901{ 902''') 903 # 904 # Record cache contents for all associated caches. 905 # 906 code.indent() 907 for param in self.config_parameters: 908 if param.type_ast.type.ident == "CacheMemory": 909 assert(param.pointer) 910 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 911 912 code.dedent() 913 code(''' 914} 915 916// Actions 917''') 918 if self.TBEType != None and self.EntryType != None: 919 for action in self.actions.itervalues(): 920 if "c_code" not in action: 921 continue 922 923 code(''' 924/** \\brief ${{action.desc}} */ 925void 926$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 927{ 928 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 929 ${{action["c_code"]}} 930} 931 932''') 933 elif self.TBEType != None: 934 for action in self.actions.itervalues(): 935 if "c_code" not in action: 936 continue 937 938 code(''' 939/** \\brief ${{action.desc}} */ 940void 941$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 942{ 943 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 944 ${{action["c_code"]}} 945} 946 947''') 948 elif self.EntryType != None: 949 for action in self.actions.itervalues(): 950 if "c_code" not in action: 951 continue 952 953 code(''' 954/** \\brief ${{action.desc}} */ 955void 956$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 957{ 958 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 959 ${{action["c_code"]}} 960} 961 962''') 963 else: 964 for action in self.actions.itervalues(): 965 if "c_code" not in action: 966 continue 967 968 code(''' 969/** \\brief ${{action.desc}} */ 970void 971$c_ident::${{action.ident}}(const Address& addr) 972{ 973 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 974 ${{action["c_code"]}} 975} 976 977''') 978 for func in self.functions: 979 code(func.generateCode()) 980 981 # Function for functional reads from messages buffered in the controller 982 code(''' 983bool 984$c_ident::functionalReadBuffers(PacketPtr& pkt) 985{ 986''') 987 for var in self.objects: 988 vtype = var.type 989 if vtype.isBuffer: 990 vid = "m_%s_ptr" % var.c_ident 991 code('if ($vid->functionalRead(pkt)) { return true; }') 992 code(''' 993 return false; 994} 995''') 996 997 # Function for functional writes to messages buffered in the controller 998 code(''' 999uint32_t 1000$c_ident::functionalWriteBuffers(PacketPtr& pkt) 1001{ 1002 uint32_t num_functional_writes = 0; 1003''') 1004 for var in self.objects: 1005 vtype = var.type 1006 if vtype.isBuffer: 1007 vid = "m_%s_ptr" % var.c_ident 1008 code('num_functional_writes += $vid->functionalWrite(pkt);') 1009 code(''' 1010 return num_functional_writes; 1011} 1012''') 1013 1014 # Check if this controller has a peer, if yes then write the 1015 # function for connecting to the peer. 1016 if has_peer: 1017 code(''' 1018 1019void 1020$c_ident::getQueuesFromPeer(AbstractController *peer) 1021{ 1022''') 1023 for var in self.objects: 1024 if "network" in var and "physical_network" in var and \ 1025 var["network"] == "From": 1026 code(''' 1027m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}}); 1028assert(m_${{var.c_ident}}_ptr != NULL); 1029m_${{var.c_ident}}_ptr->setReceiver(this); 1030 1031''') 1032 code('}') 1033 1034 code.write(path, "%s.cc" % c_ident) 1035 1036 def printCWakeup(self, path, includes): 1037 '''Output the wakeup loop for the events''' 1038 1039 code = self.symtab.codeFormatter() 1040 ident = self.ident 1041 1042 outputRequest_types = True 1043 if len(self.request_types) == 0: 1044 outputRequest_types = False 1045 1046 code(''' 1047// Auto generated C++ code started by $__file__:$__line__ 1048// ${ident}: ${{self.short}} 1049 1050#include <sys/types.h> 1051#include <unistd.h> 1052 1053#include <cassert> 1054 1055#include "base/misc.hh" 1056#include "debug/RubySlicc.hh" 1057#include "mem/protocol/${ident}_Controller.hh" 1058#include "mem/protocol/${ident}_Event.hh" 1059#include "mem/protocol/${ident}_State.hh" 1060''') 1061 1062 if outputRequest_types: 1063 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1064 1065 code(''' 1066#include "mem/protocol/Types.hh" 1067#include "mem/ruby/common/Global.hh" 1068#include "mem/ruby/system/System.hh" 1069''') 1070 1071 1072 for include_path in includes: 1073 code('#include "${{include_path}}"') 1074 1075 code(''' 1076 1077using namespace std; 1078 1079void 1080${ident}_Controller::wakeup() 1081{ 1082 int counter = 0; 1083 while (true) { 1084 // Some cases will put us into an infinite loop without this limit 1085 assert(counter <= m_transitions_per_cycle); 1086 if (counter == m_transitions_per_cycle) { 1087 // Count how often we are fully utilized 1088 m_fully_busy_cycles++; 1089 1090 // Wakeup in another cycle and try again 1091 scheduleEvent(Cycles(1)); 1092 break; 1093 } 1094''') 1095 1096 code.indent() 1097 code.indent() 1098 1099 # InPorts 1100 # 1101 for port in self.in_ports: 1102 code.indent() 1103 code('// ${ident}InPort $port') 1104 if port.pairs.has_key("rank"): 1105 code('m_cur_in_port = ${{port.pairs["rank"]}};') 1106 else: 1107 code('m_cur_in_port = 0;') 1108 code('${{port["c_code_in_port"]}}') 1109 code.dedent() 1110 1111 code('') 1112 1113 code.dedent() 1114 code.dedent() 1115 code(''' 1116 break; // If we got this far, we have nothing left todo 1117 } 1118} 1119''') 1120 1121 code.write(path, "%s_Wakeup.cc" % self.ident) 1122 1123 def printCSwitch(self, path): 1124 '''Output switch statement for transition table''' 1125 1126 code = self.symtab.codeFormatter() 1127 ident = self.ident 1128 1129 code(''' 1130// Auto generated C++ code started by $__file__:$__line__ 1131// ${ident}: ${{self.short}} 1132 1133#include <cassert> 1134 1135#include "base/misc.hh" 1136#include "base/trace.hh" 1137#include "debug/ProtocolTrace.hh" 1138#include "debug/RubyGenerated.hh" 1139#include "mem/protocol/${ident}_Controller.hh" 1140#include "mem/protocol/${ident}_Event.hh" 1141#include "mem/protocol/${ident}_State.hh" 1142#include "mem/protocol/Types.hh" 1143#include "mem/ruby/common/Global.hh" 1144#include "mem/ruby/system/System.hh" 1145 1146#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1147 1148#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1149#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1150 1151TransitionResult 1152${ident}_Controller::doTransition(${ident}_Event event, 1153''') 1154 if self.EntryType != None: 1155 code(''' 1156 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1157''') 1158 if self.TBEType != None: 1159 code(''' 1160 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1161''') 1162 code(''' 1163 const Address addr) 1164{ 1165''') 1166 if self.TBEType != None and self.EntryType != None: 1167 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1168 elif self.TBEType != None: 1169 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1170 elif self.EntryType != None: 1171 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1172 else: 1173 code('${ident}_State state = getState(addr);') 1174 1175 code(''' 1176 ${ident}_State next_state = state; 1177 1178 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1179 *this, curCycle(), ${ident}_State_to_string(state), 1180 ${ident}_Event_to_string(event), addr); 1181 1182 TransitionResult result = 1183''') 1184 if self.TBEType != None and self.EntryType != None: 1185 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1186 elif self.TBEType != None: 1187 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1188 elif self.EntryType != None: 1189 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1190 else: 1191 code('doTransitionWorker(event, state, next_state, addr);') 1192 1193 code(''' 1194 if (result == TransitionResult_Valid) { 1195 DPRINTF(RubyGenerated, "next_state: %s\\n", 1196 ${ident}_State_to_string(next_state)); 1197 countTransition(state, event); 1198 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1199 curTick(), m_version, "${ident}", 1200 ${ident}_Event_to_string(event), 1201 ${ident}_State_to_string(state), 1202 ${ident}_State_to_string(next_state), 1203 addr, GET_TRANSITION_COMMENT()); 1204 1205 CLEAR_TRANSITION_COMMENT(); 1206''') 1207 if self.TBEType != None and self.EntryType != None: 1208 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1209 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1210 elif self.TBEType != None: 1211 code('setState(m_tbe_ptr, addr, next_state);') 1212 code('setAccessPermission(addr, next_state);') 1213 elif self.EntryType != None: 1214 code('setState(m_cache_entry_ptr, addr, next_state);') 1215 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1216 else: 1217 code('setState(addr, next_state);') 1218 code('setAccessPermission(addr, next_state);') 1219 1220 code(''' 1221 } else if (result == TransitionResult_ResourceStall) { 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, "Resource Stall"); 1228 } else if (result == TransitionResult_ProtocolStall) { 1229 DPRINTF(RubyGenerated, "stalling\\n"); 1230 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1231 curTick(), m_version, "${ident}", 1232 ${ident}_Event_to_string(event), 1233 ${ident}_State_to_string(state), 1234 ${ident}_State_to_string(next_state), 1235 addr, "Protocol Stall"); 1236 } 1237 1238 return result; 1239} 1240 1241TransitionResult 1242${ident}_Controller::doTransitionWorker(${ident}_Event event, 1243 ${ident}_State state, 1244 ${ident}_State& next_state, 1245''') 1246 1247 if self.TBEType != None: 1248 code(''' 1249 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1250''') 1251 if self.EntryType != None: 1252 code(''' 1253 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1254''') 1255 code(''' 1256 const Address& addr) 1257{ 1258 switch(HASH_FUN(state, event)) { 1259''') 1260 1261 # This map will allow suppress generating duplicate code 1262 cases = orderdict() 1263 1264 for trans in self.transitions: 1265 case_string = "%s_State_%s, %s_Event_%s" % \ 1266 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1267 1268 case = self.symtab.codeFormatter() 1269 # Only set next_state if it changes 1270 if trans.state != trans.nextState: 1271 ns_ident = trans.nextState.ident 1272 case('next_state = ${ident}_State_${ns_ident};') 1273 1274 actions = trans.actions 1275 request_types = trans.request_types 1276 1277 # Check for resources 1278 case_sorter = [] 1279 res = trans.resources 1280 for key,val in res.iteritems(): 1281 if key.type.ident != "DNUCAStopTable": 1282 val = ''' 1283if (!%s.areNSlotsAvailable(%s)) 1284 return TransitionResult_ResourceStall; 1285''' % (key.code, val) 1286 case_sorter.append(val) 1287 1288 # Check all of the request_types for resource constraints 1289 for request_type in request_types: 1290 val = ''' 1291if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1292 return TransitionResult_ResourceStall; 1293} 1294''' % (self.ident, request_type.ident) 1295 case_sorter.append(val) 1296 1297 # Emit the code sequences in a sorted order. This makes the 1298 # output deterministic (without this the output order can vary 1299 # since Map's keys() on a vector of pointers is not deterministic 1300 for c in sorted(case_sorter): 1301 case("$c") 1302 1303 # Record access types for this transition 1304 for request_type in request_types: 1305 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1306 1307 # Figure out if we stall 1308 stall = False 1309 for action in actions: 1310 if action.ident == "z_stall": 1311 stall = True 1312 break 1313 1314 if stall: 1315 case('return TransitionResult_ProtocolStall;') 1316 else: 1317 if self.TBEType != None and self.EntryType != None: 1318 for action in actions: 1319 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1320 elif self.TBEType != None: 1321 for action in actions: 1322 case('${{action.ident}}(m_tbe_ptr, addr);') 1323 elif self.EntryType != None: 1324 for action in actions: 1325 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1326 else: 1327 for action in actions: 1328 case('${{action.ident}}(addr);') 1329 case('return TransitionResult_Valid;') 1330 1331 case = str(case) 1332 1333 # Look to see if this transition code is unique. 1334 if case not in cases: 1335 cases[case] = [] 1336 1337 cases[case].append(case_string) 1338 1339 # Walk through all of the unique code blocks and spit out the 1340 # corresponding case statement elements 1341 for case,transitions in cases.iteritems(): 1342 # Iterative over all the multiple transitions that share 1343 # the same code 1344 for trans in transitions: 1345 code(' case HASH_FUN($trans):') 1346 code(' $case') 1347 1348 code(''' 1349 default: 1350 fatal("Invalid transition\\n" 1351 "%s time: %d addr: %s event: %s state: %s\\n", 1352 name(), curCycle(), addr, event, state); 1353 } 1354 return TransitionResult_Valid; 1355} 1356''') 1357 code.write(path, "%s_Transitions.cc" % self.ident) 1358 1359 1360 # ************************** 1361 # ******* HTML Files ******* 1362 # ************************** 1363 def frameRef(self, click_href, click_target, over_href, over_num, text): 1364 code = self.symtab.codeFormatter(fix_newlines=False) 1365 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1366 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1367 parent.frames[$over_num].location='$over_href' 1368 }\"> 1369 ${{html.formatShorthand(text)}} 1370 </A>""") 1371 return str(code) 1372 1373 def writeHTMLFiles(self, path): 1374 # Create table with no row hilighted 1375 self.printHTMLTransitions(path, None) 1376 1377 # Generate transition tables 1378 for state in self.states.itervalues(): 1379 self.printHTMLTransitions(path, state) 1380 1381 # Generate action descriptions 1382 for action in self.actions.itervalues(): 1383 name = "%s_action_%s.html" % (self.ident, action.ident) 1384 code = html.createSymbol(action, "Action") 1385 code.write(path, name) 1386 1387 # Generate state descriptions 1388 for state in self.states.itervalues(): 1389 name = "%s_State_%s.html" % (self.ident, state.ident) 1390 code = html.createSymbol(state, "State") 1391 code.write(path, name) 1392 1393 # Generate event descriptions 1394 for event in self.events.itervalues(): 1395 name = "%s_Event_%s.html" % (self.ident, event.ident) 1396 code = html.createSymbol(event, "Event") 1397 code.write(path, name) 1398 1399 def printHTMLTransitions(self, path, active_state): 1400 code = self.symtab.codeFormatter() 1401 1402 code(''' 1403<HTML> 1404<BODY link="blue" vlink="blue"> 1405 1406<H1 align="center">${{html.formatShorthand(self.short)}}: 1407''') 1408 code.indent() 1409 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1410 mid = machine.ident 1411 if i != 0: 1412 extra = " - " 1413 else: 1414 extra = "" 1415 if machine == self: 1416 code('$extra$mid') 1417 else: 1418 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1419 code.dedent() 1420 1421 code(""" 1422</H1> 1423 1424<TABLE border=1> 1425<TR> 1426 <TH> </TH> 1427""") 1428 1429 for event in self.events.itervalues(): 1430 href = "%s_Event_%s.html" % (self.ident, event.ident) 1431 ref = self.frameRef(href, "Status", href, "1", event.short) 1432 code('<TH bgcolor=white>$ref</TH>') 1433 1434 code('</TR>') 1435 # -- Body of table 1436 for state in self.states.itervalues(): 1437 # -- Each row 1438 if state == active_state: 1439 color = "yellow" 1440 else: 1441 color = "white" 1442 1443 click = "%s_table_%s.html" % (self.ident, state.ident) 1444 over = "%s_State_%s.html" % (self.ident, state.ident) 1445 text = html.formatShorthand(state.short) 1446 ref = self.frameRef(click, "Table", over, "1", state.short) 1447 code(''' 1448<TR> 1449 <TH bgcolor=$color>$ref</TH> 1450''') 1451 1452 # -- One column for each event 1453 for event in self.events.itervalues(): 1454 trans = self.table.get((state,event), None) 1455 if trans is None: 1456 # This is the no transition case 1457 if state == active_state: 1458 color = "#C0C000" 1459 else: 1460 color = "lightgrey" 1461 1462 code('<TD bgcolor=$color> </TD>') 1463 continue 1464 1465 next = trans.nextState 1466 stall_action = False 1467 1468 # -- Get the actions 1469 for action in trans.actions: 1470 if action.ident == "z_stall" or \ 1471 action.ident == "zz_recycleMandatoryQueue": 1472 stall_action = True 1473 1474 # -- Print out "actions/next-state" 1475 if stall_action: 1476 if state == active_state: 1477 color = "#C0C000" 1478 else: 1479 color = "lightgrey" 1480 1481 elif active_state and next.ident == active_state.ident: 1482 color = "aqua" 1483 elif state == active_state: 1484 color = "yellow" 1485 else: 1486 color = "white" 1487 1488 code('<TD bgcolor=$color>') 1489 for action in trans.actions: 1490 href = "%s_action_%s.html" % (self.ident, action.ident) 1491 ref = self.frameRef(href, "Status", href, "1", 1492 action.short) 1493 code(' $ref') 1494 if next != state: 1495 if trans.actions: 1496 code('/') 1497 click = "%s_table_%s.html" % (self.ident, next.ident) 1498 over = "%s_State_%s.html" % (self.ident, next.ident) 1499 ref = self.frameRef(click, "Table", over, "1", next.short) 1500 code("$ref") 1501 code("</TD>") 1502 1503 # -- Each row 1504 if state == active_state: 1505 color = "yellow" 1506 else: 1507 color = "white" 1508 1509 click = "%s_table_%s.html" % (self.ident, state.ident) 1510 over = "%s_State_%s.html" % (self.ident, state.ident) 1511 ref = self.frameRef(click, "Table", over, "1", state.short) 1512 code(''' 1513 <TH bgcolor=$color>$ref</TH> 1514</TR> 1515''') 1516 code(''' 1517<!- Column footer-> 1518<TR> 1519 <TH> </TH> 1520''') 1521 1522 for event in self.events.itervalues(): 1523 href = "%s_Event_%s.html" % (self.ident, event.ident) 1524 ref = self.frameRef(href, "Status", href, "1", event.short) 1525 code('<TH bgcolor=white>$ref</TH>') 1526 code(''' 1527</TR> 1528</TABLE> 1529</BODY></HTML> 1530''') 1531 1532 1533 if active_state: 1534 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1535 else: 1536 name = "%s_table.html" % self.ident 1537 code.write(path, name) 1538 1539__all__ = [ "StateMachine" ]
| 680 seq_ident = "NULL" 681 for param in self.config_parameters: 682 if param.name == "sequencer": 683 assert(param.pointer) 684 seq_ident = "m_%s_ptr" % param.name 685 686 code(''' 687 688void 689$c_ident::regStats() 690{ 691 AbstractController::regStats(); 692 693 if (m_version == 0) { 694 for (${ident}_Event event = ${ident}_Event_FIRST; 695 event < ${ident}_Event_NUM; ++event) { 696 Stats::Vector *t = new Stats::Vector(); 697 t->init(m_num_controllers); 698 t->name(g_system_ptr->name() + ".${c_ident}." + 699 ${ident}_Event_to_string(event)); 700 t->flags(Stats::pdf | Stats::total | Stats::oneline | 701 Stats::nozero); 702 703 eventVec.push_back(t); 704 } 705 706 for (${ident}_State state = ${ident}_State_FIRST; 707 state < ${ident}_State_NUM; ++state) { 708 709 transVec.push_back(std::vector<Stats::Vector *>()); 710 711 for (${ident}_Event event = ${ident}_Event_FIRST; 712 event < ${ident}_Event_NUM; ++event) { 713 714 Stats::Vector *t = new Stats::Vector(); 715 t->init(m_num_controllers); 716 t->name(g_system_ptr->name() + ".${c_ident}." + 717 ${ident}_State_to_string(state) + 718 "." + ${ident}_Event_to_string(event)); 719 720 t->flags(Stats::pdf | Stats::total | Stats::oneline | 721 Stats::nozero); 722 transVec[state].push_back(t); 723 } 724 } 725 } 726} 727 728void 729$c_ident::collateStats() 730{ 731 for (${ident}_Event event = ${ident}_Event_FIRST; 732 event < ${ident}_Event_NUM; ++event) { 733 for (unsigned int i = 0; i < m_num_controllers; ++i) { 734 std::map<uint32_t, AbstractController *>::iterator it = 735 g_abs_controls[MachineType_${ident}].find(i); 736 assert(it != g_abs_controls[MachineType_${ident}].end()); 737 (*eventVec[event])[i] = 738 (($c_ident *)(*it).second)->getEventCount(event); 739 } 740 } 741 742 for (${ident}_State state = ${ident}_State_FIRST; 743 state < ${ident}_State_NUM; ++state) { 744 745 for (${ident}_Event event = ${ident}_Event_FIRST; 746 event < ${ident}_Event_NUM; ++event) { 747 748 for (unsigned int i = 0; i < m_num_controllers; ++i) { 749 std::map<uint32_t, AbstractController *>::iterator it = 750 g_abs_controls[MachineType_${ident}].find(i); 751 assert(it != g_abs_controls[MachineType_${ident}].end()); 752 (*transVec[state][event])[i] = 753 (($c_ident *)(*it).second)->getTransitionCount(state, event); 754 } 755 } 756 } 757} 758 759void 760$c_ident::countTransition(${ident}_State state, ${ident}_Event event) 761{ 762 assert(m_possible[state][event]); 763 m_counters[state][event]++; 764 m_event_counters[event]++; 765} 766void 767$c_ident::possibleTransition(${ident}_State state, 768 ${ident}_Event event) 769{ 770 m_possible[state][event] = true; 771} 772 773uint64 774$c_ident::getEventCount(${ident}_Event event) 775{ 776 return m_event_counters[event]; 777} 778 779bool 780$c_ident::isPossible(${ident}_State state, ${ident}_Event event) 781{ 782 return m_possible[state][event]; 783} 784 785uint64 786$c_ident::getTransitionCount(${ident}_State state, 787 ${ident}_Event event) 788{ 789 return m_counters[state][event]; 790} 791 792int 793$c_ident::getNumControllers() 794{ 795 return m_num_controllers; 796} 797 798MessageBuffer* 799$c_ident::getMandatoryQueue() const 800{ 801 return $mq_ident; 802} 803 804Sequencer* 805$c_ident::getSequencer() const 806{ 807 return $seq_ident; 808} 809 810const string 811$c_ident::toString() const 812{ 813 return "$c_ident"; 814} 815 816void 817$c_ident::print(ostream& out) const 818{ 819 out << "[$c_ident " << m_version << "]"; 820} 821 822void $c_ident::resetStats() 823{ 824 for (int state = 0; state < ${ident}_State_NUM; state++) { 825 for (int event = 0; event < ${ident}_Event_NUM; event++) { 826 m_counters[state][event] = 0; 827 } 828 } 829 830 for (int event = 0; event < ${ident}_Event_NUM; event++) { 831 m_event_counters[event] = 0; 832 } 833 834 AbstractController::resetStats(); 835} 836''') 837 838 if self.EntryType != None: 839 code(''' 840 841// Set and Reset for cache_entry variable 842void 843$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 844{ 845 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 846} 847 848void 849$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 850{ 851 m_cache_entry_ptr = 0; 852} 853''') 854 855 if self.TBEType != None: 856 code(''' 857 858// Set and Reset for tbe variable 859void 860$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 861{ 862 m_tbe_ptr = m_new_tbe; 863} 864 865void 866$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 867{ 868 m_tbe_ptr = NULL; 869} 870''') 871 872 code(''' 873 874void 875$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 876{ 877''') 878 # 879 # Record cache contents for all associated caches. 880 # 881 code.indent() 882 for param in self.config_parameters: 883 if param.type_ast.type.ident == "CacheMemory": 884 assert(param.pointer) 885 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 886 887 code.dedent() 888 code(''' 889} 890 891// Actions 892''') 893 if self.TBEType != None and self.EntryType != None: 894 for action in self.actions.itervalues(): 895 if "c_code" not in action: 896 continue 897 898 code(''' 899/** \\brief ${{action.desc}} */ 900void 901$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 902{ 903 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 904 ${{action["c_code"]}} 905} 906 907''') 908 elif self.TBEType != None: 909 for action in self.actions.itervalues(): 910 if "c_code" not in action: 911 continue 912 913 code(''' 914/** \\brief ${{action.desc}} */ 915void 916$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 917{ 918 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 919 ${{action["c_code"]}} 920} 921 922''') 923 elif self.EntryType != None: 924 for action in self.actions.itervalues(): 925 if "c_code" not in action: 926 continue 927 928 code(''' 929/** \\brief ${{action.desc}} */ 930void 931$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 932{ 933 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 934 ${{action["c_code"]}} 935} 936 937''') 938 else: 939 for action in self.actions.itervalues(): 940 if "c_code" not in action: 941 continue 942 943 code(''' 944/** \\brief ${{action.desc}} */ 945void 946$c_ident::${{action.ident}}(const Address& addr) 947{ 948 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 949 ${{action["c_code"]}} 950} 951 952''') 953 for func in self.functions: 954 code(func.generateCode()) 955 956 # Function for functional reads from messages buffered in the controller 957 code(''' 958bool 959$c_ident::functionalReadBuffers(PacketPtr& pkt) 960{ 961''') 962 for var in self.objects: 963 vtype = var.type 964 if vtype.isBuffer: 965 vid = "m_%s_ptr" % var.c_ident 966 code('if ($vid->functionalRead(pkt)) { return true; }') 967 code(''' 968 return false; 969} 970''') 971 972 # Function for functional writes to messages buffered in the controller 973 code(''' 974uint32_t 975$c_ident::functionalWriteBuffers(PacketPtr& pkt) 976{ 977 uint32_t num_functional_writes = 0; 978''') 979 for var in self.objects: 980 vtype = var.type 981 if vtype.isBuffer: 982 vid = "m_%s_ptr" % var.c_ident 983 code('num_functional_writes += $vid->functionalWrite(pkt);') 984 code(''' 985 return num_functional_writes; 986} 987''') 988 989 # Check if this controller has a peer, if yes then write the 990 # function for connecting to the peer. 991 if has_peer: 992 code(''' 993 994void 995$c_ident::getQueuesFromPeer(AbstractController *peer) 996{ 997''') 998 for var in self.objects: 999 if "network" in var and "physical_network" in var and \ 1000 var["network"] == "From": 1001 code(''' 1002m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}}); 1003assert(m_${{var.c_ident}}_ptr != NULL); 1004m_${{var.c_ident}}_ptr->setReceiver(this); 1005 1006''') 1007 code('}') 1008 1009 code.write(path, "%s.cc" % c_ident) 1010 1011 def printCWakeup(self, path, includes): 1012 '''Output the wakeup loop for the events''' 1013 1014 code = self.symtab.codeFormatter() 1015 ident = self.ident 1016 1017 outputRequest_types = True 1018 if len(self.request_types) == 0: 1019 outputRequest_types = False 1020 1021 code(''' 1022// Auto generated C++ code started by $__file__:$__line__ 1023// ${ident}: ${{self.short}} 1024 1025#include <sys/types.h> 1026#include <unistd.h> 1027 1028#include <cassert> 1029 1030#include "base/misc.hh" 1031#include "debug/RubySlicc.hh" 1032#include "mem/protocol/${ident}_Controller.hh" 1033#include "mem/protocol/${ident}_Event.hh" 1034#include "mem/protocol/${ident}_State.hh" 1035''') 1036 1037 if outputRequest_types: 1038 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1039 1040 code(''' 1041#include "mem/protocol/Types.hh" 1042#include "mem/ruby/common/Global.hh" 1043#include "mem/ruby/system/System.hh" 1044''') 1045 1046 1047 for include_path in includes: 1048 code('#include "${{include_path}}"') 1049 1050 code(''' 1051 1052using namespace std; 1053 1054void 1055${ident}_Controller::wakeup() 1056{ 1057 int counter = 0; 1058 while (true) { 1059 // Some cases will put us into an infinite loop without this limit 1060 assert(counter <= m_transitions_per_cycle); 1061 if (counter == m_transitions_per_cycle) { 1062 // Count how often we are fully utilized 1063 m_fully_busy_cycles++; 1064 1065 // Wakeup in another cycle and try again 1066 scheduleEvent(Cycles(1)); 1067 break; 1068 } 1069''') 1070 1071 code.indent() 1072 code.indent() 1073 1074 # InPorts 1075 # 1076 for port in self.in_ports: 1077 code.indent() 1078 code('// ${ident}InPort $port') 1079 if port.pairs.has_key("rank"): 1080 code('m_cur_in_port = ${{port.pairs["rank"]}};') 1081 else: 1082 code('m_cur_in_port = 0;') 1083 code('${{port["c_code_in_port"]}}') 1084 code.dedent() 1085 1086 code('') 1087 1088 code.dedent() 1089 code.dedent() 1090 code(''' 1091 break; // If we got this far, we have nothing left todo 1092 } 1093} 1094''') 1095 1096 code.write(path, "%s_Wakeup.cc" % self.ident) 1097 1098 def printCSwitch(self, path): 1099 '''Output switch statement for transition table''' 1100 1101 code = self.symtab.codeFormatter() 1102 ident = self.ident 1103 1104 code(''' 1105// Auto generated C++ code started by $__file__:$__line__ 1106// ${ident}: ${{self.short}} 1107 1108#include <cassert> 1109 1110#include "base/misc.hh" 1111#include "base/trace.hh" 1112#include "debug/ProtocolTrace.hh" 1113#include "debug/RubyGenerated.hh" 1114#include "mem/protocol/${ident}_Controller.hh" 1115#include "mem/protocol/${ident}_Event.hh" 1116#include "mem/protocol/${ident}_State.hh" 1117#include "mem/protocol/Types.hh" 1118#include "mem/ruby/common/Global.hh" 1119#include "mem/ruby/system/System.hh" 1120 1121#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1122 1123#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1124#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1125 1126TransitionResult 1127${ident}_Controller::doTransition(${ident}_Event event, 1128''') 1129 if self.EntryType != None: 1130 code(''' 1131 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1132''') 1133 if self.TBEType != None: 1134 code(''' 1135 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1136''') 1137 code(''' 1138 const Address addr) 1139{ 1140''') 1141 if self.TBEType != None and self.EntryType != None: 1142 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1143 elif self.TBEType != None: 1144 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1145 elif self.EntryType != None: 1146 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1147 else: 1148 code('${ident}_State state = getState(addr);') 1149 1150 code(''' 1151 ${ident}_State next_state = state; 1152 1153 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1154 *this, curCycle(), ${ident}_State_to_string(state), 1155 ${ident}_Event_to_string(event), addr); 1156 1157 TransitionResult result = 1158''') 1159 if self.TBEType != None and self.EntryType != None: 1160 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1161 elif self.TBEType != None: 1162 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1163 elif self.EntryType != None: 1164 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1165 else: 1166 code('doTransitionWorker(event, state, next_state, addr);') 1167 1168 code(''' 1169 if (result == TransitionResult_Valid) { 1170 DPRINTF(RubyGenerated, "next_state: %s\\n", 1171 ${ident}_State_to_string(next_state)); 1172 countTransition(state, event); 1173 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1174 curTick(), m_version, "${ident}", 1175 ${ident}_Event_to_string(event), 1176 ${ident}_State_to_string(state), 1177 ${ident}_State_to_string(next_state), 1178 addr, GET_TRANSITION_COMMENT()); 1179 1180 CLEAR_TRANSITION_COMMENT(); 1181''') 1182 if self.TBEType != None and self.EntryType != None: 1183 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1184 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1185 elif self.TBEType != None: 1186 code('setState(m_tbe_ptr, addr, next_state);') 1187 code('setAccessPermission(addr, next_state);') 1188 elif self.EntryType != None: 1189 code('setState(m_cache_entry_ptr, addr, next_state);') 1190 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1191 else: 1192 code('setState(addr, next_state);') 1193 code('setAccessPermission(addr, next_state);') 1194 1195 code(''' 1196 } else if (result == TransitionResult_ResourceStall) { 1197 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1198 curTick(), m_version, "${ident}", 1199 ${ident}_Event_to_string(event), 1200 ${ident}_State_to_string(state), 1201 ${ident}_State_to_string(next_state), 1202 addr, "Resource Stall"); 1203 } else if (result == TransitionResult_ProtocolStall) { 1204 DPRINTF(RubyGenerated, "stalling\\n"); 1205 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1206 curTick(), m_version, "${ident}", 1207 ${ident}_Event_to_string(event), 1208 ${ident}_State_to_string(state), 1209 ${ident}_State_to_string(next_state), 1210 addr, "Protocol Stall"); 1211 } 1212 1213 return result; 1214} 1215 1216TransitionResult 1217${ident}_Controller::doTransitionWorker(${ident}_Event event, 1218 ${ident}_State state, 1219 ${ident}_State& next_state, 1220''') 1221 1222 if self.TBEType != None: 1223 code(''' 1224 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1225''') 1226 if self.EntryType != None: 1227 code(''' 1228 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1229''') 1230 code(''' 1231 const Address& addr) 1232{ 1233 switch(HASH_FUN(state, event)) { 1234''') 1235 1236 # This map will allow suppress generating duplicate code 1237 cases = orderdict() 1238 1239 for trans in self.transitions: 1240 case_string = "%s_State_%s, %s_Event_%s" % \ 1241 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1242 1243 case = self.symtab.codeFormatter() 1244 # Only set next_state if it changes 1245 if trans.state != trans.nextState: 1246 ns_ident = trans.nextState.ident 1247 case('next_state = ${ident}_State_${ns_ident};') 1248 1249 actions = trans.actions 1250 request_types = trans.request_types 1251 1252 # Check for resources 1253 case_sorter = [] 1254 res = trans.resources 1255 for key,val in res.iteritems(): 1256 if key.type.ident != "DNUCAStopTable": 1257 val = ''' 1258if (!%s.areNSlotsAvailable(%s)) 1259 return TransitionResult_ResourceStall; 1260''' % (key.code, val) 1261 case_sorter.append(val) 1262 1263 # Check all of the request_types for resource constraints 1264 for request_type in request_types: 1265 val = ''' 1266if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1267 return TransitionResult_ResourceStall; 1268} 1269''' % (self.ident, request_type.ident) 1270 case_sorter.append(val) 1271 1272 # Emit the code sequences in a sorted order. This makes the 1273 # output deterministic (without this the output order can vary 1274 # since Map's keys() on a vector of pointers is not deterministic 1275 for c in sorted(case_sorter): 1276 case("$c") 1277 1278 # Record access types for this transition 1279 for request_type in request_types: 1280 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1281 1282 # Figure out if we stall 1283 stall = False 1284 for action in actions: 1285 if action.ident == "z_stall": 1286 stall = True 1287 break 1288 1289 if stall: 1290 case('return TransitionResult_ProtocolStall;') 1291 else: 1292 if self.TBEType != None and self.EntryType != None: 1293 for action in actions: 1294 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1295 elif self.TBEType != None: 1296 for action in actions: 1297 case('${{action.ident}}(m_tbe_ptr, addr);') 1298 elif self.EntryType != None: 1299 for action in actions: 1300 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1301 else: 1302 for action in actions: 1303 case('${{action.ident}}(addr);') 1304 case('return TransitionResult_Valid;') 1305 1306 case = str(case) 1307 1308 # Look to see if this transition code is unique. 1309 if case not in cases: 1310 cases[case] = [] 1311 1312 cases[case].append(case_string) 1313 1314 # Walk through all of the unique code blocks and spit out the 1315 # corresponding case statement elements 1316 for case,transitions in cases.iteritems(): 1317 # Iterative over all the multiple transitions that share 1318 # the same code 1319 for trans in transitions: 1320 code(' case HASH_FUN($trans):') 1321 code(' $case') 1322 1323 code(''' 1324 default: 1325 fatal("Invalid transition\\n" 1326 "%s time: %d addr: %s event: %s state: %s\\n", 1327 name(), curCycle(), addr, event, state); 1328 } 1329 return TransitionResult_Valid; 1330} 1331''') 1332 code.write(path, "%s_Transitions.cc" % self.ident) 1333 1334 1335 # ************************** 1336 # ******* HTML Files ******* 1337 # ************************** 1338 def frameRef(self, click_href, click_target, over_href, over_num, text): 1339 code = self.symtab.codeFormatter(fix_newlines=False) 1340 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1341 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1342 parent.frames[$over_num].location='$over_href' 1343 }\"> 1344 ${{html.formatShorthand(text)}} 1345 </A>""") 1346 return str(code) 1347 1348 def writeHTMLFiles(self, path): 1349 # Create table with no row hilighted 1350 self.printHTMLTransitions(path, None) 1351 1352 # Generate transition tables 1353 for state in self.states.itervalues(): 1354 self.printHTMLTransitions(path, state) 1355 1356 # Generate action descriptions 1357 for action in self.actions.itervalues(): 1358 name = "%s_action_%s.html" % (self.ident, action.ident) 1359 code = html.createSymbol(action, "Action") 1360 code.write(path, name) 1361 1362 # Generate state descriptions 1363 for state in self.states.itervalues(): 1364 name = "%s_State_%s.html" % (self.ident, state.ident) 1365 code = html.createSymbol(state, "State") 1366 code.write(path, name) 1367 1368 # Generate event descriptions 1369 for event in self.events.itervalues(): 1370 name = "%s_Event_%s.html" % (self.ident, event.ident) 1371 code = html.createSymbol(event, "Event") 1372 code.write(path, name) 1373 1374 def printHTMLTransitions(self, path, active_state): 1375 code = self.symtab.codeFormatter() 1376 1377 code(''' 1378<HTML> 1379<BODY link="blue" vlink="blue"> 1380 1381<H1 align="center">${{html.formatShorthand(self.short)}}: 1382''') 1383 code.indent() 1384 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1385 mid = machine.ident 1386 if i != 0: 1387 extra = " - " 1388 else: 1389 extra = "" 1390 if machine == self: 1391 code('$extra$mid') 1392 else: 1393 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1394 code.dedent() 1395 1396 code(""" 1397</H1> 1398 1399<TABLE border=1> 1400<TR> 1401 <TH> </TH> 1402""") 1403 1404 for event in self.events.itervalues(): 1405 href = "%s_Event_%s.html" % (self.ident, event.ident) 1406 ref = self.frameRef(href, "Status", href, "1", event.short) 1407 code('<TH bgcolor=white>$ref</TH>') 1408 1409 code('</TR>') 1410 # -- Body of table 1411 for state in self.states.itervalues(): 1412 # -- Each row 1413 if state == active_state: 1414 color = "yellow" 1415 else: 1416 color = "white" 1417 1418 click = "%s_table_%s.html" % (self.ident, state.ident) 1419 over = "%s_State_%s.html" % (self.ident, state.ident) 1420 text = html.formatShorthand(state.short) 1421 ref = self.frameRef(click, "Table", over, "1", state.short) 1422 code(''' 1423<TR> 1424 <TH bgcolor=$color>$ref</TH> 1425''') 1426 1427 # -- One column for each event 1428 for event in self.events.itervalues(): 1429 trans = self.table.get((state,event), None) 1430 if trans is None: 1431 # This is the no transition case 1432 if state == active_state: 1433 color = "#C0C000" 1434 else: 1435 color = "lightgrey" 1436 1437 code('<TD bgcolor=$color> </TD>') 1438 continue 1439 1440 next = trans.nextState 1441 stall_action = False 1442 1443 # -- Get the actions 1444 for action in trans.actions: 1445 if action.ident == "z_stall" or \ 1446 action.ident == "zz_recycleMandatoryQueue": 1447 stall_action = True 1448 1449 # -- Print out "actions/next-state" 1450 if stall_action: 1451 if state == active_state: 1452 color = "#C0C000" 1453 else: 1454 color = "lightgrey" 1455 1456 elif active_state and next.ident == active_state.ident: 1457 color = "aqua" 1458 elif state == active_state: 1459 color = "yellow" 1460 else: 1461 color = "white" 1462 1463 code('<TD bgcolor=$color>') 1464 for action in trans.actions: 1465 href = "%s_action_%s.html" % (self.ident, action.ident) 1466 ref = self.frameRef(href, "Status", href, "1", 1467 action.short) 1468 code(' $ref') 1469 if next != state: 1470 if trans.actions: 1471 code('/') 1472 click = "%s_table_%s.html" % (self.ident, next.ident) 1473 over = "%s_State_%s.html" % (self.ident, next.ident) 1474 ref = self.frameRef(click, "Table", over, "1", next.short) 1475 code("$ref") 1476 code("</TD>") 1477 1478 # -- Each row 1479 if state == active_state: 1480 color = "yellow" 1481 else: 1482 color = "white" 1483 1484 click = "%s_table_%s.html" % (self.ident, state.ident) 1485 over = "%s_State_%s.html" % (self.ident, state.ident) 1486 ref = self.frameRef(click, "Table", over, "1", state.short) 1487 code(''' 1488 <TH bgcolor=$color>$ref</TH> 1489</TR> 1490''') 1491 code(''' 1492<!- Column footer-> 1493<TR> 1494 <TH> </TH> 1495''') 1496 1497 for event in self.events.itervalues(): 1498 href = "%s_Event_%s.html" % (self.ident, event.ident) 1499 ref = self.frameRef(href, "Status", href, "1", event.short) 1500 code('<TH bgcolor=white>$ref</TH>') 1501 code(''' 1502</TR> 1503</TABLE> 1504</BODY></HTML> 1505''') 1506 1507 1508 if active_state: 1509 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1510 else: 1511 name = "%s_table.html" % self.ident 1512 code.write(path, name) 1513 1514__all__ = [ "StateMachine" ]
|