StateMachine.py revision 9595:470016acf37d
12391SN/A# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 22391SN/A# Copyright (c) 2009 The Hewlett-Packard Development Company 32391SN/A# All rights reserved. 42391SN/A# 52391SN/A# Redistribution and use in source and binary forms, with or without 62391SN/A# modification, are permitted provided that the following conditions are 72391SN/A# met: redistributions of source code must retain the above copyright 82391SN/A# notice, this list of conditions and the following disclaimer; 92391SN/A# redistributions in binary form must reproduce the above copyright 102391SN/A# notice, this list of conditions and the following disclaimer in the 112391SN/A# documentation and/or other materials provided with the distribution; 122391SN/A# neither the name of the copyright holders nor the names of its 132391SN/A# contributors may be used to endorse or promote products derived from 142391SN/A# this software without specific prior written permission. 152391SN/A# 162391SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172391SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182391SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192391SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202391SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212391SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222391SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232391SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242391SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252391SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262391SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272391SN/A 282391SN/Afrom m5.util import orderdict 292391SN/A 302391SN/Afrom slicc.symbols.Symbol import Symbol 312391SN/Afrom slicc.symbols.Var import Var 322391SN/Aimport slicc.generate.html as html 332391SN/Aimport re 342391SN/A 352391SN/Apython_class_map = { 362391SN/A "int": "Int", 372391SN/A "uint32_t" : "UInt32", 382391SN/A "std::string": "String", 392391SN/A "bool": "Bool", 402391SN/A "CacheMemory": "RubyCache", 412391SN/A "WireBuffer": "RubyWireBuffer", 422592SN/A "Sequencer": "RubySequencer", 432394SN/A "DirectoryMemory": "RubyDirectoryMemory", 442391SN/A "MemoryControl": "MemoryControl", 452391SN/A "DMASequencer": "DMASequencer", 462415SN/A "Prefetcher":"Prefetcher", 472423SN/A "Cycles":"Cycles", 482391SN/A } 492394SN/A 502391SN/Aclass StateMachine(Symbol): 512423SN/A def __init__(self, symtab, ident, location, pairs, config_parameters): 522391SN/A super(StateMachine, self).__init__(symtab, ident, location, pairs) 532630SN/A self.table = None 542415SN/A self.config_parameters = config_parameters 552415SN/A self.prefetchers = [] 562415SN/A 572415SN/A for param in config_parameters: 582415SN/A if param.pointer: 592415SN/A var = Var(symtab, param.name, location, param.type_ast.type, 602415SN/A "(*m_%s_ptr)" % param.name, {}, self) 612415SN/A else: 622415SN/A var = Var(symtab, param.name, location, param.type_ast.type, 632415SN/A "m_%s" % param.name, {}, self) 642415SN/A self.symtab.registerSym(param.name, var) 652415SN/A if str(param.type_ast.type) == "Prefetcher": 662415SN/A self.prefetchers.append(var) 672415SN/A 682415SN/A self.states = orderdict() 692415SN/A self.events = orderdict() 702415SN/A self.actions = orderdict() 712415SN/A self.request_types = orderdict() 722565SN/A self.transitions = [] 732565SN/A self.in_ports = [] 742391SN/A self.functions = [] 752391SN/A self.objects = [] 762391SN/A self.TBEType = None 772391SN/A self.EntryType = None 782391SN/A 792391SN/A def __repr__(self): 802391SN/A return "[StateMachine: %s]" % self.ident 812391SN/A 822391SN/A def addState(self, state): 832391SN/A assert self.table is None 842391SN/A self.states[state.ident] = state 852391SN/A 862391SN/A def addEvent(self, event): 872391SN/A assert self.table is None 882391SN/A self.events[event.ident] = event 892391SN/A 902391SN/A def addAction(self, action): 912391SN/A assert self.table is None 922391SN/A 932541SN/A # Check for duplicate action 942541SN/A for other in self.actions.itervalues(): 952541SN/A if action.ident == other.ident: 962541SN/A action.warning("Duplicate action definition: %s" % action.ident) 972541SN/A action.error("Duplicate action definition: %s" % action.ident) 982541SN/A if action.short == other.short: 992541SN/A other.warning("Duplicate action shorthand: %s" % other.ident) 1002541SN/A other.warning(" shorthand = %s" % other.short) 1012391SN/A action.warning("Duplicate action shorthand: %s" % action.ident) 1022391SN/A action.error(" shorthand = %s" % action.short) 1032391SN/A 1042391SN/A self.actions[action.ident] = action 1052416SN/A 1062391SN/A def addRequestType(self, request_type): 1072391SN/A assert self.table is None 1082391SN/A self.request_types[request_type.ident] = request_type 1092391SN/A 1102391SN/A def addTransition(self, trans): 1112391SN/A assert self.table is None 1122391SN/A self.transitions.append(trans) 1132391SN/A 1142391SN/A def addInPort(self, var): 1152391SN/A self.in_ports.append(var) 1162391SN/A 1172391SN/A def addFunc(self, func): 1182408SN/A # register func in the symbol table 1192408SN/A self.symtab.registerSym(str(func), func) 1202408SN/A self.functions.append(func) 1212409SN/A 1222409SN/A def addObject(self, obj): 1232408SN/A self.objects.append(obj) 1242408SN/A 1252413SN/A def addType(self, type): 1262630SN/A type_ident = '%s' % type.c_ident 1272413SN/A 1282413SN/A if type_ident == "%s_TBE" %self.ident: 1292415SN/A if self.TBEType != None: 1302639Sstever@eecs.umich.edu self.error("Multiple Transaction Buffer types in a " \ 1312630SN/A "single machine."); 1322416SN/A self.TBEType = type 1332415SN/A 1342415SN/A elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 1352413SN/A if self.EntryType != None: 1362413SN/A self.error("Multiple AbstractCacheEntry types in a " \ 1372413SN/A "single machine."); 1382413SN/A self.EntryType = type 1392630SN/A 1402413SN/A # Needs to be called before accessing the table 1412413SN/A def buildTable(self): 1422630SN/A assert self.table is None 1432413SN/A 1442413SN/A table = {} 1452413SN/A 1462413SN/A for trans in self.transitions: 1472630SN/A # Track which actions we touch so we know if we use them 1482413SN/A # all -- really this should be done for all symbols as 1492630SN/A # part of the symbol table, then only trigger it for 1502414SN/A # Actions, States, Events, etc. 1512630SN/A 1522413SN/A for action in trans.actions: 1532630SN/A action.used = True 1542630SN/A 1552418SN/A index = (trans.state, trans.event) 1562413SN/A if index in table: 1572630SN/A table[index].warning("Duplicate transition: %s" % table[index]) 1582630SN/A trans.error("Duplicate transition: %s" % trans) 1592631SN/A table[index] = trans 1602631SN/A 1612631SN/A # Look at all actions to make sure we used them all 1622631SN/A for action in self.actions.itervalues(): 1632631SN/A if not action.used: 1642418SN/A error_msg = "Unused action: %s" % action.ident 1652413SN/A if "desc" in action: 1662413SN/A error_msg += ", " + action.desc 1672413SN/A action.warning(error_msg) 1682420SN/A self.table = table 1692630SN/A 1702413SN/A def writeCodeFiles(self, path, includes): 1712413SN/A self.printControllerPython(path) 1722413SN/A self.printControllerHH(path) 1732499SN/A self.printControllerCC(path, includes) 1742413SN/A self.printCSwitch(path) 1752499SN/A self.printCWakeup(path, includes) 1762499SN/A self.printProfilerCC(path) 1772499SN/A self.printProfilerHH(path) 1782640Sstever@eecs.umich.edu self.printProfileDumperCC(path) 1792499SN/A self.printProfileDumperHH(path) 1802519SN/A 1812519SN/A def printControllerPython(self, path): 1822640Sstever@eecs.umich.edu code = self.symtab.codeFormatter() 1832462SN/A ident = self.ident 1842462SN/A py_ident = "%s_Controller" % ident 1852462SN/A c_ident = "%s_Controller" % self.ident 1862413SN/A code(''' 1872413SN/Afrom m5.params import * 1882413SN/Afrom m5.SimObject import SimObject 1892413SN/Afrom Controller import RubyController 1902413SN/A 1912413SN/Aclass $py_ident(RubyController): 1922413SN/A type = '$py_ident' 1932640Sstever@eecs.umich.edu cxx_header = 'mem/protocol/${c_ident}.hh' 1942640Sstever@eecs.umich.edu''') 1952640Sstever@eecs.umich.edu code.indent() 1962413SN/A for param in self.config_parameters: 1972413SN/A dflt_str = '' 1982413SN/A if param.default is not None: 1992413SN/A dflt_str = str(param.default) + ', ' 2002413SN/A if python_class_map.has_key(param.type_ast.type.c_ident): 2012413SN/A python_type = python_class_map[param.type_ast.type.c_ident] 2022413SN/A code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 2032413SN/A else: 2042413SN/A self.error("Unknown c++ to python class conversion for c++ " \ 2052522SN/A "type: '%s'. Please update the python_class_map " \ 2062522SN/A "in StateMachine.py", param.type_ast.type.c_ident) 2072413SN/A code.dedent() 2082522SN/A code.write(path, '%s.py' % py_ident) 2092497SN/A 2102497SN/A 2112497SN/A def printControllerHH(self, path): 2122522SN/A '''Output the method declarations for the class declaration''' 2132497SN/A code = self.symtab.codeFormatter() 2142522SN/A ident = self.ident 2152522SN/A c_ident = "%s_Controller" % self.ident 2162522SN/A 2172413SN/A code(''' 2182413SN/A/** \\file $c_ident.hh 2192415SN/A * 2202415SN/A * Auto generated C++ code started by $__file__:$__line__ 2212415SN/A * Created by slicc definition of Module "${{self.short}}" 2222415SN/A */ 2232415SN/A 2242413SN/A#ifndef __${ident}_CONTROLLER_HH__ 2252413SN/A#define __${ident}_CONTROLLER_HH__ 2262630SN/A 2272413SN/A#include <iostream> 2282416SN/A#include <sstream> 2292413SN/A#include <string> 2302413SN/A 2312413SN/A#include "mem/protocol/${ident}_ProfileDumper.hh" 2322630SN/A#include "mem/protocol/${ident}_Profiler.hh" 2332413SN/A#include "mem/protocol/TransitionResult.hh" 2342413SN/A#include "mem/protocol/Types.hh" 2352413SN/A#include "mem/ruby/common/Consumer.hh" 2362413SN/A#include "mem/ruby/common/Global.hh" 2372413SN/A#include "mem/ruby/slicc_interface/AbstractController.hh" 2382630SN/A#include "params/$c_ident.hh" 2392413SN/A''') 2402413SN/A 2412413SN/A seen_types = set() 2422413SN/A has_peer = False 2432413SN/A for var in self.objects: 2442413SN/A if var.type.ident not in seen_types and not var.type.isPrimitive: 2452391SN/A code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 2462391SN/A if "network" in var and "physical_network" in var: 2472391SN/A has_peer = True 2482391SN/A seen_types.add(var.type.ident) 2492391SN/A 2502391SN/A # for adding information to the protocol debug trace 2512391SN/A code(''' 2522391SN/Aextern std::stringstream ${ident}_transitionComment; 2532391SN/A 2542391SN/Aclass $c_ident : public AbstractController 2552391SN/A{ 2562391SN/A public: 2572391SN/A typedef ${c_ident}Params Params; 2582391SN/A $c_ident(const Params *p); 2592391SN/A static int getNumControllers(); 2602391SN/A void init(); 2612391SN/A MessageBuffer* getMandatoryQueue() const; 2622391SN/A const int & getVersion() const; 2632391SN/A const std::string toString() const; 2642391SN/A const std::string getName() const; 2652391SN/A void stallBuffer(MessageBuffer* buf, Address addr); 2662391SN/A void wakeUpBuffers(Address addr); 2672391SN/A void wakeUpAllBuffers(); 2682391SN/A void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; } 2692391SN/A void print(std::ostream& out) const; 2702391SN/A void wakeup(); 2712391SN/A void printStats(std::ostream& out) const; 2722391SN/A void clearStats(); 2732391SN/A void blockOnQueue(Address addr, MessageBuffer* port); 2742391SN/A void unblock(Address addr); 2752391SN/A void recordCacheTrace(int cntrl, CacheRecorder* tr); 2762391SN/A Sequencer* getSequencer() const; 2772391SN/A 2782391SN/A bool functionalReadBuffers(PacketPtr&); 2792391SN/A uint32_t functionalWriteBuffers(PacketPtr&); 2802391SN/A 2812391SN/Aprivate: 2822391SN/A''') 2832391SN/A 2842391SN/A code.indent() 2852391SN/A # added by SS 2862391SN/A for param in self.config_parameters: 2872391SN/A if param.pointer: 2882391SN/A code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 2892391SN/A else: 2902391SN/A code('${{param.type_ast.type}} m_${{param.ident}};') 2912391SN/A 2922391SN/A code(''' 2932391SN/ATransitionResult doTransition(${ident}_Event event, 2942391SN/A''') 2952391SN/A 2962391SN/A if self.EntryType != None: 2972391SN/A code(''' 2982391SN/A ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 2992391SN/A''') 3002391SN/A if self.TBEType != None: 3012391SN/A code(''' 3022391SN/A ${{self.TBEType.c_ident}}* m_tbe_ptr, 3032391SN/A''') 3042391SN/A 3052391SN/A code(''' 3062391SN/A const Address& addr); 3072391SN/A 3082391SN/ATransitionResult doTransitionWorker(${ident}_Event event, 3092391SN/A ${ident}_State state, 3102391SN/A ${ident}_State& next_state, 3112391SN/A''') 3122391SN/A 3132391SN/A if self.TBEType != None: 3142391SN/A code(''' 3152391SN/A ${{self.TBEType.c_ident}}*& m_tbe_ptr, 3162391SN/A''') 3172391SN/A if self.EntryType != None: 3182391SN/A code(''' 3192391SN/A ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 3202391SN/A''') 3212391SN/A 3222391SN/A code(''' 3232391SN/A const Address& addr); 3242391SN/A 3252391SN/Astatic ${ident}_ProfileDumper s_profileDumper; 3262391SN/A${ident}_Profiler m_profiler; 3272391SN/Astatic int m_num_controllers; 3282391SN/A 3292391SN/A// Internal functions 3302391SN/A''') 3312391SN/A 3322391SN/A for func in self.functions: 3332391SN/A proto = func.prototype 3342391SN/A if proto: 3352391SN/A code('$proto') 3362391SN/A 3372391SN/A if has_peer: 3382391SN/A code('void getQueuesFromPeer(AbstractController *);') 3392391SN/A if self.EntryType != None: 3402391SN/A code(''' 3412391SN/A 3422391SN/A// Set and Reset for cache_entry variable 3432391SN/Avoid set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 3442391SN/Avoid unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 3452391SN/A''') 3462391SN/A 3472391SN/A if self.TBEType != None: 3482391SN/A code(''' 3492391SN/A 3502391SN/A// Set and Reset for tbe variable 3512391SN/Avoid set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 3522413SN/Avoid unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 3532391SN/A''') 3542391SN/A 3552391SN/A code(''' 3562391SN/A 3572565SN/A// Actions 3582391SN/A''') 3592391SN/A if self.TBEType != None and self.EntryType != None: 3602391SN/A for action in self.actions.itervalues(): 3612391SN/A code('/** \\brief ${{action.desc}} */') 3622391SN/A code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 3632391SN/A elif self.TBEType != None: 3642565SN/A for action in self.actions.itervalues(): 3652565SN/A code('/** \\brief ${{action.desc}} */') 3662391SN/A code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);') 3672391SN/A elif self.EntryType != None: 3682391SN/A for action in self.actions.itervalues(): 3692391SN/A code('/** \\brief ${{action.desc}} */') 3702391SN/A code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 3712391SN/A else: 3722565SN/A for action in self.actions.itervalues(): 3732391SN/A code('/** \\brief ${{action.desc}} */') 3742391SN/A code('void ${{action.ident}}(const Address& addr);') 3752391SN/A 376 # the controller internal variables 377 code(''' 378 379// Objects 380''') 381 for var in self.objects: 382 th = var.get("template", "") 383 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 384 385 code.dedent() 386 code('};') 387 code('#endif // __${ident}_CONTROLLER_H__') 388 code.write(path, '%s.hh' % c_ident) 389 390 def printControllerCC(self, path, includes): 391 '''Output the actions for performing the actions''' 392 393 code = self.symtab.codeFormatter() 394 ident = self.ident 395 c_ident = "%s_Controller" % self.ident 396 has_peer = False 397 398 code(''' 399/** \\file $c_ident.cc 400 * 401 * Auto generated C++ code started by $__file__:$__line__ 402 * Created by slicc definition of Module "${{self.short}}" 403 */ 404 405#include <sys/types.h> 406#include <unistd.h> 407 408#include <cassert> 409#include <sstream> 410#include <string> 411 412#include "base/compiler.hh" 413#include "base/cprintf.hh" 414#include "debug/RubyGenerated.hh" 415#include "debug/RubySlicc.hh" 416#include "mem/protocol/${ident}_Controller.hh" 417#include "mem/protocol/${ident}_Event.hh" 418#include "mem/protocol/${ident}_State.hh" 419#include "mem/protocol/Types.hh" 420#include "mem/ruby/common/Global.hh" 421#include "mem/ruby/system/System.hh" 422''') 423 for include_path in includes: 424 code('#include "${{include_path}}"') 425 426 code(''' 427 428using namespace std; 429''') 430 431 # include object classes 432 seen_types = set() 433 for var in self.objects: 434 if var.type.ident not in seen_types and not var.type.isPrimitive: 435 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 436 seen_types.add(var.type.ident) 437 438 code(''' 439$c_ident * 440${c_ident}Params::create() 441{ 442 return new $c_ident(this); 443} 444 445int $c_ident::m_num_controllers = 0; 446${ident}_ProfileDumper $c_ident::s_profileDumper; 447 448// for adding information to the protocol debug trace 449stringstream ${ident}_transitionComment; 450#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 451 452/** \\brief constructor */ 453$c_ident::$c_ident(const Params *p) 454 : AbstractController(p) 455{ 456 m_name = "${ident}"; 457''') 458 # 459 # max_port_rank is used to size vectors and thus should be one plus the 460 # largest port rank 461 # 462 max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1 463 code(' m_max_in_port_rank = $max_port_rank;') 464 code.indent() 465 466 # 467 # After initializing the universal machine parameters, initialize the 468 # this machines config parameters. Also detemine if these configuration 469 # params include a sequencer. This information will be used later for 470 # contecting the sequencer back to the L1 cache controller. 471 # 472 contains_dma_sequencer = False 473 sequencers = [] 474 for param in self.config_parameters: 475 if param.name == "dma_sequencer": 476 contains_dma_sequencer = True 477 elif re.compile("sequencer").search(param.name): 478 sequencers.append(param.name) 479 if param.pointer: 480 code('m_${{param.name}}_ptr = p->${{param.name}};') 481 else: 482 code('m_${{param.name}} = p->${{param.name}};') 483 484 # 485 # For the l1 cache controller, add the special atomic support which 486 # includes passing the sequencer a pointer to the controller. 487 # 488 if self.ident == "L1Cache": 489 if not sequencers: 490 self.error("The L1Cache controller must include the sequencer " \ 491 "configuration parameter") 492 493 for seq in sequencers: 494 code(''' 495m_${{seq}}_ptr->setController(this); 496 ''') 497 498 else: 499 for seq in sequencers: 500 code(''' 501m_${{seq}}_ptr->setController(this); 502 ''') 503 504 # 505 # For the DMA controller, pass the sequencer a pointer to the 506 # controller. 507 # 508 if self.ident == "DMA": 509 if not contains_dma_sequencer: 510 self.error("The DMA controller must include the sequencer " \ 511 "configuration parameter") 512 513 code(''' 514m_dma_sequencer_ptr->setController(this); 515''') 516 517 code('m_num_controllers++;') 518 for var in self.objects: 519 if var.ident.find("mandatoryQueue") >= 0: 520 code(''' 521m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}(); 522m_${{var.c_ident}}_ptr->setReceiver(this); 523''') 524 else: 525 if "network" in var and "physical_network" in var and \ 526 var["network"] == "To": 527 has_peer = True 528 code(''' 529m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}(); 530peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr; 531m_${{var.c_ident}}_ptr->setSender(this); 532''') 533 534 code(''' 535if (p->peer != NULL) 536 connectWithPeer(p->peer); 537''') 538 code.dedent() 539 code(''' 540} 541 542void 543$c_ident::init() 544{ 545 MachineType machine_type; 546 int base; 547 machine_type = string_to_MachineType("${{var.machine.ident}}"); 548 base = MachineType_base_number(machine_type); 549 550 m_machineID.type = MachineType_${ident}; 551 m_machineID.num = m_version; 552 553 // initialize objects 554 m_profiler.setVersion(m_version); 555 s_profileDumper.registerProfiler(&m_profiler); 556 557''') 558 559 code.indent() 560 for var in self.objects: 561 vtype = var.type 562 vid = "m_%s_ptr" % var.c_ident 563 if "network" not in var: 564 # Not a network port object 565 if "primitive" in vtype: 566 code('$vid = new ${{vtype.c_ident}};') 567 if "default" in var: 568 code('(*$vid) = ${{var["default"]}};') 569 else: 570 # Normal Object 571 if var.ident.find("mandatoryQueue") < 0: 572 th = var.get("template", "") 573 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 574 args = "" 575 if "non_obj" not in vtype and not vtype.isEnumeration: 576 args = var.get("constructor", "") 577 code('$expr($args);') 578 579 code('assert($vid != NULL);') 580 581 if "default" in var: 582 code('*$vid = ${{var["default"]}}; // Object default') 583 elif "default" in vtype: 584 comment = "Type %s default" % vtype.ident 585 code('*$vid = ${{vtype["default"]}}; // $comment') 586 587 # Set ordering 588 if "ordered" in var: 589 # A buffer 590 code('$vid->setOrdering(${{var["ordered"]}});') 591 592 # Set randomization 593 if "random" in var: 594 # A buffer 595 code('$vid->setRandomization(${{var["random"]}});') 596 597 # Set Priority 598 if vtype.isBuffer and "rank" in var: 599 code('$vid->setPriority(${{var["rank"]}});') 600 601 # Set sender and receiver for trigger queue 602 if var.ident.find("triggerQueue") >= 0: 603 code('$vid->setSender(this);') 604 code('$vid->setReceiver(this);') 605 elif vtype.c_ident == "TimerTable": 606 code('$vid->setClockObj(this);') 607 608 else: 609 # Network port object 610 network = var["network"] 611 ordered = var["ordered"] 612 613 if "virtual_network" in var: 614 vnet = var["virtual_network"] 615 vnet_type = var["vnet_type"] 616 617 assert var.machine is not None 618 code(''' 619$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type"); 620assert($vid != NULL); 621''') 622 623 # Set the end 624 if network == "To": 625 code('$vid->setSender(this);') 626 else: 627 code('$vid->setReceiver(this);') 628 629 # Set ordering 630 if "ordered" in var: 631 # A buffer 632 code('$vid->setOrdering(${{var["ordered"]}});') 633 634 # Set randomization 635 if "random" in var: 636 # A buffer 637 code('$vid->setRandomization(${{var["random"]}});') 638 639 # Set Priority 640 if "rank" in var: 641 code('$vid->setPriority(${{var["rank"]}})') 642 643 # Set buffer size 644 if vtype.isBuffer: 645 code(''' 646if (m_buffer_size > 0) { 647 $vid->resize(m_buffer_size); 648} 649''') 650 651 # set description (may be overriden later by port def) 652 code(''' 653$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]"); 654 655''') 656 657 if vtype.isBuffer: 658 if "recycle_latency" in var: 659 code('$vid->setRecycleLatency( ' \ 660 'Cycles(${{var["recycle_latency"]}}));') 661 else: 662 code('$vid->setRecycleLatency(m_recycle_latency);') 663 664 # Set the prefetchers 665 code() 666 for prefetcher in self.prefetchers: 667 code('${{prefetcher.code}}.setController(this);') 668 669 code() 670 for port in self.in_ports: 671 # Set the queue consumers 672 code('${{port.code}}.setConsumer(this);') 673 # Set the queue descriptions 674 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");') 675 676 # Initialize the transition profiling 677 code() 678 for trans in self.transitions: 679 # Figure out if we stall 680 stall = False 681 for action in trans.actions: 682 if action.ident == "z_stall": 683 stall = True 684 685 # Only possible if it is not a 'z' case 686 if not stall: 687 state = "%s_State_%s" % (self.ident, trans.state.ident) 688 event = "%s_Event_%s" % (self.ident, trans.event.ident) 689 code('m_profiler.possibleTransition($state, $event);') 690 691 code.dedent() 692 code(''' 693 AbstractController::init(); 694 clearStats(); 695} 696''') 697 698 has_mandatory_q = False 699 for port in self.in_ports: 700 if port.code.find("mandatoryQueue_ptr") >= 0: 701 has_mandatory_q = True 702 703 if has_mandatory_q: 704 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 705 else: 706 mq_ident = "NULL" 707 708 seq_ident = "NULL" 709 for param in self.config_parameters: 710 if param.name == "sequencer": 711 assert(param.pointer) 712 seq_ident = "m_%s_ptr" % param.name 713 714 code(''' 715int 716$c_ident::getNumControllers() 717{ 718 return m_num_controllers; 719} 720 721MessageBuffer* 722$c_ident::getMandatoryQueue() const 723{ 724 return $mq_ident; 725} 726 727Sequencer* 728$c_ident::getSequencer() const 729{ 730 return $seq_ident; 731} 732 733const int & 734$c_ident::getVersion() const 735{ 736 return m_version; 737} 738 739const string 740$c_ident::toString() const 741{ 742 return "$c_ident"; 743} 744 745const string 746$c_ident::getName() const 747{ 748 return m_name; 749} 750 751void 752$c_ident::stallBuffer(MessageBuffer* buf, Address addr) 753{ 754 if (m_waiting_buffers.count(addr) == 0) { 755 MsgVecType* msgVec = new MsgVecType; 756 msgVec->resize(m_max_in_port_rank, NULL); 757 m_waiting_buffers[addr] = msgVec; 758 } 759 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf; 760} 761 762void 763$c_ident::wakeUpBuffers(Address addr) 764{ 765 if (m_waiting_buffers.count(addr) > 0) { 766 // 767 // Wake up all possible lower rank (i.e. lower priority) buffers that could 768 // be waiting on this message. 769 // 770 for (int in_port_rank = m_cur_in_port_rank - 1; 771 in_port_rank >= 0; 772 in_port_rank--) { 773 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) { 774 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr); 775 } 776 } 777 delete m_waiting_buffers[addr]; 778 m_waiting_buffers.erase(addr); 779 } 780} 781 782void 783$c_ident::wakeUpAllBuffers() 784{ 785 // 786 // Wake up all possible buffers that could be waiting on any message. 787 // 788 789 std::vector<MsgVecType*> wokeUpMsgVecs; 790 791 if(m_waiting_buffers.size() > 0) { 792 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin(); 793 buf_iter != m_waiting_buffers.end(); 794 ++buf_iter) { 795 for (MsgVecType::iterator vec_iter = buf_iter->second->begin(); 796 vec_iter != buf_iter->second->end(); 797 ++vec_iter) { 798 if (*vec_iter != NULL) { 799 (*vec_iter)->reanalyzeAllMessages(); 800 } 801 } 802 wokeUpMsgVecs.push_back(buf_iter->second); 803 } 804 805 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin(); 806 wb_iter != wokeUpMsgVecs.end(); 807 ++wb_iter) { 808 delete (*wb_iter); 809 } 810 811 m_waiting_buffers.clear(); 812 } 813} 814 815void 816$c_ident::blockOnQueue(Address addr, MessageBuffer* port) 817{ 818 m_is_blocking = true; 819 m_block_map[addr] = port; 820} 821 822void 823$c_ident::unblock(Address addr) 824{ 825 m_block_map.erase(addr); 826 if (m_block_map.size() == 0) { 827 m_is_blocking = false; 828 } 829} 830 831void 832$c_ident::print(ostream& out) const 833{ 834 out << "[$c_ident " << m_version << "]"; 835} 836 837void 838$c_ident::printStats(ostream& out) const 839{ 840''') 841 # 842 # Cache and Memory Controllers have specific profilers associated with 843 # them. Print out these stats before dumping state transition stats. 844 # 845 for param in self.config_parameters: 846 if param.type_ast.type.ident == "CacheMemory" or \ 847 param.type_ast.type.ident == "DirectoryMemory" or \ 848 param.type_ast.type.ident == "MemoryControl": 849 assert(param.pointer) 850 code(' m_${{param.ident}}_ptr->printStats(out);') 851 852 code(''' 853 if (m_version == 0) { 854 s_profileDumper.dumpStats(out); 855 } 856} 857 858void $c_ident::clearStats() { 859''') 860 # 861 # Cache and Memory Controllers have specific profilers associated with 862 # them. These stats must be cleared too. 863 # 864 for param in self.config_parameters: 865 if param.type_ast.type.ident == "CacheMemory" or \ 866 param.type_ast.type.ident == "MemoryControl": 867 assert(param.pointer) 868 code(' m_${{param.ident}}_ptr->clearStats();') 869 870 code(''' 871 m_profiler.clearStats(); 872 AbstractController::clearStats(); 873} 874''') 875 876 if self.EntryType != None: 877 code(''' 878 879// Set and Reset for cache_entry variable 880void 881$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 882{ 883 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 884} 885 886void 887$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 888{ 889 m_cache_entry_ptr = 0; 890} 891''') 892 893 if self.TBEType != None: 894 code(''' 895 896// Set and Reset for tbe variable 897void 898$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 899{ 900 m_tbe_ptr = m_new_tbe; 901} 902 903void 904$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 905{ 906 m_tbe_ptr = NULL; 907} 908''') 909 910 code(''' 911 912void 913$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 914{ 915''') 916 # 917 # Record cache contents for all associated caches. 918 # 919 code.indent() 920 for param in self.config_parameters: 921 if param.type_ast.type.ident == "CacheMemory": 922 assert(param.pointer) 923 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 924 925 code.dedent() 926 code(''' 927} 928 929// Actions 930''') 931 if self.TBEType != None and self.EntryType != 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, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 940{ 941 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 942 ${{action["c_code"]}} 943} 944 945''') 946 elif self.TBEType != 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.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 955{ 956 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 957 ${{action["c_code"]}} 958} 959 960''') 961 elif self.EntryType != None: 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}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 970{ 971 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 972 ${{action["c_code"]}} 973} 974 975''') 976 else: 977 for action in self.actions.itervalues(): 978 if "c_code" not in action: 979 continue 980 981 code(''' 982/** \\brief ${{action.desc}} */ 983void 984$c_ident::${{action.ident}}(const Address& addr) 985{ 986 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 987 ${{action["c_code"]}} 988} 989 990''') 991 for func in self.functions: 992 code(func.generateCode()) 993 994 # Function for functional reads from messages buffered in the controller 995 code(''' 996bool 997$c_ident::functionalReadBuffers(PacketPtr& pkt) 998{ 999''') 1000 for var in self.objects: 1001 vtype = var.type 1002 if vtype.isBuffer: 1003 vid = "m_%s_ptr" % var.c_ident 1004 code('if ($vid->functionalRead(pkt)) { return true; }') 1005 code(''' 1006 return false; 1007} 1008''') 1009 1010 # Function for functional writes to messages buffered in the controller 1011 code(''' 1012uint32_t 1013$c_ident::functionalWriteBuffers(PacketPtr& pkt) 1014{ 1015 uint32_t num_functional_writes = 0; 1016''') 1017 for var in self.objects: 1018 vtype = var.type 1019 if vtype.isBuffer: 1020 vid = "m_%s_ptr" % var.c_ident 1021 code('num_functional_writes += $vid->functionalWrite(pkt);') 1022 code(''' 1023 return num_functional_writes; 1024} 1025''') 1026 1027 # Check if this controller has a peer, if yes then write the 1028 # function for connecting to the peer. 1029 if has_peer: 1030 code(''' 1031 1032void 1033$c_ident::getQueuesFromPeer(AbstractController *peer) 1034{ 1035''') 1036 for var in self.objects: 1037 if "network" in var and "physical_network" in var and \ 1038 var["network"] == "From": 1039 code(''' 1040m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}}); 1041assert(m_${{var.c_ident}}_ptr != NULL); 1042m_${{var.c_ident}}_ptr->setReceiver(this); 1043 1044''') 1045 code('}') 1046 1047 code.write(path, "%s.cc" % c_ident) 1048 1049 def printCWakeup(self, path, includes): 1050 '''Output the wakeup loop for the events''' 1051 1052 code = self.symtab.codeFormatter() 1053 ident = self.ident 1054 1055 outputRequest_types = True 1056 if len(self.request_types) == 0: 1057 outputRequest_types = False 1058 1059 code(''' 1060// Auto generated C++ code started by $__file__:$__line__ 1061// ${ident}: ${{self.short}} 1062 1063#include <sys/types.h> 1064#include <unistd.h> 1065 1066#include <cassert> 1067 1068#include "base/misc.hh" 1069#include "debug/RubySlicc.hh" 1070#include "mem/protocol/${ident}_Controller.hh" 1071#include "mem/protocol/${ident}_Event.hh" 1072#include "mem/protocol/${ident}_State.hh" 1073''') 1074 1075 if outputRequest_types: 1076 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1077 1078 code(''' 1079#include "mem/protocol/Types.hh" 1080#include "mem/ruby/common/Global.hh" 1081#include "mem/ruby/system/System.hh" 1082''') 1083 1084 1085 for include_path in includes: 1086 code('#include "${{include_path}}"') 1087 1088 code(''' 1089 1090using namespace std; 1091 1092void 1093${ident}_Controller::wakeup() 1094{ 1095 int counter = 0; 1096 while (true) { 1097 // Some cases will put us into an infinite loop without this limit 1098 assert(counter <= m_transitions_per_cycle); 1099 if (counter == m_transitions_per_cycle) { 1100 // Count how often we are fully utilized 1101 m_fully_busy_cycles++; 1102 1103 // Wakeup in another cycle and try again 1104 scheduleEvent(Cycles(1)); 1105 break; 1106 } 1107''') 1108 1109 code.indent() 1110 code.indent() 1111 1112 # InPorts 1113 # 1114 for port in self.in_ports: 1115 code.indent() 1116 code('// ${ident}InPort $port') 1117 if port.pairs.has_key("rank"): 1118 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};') 1119 else: 1120 code('m_cur_in_port_rank = 0;') 1121 code('${{port["c_code_in_port"]}}') 1122 code.dedent() 1123 1124 code('') 1125 1126 code.dedent() 1127 code.dedent() 1128 code(''' 1129 break; // If we got this far, we have nothing left todo 1130 } 1131} 1132''') 1133 1134 code.write(path, "%s_Wakeup.cc" % self.ident) 1135 1136 def printCSwitch(self, path): 1137 '''Output switch statement for transition table''' 1138 1139 code = self.symtab.codeFormatter() 1140 ident = self.ident 1141 1142 code(''' 1143// Auto generated C++ code started by $__file__:$__line__ 1144// ${ident}: ${{self.short}} 1145 1146#include <cassert> 1147 1148#include "base/misc.hh" 1149#include "base/trace.hh" 1150#include "debug/ProtocolTrace.hh" 1151#include "debug/RubyGenerated.hh" 1152#include "mem/protocol/${ident}_Controller.hh" 1153#include "mem/protocol/${ident}_Event.hh" 1154#include "mem/protocol/${ident}_State.hh" 1155#include "mem/protocol/Types.hh" 1156#include "mem/ruby/common/Global.hh" 1157#include "mem/ruby/system/System.hh" 1158 1159#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1160 1161#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1162#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1163 1164TransitionResult 1165${ident}_Controller::doTransition(${ident}_Event event, 1166''') 1167 if self.EntryType != None: 1168 code(''' 1169 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1170''') 1171 if self.TBEType != None: 1172 code(''' 1173 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1174''') 1175 code(''' 1176 const Address &addr) 1177{ 1178''') 1179 if self.TBEType != None and self.EntryType != None: 1180 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1181 elif self.TBEType != None: 1182 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1183 elif self.EntryType != None: 1184 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1185 else: 1186 code('${ident}_State state = getState(addr);') 1187 1188 code(''' 1189 ${ident}_State next_state = state; 1190 1191 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1192 *this, curCycle(), ${ident}_State_to_string(state), 1193 ${ident}_Event_to_string(event), addr); 1194 1195 TransitionResult result = 1196''') 1197 if self.TBEType != None and self.EntryType != None: 1198 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1199 elif self.TBEType != None: 1200 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1201 elif self.EntryType != None: 1202 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1203 else: 1204 code('doTransitionWorker(event, state, next_state, addr);') 1205 1206 code(''' 1207 if (result == TransitionResult_Valid) { 1208 DPRINTF(RubyGenerated, "next_state: %s\\n", 1209 ${ident}_State_to_string(next_state)); 1210 m_profiler.countTransition(state, event); 1211 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1212 curTick(), m_version, "${ident}", 1213 ${ident}_Event_to_string(event), 1214 ${ident}_State_to_string(state), 1215 ${ident}_State_to_string(next_state), 1216 addr, GET_TRANSITION_COMMENT()); 1217 1218 CLEAR_TRANSITION_COMMENT(); 1219''') 1220 if self.TBEType != None and self.EntryType != None: 1221 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1222 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1223 elif self.TBEType != None: 1224 code('setState(m_tbe_ptr, addr, next_state);') 1225 code('setAccessPermission(addr, next_state);') 1226 elif self.EntryType != None: 1227 code('setState(m_cache_entry_ptr, addr, next_state);') 1228 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1229 else: 1230 code('setState(addr, next_state);') 1231 code('setAccessPermission(addr, next_state);') 1232 1233 code(''' 1234 } else if (result == TransitionResult_ResourceStall) { 1235 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1236 curTick(), m_version, "${ident}", 1237 ${ident}_Event_to_string(event), 1238 ${ident}_State_to_string(state), 1239 ${ident}_State_to_string(next_state), 1240 addr, "Resource Stall"); 1241 } else if (result == TransitionResult_ProtocolStall) { 1242 DPRINTF(RubyGenerated, "stalling\\n"); 1243 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1244 curTick(), m_version, "${ident}", 1245 ${ident}_Event_to_string(event), 1246 ${ident}_State_to_string(state), 1247 ${ident}_State_to_string(next_state), 1248 addr, "Protocol Stall"); 1249 } 1250 1251 return result; 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 const Address& 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 ns_ident = trans.nextState.ident 1285 case('next_state = ${ident}_State_${ns_ident};') 1286 1287 actions = trans.actions 1288 request_types = trans.request_types 1289 1290 # Check for resources 1291 case_sorter = [] 1292 res = trans.resources 1293 for key,val in res.iteritems(): 1294 if key.type.ident != "DNUCAStopTable": 1295 val = ''' 1296if (!%s.areNSlotsAvailable(%s)) 1297 return TransitionResult_ResourceStall; 1298''' % (key.code, val) 1299 case_sorter.append(val) 1300 1301 # Check all of the request_types for resource constraints 1302 for request_type in request_types: 1303 val = ''' 1304if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1305 return TransitionResult_ResourceStall; 1306} 1307''' % (self.ident, request_type.ident) 1308 case_sorter.append(val) 1309 1310 # Emit the code sequences in a sorted order. This makes the 1311 # output deterministic (without this the output order can vary 1312 # since Map's keys() on a vector of pointers is not deterministic 1313 for c in sorted(case_sorter): 1314 case("$c") 1315 1316 # Record access types for this transition 1317 for request_type in request_types: 1318 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1319 1320 # Figure out if we stall 1321 stall = False 1322 for action in actions: 1323 if action.ident == "z_stall": 1324 stall = True 1325 break 1326 1327 if stall: 1328 case('return TransitionResult_ProtocolStall;') 1329 else: 1330 if self.TBEType != None and self.EntryType != None: 1331 for action in actions: 1332 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1333 elif self.TBEType != None: 1334 for action in actions: 1335 case('${{action.ident}}(m_tbe_ptr, addr);') 1336 elif self.EntryType != None: 1337 for action in actions: 1338 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1339 else: 1340 for action in actions: 1341 case('${{action.ident}}(addr);') 1342 case('return TransitionResult_Valid;') 1343 1344 case = str(case) 1345 1346 # Look to see if this transition code is unique. 1347 if case not in cases: 1348 cases[case] = [] 1349 1350 cases[case].append(case_string) 1351 1352 # Walk through all of the unique code blocks and spit out the 1353 # corresponding case statement elements 1354 for case,transitions in cases.iteritems(): 1355 # Iterative over all the multiple transitions that share 1356 # the same code 1357 for trans in transitions: 1358 code(' case HASH_FUN($trans):') 1359 code(' $case') 1360 1361 code(''' 1362 default: 1363 fatal("Invalid transition\\n" 1364 "%s time: %d addr: %s event: %s state: %s\\n", 1365 name(), curCycle(), addr, event, state); 1366 } 1367 return TransitionResult_Valid; 1368} 1369''') 1370 code.write(path, "%s_Transitions.cc" % self.ident) 1371 1372 def printProfileDumperHH(self, path): 1373 code = self.symtab.codeFormatter() 1374 ident = self.ident 1375 1376 code(''' 1377// Auto generated C++ code started by $__file__:$__line__ 1378// ${ident}: ${{self.short}} 1379 1380#ifndef __${ident}_PROFILE_DUMPER_HH__ 1381#define __${ident}_PROFILE_DUMPER_HH__ 1382 1383#include <cassert> 1384#include <iostream> 1385#include <vector> 1386 1387#include "${ident}_Event.hh" 1388#include "${ident}_Profiler.hh" 1389 1390typedef std::vector<${ident}_Profiler *> ${ident}_profilers; 1391 1392class ${ident}_ProfileDumper 1393{ 1394 public: 1395 ${ident}_ProfileDumper(); 1396 void registerProfiler(${ident}_Profiler* profiler); 1397 void dumpStats(std::ostream& out) const; 1398 1399 private: 1400 ${ident}_profilers m_profilers; 1401}; 1402 1403#endif // __${ident}_PROFILE_DUMPER_HH__ 1404''') 1405 code.write(path, "%s_ProfileDumper.hh" % self.ident) 1406 1407 def printProfileDumperCC(self, path): 1408 code = self.symtab.codeFormatter() 1409 ident = self.ident 1410 1411 code(''' 1412// Auto generated C++ code started by $__file__:$__line__ 1413// ${ident}: ${{self.short}} 1414 1415#include "mem/protocol/${ident}_ProfileDumper.hh" 1416 1417${ident}_ProfileDumper::${ident}_ProfileDumper() 1418{ 1419} 1420 1421void 1422${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler) 1423{ 1424 m_profilers.push_back(profiler); 1425} 1426 1427void 1428${ident}_ProfileDumper::dumpStats(std::ostream& out) const 1429{ 1430 out << " --- ${ident} ---\\n"; 1431 out << " - Event Counts -\\n"; 1432 for (${ident}_Event event = ${ident}_Event_FIRST; 1433 event < ${ident}_Event_NUM; 1434 ++event) { 1435 out << (${ident}_Event) event << " ["; 1436 uint64 total = 0; 1437 for (int i = 0; i < m_profilers.size(); i++) { 1438 out << m_profilers[i]->getEventCount(event) << " "; 1439 total += m_profilers[i]->getEventCount(event); 1440 } 1441 out << "] " << total << "\\n"; 1442 } 1443 out << "\\n"; 1444 out << " - Transitions -\\n"; 1445 for (${ident}_State state = ${ident}_State_FIRST; 1446 state < ${ident}_State_NUM; 1447 ++state) { 1448 for (${ident}_Event event = ${ident}_Event_FIRST; 1449 event < ${ident}_Event_NUM; 1450 ++event) { 1451 if (m_profilers[0]->isPossible(state, event)) { 1452 out << (${ident}_State) state << " " 1453 << (${ident}_Event) event << " ["; 1454 uint64 total = 0; 1455 for (int i = 0; i < m_profilers.size(); i++) { 1456 out << m_profilers[i]->getTransitionCount(state, event) << " "; 1457 total += m_profilers[i]->getTransitionCount(state, event); 1458 } 1459 out << "] " << total << "\\n"; 1460 } 1461 } 1462 out << "\\n"; 1463 } 1464} 1465''') 1466 code.write(path, "%s_ProfileDumper.cc" % self.ident) 1467 1468 def printProfilerHH(self, path): 1469 code = self.symtab.codeFormatter() 1470 ident = self.ident 1471 1472 code(''' 1473// Auto generated C++ code started by $__file__:$__line__ 1474// ${ident}: ${{self.short}} 1475 1476#ifndef __${ident}_PROFILER_HH__ 1477#define __${ident}_PROFILER_HH__ 1478 1479#include <cassert> 1480#include <iostream> 1481 1482#include "mem/protocol/${ident}_Event.hh" 1483#include "mem/protocol/${ident}_State.hh" 1484#include "mem/ruby/common/TypeDefines.hh" 1485 1486class ${ident}_Profiler 1487{ 1488 public: 1489 ${ident}_Profiler(); 1490 void setVersion(int version); 1491 void countTransition(${ident}_State state, ${ident}_Event event); 1492 void possibleTransition(${ident}_State state, ${ident}_Event event); 1493 uint64 getEventCount(${ident}_Event event); 1494 bool isPossible(${ident}_State state, ${ident}_Event event); 1495 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 1496 void clearStats(); 1497 1498 private: 1499 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 1500 int m_event_counters[${ident}_Event_NUM]; 1501 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 1502 int m_version; 1503}; 1504 1505#endif // __${ident}_PROFILER_HH__ 1506''') 1507 code.write(path, "%s_Profiler.hh" % self.ident) 1508 1509 def printProfilerCC(self, path): 1510 code = self.symtab.codeFormatter() 1511 ident = self.ident 1512 1513 code(''' 1514// Auto generated C++ code started by $__file__:$__line__ 1515// ${ident}: ${{self.short}} 1516 1517#include <cassert> 1518 1519#include "mem/protocol/${ident}_Profiler.hh" 1520 1521${ident}_Profiler::${ident}_Profiler() 1522{ 1523 for (int state = 0; state < ${ident}_State_NUM; state++) { 1524 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1525 m_possible[state][event] = false; 1526 m_counters[state][event] = 0; 1527 } 1528 } 1529 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1530 m_event_counters[event] = 0; 1531 } 1532} 1533 1534void 1535${ident}_Profiler::setVersion(int version) 1536{ 1537 m_version = version; 1538} 1539 1540void 1541${ident}_Profiler::clearStats() 1542{ 1543 for (int state = 0; state < ${ident}_State_NUM; state++) { 1544 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1545 m_counters[state][event] = 0; 1546 } 1547 } 1548 1549 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1550 m_event_counters[event] = 0; 1551 } 1552} 1553void 1554${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1555{ 1556 assert(m_possible[state][event]); 1557 m_counters[state][event]++; 1558 m_event_counters[event]++; 1559} 1560void 1561${ident}_Profiler::possibleTransition(${ident}_State state, 1562 ${ident}_Event event) 1563{ 1564 m_possible[state][event] = true; 1565} 1566 1567uint64 1568${ident}_Profiler::getEventCount(${ident}_Event event) 1569{ 1570 return m_event_counters[event]; 1571} 1572 1573bool 1574${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event) 1575{ 1576 return m_possible[state][event]; 1577} 1578 1579uint64 1580${ident}_Profiler::getTransitionCount(${ident}_State state, 1581 ${ident}_Event event) 1582{ 1583 return m_counters[state][event]; 1584} 1585 1586''') 1587 code.write(path, "%s_Profiler.cc" % self.ident) 1588 1589 # ************************** 1590 # ******* HTML Files ******* 1591 # ************************** 1592 def frameRef(self, click_href, click_target, over_href, over_num, text): 1593 code = self.symtab.codeFormatter(fix_newlines=False) 1594 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1595 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1596 parent.frames[$over_num].location='$over_href' 1597 }\"> 1598 ${{html.formatShorthand(text)}} 1599 </A>""") 1600 return str(code) 1601 1602 def writeHTMLFiles(self, path): 1603 # Create table with no row hilighted 1604 self.printHTMLTransitions(path, None) 1605 1606 # Generate transition tables 1607 for state in self.states.itervalues(): 1608 self.printHTMLTransitions(path, state) 1609 1610 # Generate action descriptions 1611 for action in self.actions.itervalues(): 1612 name = "%s_action_%s.html" % (self.ident, action.ident) 1613 code = html.createSymbol(action, "Action") 1614 code.write(path, name) 1615 1616 # Generate state descriptions 1617 for state in self.states.itervalues(): 1618 name = "%s_State_%s.html" % (self.ident, state.ident) 1619 code = html.createSymbol(state, "State") 1620 code.write(path, name) 1621 1622 # Generate event descriptions 1623 for event in self.events.itervalues(): 1624 name = "%s_Event_%s.html" % (self.ident, event.ident) 1625 code = html.createSymbol(event, "Event") 1626 code.write(path, name) 1627 1628 def printHTMLTransitions(self, path, active_state): 1629 code = self.symtab.codeFormatter() 1630 1631 code(''' 1632<HTML> 1633<BODY link="blue" vlink="blue"> 1634 1635<H1 align="center">${{html.formatShorthand(self.short)}}: 1636''') 1637 code.indent() 1638 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1639 mid = machine.ident 1640 if i != 0: 1641 extra = " - " 1642 else: 1643 extra = "" 1644 if machine == self: 1645 code('$extra$mid') 1646 else: 1647 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1648 code.dedent() 1649 1650 code(""" 1651</H1> 1652 1653<TABLE border=1> 1654<TR> 1655 <TH> </TH> 1656""") 1657 1658 for event in self.events.itervalues(): 1659 href = "%s_Event_%s.html" % (self.ident, event.ident) 1660 ref = self.frameRef(href, "Status", href, "1", event.short) 1661 code('<TH bgcolor=white>$ref</TH>') 1662 1663 code('</TR>') 1664 # -- Body of table 1665 for state in self.states.itervalues(): 1666 # -- Each row 1667 if state == active_state: 1668 color = "yellow" 1669 else: 1670 color = "white" 1671 1672 click = "%s_table_%s.html" % (self.ident, state.ident) 1673 over = "%s_State_%s.html" % (self.ident, state.ident) 1674 text = html.formatShorthand(state.short) 1675 ref = self.frameRef(click, "Table", over, "1", state.short) 1676 code(''' 1677<TR> 1678 <TH bgcolor=$color>$ref</TH> 1679''') 1680 1681 # -- One column for each event 1682 for event in self.events.itervalues(): 1683 trans = self.table.get((state,event), None) 1684 if trans is None: 1685 # This is the no transition case 1686 if state == active_state: 1687 color = "#C0C000" 1688 else: 1689 color = "lightgrey" 1690 1691 code('<TD bgcolor=$color> </TD>') 1692 continue 1693 1694 next = trans.nextState 1695 stall_action = False 1696 1697 # -- Get the actions 1698 for action in trans.actions: 1699 if action.ident == "z_stall" or \ 1700 action.ident == "zz_recycleMandatoryQueue": 1701 stall_action = True 1702 1703 # -- Print out "actions/next-state" 1704 if stall_action: 1705 if state == active_state: 1706 color = "#C0C000" 1707 else: 1708 color = "lightgrey" 1709 1710 elif active_state and next.ident == active_state.ident: 1711 color = "aqua" 1712 elif state == active_state: 1713 color = "yellow" 1714 else: 1715 color = "white" 1716 1717 code('<TD bgcolor=$color>') 1718 for action in trans.actions: 1719 href = "%s_action_%s.html" % (self.ident, action.ident) 1720 ref = self.frameRef(href, "Status", href, "1", 1721 action.short) 1722 code(' $ref') 1723 if next != state: 1724 if trans.actions: 1725 code('/') 1726 click = "%s_table_%s.html" % (self.ident, next.ident) 1727 over = "%s_State_%s.html" % (self.ident, next.ident) 1728 ref = self.frameRef(click, "Table", over, "1", next.short) 1729 code("$ref") 1730 code("</TD>") 1731 1732 # -- Each row 1733 if state == active_state: 1734 color = "yellow" 1735 else: 1736 color = "white" 1737 1738 click = "%s_table_%s.html" % (self.ident, state.ident) 1739 over = "%s_State_%s.html" % (self.ident, state.ident) 1740 ref = self.frameRef(click, "Table", over, "1", state.short) 1741 code(''' 1742 <TH bgcolor=$color>$ref</TH> 1743</TR> 1744''') 1745 code(''' 1746<!- Column footer-> 1747<TR> 1748 <TH> </TH> 1749''') 1750 1751 for event in self.events.itervalues(): 1752 href = "%s_Event_%s.html" % (self.ident, event.ident) 1753 ref = self.frameRef(href, "Status", href, "1", event.short) 1754 code('<TH bgcolor=white>$ref</TH>') 1755 code(''' 1756</TR> 1757</TABLE> 1758</BODY></HTML> 1759''') 1760 1761 1762 if active_state: 1763 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1764 else: 1765 name = "%s_table.html" % self.ident 1766 code.write(path, name) 1767 1768__all__ = [ "StateMachine" ] 1769