StateMachine.py revision 9801
111598Sandreas.sandberg@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.eduimport re 343005Sstever@eecs.umich.edu 353005Sstever@eecs.umich.edupython_class_map = { 363005Sstever@eecs.umich.edu "int": "Int", 373005Sstever@eecs.umich.edu "uint32_t" : "UInt32", 383005Sstever@eecs.umich.edu "std::string": "String", 393005Sstever@eecs.umich.edu "bool": "Bool", 403005Sstever@eecs.umich.edu "CacheMemory": "RubyCache", 413005Sstever@eecs.umich.edu "WireBuffer": "RubyWireBuffer", 4210118Snilay@cs.wisc.edu "Sequencer": "RubySequencer", 433005Sstever@eecs.umich.edu "DirectoryMemory": "RubyDirectoryMemory", 446654Snate@binkert.org "MemoryControl": "MemoryControl", 456654Snate@binkert.org "DMASequencer": "DMASequencer", 462889SN/A "Prefetcher":"Prefetcher", 472710SN/A "Cycles":"Cycles", 486654Snate@binkert.org } 496654Snate@binkert.org 506654Snate@binkert.orgclass StateMachine(Symbol): 515457Ssaidi@eecs.umich.edu def __init__(self, symtab, ident, location, pairs, config_parameters): 5211670Sandreas.hansson@arm.com super(StateMachine, self).__init__(symtab, ident, location, pairs) 5310118Snilay@cs.wisc.edu self.table = None 5411670Sandreas.hansson@arm.com self.config_parameters = config_parameters 556654Snate@binkert.org self.prefetchers = [] 5611682Sandreas.hansson@arm.com 5711682Sandreas.hansson@arm.com for param in config_parameters: 5811682Sandreas.hansson@arm.com if param.pointer: 5911682Sandreas.hansson@arm.com var = Var(symtab, param.name, location, param.type_ast.type, 6011682Sandreas.hansson@arm.com "(*m_%s_ptr)" % param.name, {}, self) 6111682Sandreas.hansson@arm.com else: 6211790Sjungma@eit.uni-kl.de var = Var(symtab, param.name, location, param.type_ast.type, 6311682Sandreas.hansson@arm.com "m_%s" % param.name, {}, self) 6411682Sandreas.hansson@arm.com self.symtab.registerSym(param.name, var) 653444Sktlim@umich.edu if str(param.type_ast.type) == "Prefetcher": 663304Sstever@eecs.umich.edu self.prefetchers.append(var) 679653SAndreas.Sandberg@ARM.com 689653SAndreas.Sandberg@ARM.com self.states = orderdict() 699653SAndreas.Sandberg@ARM.com self.events = orderdict() 709653SAndreas.Sandberg@ARM.com self.actions = orderdict() 719653SAndreas.Sandberg@ARM.com self.request_types = orderdict() 729653SAndreas.Sandberg@ARM.com self.transitions = [] 739653SAndreas.Sandberg@ARM.com self.in_ports = [] 7410594Sgabeblack@google.com self.functions = [] 7510594Sgabeblack@google.com self.objects = [] 7610594Sgabeblack@google.com self.TBEType = None 7710594Sgabeblack@google.com self.EntryType = None 7810594Sgabeblack@google.com 7910594Sgabeblack@google.com def __repr__(self): 8010594Sgabeblack@google.com return "[StateMachine: %s]" % self.ident 8110594Sgabeblack@google.com 8210594Sgabeblack@google.com def addState(self, state): 8310594Sgabeblack@google.com assert self.table is None 8410594Sgabeblack@google.com self.states[state.ident] = state 8510119Snilay@cs.wisc.edu 8610594Sgabeblack@google.com def addEvent(self, event): 8710119Snilay@cs.wisc.edu assert self.table is None 8810594Sgabeblack@google.com self.events[event.ident] = event 8910594Sgabeblack@google.com 9010119Snilay@cs.wisc.edu def addAction(self, action): 9110594Sgabeblack@google.com assert self.table is None 9210119Snilay@cs.wisc.edu 9310594Sgabeblack@google.com # Check for duplicate action 9410119Snilay@cs.wisc.edu for other in self.actions.itervalues(): 9510119Snilay@cs.wisc.edu if action.ident == other.ident: 9610594Sgabeblack@google.com action.warning("Duplicate action definition: %s" % action.ident) 9710119Snilay@cs.wisc.edu action.error("Duplicate action definition: %s" % action.ident) 9810512SAli.Saidi@ARM.com if action.short == other.short: 9910512SAli.Saidi@ARM.com other.warning("Duplicate action shorthand: %s" % other.ident) 10010594Sgabeblack@google.com other.warning(" shorthand = %s" % other.short) 10110780SCurtis.Dunham@arm.com action.warning("Duplicate action shorthand: %s" % action.ident) 10211598Sandreas.sandberg@arm.com action.error(" shorthand = %s" % action.short) 10311598Sandreas.sandberg@arm.com 10410119Snilay@cs.wisc.edu self.actions[action.ident] = action 10510119Snilay@cs.wisc.edu 10610119Snilay@cs.wisc.edu def addRequestType(self, request_type): 10710119Snilay@cs.wisc.edu assert self.table is None 1082566SN/A self.request_types[request_type.ident] = request_type 10910119Snilay@cs.wisc.edu 11010119Snilay@cs.wisc.edu def addTransition(self, trans): 1119665Sandreas.hansson@arm.com assert self.table is None 11210119Snilay@cs.wisc.edu self.transitions.append(trans) 11310119Snilay@cs.wisc.edu 11410119Snilay@cs.wisc.edu def addInPort(self, var): 11510119Snilay@cs.wisc.edu self.in_ports.append(var) 11610119Snilay@cs.wisc.edu 11710119Snilay@cs.wisc.edu def addFunc(self, func): 11810119Snilay@cs.wisc.edu # register func in the symbol table 11910119Snilay@cs.wisc.edu self.symtab.registerSym(str(func), func) 12010119Snilay@cs.wisc.edu self.functions.append(func) 12110119Snilay@cs.wisc.edu 12210119Snilay@cs.wisc.edu def addObject(self, obj): 12310119Snilay@cs.wisc.edu self.objects.append(obj) 12410119Snilay@cs.wisc.edu 12510119Snilay@cs.wisc.edu def addType(self, type): 12610119Snilay@cs.wisc.edu type_ident = '%s' % type.c_ident 12710119Snilay@cs.wisc.edu 12810119Snilay@cs.wisc.edu if type_ident == "%s_TBE" %self.ident: 12910119Snilay@cs.wisc.edu if self.TBEType != None: 13010119Snilay@cs.wisc.edu self.error("Multiple Transaction Buffer types in a " \ 13110119Snilay@cs.wisc.edu "single machine."); 13210119Snilay@cs.wisc.edu self.TBEType = type 13310119Snilay@cs.wisc.edu 13410119Snilay@cs.wisc.edu elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 13510119Snilay@cs.wisc.edu if self.EntryType != None: 13610119Snilay@cs.wisc.edu self.error("Multiple AbstractCacheEntry types in a " \ 13710119Snilay@cs.wisc.edu "single machine."); 13810119Snilay@cs.wisc.edu self.EntryType = type 13910119Snilay@cs.wisc.edu 14010119Snilay@cs.wisc.edu # Needs to be called before accessing the table 14110119Snilay@cs.wisc.edu def buildTable(self): 14210119Snilay@cs.wisc.edu assert self.table is None 14310119Snilay@cs.wisc.edu 14410119Snilay@cs.wisc.edu table = {} 14510119Snilay@cs.wisc.edu 14611839SCurtis.Dunham@arm.com for trans in self.transitions: 14710119Snilay@cs.wisc.edu # Track which actions we touch so we know if we use them 14810119Snilay@cs.wisc.edu # all -- really this should be done for all symbols as 14910119Snilay@cs.wisc.edu # part of the symbol table, then only trigger it for 15010119Snilay@cs.wisc.edu # Actions, States, Events, etc. 15110119Snilay@cs.wisc.edu 15210119Snilay@cs.wisc.edu for action in trans.actions: 15310119Snilay@cs.wisc.edu action.used = True 15410519Snilay@cs.wisc.edu 15510519Snilay@cs.wisc.edu index = (trans.state, trans.event) 15610119Snilay@cs.wisc.edu if index in table: 15710119Snilay@cs.wisc.edu table[index].warning("Duplicate transition: %s" % table[index]) 15810119Snilay@cs.wisc.edu trans.error("Duplicate transition: %s" % trans) 15910119Snilay@cs.wisc.edu table[index] = trans 16010119Snilay@cs.wisc.edu 16110547Snilay@cs.wisc.edu # Look at all actions to make sure we used them all 16210547Snilay@cs.wisc.edu for action in self.actions.itervalues(): 16310547Snilay@cs.wisc.edu if not action.used: 16410547Snilay@cs.wisc.edu error_msg = "Unused action: %s" % action.ident 16510119Snilay@cs.wisc.edu if "desc" in action: 16610119Snilay@cs.wisc.edu error_msg += ", " + action.desc 16710119Snilay@cs.wisc.edu action.warning(error_msg) 16810119Snilay@cs.wisc.edu self.table = table 16910119Snilay@cs.wisc.edu 17010119Snilay@cs.wisc.edu def writeCodeFiles(self, path, includes): 17110119Snilay@cs.wisc.edu self.printControllerPython(path) 17210119Snilay@cs.wisc.edu self.printControllerHH(path) 17310120Snilay@cs.wisc.edu self.printControllerCC(path, includes) 17410120Snilay@cs.wisc.edu self.printCSwitch(path) 17510119Snilay@cs.wisc.edu self.printCWakeup(path, includes) 17611598Sandreas.sandberg@arm.com 17710120Snilay@cs.wisc.edu def printControllerPython(self, path): 17810120Snilay@cs.wisc.edu code = self.symtab.codeFormatter() 17910119Snilay@cs.wisc.edu ident = self.ident 18011598Sandreas.sandberg@arm.com py_ident = "%s_Controller" % ident 18111150Smitch.hayenga@arm.com c_ident = "%s_Controller" % self.ident 18211150Smitch.hayenga@arm.com code(''' 18311150Smitch.hayenga@arm.comfrom m5.params import * 18410119Snilay@cs.wisc.edufrom m5.SimObject import SimObject 1852995SN/Afrom Controller import RubyController 18610119Snilay@cs.wisc.edu 18710119Snilay@cs.wisc.educlass $py_ident(RubyController): 18810119Snilay@cs.wisc.edu type = '$py_ident' 18910119Snilay@cs.wisc.edu cxx_header = 'mem/protocol/${c_ident}.hh' 19010119Snilay@cs.wisc.edu''') 19110780SCurtis.Dunham@arm.com code.indent() 19210119Snilay@cs.wisc.edu for param in self.config_parameters: 19310119Snilay@cs.wisc.edu dflt_str = '' 19410119Snilay@cs.wisc.edu if param.default is not None: 1953304Sstever@eecs.umich.edu dflt_str = str(param.default) + ', ' 19610119Snilay@cs.wisc.edu if python_class_map.has_key(param.type_ast.type.c_ident): 19710119Snilay@cs.wisc.edu python_type = python_class_map[param.type_ast.type.c_ident] 19810119Snilay@cs.wisc.edu code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 19910119Snilay@cs.wisc.edu else: 20010119Snilay@cs.wisc.edu self.error("Unknown c++ to python class conversion for c++ " \ 20110119Snilay@cs.wisc.edu "type: '%s'. Please update the python_class_map " \ 2026135Sgblack@eecs.umich.edu "in StateMachine.py", param.type_ast.type.c_ident) 20310608Sdam.sunwoo@arm.com code.dedent() 20410608Sdam.sunwoo@arm.com code.write(path, '%s.py' % py_ident) 20510608Sdam.sunwoo@arm.com 20610608Sdam.sunwoo@arm.com 20710608Sdam.sunwoo@arm.com def printControllerHH(self, path): 20810608Sdam.sunwoo@arm.com '''Output the method declarations for the class declaration''' 20910608Sdam.sunwoo@arm.com code = self.symtab.codeFormatter() 21010119Snilay@cs.wisc.edu ident = self.ident 21110119Snilay@cs.wisc.edu c_ident = "%s_Controller" % self.ident 21210119Snilay@cs.wisc.edu 21310608Sdam.sunwoo@arm.com code(''' 21410608Sdam.sunwoo@arm.com/** \\file $c_ident.hh 21510119Snilay@cs.wisc.edu * 21610119Snilay@cs.wisc.edu * Auto generated C++ code started by $__file__:$__line__ 21710119Snilay@cs.wisc.edu * Created by slicc definition of Module "${{self.short}}" 2183819Shsul@eecs.umich.edu */ 21911251Sradhika.jagtap@ARM.com 22011251Sradhika.jagtap@ARM.com#ifndef __${ident}_CONTROLLER_HH__ 22111251Sradhika.jagtap@ARM.com#define __${ident}_CONTROLLER_HH__ 22211251Sradhika.jagtap@ARM.com 22311251Sradhika.jagtap@ARM.com#include <iostream> 22411251Sradhika.jagtap@ARM.com#include <sstream> 22511251Sradhika.jagtap@ARM.com#include <string> 22611251Sradhika.jagtap@ARM.com 22711251Sradhika.jagtap@ARM.com#include "mem/protocol/TransitionResult.hh" 22811251Sradhika.jagtap@ARM.com#include "mem/protocol/Types.hh" 22911251Sradhika.jagtap@ARM.com#include "mem/ruby/common/Consumer.hh" 23010119Snilay@cs.wisc.edu#include "mem/ruby/common/Global.hh" 23111183Serfan.azarkhish@unibo.it#include "mem/ruby/slicc_interface/AbstractController.hh" 23210119Snilay@cs.wisc.edu#include "params/$c_ident.hh" 23310118Snilay@cs.wisc.edu''') 23410119Snilay@cs.wisc.edu 2359827Sakash.bagdia@arm.com seen_types = set() 23610119Snilay@cs.wisc.edu has_peer = False 23710119Snilay@cs.wisc.edu for var in self.objects: 23810119Snilay@cs.wisc.edu if var.type.ident not in seen_types and not var.type.isPrimitive: 23910119Snilay@cs.wisc.edu code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 24010119Snilay@cs.wisc.edu if "network" in var and "physical_network" in var: 24110119Snilay@cs.wisc.edu has_peer = True 2429827Sakash.bagdia@arm.com seen_types.add(var.type.ident) 24310594Sgabeblack@google.com 2446654Snate@binkert.org # for adding information to the protocol debug trace 24510594Sgabeblack@google.com code(''' 2466654Snate@binkert.orgextern std::stringstream ${ident}_transitionComment; 24710594Sgabeblack@google.com 2486654Snate@binkert.orgclass $c_ident : public AbstractController 24910594Sgabeblack@google.com{ 2506654Snate@binkert.org public: 25110594Sgabeblack@google.com typedef ${c_ident}Params Params; 25210594Sgabeblack@google.com $c_ident(const Params *p); 2537586SAli.Saidi@arm.com static int getNumControllers(); 25410635Satgutier@umich.edu void init(); 25510635Satgutier@umich.edu MessageBuffer* getMandatoryQueue() const; 2568661SAli.Saidi@ARM.com const int & getVersion() const; 2579827Sakash.bagdia@arm.com const std::string toString() const; 2589827Sakash.bagdia@arm.com const std::string getName() const; 2599827Sakash.bagdia@arm.com void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; } 2609793Sakash.bagdia@arm.com 26110119Snilay@cs.wisc.edu void print(std::ostream& out) const; 26210119Snilay@cs.wisc.edu void wakeup(); 2639790Sakash.bagdia@arm.com void printStats(std::ostream& out) const; 2649827Sakash.bagdia@arm.com void clearStats(); 2659827Sakash.bagdia@arm.com void regStats(); 2669827Sakash.bagdia@arm.com void collateStats(); 2679793Sakash.bagdia@arm.com 2689827Sakash.bagdia@arm.com void blockOnQueue(Address addr, MessageBuffer* port); 2699827Sakash.bagdia@arm.com void unblock(Address addr); 2709827Sakash.bagdia@arm.com void recordCacheTrace(int cntrl, CacheRecorder* tr); 2719793Sakash.bagdia@arm.com Sequencer* getSequencer() const; 2729793Sakash.bagdia@arm.com 2739793Sakash.bagdia@arm.com bool functionalReadBuffers(PacketPtr&); 2749384SAndreas.Sandberg@arm.com uint32_t functionalWriteBuffers(PacketPtr&); 2758863Snilay@cs.wisc.edu 2767876Sgblack@eecs.umich.edu void countTransition(${ident}_State state, ${ident}_Event event); 2774968Sacolyte@umich.edu void possibleTransition(${ident}_State state, ${ident}_Event event); 2788926Sandreas.hansson@arm.com uint64 getEventCount(${ident}_Event event); 2794837Ssaidi@eecs.umich.edu bool isPossible(${ident}_State state, ${ident}_Event event); 2804837Ssaidi@eecs.umich.edu uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 2819408Sandreas.hansson@arm.com 2829653SAndreas.Sandberg@ARM.comprivate: 28311839SCurtis.Dunham@arm.com''') 2849653SAndreas.Sandberg@ARM.com 2859164Sandreas.hansson@arm.com code.indent() 2869408Sandreas.hansson@arm.com # added by SS 2878845Sandreas.hansson@arm.com for param in self.config_parameters: 2888845Sandreas.hansson@arm.com if param.pointer: 2894837Ssaidi@eecs.umich.edu code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 2909826Sandreas.hansson@arm.com else: 2919826Sandreas.hansson@arm.com code('${{param.type_ast.type}} m_${{param.ident}};') 2929835Sandreas.hansson@arm.com 2939826Sandreas.hansson@arm.com code(''' 2949826Sandreas.hansson@arm.comTransitionResult doTransition(${ident}_Event event, 2959826Sandreas.hansson@arm.com''') 2969826Sandreas.hansson@arm.com 2978659SAli.Saidi@ARM.com if self.EntryType != None: 29810119Snilay@cs.wisc.edu code(''' 29910119Snilay@cs.wisc.edu ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 30010119Snilay@cs.wisc.edu''') 30110119Snilay@cs.wisc.edu if self.TBEType != None: 30210119Snilay@cs.wisc.edu code(''' 30310119Snilay@cs.wisc.edu ${{self.TBEType.c_ident}}* m_tbe_ptr, 30410119Snilay@cs.wisc.edu''') 30510119Snilay@cs.wisc.edu 30610119Snilay@cs.wisc.edu code(''' 30710119Snilay@cs.wisc.edu const Address& addr); 30810119Snilay@cs.wisc.edu 30910119Snilay@cs.wisc.eduTransitionResult doTransitionWorker(${ident}_Event event, 31010119Snilay@cs.wisc.edu ${ident}_State state, 31110119Snilay@cs.wisc.edu ${ident}_State& next_state, 31210119Snilay@cs.wisc.edu''') 31310119Snilay@cs.wisc.edu 31410119Snilay@cs.wisc.edu if self.TBEType != None: 31510119Snilay@cs.wisc.edu code(''' 31610119Snilay@cs.wisc.edu ${{self.TBEType.c_ident}}*& m_tbe_ptr, 31710119Snilay@cs.wisc.edu''') 31810119Snilay@cs.wisc.edu if self.EntryType != None: 31910119Snilay@cs.wisc.edu code(''' 32010119Snilay@cs.wisc.edu ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 32110119Snilay@cs.wisc.edu''') 32210119Snilay@cs.wisc.edu 32310119Snilay@cs.wisc.edu code(''' 32410119Snilay@cs.wisc.edu const Address& addr); 32510119Snilay@cs.wisc.edu 32610119Snilay@cs.wisc.eduint m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 32710119Snilay@cs.wisc.eduint m_event_counters[${ident}_Event_NUM]; 32810119Snilay@cs.wisc.edubool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 32910119Snilay@cs.wisc.edu 33010119Snilay@cs.wisc.edustatic std::vector<Stats::Vector *> eventVec; 33110697SCurtis.Dunham@arm.comstatic std::vector<std::vector<Stats::Vector *> > transVec; 33210747SChris.Emmons@arm.comstatic int m_num_controllers; 33310697SCurtis.Dunham@arm.com 33410747SChris.Emmons@arm.com// Internal functions 33510119Snilay@cs.wisc.edu''') 33610697SCurtis.Dunham@arm.com 33710747SChris.Emmons@arm.com for func in self.functions: 33810119Snilay@cs.wisc.edu proto = func.prototype 33910119Snilay@cs.wisc.edu if proto: 34010119Snilay@cs.wisc.edu code('$proto') 34110119Snilay@cs.wisc.edu 34210119Snilay@cs.wisc.edu if has_peer: 34310119Snilay@cs.wisc.edu code('void getQueuesFromPeer(AbstractController *);') 3448801Sgblack@eecs.umich.edu 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''') 35111291Sgabor.dozsa@arm.com 35211291Sgabor.dozsa@arm.com if self.TBEType != None: 35311291Sgabor.dozsa@arm.com code(''' 35411291Sgabor.dozsa@arm.com 35511291Sgabor.dozsa@arm.com// Set and Reset for tbe variable 35611291Sgabor.dozsa@arm.comvoid set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 3573005Sstever@eecs.umich.eduvoid unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 3588801Sgblack@eecs.umich.edu''') 3593005Sstever@eecs.umich.edu 3603005Sstever@eecs.umich.edu code(''' 3613005Sstever@eecs.umich.edu 3622566SN/A// Actions 3637861Sgblack@eecs.umich.edu''') 3647861Sgblack@eecs.umich.edu if self.TBEType != None and self.EntryType != None: 3657861Sgblack@eecs.umich.edu for action in self.actions.itervalues(): 3668635Schris.emmons@arm.com code('/** \\brief ${{action.desc}} */') 3678635Schris.emmons@arm.com code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 3688635Schris.emmons@arm.com elif self.TBEType != None: 3699061Snilay@cs.wisc.edu for action in self.actions.itervalues(): 3703481Shsul@eecs.umich.edu code('/** \\brief ${{action.desc}} */') 371 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);') 372 elif self.EntryType != None: 373 for action in self.actions.itervalues(): 374 code('/** \\brief ${{action.desc}} */') 375 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 376 else: 377 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", "") 388 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 389 390 code.dedent() 391 code('};') 392 code('#endif // __${ident}_CONTROLLER_H__') 393 code.write(path, '%s.hh' % c_ident) 394 395 def printControllerCC(self, path, includes): 396 '''Output the actions for performing the actions''' 397 398 code = self.symtab.codeFormatter() 399 ident = self.ident 400 c_ident = "%s_Controller" % self.ident 401 has_peer = False 402 403 code(''' 404/** \\file $c_ident.cc 405 * 406 * Auto generated C++ code started by $__file__:$__line__ 407 * Created by slicc definition of Module "${{self.short}}" 408 */ 409 410#include <sys/types.h> 411#include <unistd.h> 412 413#include <cassert> 414#include <sstream> 415#include <string> 416 417#include "base/compiler.hh" 418#include "base/cprintf.hh" 419#include "debug/RubyGenerated.hh" 420#include "debug/RubySlicc.hh" 421#include "mem/protocol/${ident}_Controller.hh" 422#include "mem/protocol/${ident}_Event.hh" 423#include "mem/protocol/${ident}_State.hh" 424#include "mem/protocol/Types.hh" 425#include "mem/ruby/common/Global.hh" 426#include "mem/ruby/system/System.hh" 427''') 428 for include_path in includes: 429 code('#include "${{include_path}}"') 430 431 code(''' 432 433using namespace std; 434''') 435 436 # include object classes 437 seen_types = set() 438 for var in self.objects: 439 if var.type.ident not in seen_types and not var.type.isPrimitive: 440 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 441 seen_types.add(var.type.ident) 442 443 code(''' 444$c_ident * 445${c_ident}Params::create() 446{ 447 return new $c_ident(this); 448} 449 450int $c_ident::m_num_controllers = 0; 451std::vector<Stats::Vector *> $c_ident::eventVec; 452std::vector<std::vector<Stats::Vector *> > $c_ident::transVec; 453 454// for adding information to the protocol debug trace 455stringstream ${ident}_transitionComment; 456 457#ifndef NDEBUG 458#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 459#else 460#define APPEND_TRANSITION_COMMENT(str) do {} while (0) 461#endif 462 463/** \\brief constructor */ 464$c_ident::$c_ident(const Params *p) 465 : AbstractController(p) 466{ 467 m_name = "${ident}"; 468''') 469 # 470 # max_port_rank is used to size vectors and thus should be one plus the 471 # largest port rank 472 # 473 max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1 474 code(' m_max_in_port_rank = $max_port_rank;') 475 code.indent() 476 477 # 478 # After initializing the universal machine parameters, initialize the 479 # this machines config parameters. Also detemine if these configuration 480 # params include a sequencer. This information will be used later for 481 # contecting the sequencer back to the L1 cache controller. 482 # 483 contains_dma_sequencer = False 484 sequencers = [] 485 for param in self.config_parameters: 486 if param.name == "dma_sequencer": 487 contains_dma_sequencer = True 488 elif re.compile("sequencer").search(param.name): 489 sequencers.append(param.name) 490 if param.pointer: 491 code('m_${{param.name}}_ptr = p->${{param.name}};') 492 else: 493 code('m_${{param.name}} = p->${{param.name}};') 494 495 # 496 # For the l1 cache controller, add the special atomic support which 497 # includes passing the sequencer a pointer to the controller. 498 # 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 538for (int state = 0; state < ${ident}_State_NUM; state++) { 539 for (int event = 0; event < ${ident}_Event_NUM; event++) { 540 m_possible[state][event] = false; 541 m_counters[state][event] = 0; 542 } 543} 544for (int event = 0; event < ${ident}_Event_NUM; event++) { 545 m_event_counters[event] = 0; 546} 547''') 548 code.dedent() 549 code(''' 550} 551 552void 553$c_ident::init() 554{ 555 MachineType machine_type = string_to_MachineType("${{var.machine.ident}}"); 556 int base = MachineType_base_number(machine_type); 557 558 m_machineID.type = MachineType_${ident}; 559 m_machineID.num = m_version; 560 561 // initialize objects 562 563''') 564 565 code.indent() 566 for var in self.objects: 567 vtype = var.type 568 vid = "m_%s_ptr" % var.c_ident 569 if "network" not in var: 570 # Not a network port object 571 if "primitive" in vtype: 572 code('$vid = new ${{vtype.c_ident}};') 573 if "default" in var: 574 code('(*$vid) = ${{var["default"]}};') 575 else: 576 # Normal Object 577 if var.ident.find("mandatoryQueue") < 0: 578 th = var.get("template", "") 579 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 580 args = "" 581 if "non_obj" not in vtype and not vtype.isEnumeration: 582 args = var.get("constructor", "") 583 code('$expr($args);') 584 585 code('assert($vid != NULL);') 586 587 if "default" in var: 588 code('*$vid = ${{var["default"]}}; // Object default') 589 elif "default" in vtype: 590 comment = "Type %s default" % vtype.ident 591 code('*$vid = ${{vtype["default"]}}; // $comment') 592 593 # Set ordering 594 if "ordered" in var: 595 # A buffer 596 code('$vid->setOrdering(${{var["ordered"]}});') 597 598 # Set randomization 599 if "random" in var: 600 # A buffer 601 code('$vid->setRandomization(${{var["random"]}});') 602 603 # Set Priority 604 if vtype.isBuffer and "rank" in var: 605 code('$vid->setPriority(${{var["rank"]}});') 606 607 # Set sender and receiver for trigger queue 608 if var.ident.find("triggerQueue") >= 0: 609 code('$vid->setSender(this);') 610 code('$vid->setReceiver(this);') 611 elif vtype.c_ident == "TimerTable": 612 code('$vid->setClockObj(this);') 613 elif var.ident.find("optionalQueue") >= 0: 614 code('$vid->setSender(this);') 615 code('$vid->setReceiver(this);') 616 617 else: 618 # Network port object 619 network = var["network"] 620 ordered = var["ordered"] 621 622 if "virtual_network" in var: 623 vnet = var["virtual_network"] 624 vnet_type = var["vnet_type"] 625 626 assert var.machine is not None 627 code(''' 628$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type"); 629assert($vid != NULL); 630''') 631 632 # Set the end 633 if network == "To": 634 code('$vid->setSender(this);') 635 else: 636 code('$vid->setReceiver(this);') 637 638 # Set ordering 639 if "ordered" in var: 640 # A buffer 641 code('$vid->setOrdering(${{var["ordered"]}});') 642 643 # Set randomization 644 if "random" in var: 645 # A buffer 646 code('$vid->setRandomization(${{var["random"]}});') 647 648 # Set Priority 649 if "rank" in var: 650 code('$vid->setPriority(${{var["rank"]}})') 651 652 # Set buffer size 653 if vtype.isBuffer: 654 code(''' 655if (m_buffer_size > 0) { 656 $vid->resize(m_buffer_size); 657} 658''') 659 660 # set description (may be overriden later by port def) 661 code(''' 662$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]"); 663 664''') 665 666 if vtype.isBuffer: 667 if "recycle_latency" in var: 668 code('$vid->setRecycleLatency( ' \ 669 'Cycles(${{var["recycle_latency"]}}));') 670 else: 671 code('$vid->setRecycleLatency(m_recycle_latency);') 672 673 # Set the prefetchers 674 code() 675 for prefetcher in self.prefetchers: 676 code('${{prefetcher.code}}.setController(this);') 677 678 code() 679 for port in self.in_ports: 680 # Set the queue consumers 681 code('${{port.code}}.setConsumer(this);') 682 # Set the queue descriptions 683 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");') 684 685 # Initialize the transition profiling 686 code() 687 for trans in self.transitions: 688 # Figure out if we stall 689 stall = False 690 for action in trans.actions: 691 if action.ident == "z_stall": 692 stall = True 693 694 # Only possible if it is not a 'z' case 695 if not stall: 696 state = "%s_State_%s" % (self.ident, trans.state.ident) 697 event = "%s_Event_%s" % (self.ident, trans.event.ident) 698 code('possibleTransition($state, $event);') 699 700 code.dedent() 701 code(''' 702 AbstractController::init(); 703 clearStats(); 704} 705''') 706 707 has_mandatory_q = False 708 for port in self.in_ports: 709 if port.code.find("mandatoryQueue_ptr") >= 0: 710 has_mandatory_q = True 711 712 if has_mandatory_q: 713 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 714 else: 715 mq_ident = "NULL" 716 717 seq_ident = "NULL" 718 for param in self.config_parameters: 719 if param.name == "sequencer": 720 assert(param.pointer) 721 seq_ident = "m_%s_ptr" % param.name 722 723 code(''' 724 725void 726$c_ident::regStats() 727{ 728 if (m_version == 0) { 729 for (${ident}_Event event = ${ident}_Event_FIRST; 730 event < ${ident}_Event_NUM; ++event) { 731 Stats::Vector *t = new Stats::Vector(); 732 t->init(m_num_controllers); 733 t->name(name() + "." + ${ident}_Event_to_string(event)); 734 t->flags(Stats::pdf | Stats::total | Stats::oneline | 735 Stats::nozero); 736 737 eventVec.push_back(t); 738 } 739 740 for (${ident}_State state = ${ident}_State_FIRST; 741 state < ${ident}_State_NUM; ++state) { 742 743 transVec.push_back(std::vector<Stats::Vector *>()); 744 745 for (${ident}_Event event = ${ident}_Event_FIRST; 746 event < ${ident}_Event_NUM; ++event) { 747 748 Stats::Vector *t = new Stats::Vector(); 749 t->init(m_num_controllers); 750 t->name(name() + "." + ${ident}_State_to_string(state) + 751 "." + ${ident}_Event_to_string(event)); 752 753 t->flags(Stats::pdf | Stats::total | Stats::oneline | 754 Stats::nozero); 755 transVec[state].push_back(t); 756 } 757 } 758 } 759} 760 761void 762$c_ident::collateStats() 763{ 764 for (${ident}_Event event = ${ident}_Event_FIRST; 765 event < ${ident}_Event_NUM; ++event) { 766 for (unsigned int i = 0; i < m_num_controllers; ++i) { 767 std::map<uint32_t, AbstractController *>::iterator it = 768 g_abs_controls[MachineType_${ident}].find(i); 769 assert(it != g_abs_controls[MachineType_${ident}].end()); 770 (*eventVec[event])[i] = 771 (($c_ident *)(*it).second)->getEventCount(event); 772 } 773 } 774 775 for (${ident}_State state = ${ident}_State_FIRST; 776 state < ${ident}_State_NUM; ++state) { 777 778 for (${ident}_Event event = ${ident}_Event_FIRST; 779 event < ${ident}_Event_NUM; ++event) { 780 781 for (unsigned int i = 0; i < m_num_controllers; ++i) { 782 std::map<uint32_t, AbstractController *>::iterator it = 783 g_abs_controls[MachineType_${ident}].find(i); 784 assert(it != g_abs_controls[MachineType_${ident}].end()); 785 (*transVec[state][event])[i] = 786 (($c_ident *)(*it).second)->getTransitionCount(state, event); 787 } 788 } 789 } 790} 791 792void 793$c_ident::countTransition(${ident}_State state, ${ident}_Event event) 794{ 795 assert(m_possible[state][event]); 796 m_counters[state][event]++; 797 m_event_counters[event]++; 798} 799void 800$c_ident::possibleTransition(${ident}_State state, 801 ${ident}_Event event) 802{ 803 m_possible[state][event] = true; 804} 805 806uint64 807$c_ident::getEventCount(${ident}_Event event) 808{ 809 return m_event_counters[event]; 810} 811 812bool 813$c_ident::isPossible(${ident}_State state, ${ident}_Event event) 814{ 815 return m_possible[state][event]; 816} 817 818uint64 819$c_ident::getTransitionCount(${ident}_State state, 820 ${ident}_Event event) 821{ 822 return m_counters[state][event]; 823} 824 825int 826$c_ident::getNumControllers() 827{ 828 return m_num_controllers; 829} 830 831MessageBuffer* 832$c_ident::getMandatoryQueue() const 833{ 834 return $mq_ident; 835} 836 837Sequencer* 838$c_ident::getSequencer() const 839{ 840 return $seq_ident; 841} 842 843const int & 844$c_ident::getVersion() const 845{ 846 return m_version; 847} 848 849const string 850$c_ident::toString() const 851{ 852 return "$c_ident"; 853} 854 855const string 856$c_ident::getName() const 857{ 858 return m_name; 859} 860 861void 862$c_ident::blockOnQueue(Address addr, MessageBuffer* port) 863{ 864 m_is_blocking = true; 865 m_block_map[addr] = port; 866} 867 868void 869$c_ident::unblock(Address addr) 870{ 871 m_block_map.erase(addr); 872 if (m_block_map.size() == 0) { 873 m_is_blocking = false; 874 } 875} 876 877void 878$c_ident::print(ostream& out) const 879{ 880 out << "[$c_ident " << m_version << "]"; 881} 882 883void 884$c_ident::printStats(ostream& out) const 885{ 886''') 887 # 888 # Cache and Memory Controllers have specific profilers associated with 889 # them. Print out these stats before dumping state transition stats. 890 # 891 for param in self.config_parameters: 892 if param.type_ast.type.ident == "DirectoryMemory": 893 assert(param.pointer) 894 code(' m_${{param.ident}}_ptr->printStats(out);') 895 896 code(''' 897} 898 899void $c_ident::clearStats() 900{ 901 for (int state = 0; state < ${ident}_State_NUM; state++) { 902 for (int event = 0; event < ${ident}_Event_NUM; event++) { 903 m_counters[state][event] = 0; 904 } 905 } 906 907 for (int event = 0; event < ${ident}_Event_NUM; event++) { 908 m_event_counters[event] = 0; 909 } 910 911 AbstractController::clearStats(); 912} 913''') 914 915 if self.EntryType != None: 916 code(''' 917 918// Set and Reset for cache_entry variable 919void 920$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 921{ 922 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 923} 924 925void 926$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 927{ 928 m_cache_entry_ptr = 0; 929} 930''') 931 932 if self.TBEType != None: 933 code(''' 934 935// Set and Reset for tbe variable 936void 937$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 938{ 939 m_tbe_ptr = m_new_tbe; 940} 941 942void 943$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 944{ 945 m_tbe_ptr = NULL; 946} 947''') 948 949 code(''' 950 951void 952$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 953{ 954''') 955 # 956 # Record cache contents for all associated caches. 957 # 958 code.indent() 959 for param in self.config_parameters: 960 if param.type_ast.type.ident == "CacheMemory": 961 assert(param.pointer) 962 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 963 964 code.dedent() 965 code(''' 966} 967 968// Actions 969''') 970 if self.TBEType != None and self.EntryType != None: 971 for action in self.actions.itervalues(): 972 if "c_code" not in action: 973 continue 974 975 code(''' 976/** \\brief ${{action.desc}} */ 977void 978$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 979{ 980 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 981 ${{action["c_code"]}} 982} 983 984''') 985 elif self.TBEType != None: 986 for action in self.actions.itervalues(): 987 if "c_code" not in action: 988 continue 989 990 code(''' 991/** \\brief ${{action.desc}} */ 992void 993$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 994{ 995 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 996 ${{action["c_code"]}} 997} 998 999''') 1000 elif self.EntryType != None: 1001 for action in self.actions.itervalues(): 1002 if "c_code" not in action: 1003 continue 1004 1005 code(''' 1006/** \\brief ${{action.desc}} */ 1007void 1008$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 1009{ 1010 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 1011 ${{action["c_code"]}} 1012} 1013 1014''') 1015 else: 1016 for action in self.actions.itervalues(): 1017 if "c_code" not in action: 1018 continue 1019 1020 code(''' 1021/** \\brief ${{action.desc}} */ 1022void 1023$c_ident::${{action.ident}}(const Address& addr) 1024{ 1025 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 1026 ${{action["c_code"]}} 1027} 1028 1029''') 1030 for func in self.functions: 1031 code(func.generateCode()) 1032 1033 # Function for functional reads from messages buffered in the controller 1034 code(''' 1035bool 1036$c_ident::functionalReadBuffers(PacketPtr& pkt) 1037{ 1038''') 1039 for var in self.objects: 1040 vtype = var.type 1041 if vtype.isBuffer: 1042 vid = "m_%s_ptr" % var.c_ident 1043 code('if ($vid->functionalRead(pkt)) { return true; }') 1044 code(''' 1045 return false; 1046} 1047''') 1048 1049 # Function for functional writes to messages buffered in the controller 1050 code(''' 1051uint32_t 1052$c_ident::functionalWriteBuffers(PacketPtr& pkt) 1053{ 1054 uint32_t num_functional_writes = 0; 1055''') 1056 for var in self.objects: 1057 vtype = var.type 1058 if vtype.isBuffer: 1059 vid = "m_%s_ptr" % var.c_ident 1060 code('num_functional_writes += $vid->functionalWrite(pkt);') 1061 code(''' 1062 return num_functional_writes; 1063} 1064''') 1065 1066 # Check if this controller has a peer, if yes then write the 1067 # function for connecting to the peer. 1068 if has_peer: 1069 code(''' 1070 1071void 1072$c_ident::getQueuesFromPeer(AbstractController *peer) 1073{ 1074''') 1075 for var in self.objects: 1076 if "network" in var and "physical_network" in var and \ 1077 var["network"] == "From": 1078 code(''' 1079m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}}); 1080assert(m_${{var.c_ident}}_ptr != NULL); 1081m_${{var.c_ident}}_ptr->setReceiver(this); 1082 1083''') 1084 code('}') 1085 1086 code.write(path, "%s.cc" % c_ident) 1087 1088 def printCWakeup(self, path, includes): 1089 '''Output the wakeup loop for the events''' 1090 1091 code = self.symtab.codeFormatter() 1092 ident = self.ident 1093 1094 outputRequest_types = True 1095 if len(self.request_types) == 0: 1096 outputRequest_types = False 1097 1098 code(''' 1099// Auto generated C++ code started by $__file__:$__line__ 1100// ${ident}: ${{self.short}} 1101 1102#include <sys/types.h> 1103#include <unistd.h> 1104 1105#include <cassert> 1106 1107#include "base/misc.hh" 1108#include "debug/RubySlicc.hh" 1109#include "mem/protocol/${ident}_Controller.hh" 1110#include "mem/protocol/${ident}_Event.hh" 1111#include "mem/protocol/${ident}_State.hh" 1112''') 1113 1114 if outputRequest_types: 1115 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1116 1117 code(''' 1118#include "mem/protocol/Types.hh" 1119#include "mem/ruby/common/Global.hh" 1120#include "mem/ruby/system/System.hh" 1121''') 1122 1123 1124 for include_path in includes: 1125 code('#include "${{include_path}}"') 1126 1127 code(''' 1128 1129using namespace std; 1130 1131void 1132${ident}_Controller::wakeup() 1133{ 1134 int counter = 0; 1135 while (true) { 1136 // Some cases will put us into an infinite loop without this limit 1137 assert(counter <= m_transitions_per_cycle); 1138 if (counter == m_transitions_per_cycle) { 1139 // Count how often we are fully utilized 1140 m_fully_busy_cycles++; 1141 1142 // Wakeup in another cycle and try again 1143 scheduleEvent(Cycles(1)); 1144 break; 1145 } 1146''') 1147 1148 code.indent() 1149 code.indent() 1150 1151 # InPorts 1152 # 1153 for port in self.in_ports: 1154 code.indent() 1155 code('// ${ident}InPort $port') 1156 if port.pairs.has_key("rank"): 1157 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};') 1158 else: 1159 code('m_cur_in_port_rank = 0;') 1160 code('${{port["c_code_in_port"]}}') 1161 code.dedent() 1162 1163 code('') 1164 1165 code.dedent() 1166 code.dedent() 1167 code(''' 1168 break; // If we got this far, we have nothing left todo 1169 } 1170} 1171''') 1172 1173 code.write(path, "%s_Wakeup.cc" % self.ident) 1174 1175 def printCSwitch(self, path): 1176 '''Output switch statement for transition table''' 1177 1178 code = self.symtab.codeFormatter() 1179 ident = self.ident 1180 1181 code(''' 1182// Auto generated C++ code started by $__file__:$__line__ 1183// ${ident}: ${{self.short}} 1184 1185#include <cassert> 1186 1187#include "base/misc.hh" 1188#include "base/trace.hh" 1189#include "debug/ProtocolTrace.hh" 1190#include "debug/RubyGenerated.hh" 1191#include "mem/protocol/${ident}_Controller.hh" 1192#include "mem/protocol/${ident}_Event.hh" 1193#include "mem/protocol/${ident}_State.hh" 1194#include "mem/protocol/Types.hh" 1195#include "mem/ruby/common/Global.hh" 1196#include "mem/ruby/system/System.hh" 1197 1198#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1199 1200#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1201#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1202 1203TransitionResult 1204${ident}_Controller::doTransition(${ident}_Event event, 1205''') 1206 if self.EntryType != None: 1207 code(''' 1208 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1209''') 1210 if self.TBEType != None: 1211 code(''' 1212 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1213''') 1214 code(''' 1215 const Address &addr) 1216{ 1217''') 1218 if self.TBEType != None and self.EntryType != None: 1219 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1220 elif self.TBEType != None: 1221 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1222 elif self.EntryType != None: 1223 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1224 else: 1225 code('${ident}_State state = getState(addr);') 1226 1227 code(''' 1228 ${ident}_State next_state = state; 1229 1230 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1231 *this, curCycle(), ${ident}_State_to_string(state), 1232 ${ident}_Event_to_string(event), addr); 1233 1234 TransitionResult result = 1235''') 1236 if self.TBEType != None and self.EntryType != None: 1237 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1238 elif self.TBEType != None: 1239 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1240 elif self.EntryType != None: 1241 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1242 else: 1243 code('doTransitionWorker(event, state, next_state, addr);') 1244 1245 code(''' 1246 if (result == TransitionResult_Valid) { 1247 DPRINTF(RubyGenerated, "next_state: %s\\n", 1248 ${ident}_State_to_string(next_state)); 1249 countTransition(state, event); 1250 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1251 curTick(), m_version, "${ident}", 1252 ${ident}_Event_to_string(event), 1253 ${ident}_State_to_string(state), 1254 ${ident}_State_to_string(next_state), 1255 addr, GET_TRANSITION_COMMENT()); 1256 1257 CLEAR_TRANSITION_COMMENT(); 1258''') 1259 if self.TBEType != None and self.EntryType != None: 1260 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1261 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1262 elif self.TBEType != None: 1263 code('setState(m_tbe_ptr, addr, next_state);') 1264 code('setAccessPermission(addr, next_state);') 1265 elif self.EntryType != None: 1266 code('setState(m_cache_entry_ptr, addr, next_state);') 1267 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1268 else: 1269 code('setState(addr, next_state);') 1270 code('setAccessPermission(addr, next_state);') 1271 1272 code(''' 1273 } else if (result == TransitionResult_ResourceStall) { 1274 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1275 curTick(), m_version, "${ident}", 1276 ${ident}_Event_to_string(event), 1277 ${ident}_State_to_string(state), 1278 ${ident}_State_to_string(next_state), 1279 addr, "Resource Stall"); 1280 } else if (result == TransitionResult_ProtocolStall) { 1281 DPRINTF(RubyGenerated, "stalling\\n"); 1282 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1283 curTick(), m_version, "${ident}", 1284 ${ident}_Event_to_string(event), 1285 ${ident}_State_to_string(state), 1286 ${ident}_State_to_string(next_state), 1287 addr, "Protocol Stall"); 1288 } 1289 1290 return result; 1291} 1292 1293TransitionResult 1294${ident}_Controller::doTransitionWorker(${ident}_Event event, 1295 ${ident}_State state, 1296 ${ident}_State& next_state, 1297''') 1298 1299 if self.TBEType != None: 1300 code(''' 1301 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1302''') 1303 if self.EntryType != None: 1304 code(''' 1305 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1306''') 1307 code(''' 1308 const Address& addr) 1309{ 1310 switch(HASH_FUN(state, event)) { 1311''') 1312 1313 # This map will allow suppress generating duplicate code 1314 cases = orderdict() 1315 1316 for trans in self.transitions: 1317 case_string = "%s_State_%s, %s_Event_%s" % \ 1318 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1319 1320 case = self.symtab.codeFormatter() 1321 # Only set next_state if it changes 1322 if trans.state != trans.nextState: 1323 ns_ident = trans.nextState.ident 1324 case('next_state = ${ident}_State_${ns_ident};') 1325 1326 actions = trans.actions 1327 request_types = trans.request_types 1328 1329 # Check for resources 1330 case_sorter = [] 1331 res = trans.resources 1332 for key,val in res.iteritems(): 1333 if key.type.ident != "DNUCAStopTable": 1334 val = ''' 1335if (!%s.areNSlotsAvailable(%s)) 1336 return TransitionResult_ResourceStall; 1337''' % (key.code, val) 1338 case_sorter.append(val) 1339 1340 # Check all of the request_types for resource constraints 1341 for request_type in request_types: 1342 val = ''' 1343if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1344 return TransitionResult_ResourceStall; 1345} 1346''' % (self.ident, request_type.ident) 1347 case_sorter.append(val) 1348 1349 # Emit the code sequences in a sorted order. This makes the 1350 # output deterministic (without this the output order can vary 1351 # since Map's keys() on a vector of pointers is not deterministic 1352 for c in sorted(case_sorter): 1353 case("$c") 1354 1355 # Record access types for this transition 1356 for request_type in request_types: 1357 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1358 1359 # Figure out if we stall 1360 stall = False 1361 for action in actions: 1362 if action.ident == "z_stall": 1363 stall = True 1364 break 1365 1366 if stall: 1367 case('return TransitionResult_ProtocolStall;') 1368 else: 1369 if self.TBEType != None and self.EntryType != None: 1370 for action in actions: 1371 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1372 elif self.TBEType != None: 1373 for action in actions: 1374 case('${{action.ident}}(m_tbe_ptr, addr);') 1375 elif self.EntryType != None: 1376 for action in actions: 1377 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1378 else: 1379 for action in actions: 1380 case('${{action.ident}}(addr);') 1381 case('return TransitionResult_Valid;') 1382 1383 case = str(case) 1384 1385 # Look to see if this transition code is unique. 1386 if case not in cases: 1387 cases[case] = [] 1388 1389 cases[case].append(case_string) 1390 1391 # Walk through all of the unique code blocks and spit out the 1392 # corresponding case statement elements 1393 for case,transitions in cases.iteritems(): 1394 # Iterative over all the multiple transitions that share 1395 # the same code 1396 for trans in transitions: 1397 code(' case HASH_FUN($trans):') 1398 code(' $case') 1399 1400 code(''' 1401 default: 1402 fatal("Invalid transition\\n" 1403 "%s time: %d addr: %s event: %s state: %s\\n", 1404 name(), curCycle(), addr, event, state); 1405 } 1406 return TransitionResult_Valid; 1407} 1408''') 1409 code.write(path, "%s_Transitions.cc" % self.ident) 1410 1411 1412 # ************************** 1413 # ******* HTML Files ******* 1414 # ************************** 1415 def frameRef(self, click_href, click_target, over_href, over_num, text): 1416 code = self.symtab.codeFormatter(fix_newlines=False) 1417 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1418 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1419 parent.frames[$over_num].location='$over_href' 1420 }\"> 1421 ${{html.formatShorthand(text)}} 1422 </A>""") 1423 return str(code) 1424 1425 def writeHTMLFiles(self, path): 1426 # Create table with no row hilighted 1427 self.printHTMLTransitions(path, None) 1428 1429 # Generate transition tables 1430 for state in self.states.itervalues(): 1431 self.printHTMLTransitions(path, state) 1432 1433 # Generate action descriptions 1434 for action in self.actions.itervalues(): 1435 name = "%s_action_%s.html" % (self.ident, action.ident) 1436 code = html.createSymbol(action, "Action") 1437 code.write(path, name) 1438 1439 # Generate state descriptions 1440 for state in self.states.itervalues(): 1441 name = "%s_State_%s.html" % (self.ident, state.ident) 1442 code = html.createSymbol(state, "State") 1443 code.write(path, name) 1444 1445 # Generate event descriptions 1446 for event in self.events.itervalues(): 1447 name = "%s_Event_%s.html" % (self.ident, event.ident) 1448 code = html.createSymbol(event, "Event") 1449 code.write(path, name) 1450 1451 def printHTMLTransitions(self, path, active_state): 1452 code = self.symtab.codeFormatter() 1453 1454 code(''' 1455<HTML> 1456<BODY link="blue" vlink="blue"> 1457 1458<H1 align="center">${{html.formatShorthand(self.short)}}: 1459''') 1460 code.indent() 1461 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1462 mid = machine.ident 1463 if i != 0: 1464 extra = " - " 1465 else: 1466 extra = "" 1467 if machine == self: 1468 code('$extra$mid') 1469 else: 1470 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1471 code.dedent() 1472 1473 code(""" 1474</H1> 1475 1476<TABLE border=1> 1477<TR> 1478 <TH> </TH> 1479""") 1480 1481 for event in self.events.itervalues(): 1482 href = "%s_Event_%s.html" % (self.ident, event.ident) 1483 ref = self.frameRef(href, "Status", href, "1", event.short) 1484 code('<TH bgcolor=white>$ref</TH>') 1485 1486 code('</TR>') 1487 # -- Body of table 1488 for state in self.states.itervalues(): 1489 # -- Each row 1490 if state == active_state: 1491 color = "yellow" 1492 else: 1493 color = "white" 1494 1495 click = "%s_table_%s.html" % (self.ident, state.ident) 1496 over = "%s_State_%s.html" % (self.ident, state.ident) 1497 text = html.formatShorthand(state.short) 1498 ref = self.frameRef(click, "Table", over, "1", state.short) 1499 code(''' 1500<TR> 1501 <TH bgcolor=$color>$ref</TH> 1502''') 1503 1504 # -- One column for each event 1505 for event in self.events.itervalues(): 1506 trans = self.table.get((state,event), None) 1507 if trans is None: 1508 # This is the no transition case 1509 if state == active_state: 1510 color = "#C0C000" 1511 else: 1512 color = "lightgrey" 1513 1514 code('<TD bgcolor=$color> </TD>') 1515 continue 1516 1517 next = trans.nextState 1518 stall_action = False 1519 1520 # -- Get the actions 1521 for action in trans.actions: 1522 if action.ident == "z_stall" or \ 1523 action.ident == "zz_recycleMandatoryQueue": 1524 stall_action = True 1525 1526 # -- Print out "actions/next-state" 1527 if stall_action: 1528 if state == active_state: 1529 color = "#C0C000" 1530 else: 1531 color = "lightgrey" 1532 1533 elif active_state and next.ident == active_state.ident: 1534 color = "aqua" 1535 elif state == active_state: 1536 color = "yellow" 1537 else: 1538 color = "white" 1539 1540 code('<TD bgcolor=$color>') 1541 for action in trans.actions: 1542 href = "%s_action_%s.html" % (self.ident, action.ident) 1543 ref = self.frameRef(href, "Status", href, "1", 1544 action.short) 1545 code(' $ref') 1546 if next != state: 1547 if trans.actions: 1548 code('/') 1549 click = "%s_table_%s.html" % (self.ident, next.ident) 1550 over = "%s_State_%s.html" % (self.ident, next.ident) 1551 ref = self.frameRef(click, "Table", over, "1", next.short) 1552 code("$ref") 1553 code("</TD>") 1554 1555 # -- Each row 1556 if state == active_state: 1557 color = "yellow" 1558 else: 1559 color = "white" 1560 1561 click = "%s_table_%s.html" % (self.ident, state.ident) 1562 over = "%s_State_%s.html" % (self.ident, state.ident) 1563 ref = self.frameRef(click, "Table", over, "1", state.short) 1564 code(''' 1565 <TH bgcolor=$color>$ref</TH> 1566</TR> 1567''') 1568 code(''' 1569<!- Column footer-> 1570<TR> 1571 <TH> </TH> 1572''') 1573 1574 for event in self.events.itervalues(): 1575 href = "%s_Event_%s.html" % (self.ident, event.ident) 1576 ref = self.frameRef(href, "Status", href, "1", event.short) 1577 code('<TH bgcolor=white>$ref</TH>') 1578 code(''' 1579</TR> 1580</TABLE> 1581</BODY></HTML> 1582''') 1583 1584 1585 if active_state: 1586 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1587 else: 1588 name = "%s_table.html" % self.ident 1589 code.write(path, name) 1590 1591__all__ = [ "StateMachine" ] 1592