StateMachine.py revision 8055
113606Sciro.santilli@arm.com# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 27586SAli.Saidi@arm.com# Copyright (c) 2009 The Hewlett-Packard Development Company 37586SAli.Saidi@arm.com# All rights reserved. 47586SAli.Saidi@arm.com# 57586SAli.Saidi@arm.com# Redistribution and use in source and binary forms, with or without 67586SAli.Saidi@arm.com# modification, are permitted provided that the following conditions are 77586SAli.Saidi@arm.com# met: redistributions of source code must retain the above copyright 87586SAli.Saidi@arm.com# notice, this list of conditions and the following disclaimer; 97586SAli.Saidi@arm.com# redistributions in binary form must reproduce the above copyright 107586SAli.Saidi@arm.com# notice, this list of conditions and the following disclaimer in the 117586SAli.Saidi@arm.com# documentation and/or other materials provided with the distribution; 127586SAli.Saidi@arm.com# neither the name of the copyright holders nor the names of its 1310118Snilay@cs.wisc.edu# contributors may be used to endorse or promote products derived from 1410118Snilay@cs.wisc.edu# this software without specific prior written permission. 153970Sgblack@eecs.umich.edu# 163005Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173005Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183005Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193005Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203005Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213005Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223005Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233005Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243005Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253005Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263005Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273005Sstever@eecs.umich.edu 283005Sstever@eecs.umich.edufrom m5.util import orderdict 293005Sstever@eecs.umich.edu 303005Sstever@eecs.umich.edufrom slicc.symbols.Symbol import Symbol 313005Sstever@eecs.umich.edufrom slicc.symbols.Var import Var 323005Sstever@eecs.umich.eduimport slicc.generate.html as html 333005Sstever@eecs.umich.edu 343005Sstever@eecs.umich.edupython_class_map = {"int": "Int", 353005Sstever@eecs.umich.edu "std::string": "String", 363005Sstever@eecs.umich.edu "bool": "Bool", 373005Sstever@eecs.umich.edu "CacheMemory": "RubyCache", 383005Sstever@eecs.umich.edu "Sequencer": "RubySequencer", 393005Sstever@eecs.umich.edu "DirectoryMemory": "RubyDirectoryMemory", 403005Sstever@eecs.umich.edu "MemoryControl": "RubyMemoryControl", 413005Sstever@eecs.umich.edu "DMASequencer": "DMASequencer" 4210118Snilay@cs.wisc.edu } 433005Sstever@eecs.umich.edu 4412564Sgabeblack@google.comclass StateMachine(Symbol): 4513774Sandreas.sandberg@arm.com def __init__(self, symtab, ident, location, pairs, config_parameters): 4612564Sgabeblack@google.com super(StateMachine, self).__init__(symtab, ident, location, pairs) 476654Snate@binkert.org self.table = None 486654Snate@binkert.org self.config_parameters = config_parameters 492889SN/A 502710SN/A for param in config_parameters: 516654Snate@binkert.org if param.pointer: 526654Snate@binkert.org var = Var(symtab, param.name, location, param.type_ast.type, 5312395Sswapnilster@gmail.com "(*m_%s_ptr)" % param.name, {}, self) 5412475Sglenn.bergmans@arm.com else: 555457Ssaidi@eecs.umich.edu var = Var(symtab, param.name, location, param.type_ast.type, 5611670Sandreas.hansson@arm.com "m_%s" % param.name, {}, self) 5710118Snilay@cs.wisc.edu self.symtab.registerSym(param.name, var) 5811670Sandreas.hansson@arm.com 596654Snate@binkert.org self.states = orderdict() 6011682Sandreas.hansson@arm.com self.events = orderdict() 6111682Sandreas.hansson@arm.com self.actions = orderdict() 6211682Sandreas.hansson@arm.com self.transitions = [] 6311682Sandreas.hansson@arm.com self.in_ports = [] 6411682Sandreas.hansson@arm.com self.functions = [] 6511682Sandreas.hansson@arm.com self.objects = [] 6611790Sjungma@eit.uni-kl.de self.TBEType = None 6713432Spau.cabre@metempsy.com self.EntryType = None 6811682Sandreas.hansson@arm.com 6911682Sandreas.hansson@arm.com self.message_buffer_names = [] 703444Sktlim@umich.edu 7110594Sgabeblack@google.com def __repr__(self): 7210594Sgabeblack@google.com return "[StateMachine: %s]" % self.ident 7312564Sgabeblack@google.com 7412564Sgabeblack@google.com def addState(self, state): 7510594Sgabeblack@google.com assert self.table is None 7610594Sgabeblack@google.com self.states[state.ident] = state 7710594Sgabeblack@google.com 7810594Sgabeblack@google.com def addEvent(self, event): 7910594Sgabeblack@google.com assert self.table is None 8010594Sgabeblack@google.com self.events[event.ident] = event 8110594Sgabeblack@google.com 8210119Snilay@cs.wisc.edu def addAction(self, action): 8310594Sgabeblack@google.com assert self.table is None 8410119Snilay@cs.wisc.edu 8510594Sgabeblack@google.com # Check for duplicate action 8610594Sgabeblack@google.com for other in self.actions.itervalues(): 8710119Snilay@cs.wisc.edu if action.ident == other.ident: 8810594Sgabeblack@google.com action.warning("Duplicate action definition: %s" % action.ident) 8910119Snilay@cs.wisc.edu action.error("Duplicate action definition: %s" % action.ident) 9010594Sgabeblack@google.com if action.short == other.short: 9110119Snilay@cs.wisc.edu other.warning("Duplicate action shorthand: %s" % other.ident) 9210119Snilay@cs.wisc.edu other.warning(" shorthand = %s" % other.short) 9310594Sgabeblack@google.com action.warning("Duplicate action shorthand: %s" % action.ident) 9410119Snilay@cs.wisc.edu action.error(" shorthand = %s" % action.short) 9510512SAli.Saidi@ARM.com 9610512SAli.Saidi@ARM.com self.actions[action.ident] = action 9710594Sgabeblack@google.com 9810780SCurtis.Dunham@arm.com def addTransition(self, trans): 9912475Sglenn.bergmans@arm.com assert self.table is None 10012475Sglenn.bergmans@arm.com self.transitions.append(trans) 10112079Sgedare@rtems.org 10212079Sgedare@rtems.org def addInPort(self, var): 10310119Snilay@cs.wisc.edu self.in_ports.append(var) 10410119Snilay@cs.wisc.edu 10510119Snilay@cs.wisc.edu def addFunc(self, func): 10610119Snilay@cs.wisc.edu # register func in the symbol table 1072566SN/A self.symtab.registerSym(str(func), func) 10810119Snilay@cs.wisc.edu self.functions.append(func) 10910119Snilay@cs.wisc.edu 1109665Sandreas.hansson@arm.com def addObject(self, obj): 11110119Snilay@cs.wisc.edu self.objects.append(obj) 11210119Snilay@cs.wisc.edu 11310119Snilay@cs.wisc.edu def addType(self, type): 11410119Snilay@cs.wisc.edu type_ident = '%s' % type.c_ident 11510119Snilay@cs.wisc.edu 11610119Snilay@cs.wisc.edu if type_ident == "%s_TBE" %self.ident: 11710119Snilay@cs.wisc.edu if self.TBEType != None: 11810119Snilay@cs.wisc.edu self.error("Multiple Transaction Buffer types in a " \ 11910119Snilay@cs.wisc.edu "single machine."); 12010119Snilay@cs.wisc.edu self.TBEType = type 12110119Snilay@cs.wisc.edu 12210119Snilay@cs.wisc.edu elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 12310119Snilay@cs.wisc.edu if self.EntryType != None: 12410119Snilay@cs.wisc.edu self.error("Multiple AbstractCacheEntry types in a " \ 12510119Snilay@cs.wisc.edu "single machine."); 12610119Snilay@cs.wisc.edu self.EntryType = type 12710119Snilay@cs.wisc.edu 12813803Sodanrc@yahoo.com.br # Needs to be called before accessing the table 12913803Sodanrc@yahoo.com.br def buildTable(self): 13013803Sodanrc@yahoo.com.br assert self.table is None 13110119Snilay@cs.wisc.edu 13210119Snilay@cs.wisc.edu table = {} 13310119Snilay@cs.wisc.edu 13410119Snilay@cs.wisc.edu for trans in self.transitions: 13510119Snilay@cs.wisc.edu # Track which actions we touch so we know if we use them 13610119Snilay@cs.wisc.edu # all -- really this should be done for all symbols as 13710119Snilay@cs.wisc.edu # part of the symbol table, then only trigger it for 13810119Snilay@cs.wisc.edu # Actions, States, Events, etc. 13910119Snilay@cs.wisc.edu 14010119Snilay@cs.wisc.edu for action in trans.actions: 14110119Snilay@cs.wisc.edu action.used = True 14210119Snilay@cs.wisc.edu 14310119Snilay@cs.wisc.edu index = (trans.state, trans.event) 14410119Snilay@cs.wisc.edu if index in table: 14513731Sandreas.sandberg@arm.com table[index].warning("Duplicate transition: %s" % table[index]) 14610119Snilay@cs.wisc.edu trans.error("Duplicate transition: %s" % trans) 14712941Sandreas.sandberg@arm.com table[index] = trans 14811839SCurtis.Dunham@arm.com 14910119Snilay@cs.wisc.edu # Look at all actions to make sure we used them all 15010119Snilay@cs.wisc.edu for action in self.actions.itervalues(): 15112598Snikos.nikoleris@arm.com if not action.used: 15210519Snilay@cs.wisc.edu error_msg = "Unused action: %s" % action.ident 15312598Snikos.nikoleris@arm.com if "desc" in action: 15410119Snilay@cs.wisc.edu error_msg += ", " + action.desc 15510119Snilay@cs.wisc.edu action.warning(error_msg) 15610119Snilay@cs.wisc.edu self.table = table 15710119Snilay@cs.wisc.edu 15810119Snilay@cs.wisc.edu def writeCodeFiles(self, path): 15910547Snilay@cs.wisc.edu self.printControllerPython(path) 16010547Snilay@cs.wisc.edu self.printControllerHH(path) 16110547Snilay@cs.wisc.edu self.printControllerCC(path) 16210547Snilay@cs.wisc.edu self.printCSwitch(path) 16310119Snilay@cs.wisc.edu self.printCWakeup(path) 16410119Snilay@cs.wisc.edu self.printProfilerCC(path) 16510119Snilay@cs.wisc.edu self.printProfilerHH(path) 16610119Snilay@cs.wisc.edu self.printProfileDumperCC(path) 16710119Snilay@cs.wisc.edu self.printProfileDumperHH(path) 16810119Snilay@cs.wisc.edu 16910119Snilay@cs.wisc.edu for func in self.functions: 17010119Snilay@cs.wisc.edu func.writeCodeFiles(path) 17110120Snilay@cs.wisc.edu 17210120Snilay@cs.wisc.edu def printControllerPython(self, path): 17310119Snilay@cs.wisc.edu code = self.symtab.codeFormatter() 17411598Sandreas.sandberg@arm.com ident = self.ident 17510120Snilay@cs.wisc.edu py_ident = "%s_Controller" % ident 17610120Snilay@cs.wisc.edu c_ident = "%s_Controller" % self.ident 17710119Snilay@cs.wisc.edu code(''' 17811598Sandreas.sandberg@arm.comfrom m5.params import * 17911150Smitch.hayenga@arm.comfrom m5.SimObject import SimObject 18011150Smitch.hayenga@arm.comfrom Controller import RubyController 18111150Smitch.hayenga@arm.com 18210119Snilay@cs.wisc.educlass $py_ident(RubyController): 1832995SN/A type = '$py_ident' 18410119Snilay@cs.wisc.edu''') 18510119Snilay@cs.wisc.edu code.indent() 18610119Snilay@cs.wisc.edu for param in self.config_parameters: 18710119Snilay@cs.wisc.edu dflt_str = '' 18810119Snilay@cs.wisc.edu if param.default is not None: 18910780SCurtis.Dunham@arm.com dflt_str = str(param.default) + ', ' 19010119Snilay@cs.wisc.edu if python_class_map.has_key(param.type_ast.type.c_ident): 19110119Snilay@cs.wisc.edu python_type = python_class_map[param.type_ast.type.c_ident] 19210119Snilay@cs.wisc.edu code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 1933304Sstever@eecs.umich.edu else: 19410119Snilay@cs.wisc.edu self.error("Unknown c++ to python class conversion for c++ " \ 19510608Sdam.sunwoo@arm.com "type: '%s'. Please update the python_class_map " \ 19613684Sgiacomo.travaglini@arm.com "in StateMachine.py", param.type_ast.type.c_ident) 19713012Sandreas.sandberg@arm.com code.dedent() 19810608Sdam.sunwoo@arm.com code.write(path, '%s.py' % py_ident) 19910608Sdam.sunwoo@arm.com 20010608Sdam.sunwoo@arm.com 20113731Sandreas.sandberg@arm.com def printControllerHH(self, path): 20210608Sdam.sunwoo@arm.com '''Output the method declarations for the class declaration''' 20310608Sdam.sunwoo@arm.com code = self.symtab.codeFormatter() 20410119Snilay@cs.wisc.edu ident = self.ident 20510119Snilay@cs.wisc.edu c_ident = "%s_Controller" % self.ident 20613432Spau.cabre@metempsy.com 20713432Spau.cabre@metempsy.com self.message_buffer_names = [] 20813432Spau.cabre@metempsy.com 20910119Snilay@cs.wisc.edu code(''' 2103819Shsul@eecs.umich.edu/** \\file $c_ident.hh 21111251Sradhika.jagtap@ARM.com * 21211251Sradhika.jagtap@ARM.com * Auto generated C++ code started by $__file__:$__line__ 21311251Sradhika.jagtap@ARM.com * Created by slicc definition of Module "${{self.short}}" 21411251Sradhika.jagtap@ARM.com */ 21511251Sradhika.jagtap@ARM.com 21611251Sradhika.jagtap@ARM.com#ifndef __${ident}_CONTROLLER_HH__ 21711251Sradhika.jagtap@ARM.com#define __${ident}_CONTROLLER_HH__ 21811251Sradhika.jagtap@ARM.com 21911251Sradhika.jagtap@ARM.com#include <iostream> 22011251Sradhika.jagtap@ARM.com#include <sstream> 22111251Sradhika.jagtap@ARM.com#include <string> 22210119Snilay@cs.wisc.edu 22311183Serfan.azarkhish@unibo.it#include "params/$c_ident.hh" 22410119Snilay@cs.wisc.edu 22510118Snilay@cs.wisc.edu#include "mem/ruby/common/Global.hh" 22610119Snilay@cs.wisc.edu#include "mem/ruby/common/Consumer.hh" 2279827Sakash.bagdia@arm.com#include "mem/ruby/slicc_interface/AbstractController.hh" 22810119Snilay@cs.wisc.edu#include "mem/protocol/TransitionResult.hh" 22910119Snilay@cs.wisc.edu#include "mem/protocol/Types.hh" 23010119Snilay@cs.wisc.edu#include "mem/protocol/${ident}_Profiler.hh" 23110119Snilay@cs.wisc.edu#include "mem/protocol/${ident}_ProfileDumper.hh" 23210119Snilay@cs.wisc.edu''') 23310119Snilay@cs.wisc.edu 2349827Sakash.bagdia@arm.com seen_types = set() 23510594Sgabeblack@google.com for var in self.objects: 2366654Snate@binkert.org if var.type.ident not in seen_types and not var.type.isPrimitive: 23713803Sodanrc@yahoo.com.br code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 23813803Sodanrc@yahoo.com.br seen_types.add(var.type.ident) 2396654Snate@binkert.org 24010594Sgabeblack@google.com # for adding information to the protocol debug trace 2416654Snate@binkert.org code(''' 24210594Sgabeblack@google.comextern std::stringstream ${ident}_transitionComment; 2436654Snate@binkert.org 24410594Sgabeblack@google.comclass $c_ident : public AbstractController 24510594Sgabeblack@google.com{ 2467586SAli.Saidi@arm.com// the coherence checker needs to call isBlockExclusive() and isBlockShared() 24710635Satgutier@umich.edu// making the Chip a friend class is an easy way to do this for now 24813606Sciro.santilli@arm.com 2498661SAli.Saidi@ARM.compublic: 2509827Sakash.bagdia@arm.com typedef ${c_ident}Params Params; 2519827Sakash.bagdia@arm.com $c_ident(const Params *p); 2529827Sakash.bagdia@arm.com static int getNumControllers(); 2539793Sakash.bagdia@arm.com void init(); 25410119Snilay@cs.wisc.edu MessageBuffer* getMandatoryQueue() const; 25510119Snilay@cs.wisc.edu const int & getVersion() const; 2569790Sakash.bagdia@arm.com const std::string toString() const; 2579827Sakash.bagdia@arm.com const std::string getName() const; 2589827Sakash.bagdia@arm.com const MachineType getMachineType() const; 2599827Sakash.bagdia@arm.com void stallBuffer(MessageBuffer* buf, Address addr); 2609793Sakash.bagdia@arm.com void wakeUpBuffers(Address addr); 2619827Sakash.bagdia@arm.com void wakeUpAllBuffers(); 2629827Sakash.bagdia@arm.com void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; } 2639827Sakash.bagdia@arm.com void print(std::ostream& out) const; 2649793Sakash.bagdia@arm.com void printConfig(std::ostream& out) const; 2659793Sakash.bagdia@arm.com void wakeup(); 2669793Sakash.bagdia@arm.com void printStats(std::ostream& out) const; 2679384SAndreas.Sandberg@arm.com void clearStats(); 2688863Snilay@cs.wisc.edu void blockOnQueue(Address addr, MessageBuffer* port); 2697876Sgblack@eecs.umich.edu void unblock(Address addr); 2704837Ssaidi@eecs.umich.edu 2714837Ssaidi@eecs.umich.eduprivate: 27213803Sodanrc@yahoo.com.br''') 27313803Sodanrc@yahoo.com.br 27413803Sodanrc@yahoo.com.br code.indent() 2759408Sandreas.hansson@arm.com # added by SS 27612941Sandreas.sandberg@arm.com for param in self.config_parameters: 27711839SCurtis.Dunham@arm.com if param.pointer: 2789653SAndreas.Sandberg@ARM.com code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 2799164Sandreas.hansson@arm.com else: 2809408Sandreas.hansson@arm.com code('${{param.type_ast.type}} m_${{param.ident}};') 2818845Sandreas.hansson@arm.com 2828845Sandreas.hansson@arm.com code(''' 2834837Ssaidi@eecs.umich.eduint m_number_of_TBEs; 2849826Sandreas.hansson@arm.com 2859826Sandreas.hansson@arm.comTransitionResult doTransition(${ident}_Event event, 2869835Sandreas.hansson@arm.com''') 2879826Sandreas.hansson@arm.com 28813731Sandreas.sandberg@arm.com if self.EntryType != None: 2899826Sandreas.hansson@arm.com code(''' 2909826Sandreas.hansson@arm.com ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 2918659SAli.Saidi@ARM.com''') 29210119Snilay@cs.wisc.edu if self.TBEType != None: 29310119Snilay@cs.wisc.edu code(''' 29410119Snilay@cs.wisc.edu ${{self.TBEType.c_ident}}* m_tbe_ptr, 29510119Snilay@cs.wisc.edu''') 29610119Snilay@cs.wisc.edu 29710119Snilay@cs.wisc.edu code(''' 29810119Snilay@cs.wisc.edu const Address& addr); 29910119Snilay@cs.wisc.edu 30010119Snilay@cs.wisc.eduTransitionResult doTransitionWorker(${ident}_Event event, 30110119Snilay@cs.wisc.edu ${ident}_State state, 30210119Snilay@cs.wisc.edu ${ident}_State& next_state, 30310119Snilay@cs.wisc.edu''') 30410119Snilay@cs.wisc.edu 30510119Snilay@cs.wisc.edu if self.TBEType != None: 30610119Snilay@cs.wisc.edu code(''' 30712564Sgabeblack@google.com ${{self.TBEType.c_ident}}*& m_tbe_ptr, 30810119Snilay@cs.wisc.edu''') 30910119Snilay@cs.wisc.edu if self.EntryType != None: 31010119Snilay@cs.wisc.edu code(''' 31110119Snilay@cs.wisc.edu ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 31210119Snilay@cs.wisc.edu''') 31310119Snilay@cs.wisc.edu 31410119Snilay@cs.wisc.edu code(''' 31510119Snilay@cs.wisc.edu const Address& addr); 31610119Snilay@cs.wisc.edu 31710119Snilay@cs.wisc.edustd::string m_name; 31810119Snilay@cs.wisc.eduint m_transitions_per_cycle; 31910119Snilay@cs.wisc.eduint m_buffer_size; 32012564Sgabeblack@google.comint m_recycle_latency; 32112564Sgabeblack@google.comstd::map<std::string, std::string> m_cfg; 32210119Snilay@cs.wisc.eduNodeID m_version; 32310119Snilay@cs.wisc.eduNetwork* m_net_ptr; 32410119Snilay@cs.wisc.eduMachineID m_machineID; 32510697SCurtis.Dunham@arm.combool m_is_blocking; 32610747SChris.Emmons@arm.comstd::map<Address, MessageBuffer*> m_block_map; 32710697SCurtis.Dunham@arm.comtypedef std::vector<MessageBuffer*> MsgVecType; 32810747SChris.Emmons@arm.comtypedef m5::hash_map< Address, MsgVecType* > WaitingBufType; 32910119Snilay@cs.wisc.eduWaitingBufType m_waiting_buffers; 33010697SCurtis.Dunham@arm.comint m_max_in_port_rank; 33110747SChris.Emmons@arm.comint m_cur_in_port_rank; 33210119Snilay@cs.wisc.edustatic ${ident}_ProfileDumper s_profileDumper; 33310119Snilay@cs.wisc.edu${ident}_Profiler m_profiler; 33410119Snilay@cs.wisc.edustatic int m_num_controllers; 33510119Snilay@cs.wisc.edu 33610119Snilay@cs.wisc.edu// Internal functions 33710119Snilay@cs.wisc.edu''') 3388801Sgblack@eecs.umich.edu 33911291Sgabor.dozsa@arm.com for func in self.functions: 34011291Sgabor.dozsa@arm.com proto = func.prototype 34111291Sgabor.dozsa@arm.com if proto: 34211291Sgabor.dozsa@arm.com code('$proto') 34311291Sgabor.dozsa@arm.com 34411291Sgabor.dozsa@arm.com if self.EntryType != None: 34511291Sgabor.dozsa@arm.com code(''' 34611291Sgabor.dozsa@arm.com 34711291Sgabor.dozsa@arm.com// Set and Reset for cache_entry variable 34811291Sgabor.dozsa@arm.comvoid set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 34911291Sgabor.dozsa@arm.comvoid unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 35011291Sgabor.dozsa@arm.com''') 3513005Sstever@eecs.umich.edu 3528801Sgblack@eecs.umich.edu if self.TBEType != None: 3533005Sstever@eecs.umich.edu code(''' 35412564Sgabeblack@google.com 3553005Sstever@eecs.umich.edu// Set and Reset for tbe variable 3562566SN/Avoid set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 3577861Sgblack@eecs.umich.eduvoid unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 3587861Sgblack@eecs.umich.edu''') 3597861Sgblack@eecs.umich.edu 3608635Schris.emmons@arm.com code(''' 3618635Schris.emmons@arm.com 3628635Schris.emmons@arm.com// Actions 36313606Sciro.santilli@arm.com''') 36413606Sciro.santilli@arm.com if self.TBEType != None and self.EntryType != None: 36512475Sglenn.bergmans@arm.com for action in self.actions.itervalues(): 36612475Sglenn.bergmans@arm.com code('/** \\brief ${{action.desc}} */') 36712475Sglenn.bergmans@arm.com code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 36812475Sglenn.bergmans@arm.com elif self.TBEType != None: 36912475Sglenn.bergmans@arm.com for action in self.actions.itervalues(): 37012475Sglenn.bergmans@arm.com code('/** \\brief ${{action.desc}} */') 37112475Sglenn.bergmans@arm.com code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);') 37212475Sglenn.bergmans@arm.com elif self.EntryType != None: 37312475Sglenn.bergmans@arm.com for action in self.actions.itervalues(): 37413608Sgiacomo.travaglini@arm.com code('/** \\brief ${{action.desc}} */') 37512475Sglenn.bergmans@arm.com code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 3769061Snilay@cs.wisc.edu else: 3773481Shsul@eecs.umich.edu for action in self.actions.itervalues(): 378 code('/** \\brief ${{action.desc}} */') 379 code('void ${{action.ident}}(const Address& addr);') 380 381 # the controller internal variables 382 code(''' 383 384// Objects 385''') 386 for var in self.objects: 387 th = var.get("template_hack", "") 388 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 389 390 if var.type.ident == "MessageBuffer": 391 self.message_buffer_names.append("m_%s_ptr" % var.c_ident) 392 393 code.dedent() 394 code('};') 395 code('#endif // __${ident}_CONTROLLER_H__') 396 code.write(path, '%s.hh' % c_ident) 397 398 def printControllerCC(self, path): 399 '''Output the actions for performing the actions''' 400 401 code = self.symtab.codeFormatter() 402 ident = self.ident 403 c_ident = "%s_Controller" % self.ident 404 405 code(''' 406/** \\file $c_ident.cc 407 * 408 * Auto generated C++ code started by $__file__:$__line__ 409 * Created by slicc definition of Module "${{self.short}}" 410 */ 411 412#include <cassert> 413#include <sstream> 414#include <string> 415 416#include "base/cprintf.hh" 417#include "mem/protocol/${ident}_Controller.hh" 418#include "mem/protocol/${ident}_State.hh" 419#include "mem/protocol/${ident}_Event.hh" 420#include "mem/protocol/Types.hh" 421#include "mem/ruby/common/Global.hh" 422#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 423#include "mem/ruby/system/System.hh" 424 425using namespace std; 426''') 427 428 # include object classes 429 seen_types = set() 430 for var in self.objects: 431 if var.type.ident not in seen_types and not var.type.isPrimitive: 432 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 433 seen_types.add(var.type.ident) 434 435 code(''' 436$c_ident * 437${c_ident}Params::create() 438{ 439 return new $c_ident(this); 440} 441 442int $c_ident::m_num_controllers = 0; 443${ident}_ProfileDumper $c_ident::s_profileDumper; 444 445// for adding information to the protocol debug trace 446stringstream ${ident}_transitionComment; 447#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 448 449/** \\brief constructor */ 450$c_ident::$c_ident(const Params *p) 451 : AbstractController(p) 452{ 453 m_version = p->version; 454 m_transitions_per_cycle = p->transitions_per_cycle; 455 m_buffer_size = p->buffer_size; 456 m_recycle_latency = p->recycle_latency; 457 m_number_of_TBEs = p->number_of_TBEs; 458 m_is_blocking = false; 459''') 460 # 461 # max_port_rank is used to size vectors and thus should be one plus the 462 # largest port rank 463 # 464 max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1 465 code(' m_max_in_port_rank = $max_port_rank;') 466 code.indent() 467 468 # 469 # After initializing the universal machine parameters, initialize the 470 # this machines config parameters. Also detemine if these configuration 471 # params include a sequencer. This information will be used later for 472 # contecting the sequencer back to the L1 cache controller. 473 # 474 contains_sequencer = False 475 for param in self.config_parameters: 476 if param.name == "sequencer" or param.name == "dma_sequencer": 477 contains_sequencer = True 478 if param.pointer: 479 code('m_${{param.name}}_ptr = p->${{param.name}};') 480 else: 481 code('m_${{param.name}} = p->${{param.name}};') 482 483 # 484 # For the l1 cache controller, add the special atomic support which 485 # includes passing the sequencer a pointer to the controller. 486 # 487 if self.ident == "L1Cache": 488 if not contains_sequencer: 489 self.error("The L1Cache controller must include the sequencer " \ 490 "configuration parameter") 491 492 code(''' 493m_sequencer_ptr->setController(this); 494''') 495 # 496 # For the DMA controller, pass the sequencer a pointer to the 497 # controller. 498 # 499 if self.ident == "DMA": 500 if not contains_sequencer: 501 self.error("The DMA controller must include the sequencer " \ 502 "configuration parameter") 503 504 code(''' 505m_dma_sequencer_ptr->setController(this); 506''') 507 508 code('m_num_controllers++;') 509 for var in self.objects: 510 if var.ident.find("mandatoryQueue") >= 0: 511 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();') 512 513 code.dedent() 514 code(''' 515} 516 517void 518$c_ident::init() 519{ 520 MachineType machine_type; 521 int base; 522 523 m_machineID.type = MachineType_${ident}; 524 m_machineID.num = m_version; 525 526 // initialize objects 527 m_profiler.setVersion(m_version); 528 s_profileDumper.registerProfiler(&m_profiler); 529 530''') 531 532 code.indent() 533 for var in self.objects: 534 vtype = var.type 535 vid = "m_%s_ptr" % var.c_ident 536 if "network" not in var: 537 # Not a network port object 538 if "primitive" in vtype: 539 code('$vid = new ${{vtype.c_ident}};') 540 if "default" in var: 541 code('(*$vid) = ${{var["default"]}};') 542 else: 543 # Normal Object 544 # added by SS 545 if "factory" in var: 546 code('$vid = ${{var["factory"]}};') 547 elif var.ident.find("mandatoryQueue") < 0: 548 th = var.get("template_hack", "") 549 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 550 551 args = "" 552 if "non_obj" not in vtype and not vtype.isEnumeration: 553 if expr.find("TBETable") >= 0: 554 args = "m_number_of_TBEs" 555 else: 556 args = var.get("constructor_hack", "") 557 558 code('$expr($args);') 559 560 code('assert($vid != NULL);') 561 562 if "default" in var: 563 code('*$vid = ${{var["default"]}}; // Object default') 564 elif "default" in vtype: 565 comment = "Type %s default" % vtype.ident 566 code('*$vid = ${{vtype["default"]}}; // $comment') 567 568 # Set ordering 569 if "ordered" in var and "trigger_queue" not in var: 570 # A buffer 571 code('$vid->setOrdering(${{var["ordered"]}});') 572 573 # Set randomization 574 if "random" in var: 575 # A buffer 576 code('$vid->setRandomization(${{var["random"]}});') 577 578 # Set Priority 579 if vtype.isBuffer and \ 580 "rank" in var and "trigger_queue" not in var: 581 code('$vid->setPriority(${{var["rank"]}});') 582 583 else: 584 # Network port object 585 network = var["network"] 586 ordered = var["ordered"] 587 vnet = var["virtual_network"] 588 589 assert var.machine is not None 590 code(''' 591machine_type = string_to_MachineType("${{var.machine.ident}}"); 592base = MachineType_base_number(machine_type); 593$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet); 594''') 595 596 code('assert($vid != NULL);') 597 598 # Set ordering 599 if "ordered" in var: 600 # A buffer 601 code('$vid->setOrdering(${{var["ordered"]}});') 602 603 # Set randomization 604 if "random" in var: 605 # A buffer 606 code('$vid->setRandomization(${{var["random"]}})') 607 608 # Set Priority 609 if "rank" in var: 610 code('$vid->setPriority(${{var["rank"]}})') 611 612 # Set buffer size 613 if vtype.isBuffer: 614 code(''' 615if (m_buffer_size > 0) { 616 $vid->resize(m_buffer_size); 617} 618''') 619 620 # set description (may be overriden later by port def) 621 code(''' 622$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]"); 623 624''') 625 626 if vtype.isBuffer: 627 if "recycle_latency" in var: 628 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});') 629 else: 630 code('$vid->setRecycleLatency(m_recycle_latency);') 631 632 633 # Set the queue consumers 634 code() 635 for port in self.in_ports: 636 code('${{port.code}}.setConsumer(this);') 637 638 # Set the queue descriptions 639 code() 640 for port in self.in_ports: 641 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");') 642 643 # Initialize the transition profiling 644 code() 645 for trans in self.transitions: 646 # Figure out if we stall 647 stall = False 648 for action in trans.actions: 649 if action.ident == "z_stall": 650 stall = True 651 652 # Only possible if it is not a 'z' case 653 if not stall: 654 state = "%s_State_%s" % (self.ident, trans.state.ident) 655 event = "%s_Event_%s" % (self.ident, trans.event.ident) 656 code('m_profiler.possibleTransition($state, $event);') 657 658 code.dedent() 659 code('}') 660 661 has_mandatory_q = False 662 for port in self.in_ports: 663 if port.code.find("mandatoryQueue_ptr") >= 0: 664 has_mandatory_q = True 665 666 if has_mandatory_q: 667 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 668 else: 669 mq_ident = "NULL" 670 671 code(''' 672int 673$c_ident::getNumControllers() 674{ 675 return m_num_controllers; 676} 677 678MessageBuffer* 679$c_ident::getMandatoryQueue() const 680{ 681 return $mq_ident; 682} 683 684const int & 685$c_ident::getVersion() const 686{ 687 return m_version; 688} 689 690const string 691$c_ident::toString() const 692{ 693 return "$c_ident"; 694} 695 696const string 697$c_ident::getName() const 698{ 699 return m_name; 700} 701 702const MachineType 703$c_ident::getMachineType() const 704{ 705 return MachineType_${ident}; 706} 707 708void 709$c_ident::stallBuffer(MessageBuffer* buf, Address addr) 710{ 711 if (m_waiting_buffers.count(addr) == 0) { 712 MsgVecType* msgVec = new MsgVecType; 713 msgVec->resize(m_max_in_port_rank, NULL); 714 m_waiting_buffers[addr] = msgVec; 715 } 716 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf; 717} 718 719void 720$c_ident::wakeUpBuffers(Address addr) 721{ 722 // 723 // Wake up all possible lower rank (i.e. lower priority) buffers that could 724 // be waiting on this message. 725 // 726 for (int in_port_rank = m_cur_in_port_rank - 1; 727 in_port_rank >= 0; 728 in_port_rank--) { 729 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) { 730 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr); 731 } 732 } 733 delete m_waiting_buffers[addr]; 734 m_waiting_buffers.erase(addr); 735} 736 737void 738$c_ident::wakeUpAllBuffers() 739{ 740 // 741 // Wake up all possible buffers that could be waiting on any message. 742 // 743 744 std::vector<MsgVecType*> wokeUpMsgVecs; 745 746 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin(); 747 buf_iter != m_waiting_buffers.end(); 748 ++buf_iter) { 749 for (MsgVecType::iterator vec_iter = buf_iter->second->begin(); 750 vec_iter != buf_iter->second->end(); 751 ++vec_iter) { 752 if (*vec_iter != NULL) { 753 (*vec_iter)->reanalyzeAllMessages(); 754 } 755 } 756 wokeUpMsgVecs.push_back(buf_iter->second); 757 } 758 759 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin(); 760 wb_iter != wokeUpMsgVecs.end(); 761 ++wb_iter) { 762 delete (*wb_iter); 763 } 764 765 m_waiting_buffers.clear(); 766} 767 768void 769$c_ident::blockOnQueue(Address addr, MessageBuffer* port) 770{ 771 m_is_blocking = true; 772 m_block_map[addr] = port; 773} 774 775void 776$c_ident::unblock(Address addr) 777{ 778 m_block_map.erase(addr); 779 if (m_block_map.size() == 0) { 780 m_is_blocking = false; 781 } 782} 783 784void 785$c_ident::print(ostream& out) const 786{ 787 out << "[$c_ident " << m_version << "]"; 788} 789 790void 791$c_ident::printConfig(ostream& out) const 792{ 793 out << "$c_ident config: " << m_name << endl; 794 out << " version: " << m_version << endl; 795 map<string, string>::const_iterator it; 796 for (it = m_cfg.begin(); it != m_cfg.end(); it++) 797 out << " " << it->first << ": " << it->second << endl; 798} 799 800void 801$c_ident::printStats(ostream& out) const 802{ 803''') 804 # 805 # Cache and Memory Controllers have specific profilers associated with 806 # them. Print out these stats before dumping state transition stats. 807 # 808 for param in self.config_parameters: 809 if param.type_ast.type.ident == "CacheMemory" or \ 810 param.type_ast.type.ident == "DirectoryMemory" or \ 811 param.type_ast.type.ident == "MemoryControl": 812 assert(param.pointer) 813 code(' m_${{param.ident}}_ptr->printStats(out);') 814 815 code(''' 816 if (m_version == 0) { 817 s_profileDumper.dumpStats(out); 818 } 819} 820 821void $c_ident::clearStats() { 822''') 823 # 824 # Cache and Memory Controllers have specific profilers associated with 825 # them. These stats must be cleared too. 826 # 827 for param in self.config_parameters: 828 if param.type_ast.type.ident == "CacheMemory" or \ 829 param.type_ast.type.ident == "MemoryControl": 830 assert(param.pointer) 831 code(' m_${{param.ident}}_ptr->clearStats();') 832 833 code(''' 834 m_profiler.clearStats(); 835} 836''') 837 838 if self.EntryType != None: 839 code(''' 840 841// Set and Reset for cache_entry variable 842void 843$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 844{ 845 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 846} 847 848void 849$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 850{ 851 m_cache_entry_ptr = 0; 852} 853''') 854 855 if self.TBEType != None: 856 code(''' 857 858// Set and Reset for tbe variable 859void 860$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 861{ 862 m_tbe_ptr = m_new_tbe; 863} 864 865void 866$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 867{ 868 m_tbe_ptr = NULL; 869} 870''') 871 872 code(''' 873 874// Actions 875''') 876 if self.TBEType != None and self.EntryType != None: 877 for action in self.actions.itervalues(): 878 if "c_code" not in action: 879 continue 880 881 code(''' 882/** \\brief ${{action.desc}} */ 883void 884$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 885{ 886 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 887 ${{action["c_code"]}} 888} 889 890''') 891 elif self.TBEType != None: 892 for action in self.actions.itervalues(): 893 if "c_code" not in action: 894 continue 895 896 code(''' 897/** \\brief ${{action.desc}} */ 898void 899$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 900{ 901 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 902 ${{action["c_code"]}} 903} 904 905''') 906 elif self.EntryType != None: 907 for action in self.actions.itervalues(): 908 if "c_code" not in action: 909 continue 910 911 code(''' 912/** \\brief ${{action.desc}} */ 913void 914$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 915{ 916 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 917 ${{action["c_code"]}} 918} 919 920''') 921 else: 922 for action in self.actions.itervalues(): 923 if "c_code" not in action: 924 continue 925 926 code(''' 927/** \\brief ${{action.desc}} */ 928void 929$c_ident::${{action.ident}}(const Address& addr) 930{ 931 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 932 ${{action["c_code"]}} 933} 934 935''') 936 code.write(path, "%s.cc" % c_ident) 937 938 def printCWakeup(self, path): 939 '''Output the wakeup loop for the events''' 940 941 code = self.symtab.codeFormatter() 942 ident = self.ident 943 944 code(''' 945// Auto generated C++ code started by $__file__:$__line__ 946// ${ident}: ${{self.short}} 947 948#include <cassert> 949 950#include "base/misc.hh" 951#include "mem/ruby/common/Global.hh" 952#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 953#include "mem/protocol/${ident}_Controller.hh" 954#include "mem/protocol/${ident}_State.hh" 955#include "mem/protocol/${ident}_Event.hh" 956#include "mem/protocol/Types.hh" 957#include "mem/ruby/system/System.hh" 958 959using namespace std; 960 961void 962${ident}_Controller::wakeup() 963{ 964 int counter = 0; 965 while (true) { 966 // Some cases will put us into an infinite loop without this limit 967 assert(counter <= m_transitions_per_cycle); 968 if (counter == m_transitions_per_cycle) { 969 // Count how often we are fully utilized 970 g_system_ptr->getProfiler()->controllerBusy(m_machineID); 971 972 // Wakeup in another cycle and try again 973 g_eventQueue_ptr->scheduleEvent(this, 1); 974 break; 975 } 976''') 977 978 code.indent() 979 code.indent() 980 981 # InPorts 982 # 983 for port in self.in_ports: 984 code.indent() 985 code('// ${ident}InPort $port') 986 if port.pairs.has_key("rank"): 987 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};') 988 else: 989 code('m_cur_in_port_rank = 0;') 990 code('${{port["c_code_in_port"]}}') 991 code.dedent() 992 993 code('') 994 995 code.dedent() 996 code.dedent() 997 code(''' 998 break; // If we got this far, we have nothing left todo 999 } 1000 // g_eventQueue_ptr->scheduleEvent(this, 1); 1001} 1002''') 1003 1004 code.write(path, "%s_Wakeup.cc" % self.ident) 1005 1006 def printCSwitch(self, path): 1007 '''Output switch statement for transition table''' 1008 1009 code = self.symtab.codeFormatter() 1010 ident = self.ident 1011 1012 code(''' 1013// Auto generated C++ code started by $__file__:$__line__ 1014// ${ident}: ${{self.short}} 1015 1016#include <cassert> 1017 1018#include "base/misc.hh" 1019#include "base/trace.hh" 1020#include "mem/ruby/common/Global.hh" 1021#include "mem/protocol/${ident}_Controller.hh" 1022#include "mem/protocol/${ident}_State.hh" 1023#include "mem/protocol/${ident}_Event.hh" 1024#include "mem/protocol/Types.hh" 1025#include "mem/ruby/system/System.hh" 1026 1027#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1028 1029#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1030#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1031 1032TransitionResult 1033${ident}_Controller::doTransition(${ident}_Event event, 1034''') 1035 if self.EntryType != None: 1036 code(''' 1037 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1038''') 1039 if self.TBEType != None: 1040 code(''' 1041 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1042''') 1043 code(''' 1044 const Address &addr) 1045{ 1046''') 1047 if self.TBEType != None and self.EntryType != None: 1048 code('${ident}_State state = ${ident}_getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1049 elif self.TBEType != None: 1050 code('${ident}_State state = ${ident}_getState(m_tbe_ptr, addr);') 1051 elif self.EntryType != None: 1052 code('${ident}_State state = ${ident}_getState(m_cache_entry_ptr, addr);') 1053 else: 1054 code('${ident}_State state = ${ident}_getState(addr);') 1055 1056 code(''' 1057 ${ident}_State next_state = state; 1058 1059 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1060 *this, 1061 g_eventQueue_ptr->getTime(), 1062 ${ident}_State_to_string(state), 1063 ${ident}_Event_to_string(event), 1064 addr); 1065 1066 TransitionResult result = 1067''') 1068 if self.TBEType != None and self.EntryType != None: 1069 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1070 elif self.TBEType != None: 1071 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1072 elif self.EntryType != None: 1073 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1074 else: 1075 code('doTransitionWorker(event, state, next_state, addr);') 1076 1077 code(''' 1078 if (result == TransitionResult_Valid) { 1079 DPRINTF(RubyGenerated, "next_state: %s\\n", 1080 ${ident}_State_to_string(next_state)); 1081 m_profiler.countTransition(state, event); 1082 DPRINTFR(ProtocolTrace, "%7d %3s %10s%20s %6s>%-6s %s %s\\n", 1083 g_eventQueue_ptr->getTime(), m_version, "${ident}", 1084 ${ident}_Event_to_string(event), 1085 ${ident}_State_to_string(state), 1086 ${ident}_State_to_string(next_state), 1087 addr, GET_TRANSITION_COMMENT()); 1088 1089 CLEAR_TRANSITION_COMMENT(); 1090''') 1091 if self.TBEType != None and self.EntryType != None: 1092 code('${ident}_setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1093 elif self.TBEType != None: 1094 code('${ident}_setState(m_tbe_ptr, addr, next_state);') 1095 elif self.EntryType != None: 1096 code('${ident}_setState(m_cache_entry_ptr, addr, next_state);') 1097 else: 1098 code('${ident}_setState(addr, next_state);') 1099 1100 code(''' 1101 } else if (result == TransitionResult_ResourceStall) { 1102 DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n", 1103 g_eventQueue_ptr->getTime(), m_version, "${ident}", 1104 ${ident}_Event_to_string(event), 1105 ${ident}_State_to_string(state), 1106 ${ident}_State_to_string(next_state), 1107 addr, "Resource Stall"); 1108 } else if (result == TransitionResult_ProtocolStall) { 1109 DPRINTF(RubyGenerated, "stalling\\n"); 1110 DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n", 1111 g_eventQueue_ptr->getTime(), m_version, "${ident}", 1112 ${ident}_Event_to_string(event), 1113 ${ident}_State_to_string(state), 1114 ${ident}_State_to_string(next_state), 1115 addr, "Protocol Stall"); 1116 } 1117 1118 return result; 1119} 1120 1121TransitionResult 1122${ident}_Controller::doTransitionWorker(${ident}_Event event, 1123 ${ident}_State state, 1124 ${ident}_State& next_state, 1125''') 1126 1127 if self.TBEType != None: 1128 code(''' 1129 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1130''') 1131 if self.EntryType != None: 1132 code(''' 1133 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1134''') 1135 code(''' 1136 const Address& addr) 1137{ 1138 switch(HASH_FUN(state, event)) { 1139''') 1140 1141 # This map will allow suppress generating duplicate code 1142 cases = orderdict() 1143 1144 for trans in self.transitions: 1145 case_string = "%s_State_%s, %s_Event_%s" % \ 1146 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1147 1148 case = self.symtab.codeFormatter() 1149 # Only set next_state if it changes 1150 if trans.state != trans.nextState: 1151 ns_ident = trans.nextState.ident 1152 case('next_state = ${ident}_State_${ns_ident};') 1153 1154 actions = trans.actions 1155 1156 # Check for resources 1157 case_sorter = [] 1158 res = trans.resources 1159 for key,val in res.iteritems(): 1160 if key.type.ident != "DNUCAStopTable": 1161 val = ''' 1162if (!%s.areNSlotsAvailable(%s)) 1163 return TransitionResult_ResourceStall; 1164''' % (key.code, val) 1165 case_sorter.append(val) 1166 1167 1168 # Emit the code sequences in a sorted order. This makes the 1169 # output deterministic (without this the output order can vary 1170 # since Map's keys() on a vector of pointers is not deterministic 1171 for c in sorted(case_sorter): 1172 case("$c") 1173 1174 # Figure out if we stall 1175 stall = False 1176 for action in actions: 1177 if action.ident == "z_stall": 1178 stall = True 1179 break 1180 1181 if stall: 1182 case('return TransitionResult_ProtocolStall;') 1183 else: 1184 if self.TBEType != None and self.EntryType != None: 1185 for action in actions: 1186 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1187 elif self.TBEType != None: 1188 for action in actions: 1189 case('${{action.ident}}(m_tbe_ptr, addr);') 1190 elif self.EntryType != None: 1191 for action in actions: 1192 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1193 else: 1194 for action in actions: 1195 case('${{action.ident}}(addr);') 1196 case('return TransitionResult_Valid;') 1197 1198 case = str(case) 1199 1200 # Look to see if this transition code is unique. 1201 if case not in cases: 1202 cases[case] = [] 1203 1204 cases[case].append(case_string) 1205 1206 # Walk through all of the unique code blocks and spit out the 1207 # corresponding case statement elements 1208 for case,transitions in cases.iteritems(): 1209 # Iterative over all the multiple transitions that share 1210 # the same code 1211 for trans in transitions: 1212 code(' case HASH_FUN($trans):') 1213 code(' $case') 1214 1215 code(''' 1216 default: 1217 fatal("Invalid transition\\n" 1218 "version: %d time: %d addr: %s event: %s state: %s\\n", 1219 m_version, g_eventQueue_ptr->getTime(), addr, event, state); 1220 } 1221 return TransitionResult_Valid; 1222} 1223''') 1224 code.write(path, "%s_Transitions.cc" % self.ident) 1225 1226 def printProfileDumperHH(self, path): 1227 code = self.symtab.codeFormatter() 1228 ident = self.ident 1229 1230 code(''' 1231// Auto generated C++ code started by $__file__:$__line__ 1232// ${ident}: ${{self.short}} 1233 1234#ifndef __${ident}_PROFILE_DUMPER_HH__ 1235#define __${ident}_PROFILE_DUMPER_HH__ 1236 1237#include <cassert> 1238#include <iostream> 1239#include <vector> 1240 1241#include "${ident}_Profiler.hh" 1242#include "${ident}_Event.hh" 1243 1244typedef std::vector<${ident}_Profiler *> ${ident}_profilers; 1245 1246class ${ident}_ProfileDumper 1247{ 1248 public: 1249 ${ident}_ProfileDumper(); 1250 void registerProfiler(${ident}_Profiler* profiler); 1251 void dumpStats(std::ostream& out) const; 1252 1253 private: 1254 ${ident}_profilers m_profilers; 1255}; 1256 1257#endif // __${ident}_PROFILE_DUMPER_HH__ 1258''') 1259 code.write(path, "%s_ProfileDumper.hh" % self.ident) 1260 1261 def printProfileDumperCC(self, path): 1262 code = self.symtab.codeFormatter() 1263 ident = self.ident 1264 1265 code(''' 1266// Auto generated C++ code started by $__file__:$__line__ 1267// ${ident}: ${{self.short}} 1268 1269#include "mem/protocol/${ident}_ProfileDumper.hh" 1270 1271${ident}_ProfileDumper::${ident}_ProfileDumper() 1272{ 1273} 1274 1275void 1276${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler) 1277{ 1278 m_profilers.push_back(profiler); 1279} 1280 1281void 1282${ident}_ProfileDumper::dumpStats(std::ostream& out) const 1283{ 1284 out << " --- ${ident} ---\\n"; 1285 out << " - Event Counts -\\n"; 1286 for (${ident}_Event event = ${ident}_Event_FIRST; 1287 event < ${ident}_Event_NUM; 1288 ++event) { 1289 out << (${ident}_Event) event << " ["; 1290 uint64 total = 0; 1291 for (int i = 0; i < m_profilers.size(); i++) { 1292 out << m_profilers[i]->getEventCount(event) << " "; 1293 total += m_profilers[i]->getEventCount(event); 1294 } 1295 out << "] " << total << "\\n"; 1296 } 1297 out << "\\n"; 1298 out << " - Transitions -\\n"; 1299 for (${ident}_State state = ${ident}_State_FIRST; 1300 state < ${ident}_State_NUM; 1301 ++state) { 1302 for (${ident}_Event event = ${ident}_Event_FIRST; 1303 event < ${ident}_Event_NUM; 1304 ++event) { 1305 if (m_profilers[0]->isPossible(state, event)) { 1306 out << (${ident}_State) state << " " 1307 << (${ident}_Event) event << " ["; 1308 uint64 total = 0; 1309 for (int i = 0; i < m_profilers.size(); i++) { 1310 out << m_profilers[i]->getTransitionCount(state, event) << " "; 1311 total += m_profilers[i]->getTransitionCount(state, event); 1312 } 1313 out << "] " << total << "\\n"; 1314 } 1315 } 1316 out << "\\n"; 1317 } 1318} 1319''') 1320 code.write(path, "%s_ProfileDumper.cc" % self.ident) 1321 1322 def printProfilerHH(self, path): 1323 code = self.symtab.codeFormatter() 1324 ident = self.ident 1325 1326 code(''' 1327// Auto generated C++ code started by $__file__:$__line__ 1328// ${ident}: ${{self.short}} 1329 1330#ifndef __${ident}_PROFILER_HH__ 1331#define __${ident}_PROFILER_HH__ 1332 1333#include <cassert> 1334#include <iostream> 1335 1336#include "mem/ruby/common/Global.hh" 1337#include "mem/protocol/${ident}_State.hh" 1338#include "mem/protocol/${ident}_Event.hh" 1339 1340class ${ident}_Profiler 1341{ 1342 public: 1343 ${ident}_Profiler(); 1344 void setVersion(int version); 1345 void countTransition(${ident}_State state, ${ident}_Event event); 1346 void possibleTransition(${ident}_State state, ${ident}_Event event); 1347 uint64 getEventCount(${ident}_Event event); 1348 bool isPossible(${ident}_State state, ${ident}_Event event); 1349 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 1350 void clearStats(); 1351 1352 private: 1353 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 1354 int m_event_counters[${ident}_Event_NUM]; 1355 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 1356 int m_version; 1357}; 1358 1359#endif // __${ident}_PROFILER_HH__ 1360''') 1361 code.write(path, "%s_Profiler.hh" % self.ident) 1362 1363 def printProfilerCC(self, path): 1364 code = self.symtab.codeFormatter() 1365 ident = self.ident 1366 1367 code(''' 1368// Auto generated C++ code started by $__file__:$__line__ 1369// ${ident}: ${{self.short}} 1370 1371#include <cassert> 1372 1373#include "mem/protocol/${ident}_Profiler.hh" 1374 1375${ident}_Profiler::${ident}_Profiler() 1376{ 1377 for (int state = 0; state < ${ident}_State_NUM; state++) { 1378 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1379 m_possible[state][event] = false; 1380 m_counters[state][event] = 0; 1381 } 1382 } 1383 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1384 m_event_counters[event] = 0; 1385 } 1386} 1387 1388void 1389${ident}_Profiler::setVersion(int version) 1390{ 1391 m_version = version; 1392} 1393 1394void 1395${ident}_Profiler::clearStats() 1396{ 1397 for (int state = 0; state < ${ident}_State_NUM; state++) { 1398 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1399 m_counters[state][event] = 0; 1400 } 1401 } 1402 1403 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1404 m_event_counters[event] = 0; 1405 } 1406} 1407void 1408${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1409{ 1410 assert(m_possible[state][event]); 1411 m_counters[state][event]++; 1412 m_event_counters[event]++; 1413} 1414void 1415${ident}_Profiler::possibleTransition(${ident}_State state, 1416 ${ident}_Event event) 1417{ 1418 m_possible[state][event] = true; 1419} 1420 1421uint64 1422${ident}_Profiler::getEventCount(${ident}_Event event) 1423{ 1424 return m_event_counters[event]; 1425} 1426 1427bool 1428${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event) 1429{ 1430 return m_possible[state][event]; 1431} 1432 1433uint64 1434${ident}_Profiler::getTransitionCount(${ident}_State state, 1435 ${ident}_Event event) 1436{ 1437 return m_counters[state][event]; 1438} 1439 1440''') 1441 code.write(path, "%s_Profiler.cc" % self.ident) 1442 1443 # ************************** 1444 # ******* HTML Files ******* 1445 # ************************** 1446 def frameRef(self, click_href, click_target, over_href, over_num, text): 1447 code = self.symtab.codeFormatter(fix_newlines=False) 1448 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1449 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1450 parent.frames[$over_num].location='$over_href' 1451 }\"> 1452 ${{html.formatShorthand(text)}} 1453 </A>""") 1454 return str(code) 1455 1456 def writeHTMLFiles(self, path): 1457 # Create table with no row hilighted 1458 self.printHTMLTransitions(path, None) 1459 1460 # Generate transition tables 1461 for state in self.states.itervalues(): 1462 self.printHTMLTransitions(path, state) 1463 1464 # Generate action descriptions 1465 for action in self.actions.itervalues(): 1466 name = "%s_action_%s.html" % (self.ident, action.ident) 1467 code = html.createSymbol(action, "Action") 1468 code.write(path, name) 1469 1470 # Generate state descriptions 1471 for state in self.states.itervalues(): 1472 name = "%s_State_%s.html" % (self.ident, state.ident) 1473 code = html.createSymbol(state, "State") 1474 code.write(path, name) 1475 1476 # Generate event descriptions 1477 for event in self.events.itervalues(): 1478 name = "%s_Event_%s.html" % (self.ident, event.ident) 1479 code = html.createSymbol(event, "Event") 1480 code.write(path, name) 1481 1482 def printHTMLTransitions(self, path, active_state): 1483 code = self.symtab.codeFormatter() 1484 1485 code(''' 1486<HTML> 1487<BODY link="blue" vlink="blue"> 1488 1489<H1 align="center">${{html.formatShorthand(self.short)}}: 1490''') 1491 code.indent() 1492 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1493 mid = machine.ident 1494 if i != 0: 1495 extra = " - " 1496 else: 1497 extra = "" 1498 if machine == self: 1499 code('$extra$mid') 1500 else: 1501 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1502 code.dedent() 1503 1504 code(""" 1505</H1> 1506 1507<TABLE border=1> 1508<TR> 1509 <TH> </TH> 1510""") 1511 1512 for event in self.events.itervalues(): 1513 href = "%s_Event_%s.html" % (self.ident, event.ident) 1514 ref = self.frameRef(href, "Status", href, "1", event.short) 1515 code('<TH bgcolor=white>$ref</TH>') 1516 1517 code('</TR>') 1518 # -- Body of table 1519 for state in self.states.itervalues(): 1520 # -- Each row 1521 if state == active_state: 1522 color = "yellow" 1523 else: 1524 color = "white" 1525 1526 click = "%s_table_%s.html" % (self.ident, state.ident) 1527 over = "%s_State_%s.html" % (self.ident, state.ident) 1528 text = html.formatShorthand(state.short) 1529 ref = self.frameRef(click, "Table", over, "1", state.short) 1530 code(''' 1531<TR> 1532 <TH bgcolor=$color>$ref</TH> 1533''') 1534 1535 # -- One column for each event 1536 for event in self.events.itervalues(): 1537 trans = self.table.get((state,event), None) 1538 if trans is None: 1539 # This is the no transition case 1540 if state == active_state: 1541 color = "#C0C000" 1542 else: 1543 color = "lightgrey" 1544 1545 code('<TD bgcolor=$color> </TD>') 1546 continue 1547 1548 next = trans.nextState 1549 stall_action = False 1550 1551 # -- Get the actions 1552 for action in trans.actions: 1553 if action.ident == "z_stall" or \ 1554 action.ident == "zz_recycleMandatoryQueue": 1555 stall_action = True 1556 1557 # -- Print out "actions/next-state" 1558 if stall_action: 1559 if state == active_state: 1560 color = "#C0C000" 1561 else: 1562 color = "lightgrey" 1563 1564 elif active_state and next.ident == active_state.ident: 1565 color = "aqua" 1566 elif state == active_state: 1567 color = "yellow" 1568 else: 1569 color = "white" 1570 1571 code('<TD bgcolor=$color>') 1572 for action in trans.actions: 1573 href = "%s_action_%s.html" % (self.ident, action.ident) 1574 ref = self.frameRef(href, "Status", href, "1", 1575 action.short) 1576 code(' $ref') 1577 if next != state: 1578 if trans.actions: 1579 code('/') 1580 click = "%s_table_%s.html" % (self.ident, next.ident) 1581 over = "%s_State_%s.html" % (self.ident, next.ident) 1582 ref = self.frameRef(click, "Table", over, "1", next.short) 1583 code("$ref") 1584 code("</TD>") 1585 1586 # -- Each row 1587 if state == active_state: 1588 color = "yellow" 1589 else: 1590 color = "white" 1591 1592 click = "%s_table_%s.html" % (self.ident, state.ident) 1593 over = "%s_State_%s.html" % (self.ident, state.ident) 1594 ref = self.frameRef(click, "Table", over, "1", state.short) 1595 code(''' 1596 <TH bgcolor=$color>$ref</TH> 1597</TR> 1598''') 1599 code(''' 1600<!- Column footer-> 1601<TR> 1602 <TH> </TH> 1603''') 1604 1605 for event in self.events.itervalues(): 1606 href = "%s_Event_%s.html" % (self.ident, event.ident) 1607 ref = self.frameRef(href, "Status", href, "1", event.short) 1608 code('<TH bgcolor=white>$ref</TH>') 1609 code(''' 1610</TR> 1611</TABLE> 1612</BODY></HTML> 1613''') 1614 1615 1616 if active_state: 1617 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1618 else: 1619 name = "%s_table.html" % self.ident 1620 code.write(path, name) 1621 1622__all__ = [ "StateMachine" ] 1623