StateMachine.py revision 10919
12292SN/A# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 22292SN/A# Copyright (c) 2009 The Hewlett-Packard Development Company 32292SN/A# All rights reserved. 42292SN/A# 52292SN/A# Redistribution and use in source and binary forms, with or without 62292SN/A# modification, are permitted provided that the following conditions are 72292SN/A# met: redistributions of source code must retain the above copyright 82292SN/A# notice, this list of conditions and the following disclaimer; 92292SN/A# redistributions in binary form must reproduce the above copyright 102292SN/A# notice, this list of conditions and the following disclaimer in the 112292SN/A# documentation and/or other materials provided with the distribution; 122292SN/A# neither the name of the copyright holders nor the names of its 132292SN/A# contributors may be used to endorse or promote products derived from 142292SN/A# this software without specific prior written permission. 152292SN/A# 162292SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172292SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182292SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192292SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202292SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212292SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222292SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232292SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242292SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252292SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262292SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272689Sktlim@umich.edu 282689Sktlim@umich.edufrom m5.util import orderdict 292689Sktlim@umich.edu 302292SN/Afrom slicc.symbols.Symbol import Symbol 312292SN/Afrom slicc.symbols.Var import Var 322316SN/Aimport slicc.generate.html as html 332292SN/Aimport re 342292SN/A 352669Sktlim@umich.edupython_class_map = { 362292SN/A "int": "Int", 372669Sktlim@umich.edu "uint32_t" : "UInt32", 382678Sktlim@umich.edu "std::string": "String", 392678Sktlim@umich.edu "bool": "Bool", 402678Sktlim@umich.edu "CacheMemory": "RubyCache", 412292SN/A "WireBuffer": "RubyWireBuffer", 422678Sktlim@umich.edu "Sequencer": "RubySequencer", 432292SN/A "DirectoryMemory": "RubyDirectoryMemory", 442292SN/A "MemoryControl": "MemoryControl", 452669Sktlim@umich.edu "DMASequencer": "DMASequencer", 462292SN/A "Prefetcher":"Prefetcher", 472678Sktlim@umich.edu "Cycles":"Cycles", 482292SN/A } 492678Sktlim@umich.edu 502678Sktlim@umich.educlass StateMachine(Symbol): 512678Sktlim@umich.edu def __init__(self, symtab, ident, location, pairs, config_parameters): 522678Sktlim@umich.edu super(StateMachine, self).__init__(symtab, ident, location, pairs) 532678Sktlim@umich.edu self.table = None 542292SN/A 552678Sktlim@umich.edu # Data members in the State Machine that have been declared before 562678Sktlim@umich.edu # the opening brace '{' of the machine. Note that these along with 572678Sktlim@umich.edu # the members in self.objects form the entire set of data members. 582678Sktlim@umich.edu self.config_parameters = config_parameters 592678Sktlim@umich.edu 602678Sktlim@umich.edu self.prefetchers = [] 612292SN/A 622678Sktlim@umich.edu for param in config_parameters: 632678Sktlim@umich.edu if param.pointer: 642678Sktlim@umich.edu var = Var(symtab, param.ident, location, param.type_ast.type, 652678Sktlim@umich.edu "(*m_%s_ptr)" % param.ident, {}, self) 662678Sktlim@umich.edu else: 672678Sktlim@umich.edu var = Var(symtab, param.ident, location, param.type_ast.type, 682678Sktlim@umich.edu "m_%s" % param.ident, {}, self) 692678Sktlim@umich.edu 702344SN/A self.symtab.registerSym(param.ident, var) 712678Sktlim@umich.edu 722678Sktlim@umich.edu if str(param.type_ast.type) == "Prefetcher": 732678Sktlim@umich.edu self.prefetchers.append(var) 742678Sktlim@umich.edu 752678Sktlim@umich.edu self.states = orderdict() 762307SN/A self.events = orderdict() 772678Sktlim@umich.edu self.actions = orderdict() 782678Sktlim@umich.edu self.request_types = orderdict() 792678Sktlim@umich.edu self.transitions = [] 802678Sktlim@umich.edu self.in_ports = [] 812678Sktlim@umich.edu self.functions = [] 822678Sktlim@umich.edu 832678Sktlim@umich.edu # Data members in the State Machine that have been declared inside 842678Sktlim@umich.edu # the {} machine. Note that these along with the config params 852344SN/A # form the entire set of data members of the machine. 862307SN/A self.objects = [] 872678Sktlim@umich.edu self.TBEType = None 882678Sktlim@umich.edu self.EntryType = None 892292SN/A 902292SN/A def __repr__(self): 912292SN/A return "[StateMachine: %s]" % self.ident 922669Sktlim@umich.edu 932669Sktlim@umich.edu def addState(self, state): 942292SN/A assert self.table is None 952669Sktlim@umich.edu self.states[state.ident] = state 962669Sktlim@umich.edu 972669Sktlim@umich.edu def addEvent(self, event): 982669Sktlim@umich.edu assert self.table is None 992669Sktlim@umich.edu self.events[event.ident] = event 1002669Sktlim@umich.edu 1012669Sktlim@umich.edu def addAction(self, action): 1022669Sktlim@umich.edu assert self.table is None 1032669Sktlim@umich.edu 1042669Sktlim@umich.edu # Check for duplicate action 1052669Sktlim@umich.edu for other in self.actions.itervalues(): 1062669Sktlim@umich.edu if action.ident == other.ident: 1072669Sktlim@umich.edu action.warning("Duplicate action definition: %s" % action.ident) 1082669Sktlim@umich.edu action.error("Duplicate action definition: %s" % action.ident) 1092669Sktlim@umich.edu if action.short == other.short: 1102669Sktlim@umich.edu other.warning("Duplicate action shorthand: %s" % other.ident) 1112669Sktlim@umich.edu other.warning(" shorthand = %s" % other.short) 1122669Sktlim@umich.edu action.warning("Duplicate action shorthand: %s" % action.ident) 1132669Sktlim@umich.edu action.error(" shorthand = %s" % action.short) 1142669Sktlim@umich.edu 1152669Sktlim@umich.edu self.actions[action.ident] = action 1162669Sktlim@umich.edu 1172669Sktlim@umich.edu def addRequestType(self, request_type): 1182669Sktlim@umich.edu assert self.table is None 1192669Sktlim@umich.edu self.request_types[request_type.ident] = request_type 1202669Sktlim@umich.edu 1212669Sktlim@umich.edu def addTransition(self, trans): 1222669Sktlim@umich.edu assert self.table is None 1232669Sktlim@umich.edu self.transitions.append(trans) 1242669Sktlim@umich.edu 1252669Sktlim@umich.edu def addInPort(self, var): 1262669Sktlim@umich.edu self.in_ports.append(var) 1272669Sktlim@umich.edu 1282669Sktlim@umich.edu def addFunc(self, func): 1292669Sktlim@umich.edu # register func in the symbol table 1302669Sktlim@umich.edu self.symtab.registerSym(str(func), func) 1312669Sktlim@umich.edu self.functions.append(func) 1322669Sktlim@umich.edu 1332669Sktlim@umich.edu def addObject(self, obj): 1342669Sktlim@umich.edu self.symtab.registerSym(str(obj), obj) 1352669Sktlim@umich.edu self.objects.append(obj) 1362669Sktlim@umich.edu 1372669Sktlim@umich.edu def addType(self, type): 1382669Sktlim@umich.edu type_ident = '%s' % type.c_ident 1392669Sktlim@umich.edu 1402292SN/A if type_ident == "%s_TBE" %self.ident: 1412292SN/A if self.TBEType != None: 1422292SN/A self.error("Multiple Transaction Buffer types in a " \ 1432292SN/A "single machine."); 1442678Sktlim@umich.edu self.TBEType = type 1452678Sktlim@umich.edu 1462292SN/A elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 1472292SN/A if self.EntryType != None: 1482292SN/A self.error("Multiple AbstractCacheEntry types in a " \ 1492292SN/A "single machine."); 1502292SN/A self.EntryType = type 1512292SN/A 1522292SN/A # Needs to be called before accessing the table 1532292SN/A def buildTable(self): 1542292SN/A assert self.table is None 1552292SN/A 1562292SN/A table = {} 1572307SN/A 1582307SN/A for trans in self.transitions: 1592292SN/A # Track which actions we touch so we know if we use them 1602292SN/A # all -- really this should be done for all symbols as 1612329SN/A # part of the symbol table, then only trigger it for 1622329SN/A # Actions, States, Events, etc. 1632329SN/A 1642292SN/A for action in trans.actions: 1652292SN/A action.used = True 1662292SN/A 1672292SN/A index = (trans.state, trans.event) 1682292SN/A if index in table: 1692292SN/A table[index].warning("Duplicate transition: %s" % table[index]) 1702292SN/A trans.error("Duplicate transition: %s" % trans) 1712292SN/A table[index] = trans 1722292SN/A 1732292SN/A # Look at all actions to make sure we used them all 1742292SN/A for action in self.actions.itervalues(): 1752678Sktlim@umich.edu if not action.used: 1762292SN/A error_msg = "Unused action: %s" % action.ident 1772329SN/A if "desc" in action: 1782292SN/A error_msg += ", " + action.desc 1792292SN/A action.warning(error_msg) 1802292SN/A self.table = table 1812292SN/A 1822292SN/A def writeCodeFiles(self, path, includes): 1832669Sktlim@umich.edu self.printControllerPython(path) 1842669Sktlim@umich.edu self.printControllerHH(path) 1852669Sktlim@umich.edu self.printControllerCC(path, includes) 1862669Sktlim@umich.edu self.printCSwitch(path) 1872669Sktlim@umich.edu self.printCWakeup(path, includes) 1882678Sktlim@umich.edu 1892678Sktlim@umich.edu def printControllerPython(self, path): 1902678Sktlim@umich.edu code = self.symtab.codeFormatter() 1912678Sktlim@umich.edu ident = self.ident 1922679Sktlim@umich.edu 1932679Sktlim@umich.edu py_ident = "%s_Controller" % ident 1942679Sktlim@umich.edu c_ident = "%s_Controller" % self.ident 1952679Sktlim@umich.edu 1962669Sktlim@umich.edu code(''' 1972669Sktlim@umich.edufrom m5.params import * 1982669Sktlim@umich.edufrom m5.SimObject import SimObject 1992292SN/Afrom Controller import RubyController 2002292SN/A 2012292SN/Aclass $py_ident(RubyController): 2022292SN/A type = '$py_ident' 2032292SN/A cxx_header = 'mem/protocol/${c_ident}.hh' 2042292SN/A''') 2052292SN/A code.indent() 2062292SN/A for param in self.config_parameters: 2072292SN/A dflt_str = '' 2082292SN/A 2092292SN/A if param.rvalue is not None: 2102292SN/A dflt_str = str(param.rvalue.inline()) + ', ' 2112292SN/A 2122292SN/A if param.type_ast.type.c_ident == "MessageBuffer": 2132292SN/A if param["network"] == "To": 2142292SN/A code('${{param.ident}} = MasterPort(${dflt_str}"")') 2152292SN/A else: 2162292SN/A code('${{param.ident}} = SlavePort(${dflt_str}"")') 2172292SN/A 2182292SN/A elif python_class_map.has_key(param.type_ast.type.c_ident): 2192292SN/A python_type = python_class_map[param.type_ast.type.c_ident] 2202292SN/A code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")') 2212292SN/A 2222292SN/A else: 2232292SN/A self.error("Unknown c++ to python class conversion for c++ " \ 2242292SN/A "type: '%s'. Please update the python_class_map " \ 2252292SN/A "in StateMachine.py", param.type_ast.type.c_ident) 2262292SN/A code.dedent() 2272292SN/A code.write(path, '%s.py' % py_ident) 2282292SN/A 2292292SN/A 2302292SN/A def printControllerHH(self, path): 2312292SN/A '''Output the method declarations for the class declaration''' 2322292SN/A code = self.symtab.codeFormatter() 2332292SN/A ident = self.ident 2342292SN/A c_ident = "%s_Controller" % self.ident 2352307SN/A 2362307SN/A code(''' 2372307SN/A/** \\file $c_ident.hh 2382307SN/A * 2392307SN/A * Auto generated C++ code started by $__file__:$__line__ 2402307SN/A * Created by slicc definition of Module "${{self.short}}" 2412329SN/A */ 2422307SN/A 2432307SN/A#ifndef __${ident}_CONTROLLER_HH__ 2442307SN/A#define __${ident}_CONTROLLER_HH__ 2452307SN/A 2462307SN/A#include <iostream> 2472307SN/A#include <sstream> 2482307SN/A#include <string> 2492307SN/A 2502307SN/A#include "mem/protocol/TransitionResult.hh" 2512307SN/A#include "mem/protocol/Types.hh" 2522307SN/A#include "mem/ruby/common/Consumer.hh" 2532307SN/A#include "mem/ruby/common/Global.hh" 2542307SN/A#include "mem/ruby/slicc_interface/AbstractController.hh" 2552307SN/A#include "params/$c_ident.hh" 2562307SN/A''') 2572329SN/A 2582307SN/A seen_types = set() 2592307SN/A for var in self.objects: 2602307SN/A if var.type.ident not in seen_types and not var.type.isPrimitive: 2612307SN/A code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 2622307SN/A seen_types.add(var.type.ident) 2632307SN/A 2642307SN/A # for adding information to the protocol debug trace 2652307SN/A code(''' 2662307SN/Aextern std::stringstream ${ident}_transitionComment; 2672307SN/A 2682292SN/Aclass $c_ident : public AbstractController 2692292SN/A{ 2702329SN/A public: 2712329SN/A typedef ${c_ident}Params Params; 2722292SN/A $c_ident(const Params *p); 2732329SN/A static int getNumControllers(); 2742329SN/A void init(); 2752292SN/A 2762292SN/A MessageBuffer* getMandatoryQueue() const; 2772292SN/A void setNetQueue(const std::string& name, MessageBuffer *b); 2782292SN/A 2792292SN/A void print(std::ostream& out) const; 2802329SN/A void wakeup(); 2812292SN/A void resetStats(); 2822292SN/A void regStats(); 2832292SN/A void collateStats(); 2842292SN/A 2852292SN/A void recordCacheTrace(int cntrl, CacheRecorder* tr); 2862292SN/A Sequencer* getSequencer() const; 2872292SN/A 2882292SN/A int functionalWriteBuffers(PacketPtr&); 2892329SN/A 2902329SN/A void countTransition(${ident}_State state, ${ident}_Event event); 2912329SN/A void possibleTransition(${ident}_State state, ${ident}_Event event); 2922292SN/A uint64 getEventCount(${ident}_Event event); 2932292SN/A bool isPossible(${ident}_State state, ${ident}_Event event); 2942292SN/A uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 2952292SN/A 2962292SN/Aprivate: 2972329SN/A''') 2982292SN/A 2992292SN/A code.indent() 3002292SN/A # added by SS 3012292SN/A for param in self.config_parameters: 3022292SN/A if param.pointer: 3032292SN/A code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 3042292SN/A else: 3052292SN/A code('${{param.type_ast.type}} m_${{param.ident}};') 3062292SN/A 3072292SN/A code(''' 3082292SN/ATransitionResult doTransition(${ident}_Event event, 3092292SN/A''') 3102292SN/A 3112292SN/A if self.EntryType != None: 3122292SN/A code(''' 3132292SN/A ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 3142292SN/A''') 3152292SN/A if self.TBEType != None: 3162292SN/A code(''' 3172292SN/A ${{self.TBEType.c_ident}}* m_tbe_ptr, 3182292SN/A''') 3192292SN/A 3202292SN/A code(''' 3212292SN/A const Address addr); 3222329SN/A 3232329SN/ATransitionResult doTransitionWorker(${ident}_Event event, 3242292SN/A ${ident}_State state, 3252292SN/A ${ident}_State& next_state, 3262292SN/A''') 3272292SN/A 3282292SN/A if self.TBEType != None: 3292292SN/A code(''' 3302292SN/A ${{self.TBEType.c_ident}}*& m_tbe_ptr, 3312292SN/A''') 3322292SN/A if self.EntryType != None: 3332292SN/A code(''' 3342292SN/A ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 3352292SN/A''') 3362292SN/A 3372292SN/A code(''' 3382292SN/A const Address& addr); 3392292SN/A 3402292SN/Aint m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 3412292SN/Aint m_event_counters[${ident}_Event_NUM]; 3422292SN/Abool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 3432292SN/A 3442292SN/Astatic std::vector<Stats::Vector *> eventVec; 3452292SN/Astatic std::vector<std::vector<Stats::Vector *> > transVec; 3462292SN/Astatic int m_num_controllers; 3472292SN/A 3482292SN/A// Internal functions 3492292SN/A''') 3502292SN/A 3512292SN/A for func in self.functions: 3522292SN/A proto = func.prototype 3532292SN/A if proto: 3542292SN/A code('$proto') 3552292SN/A 3562292SN/A if self.EntryType != None: 3572292SN/A code(''' 3582292SN/A 3592292SN/A// Set and Reset for cache_entry variable 3602292SN/Avoid set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 3612292SN/Avoid unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 3622292SN/A''') 3632292SN/A 3642292SN/A if self.TBEType != None: 3652292SN/A code(''' 3662292SN/A 3672292SN/A// Set and Reset for tbe variable 3682292SN/Avoid set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 3692292SN/Avoid unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 3702292SN/A''') 3712292SN/A 3722292SN/A # Prototype the actions that the controller can take 3732292SN/A code(''' 3742292SN/A 3752292SN/A// Actions 3762292SN/A''') 3772292SN/A if self.TBEType != None and self.EntryType != None: 3782292SN/A for action in self.actions.itervalues(): 3792292SN/A code('/** \\brief ${{action.desc}} */') 3802292SN/A code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 3812292SN/A 'm_tbe_ptr, ${{self.EntryType.c_ident}}*& ' 3822292SN/A 'm_cache_entry_ptr, const Address& addr);') 3832292SN/A elif self.TBEType != None: 3842292SN/A for action in self.actions.itervalues(): 3852292SN/A code('/** \\brief ${{action.desc}} */') 3862292SN/A code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 3872292SN/A 'm_tbe_ptr, const Address& addr);') 3882292SN/A elif self.EntryType != None: 3892292SN/A for action in self.actions.itervalues(): 3902292SN/A code('/** \\brief ${{action.desc}} */') 3912292SN/A code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& ' 3922292SN/A 'm_cache_entry_ptr, const Address& addr);') 3932292SN/A else: 3942292SN/A for action in self.actions.itervalues(): 3952292SN/A code('/** \\brief ${{action.desc}} */') 3962292SN/A code('void ${{action.ident}}(const Address& addr);') 3972292SN/A 3982292SN/A # the controller internal variables 3992292SN/A code(''' 4002292SN/A 4012292SN/A// Objects 4022292SN/A''') 4032292SN/A for var in self.objects: 4042292SN/A th = var.get("template", "") 4052292SN/A code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;') 4062292SN/A 4072292SN/A code.dedent() 4082292SN/A code('};') 4092292SN/A code('#endif // __${ident}_CONTROLLER_H__') 4102292SN/A code.write(path, '%s.hh' % c_ident) 4112292SN/A 4122292SN/A def printControllerCC(self, path, includes): 4132292SN/A '''Output the actions for performing the actions''' 4142292SN/A 4152292SN/A code = self.symtab.codeFormatter() 4162292SN/A ident = self.ident 4172292SN/A c_ident = "%s_Controller" % self.ident 4182292SN/A 4192669Sktlim@umich.edu code(''' 4202292SN/A/** \\file $c_ident.cc 4212292SN/A * 4222292SN/A * Auto generated C++ code started by $__file__:$__line__ 4232292SN/A * Created by slicc definition of Module "${{self.short}}" 4242329SN/A */ 4252329SN/A 4262292SN/A#include <sys/types.h> 4272292SN/A#include <unistd.h> 4282292SN/A 4292292SN/A#include <cassert> 4302292SN/A#include <sstream> 4312292SN/A#include <string> 4322292SN/A 4332292SN/A#include "base/compiler.hh" 4342292SN/A#include "base/cprintf.hh" 4352292SN/A#include "debug/RubyGenerated.hh" 4362292SN/A#include "debug/RubySlicc.hh" 4372292SN/A#include "mem/protocol/${ident}_Controller.hh" 4382292SN/A#include "mem/protocol/${ident}_Event.hh" 4392292SN/A#include "mem/protocol/${ident}_State.hh" 4402292SN/A#include "mem/protocol/Types.hh" 4412292SN/A#include "mem/ruby/common/Global.hh" 4422292SN/A#include "mem/ruby/system/System.hh" 4432292SN/A''') 4442292SN/A for include_path in includes: 4452292SN/A code('#include "${{include_path}}"') 4462292SN/A 4472292SN/A code(''' 4482292SN/A 4492292SN/Ausing namespace std; 4502292SN/A''') 4512292SN/A 4522329SN/A # include object classes 4532292SN/A seen_types = set() 4542292SN/A for var in self.objects: 4552292SN/A if var.type.ident not in seen_types and not var.type.isPrimitive: 4562292SN/A code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 4572292SN/A seen_types.add(var.type.ident) 4582292SN/A 4592292SN/A num_in_ports = len(self.in_ports) 4602292SN/A 4612336SN/A code(''' 4622336SN/A$c_ident * 4632336SN/A${c_ident}Params::create() 4642329SN/A{ 4652292SN/A return new $c_ident(this); 4662329SN/A} 4672292SN/A 4682292SN/Aint $c_ident::m_num_controllers = 0; 4692292SN/Astd::vector<Stats::Vector *> $c_ident::eventVec; 4702292SN/Astd::vector<std::vector<Stats::Vector *> > $c_ident::transVec; 4712329SN/A 4722329SN/A// for adding information to the protocol debug trace 4732329SN/Astringstream ${ident}_transitionComment; 4742292SN/A 4752329SN/A#ifndef NDEBUG 4762329SN/A#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 4772329SN/A#else 4782329SN/A#define APPEND_TRANSITION_COMMENT(str) do {} while (0) 4792292SN/A#endif 4802292SN/A 4812292SN/A/** \\brief constructor */ 4822292SN/A$c_ident::$c_ident(const Params *p) 4832292SN/A : AbstractController(p) 4842292SN/A{ 4852292SN/A m_machineID.type = MachineType_${ident}; 4862292SN/A m_machineID.num = m_version; 4872292SN/A m_num_controllers++; 4882292SN/A 4892292SN/A m_in_ports = $num_in_ports; 4902292SN/A''') 4912292SN/A code.indent() 4922292SN/A 4932292SN/A # 4942292SN/A # After initializing the universal machine parameters, initialize the 4952292SN/A # this machines config parameters. Also if these configuration params 4962292SN/A # include a sequencer, connect the it to the controller. 4972292SN/A # 4982292SN/A for param in self.config_parameters: 4992292SN/A 5002292SN/A # Do not initialize messgage buffers since they are initialized 5012292SN/A # when the port based connections are made. 5022292SN/A if param.type_ast.type.c_ident == "MessageBuffer": 5032292SN/A continue 5042292SN/A 5052292SN/A if param.pointer: 5062292SN/A code('m_${{param.ident}}_ptr = p->${{param.ident}};') 5072292SN/A else: 5082292SN/A code('m_${{param.ident}} = p->${{param.ident}};') 5092292SN/A 5102292SN/A if re.compile("sequencer").search(param.ident): 5112292SN/A code('m_${{param.ident}}_ptr->setController(this);') 5122292SN/A 5132292SN/A for var in self.objects: 5142292SN/A if var.ident.find("mandatoryQueue") >= 0: 5152292SN/A code(''' 5162292SN/Am_${{var.ident}}_ptr = new ${{var.type.c_ident}}(); 5172292SN/Am_${{var.ident}}_ptr->setReceiver(this); 5182292SN/A''') 5192292SN/A 5202292SN/A code(''' 5212292SN/A 5222292SN/Afor (int state = 0; state < ${ident}_State_NUM; state++) { 5232292SN/A for (int event = 0; event < ${ident}_Event_NUM; event++) { 5242292SN/A m_possible[state][event] = false; 5252292SN/A m_counters[state][event] = 0; 5262292SN/A } 5272292SN/A} 5282292SN/Afor (int event = 0; event < ${ident}_Event_NUM; event++) { 5292292SN/A m_event_counters[event] = 0; 5302292SN/A} 5312292SN/A''') 5322292SN/A code.dedent() 5332292SN/A code(''' 5342292SN/A} 5352292SN/A 5362329SN/Avoid 5372329SN/A$c_ident::setNetQueue(const std::string& name, MessageBuffer *b) 5382292SN/A{ 5392292SN/A MachineType machine_type = string_to_MachineType("${{self.ident}}"); 5402292SN/A int base M5_VAR_USED = MachineType_base_number(machine_type); 5412292SN/A 5422292SN/A''') 5432292SN/A code.indent() 5442292SN/A 5452292SN/A # set for maintaining the vnet, direction pairs already seen for this 5462292SN/A # machine. This map helps in implementing the check for avoiding 5472292SN/A # multiple message buffers being mapped to the same vnet. 5482292SN/A vnet_dir_set = set() 5492292SN/A 5502292SN/A for var in self.config_parameters: 5512292SN/A if "network" in var: 5522292SN/A vtype = var.type_ast.type 5532292SN/A vid = "m_%s_ptr" % var.ident 5542292SN/A 5552292SN/A code(''' 5562292SN/Aif ("${{var.ident}}" == name) { 5572292SN/A $vid = b; 5582292SN/A assert($vid != NULL); 5592292SN/A''') 5602292SN/A code.indent() 5612292SN/A # Network port object 5622292SN/A network = var["network"] 5632292SN/A ordered = var["ordered"] 5642292SN/A 5652292SN/A if "virtual_network" in var: 5662678Sktlim@umich.edu vnet = var["virtual_network"] 5672678Sktlim@umich.edu vnet_type = var["vnet_type"] 5682678Sktlim@umich.edu 5692678Sktlim@umich.edu assert (vnet, network) not in vnet_dir_set 5702678Sktlim@umich.edu vnet_dir_set.add((vnet,network)) 5712678Sktlim@umich.edu 5722329SN/A code(''' 5732329SN/Am_net_ptr->set${network}NetQueue(m_version + base, $ordered, $vnet, 5742292SN/A "$vnet_type", b); 5752292SN/A''') 5762292SN/A # Set the end 5772292SN/A if network == "To": 5782292SN/A code('$vid->setSender(this);') 5792292SN/A else: 5802292SN/A code('$vid->setReceiver(this);') 5812678Sktlim@umich.edu 5822292SN/A # Set ordering 5832292SN/A code('$vid->setOrdering(${{var["ordered"]}});') 5842292SN/A 5852292SN/A # Set randomization 5862292SN/A if "random" in var: 5872292SN/A # A buffer 5882292SN/A code('$vid->setRandomization(${{var["random"]}});') 5892292SN/A 5902292SN/A # Set Priority 5912292SN/A if "rank" in var: 5922292SN/A code('$vid->setPriority(${{var["rank"]}})') 5932669Sktlim@umich.edu 5942669Sktlim@umich.edu # Set buffer size 5952669Sktlim@umich.edu code('$vid->resize(m_buffer_size);') 5962292SN/A 5972292SN/A if "recycle_latency" in var: 5982669Sktlim@umich.edu code('$vid->setRecycleLatency( ' \ 5992669Sktlim@umich.edu 'Cycles(${{var["recycle_latency"]}}));') 6002678Sktlim@umich.edu else: 6012678Sktlim@umich.edu code('$vid->setRecycleLatency(m_recycle_latency);') 6022669Sktlim@umich.edu 6032669Sktlim@umich.edu # set description (may be overriden later by port def) 6042669Sktlim@umich.edu code(''' 6052292SN/A$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.ident}}]"); 6062678Sktlim@umich.edu''') 6072678Sktlim@umich.edu code.dedent() 6082678Sktlim@umich.edu code('}\n') 6092678Sktlim@umich.edu 6102678Sktlim@umich.edu code.dedent() 6112678Sktlim@umich.edu code(''' 6122292SN/A} 6132292SN/A 6142669Sktlim@umich.eduvoid 6152669Sktlim@umich.edu$c_ident::init() 6162292SN/A{ 6172292SN/A // initialize objects 6182669Sktlim@umich.edu 6192669Sktlim@umich.edu''') 6202678Sktlim@umich.edu 6212669Sktlim@umich.edu code.indent() 6222292SN/A 6232292SN/A for var in self.objects: 6242292SN/A vtype = var.type 6252292SN/A vid = "m_%s_ptr" % var.ident 6262292SN/A if "network" not in var: 6272292SN/A # Not a network port object 6282292SN/A if "primitive" in vtype: 6292292SN/A code('$vid = new ${{vtype.c_ident}};') 6302292SN/A if "default" in var: 6312678Sktlim@umich.edu code('(*$vid) = ${{var["default"]}};') 6322678Sktlim@umich.edu else: 6332678Sktlim@umich.edu # Normal Object 6342678Sktlim@umich.edu if var.ident.find("mandatoryQueue") < 0: 6352678Sktlim@umich.edu th = var.get("template", "") 6362329SN/A expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 6372678Sktlim@umich.edu args = "" 6382669Sktlim@umich.edu if "non_obj" not in vtype and not vtype.isEnumeration: 6392329SN/A args = var.get("constructor", "") 6402329SN/A code('$expr($args);') 6412292SN/A 6422292SN/A code('assert($vid != NULL);') 6432292SN/A 6442292SN/A if "default" in var: 6452292SN/A code('*$vid = ${{var["default"]}}; // Object default') 6462292SN/A elif "default" in vtype: 6472292SN/A comment = "Type %s default" % vtype.ident 6482292SN/A code('*$vid = ${{vtype["default"]}}; // $comment') 6492329SN/A 6502292SN/A # Set ordering 6512292SN/A if "ordered" in var: 6522292SN/A # A buffer 6532292SN/A code('$vid->setOrdering(${{var["ordered"]}});') 6542292SN/A 6552292SN/A # Set randomization 6562292SN/A if "random" in var: 6572292SN/A # A buffer 6582292SN/A code('$vid->setRandomization(${{var["random"]}});') 6592292SN/A 6602292SN/A # Set Priority 6612292SN/A if vtype.isBuffer and "rank" in var: 6622292SN/A code('$vid->setPriority(${{var["rank"]}});') 6632292SN/A 6642292SN/A # Set sender and receiver for trigger queue 6652292SN/A if var.ident.find("triggerQueue") >= 0: 6662292SN/A code('$vid->setSender(this);') 6672292SN/A code('$vid->setReceiver(this);') 6682292SN/A elif vtype.c_ident == "TimerTable": 6692292SN/A code('$vid->setClockObj(this);') 6702292SN/A elif var.ident.find("optionalQueue") >= 0: 6712292SN/A code('$vid->setSender(this);') 6722292SN/A code('$vid->setReceiver(this);') 6732292SN/A 6742292SN/A if vtype.isBuffer: 6752292SN/A if "recycle_latency" in var: 6762292SN/A code('$vid->setRecycleLatency( ' \ 6772292SN/A 'Cycles(${{var["recycle_latency"]}}));') 6782292SN/A else: 6792292SN/A code('$vid->setRecycleLatency(m_recycle_latency);') 6802292SN/A 6812292SN/A # Set the prefetchers 6822292SN/A code() 6832292SN/A for prefetcher in self.prefetchers: 6842292SN/A code('${{prefetcher.code}}.setController(this);') 6852292SN/A 6862292SN/A code() 6872329SN/A for port in self.in_ports: 6882292SN/A # Set the queue consumers 6892292SN/A code('${{port.code}}.setConsumer(this);') 6902292SN/A # Set the queue descriptions 6912292SN/A code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");') 6922292SN/A 6932292SN/A # Initialize the transition profiling 6942292SN/A code() 6952292SN/A for trans in self.transitions: 6962292SN/A # Figure out if we stall 6972292SN/A stall = False 6982292SN/A for action in trans.actions: 6992292SN/A if action.ident == "z_stall": 7002292SN/A stall = True 7012292SN/A 7022292SN/A # Only possible if it is not a 'z' case 7032292SN/A if not stall: 7042329SN/A state = "%s_State_%s" % (self.ident, trans.state.ident) 7052292SN/A event = "%s_Event_%s" % (self.ident, trans.event.ident) 7062292SN/A code('possibleTransition($state, $event);') 7072292SN/A 7082292SN/A code.dedent() 7092292SN/A code(''' 7102292SN/A AbstractController::init(); 7112292SN/A resetStats(); 7122292SN/A} 7132292SN/A''') 7142292SN/A 7152292SN/A mq_ident = "NULL" 7162292SN/A for port in self.in_ports: 7172292SN/A if port.code.find("mandatoryQueue_ptr") >= 0: 7182292SN/A mq_ident = "m_mandatoryQueue_ptr" 7192292SN/A 7202292SN/A seq_ident = "NULL" 7212292SN/A for param in self.config_parameters: 7222292SN/A if param.ident == "sequencer": 7232292SN/A assert(param.pointer) 7242292SN/A seq_ident = "m_%s_ptr" % param.ident 7252292SN/A 7262292SN/A code(''' 7272292SN/A 7282329SN/Avoid 7292292SN/A$c_ident::regStats() 7302292SN/A{ 7312292SN/A AbstractController::regStats(); 7322292SN/A 7332292SN/A if (m_version == 0) { 7342292SN/A for (${ident}_Event event = ${ident}_Event_FIRST; 7352292SN/A event < ${ident}_Event_NUM; ++event) { 7362292SN/A Stats::Vector *t = new Stats::Vector(); 7372292SN/A t->init(m_num_controllers); 7382329SN/A t->name(params()->ruby_system->name() + ".${c_ident}." + 7392329SN/A ${ident}_Event_to_string(event)); 7402292SN/A t->flags(Stats::pdf | Stats::total | Stats::oneline | 7412292SN/A Stats::nozero); 7422292SN/A 7432292SN/A eventVec.push_back(t); 7442292SN/A } 7452292SN/A 7462292SN/A for (${ident}_State state = ${ident}_State_FIRST; 7472329SN/A state < ${ident}_State_NUM; ++state) { 7482292SN/A 7492292SN/A transVec.push_back(std::vector<Stats::Vector *>()); 7502292SN/A 7512292SN/A for (${ident}_Event event = ${ident}_Event_FIRST; 7522292SN/A event < ${ident}_Event_NUM; ++event) { 7532292SN/A 7542292SN/A Stats::Vector *t = new Stats::Vector(); 7552292SN/A t->init(m_num_controllers); 7562292SN/A t->name(params()->ruby_system->name() + ".${c_ident}." + 7572292SN/A ${ident}_State_to_string(state) + 7582292SN/A "." + ${ident}_Event_to_string(event)); 7592292SN/A 7602292SN/A t->flags(Stats::pdf | Stats::total | Stats::oneline | 7612292SN/A Stats::nozero); 7622292SN/A transVec[state].push_back(t); 7632292SN/A } 7642678Sktlim@umich.edu } 7652678Sktlim@umich.edu } 7662678Sktlim@umich.edu} 7672678Sktlim@umich.edu 7682678Sktlim@umich.eduvoid 7692678Sktlim@umich.edu$c_ident::collateStats() 7702678Sktlim@umich.edu{ 7712678Sktlim@umich.edu for (${ident}_Event event = ${ident}_Event_FIRST; 7722678Sktlim@umich.edu event < ${ident}_Event_NUM; ++event) { 7732678Sktlim@umich.edu for (unsigned int i = 0; i < m_num_controllers; ++i) { 7742678Sktlim@umich.edu std::map<uint32_t, AbstractController *>::iterator it = 7752678Sktlim@umich.edu g_abs_controls[MachineType_${ident}].find(i); 7762678Sktlim@umich.edu assert(it != g_abs_controls[MachineType_${ident}].end()); 7772678Sktlim@umich.edu (*eventVec[event])[i] = 7782678Sktlim@umich.edu (($c_ident *)(*it).second)->getEventCount(event); 7792678Sktlim@umich.edu } 7802678Sktlim@umich.edu } 7812678Sktlim@umich.edu 7822678Sktlim@umich.edu for (${ident}_State state = ${ident}_State_FIRST; 7832678Sktlim@umich.edu state < ${ident}_State_NUM; ++state) { 7842678Sktlim@umich.edu 7852678Sktlim@umich.edu for (${ident}_Event event = ${ident}_Event_FIRST; 7862678Sktlim@umich.edu event < ${ident}_Event_NUM; ++event) { 7872678Sktlim@umich.edu 7882678Sktlim@umich.edu for (unsigned int i = 0; i < m_num_controllers; ++i) { 7892292SN/A std::map<uint32_t, AbstractController *>::iterator it = 7902292SN/A g_abs_controls[MachineType_${ident}].find(i); 7912292SN/A assert(it != g_abs_controls[MachineType_${ident}].end()); 7922292SN/A (*transVec[state][event])[i] = 7932292SN/A (($c_ident *)(*it).second)->getTransitionCount(state, event); 7942292SN/A } 7952292SN/A } 7962292SN/A } 7972292SN/A} 7982292SN/A 7992292SN/Avoid 8002292SN/A$c_ident::countTransition(${ident}_State state, ${ident}_Event event) 8012292SN/A{ 8022292SN/A assert(m_possible[state][event]); 8032292SN/A m_counters[state][event]++; 8042292SN/A m_event_counters[event]++; 8052292SN/A} 8062292SN/Avoid 8072292SN/A$c_ident::possibleTransition(${ident}_State state, 8082292SN/A ${ident}_Event event) 8092292SN/A{ 8102329SN/A m_possible[state][event] = true; 8112329SN/A} 8122329SN/A 8132292SN/Auint64 8142292SN/A$c_ident::getEventCount(${ident}_Event event) 8152292SN/A{ 8162292SN/A return m_event_counters[event]; 8172292SN/A} 8182292SN/A 8192292SN/Abool 8202292SN/A$c_ident::isPossible(${ident}_State state, ${ident}_Event event) 8212292SN/A{ 8222292SN/A return m_possible[state][event]; 8232316SN/A} 8242316SN/A 8252329SN/Auint64 8262329SN/A$c_ident::getTransitionCount(${ident}_State state, 8272329SN/A ${ident}_Event event) 8282329SN/A{ 8292316SN/A return m_counters[state][event]; 8302316SN/A} 8312316SN/A 8322292SN/Aint 8332292SN/A$c_ident::getNumControllers() 8342292SN/A{ 8352292SN/A return m_num_controllers; 8362292SN/A} 8372292SN/A 8382292SN/AMessageBuffer* 8392292SN/A$c_ident::getMandatoryQueue() const 8402292SN/A{ 8412292SN/A return $mq_ident; 8422292SN/A} 8432292SN/A 8442292SN/ASequencer* 8452292SN/A$c_ident::getSequencer() const 8462292SN/A{ 8472292SN/A return $seq_ident; 8482292SN/A} 8492292SN/A 8502292SN/Avoid 8512292SN/A$c_ident::print(ostream& out) const 8522292SN/A{ 8532292SN/A out << "[$c_ident " << m_version << "]"; 8542292SN/A} 8552292SN/A 8562292SN/Avoid $c_ident::resetStats() 8572292SN/A{ 8582292SN/A for (int state = 0; state < ${ident}_State_NUM; state++) { 8592292SN/A for (int event = 0; event < ${ident}_Event_NUM; event++) { 8602292SN/A m_counters[state][event] = 0; 8612292SN/A } 8622292SN/A } 8632292SN/A 8642292SN/A for (int event = 0; event < ${ident}_Event_NUM; event++) { 8652329SN/A m_event_counters[event] = 0; 8662329SN/A } 8672329SN/A 8682329SN/A AbstractController::resetStats(); 8692329SN/A} 8702329SN/A''') 8712329SN/A 8722329SN/A if self.EntryType != None: 8732329SN/A code(''' 8742329SN/A 8752329SN/A// Set and Reset for cache_entry variable 8762329SN/Avoid 8772329SN/A$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 8782329SN/A{ 8792329SN/A m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 8802329SN/A} 8812329SN/A 8822329SN/Avoid 8832329SN/A$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 8842329SN/A{ 8852329SN/A m_cache_entry_ptr = 0; 8862329SN/A} 8872329SN/A''') 8882329SN/A 8892329SN/A if self.TBEType != None: 8902329SN/A code(''' 8912329SN/A 8922329SN/A// Set and Reset for tbe variable 8932329SN/Avoid 8942329SN/A$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 895{ 896 m_tbe_ptr = m_new_tbe; 897} 898 899void 900$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 901{ 902 m_tbe_ptr = NULL; 903} 904''') 905 906 code(''' 907 908void 909$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 910{ 911''') 912 # 913 # Record cache contents for all associated caches. 914 # 915 code.indent() 916 for param in self.config_parameters: 917 if param.type_ast.type.ident == "CacheMemory": 918 assert(param.pointer) 919 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 920 921 code.dedent() 922 code(''' 923} 924 925// Actions 926''') 927 if self.TBEType != None and self.EntryType != None: 928 for action in self.actions.itervalues(): 929 if "c_code" not in action: 930 continue 931 932 code(''' 933/** \\brief ${{action.desc}} */ 934void 935$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 936{ 937 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 938 ${{action["c_code"]}} 939} 940 941''') 942 elif self.TBEType != None: 943 for action in self.actions.itervalues(): 944 if "c_code" not in action: 945 continue 946 947 code(''' 948/** \\brief ${{action.desc}} */ 949void 950$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 951{ 952 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 953 ${{action["c_code"]}} 954} 955 956''') 957 elif self.EntryType != None: 958 for action in self.actions.itervalues(): 959 if "c_code" not in action: 960 continue 961 962 code(''' 963/** \\brief ${{action.desc}} */ 964void 965$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 966{ 967 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 968 ${{action["c_code"]}} 969} 970 971''') 972 else: 973 for action in self.actions.itervalues(): 974 if "c_code" not in action: 975 continue 976 977 code(''' 978/** \\brief ${{action.desc}} */ 979void 980$c_ident::${{action.ident}}(const Address& addr) 981{ 982 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 983 ${{action["c_code"]}} 984} 985 986''') 987 for func in self.functions: 988 code(func.generateCode()) 989 990 # Function for functional writes to messages buffered in the controller 991 code(''' 992int 993$c_ident::functionalWriteBuffers(PacketPtr& pkt) 994{ 995 int num_functional_writes = 0; 996''') 997 for var in self.objects: 998 vtype = var.type 999 if vtype.isBuffer: 1000 vid = "m_%s_ptr" % var.ident 1001 code('num_functional_writes += $vid->functionalWrite(pkt);') 1002 1003 for var in self.config_parameters: 1004 vtype = var.type_ast.type 1005 if vtype.isBuffer: 1006 vid = "m_%s_ptr" % var.ident 1007 code('num_functional_writes += $vid->functionalWrite(pkt);') 1008 1009 code(''' 1010 return num_functional_writes; 1011} 1012''') 1013 1014 code.write(path, "%s.cc" % c_ident) 1015 1016 def printCWakeup(self, path, includes): 1017 '''Output the wakeup loop for the events''' 1018 1019 code = self.symtab.codeFormatter() 1020 ident = self.ident 1021 1022 outputRequest_types = True 1023 if len(self.request_types) == 0: 1024 outputRequest_types = False 1025 1026 code(''' 1027// Auto generated C++ code started by $__file__:$__line__ 1028// ${ident}: ${{self.short}} 1029 1030#include <sys/types.h> 1031#include <unistd.h> 1032 1033#include <cassert> 1034 1035#include "base/misc.hh" 1036#include "debug/RubySlicc.hh" 1037#include "mem/protocol/${ident}_Controller.hh" 1038#include "mem/protocol/${ident}_Event.hh" 1039#include "mem/protocol/${ident}_State.hh" 1040''') 1041 1042 if outputRequest_types: 1043 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1044 1045 code(''' 1046#include "mem/protocol/Types.hh" 1047#include "mem/ruby/common/Global.hh" 1048#include "mem/ruby/system/System.hh" 1049''') 1050 1051 1052 for include_path in includes: 1053 code('#include "${{include_path}}"') 1054 1055 code(''' 1056 1057using namespace std; 1058 1059void 1060${ident}_Controller::wakeup() 1061{ 1062 int counter = 0; 1063 while (true) { 1064 // Some cases will put us into an infinite loop without this limit 1065 assert(counter <= m_transitions_per_cycle); 1066 if (counter == m_transitions_per_cycle) { 1067 // Count how often we are fully utilized 1068 m_fully_busy_cycles++; 1069 1070 // Wakeup in another cycle and try again 1071 scheduleEvent(Cycles(1)); 1072 break; 1073 } 1074''') 1075 1076 code.indent() 1077 code.indent() 1078 1079 # InPorts 1080 # 1081 for port in self.in_ports: 1082 code.indent() 1083 code('// ${ident}InPort $port') 1084 if port.pairs.has_key("rank"): 1085 code('m_cur_in_port = ${{port.pairs["rank"]}};') 1086 else: 1087 code('m_cur_in_port = 0;') 1088 code('${{port["c_code_in_port"]}}') 1089 code.dedent() 1090 1091 code('') 1092 1093 code.dedent() 1094 code.dedent() 1095 code(''' 1096 break; // If we got this far, we have nothing left todo 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/common/Global.hh" 1124#include "mem/ruby/system/System.hh" 1125 1126#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1127 1128#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1129#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1130 1131TransitionResult 1132${ident}_Controller::doTransition(${ident}_Event event, 1133''') 1134 if self.EntryType != None: 1135 code(''' 1136 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1137''') 1138 if self.TBEType != None: 1139 code(''' 1140 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1141''') 1142 code(''' 1143 const Address addr) 1144{ 1145''') 1146 code.indent() 1147 1148 if self.TBEType != None and self.EntryType != None: 1149 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1150 elif self.TBEType != None: 1151 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1152 elif self.EntryType != None: 1153 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1154 else: 1155 code('${ident}_State state = getState(addr);') 1156 1157 code(''' 1158${ident}_State next_state = state; 1159 1160DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1161 *this, curCycle(), ${ident}_State_to_string(state), 1162 ${ident}_Event_to_string(event), addr); 1163 1164TransitionResult result = 1165''') 1166 if self.TBEType != None and self.EntryType != None: 1167 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1168 elif self.TBEType != None: 1169 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1170 elif self.EntryType != None: 1171 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1172 else: 1173 code('doTransitionWorker(event, state, next_state, addr);') 1174 1175 code(''' 1176 1177if (result == TransitionResult_Valid) { 1178 DPRINTF(RubyGenerated, "next_state: %s\\n", 1179 ${ident}_State_to_string(next_state)); 1180 countTransition(state, event); 1181 1182 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1183 curTick(), m_version, "${ident}", 1184 ${ident}_Event_to_string(event), 1185 ${ident}_State_to_string(state), 1186 ${ident}_State_to_string(next_state), 1187 addr, GET_TRANSITION_COMMENT()); 1188 1189 CLEAR_TRANSITION_COMMENT(); 1190''') 1191 if self.TBEType != None and self.EntryType != None: 1192 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1193 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1194 elif self.TBEType != None: 1195 code('setState(m_tbe_ptr, addr, next_state);') 1196 code('setAccessPermission(addr, next_state);') 1197 elif self.EntryType != None: 1198 code('setState(m_cache_entry_ptr, addr, next_state);') 1199 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1200 else: 1201 code('setState(addr, next_state);') 1202 code('setAccessPermission(addr, next_state);') 1203 1204 code(''' 1205} else if (result == TransitionResult_ResourceStall) { 1206 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1207 curTick(), m_version, "${ident}", 1208 ${ident}_Event_to_string(event), 1209 ${ident}_State_to_string(state), 1210 ${ident}_State_to_string(next_state), 1211 addr, "Resource Stall"); 1212} else if (result == TransitionResult_ProtocolStall) { 1213 DPRINTF(RubyGenerated, "stalling\\n"); 1214 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1215 curTick(), m_version, "${ident}", 1216 ${ident}_Event_to_string(event), 1217 ${ident}_State_to_string(state), 1218 ${ident}_State_to_string(next_state), 1219 addr, "Protocol Stall"); 1220} 1221 1222return result; 1223''') 1224 code.dedent() 1225 code(''' 1226} 1227 1228TransitionResult 1229${ident}_Controller::doTransitionWorker(${ident}_Event event, 1230 ${ident}_State state, 1231 ${ident}_State& next_state, 1232''') 1233 1234 if self.TBEType != None: 1235 code(''' 1236 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1237''') 1238 if self.EntryType != None: 1239 code(''' 1240 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1241''') 1242 code(''' 1243 const Address& addr) 1244{ 1245 switch(HASH_FUN(state, event)) { 1246''') 1247 1248 # This map will allow suppress generating duplicate code 1249 cases = orderdict() 1250 1251 for trans in self.transitions: 1252 case_string = "%s_State_%s, %s_Event_%s" % \ 1253 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1254 1255 case = self.symtab.codeFormatter() 1256 # Only set next_state if it changes 1257 if trans.state != trans.nextState: 1258 ns_ident = trans.nextState.ident 1259 case('next_state = ${ident}_State_${ns_ident};') 1260 1261 actions = trans.actions 1262 request_types = trans.request_types 1263 1264 # Check for resources 1265 case_sorter = [] 1266 res = trans.resources 1267 for key,val in res.iteritems(): 1268 val = ''' 1269if (!%s.areNSlotsAvailable(%s)) 1270 return TransitionResult_ResourceStall; 1271''' % (key.code, val) 1272 case_sorter.append(val) 1273 1274 # Check all of the request_types for resource constraints 1275 for request_type in request_types: 1276 val = ''' 1277if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1278 return TransitionResult_ResourceStall; 1279} 1280''' % (self.ident, request_type.ident) 1281 case_sorter.append(val) 1282 1283 # Emit the code sequences in a sorted order. This makes the 1284 # output deterministic (without this the output order can vary 1285 # since Map's keys() on a vector of pointers is not deterministic 1286 for c in sorted(case_sorter): 1287 case("$c") 1288 1289 # Record access types for this transition 1290 for request_type in request_types: 1291 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1292 1293 # Figure out if we stall 1294 stall = False 1295 for action in actions: 1296 if action.ident == "z_stall": 1297 stall = True 1298 break 1299 1300 if stall: 1301 case('return TransitionResult_ProtocolStall;') 1302 else: 1303 if self.TBEType != None and self.EntryType != None: 1304 for action in actions: 1305 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1306 elif self.TBEType != None: 1307 for action in actions: 1308 case('${{action.ident}}(m_tbe_ptr, addr);') 1309 elif self.EntryType != None: 1310 for action in actions: 1311 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1312 else: 1313 for action in actions: 1314 case('${{action.ident}}(addr);') 1315 case('return TransitionResult_Valid;') 1316 1317 case = str(case) 1318 1319 # Look to see if this transition code is unique. 1320 if case not in cases: 1321 cases[case] = [] 1322 1323 cases[case].append(case_string) 1324 1325 # Walk through all of the unique code blocks and spit out the 1326 # corresponding case statement elements 1327 for case,transitions in cases.iteritems(): 1328 # Iterative over all the multiple transitions that share 1329 # the same code 1330 for trans in transitions: 1331 code(' case HASH_FUN($trans):') 1332 code(' $case\n') 1333 1334 code(''' 1335 default: 1336 fatal("Invalid transition\\n" 1337 "%s time: %d addr: %s event: %s state: %s\\n", 1338 name(), curCycle(), addr, event, state); 1339 } 1340 1341 return TransitionResult_Valid; 1342} 1343''') 1344 code.write(path, "%s_Transitions.cc" % self.ident) 1345 1346 1347 # ************************** 1348 # ******* HTML Files ******* 1349 # ************************** 1350 def frameRef(self, click_href, click_target, over_href, over_num, text): 1351 code = self.symtab.codeFormatter(fix_newlines=False) 1352 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1353 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1354 parent.frames[$over_num].location='$over_href' 1355 }\"> 1356 ${{html.formatShorthand(text)}} 1357 </A>""") 1358 return str(code) 1359 1360 def writeHTMLFiles(self, path): 1361 # Create table with no row hilighted 1362 self.printHTMLTransitions(path, None) 1363 1364 # Generate transition tables 1365 for state in self.states.itervalues(): 1366 self.printHTMLTransitions(path, state) 1367 1368 # Generate action descriptions 1369 for action in self.actions.itervalues(): 1370 name = "%s_action_%s.html" % (self.ident, action.ident) 1371 code = html.createSymbol(action, "Action") 1372 code.write(path, name) 1373 1374 # Generate state descriptions 1375 for state in self.states.itervalues(): 1376 name = "%s_State_%s.html" % (self.ident, state.ident) 1377 code = html.createSymbol(state, "State") 1378 code.write(path, name) 1379 1380 # Generate event descriptions 1381 for event in self.events.itervalues(): 1382 name = "%s_Event_%s.html" % (self.ident, event.ident) 1383 code = html.createSymbol(event, "Event") 1384 code.write(path, name) 1385 1386 def printHTMLTransitions(self, path, active_state): 1387 code = self.symtab.codeFormatter() 1388 1389 code(''' 1390<HTML> 1391<BODY link="blue" vlink="blue"> 1392 1393<H1 align="center">${{html.formatShorthand(self.short)}}: 1394''') 1395 code.indent() 1396 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1397 mid = machine.ident 1398 if i != 0: 1399 extra = " - " 1400 else: 1401 extra = "" 1402 if machine == self: 1403 code('$extra$mid') 1404 else: 1405 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1406 code.dedent() 1407 1408 code(""" 1409</H1> 1410 1411<TABLE border=1> 1412<TR> 1413 <TH> </TH> 1414""") 1415 1416 for event in self.events.itervalues(): 1417 href = "%s_Event_%s.html" % (self.ident, event.ident) 1418 ref = self.frameRef(href, "Status", href, "1", event.short) 1419 code('<TH bgcolor=white>$ref</TH>') 1420 1421 code('</TR>') 1422 # -- Body of table 1423 for state in self.states.itervalues(): 1424 # -- Each row 1425 if state == active_state: 1426 color = "yellow" 1427 else: 1428 color = "white" 1429 1430 click = "%s_table_%s.html" % (self.ident, state.ident) 1431 over = "%s_State_%s.html" % (self.ident, state.ident) 1432 text = html.formatShorthand(state.short) 1433 ref = self.frameRef(click, "Table", over, "1", state.short) 1434 code(''' 1435<TR> 1436 <TH bgcolor=$color>$ref</TH> 1437''') 1438 1439 # -- One column for each event 1440 for event in self.events.itervalues(): 1441 trans = self.table.get((state,event), None) 1442 if trans is None: 1443 # This is the no transition case 1444 if state == active_state: 1445 color = "#C0C000" 1446 else: 1447 color = "lightgrey" 1448 1449 code('<TD bgcolor=$color> </TD>') 1450 continue 1451 1452 next = trans.nextState 1453 stall_action = False 1454 1455 # -- Get the actions 1456 for action in trans.actions: 1457 if action.ident == "z_stall" or \ 1458 action.ident == "zz_recycleMandatoryQueue": 1459 stall_action = True 1460 1461 # -- Print out "actions/next-state" 1462 if stall_action: 1463 if state == active_state: 1464 color = "#C0C000" 1465 else: 1466 color = "lightgrey" 1467 1468 elif active_state and next.ident == active_state.ident: 1469 color = "aqua" 1470 elif state == active_state: 1471 color = "yellow" 1472 else: 1473 color = "white" 1474 1475 code('<TD bgcolor=$color>') 1476 for action in trans.actions: 1477 href = "%s_action_%s.html" % (self.ident, action.ident) 1478 ref = self.frameRef(href, "Status", href, "1", 1479 action.short) 1480 code(' $ref') 1481 if next != state: 1482 if trans.actions: 1483 code('/') 1484 click = "%s_table_%s.html" % (self.ident, next.ident) 1485 over = "%s_State_%s.html" % (self.ident, next.ident) 1486 ref = self.frameRef(click, "Table", over, "1", next.short) 1487 code("$ref") 1488 code("</TD>") 1489 1490 # -- Each row 1491 if state == active_state: 1492 color = "yellow" 1493 else: 1494 color = "white" 1495 1496 click = "%s_table_%s.html" % (self.ident, state.ident) 1497 over = "%s_State_%s.html" % (self.ident, state.ident) 1498 ref = self.frameRef(click, "Table", over, "1", state.short) 1499 code(''' 1500 <TH bgcolor=$color>$ref</TH> 1501</TR> 1502''') 1503 code(''' 1504<!- Column footer-> 1505<TR> 1506 <TH> </TH> 1507''') 1508 1509 for event in self.events.itervalues(): 1510 href = "%s_Event_%s.html" % (self.ident, event.ident) 1511 ref = self.frameRef(href, "Status", href, "1", event.short) 1512 code('<TH bgcolor=white>$ref</TH>') 1513 code(''' 1514</TR> 1515</TABLE> 1516</BODY></HTML> 1517''') 1518 1519 1520 if active_state: 1521 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1522 else: 1523 name = "%s_table.html" % self.ident 1524 code.write(path, name) 1525 1526__all__ = [ "StateMachine" ] 1527