StateMachine.py revision 11308
111923Sandreas.sandberg@arm.com# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 211923Sandreas.sandberg@arm.com# Copyright (c) 2009 The Hewlett-Packard Development Company 311923Sandreas.sandberg@arm.com# Copyright (c) 2013 Advanced Micro Devices, Inc. 411923Sandreas.sandberg@arm.com# All rights reserved. 511923Sandreas.sandberg@arm.com# 611923Sandreas.sandberg@arm.com# Redistribution and use in source and binary forms, with or without 711923Sandreas.sandberg@arm.com# modification, are permitted provided that the following conditions are 811923Sandreas.sandberg@arm.com# met: redistributions of source code must retain the above copyright 911923Sandreas.sandberg@arm.com# notice, this list of conditions and the following disclaimer; 1011923Sandreas.sandberg@arm.com# redistributions in binary form must reproduce the above copyright 1111923Sandreas.sandberg@arm.com# notice, this list of conditions and the following disclaimer in the 1211923Sandreas.sandberg@arm.com# documentation and/or other materials provided with the distribution; 136654Snate@binkert.org# neither the name of the copyright holders nor the names of its 146654Snate@binkert.org# contributors may be used to endorse or promote products derived from 155467Snate@binkert.org# this software without specific prior written permission. 165467Snate@binkert.org# 175467Snate@binkert.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 185467Snate@binkert.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 195467Snate@binkert.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 205467Snate@binkert.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 215467Snate@binkert.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 225467Snate@binkert.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 235467Snate@binkert.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 245467Snate@binkert.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 255467Snate@binkert.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 265467Snate@binkert.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 275467Snate@binkert.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 285467Snate@binkert.org 295467Snate@binkert.orgfrom m5.util import orderdict 305467Snate@binkert.org 315467Snate@binkert.orgfrom slicc.symbols.Symbol import Symbol 325467Snate@binkert.orgfrom slicc.symbols.Var import Var 335467Snate@binkert.orgimport slicc.generate.html as html 345467Snate@binkert.orgimport re 355467Snate@binkert.org 365467Snate@binkert.orgpython_class_map = { 375467Snate@binkert.org "int": "Int", 385467Snate@binkert.org "NodeID": "Int", 395467Snate@binkert.org "uint32_t" : "UInt32", 405467Snate@binkert.org "std::string": "String", 415467Snate@binkert.org "bool": "Bool", 426654Snate@binkert.org "CacheMemory": "RubyCache", 436654Snate@binkert.org "WireBuffer": "RubyWireBuffer", 446654Snate@binkert.org "Sequencer": "RubySequencer", 456654Snate@binkert.org "GPUCoalescer" : "RubyGPUCoalescer", 466654Snate@binkert.org "VIPERCoalescer" : "VIPERCoalescer", 476654Snate@binkert.org "DirectoryMemory": "RubyDirectoryMemory", 486654Snate@binkert.org "PerfectCacheMemory": "RubyPerfectCacheMemory", 497459Snate@binkert.org "MemoryControl": "MemoryControl", 506502Snate@binkert.org "MessageBuffer": "MessageBuffer", 515467Snate@binkert.org "DMASequencer": "DMASequencer", 526500Snate@binkert.org "Prefetcher":"Prefetcher", 536654Snate@binkert.org "Cycles":"Cycles", 547503Snate@binkert.org } 555873Snate@binkert.org 566654Snate@binkert.orgclass StateMachine(Symbol): 576654Snate@binkert.org def __init__(self, symtab, ident, location, pairs, config_parameters): 586654Snate@binkert.org super(StateMachine, self).__init__(symtab, ident, location, pairs) 596654Snate@binkert.org self.table = None 606654Snate@binkert.org 616654Snate@binkert.org # Data members in the State Machine that have been declared before 626654Snate@binkert.org # the opening brace '{' of the machine. Note that these along with 636654Snate@binkert.org # the members in self.objects form the entire set of data members. 646654Snate@binkert.org self.config_parameters = config_parameters 656654Snate@binkert.org 666654Snate@binkert.org self.prefetchers = [] 676654Snate@binkert.org 686654Snate@binkert.org for param in config_parameters: 696654Snate@binkert.org if param.pointer: 709528Ssascha.bischoff@arm.com var = Var(symtab, param.ident, location, param.type_ast.type, 719528Ssascha.bischoff@arm.com "(*m_%s_ptr)" % param.ident, {}, self) 729528Ssascha.bischoff@arm.com else: 739528Ssascha.bischoff@arm.com var = Var(symtab, param.ident, location, param.type_ast.type, 749528Ssascha.bischoff@arm.com "m_%s" % param.ident, {}, self) 759528Ssascha.bischoff@arm.com 769528Ssascha.bischoff@arm.com self.symtab.registerSym(param.ident, var) 779528Ssascha.bischoff@arm.com 789528Ssascha.bischoff@arm.com if str(param.type_ast.type) == "Prefetcher": 799528Ssascha.bischoff@arm.com self.prefetchers.append(var) 809528Ssascha.bischoff@arm.com 816654Snate@binkert.org self.states = orderdict() 826654Snate@binkert.org self.events = orderdict() 836654Snate@binkert.org self.actions = orderdict() 846654Snate@binkert.org self.request_types = orderdict() 856654Snate@binkert.org self.transitions = [] 866654Snate@binkert.org self.in_ports = [] 876654Snate@binkert.org self.functions = [] 886654Snate@binkert.org 896654Snate@binkert.org # Data members in the State Machine that have been declared inside 906654Snate@binkert.org # the {} machine. Note that these along with the config params 916654Snate@binkert.org # form the entire set of data members of the machine. 926654Snate@binkert.org self.objects = [] 936654Snate@binkert.org self.TBEType = None 946654Snate@binkert.org self.EntryType = None 956654Snate@binkert.org self.debug_flags = set() 966654Snate@binkert.org self.debug_flags.add('RubyGenerated') 976654Snate@binkert.org self.debug_flags.add('RubySlicc') 986654Snate@binkert.org 996654Snate@binkert.org def __repr__(self): 1006654Snate@binkert.org return "[StateMachine: %s]" % self.ident 1016654Snate@binkert.org 1026654Snate@binkert.org def addState(self, state): 1036654Snate@binkert.org assert self.table is None 1046654Snate@binkert.org self.states[state.ident] = state 1056654Snate@binkert.org 1066654Snate@binkert.org def addEvent(self, event): 1076654Snate@binkert.org assert self.table is None 1086654Snate@binkert.org self.events[event.ident] = event 1096654Snate@binkert.org 1106654Snate@binkert.org def addAction(self, action): 1116654Snate@binkert.org assert self.table is None 1126654Snate@binkert.org 1136654Snate@binkert.org # Check for duplicate action 1146654Snate@binkert.org for other in self.actions.itervalues(): 1156654Snate@binkert.org if action.ident == other.ident: 1166654Snate@binkert.org action.warning("Duplicate action definition: %s" % action.ident) 1176654Snate@binkert.org action.error("Duplicate action definition: %s" % action.ident) 1186654Snate@binkert.org if action.short == other.short: 1196654Snate@binkert.org other.warning("Duplicate action shorthand: %s" % other.ident) 1206654Snate@binkert.org other.warning(" shorthand = %s" % other.short) 1216654Snate@binkert.org action.warning("Duplicate action shorthand: %s" % action.ident) 1226654Snate@binkert.org action.error(" shorthand = %s" % action.short) 1236654Snate@binkert.org 1246654Snate@binkert.org self.actions[action.ident] = action 1256654Snate@binkert.org 1266654Snate@binkert.org def addDebugFlag(self, flag): 1276654Snate@binkert.org self.debug_flags.add(flag) 1286654Snate@binkert.org 1296654Snate@binkert.org def addRequestType(self, request_type): 1306654Snate@binkert.org assert self.table is None 1316654Snate@binkert.org self.request_types[request_type.ident] = request_type 1326654Snate@binkert.org 1336654Snate@binkert.org def addTransition(self, trans): 1346654Snate@binkert.org assert self.table is None 1356654Snate@binkert.org self.transitions.append(trans) 1366654Snate@binkert.org 1376654Snate@binkert.org def addInPort(self, var): 1386654Snate@binkert.org self.in_ports.append(var) 1396654Snate@binkert.org 1406654Snate@binkert.org def addFunc(self, func): 1416654Snate@binkert.org # register func in the symbol table 1426654Snate@binkert.org self.symtab.registerSym(str(func), func) 1436654Snate@binkert.org self.functions.append(func) 1446654Snate@binkert.org 1456654Snate@binkert.org def addObject(self, obj): 1466654Snate@binkert.org self.symtab.registerSym(str(obj), obj) 1476654Snate@binkert.org self.objects.append(obj) 1486654Snate@binkert.org 1496654Snate@binkert.org def addType(self, type): 1506654Snate@binkert.org type_ident = '%s' % type.c_ident 1516654Snate@binkert.org 1526654Snate@binkert.org if type_ident == "%s_TBE" %self.ident: 1536654Snate@binkert.org if self.TBEType != None: 1546654Snate@binkert.org self.error("Multiple Transaction Buffer types in a " \ 1556654Snate@binkert.org "single machine."); 1566654Snate@binkert.org self.TBEType = type 1576654Snate@binkert.org 1586654Snate@binkert.org elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 1596654Snate@binkert.org if "main" in type and "false" == type["main"].lower(): 1606654Snate@binkert.org pass # this isn't the EntryType 1616654Snate@binkert.org else: 1626654Snate@binkert.org if self.EntryType != None: 1636654Snate@binkert.org self.error("Multiple AbstractCacheEntry types in a " \ 1646654Snate@binkert.org "single machine."); 1656654Snate@binkert.org self.EntryType = type 1665873Snate@binkert.org 1675873Snate@binkert.org # Needs to be called before accessing the table 1685873Snate@binkert.org def buildTable(self): 1695873Snate@binkert.org assert self.table is None 1705873Snate@binkert.org 1715873Snate@binkert.org table = {} 1725873Snate@binkert.org 1735873Snate@binkert.org for trans in self.transitions: 1745873Snate@binkert.org # Track which actions we touch so we know if we use them 1755873Snate@binkert.org # all -- really this should be done for all symbols as 1765873Snate@binkert.org # part of the symbol table, then only trigger it for 1776654Snate@binkert.org # Actions, States, Events, etc. 1786654Snate@binkert.org 1796654Snate@binkert.org for action in trans.actions: 1806654Snate@binkert.org action.used = True 1816654Snate@binkert.org 1826654Snate@binkert.org index = (trans.state, trans.event) 1836654Snate@binkert.org if index in table: 1846654Snate@binkert.org table[index].warning("Duplicate transition: %s" % table[index]) 1856654Snate@binkert.org trans.error("Duplicate transition: %s" % trans) 1866654Snate@binkert.org table[index] = trans 1876654Snate@binkert.org 18811320Ssteve.reinhardt@amd.com # Look at all actions to make sure we used them all 1896654Snate@binkert.org for action in self.actions.itervalues(): 1906654Snate@binkert.org if not action.used: 1916654Snate@binkert.org error_msg = "Unused action: %s" % action.ident 1926654Snate@binkert.org if "desc" in action: 1936654Snate@binkert.org error_msg += ", " + action.desc 1946654Snate@binkert.org action.warning(error_msg) 1956654Snate@binkert.org self.table = table 1966654Snate@binkert.org 1976654Snate@binkert.org # determine the port->msg buffer mappings 1986654Snate@binkert.org def getBufferMaps(self, ident): 1996654Snate@binkert.org msg_bufs = [] 2006654Snate@binkert.org port_to_buf_map = {} 2018453Snate@binkert.org in_msg_bufs = {} 2028453Snate@binkert.org for port in self.in_ports: 2038453Snate@binkert.org buf_name = "m_%s_ptr" % port.pairs["buffer_expr"].name 2048453Snate@binkert.org msg_bufs.append(buf_name) 2058453Snate@binkert.org port_to_buf_map[port] = msg_bufs.index(buf_name) 2068453Snate@binkert.org if buf_name not in in_msg_bufs: 2078453Snate@binkert.org in_msg_bufs[buf_name] = [port] 2088453Snate@binkert.org else: 2098453Snate@binkert.org in_msg_bufs[buf_name].append(port) 21011923Sandreas.sandberg@arm.com return port_to_buf_map, in_msg_bufs, msg_bufs 21111923Sandreas.sandberg@arm.com 21211923Sandreas.sandberg@arm.com def writeCodeFiles(self, path, includes): 21311923Sandreas.sandberg@arm.com self.printControllerPython(path) 21411923Sandreas.sandberg@arm.com self.printControllerHH(path) 215 self.printControllerCC(path, includes) 216 self.printCSwitch(path) 217 self.printCWakeup(path, includes) 218 219 def printControllerPython(self, path): 220 code = self.symtab.codeFormatter() 221 ident = self.ident 222 223 py_ident = "%s_Controller" % ident 224 c_ident = "%s_Controller" % self.ident 225 226 code(''' 227from m5.params import * 228from m5.SimObject import SimObject 229from Controller import RubyController 230 231class $py_ident(RubyController): 232 type = '$py_ident' 233 cxx_header = 'mem/protocol/${c_ident}.hh' 234''') 235 code.indent() 236 for param in self.config_parameters: 237 dflt_str = '' 238 239 if param.rvalue is not None: 240 dflt_str = str(param.rvalue.inline()) + ', ' 241 242 if python_class_map.has_key(param.type_ast.type.c_ident): 243 python_type = python_class_map[param.type_ast.type.c_ident] 244 code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")') 245 246 else: 247 self.error("Unknown c++ to python class conversion for c++ " \ 248 "type: '%s'. Please update the python_class_map " \ 249 "in StateMachine.py", param.type_ast.type.c_ident) 250 251 code.dedent() 252 code.write(path, '%s.py' % py_ident) 253 254 255 def printControllerHH(self, path): 256 '''Output the method declarations for the class declaration''' 257 code = self.symtab.codeFormatter() 258 ident = self.ident 259 c_ident = "%s_Controller" % self.ident 260 261 code(''' 262/** \\file $c_ident.hh 263 * 264 * Auto generated C++ code started by $__file__:$__line__ 265 * Created by slicc definition of Module "${{self.short}}" 266 */ 267 268#ifndef __${ident}_CONTROLLER_HH__ 269#define __${ident}_CONTROLLER_HH__ 270 271#include <iostream> 272#include <sstream> 273#include <string> 274 275#include "mem/protocol/TransitionResult.hh" 276#include "mem/protocol/Types.hh" 277#include "mem/ruby/common/Consumer.hh" 278#include "mem/ruby/slicc_interface/AbstractController.hh" 279#include "params/$c_ident.hh" 280 281''') 282 283 seen_types = set() 284 for var in self.objects: 285 if var.type.ident not in seen_types and not var.type.isPrimitive: 286 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 287 seen_types.add(var.type.ident) 288 289 # for adding information to the protocol debug trace 290 code(''' 291extern std::stringstream ${ident}_transitionComment; 292 293class $c_ident : public AbstractController 294{ 295 public: 296 typedef ${c_ident}Params Params; 297 $c_ident(const Params *p); 298 static int getNumControllers(); 299 void init(); 300 301 MessageBuffer *getMandatoryQueue() const; 302 MessageBuffer *getMemoryQueue() const; 303 void initNetQueues(); 304 305 void print(std::ostream& out) const; 306 void wakeup(); 307 void resetStats(); 308 void regStats(); 309 void collateStats(); 310 311 void recordCacheTrace(int cntrl, CacheRecorder* tr); 312 Sequencer* getCPUSequencer() const; 313 314 int functionalWriteBuffers(PacketPtr&); 315 316 void countTransition(${ident}_State state, ${ident}_Event event); 317 void possibleTransition(${ident}_State state, ${ident}_Event event); 318 uint64_t getEventCount(${ident}_Event event); 319 bool isPossible(${ident}_State state, ${ident}_Event event); 320 uint64_t getTransitionCount(${ident}_State state, ${ident}_Event event); 321 322private: 323''') 324 325 code.indent() 326 # added by SS 327 for param in self.config_parameters: 328 if param.pointer: 329 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 330 else: 331 code('${{param.type_ast.type}} m_${{param.ident}};') 332 333 code(''' 334TransitionResult doTransition(${ident}_Event event, 335''') 336 337 if self.EntryType != None: 338 code(''' 339 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 340''') 341 if self.TBEType != None: 342 code(''' 343 ${{self.TBEType.c_ident}}* m_tbe_ptr, 344''') 345 346 code(''' 347 Addr addr); 348 349TransitionResult doTransitionWorker(${ident}_Event event, 350 ${ident}_State state, 351 ${ident}_State& next_state, 352''') 353 354 if self.TBEType != None: 355 code(''' 356 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 357''') 358 if self.EntryType != None: 359 code(''' 360 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 361''') 362 363 code(''' 364 Addr addr); 365 366int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 367int m_event_counters[${ident}_Event_NUM]; 368bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 369 370static std::vector<Stats::Vector *> eventVec; 371static std::vector<std::vector<Stats::Vector *> > transVec; 372static int m_num_controllers; 373 374// Internal functions 375''') 376 377 for func in self.functions: 378 proto = func.prototype 379 if proto: 380 code('$proto') 381 382 if self.EntryType != None: 383 code(''' 384 385// Set and Reset for cache_entry variable 386void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 387void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 388''') 389 390 if self.TBEType != None: 391 code(''' 392 393// Set and Reset for tbe variable 394void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 395void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 396''') 397 398 # Prototype the actions that the controller can take 399 code(''' 400 401// Actions 402''') 403 if self.TBEType != None and self.EntryType != None: 404 for action in self.actions.itervalues(): 405 code('/** \\brief ${{action.desc}} */') 406 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 407 'm_tbe_ptr, ${{self.EntryType.c_ident}}*& ' 408 'm_cache_entry_ptr, Addr addr);') 409 elif self.TBEType != None: 410 for action in self.actions.itervalues(): 411 code('/** \\brief ${{action.desc}} */') 412 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 413 'm_tbe_ptr, Addr addr);') 414 elif self.EntryType != None: 415 for action in self.actions.itervalues(): 416 code('/** \\brief ${{action.desc}} */') 417 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& ' 418 'm_cache_entry_ptr, Addr addr);') 419 else: 420 for action in self.actions.itervalues(): 421 code('/** \\brief ${{action.desc}} */') 422 code('void ${{action.ident}}(Addr addr);') 423 424 # the controller internal variables 425 code(''' 426 427// Objects 428''') 429 for var in self.objects: 430 th = var.get("template", "") 431 code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;') 432 433 code.dedent() 434 code('};') 435 code('#endif // __${ident}_CONTROLLER_H__') 436 code.write(path, '%s.hh' % c_ident) 437 438 def printControllerCC(self, path, includes): 439 '''Output the actions for performing the actions''' 440 441 code = self.symtab.codeFormatter() 442 ident = self.ident 443 c_ident = "%s_Controller" % self.ident 444 445 code(''' 446/** \\file $c_ident.cc 447 * 448 * Auto generated C++ code started by $__file__:$__line__ 449 * Created by slicc definition of Module "${{self.short}}" 450 */ 451 452#include <sys/types.h> 453#include <unistd.h> 454 455#include <cassert> 456#include <sstream> 457#include <string> 458#include <typeinfo> 459 460#include "base/compiler.hh" 461#include "base/cprintf.hh" 462 463''') 464 for f in self.debug_flags: 465 code('#include "debug/${{f}}.hh"') 466 code(''' 467#include "mem/protocol/${ident}_Controller.hh" 468#include "mem/protocol/${ident}_Event.hh" 469#include "mem/protocol/${ident}_State.hh" 470#include "mem/protocol/Types.hh" 471#include "mem/ruby/system/RubySystem.hh" 472 473''') 474 for include_path in includes: 475 code('#include "${{include_path}}"') 476 477 code(''' 478 479using namespace std; 480''') 481 482 # include object classes 483 seen_types = set() 484 for var in self.objects: 485 if var.type.ident not in seen_types and not var.type.isPrimitive: 486 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 487 seen_types.add(var.type.ident) 488 489 num_in_ports = len(self.in_ports) 490 491 code(''' 492$c_ident * 493${c_ident}Params::create() 494{ 495 return new $c_ident(this); 496} 497 498int $c_ident::m_num_controllers = 0; 499std::vector<Stats::Vector *> $c_ident::eventVec; 500std::vector<std::vector<Stats::Vector *> > $c_ident::transVec; 501 502// for adding information to the protocol debug trace 503stringstream ${ident}_transitionComment; 504 505#ifndef NDEBUG 506#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 507#else 508#define APPEND_TRANSITION_COMMENT(str) do {} while (0) 509#endif 510 511/** \\brief constructor */ 512$c_ident::$c_ident(const Params *p) 513 : AbstractController(p) 514{ 515 m_machineID.type = MachineType_${ident}; 516 m_machineID.num = m_version; 517 m_num_controllers++; 518 519 m_in_ports = $num_in_ports; 520''') 521 code.indent() 522 523 # 524 # After initializing the universal machine parameters, initialize the 525 # this machines config parameters. Also if these configuration params 526 # include a sequencer, connect the it to the controller. 527 # 528 for param in self.config_parameters: 529 if param.pointer: 530 code('m_${{param.ident}}_ptr = p->${{param.ident}};') 531 else: 532 code('m_${{param.ident}} = p->${{param.ident}};') 533 534 if re.compile("sequencer").search(param.ident) or \ 535 param.type_ast.type.c_ident == "GPUCoalescer" or \ 536 param.type_ast.type.c_ident == "VIPERCoalescer": 537 code(''' 538if (m_${{param.ident}}_ptr != NULL) { 539 m_${{param.ident}}_ptr->setController(this); 540} 541''') 542 543 code(''' 544 545for (int state = 0; state < ${ident}_State_NUM; state++) { 546 for (int event = 0; event < ${ident}_Event_NUM; event++) { 547 m_possible[state][event] = false; 548 m_counters[state][event] = 0; 549 } 550} 551for (int event = 0; event < ${ident}_Event_NUM; event++) { 552 m_event_counters[event] = 0; 553} 554''') 555 code.dedent() 556 code(''' 557} 558 559void 560$c_ident::initNetQueues() 561{ 562 MachineType machine_type = string_to_MachineType("${{self.ident}}"); 563 int base M5_VAR_USED = MachineType_base_number(machine_type); 564 565''') 566 code.indent() 567 568 # set for maintaining the vnet, direction pairs already seen for this 569 # machine. This map helps in implementing the check for avoiding 570 # multiple message buffers being mapped to the same vnet. 571 vnet_dir_set = set() 572 573 for var in self.config_parameters: 574 vid = "m_%s_ptr" % var.ident 575 if "network" in var: 576 vtype = var.type_ast.type 577 code('assert($vid != NULL);') 578 579 # Network port object 580 network = var["network"] 581 582 if "virtual_network" in var: 583 vnet = var["virtual_network"] 584 vnet_type = var["vnet_type"] 585 586 assert (vnet, network) not in vnet_dir_set 587 vnet_dir_set.add((vnet,network)) 588 589 code(''' 590m_net_ptr->set${network}NetQueue(m_version + base, $vid->getOrdered(), $vnet, 591 "$vnet_type", $vid); 592''') 593 # Set Priority 594 if "rank" in var: 595 code('$vid->setPriority(${{var["rank"]}})') 596 597 code.dedent() 598 code(''' 599} 600 601void 602$c_ident::init() 603{ 604 // initialize objects 605''') 606 607 code.indent() 608 609 for var in self.objects: 610 vtype = var.type 611 vid = "m_%s_ptr" % var.ident 612 if "network" not in var: 613 # Not a network port object 614 if "primitive" in vtype: 615 code('$vid = new ${{vtype.c_ident}};') 616 if "default" in var: 617 code('(*$vid) = ${{var["default"]}};') 618 else: 619 # Normal Object 620 th = var.get("template", "") 621 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 622 args = "" 623 if "non_obj" not in vtype and not vtype.isEnumeration: 624 args = var.get("constructor", "") 625 626 code('$expr($args);') 627 code('assert($vid != NULL);') 628 629 if "default" in var: 630 code('*$vid = ${{var["default"]}}; // Object default') 631 elif "default" in vtype: 632 comment = "Type %s default" % vtype.ident 633 code('*$vid = ${{vtype["default"]}}; // $comment') 634 635 # Set the prefetchers 636 code() 637 for prefetcher in self.prefetchers: 638 code('${{prefetcher.code}}.setController(this);') 639 640 code() 641 for port in self.in_ports: 642 # Set the queue consumers 643 code('${{port.code}}.setConsumer(this);') 644 645 # Initialize the transition profiling 646 code() 647 for trans in self.transitions: 648 # Figure out if we stall 649 stall = False 650 for action in trans.actions: 651 if action.ident == "z_stall": 652 stall = True 653 654 # Only possible if it is not a 'z' case 655 if not stall: 656 state = "%s_State_%s" % (self.ident, trans.state.ident) 657 event = "%s_Event_%s" % (self.ident, trans.event.ident) 658 code('possibleTransition($state, $event);') 659 660 code.dedent() 661 code(''' 662 AbstractController::init(); 663 resetStats(); 664} 665''') 666 667 mq_ident = "NULL" 668 for port in self.in_ports: 669 if port.code.find("mandatoryQueue_ptr") >= 0: 670 mq_ident = "m_mandatoryQueue_ptr" 671 672 memq_ident = "NULL" 673 for port in self.in_ports: 674 if port.code.find("responseFromMemory_ptr") >= 0: 675 memq_ident = "m_responseFromMemory_ptr" 676 677 seq_ident = "NULL" 678 for param in self.config_parameters: 679 if param.ident == "sequencer": 680 assert(param.pointer) 681 seq_ident = "m_%s_ptr" % param.ident 682 683 if seq_ident != "NULL": 684 code(''' 685Sequencer* 686$c_ident::getCPUSequencer() const 687{ 688 if (NULL != $seq_ident && $seq_ident->isCPUSequencer()) { 689 return $seq_ident; 690 } else { 691 return NULL; 692 } 693} 694''') 695 else: 696 code(''' 697 698Sequencer* 699$c_ident::getCPUSequencer() const 700{ 701 return NULL; 702} 703''') 704 705 code(''' 706 707void 708$c_ident::regStats() 709{ 710 AbstractController::regStats(); 711 712 if (m_version == 0) { 713 for (${ident}_Event event = ${ident}_Event_FIRST; 714 event < ${ident}_Event_NUM; ++event) { 715 Stats::Vector *t = new Stats::Vector(); 716 t->init(m_num_controllers); 717 t->name(params()->ruby_system->name() + ".${c_ident}." + 718 ${ident}_Event_to_string(event)); 719 t->flags(Stats::pdf | Stats::total | Stats::oneline | 720 Stats::nozero); 721 722 eventVec.push_back(t); 723 } 724 725 for (${ident}_State state = ${ident}_State_FIRST; 726 state < ${ident}_State_NUM; ++state) { 727 728 transVec.push_back(std::vector<Stats::Vector *>()); 729 730 for (${ident}_Event event = ${ident}_Event_FIRST; 731 event < ${ident}_Event_NUM; ++event) { 732 733 Stats::Vector *t = new Stats::Vector(); 734 t->init(m_num_controllers); 735 t->name(params()->ruby_system->name() + ".${c_ident}." + 736 ${ident}_State_to_string(state) + 737 "." + ${ident}_Event_to_string(event)); 738 739 t->flags(Stats::pdf | Stats::total | Stats::oneline | 740 Stats::nozero); 741 transVec[state].push_back(t); 742 } 743 } 744 } 745} 746 747void 748$c_ident::collateStats() 749{ 750 for (${ident}_Event event = ${ident}_Event_FIRST; 751 event < ${ident}_Event_NUM; ++event) { 752 for (unsigned int i = 0; i < m_num_controllers; ++i) { 753 RubySystem *rs = params()->ruby_system; 754 std::map<uint32_t, AbstractController *>::iterator it = 755 rs->m_abstract_controls[MachineType_${ident}].find(i); 756 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 757 (*eventVec[event])[i] = 758 (($c_ident *)(*it).second)->getEventCount(event); 759 } 760 } 761 762 for (${ident}_State state = ${ident}_State_FIRST; 763 state < ${ident}_State_NUM; ++state) { 764 765 for (${ident}_Event event = ${ident}_Event_FIRST; 766 event < ${ident}_Event_NUM; ++event) { 767 768 for (unsigned int i = 0; i < m_num_controllers; ++i) { 769 RubySystem *rs = params()->ruby_system; 770 std::map<uint32_t, AbstractController *>::iterator it = 771 rs->m_abstract_controls[MachineType_${ident}].find(i); 772 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 773 (*transVec[state][event])[i] = 774 (($c_ident *)(*it).second)->getTransitionCount(state, event); 775 } 776 } 777 } 778} 779 780void 781$c_ident::countTransition(${ident}_State state, ${ident}_Event event) 782{ 783 assert(m_possible[state][event]); 784 m_counters[state][event]++; 785 m_event_counters[event]++; 786} 787void 788$c_ident::possibleTransition(${ident}_State state, 789 ${ident}_Event event) 790{ 791 m_possible[state][event] = true; 792} 793 794uint64_t 795$c_ident::getEventCount(${ident}_Event event) 796{ 797 return m_event_counters[event]; 798} 799 800bool 801$c_ident::isPossible(${ident}_State state, ${ident}_Event event) 802{ 803 return m_possible[state][event]; 804} 805 806uint64_t 807$c_ident::getTransitionCount(${ident}_State state, 808 ${ident}_Event event) 809{ 810 return m_counters[state][event]; 811} 812 813int 814$c_ident::getNumControllers() 815{ 816 return m_num_controllers; 817} 818 819MessageBuffer* 820$c_ident::getMandatoryQueue() const 821{ 822 return $mq_ident; 823} 824 825MessageBuffer* 826$c_ident::getMemoryQueue() const 827{ 828 return $memq_ident; 829} 830 831void 832$c_ident::print(ostream& out) const 833{ 834 out << "[$c_ident " << m_version << "]"; 835} 836 837void $c_ident::resetStats() 838{ 839 for (int state = 0; state < ${ident}_State_NUM; state++) { 840 for (int event = 0; event < ${ident}_Event_NUM; event++) { 841 m_counters[state][event] = 0; 842 } 843 } 844 845 for (int event = 0; event < ${ident}_Event_NUM; event++) { 846 m_event_counters[event] = 0; 847 } 848 849 AbstractController::resetStats(); 850} 851''') 852 853 if self.EntryType != None: 854 code(''' 855 856// Set and Reset for cache_entry variable 857void 858$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 859{ 860 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 861} 862 863void 864$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 865{ 866 m_cache_entry_ptr = 0; 867} 868''') 869 870 if self.TBEType != None: 871 code(''' 872 873// Set and Reset for tbe variable 874void 875$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 876{ 877 m_tbe_ptr = m_new_tbe; 878} 879 880void 881$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 882{ 883 m_tbe_ptr = NULL; 884} 885''') 886 887 code(''' 888 889void 890$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 891{ 892''') 893 # 894 # Record cache contents for all associated caches. 895 # 896 code.indent() 897 for param in self.config_parameters: 898 if param.type_ast.type.ident == "CacheMemory": 899 assert(param.pointer) 900 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 901 902 code.dedent() 903 code(''' 904} 905 906// Actions 907''') 908 if self.TBEType != None and self.EntryType != 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, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 917{ 918 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 919 try { 920 ${{action["c_code"]}} 921 } catch (const RejectException & e) { 922 fatal("Error in action ${{ident}}:${{action.ident}}: " 923 "executed a peek statement with the wrong message " 924 "type specified. "); 925 } 926} 927 928''') 929 elif self.TBEType != None: 930 for action in self.actions.itervalues(): 931 if "c_code" not in action: 932 continue 933 934 code(''' 935/** \\brief ${{action.desc}} */ 936void 937$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, Addr addr) 938{ 939 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 940 ${{action["c_code"]}} 941} 942 943''') 944 elif self.EntryType != None: 945 for action in self.actions.itervalues(): 946 if "c_code" not in action: 947 continue 948 949 code(''' 950/** \\brief ${{action.desc}} */ 951void 952$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 953{ 954 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 955 ${{action["c_code"]}} 956} 957 958''') 959 else: 960 for action in self.actions.itervalues(): 961 if "c_code" not in action: 962 continue 963 964 code(''' 965/** \\brief ${{action.desc}} */ 966void 967$c_ident::${{action.ident}}(Addr addr) 968{ 969 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 970 ${{action["c_code"]}} 971} 972 973''') 974 for func in self.functions: 975 code(func.generateCode()) 976 977 # Function for functional writes to messages buffered in the controller 978 code(''' 979int 980$c_ident::functionalWriteBuffers(PacketPtr& pkt) 981{ 982 int num_functional_writes = 0; 983''') 984 for var in self.objects: 985 vtype = var.type 986 if vtype.isBuffer: 987 vid = "m_%s_ptr" % var.ident 988 code('num_functional_writes += $vid->functionalWrite(pkt);') 989 990 for var in self.config_parameters: 991 vtype = var.type_ast.type 992 if vtype.isBuffer: 993 vid = "m_%s_ptr" % var.ident 994 code('num_functional_writes += $vid->functionalWrite(pkt);') 995 996 code(''' 997 return num_functional_writes; 998} 999''') 1000 1001 code.write(path, "%s.cc" % c_ident) 1002 1003 def printCWakeup(self, path, includes): 1004 '''Output the wakeup loop for the events''' 1005 1006 code = self.symtab.codeFormatter() 1007 ident = self.ident 1008 1009 outputRequest_types = True 1010 if len(self.request_types) == 0: 1011 outputRequest_types = False 1012 1013 code(''' 1014// Auto generated C++ code started by $__file__:$__line__ 1015// ${ident}: ${{self.short}} 1016 1017#include <sys/types.h> 1018#include <unistd.h> 1019 1020#include <cassert> 1021#include <typeinfo> 1022 1023#include "base/misc.hh" 1024 1025''') 1026 for f in self.debug_flags: 1027 code('#include "debug/${{f}}.hh"') 1028 code(''' 1029#include "mem/protocol/${ident}_Controller.hh" 1030#include "mem/protocol/${ident}_Event.hh" 1031#include "mem/protocol/${ident}_State.hh" 1032 1033''') 1034 1035 if outputRequest_types: 1036 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1037 1038 code(''' 1039#include "mem/protocol/Types.hh" 1040#include "mem/ruby/system/RubySystem.hh" 1041 1042''') 1043 1044 1045 for include_path in includes: 1046 code('#include "${{include_path}}"') 1047 1048 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1049 1050 code(''' 1051 1052using namespace std; 1053 1054void 1055${ident}_Controller::wakeup() 1056{ 1057 int counter = 0; 1058 while (true) { 1059 unsigned char rejected[${{len(msg_bufs)}}]; 1060 memset(rejected, 0, sizeof(unsigned char)*${{len(msg_bufs)}}); 1061 // Some cases will put us into an infinite loop without this limit 1062 assert(counter <= m_transitions_per_cycle); 1063 if (counter == m_transitions_per_cycle) { 1064 // Count how often we are fully utilized 1065 m_fully_busy_cycles++; 1066 1067 // Wakeup in another cycle and try again 1068 scheduleEvent(Cycles(1)); 1069 break; 1070 } 1071''') 1072 1073 code.indent() 1074 code.indent() 1075 1076 # InPorts 1077 # 1078 for port in self.in_ports: 1079 code.indent() 1080 code('// ${ident}InPort $port') 1081 if port.pairs.has_key("rank"): 1082 code('m_cur_in_port = ${{port.pairs["rank"]}};') 1083 else: 1084 code('m_cur_in_port = 0;') 1085 if port in port_to_buf_map: 1086 code('try {') 1087 code.indent() 1088 code('${{port["c_code_in_port"]}}') 1089 1090 if port in port_to_buf_map: 1091 code.dedent() 1092 code(''' 1093 } catch (const RejectException & e) { 1094 rejected[${{port_to_buf_map[port]}}]++; 1095 } 1096''') 1097 code.dedent() 1098 code('') 1099 1100 code.dedent() 1101 code.dedent() 1102 code(''' 1103 // If we got this far, we have nothing left todo or something went 1104 // wrong''') 1105 for buf_name, ports in in_msg_bufs.items(): 1106 if len(ports) > 1: 1107 # only produce checks when a buffer is shared by multiple ports 1108 code(''' 1109 if (${{buf_name}}->isReady(clockEdge()) && rejected[${{port_to_buf_map[ports[0]]}}] == ${{len(ports)}}) 1110 { 1111 // no port claimed the message on the top of this buffer 1112 panic("Runtime Error at Ruby Time: %d. " 1113 "All ports rejected a message. " 1114 "You are probably sending a message type to this controller " 1115 "over a virtual network that do not define an in_port for " 1116 "the incoming message type.\\n", 1117 Cycles(1)); 1118 } 1119''') 1120 code(''' 1121 break; 1122 } 1123} 1124''') 1125 1126 code.write(path, "%s_Wakeup.cc" % self.ident) 1127 1128 def printCSwitch(self, path): 1129 '''Output switch statement for transition table''' 1130 1131 code = self.symtab.codeFormatter() 1132 ident = self.ident 1133 1134 code(''' 1135// Auto generated C++ code started by $__file__:$__line__ 1136// ${ident}: ${{self.short}} 1137 1138#include <cassert> 1139 1140#include "base/misc.hh" 1141#include "base/trace.hh" 1142#include "debug/ProtocolTrace.hh" 1143#include "debug/RubyGenerated.hh" 1144#include "mem/protocol/${ident}_Controller.hh" 1145#include "mem/protocol/${ident}_Event.hh" 1146#include "mem/protocol/${ident}_State.hh" 1147#include "mem/protocol/Types.hh" 1148#include "mem/ruby/system/RubySystem.hh" 1149 1150#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1151 1152#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1153#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1154 1155TransitionResult 1156${ident}_Controller::doTransition(${ident}_Event event, 1157''') 1158 if self.EntryType != None: 1159 code(''' 1160 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1161''') 1162 if self.TBEType != None: 1163 code(''' 1164 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1165''') 1166 code(''' 1167 Addr addr) 1168{ 1169''') 1170 code.indent() 1171 1172 if self.TBEType != None and self.EntryType != None: 1173 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1174 elif self.TBEType != None: 1175 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1176 elif self.EntryType != None: 1177 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1178 else: 1179 code('${ident}_State state = getState(addr);') 1180 1181 code(''' 1182${ident}_State next_state = state; 1183 1184DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %#x\\n", 1185 *this, curCycle(), ${ident}_State_to_string(state), 1186 ${ident}_Event_to_string(event), addr); 1187 1188TransitionResult result = 1189''') 1190 if self.TBEType != None and self.EntryType != None: 1191 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1192 elif self.TBEType != None: 1193 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1194 elif self.EntryType != None: 1195 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1196 else: 1197 code('doTransitionWorker(event, state, next_state, addr);') 1198 1199 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1200 1201 code(''' 1202 1203if (result == TransitionResult_Valid) { 1204 DPRINTF(RubyGenerated, "next_state: %s\\n", 1205 ${ident}_State_to_string(next_state)); 1206 countTransition(state, event); 1207 1208 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %#x %s\\n", 1209 curTick(), m_version, "${ident}", 1210 ${ident}_Event_to_string(event), 1211 ${ident}_State_to_string(state), 1212 ${ident}_State_to_string(next_state), 1213 printAddress(addr), GET_TRANSITION_COMMENT()); 1214 1215 CLEAR_TRANSITION_COMMENT(); 1216''') 1217 if self.TBEType != None and self.EntryType != None: 1218 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1219 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1220 elif self.TBEType != None: 1221 code('setState(m_tbe_ptr, addr, next_state);') 1222 code('setAccessPermission(addr, next_state);') 1223 elif self.EntryType != None: 1224 code('setState(m_cache_entry_ptr, addr, next_state);') 1225 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1226 else: 1227 code('setState(addr, next_state);') 1228 code('setAccessPermission(addr, next_state);') 1229 1230 code(''' 1231} else if (result == TransitionResult_ResourceStall) { 1232 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1233 curTick(), m_version, "${ident}", 1234 ${ident}_Event_to_string(event), 1235 ${ident}_State_to_string(state), 1236 ${ident}_State_to_string(next_state), 1237 printAddress(addr), "Resource Stall"); 1238} else if (result == TransitionResult_ProtocolStall) { 1239 DPRINTF(RubyGenerated, "stalling\\n"); 1240 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1241 curTick(), m_version, "${ident}", 1242 ${ident}_Event_to_string(event), 1243 ${ident}_State_to_string(state), 1244 ${ident}_State_to_string(next_state), 1245 printAddress(addr), "Protocol Stall"); 1246} 1247 1248return result; 1249''') 1250 code.dedent() 1251 code(''' 1252} 1253 1254TransitionResult 1255${ident}_Controller::doTransitionWorker(${ident}_Event event, 1256 ${ident}_State state, 1257 ${ident}_State& next_state, 1258''') 1259 1260 if self.TBEType != None: 1261 code(''' 1262 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1263''') 1264 if self.EntryType != None: 1265 code(''' 1266 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1267''') 1268 code(''' 1269 Addr addr) 1270{ 1271 switch(HASH_FUN(state, event)) { 1272''') 1273 1274 # This map will allow suppress generating duplicate code 1275 cases = orderdict() 1276 1277 for trans in self.transitions: 1278 case_string = "%s_State_%s, %s_Event_%s" % \ 1279 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1280 1281 case = self.symtab.codeFormatter() 1282 # Only set next_state if it changes 1283 if trans.state != trans.nextState: 1284 if trans.nextState.isWildcard(): 1285 # When * is encountered as an end state of a transition, 1286 # the next state is determined by calling the 1287 # machine-specific getNextState function. The next state 1288 # is determined before any actions of the transition 1289 # execute, and therefore the next state calculation cannot 1290 # depend on any of the transitionactions. 1291 case('next_state = getNextState(addr);') 1292 else: 1293 ns_ident = trans.nextState.ident 1294 case('next_state = ${ident}_State_${ns_ident};') 1295 1296 actions = trans.actions 1297 request_types = trans.request_types 1298 1299 # Check for resources 1300 case_sorter = [] 1301 res = trans.resources 1302 for key,val in res.iteritems(): 1303 val = ''' 1304if (!%s.areNSlotsAvailable(%s, clockEdge())) 1305 return TransitionResult_ResourceStall; 1306''' % (key.code, val) 1307 case_sorter.append(val) 1308 1309 # Check all of the request_types for resource constraints 1310 for request_type in request_types: 1311 val = ''' 1312if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1313 return TransitionResult_ResourceStall; 1314} 1315''' % (self.ident, request_type.ident) 1316 case_sorter.append(val) 1317 1318 # Emit the code sequences in a sorted order. This makes the 1319 # output deterministic (without this the output order can vary 1320 # since Map's keys() on a vector of pointers is not deterministic 1321 for c in sorted(case_sorter): 1322 case("$c") 1323 1324 # Record access types for this transition 1325 for request_type in request_types: 1326 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1327 1328 # Figure out if we stall 1329 stall = False 1330 for action in actions: 1331 if action.ident == "z_stall": 1332 stall = True 1333 break 1334 1335 if stall: 1336 case('return TransitionResult_ProtocolStall;') 1337 else: 1338 if self.TBEType != None and self.EntryType != None: 1339 for action in actions: 1340 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1341 elif self.TBEType != None: 1342 for action in actions: 1343 case('${{action.ident}}(m_tbe_ptr, addr);') 1344 elif self.EntryType != None: 1345 for action in actions: 1346 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1347 else: 1348 for action in actions: 1349 case('${{action.ident}}(addr);') 1350 case('return TransitionResult_Valid;') 1351 1352 case = str(case) 1353 1354 # Look to see if this transition code is unique. 1355 if case not in cases: 1356 cases[case] = [] 1357 1358 cases[case].append(case_string) 1359 1360 # Walk through all of the unique code blocks and spit out the 1361 # corresponding case statement elements 1362 for case,transitions in cases.iteritems(): 1363 # Iterative over all the multiple transitions that share 1364 # the same code 1365 for trans in transitions: 1366 code(' case HASH_FUN($trans):') 1367 code(' $case\n') 1368 1369 code(''' 1370 default: 1371 panic("Invalid transition\\n" 1372 "%s time: %d addr: %s event: %s state: %s\\n", 1373 name(), curCycle(), addr, event, state); 1374 } 1375 1376 return TransitionResult_Valid; 1377} 1378''') 1379 code.write(path, "%s_Transitions.cc" % self.ident) 1380 1381 1382 # ************************** 1383 # ******* HTML Files ******* 1384 # ************************** 1385 def frameRef(self, click_href, click_target, over_href, over_num, text): 1386 code = self.symtab.codeFormatter(fix_newlines=False) 1387 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1388 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1389 parent.frames[$over_num].location='$over_href' 1390 }\"> 1391 ${{html.formatShorthand(text)}} 1392 </A>""") 1393 return str(code) 1394 1395 def writeHTMLFiles(self, path): 1396 # Create table with no row hilighted 1397 self.printHTMLTransitions(path, None) 1398 1399 # Generate transition tables 1400 for state in self.states.itervalues(): 1401 self.printHTMLTransitions(path, state) 1402 1403 # Generate action descriptions 1404 for action in self.actions.itervalues(): 1405 name = "%s_action_%s.html" % (self.ident, action.ident) 1406 code = html.createSymbol(action, "Action") 1407 code.write(path, name) 1408 1409 # Generate state descriptions 1410 for state in self.states.itervalues(): 1411 name = "%s_State_%s.html" % (self.ident, state.ident) 1412 code = html.createSymbol(state, "State") 1413 code.write(path, name) 1414 1415 # Generate event descriptions 1416 for event in self.events.itervalues(): 1417 name = "%s_Event_%s.html" % (self.ident, event.ident) 1418 code = html.createSymbol(event, "Event") 1419 code.write(path, name) 1420 1421 def printHTMLTransitions(self, path, active_state): 1422 code = self.symtab.codeFormatter() 1423 1424 code(''' 1425<HTML> 1426<BODY link="blue" vlink="blue"> 1427 1428<H1 align="center">${{html.formatShorthand(self.short)}}: 1429''') 1430 code.indent() 1431 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1432 mid = machine.ident 1433 if i != 0: 1434 extra = " - " 1435 else: 1436 extra = "" 1437 if machine == self: 1438 code('$extra$mid') 1439 else: 1440 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1441 code.dedent() 1442 1443 code(""" 1444</H1> 1445 1446<TABLE border=1> 1447<TR> 1448 <TH> </TH> 1449""") 1450 1451 for event in self.events.itervalues(): 1452 href = "%s_Event_%s.html" % (self.ident, event.ident) 1453 ref = self.frameRef(href, "Status", href, "1", event.short) 1454 code('<TH bgcolor=white>$ref</TH>') 1455 1456 code('</TR>') 1457 # -- Body of table 1458 for state in self.states.itervalues(): 1459 # -- Each row 1460 if state == active_state: 1461 color = "yellow" 1462 else: 1463 color = "white" 1464 1465 click = "%s_table_%s.html" % (self.ident, state.ident) 1466 over = "%s_State_%s.html" % (self.ident, state.ident) 1467 text = html.formatShorthand(state.short) 1468 ref = self.frameRef(click, "Table", over, "1", state.short) 1469 code(''' 1470<TR> 1471 <TH bgcolor=$color>$ref</TH> 1472''') 1473 1474 # -- One column for each event 1475 for event in self.events.itervalues(): 1476 trans = self.table.get((state,event), None) 1477 if trans is None: 1478 # This is the no transition case 1479 if state == active_state: 1480 color = "#C0C000" 1481 else: 1482 color = "lightgrey" 1483 1484 code('<TD bgcolor=$color> </TD>') 1485 continue 1486 1487 next = trans.nextState 1488 stall_action = False 1489 1490 # -- Get the actions 1491 for action in trans.actions: 1492 if action.ident == "z_stall" or \ 1493 action.ident == "zz_recycleMandatoryQueue": 1494 stall_action = True 1495 1496 # -- Print out "actions/next-state" 1497 if stall_action: 1498 if state == active_state: 1499 color = "#C0C000" 1500 else: 1501 color = "lightgrey" 1502 1503 elif active_state and next.ident == active_state.ident: 1504 color = "aqua" 1505 elif state == active_state: 1506 color = "yellow" 1507 else: 1508 color = "white" 1509 1510 code('<TD bgcolor=$color>') 1511 for action in trans.actions: 1512 href = "%s_action_%s.html" % (self.ident, action.ident) 1513 ref = self.frameRef(href, "Status", href, "1", 1514 action.short) 1515 code(' $ref') 1516 if next != state: 1517 if trans.actions: 1518 code('/') 1519 click = "%s_table_%s.html" % (self.ident, next.ident) 1520 over = "%s_State_%s.html" % (self.ident, next.ident) 1521 ref = self.frameRef(click, "Table", over, "1", next.short) 1522 code("$ref") 1523 code("</TD>") 1524 1525 # -- Each row 1526 if state == active_state: 1527 color = "yellow" 1528 else: 1529 color = "white" 1530 1531 click = "%s_table_%s.html" % (self.ident, state.ident) 1532 over = "%s_State_%s.html" % (self.ident, state.ident) 1533 ref = self.frameRef(click, "Table", over, "1", state.short) 1534 code(''' 1535 <TH bgcolor=$color>$ref</TH> 1536</TR> 1537''') 1538 code(''' 1539<!- Column footer-> 1540<TR> 1541 <TH> </TH> 1542''') 1543 1544 for event in self.events.itervalues(): 1545 href = "%s_Event_%s.html" % (self.ident, event.ident) 1546 ref = self.frameRef(href, "Status", href, "1", event.short) 1547 code('<TH bgcolor=white>$ref</TH>') 1548 code(''' 1549</TR> 1550</TABLE> 1551</BODY></HTML> 1552''') 1553 1554 1555 if active_state: 1556 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1557 else: 1558 name = "%s_table.html" % self.ident 1559 code.write(path, name) 1560 1561__all__ = [ "StateMachine" ] 1562