StateMachine.py revision 11111:6da33e720481
12810Srdreslin@umich.edu# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 28702Sandreas.hansson@arm.com# Copyright (c) 2009 The Hewlett-Packard Development Company 38702Sandreas.hansson@arm.com# Copyright (c) 2013 Advanced Micro Devices, Inc. 48702Sandreas.hansson@arm.com# All rights reserved. 58702Sandreas.hansson@arm.com# 68702Sandreas.hansson@arm.com# Redistribution and use in source and binary forms, with or without 78702Sandreas.hansson@arm.com# modification, are permitted provided that the following conditions are 88702Sandreas.hansson@arm.com# met: redistributions of source code must retain the above copyright 98702Sandreas.hansson@arm.com# notice, this list of conditions and the following disclaimer; 108702Sandreas.hansson@arm.com# redistributions in binary form must reproduce the above copyright 118702Sandreas.hansson@arm.com# notice, this list of conditions and the following disclaimer in the 128702Sandreas.hansson@arm.com# documentation and/or other materials provided with the distribution; 138702Sandreas.hansson@arm.com# neither the name of the copyright holders nor the names of its 142810Srdreslin@umich.edu# contributors may be used to endorse or promote products derived from 152810Srdreslin@umich.edu# this software without specific prior written permission. 162810Srdreslin@umich.edu# 172810Srdreslin@umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 182810Srdreslin@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 192810Srdreslin@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 202810Srdreslin@umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 212810Srdreslin@umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 222810Srdreslin@umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 232810Srdreslin@umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 242810Srdreslin@umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 252810Srdreslin@umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 262810Srdreslin@umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 272810Srdreslin@umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 282810Srdreslin@umich.edu 292810Srdreslin@umich.edufrom m5.util import orderdict 302810Srdreslin@umich.edu 312810Srdreslin@umich.edufrom slicc.symbols.Symbol import Symbol 322810Srdreslin@umich.edufrom slicc.symbols.Var import Var 332810Srdreslin@umich.eduimport slicc.generate.html as html 342810Srdreslin@umich.eduimport re 352810Srdreslin@umich.edu 362810Srdreslin@umich.edupython_class_map = { 372810Srdreslin@umich.edu "int": "Int", 382810Srdreslin@umich.edu "uint32_t" : "UInt32", 392810Srdreslin@umich.edu "std::string": "String", 402810Srdreslin@umich.edu "bool": "Bool", 412810Srdreslin@umich.edu "CacheMemory": "RubyCache", 422810Srdreslin@umich.edu "WireBuffer": "RubyWireBuffer", 434458Sstever@eecs.umich.edu "Sequencer": "RubySequencer", 448856Sandreas.hansson@arm.com "DirectoryMemory": "RubyDirectoryMemory", 452810Srdreslin@umich.edu "MemoryControl": "MemoryControl", 462810Srdreslin@umich.edu "MessageBuffer": "MessageBuffer", 472810Srdreslin@umich.edu "DMASequencer": "DMASequencer", 482810Srdreslin@umich.edu "Prefetcher":"Prefetcher", 492810Srdreslin@umich.edu "Cycles":"Cycles", 502810Srdreslin@umich.edu } 512810Srdreslin@umich.edu 522810Srdreslin@umich.educlass StateMachine(Symbol): 532810Srdreslin@umich.edu def __init__(self, symtab, ident, location, pairs, config_parameters): 542810Srdreslin@umich.edu super(StateMachine, self).__init__(symtab, ident, location, pairs) 552810Srdreslin@umich.edu self.table = None 565338Sstever@gmail.com 575338Sstever@gmail.com # Data members in the State Machine that have been declared before 585338Sstever@gmail.com # the opening brace '{' of the machine. Note that these along with 594458Sstever@eecs.umich.edu # the members in self.objects form the entire set of data members. 604458Sstever@eecs.umich.edu self.config_parameters = config_parameters 612813Srdreslin@umich.edu 623861Sstever@eecs.umich.edu self.prefetchers = [] 632810Srdreslin@umich.edu 642810Srdreslin@umich.edu for param in config_parameters: 652810Srdreslin@umich.edu if param.pointer: 662810Srdreslin@umich.edu var = Var(symtab, param.ident, location, param.type_ast.type, 674672Sstever@eecs.umich.edu "(*m_%s_ptr)" % param.ident, {}, self) 682810Srdreslin@umich.edu else: 694672Sstever@eecs.umich.edu var = Var(symtab, param.ident, location, param.type_ast.type, 702810Srdreslin@umich.edu "m_%s" % param.ident, {}, self) 712810Srdreslin@umich.edu 722810Srdreslin@umich.edu self.symtab.registerSym(param.ident, var) 732810Srdreslin@umich.edu 742810Srdreslin@umich.edu if str(param.type_ast.type) == "Prefetcher": 753860Sstever@eecs.umich.edu self.prefetchers.append(var) 763860Sstever@eecs.umich.edu 772810Srdreslin@umich.edu self.states = orderdict() 782810Srdreslin@umich.edu self.events = orderdict() 792810Srdreslin@umich.edu self.actions = orderdict() 808856Sandreas.hansson@arm.com self.request_types = orderdict() 818856Sandreas.hansson@arm.com self.transitions = [] 828856Sandreas.hansson@arm.com self.in_ports = [] 838856Sandreas.hansson@arm.com self.functions = [] 848856Sandreas.hansson@arm.com 853738Sstever@eecs.umich.edu # Data members in the State Machine that have been declared inside 868856Sandreas.hansson@arm.com # the {} machine. Note that these along with the config params 873738Sstever@eecs.umich.edu # form the entire set of data members of the machine. 888856Sandreas.hansson@arm.com self.objects = [] 898856Sandreas.hansson@arm.com self.TBEType = None 903738Sstever@eecs.umich.edu self.EntryType = None 918856Sandreas.hansson@arm.com self.debug_flags = set() 924478Sstever@eecs.umich.edu self.debug_flags.add('RubyGenerated') 938975Sandreas.hansson@arm.com self.debug_flags.add('RubySlicc') 948948Sandreas.hansson@arm.com 958975Sandreas.hansson@arm.com def __repr__(self): 963738Sstever@eecs.umich.edu return "[StateMachine: %s]" % self.ident 973738Sstever@eecs.umich.edu 983738Sstever@eecs.umich.edu def addState(self, state): 993738Sstever@eecs.umich.edu assert self.table is None 1008856Sandreas.hansson@arm.com self.states[state.ident] = state 1018856Sandreas.hansson@arm.com 1028856Sandreas.hansson@arm.com def addEvent(self, event): 1038856Sandreas.hansson@arm.com assert self.table is None 1049090Sandreas.hansson@arm.com self.events[event.ident] = event 1058856Sandreas.hansson@arm.com 1068856Sandreas.hansson@arm.com def addAction(self, action): 1078856Sandreas.hansson@arm.com assert self.table is None 1088856Sandreas.hansson@arm.com 1098856Sandreas.hansson@arm.com # Check for duplicate action 1108856Sandreas.hansson@arm.com for other in self.actions.itervalues(): 1113738Sstever@eecs.umich.edu if action.ident == other.ident: 1123738Sstever@eecs.umich.edu action.warning("Duplicate action definition: %s" % action.ident) 1138856Sandreas.hansson@arm.com action.error("Duplicate action definition: %s" % action.ident) 1148914Sandreas.hansson@arm.com if action.short == other.short: 1158914Sandreas.hansson@arm.com other.warning("Duplicate action shorthand: %s" % other.ident) 1168914Sandreas.hansson@arm.com other.warning(" shorthand = %s" % other.short) 1178914Sandreas.hansson@arm.com action.warning("Duplicate action shorthand: %s" % action.ident) 1188914Sandreas.hansson@arm.com action.error(" shorthand = %s" % action.short) 1198975Sandreas.hansson@arm.com 1208914Sandreas.hansson@arm.com self.actions[action.ident] = action 1218914Sandreas.hansson@arm.com 1228914Sandreas.hansson@arm.com def addDebugFlag(self, flag): 1238914Sandreas.hansson@arm.com self.debug_flags.add(flag) 1248914Sandreas.hansson@arm.com 1258914Sandreas.hansson@arm.com def addRequestType(self, request_type): 1268914Sandreas.hansson@arm.com assert self.table is None 1278914Sandreas.hansson@arm.com self.request_types[request_type.ident] = request_type 1288975Sandreas.hansson@arm.com 1298914Sandreas.hansson@arm.com def addTransition(self, trans): 1308975Sandreas.hansson@arm.com assert self.table is None 1318914Sandreas.hansson@arm.com self.transitions.append(trans) 1328914Sandreas.hansson@arm.com 1338914Sandreas.hansson@arm.com def addInPort(self, var): 1348914Sandreas.hansson@arm.com self.in_ports.append(var) 1358914Sandreas.hansson@arm.com 1368914Sandreas.hansson@arm.com def addFunc(self, func): 1378914Sandreas.hansson@arm.com # register func in the symbol table 1388914Sandreas.hansson@arm.com self.symtab.registerSym(str(func), func) 1398914Sandreas.hansson@arm.com self.functions.append(func) 1408914Sandreas.hansson@arm.com 1418914Sandreas.hansson@arm.com def addObject(self, obj): 1428856Sandreas.hansson@arm.com self.symtab.registerSym(str(obj), obj) 1438856Sandreas.hansson@arm.com self.objects.append(obj) 1448856Sandreas.hansson@arm.com 1458856Sandreas.hansson@arm.com def addType(self, type): 1463738Sstever@eecs.umich.edu type_ident = '%s' % type.c_ident 1478856Sandreas.hansson@arm.com 1483738Sstever@eecs.umich.edu if type_ident == "%s_TBE" %self.ident: 1498914Sandreas.hansson@arm.com if self.TBEType != None: 1508914Sandreas.hansson@arm.com self.error("Multiple Transaction Buffer types in a " \ 1518914Sandreas.hansson@arm.com "single machine."); 1528856Sandreas.hansson@arm.com self.TBEType = type 1538856Sandreas.hansson@arm.com 1543738Sstever@eecs.umich.edu elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 1558856Sandreas.hansson@arm.com if "main" in type and "false" == type["main"].lower(): 1564478Sstever@eecs.umich.edu pass # this isn't the EntryType 1578975Sandreas.hansson@arm.com else: 1588948Sandreas.hansson@arm.com if self.EntryType != None: 1598975Sandreas.hansson@arm.com self.error("Multiple AbstractCacheEntry types in a " \ 1603738Sstever@eecs.umich.edu "single machine."); 1618948Sandreas.hansson@arm.com self.EntryType = type 1623738Sstever@eecs.umich.edu 1638948Sandreas.hansson@arm.com # Needs to be called before accessing the table 1644458Sstever@eecs.umich.edu def buildTable(self): 1658856Sandreas.hansson@arm.com assert self.table is None 1668856Sandreas.hansson@arm.com 1678856Sandreas.hansson@arm.com table = {} 1688856Sandreas.hansson@arm.com 1698856Sandreas.hansson@arm.com for trans in self.transitions: 1708856Sandreas.hansson@arm.com # Track which actions we touch so we know if we use them 1718856Sandreas.hansson@arm.com # all -- really this should be done for all symbols as 1723738Sstever@eecs.umich.edu # part of the symbol table, then only trigger it for 1733738Sstever@eecs.umich.edu # Actions, States, Events, etc. 1742810Srdreslin@umich.edu 1752810Srdreslin@umich.edu for action in trans.actions: 1764626Sstever@eecs.umich.edu action.used = True 1772810Srdreslin@umich.edu 1783861Sstever@eecs.umich.edu index = (trans.state, trans.event) 1792810Srdreslin@umich.edu if index in table: 1804671Sstever@eecs.umich.edu table[index].warning("Duplicate transition: %s" % table[index]) 1814671Sstever@eecs.umich.edu trans.error("Duplicate transition: %s" % trans) 1824671Sstever@eecs.umich.edu table[index] = trans 1832810Srdreslin@umich.edu 1845707Shsul@eecs.umich.edu # Look at all actions to make sure we used them all 1853860Sstever@eecs.umich.edu for action in self.actions.itervalues(): 1863860Sstever@eecs.umich.edu if not action.used: 1873860Sstever@eecs.umich.edu error_msg = "Unused action: %s" % action.ident 1885875Ssteve.reinhardt@amd.com if "desc" in action: 1895875Ssteve.reinhardt@amd.com error_msg += ", " + action.desc 1905875Ssteve.reinhardt@amd.com action.warning(error_msg) 1915875Ssteve.reinhardt@amd.com self.table = table 1923860Sstever@eecs.umich.edu 1933860Sstever@eecs.umich.edu # determine the port->msg buffer mappings 1949063SAli.Saidi@ARM.com def getBufferMaps(self, ident): 1959063SAli.Saidi@ARM.com msg_bufs = [] 1969063SAli.Saidi@ARM.com port_to_buf_map = {} 1979063SAli.Saidi@ARM.com in_msg_bufs = {} 1989063SAli.Saidi@ARM.com for port in self.in_ports: 1999063SAli.Saidi@ARM.com buf_name = "m_%s_ptr" % port.pairs["buffer_expr"].name 2009063SAli.Saidi@ARM.com msg_bufs.append(buf_name) 2013860Sstever@eecs.umich.edu port_to_buf_map[port] = msg_bufs.index(buf_name) 2023860Sstever@eecs.umich.edu if buf_name not in in_msg_bufs: 2033860Sstever@eecs.umich.edu in_msg_bufs[buf_name] = [port] 2043860Sstever@eecs.umich.edu else: 2053860Sstever@eecs.umich.edu in_msg_bufs[buf_name].append(port) 2065707Shsul@eecs.umich.edu return port_to_buf_map, in_msg_bufs, msg_bufs 2073860Sstever@eecs.umich.edu 2085388Sstever@gmail.com def writeCodeFiles(self, path, includes): 2095388Sstever@gmail.com self.printControllerPython(path) 2104219Srdreslin@umich.edu self.printControllerHH(path) 2114219Srdreslin@umich.edu self.printControllerCC(path, includes) 2124219Srdreslin@umich.edu self.printCSwitch(path) 2134219Srdreslin@umich.edu self.printCWakeup(path, includes) 2144626Sstever@eecs.umich.edu 2153860Sstever@eecs.umich.edu def printControllerPython(self, path): 2163860Sstever@eecs.umich.edu code = self.symtab.codeFormatter() 2175350Sstever@gmail.com ident = self.ident 2185350Sstever@gmail.com 2195350Sstever@gmail.com py_ident = "%s_Controller" % ident 2205350Sstever@gmail.com c_ident = "%s_Controller" % self.ident 2215350Sstever@gmail.com 2225350Sstever@gmail.com code(''' 2235350Sstever@gmail.comfrom m5.params import * 2245350Sstever@gmail.comfrom m5.SimObject import SimObject 2253860Sstever@eecs.umich.edufrom Controller import RubyController 2263860Sstever@eecs.umich.edu 2273860Sstever@eecs.umich.educlass $py_ident(RubyController): 2284626Sstever@eecs.umich.edu type = '$py_ident' 2293860Sstever@eecs.umich.edu cxx_header = 'mem/protocol/${c_ident}.hh' 2303860Sstever@eecs.umich.edu''') 2313860Sstever@eecs.umich.edu code.indent() 2323860Sstever@eecs.umich.edu for param in self.config_parameters: 2334626Sstever@eecs.umich.edu dflt_str = '' 2344626Sstever@eecs.umich.edu 2353860Sstever@eecs.umich.edu if param.rvalue is not None: 2367667Ssteve.reinhardt@amd.com dflt_str = str(param.rvalue.inline()) + ', ' 2377667Ssteve.reinhardt@amd.com 2387667Ssteve.reinhardt@amd.com if python_class_map.has_key(param.type_ast.type.c_ident): 2394628Sstever@eecs.umich.edu python_type = python_class_map[param.type_ast.type.c_ident] 2404626Sstever@eecs.umich.edu code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")') 2414670Sstever@eecs.umich.edu 2425319Sstever@gmail.com else: 2433860Sstever@eecs.umich.edu self.error("Unknown c++ to python class conversion for c++ " \ 2443860Sstever@eecs.umich.edu "type: '%s'. Please update the python_class_map " \ 2453860Sstever@eecs.umich.edu "in StateMachine.py", param.type_ast.type.c_ident) 2463860Sstever@eecs.umich.edu 2473860Sstever@eecs.umich.edu code.dedent() 2483860Sstever@eecs.umich.edu code.write(path, '%s.py' % py_ident) 2494670Sstever@eecs.umich.edu 2505319Sstever@gmail.com 2513860Sstever@eecs.umich.edu def printControllerHH(self, path): 2523860Sstever@eecs.umich.edu '''Output the method declarations for the class declaration''' 2533860Sstever@eecs.umich.edu code = self.symtab.codeFormatter() 2543860Sstever@eecs.umich.edu ident = self.ident 2553860Sstever@eecs.umich.edu c_ident = "%s_Controller" % self.ident 2563860Sstever@eecs.umich.edu 2573860Sstever@eecs.umich.edu code(''' 2583860Sstever@eecs.umich.edu/** \\file $c_ident.hh 2592810Srdreslin@umich.edu * 2602810Srdreslin@umich.edu * Auto generated C++ code started by $__file__:$__line__ 2618831Smrinmoy.ghosh@arm.com * Created by slicc definition of Module "${{self.short}}" 2622810Srdreslin@umich.edu */ 2632810Srdreslin@umich.edu 2642810Srdreslin@umich.edu#ifndef __${ident}_CONTROLLER_HH__ 2652810Srdreslin@umich.edu#define __${ident}_CONTROLLER_HH__ 2662810Srdreslin@umich.edu 2672982Sstever@eecs.umich.edu#include <iostream> 2682810Srdreslin@umich.edu#include <sstream> 2692810Srdreslin@umich.edu#include <string> 2704626Sstever@eecs.umich.edu 2712810Srdreslin@umich.edu#include "mem/protocol/TransitionResult.hh" 2722810Srdreslin@umich.edu#include "mem/protocol/Types.hh" 2734626Sstever@eecs.umich.edu#include "mem/ruby/common/Consumer.hh" 2744626Sstever@eecs.umich.edu#include "mem/ruby/slicc_interface/AbstractController.hh" 2754626Sstever@eecs.umich.edu#include "params/$c_ident.hh" 2762810Srdreslin@umich.edu 2774626Sstever@eecs.umich.edu''') 2782810Srdreslin@umich.edu 2792810Srdreslin@umich.edu seen_types = set() 2804626Sstever@eecs.umich.edu for var in self.objects: 2814626Sstever@eecs.umich.edu if var.type.ident not in seen_types and not var.type.isPrimitive: 2828702Sandreas.hansson@arm.com code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 2832810Srdreslin@umich.edu seen_types.add(var.type.ident) 2848702Sandreas.hansson@arm.com 2853293Srdreslin@umich.edu # for adding information to the protocol debug trace 2863293Srdreslin@umich.edu code(''' 2872810Srdreslin@umich.eduextern std::stringstream ${ident}_transitionComment; 2882982Sstever@eecs.umich.edu 2892810Srdreslin@umich.educlass $c_ident : public AbstractController 2904626Sstever@eecs.umich.edu{ 2912810Srdreslin@umich.edu public: 2922810Srdreslin@umich.edu typedef ${c_ident}Params Params; 2932810Srdreslin@umich.edu $c_ident(const Params *p); 2942982Sstever@eecs.umich.edu static int getNumControllers(); 2952810Srdreslin@umich.edu void init(); 2964626Sstever@eecs.umich.edu 2972810Srdreslin@umich.edu MessageBuffer *getMandatoryQueue() const; 2984626Sstever@eecs.umich.edu MessageBuffer *getMemoryQueue() const; 2994626Sstever@eecs.umich.edu void initNetQueues(); 3004626Sstever@eecs.umich.edu 3014626Sstever@eecs.umich.edu void print(std::ostream& out) const; 3024626Sstever@eecs.umich.edu void wakeup(); 3034626Sstever@eecs.umich.edu void resetStats(); 3044626Sstever@eecs.umich.edu void regStats(); 3052810Srdreslin@umich.edu void collateStats(); 3062810Srdreslin@umich.edu 3072982Sstever@eecs.umich.edu void recordCacheTrace(int cntrl, CacheRecorder* tr); 3082810Srdreslin@umich.edu Sequencer* getSequencer() const; 3092982Sstever@eecs.umich.edu 3102810Srdreslin@umich.edu int functionalWriteBuffers(PacketPtr&); 3114626Sstever@eecs.umich.edu 3124626Sstever@eecs.umich.edu void countTransition(${ident}_State state, ${ident}_Event event); 3134626Sstever@eecs.umich.edu void possibleTransition(${ident}_State state, ${ident}_Event event); 3145365Sstever@gmail.com uint64_t getEventCount(${ident}_Event event); 3155365Sstever@gmail.com bool isPossible(${ident}_State state, ${ident}_Event event); 3165365Sstever@gmail.com uint64_t getTransitionCount(${ident}_State state, ${ident}_Event event); 3175365Sstever@gmail.com 3185365Sstever@gmail.comprivate: 3195365Sstever@gmail.com''') 3205365Sstever@gmail.com 3215365Sstever@gmail.com code.indent() 3225365Sstever@gmail.com # added by SS 3234626Sstever@eecs.umich.edu for param in self.config_parameters: 3244628Sstever@eecs.umich.edu if param.pointer: 3254628Sstever@eecs.umich.edu code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 3265365Sstever@gmail.com else: 3275365Sstever@gmail.com code('${{param.type_ast.type}} m_${{param.ident}};') 3285365Sstever@gmail.com 3295365Sstever@gmail.com code(''' 3305365Sstever@gmail.comTransitionResult doTransition(${ident}_Event event, 3315365Sstever@gmail.com''') 3325365Sstever@gmail.com 3334626Sstever@eecs.umich.edu if self.EntryType != None: 3345365Sstever@gmail.com code(''' 3355365Sstever@gmail.com ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 3365365Sstever@gmail.com''') 3375365Sstever@gmail.com if self.TBEType != None: 3385365Sstever@gmail.com code(''' 3395365Sstever@gmail.com ${{self.TBEType.c_ident}}* m_tbe_ptr, 3404628Sstever@eecs.umich.edu''') 3414626Sstever@eecs.umich.edu 3424626Sstever@eecs.umich.edu code(''' 3434626Sstever@eecs.umich.edu Addr addr); 3444626Sstever@eecs.umich.edu 3454626Sstever@eecs.umich.eduTransitionResult doTransitionWorker(${ident}_Event event, 3464626Sstever@eecs.umich.edu ${ident}_State state, 3474626Sstever@eecs.umich.edu ${ident}_State& next_state, 3487667Ssteve.reinhardt@amd.com''') 3494626Sstever@eecs.umich.edu 3504626Sstever@eecs.umich.edu if self.TBEType != None: 3514626Sstever@eecs.umich.edu code(''' 3524626Sstever@eecs.umich.edu ${{self.TBEType.c_ident}}*& m_tbe_ptr, 3534626Sstever@eecs.umich.edu''') 3542810Srdreslin@umich.edu if self.EntryType != None: 3554626Sstever@eecs.umich.edu code(''' 3562810Srdreslin@umich.edu ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 3572810Srdreslin@umich.edu''') 3584626Sstever@eecs.umich.edu 3594626Sstever@eecs.umich.edu code(''' 3602810Srdreslin@umich.edu Addr addr); 3612810Srdreslin@umich.edu 3623861Sstever@eecs.umich.eduint m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 3633861Sstever@eecs.umich.eduint m_event_counters[${ident}_Event_NUM]; 3643861Sstever@eecs.umich.edubool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 3653861Sstever@eecs.umich.edu 3663861Sstever@eecs.umich.edustatic std::vector<Stats::Vector *> eventVec; 3674626Sstever@eecs.umich.edustatic std::vector<std::vector<Stats::Vector *> > transVec; 3683861Sstever@eecs.umich.edustatic int m_num_controllers; 3695875Ssteve.reinhardt@amd.com 3705875Ssteve.reinhardt@amd.com// Internal functions 3715875Ssteve.reinhardt@amd.com''') 3725875Ssteve.reinhardt@amd.com 3735875Ssteve.reinhardt@amd.com for func in self.functions: 3748985SAli.Saidi@ARM.com proto = func.prototype 3758985SAli.Saidi@ARM.com if proto: 3768985SAli.Saidi@ARM.com code('$proto') 3778985SAli.Saidi@ARM.com 3788985SAli.Saidi@ARM.com if self.EntryType != None: 3798985SAli.Saidi@ARM.com code(''' 3802810Srdreslin@umich.edu 3812810Srdreslin@umich.edu// Set and Reset for cache_entry variable 3822810Srdreslin@umich.eduvoid set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 383void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 384''') 385 386 if self.TBEType != None: 387 code(''' 388 389// Set and Reset for tbe variable 390void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 391void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 392''') 393 394 # Prototype the actions that the controller can take 395 code(''' 396 397// Actions 398''') 399 if self.TBEType != None and self.EntryType != None: 400 for action in self.actions.itervalues(): 401 code('/** \\brief ${{action.desc}} */') 402 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 403 'm_tbe_ptr, ${{self.EntryType.c_ident}}*& ' 404 'm_cache_entry_ptr, Addr addr);') 405 elif self.TBEType != None: 406 for action in self.actions.itervalues(): 407 code('/** \\brief ${{action.desc}} */') 408 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 409 'm_tbe_ptr, Addr addr);') 410 elif self.EntryType != None: 411 for action in self.actions.itervalues(): 412 code('/** \\brief ${{action.desc}} */') 413 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& ' 414 'm_cache_entry_ptr, Addr addr);') 415 else: 416 for action in self.actions.itervalues(): 417 code('/** \\brief ${{action.desc}} */') 418 code('void ${{action.ident}}(Addr addr);') 419 420 # the controller internal variables 421 code(''' 422 423// Objects 424''') 425 for var in self.objects: 426 th = var.get("template", "") 427 code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;') 428 429 code.dedent() 430 code('};') 431 code('#endif // __${ident}_CONTROLLER_H__') 432 code.write(path, '%s.hh' % c_ident) 433 434 def printControllerCC(self, path, includes): 435 '''Output the actions for performing the actions''' 436 437 code = self.symtab.codeFormatter() 438 ident = self.ident 439 c_ident = "%s_Controller" % self.ident 440 441 code(''' 442/** \\file $c_ident.cc 443 * 444 * Auto generated C++ code started by $__file__:$__line__ 445 * Created by slicc definition of Module "${{self.short}}" 446 */ 447 448#include <sys/types.h> 449#include <unistd.h> 450 451#include <cassert> 452#include <sstream> 453#include <string> 454#include <typeinfo> 455 456#include "base/compiler.hh" 457#include "base/cprintf.hh" 458 459''') 460 for f in self.debug_flags: 461 code('#include "debug/${{f}}.hh"') 462 code(''' 463#include "mem/protocol/${ident}_Controller.hh" 464#include "mem/protocol/${ident}_Event.hh" 465#include "mem/protocol/${ident}_State.hh" 466#include "mem/protocol/Types.hh" 467#include "mem/ruby/system/RubySystem.hh" 468 469''') 470 for include_path in includes: 471 code('#include "${{include_path}}"') 472 473 code(''' 474 475using namespace std; 476''') 477 478 # include object classes 479 seen_types = set() 480 for var in self.objects: 481 if var.type.ident not in seen_types and not var.type.isPrimitive: 482 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 483 seen_types.add(var.type.ident) 484 485 num_in_ports = len(self.in_ports) 486 487 code(''' 488$c_ident * 489${c_ident}Params::create() 490{ 491 return new $c_ident(this); 492} 493 494int $c_ident::m_num_controllers = 0; 495std::vector<Stats::Vector *> $c_ident::eventVec; 496std::vector<std::vector<Stats::Vector *> > $c_ident::transVec; 497 498// for adding information to the protocol debug trace 499stringstream ${ident}_transitionComment; 500 501#ifndef NDEBUG 502#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 503#else 504#define APPEND_TRANSITION_COMMENT(str) do {} while (0) 505#endif 506 507/** \\brief constructor */ 508$c_ident::$c_ident(const Params *p) 509 : AbstractController(p) 510{ 511 m_machineID.type = MachineType_${ident}; 512 m_machineID.num = m_version; 513 m_num_controllers++; 514 515 m_in_ports = $num_in_ports; 516''') 517 code.indent() 518 519 # 520 # After initializing the universal machine parameters, initialize the 521 # this machines config parameters. Also if these configuration params 522 # include a sequencer, connect the it to the controller. 523 # 524 for param in self.config_parameters: 525 if param.pointer: 526 code('m_${{param.ident}}_ptr = p->${{param.ident}};') 527 else: 528 code('m_${{param.ident}} = p->${{param.ident}};') 529 530 if re.compile("sequencer").search(param.ident): 531 code('m_${{param.ident}}_ptr->setController(this);') 532 533 code(''' 534 535for (int state = 0; state < ${ident}_State_NUM; state++) { 536 for (int event = 0; event < ${ident}_Event_NUM; event++) { 537 m_possible[state][event] = false; 538 m_counters[state][event] = 0; 539 } 540} 541for (int event = 0; event < ${ident}_Event_NUM; event++) { 542 m_event_counters[event] = 0; 543} 544''') 545 code.dedent() 546 code(''' 547} 548 549void 550$c_ident::initNetQueues() 551{ 552 MachineType machine_type = string_to_MachineType("${{self.ident}}"); 553 int base M5_VAR_USED = MachineType_base_number(machine_type); 554 555''') 556 code.indent() 557 558 # set for maintaining the vnet, direction pairs already seen for this 559 # machine. This map helps in implementing the check for avoiding 560 # multiple message buffers being mapped to the same vnet. 561 vnet_dir_set = set() 562 563 for var in self.config_parameters: 564 vid = "m_%s_ptr" % var.ident 565 if "network" in var: 566 vtype = var.type_ast.type 567 code('assert($vid != NULL);') 568 569 # Network port object 570 network = var["network"] 571 572 if "virtual_network" in var: 573 vnet = var["virtual_network"] 574 vnet_type = var["vnet_type"] 575 576 assert (vnet, network) not in vnet_dir_set 577 vnet_dir_set.add((vnet,network)) 578 579 code(''' 580m_net_ptr->set${network}NetQueue(m_version + base, $vid->getOrdered(), $vnet, 581 "$vnet_type", $vid); 582''') 583 # Set Priority 584 if "rank" in var: 585 code('$vid->setPriority(${{var["rank"]}})') 586 587 code.dedent() 588 code(''' 589} 590 591void 592$c_ident::init() 593{ 594 // initialize objects 595 initNetQueues(); 596''') 597 598 code.indent() 599 600 for var in self.objects: 601 vtype = var.type 602 vid = "m_%s_ptr" % var.ident 603 if "network" not in var: 604 # Not a network port object 605 if "primitive" in vtype: 606 code('$vid = new ${{vtype.c_ident}};') 607 if "default" in var: 608 code('(*$vid) = ${{var["default"]}};') 609 else: 610 # Normal Object 611 th = var.get("template", "") 612 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 613 args = "" 614 if "non_obj" not in vtype and not vtype.isEnumeration: 615 args = var.get("constructor", "") 616 617 code('$expr($args);') 618 code('assert($vid != NULL);') 619 620 if "default" in var: 621 code('*$vid = ${{var["default"]}}; // Object default') 622 elif "default" in vtype: 623 comment = "Type %s default" % vtype.ident 624 code('*$vid = ${{vtype["default"]}}; // $comment') 625 626 # Set the prefetchers 627 code() 628 for prefetcher in self.prefetchers: 629 code('${{prefetcher.code}}.setController(this);') 630 631 code() 632 for port in self.in_ports: 633 # Set the queue consumers 634 code('${{port.code}}.setConsumer(this);') 635 636 # Initialize the transition profiling 637 code() 638 for trans in self.transitions: 639 # Figure out if we stall 640 stall = False 641 for action in trans.actions: 642 if action.ident == "z_stall": 643 stall = True 644 645 # Only possible if it is not a 'z' case 646 if not stall: 647 state = "%s_State_%s" % (self.ident, trans.state.ident) 648 event = "%s_Event_%s" % (self.ident, trans.event.ident) 649 code('possibleTransition($state, $event);') 650 651 code.dedent() 652 code(''' 653 AbstractController::init(); 654 resetStats(); 655} 656''') 657 658 mq_ident = "NULL" 659 for port in self.in_ports: 660 if port.code.find("mandatoryQueue_ptr") >= 0: 661 mq_ident = "m_mandatoryQueue_ptr" 662 663 memq_ident = "NULL" 664 for port in self.in_ports: 665 if port.code.find("responseFromMemory_ptr") >= 0: 666 memq_ident = "m_responseFromMemory_ptr" 667 668 seq_ident = "NULL" 669 for param in self.config_parameters: 670 if param.ident == "sequencer": 671 assert(param.pointer) 672 seq_ident = "m_%s_ptr" % param.ident 673 674 code(''' 675 676void 677$c_ident::regStats() 678{ 679 AbstractController::regStats(); 680 681 if (m_version == 0) { 682 for (${ident}_Event event = ${ident}_Event_FIRST; 683 event < ${ident}_Event_NUM; ++event) { 684 Stats::Vector *t = new Stats::Vector(); 685 t->init(m_num_controllers); 686 t->name(params()->ruby_system->name() + ".${c_ident}." + 687 ${ident}_Event_to_string(event)); 688 t->flags(Stats::pdf | Stats::total | Stats::oneline | 689 Stats::nozero); 690 691 eventVec.push_back(t); 692 } 693 694 for (${ident}_State state = ${ident}_State_FIRST; 695 state < ${ident}_State_NUM; ++state) { 696 697 transVec.push_back(std::vector<Stats::Vector *>()); 698 699 for (${ident}_Event event = ${ident}_Event_FIRST; 700 event < ${ident}_Event_NUM; ++event) { 701 702 Stats::Vector *t = new Stats::Vector(); 703 t->init(m_num_controllers); 704 t->name(params()->ruby_system->name() + ".${c_ident}." + 705 ${ident}_State_to_string(state) + 706 "." + ${ident}_Event_to_string(event)); 707 708 t->flags(Stats::pdf | Stats::total | Stats::oneline | 709 Stats::nozero); 710 transVec[state].push_back(t); 711 } 712 } 713 } 714} 715 716void 717$c_ident::collateStats() 718{ 719 for (${ident}_Event event = ${ident}_Event_FIRST; 720 event < ${ident}_Event_NUM; ++event) { 721 for (unsigned int i = 0; i < m_num_controllers; ++i) { 722 RubySystem *rs = params()->ruby_system; 723 std::map<uint32_t, AbstractController *>::iterator it = 724 rs->m_abstract_controls[MachineType_${ident}].find(i); 725 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 726 (*eventVec[event])[i] = 727 (($c_ident *)(*it).second)->getEventCount(event); 728 } 729 } 730 731 for (${ident}_State state = ${ident}_State_FIRST; 732 state < ${ident}_State_NUM; ++state) { 733 734 for (${ident}_Event event = ${ident}_Event_FIRST; 735 event < ${ident}_Event_NUM; ++event) { 736 737 for (unsigned int i = 0; i < m_num_controllers; ++i) { 738 RubySystem *rs = params()->ruby_system; 739 std::map<uint32_t, AbstractController *>::iterator it = 740 rs->m_abstract_controls[MachineType_${ident}].find(i); 741 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 742 (*transVec[state][event])[i] = 743 (($c_ident *)(*it).second)->getTransitionCount(state, event); 744 } 745 } 746 } 747} 748 749void 750$c_ident::countTransition(${ident}_State state, ${ident}_Event event) 751{ 752 assert(m_possible[state][event]); 753 m_counters[state][event]++; 754 m_event_counters[event]++; 755} 756void 757$c_ident::possibleTransition(${ident}_State state, 758 ${ident}_Event event) 759{ 760 m_possible[state][event] = true; 761} 762 763uint64_t 764$c_ident::getEventCount(${ident}_Event event) 765{ 766 return m_event_counters[event]; 767} 768 769bool 770$c_ident::isPossible(${ident}_State state, ${ident}_Event event) 771{ 772 return m_possible[state][event]; 773} 774 775uint64_t 776$c_ident::getTransitionCount(${ident}_State state, 777 ${ident}_Event event) 778{ 779 return m_counters[state][event]; 780} 781 782int 783$c_ident::getNumControllers() 784{ 785 return m_num_controllers; 786} 787 788MessageBuffer* 789$c_ident::getMandatoryQueue() const 790{ 791 return $mq_ident; 792} 793 794MessageBuffer* 795$c_ident::getMemoryQueue() const 796{ 797 return $memq_ident; 798} 799 800Sequencer* 801$c_ident::getSequencer() const 802{ 803 return $seq_ident; 804} 805 806void 807$c_ident::print(ostream& out) const 808{ 809 out << "[$c_ident " << m_version << "]"; 810} 811 812void $c_ident::resetStats() 813{ 814 for (int state = 0; state < ${ident}_State_NUM; state++) { 815 for (int event = 0; event < ${ident}_Event_NUM; event++) { 816 m_counters[state][event] = 0; 817 } 818 } 819 820 for (int event = 0; event < ${ident}_Event_NUM; event++) { 821 m_event_counters[event] = 0; 822 } 823 824 AbstractController::resetStats(); 825} 826''') 827 828 if self.EntryType != None: 829 code(''' 830 831// Set and Reset for cache_entry variable 832void 833$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 834{ 835 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 836} 837 838void 839$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 840{ 841 m_cache_entry_ptr = 0; 842} 843''') 844 845 if self.TBEType != None: 846 code(''' 847 848// Set and Reset for tbe variable 849void 850$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 851{ 852 m_tbe_ptr = m_new_tbe; 853} 854 855void 856$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 857{ 858 m_tbe_ptr = NULL; 859} 860''') 861 862 code(''' 863 864void 865$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 866{ 867''') 868 # 869 # Record cache contents for all associated caches. 870 # 871 code.indent() 872 for param in self.config_parameters: 873 if param.type_ast.type.ident == "CacheMemory": 874 assert(param.pointer) 875 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 876 877 code.dedent() 878 code(''' 879} 880 881// Actions 882''') 883 if self.TBEType != None and self.EntryType != None: 884 for action in self.actions.itervalues(): 885 if "c_code" not in action: 886 continue 887 888 code(''' 889/** \\brief ${{action.desc}} */ 890void 891$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 892{ 893 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 894 try { 895 ${{action["c_code"]}} 896 } catch (const RejectException & e) { 897 fatal("Error in action ${{ident}}:${{action.ident}}: " 898 "executed a peek statement with the wrong message " 899 "type specified. "); 900 } 901} 902 903''') 904 elif self.TBEType != None: 905 for action in self.actions.itervalues(): 906 if "c_code" not in action: 907 continue 908 909 code(''' 910/** \\brief ${{action.desc}} */ 911void 912$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, Addr addr) 913{ 914 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 915 ${{action["c_code"]}} 916} 917 918''') 919 elif self.EntryType != None: 920 for action in self.actions.itervalues(): 921 if "c_code" not in action: 922 continue 923 924 code(''' 925/** \\brief ${{action.desc}} */ 926void 927$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 928{ 929 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 930 ${{action["c_code"]}} 931} 932 933''') 934 else: 935 for action in self.actions.itervalues(): 936 if "c_code" not in action: 937 continue 938 939 code(''' 940/** \\brief ${{action.desc}} */ 941void 942$c_ident::${{action.ident}}(Addr addr) 943{ 944 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 945 ${{action["c_code"]}} 946} 947 948''') 949 for func in self.functions: 950 code(func.generateCode()) 951 952 # Function for functional writes to messages buffered in the controller 953 code(''' 954int 955$c_ident::functionalWriteBuffers(PacketPtr& pkt) 956{ 957 int num_functional_writes = 0; 958''') 959 for var in self.objects: 960 vtype = var.type 961 if vtype.isBuffer: 962 vid = "m_%s_ptr" % var.ident 963 code('num_functional_writes += $vid->functionalWrite(pkt);') 964 965 for var in self.config_parameters: 966 vtype = var.type_ast.type 967 if vtype.isBuffer: 968 vid = "m_%s_ptr" % var.ident 969 code('num_functional_writes += $vid->functionalWrite(pkt);') 970 971 code(''' 972 return num_functional_writes; 973} 974''') 975 976 code.write(path, "%s.cc" % c_ident) 977 978 def printCWakeup(self, path, includes): 979 '''Output the wakeup loop for the events''' 980 981 code = self.symtab.codeFormatter() 982 ident = self.ident 983 984 outputRequest_types = True 985 if len(self.request_types) == 0: 986 outputRequest_types = False 987 988 code(''' 989// Auto generated C++ code started by $__file__:$__line__ 990// ${ident}: ${{self.short}} 991 992#include <sys/types.h> 993#include <unistd.h> 994 995#include <cassert> 996#include <typeinfo> 997 998#include "base/misc.hh" 999 1000''') 1001 for f in self.debug_flags: 1002 code('#include "debug/${{f}}.hh"') 1003 code(''' 1004#include "mem/protocol/${ident}_Controller.hh" 1005#include "mem/protocol/${ident}_Event.hh" 1006#include "mem/protocol/${ident}_State.hh" 1007 1008''') 1009 1010 if outputRequest_types: 1011 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1012 1013 code(''' 1014#include "mem/protocol/Types.hh" 1015#include "mem/ruby/system/RubySystem.hh" 1016 1017''') 1018 1019 1020 for include_path in includes: 1021 code('#include "${{include_path}}"') 1022 1023 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1024 1025 code(''' 1026 1027using namespace std; 1028 1029void 1030${ident}_Controller::wakeup() 1031{ 1032 int counter = 0; 1033 while (true) { 1034 unsigned char rejected[${{len(msg_bufs)}}]; 1035 memset(rejected, 0, sizeof(unsigned char)*${{len(msg_bufs)}}); 1036 // Some cases will put us into an infinite loop without this limit 1037 assert(counter <= m_transitions_per_cycle); 1038 if (counter == m_transitions_per_cycle) { 1039 // Count how often we are fully utilized 1040 m_fully_busy_cycles++; 1041 1042 // Wakeup in another cycle and try again 1043 scheduleEvent(Cycles(1)); 1044 break; 1045 } 1046''') 1047 1048 code.indent() 1049 code.indent() 1050 1051 # InPorts 1052 # 1053 for port in self.in_ports: 1054 code.indent() 1055 code('// ${ident}InPort $port') 1056 if port.pairs.has_key("rank"): 1057 code('m_cur_in_port = ${{port.pairs["rank"]}};') 1058 else: 1059 code('m_cur_in_port = 0;') 1060 if port in port_to_buf_map: 1061 code('try {') 1062 code.indent() 1063 code('${{port["c_code_in_port"]}}') 1064 1065 if port in port_to_buf_map: 1066 code.dedent() 1067 code(''' 1068 } catch (const RejectException & e) { 1069 rejected[${{port_to_buf_map[port]}}]++; 1070 } 1071''') 1072 code.dedent() 1073 code('') 1074 1075 code.dedent() 1076 code.dedent() 1077 code(''' 1078 // If we got this far, we have nothing left todo or something went 1079 // wrong''') 1080 for buf_name, ports in in_msg_bufs.items(): 1081 if len(ports) > 1: 1082 # only produce checks when a buffer is shared by multiple ports 1083 code(''' 1084 if (${{buf_name}}->isReady() && rejected[${{port_to_buf_map[ports[0]]}}] == ${{len(ports)}}) 1085 { 1086 // no port claimed the message on the top of this buffer 1087 panic("Runtime Error at Ruby Time: %d. " 1088 "All ports rejected a message. " 1089 "You are probably sending a message type to this controller " 1090 "over a virtual network that do not define an in_port for " 1091 "the incoming message type.\\n", 1092 Cycles(1)); 1093 } 1094''') 1095 code(''' 1096 break; 1097 } 1098} 1099''') 1100 1101 code.write(path, "%s_Wakeup.cc" % self.ident) 1102 1103 def printCSwitch(self, path): 1104 '''Output switch statement for transition table''' 1105 1106 code = self.symtab.codeFormatter() 1107 ident = self.ident 1108 1109 code(''' 1110// Auto generated C++ code started by $__file__:$__line__ 1111// ${ident}: ${{self.short}} 1112 1113#include <cassert> 1114 1115#include "base/misc.hh" 1116#include "base/trace.hh" 1117#include "debug/ProtocolTrace.hh" 1118#include "debug/RubyGenerated.hh" 1119#include "mem/protocol/${ident}_Controller.hh" 1120#include "mem/protocol/${ident}_Event.hh" 1121#include "mem/protocol/${ident}_State.hh" 1122#include "mem/protocol/Types.hh" 1123#include "mem/ruby/system/RubySystem.hh" 1124 1125#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1126 1127#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1128#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1129 1130TransitionResult 1131${ident}_Controller::doTransition(${ident}_Event event, 1132''') 1133 if self.EntryType != None: 1134 code(''' 1135 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1136''') 1137 if self.TBEType != None: 1138 code(''' 1139 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1140''') 1141 code(''' 1142 Addr addr) 1143{ 1144''') 1145 code.indent() 1146 1147 if self.TBEType != None and self.EntryType != None: 1148 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1149 elif self.TBEType != None: 1150 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1151 elif self.EntryType != None: 1152 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1153 else: 1154 code('${ident}_State state = getState(addr);') 1155 1156 code(''' 1157${ident}_State next_state = state; 1158 1159DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1160 *this, curCycle(), ${ident}_State_to_string(state), 1161 ${ident}_Event_to_string(event), addr); 1162 1163TransitionResult result = 1164''') 1165 if self.TBEType != None and self.EntryType != None: 1166 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1167 elif self.TBEType != None: 1168 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1169 elif self.EntryType != None: 1170 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1171 else: 1172 code('doTransitionWorker(event, state, next_state, addr);') 1173 1174 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1175 1176 code(''' 1177 1178if (result == TransitionResult_Valid) { 1179 DPRINTF(RubyGenerated, "next_state: %s\\n", 1180 ${ident}_State_to_string(next_state)); 1181 countTransition(state, event); 1182 1183 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %#x %s\\n", 1184 curTick(), m_version, "${ident}", 1185 ${ident}_Event_to_string(event), 1186 ${ident}_State_to_string(state), 1187 ${ident}_State_to_string(next_state), 1188 addr, GET_TRANSITION_COMMENT()); 1189 1190 CLEAR_TRANSITION_COMMENT(); 1191''') 1192 if self.TBEType != None and self.EntryType != None: 1193 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1194 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1195 elif self.TBEType != None: 1196 code('setState(m_tbe_ptr, addr, next_state);') 1197 code('setAccessPermission(addr, next_state);') 1198 elif self.EntryType != None: 1199 code('setState(m_cache_entry_ptr, addr, next_state);') 1200 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1201 else: 1202 code('setState(addr, next_state);') 1203 code('setAccessPermission(addr, next_state);') 1204 1205 code(''' 1206} else if (result == TransitionResult_ResourceStall) { 1207 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1208 curTick(), m_version, "${ident}", 1209 ${ident}_Event_to_string(event), 1210 ${ident}_State_to_string(state), 1211 ${ident}_State_to_string(next_state), 1212 addr, "Resource Stall"); 1213} else if (result == TransitionResult_ProtocolStall) { 1214 DPRINTF(RubyGenerated, "stalling\\n"); 1215 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1216 curTick(), m_version, "${ident}", 1217 ${ident}_Event_to_string(event), 1218 ${ident}_State_to_string(state), 1219 ${ident}_State_to_string(next_state), 1220 addr, "Protocol Stall"); 1221} 1222 1223return result; 1224''') 1225 code.dedent() 1226 code(''' 1227} 1228 1229TransitionResult 1230${ident}_Controller::doTransitionWorker(${ident}_Event event, 1231 ${ident}_State state, 1232 ${ident}_State& next_state, 1233''') 1234 1235 if self.TBEType != None: 1236 code(''' 1237 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1238''') 1239 if self.EntryType != None: 1240 code(''' 1241 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1242''') 1243 code(''' 1244 Addr addr) 1245{ 1246 switch(HASH_FUN(state, event)) { 1247''') 1248 1249 # This map will allow suppress generating duplicate code 1250 cases = orderdict() 1251 1252 for trans in self.transitions: 1253 case_string = "%s_State_%s, %s_Event_%s" % \ 1254 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1255 1256 case = self.symtab.codeFormatter() 1257 # Only set next_state if it changes 1258 if trans.state != trans.nextState: 1259 if trans.nextState.isWildcard(): 1260 # When * is encountered as an end state of a transition, 1261 # the next state is determined by calling the 1262 # machine-specific getNextState function. The next state 1263 # is determined before any actions of the transition 1264 # execute, and therefore the next state calculation cannot 1265 # depend on any of the transitionactions. 1266 case('next_state = getNextState(addr);') 1267 else: 1268 ns_ident = trans.nextState.ident 1269 case('next_state = ${ident}_State_${ns_ident};') 1270 1271 actions = trans.actions 1272 request_types = trans.request_types 1273 1274 # Check for resources 1275 case_sorter = [] 1276 res = trans.resources 1277 for key,val in res.iteritems(): 1278 val = ''' 1279if (!%s.areNSlotsAvailable(%s, clockEdge())) 1280 return TransitionResult_ResourceStall; 1281''' % (key.code, val) 1282 case_sorter.append(val) 1283 1284 # Check all of the request_types for resource constraints 1285 for request_type in request_types: 1286 val = ''' 1287if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1288 return TransitionResult_ResourceStall; 1289} 1290''' % (self.ident, request_type.ident) 1291 case_sorter.append(val) 1292 1293 # Emit the code sequences in a sorted order. This makes the 1294 # output deterministic (without this the output order can vary 1295 # since Map's keys() on a vector of pointers is not deterministic 1296 for c in sorted(case_sorter): 1297 case("$c") 1298 1299 # Record access types for this transition 1300 for request_type in request_types: 1301 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1302 1303 # Figure out if we stall 1304 stall = False 1305 for action in actions: 1306 if action.ident == "z_stall": 1307 stall = True 1308 break 1309 1310 if stall: 1311 case('return TransitionResult_ProtocolStall;') 1312 else: 1313 if self.TBEType != None and self.EntryType != None: 1314 for action in actions: 1315 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1316 elif self.TBEType != None: 1317 for action in actions: 1318 case('${{action.ident}}(m_tbe_ptr, addr);') 1319 elif self.EntryType != None: 1320 for action in actions: 1321 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1322 else: 1323 for action in actions: 1324 case('${{action.ident}}(addr);') 1325 case('return TransitionResult_Valid;') 1326 1327 case = str(case) 1328 1329 # Look to see if this transition code is unique. 1330 if case not in cases: 1331 cases[case] = [] 1332 1333 cases[case].append(case_string) 1334 1335 # Walk through all of the unique code blocks and spit out the 1336 # corresponding case statement elements 1337 for case,transitions in cases.iteritems(): 1338 # Iterative over all the multiple transitions that share 1339 # the same code 1340 for trans in transitions: 1341 code(' case HASH_FUN($trans):') 1342 code(' $case\n') 1343 1344 code(''' 1345 default: 1346 panic("Invalid transition\\n" 1347 "%s time: %d addr: %s event: %s state: %s\\n", 1348 name(), curCycle(), addr, event, state); 1349 } 1350 1351 return TransitionResult_Valid; 1352} 1353''') 1354 code.write(path, "%s_Transitions.cc" % self.ident) 1355 1356 1357 # ************************** 1358 # ******* HTML Files ******* 1359 # ************************** 1360 def frameRef(self, click_href, click_target, over_href, over_num, text): 1361 code = self.symtab.codeFormatter(fix_newlines=False) 1362 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1363 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1364 parent.frames[$over_num].location='$over_href' 1365 }\"> 1366 ${{html.formatShorthand(text)}} 1367 </A>""") 1368 return str(code) 1369 1370 def writeHTMLFiles(self, path): 1371 # Create table with no row hilighted 1372 self.printHTMLTransitions(path, None) 1373 1374 # Generate transition tables 1375 for state in self.states.itervalues(): 1376 self.printHTMLTransitions(path, state) 1377 1378 # Generate action descriptions 1379 for action in self.actions.itervalues(): 1380 name = "%s_action_%s.html" % (self.ident, action.ident) 1381 code = html.createSymbol(action, "Action") 1382 code.write(path, name) 1383 1384 # Generate state descriptions 1385 for state in self.states.itervalues(): 1386 name = "%s_State_%s.html" % (self.ident, state.ident) 1387 code = html.createSymbol(state, "State") 1388 code.write(path, name) 1389 1390 # Generate event descriptions 1391 for event in self.events.itervalues(): 1392 name = "%s_Event_%s.html" % (self.ident, event.ident) 1393 code = html.createSymbol(event, "Event") 1394 code.write(path, name) 1395 1396 def printHTMLTransitions(self, path, active_state): 1397 code = self.symtab.codeFormatter() 1398 1399 code(''' 1400<HTML> 1401<BODY link="blue" vlink="blue"> 1402 1403<H1 align="center">${{html.formatShorthand(self.short)}}: 1404''') 1405 code.indent() 1406 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1407 mid = machine.ident 1408 if i != 0: 1409 extra = " - " 1410 else: 1411 extra = "" 1412 if machine == self: 1413 code('$extra$mid') 1414 else: 1415 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1416 code.dedent() 1417 1418 code(""" 1419</H1> 1420 1421<TABLE border=1> 1422<TR> 1423 <TH> </TH> 1424""") 1425 1426 for event in self.events.itervalues(): 1427 href = "%s_Event_%s.html" % (self.ident, event.ident) 1428 ref = self.frameRef(href, "Status", href, "1", event.short) 1429 code('<TH bgcolor=white>$ref</TH>') 1430 1431 code('</TR>') 1432 # -- Body of table 1433 for state in self.states.itervalues(): 1434 # -- Each row 1435 if state == active_state: 1436 color = "yellow" 1437 else: 1438 color = "white" 1439 1440 click = "%s_table_%s.html" % (self.ident, state.ident) 1441 over = "%s_State_%s.html" % (self.ident, state.ident) 1442 text = html.formatShorthand(state.short) 1443 ref = self.frameRef(click, "Table", over, "1", state.short) 1444 code(''' 1445<TR> 1446 <TH bgcolor=$color>$ref</TH> 1447''') 1448 1449 # -- One column for each event 1450 for event in self.events.itervalues(): 1451 trans = self.table.get((state,event), None) 1452 if trans is None: 1453 # This is the no transition case 1454 if state == active_state: 1455 color = "#C0C000" 1456 else: 1457 color = "lightgrey" 1458 1459 code('<TD bgcolor=$color> </TD>') 1460 continue 1461 1462 next = trans.nextState 1463 stall_action = False 1464 1465 # -- Get the actions 1466 for action in trans.actions: 1467 if action.ident == "z_stall" or \ 1468 action.ident == "zz_recycleMandatoryQueue": 1469 stall_action = True 1470 1471 # -- Print out "actions/next-state" 1472 if stall_action: 1473 if state == active_state: 1474 color = "#C0C000" 1475 else: 1476 color = "lightgrey" 1477 1478 elif active_state and next.ident == active_state.ident: 1479 color = "aqua" 1480 elif state == active_state: 1481 color = "yellow" 1482 else: 1483 color = "white" 1484 1485 code('<TD bgcolor=$color>') 1486 for action in trans.actions: 1487 href = "%s_action_%s.html" % (self.ident, action.ident) 1488 ref = self.frameRef(href, "Status", href, "1", 1489 action.short) 1490 code(' $ref') 1491 if next != state: 1492 if trans.actions: 1493 code('/') 1494 click = "%s_table_%s.html" % (self.ident, next.ident) 1495 over = "%s_State_%s.html" % (self.ident, next.ident) 1496 ref = self.frameRef(click, "Table", over, "1", next.short) 1497 code("$ref") 1498 code("</TD>") 1499 1500 # -- Each row 1501 if state == active_state: 1502 color = "yellow" 1503 else: 1504 color = "white" 1505 1506 click = "%s_table_%s.html" % (self.ident, state.ident) 1507 over = "%s_State_%s.html" % (self.ident, state.ident) 1508 ref = self.frameRef(click, "Table", over, "1", state.short) 1509 code(''' 1510 <TH bgcolor=$color>$ref</TH> 1511</TR> 1512''') 1513 code(''' 1514<!- Column footer-> 1515<TR> 1516 <TH> </TH> 1517''') 1518 1519 for event in self.events.itervalues(): 1520 href = "%s_Event_%s.html" % (self.ident, event.ident) 1521 ref = self.frameRef(href, "Status", href, "1", event.short) 1522 code('<TH bgcolor=white>$ref</TH>') 1523 code(''' 1524</TR> 1525</TABLE> 1526</BODY></HTML> 1527''') 1528 1529 1530 if active_state: 1531 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1532 else: 1533 name = "%s_table.html" % self.ident 1534 code.write(path, name) 1535 1536__all__ = [ "StateMachine" ] 1537