StateMachine.py revision 9996
13970Sgblack@eecs.umich.edu# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 23005Sstever@eecs.umich.edu# Copyright (c) 2009 The Hewlett-Packard Development Company 33005Sstever@eecs.umich.edu# All rights reserved. 43005Sstever@eecs.umich.edu# 53005Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without 63005Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are 73005Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright 83005Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer; 93005Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright 103005Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the 113005Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution; 123005Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its 133005Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from 143005Sstever@eecs.umich.edu# this software without specific prior written permission. 153005Sstever@eecs.umich.edu# 163005Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173005Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183005Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193005Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203005Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213005Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223005Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233005Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243005Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253005Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263005Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273005Sstever@eecs.umich.edu 283005Sstever@eecs.umich.edufrom m5.util import orderdict 292889SN/A 302889SN/Afrom slicc.symbols.Symbol import Symbol 312710SN/Afrom slicc.symbols.Var import Var 325457Ssaidi@eecs.umich.eduimport slicc.generate.html as html 335457Ssaidi@eecs.umich.eduimport re 345457Ssaidi@eecs.umich.edu 355457Ssaidi@eecs.umich.edupython_class_map = { 362710SN/A "int": "Int", 372934SN/A "uint32_t" : "UInt32", 382934SN/A "std::string": "String", 392549SN/A "bool": "Bool", 402995SN/A "CacheMemory": "RubyCache", 413395Shsul@eecs.umich.edu "WireBuffer": "RubyWireBuffer", 423448Shsul@eecs.umich.edu "Sequencer": "RubySequencer", 432549SN/A "DirectoryMemory": "RubyDirectoryMemory", 443444Sktlim@umich.edu "MemoryControl": "MemoryControl", 453444Sktlim@umich.edu "DMASequencer": "DMASequencer", 463444Sktlim@umich.edu "Prefetcher":"Prefetcher", 473444Sktlim@umich.edu "Cycles":"Cycles", 482889SN/A } 492710SN/A 503873Sbinkertn@umich.educlass StateMachine(Symbol): 513873Sbinkertn@umich.edu def __init__(self, symtab, ident, location, pairs, config_parameters): 523873Sbinkertn@umich.edu super(StateMachine, self).__init__(symtab, ident, location, pairs) 533873Sbinkertn@umich.edu self.table = None 543322Shsul@eecs.umich.edu self.config_parameters = config_parameters 552995SN/A self.prefetchers = [] 562995SN/A 572995SN/A for param in config_parameters: 582995SN/A if param.pointer: 592995SN/A var = Var(symtab, param.name, location, param.type_ast.type, 603143Shsul@eecs.umich.edu "(*m_%s_ptr)" % param.name, {}, self) 613322Shsul@eecs.umich.edu else: 623322Shsul@eecs.umich.edu var = Var(symtab, param.name, location, param.type_ast.type, 633025Ssaidi@eecs.umich.edu "m_%s" % param.name, {}, self) 643143Shsul@eecs.umich.edu self.symtab.registerSym(param.name, var) 653143Shsul@eecs.umich.edu if str(param.type_ast.type) == "Prefetcher": 663322Shsul@eecs.umich.edu self.prefetchers.append(var) 673444Sktlim@umich.edu 683322Shsul@eecs.umich.edu self.states = orderdict() 692710SN/A self.events = orderdict() 702710SN/A self.actions = orderdict() 712710SN/A self.request_types = orderdict() 722710SN/A self.transitions = [] 732710SN/A self.in_ports = [] 742710SN/A self.functions = [] 753322Shsul@eecs.umich.edu self.objects = [] 763304Sstever@eecs.umich.edu self.TBEType = None 773322Shsul@eecs.umich.edu self.EntryType = None 783322Shsul@eecs.umich.edu 793304Sstever@eecs.umich.edu def __repr__(self): 803481Shsul@eecs.umich.edu return "[StateMachine: %s]" % self.ident 813481Shsul@eecs.umich.edu 822566SN/A def addState(self, state): 833322Shsul@eecs.umich.edu assert self.table is None 843322Shsul@eecs.umich.edu self.states[state.ident] = state 852995SN/A 862995SN/A def addEvent(self, event): 873304Sstever@eecs.umich.edu assert self.table is None 883304Sstever@eecs.umich.edu self.events[event.ident] = event 893304Sstever@eecs.umich.edu 902995SN/A def addAction(self, action): 912995SN/A assert self.table is None 922995SN/A 932917SN/A # Check for duplicate action 942995SN/A for other in self.actions.itervalues(): 953304Sstever@eecs.umich.edu if action.ident == other.ident: 962995SN/A action.warning("Duplicate action definition: %s" % action.ident) 973304Sstever@eecs.umich.edu action.error("Duplicate action definition: %s" % action.ident) 983304Sstever@eecs.umich.edu if action.short == other.short: 993819Shsul@eecs.umich.edu other.warning("Duplicate action shorthand: %s" % other.ident) 1003819Shsul@eecs.umich.edu other.warning(" shorthand = %s" % other.short) 1015222Sksewell@umich.edu action.warning("Duplicate action shorthand: %s" % action.ident) 1025222Sksewell@umich.edu action.error(" shorthand = %s" % action.short) 1033819Shsul@eecs.umich.edu 1043819Shsul@eecs.umich.edu self.actions[action.ident] = action 1055133Sgblack@eecs.umich.edu 1065299Sgblack@eecs.umich.edu def addRequestType(self, request_type): 1073819Shsul@eecs.umich.edu assert self.table is None 1083819Shsul@eecs.umich.edu self.request_types[request_type.ident] = request_type 1093819Shsul@eecs.umich.edu 1103873Sbinkertn@umich.edu def addTransition(self, trans): 1113873Sbinkertn@umich.edu assert self.table is None 1123873Sbinkertn@umich.edu self.transitions.append(trans) 1133873Sbinkertn@umich.edu 1143873Sbinkertn@umich.edu def addInPort(self, var): 1153873Sbinkertn@umich.edu self.in_ports.append(var) 1163312Sstever@eecs.umich.edu 1173668Srdreslin@umich.edu def addFunc(self, func): 1183668Srdreslin@umich.edu # register func in the symbol table 1193668Srdreslin@umich.edu self.symtab.registerSym(str(func), func) 1203668Srdreslin@umich.edu self.functions.append(func) 1213668Srdreslin@umich.edu 1223668Srdreslin@umich.edu def addObject(self, obj): 1233668Srdreslin@umich.edu self.objects.append(obj) 1243322Shsul@eecs.umich.edu 1255142Ssaidi@eecs.umich.edu def addType(self, type): 1265142Ssaidi@eecs.umich.edu type_ident = '%s' % type.c_ident 1275142Ssaidi@eecs.umich.edu 1285142Ssaidi@eecs.umich.edu if type_ident == "%s_TBE" %self.ident: 1295142Ssaidi@eecs.umich.edu if self.TBEType != None: 1305142Ssaidi@eecs.umich.edu self.error("Multiple Transaction Buffer types in a " \ 1315142Ssaidi@eecs.umich.edu "single machine."); 1325142Ssaidi@eecs.umich.edu self.TBEType = type 1335142Ssaidi@eecs.umich.edu 1343312Sstever@eecs.umich.edu elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 1353514Sktlim@umich.edu if self.EntryType != None: 1363395Shsul@eecs.umich.edu self.error("Multiple AbstractCacheEntry types in a " \ 1373448Shsul@eecs.umich.edu "single machine."); 1383668Srdreslin@umich.edu self.EntryType = type 1393668Srdreslin@umich.edu 1403668Srdreslin@umich.edu # Needs to be called before accessing the table 1413668Srdreslin@umich.edu def buildTable(self): 1423005Sstever@eecs.umich.edu assert self.table is None 1434968Sacolyte@umich.edu 1444968Sacolyte@umich.edu table = {} 1454968Sacolyte@umich.edu 1465222Sksewell@umich.edu for trans in self.transitions: 1475254Sksewell@umich.edu # Track which actions we touch so we know if we use them 1485222Sksewell@umich.edu # all -- really this should be done for all symbols as 1493005Sstever@eecs.umich.edu # part of the symbol table, then only trigger it for 1503819Shsul@eecs.umich.edu # Actions, States, Events, etc. 1513819Shsul@eecs.umich.edu 1525222Sksewell@umich.edu for action in trans.actions: 1535222Sksewell@umich.edu action.used = True 1543819Shsul@eecs.umich.edu 1553819Shsul@eecs.umich.edu index = (trans.state, trans.event) 1565133Sgblack@eecs.umich.edu if index in table: 1575133Sgblack@eecs.umich.edu table[index].warning("Duplicate transition: %s" % table[index]) 1583322Shsul@eecs.umich.edu trans.error("Duplicate transition: %s" % trans) 1593322Shsul@eecs.umich.edu table[index] = trans 1604968Sacolyte@umich.edu 1614968Sacolyte@umich.edu # Look at all actions to make sure we used them all 1624837Ssaidi@eecs.umich.edu for action in self.actions.itervalues(): 1634837Ssaidi@eecs.umich.edu if not action.used: 1644837Ssaidi@eecs.umich.edu error_msg = "Unused action: %s" % action.ident 1653322Shsul@eecs.umich.edu if "desc" in action: 1663005Sstever@eecs.umich.edu error_msg += ", " + action.desc 1674167Sbinkertn@umich.edu action.warning(error_msg) 1683005Sstever@eecs.umich.edu self.table = table 1693005Sstever@eecs.umich.edu 1703005Sstever@eecs.umich.edu def writeCodeFiles(self, path, includes): 1712566SN/A self.printControllerPython(path) 1723481Shsul@eecs.umich.edu 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 clearStats(); 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 354 code(''' 355 356// Actions 357''') 358 if self.TBEType != None and self.EntryType != None: 359 for action in self.actions.itervalues(): 360 code('/** \\brief ${{action.desc}} */') 361 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 362 elif self.TBEType != None: 363 for action in self.actions.itervalues(): 364 code('/** \\brief ${{action.desc}} */') 365 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);') 366 elif self.EntryType != None: 367 for action in self.actions.itervalues(): 368 code('/** \\brief ${{action.desc}} */') 369 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 370 else: 371 for action in self.actions.itervalues(): 372 code('/** \\brief ${{action.desc}} */') 373 code('void ${{action.ident}}(const Address& addr);') 374 375 # the controller internal variables 376 code(''' 377 378// Objects 379''') 380 for var in self.objects: 381 th = var.get("template", "") 382 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 383 384 code.dedent() 385 code('};') 386 code('#endif // __${ident}_CONTROLLER_H__') 387 code.write(path, '%s.hh' % c_ident) 388 389 def printControllerCC(self, path, includes): 390 '''Output the actions for performing the actions''' 391 392 code = self.symtab.codeFormatter() 393 ident = self.ident 394 c_ident = "%s_Controller" % self.ident 395 has_peer = False 396 397 code(''' 398/** \\file $c_ident.cc 399 * 400 * Auto generated C++ code started by $__file__:$__line__ 401 * Created by slicc definition of Module "${{self.short}}" 402 */ 403 404#include <sys/types.h> 405#include <unistd.h> 406 407#include <cassert> 408#include <sstream> 409#include <string> 410 411#include "base/compiler.hh" 412#include "base/cprintf.hh" 413#include "debug/RubyGenerated.hh" 414#include "debug/RubySlicc.hh" 415#include "mem/protocol/${ident}_Controller.hh" 416#include "mem/protocol/${ident}_Event.hh" 417#include "mem/protocol/${ident}_State.hh" 418#include "mem/protocol/Types.hh" 419#include "mem/ruby/common/Global.hh" 420#include "mem/ruby/system/System.hh" 421''') 422 for include_path in includes: 423 code('#include "${{include_path}}"') 424 425 code(''' 426 427using namespace std; 428''') 429 430 # include object classes 431 seen_types = set() 432 for var in self.objects: 433 if var.type.ident not in seen_types and not var.type.isPrimitive: 434 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 435 seen_types.add(var.type.ident) 436 437 code(''' 438$c_ident * 439${c_ident}Params::create() 440{ 441 return new $c_ident(this); 442} 443 444int $c_ident::m_num_controllers = 0; 445std::vector<Stats::Vector *> $c_ident::eventVec; 446std::vector<std::vector<Stats::Vector *> > $c_ident::transVec; 447 448// for adding information to the protocol debug trace 449stringstream ${ident}_transitionComment; 450 451#ifndef NDEBUG 452#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 453#else 454#define APPEND_TRANSITION_COMMENT(str) do {} while (0) 455#endif 456 457/** \\brief constructor */ 458$c_ident::$c_ident(const Params *p) 459 : AbstractController(p) 460{ 461 m_name = "${ident}"; 462''') 463 num_in_ports = len(self.in_ports) 464 code(' m_in_ports = $num_in_ports;') 465 code.indent() 466 467 # 468 # After initializing the universal machine parameters, initialize the 469 # this machines config parameters. Also detemine if these configuration 470 # params include a sequencer. This information will be used later for 471 # contecting the sequencer back to the L1 cache controller. 472 # 473 contains_dma_sequencer = False 474 sequencers = [] 475 for param in self.config_parameters: 476 if param.name == "dma_sequencer": 477 contains_dma_sequencer = True 478 elif re.compile("sequencer").search(param.name): 479 sequencers.append(param.name) 480 if param.pointer: 481 code('m_${{param.name}}_ptr = p->${{param.name}};') 482 else: 483 code('m_${{param.name}} = p->${{param.name}};') 484 485 # 486 # For the l1 cache controller, add the special atomic support which 487 # includes passing the sequencer a pointer to the controller. 488 # 489 for seq in sequencers: 490 code(''' 491m_${{seq}}_ptr->setController(this); 492 ''') 493 494 # 495 # For the DMA controller, pass the sequencer a pointer to the 496 # controller. 497 # 498 if self.ident == "DMA": 499 if not contains_dma_sequencer: 500 self.error("The DMA controller must include the sequencer " \ 501 "configuration parameter") 502 503 code(''' 504m_dma_sequencer_ptr->setController(this); 505''') 506 507 code('m_num_controllers++;') 508 for var in self.objects: 509 if var.ident.find("mandatoryQueue") >= 0: 510 code(''' 511m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}(); 512m_${{var.c_ident}}_ptr->setReceiver(this); 513''') 514 else: 515 if "network" in var and "physical_network" in var and \ 516 var["network"] == "To": 517 has_peer = True 518 code(''' 519m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}(); 520peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr; 521m_${{var.c_ident}}_ptr->setSender(this); 522''') 523 524 code(''' 525if (p->peer != NULL) 526 connectWithPeer(p->peer); 527 528for (int state = 0; state < ${ident}_State_NUM; state++) { 529 for (int event = 0; event < ${ident}_Event_NUM; event++) { 530 m_possible[state][event] = false; 531 m_counters[state][event] = 0; 532 } 533} 534for (int event = 0; event < ${ident}_Event_NUM; event++) { 535 m_event_counters[event] = 0; 536} 537''') 538 code.dedent() 539 code(''' 540} 541 542void 543$c_ident::init() 544{ 545 MachineType machine_type = string_to_MachineType("${{var.machine.ident}}"); 546 int base = MachineType_base_number(machine_type); 547 548 m_machineID.type = MachineType_${ident}; 549 m_machineID.num = m_version; 550 551 // initialize objects 552 553''') 554 555 code.indent() 556 for var in self.objects: 557 vtype = var.type 558 vid = "m_%s_ptr" % var.c_ident 559 if "network" not in var: 560 # Not a network port object 561 if "primitive" in vtype: 562 code('$vid = new ${{vtype.c_ident}};') 563 if "default" in var: 564 code('(*$vid) = ${{var["default"]}};') 565 else: 566 # Normal Object 567 if var.ident.find("mandatoryQueue") < 0: 568 th = var.get("template", "") 569 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 570 args = "" 571 if "non_obj" not in vtype and not vtype.isEnumeration: 572 args = var.get("constructor", "") 573 code('$expr($args);') 574 575 code('assert($vid != NULL);') 576 577 if "default" in var: 578 code('*$vid = ${{var["default"]}}; // Object default') 579 elif "default" in vtype: 580 comment = "Type %s default" % vtype.ident 581 code('*$vid = ${{vtype["default"]}}; // $comment') 582 583 # Set ordering 584 if "ordered" in var: 585 # A buffer 586 code('$vid->setOrdering(${{var["ordered"]}});') 587 588 # Set randomization 589 if "random" in var: 590 # A buffer 591 code('$vid->setRandomization(${{var["random"]}});') 592 593 # Set Priority 594 if vtype.isBuffer and "rank" in var: 595 code('$vid->setPriority(${{var["rank"]}});') 596 597 # Set sender and receiver for trigger queue 598 if var.ident.find("triggerQueue") >= 0: 599 code('$vid->setSender(this);') 600 code('$vid->setReceiver(this);') 601 elif vtype.c_ident == "TimerTable": 602 code('$vid->setClockObj(this);') 603 elif var.ident.find("optionalQueue") >= 0: 604 code('$vid->setSender(this);') 605 code('$vid->setReceiver(this);') 606 607 else: 608 # Network port object 609 network = var["network"] 610 ordered = var["ordered"] 611 612 if "virtual_network" in var: 613 vnet = var["virtual_network"] 614 vnet_type = var["vnet_type"] 615 616 assert var.machine is not None 617 code(''' 618$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type"); 619assert($vid != NULL); 620''') 621 622 # Set the end 623 if network == "To": 624 code('$vid->setSender(this);') 625 else: 626 code('$vid->setReceiver(this);') 627 628 # Set ordering 629 if "ordered" in var: 630 # A buffer 631 code('$vid->setOrdering(${{var["ordered"]}});') 632 633 # Set randomization 634 if "random" in var: 635 # A buffer 636 code('$vid->setRandomization(${{var["random"]}});') 637 638 # Set Priority 639 if "rank" in var: 640 code('$vid->setPriority(${{var["rank"]}})') 641 642 # Set buffer size 643 if vtype.isBuffer: 644 code(''' 645if (m_buffer_size > 0) { 646 $vid->resize(m_buffer_size); 647} 648''') 649 650 # set description (may be overriden later by port def) 651 code(''' 652$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]"); 653 654''') 655 656 if vtype.isBuffer: 657 if "recycle_latency" in var: 658 code('$vid->setRecycleLatency( ' \ 659 'Cycles(${{var["recycle_latency"]}}));') 660 else: 661 code('$vid->setRecycleLatency(m_recycle_latency);') 662 663 # Set the prefetchers 664 code() 665 for prefetcher in self.prefetchers: 666 code('${{prefetcher.code}}.setController(this);') 667 668 code() 669 for port in self.in_ports: 670 # Set the queue consumers 671 code('${{port.code}}.setConsumer(this);') 672 # Set the queue descriptions 673 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");') 674 675 # Initialize the transition profiling 676 code() 677 for trans in self.transitions: 678 # Figure out if we stall 679 stall = False 680 for action in trans.actions: 681 if action.ident == "z_stall": 682 stall = True 683 684 # Only possible if it is not a 'z' case 685 if not stall: 686 state = "%s_State_%s" % (self.ident, trans.state.ident) 687 event = "%s_Event_%s" % (self.ident, trans.event.ident) 688 code('possibleTransition($state, $event);') 689 690 code.dedent() 691 code(''' 692 AbstractController::init(); 693 clearStats(); 694} 695''') 696 697 has_mandatory_q = False 698 for port in self.in_ports: 699 if port.code.find("mandatoryQueue_ptr") >= 0: 700 has_mandatory_q = True 701 702 if has_mandatory_q: 703 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 704 else: 705 mq_ident = "NULL" 706 707 seq_ident = "NULL" 708 for param in self.config_parameters: 709 if param.name == "sequencer": 710 assert(param.pointer) 711 seq_ident = "m_%s_ptr" % param.name 712 713 code(''' 714 715void 716$c_ident::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(name() + "." + ${ident}_Event_to_string(event)); 724 t->flags(Stats::pdf | Stats::total | Stats::oneline | 725 Stats::nozero); 726 727 eventVec.push_back(t); 728 } 729 730 for (${ident}_State state = ${ident}_State_FIRST; 731 state < ${ident}_State_NUM; ++state) { 732 733 transVec.push_back(std::vector<Stats::Vector *>()); 734 735 for (${ident}_Event event = ${ident}_Event_FIRST; 736 event < ${ident}_Event_NUM; ++event) { 737 738 Stats::Vector *t = new Stats::Vector(); 739 t->init(m_num_controllers); 740 t->name(name() + "." + ${ident}_State_to_string(state) + 741 "." + ${ident}_Event_to_string(event)); 742 743 t->flags(Stats::pdf | Stats::total | Stats::oneline | 744 Stats::nozero); 745 transVec[state].push_back(t); 746 } 747 } 748 } 749} 750 751void 752$c_ident::collateStats() 753{ 754 for (${ident}_Event event = ${ident}_Event_FIRST; 755 event < ${ident}_Event_NUM; ++event) { 756 for (unsigned int i = 0; i < m_num_controllers; ++i) { 757 std::map<uint32_t, AbstractController *>::iterator it = 758 g_abs_controls[MachineType_${ident}].find(i); 759 assert(it != g_abs_controls[MachineType_${ident}].end()); 760 (*eventVec[event])[i] = 761 (($c_ident *)(*it).second)->getEventCount(event); 762 } 763 } 764 765 for (${ident}_State state = ${ident}_State_FIRST; 766 state < ${ident}_State_NUM; ++state) { 767 768 for (${ident}_Event event = ${ident}_Event_FIRST; 769 event < ${ident}_Event_NUM; ++event) { 770 771 for (unsigned int i = 0; i < m_num_controllers; ++i) { 772 std::map<uint32_t, AbstractController *>::iterator it = 773 g_abs_controls[MachineType_${ident}].find(i); 774 assert(it != g_abs_controls[MachineType_${ident}].end()); 775 (*transVec[state][event])[i] = 776 (($c_ident *)(*it).second)->getTransitionCount(state, event); 777 } 778 } 779 } 780} 781 782void 783$c_ident::countTransition(${ident}_State state, ${ident}_Event event) 784{ 785 assert(m_possible[state][event]); 786 m_counters[state][event]++; 787 m_event_counters[event]++; 788} 789void 790$c_ident::possibleTransition(${ident}_State state, 791 ${ident}_Event event) 792{ 793 m_possible[state][event] = true; 794} 795 796uint64 797$c_ident::getEventCount(${ident}_Event event) 798{ 799 return m_event_counters[event]; 800} 801 802bool 803$c_ident::isPossible(${ident}_State state, ${ident}_Event event) 804{ 805 return m_possible[state][event]; 806} 807 808uint64 809$c_ident::getTransitionCount(${ident}_State state, 810 ${ident}_Event event) 811{ 812 return m_counters[state][event]; 813} 814 815int 816$c_ident::getNumControllers() 817{ 818 return m_num_controllers; 819} 820 821MessageBuffer* 822$c_ident::getMandatoryQueue() const 823{ 824 return $mq_ident; 825} 826 827Sequencer* 828$c_ident::getSequencer() const 829{ 830 return $seq_ident; 831} 832 833const string 834$c_ident::toString() const 835{ 836 return "$c_ident"; 837} 838 839void 840$c_ident::print(ostream& out) const 841{ 842 out << "[$c_ident " << m_version << "]"; 843} 844 845void $c_ident::clearStats() 846{ 847 for (int state = 0; state < ${ident}_State_NUM; state++) { 848 for (int event = 0; event < ${ident}_Event_NUM; event++) { 849 m_counters[state][event] = 0; 850 } 851 } 852 853 for (int event = 0; event < ${ident}_Event_NUM; event++) { 854 m_event_counters[event] = 0; 855 } 856 857 AbstractController::clearStats(); 858} 859''') 860 861 if self.EntryType != None: 862 code(''' 863 864// Set and Reset for cache_entry variable 865void 866$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 867{ 868 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 869} 870 871void 872$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 873{ 874 m_cache_entry_ptr = 0; 875} 876''') 877 878 if self.TBEType != None: 879 code(''' 880 881// Set and Reset for tbe variable 882void 883$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 884{ 885 m_tbe_ptr = m_new_tbe; 886} 887 888void 889$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 890{ 891 m_tbe_ptr = NULL; 892} 893''') 894 895 code(''' 896 897void 898$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 899{ 900''') 901 # 902 # Record cache contents for all associated caches. 903 # 904 code.indent() 905 for param in self.config_parameters: 906 if param.type_ast.type.ident == "CacheMemory": 907 assert(param.pointer) 908 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 909 910 code.dedent() 911 code(''' 912} 913 914// Actions 915''') 916 if self.TBEType != None and self.EntryType != None: 917 for action in self.actions.itervalues(): 918 if "c_code" not in action: 919 continue 920 921 code(''' 922/** \\brief ${{action.desc}} */ 923void 924$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 925{ 926 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 927 ${{action["c_code"]}} 928} 929 930''') 931 elif self.TBEType != None: 932 for action in self.actions.itervalues(): 933 if "c_code" not in action: 934 continue 935 936 code(''' 937/** \\brief ${{action.desc}} */ 938void 939$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 940{ 941 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 942 ${{action["c_code"]}} 943} 944 945''') 946 elif self.EntryType != None: 947 for action in self.actions.itervalues(): 948 if "c_code" not in action: 949 continue 950 951 code(''' 952/** \\brief ${{action.desc}} */ 953void 954$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 955{ 956 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 957 ${{action["c_code"]}} 958} 959 960''') 961 else: 962 for action in self.actions.itervalues(): 963 if "c_code" not in action: 964 continue 965 966 code(''' 967/** \\brief ${{action.desc}} */ 968void 969$c_ident::${{action.ident}}(const Address& addr) 970{ 971 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 972 ${{action["c_code"]}} 973} 974 975''') 976 for func in self.functions: 977 code(func.generateCode()) 978 979 # Function for functional reads from messages buffered in the controller 980 code(''' 981bool 982$c_ident::functionalReadBuffers(PacketPtr& pkt) 983{ 984''') 985 for var in self.objects: 986 vtype = var.type 987 if vtype.isBuffer: 988 vid = "m_%s_ptr" % var.c_ident 989 code('if ($vid->functionalRead(pkt)) { return true; }') 990 code(''' 991 return false; 992} 993''') 994 995 # Function for functional writes to messages buffered in the controller 996 code(''' 997uint32_t 998$c_ident::functionalWriteBuffers(PacketPtr& pkt) 999{ 1000 uint32_t num_functional_writes = 0; 1001''') 1002 for var in self.objects: 1003 vtype = var.type 1004 if vtype.isBuffer: 1005 vid = "m_%s_ptr" % var.c_ident 1006 code('num_functional_writes += $vid->functionalWrite(pkt);') 1007 code(''' 1008 return num_functional_writes; 1009} 1010''') 1011 1012 # Check if this controller has a peer, if yes then write the 1013 # function for connecting to the peer. 1014 if has_peer: 1015 code(''' 1016 1017void 1018$c_ident::getQueuesFromPeer(AbstractController *peer) 1019{ 1020''') 1021 for var in self.objects: 1022 if "network" in var and "physical_network" in var and \ 1023 var["network"] == "From": 1024 code(''' 1025m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}}); 1026assert(m_${{var.c_ident}}_ptr != NULL); 1027m_${{var.c_ident}}_ptr->setReceiver(this); 1028 1029''') 1030 code('}') 1031 1032 code.write(path, "%s.cc" % c_ident) 1033 1034 def printCWakeup(self, path, includes): 1035 '''Output the wakeup loop for the events''' 1036 1037 code = self.symtab.codeFormatter() 1038 ident = self.ident 1039 1040 outputRequest_types = True 1041 if len(self.request_types) == 0: 1042 outputRequest_types = False 1043 1044 code(''' 1045// Auto generated C++ code started by $__file__:$__line__ 1046// ${ident}: ${{self.short}} 1047 1048#include <sys/types.h> 1049#include <unistd.h> 1050 1051#include <cassert> 1052 1053#include "base/misc.hh" 1054#include "debug/RubySlicc.hh" 1055#include "mem/protocol/${ident}_Controller.hh" 1056#include "mem/protocol/${ident}_Event.hh" 1057#include "mem/protocol/${ident}_State.hh" 1058''') 1059 1060 if outputRequest_types: 1061 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1062 1063 code(''' 1064#include "mem/protocol/Types.hh" 1065#include "mem/ruby/common/Global.hh" 1066#include "mem/ruby/system/System.hh" 1067''') 1068 1069 1070 for include_path in includes: 1071 code('#include "${{include_path}}"') 1072 1073 code(''' 1074 1075using namespace std; 1076 1077void 1078${ident}_Controller::wakeup() 1079{ 1080 int counter = 0; 1081 while (true) { 1082 // Some cases will put us into an infinite loop without this limit 1083 assert(counter <= m_transitions_per_cycle); 1084 if (counter == m_transitions_per_cycle) { 1085 // Count how often we are fully utilized 1086 m_fully_busy_cycles++; 1087 1088 // Wakeup in another cycle and try again 1089 scheduleEvent(Cycles(1)); 1090 break; 1091 } 1092''') 1093 1094 code.indent() 1095 code.indent() 1096 1097 # InPorts 1098 # 1099 for port in self.in_ports: 1100 code.indent() 1101 code('// ${ident}InPort $port') 1102 if port.pairs.has_key("rank"): 1103 code('m_cur_in_port = ${{port.pairs["rank"]}};') 1104 else: 1105 code('m_cur_in_port = 0;') 1106 code('${{port["c_code_in_port"]}}') 1107 code.dedent() 1108 1109 code('') 1110 1111 code.dedent() 1112 code.dedent() 1113 code(''' 1114 break; // If we got this far, we have nothing left todo 1115 } 1116} 1117''') 1118 1119 code.write(path, "%s_Wakeup.cc" % self.ident) 1120 1121 def printCSwitch(self, path): 1122 '''Output switch statement for transition table''' 1123 1124 code = self.symtab.codeFormatter() 1125 ident = self.ident 1126 1127 code(''' 1128// Auto generated C++ code started by $__file__:$__line__ 1129// ${ident}: ${{self.short}} 1130 1131#include <cassert> 1132 1133#include "base/misc.hh" 1134#include "base/trace.hh" 1135#include "debug/ProtocolTrace.hh" 1136#include "debug/RubyGenerated.hh" 1137#include "mem/protocol/${ident}_Controller.hh" 1138#include "mem/protocol/${ident}_Event.hh" 1139#include "mem/protocol/${ident}_State.hh" 1140#include "mem/protocol/Types.hh" 1141#include "mem/ruby/common/Global.hh" 1142#include "mem/ruby/system/System.hh" 1143 1144#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1145 1146#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1147#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1148 1149TransitionResult 1150${ident}_Controller::doTransition(${ident}_Event event, 1151''') 1152 if self.EntryType != None: 1153 code(''' 1154 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1155''') 1156 if self.TBEType != None: 1157 code(''' 1158 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1159''') 1160 code(''' 1161 const Address &addr) 1162{ 1163''') 1164 if self.TBEType != None and self.EntryType != None: 1165 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1166 elif self.TBEType != None: 1167 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1168 elif self.EntryType != None: 1169 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1170 else: 1171 code('${ident}_State state = getState(addr);') 1172 1173 code(''' 1174 ${ident}_State next_state = state; 1175 1176 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1177 *this, curCycle(), ${ident}_State_to_string(state), 1178 ${ident}_Event_to_string(event), addr); 1179 1180 TransitionResult result = 1181''') 1182 if self.TBEType != None and self.EntryType != None: 1183 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1184 elif self.TBEType != None: 1185 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1186 elif self.EntryType != None: 1187 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1188 else: 1189 code('doTransitionWorker(event, state, next_state, addr);') 1190 1191 code(''' 1192 if (result == TransitionResult_Valid) { 1193 DPRINTF(RubyGenerated, "next_state: %s\\n", 1194 ${ident}_State_to_string(next_state)); 1195 countTransition(state, event); 1196 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1197 curTick(), m_version, "${ident}", 1198 ${ident}_Event_to_string(event), 1199 ${ident}_State_to_string(state), 1200 ${ident}_State_to_string(next_state), 1201 addr, GET_TRANSITION_COMMENT()); 1202 1203 CLEAR_TRANSITION_COMMENT(); 1204''') 1205 if self.TBEType != None and self.EntryType != None: 1206 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1207 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1208 elif self.TBEType != None: 1209 code('setState(m_tbe_ptr, addr, next_state);') 1210 code('setAccessPermission(addr, next_state);') 1211 elif self.EntryType != None: 1212 code('setState(m_cache_entry_ptr, addr, next_state);') 1213 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1214 else: 1215 code('setState(addr, next_state);') 1216 code('setAccessPermission(addr, next_state);') 1217 1218 code(''' 1219 } else if (result == TransitionResult_ResourceStall) { 1220 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1221 curTick(), m_version, "${ident}", 1222 ${ident}_Event_to_string(event), 1223 ${ident}_State_to_string(state), 1224 ${ident}_State_to_string(next_state), 1225 addr, "Resource Stall"); 1226 } else if (result == TransitionResult_ProtocolStall) { 1227 DPRINTF(RubyGenerated, "stalling\\n"); 1228 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1229 curTick(), m_version, "${ident}", 1230 ${ident}_Event_to_string(event), 1231 ${ident}_State_to_string(state), 1232 ${ident}_State_to_string(next_state), 1233 addr, "Protocol Stall"); 1234 } 1235 1236 return result; 1237} 1238 1239TransitionResult 1240${ident}_Controller::doTransitionWorker(${ident}_Event event, 1241 ${ident}_State state, 1242 ${ident}_State& next_state, 1243''') 1244 1245 if self.TBEType != None: 1246 code(''' 1247 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1248''') 1249 if self.EntryType != None: 1250 code(''' 1251 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1252''') 1253 code(''' 1254 const Address& addr) 1255{ 1256 switch(HASH_FUN(state, event)) { 1257''') 1258 1259 # This map will allow suppress generating duplicate code 1260 cases = orderdict() 1261 1262 for trans in self.transitions: 1263 case_string = "%s_State_%s, %s_Event_%s" % \ 1264 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1265 1266 case = self.symtab.codeFormatter() 1267 # Only set next_state if it changes 1268 if trans.state != trans.nextState: 1269 ns_ident = trans.nextState.ident 1270 case('next_state = ${ident}_State_${ns_ident};') 1271 1272 actions = trans.actions 1273 request_types = trans.request_types 1274 1275 # Check for resources 1276 case_sorter = [] 1277 res = trans.resources 1278 for key,val in res.iteritems(): 1279 if key.type.ident != "DNUCAStopTable": 1280 val = ''' 1281if (!%s.areNSlotsAvailable(%s)) 1282 return TransitionResult_ResourceStall; 1283''' % (key.code, val) 1284 case_sorter.append(val) 1285 1286 # Check all of the request_types for resource constraints 1287 for request_type in request_types: 1288 val = ''' 1289if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1290 return TransitionResult_ResourceStall; 1291} 1292''' % (self.ident, request_type.ident) 1293 case_sorter.append(val) 1294 1295 # Emit the code sequences in a sorted order. This makes the 1296 # output deterministic (without this the output order can vary 1297 # since Map's keys() on a vector of pointers is not deterministic 1298 for c in sorted(case_sorter): 1299 case("$c") 1300 1301 # Record access types for this transition 1302 for request_type in request_types: 1303 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1304 1305 # Figure out if we stall 1306 stall = False 1307 for action in actions: 1308 if action.ident == "z_stall": 1309 stall = True 1310 break 1311 1312 if stall: 1313 case('return TransitionResult_ProtocolStall;') 1314 else: 1315 if self.TBEType != None and self.EntryType != None: 1316 for action in actions: 1317 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1318 elif self.TBEType != None: 1319 for action in actions: 1320 case('${{action.ident}}(m_tbe_ptr, addr);') 1321 elif self.EntryType != None: 1322 for action in actions: 1323 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1324 else: 1325 for action in actions: 1326 case('${{action.ident}}(addr);') 1327 case('return TransitionResult_Valid;') 1328 1329 case = str(case) 1330 1331 # Look to see if this transition code is unique. 1332 if case not in cases: 1333 cases[case] = [] 1334 1335 cases[case].append(case_string) 1336 1337 # Walk through all of the unique code blocks and spit out the 1338 # corresponding case statement elements 1339 for case,transitions in cases.iteritems(): 1340 # Iterative over all the multiple transitions that share 1341 # the same code 1342 for trans in transitions: 1343 code(' case HASH_FUN($trans):') 1344 code(' $case') 1345 1346 code(''' 1347 default: 1348 fatal("Invalid transition\\n" 1349 "%s time: %d addr: %s event: %s state: %s\\n", 1350 name(), curCycle(), addr, event, state); 1351 } 1352 return TransitionResult_Valid; 1353} 1354''') 1355 code.write(path, "%s_Transitions.cc" % self.ident) 1356 1357 1358 # ************************** 1359 # ******* HTML Files ******* 1360 # ************************** 1361 def frameRef(self, click_href, click_target, over_href, over_num, text): 1362 code = self.symtab.codeFormatter(fix_newlines=False) 1363 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1364 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1365 parent.frames[$over_num].location='$over_href' 1366 }\"> 1367 ${{html.formatShorthand(text)}} 1368 </A>""") 1369 return str(code) 1370 1371 def writeHTMLFiles(self, path): 1372 # Create table with no row hilighted 1373 self.printHTMLTransitions(path, None) 1374 1375 # Generate transition tables 1376 for state in self.states.itervalues(): 1377 self.printHTMLTransitions(path, state) 1378 1379 # Generate action descriptions 1380 for action in self.actions.itervalues(): 1381 name = "%s_action_%s.html" % (self.ident, action.ident) 1382 code = html.createSymbol(action, "Action") 1383 code.write(path, name) 1384 1385 # Generate state descriptions 1386 for state in self.states.itervalues(): 1387 name = "%s_State_%s.html" % (self.ident, state.ident) 1388 code = html.createSymbol(state, "State") 1389 code.write(path, name) 1390 1391 # Generate event descriptions 1392 for event in self.events.itervalues(): 1393 name = "%s_Event_%s.html" % (self.ident, event.ident) 1394 code = html.createSymbol(event, "Event") 1395 code.write(path, name) 1396 1397 def printHTMLTransitions(self, path, active_state): 1398 code = self.symtab.codeFormatter() 1399 1400 code(''' 1401<HTML> 1402<BODY link="blue" vlink="blue"> 1403 1404<H1 align="center">${{html.formatShorthand(self.short)}}: 1405''') 1406 code.indent() 1407 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1408 mid = machine.ident 1409 if i != 0: 1410 extra = " - " 1411 else: 1412 extra = "" 1413 if machine == self: 1414 code('$extra$mid') 1415 else: 1416 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1417 code.dedent() 1418 1419 code(""" 1420</H1> 1421 1422<TABLE border=1> 1423<TR> 1424 <TH> </TH> 1425""") 1426 1427 for event in self.events.itervalues(): 1428 href = "%s_Event_%s.html" % (self.ident, event.ident) 1429 ref = self.frameRef(href, "Status", href, "1", event.short) 1430 code('<TH bgcolor=white>$ref</TH>') 1431 1432 code('</TR>') 1433 # -- Body of table 1434 for state in self.states.itervalues(): 1435 # -- Each row 1436 if state == active_state: 1437 color = "yellow" 1438 else: 1439 color = "white" 1440 1441 click = "%s_table_%s.html" % (self.ident, state.ident) 1442 over = "%s_State_%s.html" % (self.ident, state.ident) 1443 text = html.formatShorthand(state.short) 1444 ref = self.frameRef(click, "Table", over, "1", state.short) 1445 code(''' 1446<TR> 1447 <TH bgcolor=$color>$ref</TH> 1448''') 1449 1450 # -- One column for each event 1451 for event in self.events.itervalues(): 1452 trans = self.table.get((state,event), None) 1453 if trans is None: 1454 # This is the no transition case 1455 if state == active_state: 1456 color = "#C0C000" 1457 else: 1458 color = "lightgrey" 1459 1460 code('<TD bgcolor=$color> </TD>') 1461 continue 1462 1463 next = trans.nextState 1464 stall_action = False 1465 1466 # -- Get the actions 1467 for action in trans.actions: 1468 if action.ident == "z_stall" or \ 1469 action.ident == "zz_recycleMandatoryQueue": 1470 stall_action = True 1471 1472 # -- Print out "actions/next-state" 1473 if stall_action: 1474 if state == active_state: 1475 color = "#C0C000" 1476 else: 1477 color = "lightgrey" 1478 1479 elif active_state and next.ident == active_state.ident: 1480 color = "aqua" 1481 elif state == active_state: 1482 color = "yellow" 1483 else: 1484 color = "white" 1485 1486 code('<TD bgcolor=$color>') 1487 for action in trans.actions: 1488 href = "%s_action_%s.html" % (self.ident, action.ident) 1489 ref = self.frameRef(href, "Status", href, "1", 1490 action.short) 1491 code(' $ref') 1492 if next != state: 1493 if trans.actions: 1494 code('/') 1495 click = "%s_table_%s.html" % (self.ident, next.ident) 1496 over = "%s_State_%s.html" % (self.ident, next.ident) 1497 ref = self.frameRef(click, "Table", over, "1", next.short) 1498 code("$ref") 1499 code("</TD>") 1500 1501 # -- Each row 1502 if state == active_state: 1503 color = "yellow" 1504 else: 1505 color = "white" 1506 1507 click = "%s_table_%s.html" % (self.ident, state.ident) 1508 over = "%s_State_%s.html" % (self.ident, state.ident) 1509 ref = self.frameRef(click, "Table", over, "1", state.short) 1510 code(''' 1511 <TH bgcolor=$color>$ref</TH> 1512</TR> 1513''') 1514 code(''' 1515<!- Column footer-> 1516<TR> 1517 <TH> </TH> 1518''') 1519 1520 for event in self.events.itervalues(): 1521 href = "%s_Event_%s.html" % (self.ident, event.ident) 1522 ref = self.frameRef(href, "Status", href, "1", event.short) 1523 code('<TH bgcolor=white>$ref</TH>') 1524 code(''' 1525</TR> 1526</TABLE> 1527</BODY></HTML> 1528''') 1529 1530 1531 if active_state: 1532 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1533 else: 1534 name = "%s_table.html" % self.ident 1535 code.write(path, name) 1536 1537__all__ = [ "StateMachine" ] 1538