StateMachine.py revision 13672
16657Snate@binkert.org# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 26657Snate@binkert.org# Copyright (c) 2009 The Hewlett-Packard Development Company 36657Snate@binkert.org# Copyright (c) 2013 Advanced Micro Devices, Inc. 46657Snate@binkert.org# All rights reserved. 56657Snate@binkert.org# 66657Snate@binkert.org# Redistribution and use in source and binary forms, with or without 76657Snate@binkert.org# modification, are permitted provided that the following conditions are 86657Snate@binkert.org# met: redistributions of source code must retain the above copyright 96657Snate@binkert.org# notice, this list of conditions and the following disclaimer; 106657Snate@binkert.org# redistributions in binary form must reproduce the above copyright 116657Snate@binkert.org# notice, this list of conditions and the following disclaimer in the 126657Snate@binkert.org# documentation and/or other materials provided with the distribution; 136657Snate@binkert.org# neither the name of the copyright holders nor the names of its 146657Snate@binkert.org# contributors may be used to endorse or promote products derived from 156657Snate@binkert.org# this software without specific prior written permission. 166657Snate@binkert.org# 176657Snate@binkert.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 186657Snate@binkert.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 196657Snate@binkert.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 206657Snate@binkert.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 216657Snate@binkert.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 226657Snate@binkert.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 236657Snate@binkert.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 246657Snate@binkert.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 256657Snate@binkert.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 266657Snate@binkert.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 276657Snate@binkert.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 286999Snate@binkert.org 296657Snate@binkert.orgfrom collections import OrderedDict 306657Snate@binkert.org 316657Snate@binkert.orgfrom slicc.symbols.Symbol import Symbol 329302Snilay@cs.wisc.edufrom slicc.symbols.Var import Var 336657Snate@binkert.orgimport slicc.generate.html as html 346657Snate@binkert.orgimport re 356657Snate@binkert.org 366657Snate@binkert.orgpython_class_map = { 376657Snate@binkert.org "int": "Int", 386657Snate@binkert.org "NodeID": "Int", 396657Snate@binkert.org "uint32_t" : "UInt32", 406657Snate@binkert.org "std::string": "String", 416657Snate@binkert.org "bool": "Bool", 426657Snate@binkert.org "CacheMemory": "RubyCache", 436657Snate@binkert.org "WireBuffer": "RubyWireBuffer", 446657Snate@binkert.org "Sequencer": "RubySequencer", 456657Snate@binkert.org "GPUCoalescer" : "RubyGPUCoalescer", 466657Snate@binkert.org "VIPERCoalescer" : "VIPERCoalescer", 476657Snate@binkert.org "DirectoryMemory": "RubyDirectoryMemory", 486657Snate@binkert.org "PerfectCacheMemory": "RubyPerfectCacheMemory", 496657Snate@binkert.org "MemoryControl": "MemoryControl", 506882SBrad.Beckmann@amd.com "MessageBuffer": "MessageBuffer", 516657Snate@binkert.org "DMASequencer": "DMASequencer", 526657Snate@binkert.org "Prefetcher":"Prefetcher", 536657Snate@binkert.org "Cycles":"Cycles", 546657Snate@binkert.org } 556657Snate@binkert.org 566657Snate@binkert.orgclass StateMachine(Symbol): 576657Snate@binkert.org def __init__(self, symtab, ident, location, pairs, config_parameters): 586657Snate@binkert.org super(StateMachine, self).__init__(symtab, ident, location, pairs) 596657Snate@binkert.org self.table = None 606657Snate@binkert.org 616657Snate@binkert.org # Data members in the State Machine that have been declared before 626657Snate@binkert.org # the opening brace '{' of the machine. Note that these along with 636657Snate@binkert.org # the members in self.objects form the entire set of data members. 6410895Snilay@cs.wisc.edu self.config_parameters = config_parameters 656657Snate@binkert.org 666657Snate@binkert.org self.prefetchers = [] 676657Snate@binkert.org 6810228Snilay@cs.wisc.edu for param in config_parameters: 696657Snate@binkert.org if param.pointer: 706657Snate@binkert.org var = Var(symtab, param.ident, location, param.type_ast.type, 7110228Snilay@cs.wisc.edu "(*m_%s_ptr)" % param.ident, {}, self) 726657Snate@binkert.org else: 736657Snate@binkert.org var = Var(symtab, param.ident, location, param.type_ast.type, 746657Snate@binkert.org "m_%s" % param.ident, {}, self) 756657Snate@binkert.org 766657Snate@binkert.org self.symtab.registerSym(param.ident, var) 776657Snate@binkert.org 786657Snate@binkert.org if str(param.type_ast.type) == "Prefetcher": 796657Snate@binkert.org self.prefetchers.append(var) 806657Snate@binkert.org 816657Snate@binkert.org self.states = OrderedDict() 826657Snate@binkert.org self.events = OrderedDict() 836657Snate@binkert.org self.actions = OrderedDict() 846657Snate@binkert.org self.request_types = OrderedDict() 856657Snate@binkert.org self.transitions = [] 866657Snate@binkert.org self.in_ports = [] 876657Snate@binkert.org self.functions = [] 888086SBrad.Beckmann@amd.com 898086SBrad.Beckmann@amd.com # Data members in the State Machine that have been declared inside 908086SBrad.Beckmann@amd.com # the {} machine. Note that these along with the config params 916657Snate@binkert.org # form the entire set of data members of the machine. 926657Snate@binkert.org self.objects = [] 936657Snate@binkert.org self.TBEType = None 946657Snate@binkert.org self.EntryType = None 956657Snate@binkert.org self.debug_flags = set() 966657Snate@binkert.org self.debug_flags.add('RubyGenerated') 976657Snate@binkert.org self.debug_flags.add('RubySlicc') 9810895Snilay@cs.wisc.edu 996657Snate@binkert.org def __repr__(self): 1006657Snate@binkert.org return "[StateMachine: %s]" % self.ident 1016657Snate@binkert.org 1026657Snate@binkert.org def addState(self, state): 1036657Snate@binkert.org assert self.table is None 1046657Snate@binkert.org self.states[state.ident] = state 1056657Snate@binkert.org 1066657Snate@binkert.org def addEvent(self, event): 1076657Snate@binkert.org assert self.table is None 1086657Snate@binkert.org self.events[event.ident] = event 1096657Snate@binkert.org 1106657Snate@binkert.org def addAction(self, action): 1116657Snate@binkert.org assert self.table is None 1126657Snate@binkert.org 1136657Snate@binkert.org # Check for duplicate action 1146657Snate@binkert.org for other in self.actions.itervalues(): 1156657Snate@binkert.org if action.ident == other.ident: 1166657Snate@binkert.org action.warning("Duplicate action definition: %s" % action.ident) 1176657Snate@binkert.org action.error("Duplicate action definition: %s" % action.ident) 1186657Snate@binkert.org if action.short == other.short: 1196657Snate@binkert.org other.warning("Duplicate action shorthand: %s" % other.ident) 1206657Snate@binkert.org other.warning(" shorthand = %s" % other.short) 1216657Snate@binkert.org action.warning("Duplicate action shorthand: %s" % action.ident) 1226657Snate@binkert.org action.error(" shorthand = %s" % action.short) 1236657Snate@binkert.org 1246657Snate@binkert.org self.actions[action.ident] = action 1259298Snilay@cs.wisc.edu 1266657Snate@binkert.org def addDebugFlag(self, flag): 1276657Snate@binkert.org self.debug_flags.add(flag) 1286657Snate@binkert.org 1296657Snate@binkert.org def addRequestType(self, request_type): 1306657Snate@binkert.org assert self.table is None 1316657Snate@binkert.org self.request_types[request_type.ident] = request_type 1329302Snilay@cs.wisc.edu 1339302Snilay@cs.wisc.edu def addTransition(self, trans): 1349302Snilay@cs.wisc.edu assert self.table is None 1356657Snate@binkert.org self.transitions.append(trans) 1366657Snate@binkert.org 1376657Snate@binkert.org def addInPort(self, var): 1386657Snate@binkert.org self.in_ports.append(var) 1396657Snate@binkert.org 1406657Snate@binkert.org def addFunc(self, func): 1416657Snate@binkert.org # register func in the symbol table 1426657Snate@binkert.org self.symtab.registerSym(str(func), func) 1436882SBrad.Beckmann@amd.com self.functions.append(func) 1446882SBrad.Beckmann@amd.com 1456882SBrad.Beckmann@amd.com def addObject(self, obj): 1468086SBrad.Beckmann@amd.com self.symtab.registerSym(str(obj), obj) 1478086SBrad.Beckmann@amd.com self.objects.append(obj) 1488086SBrad.Beckmann@amd.com 14910307Snilay@cs.wisc.edu def addType(self, type): 15010307Snilay@cs.wisc.edu type_ident = '%s' % type.c_ident 1516657Snate@binkert.org 1526657Snate@binkert.org if type_ident == "%s_TBE" %self.ident: 1536657Snate@binkert.org if self.TBEType != None: 15410307Snilay@cs.wisc.edu self.error("Multiple Transaction Buffer types in a " \ 1559298Snilay@cs.wisc.edu "single machine."); 1569298Snilay@cs.wisc.edu self.TBEType = type 1579298Snilay@cs.wisc.edu 1586657Snate@binkert.org elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 1596657Snate@binkert.org if "main" in type and "false" == type["main"].lower(): 1606657Snate@binkert.org pass # this isn't the EntryType 1616657Snate@binkert.org else: 1626657Snate@binkert.org if self.EntryType != None: 1636657Snate@binkert.org self.error("Multiple AbstractCacheEntry types in a " \ 1646657Snate@binkert.org "single machine."); 1656657Snate@binkert.org self.EntryType = type 1666657Snate@binkert.org 1676657Snate@binkert.org # Needs to be called before accessing the table 1686657Snate@binkert.org def buildTable(self): 1699219Spower.jg@gmail.com assert self.table is None 1706657Snate@binkert.org 1716657Snate@binkert.org table = {} 1726657Snate@binkert.org 1736657Snate@binkert.org for trans in self.transitions: 1746657Snate@binkert.org # Track which actions we touch so we know if we use them 1756657Snate@binkert.org # all -- really this should be done for all symbols as 1766657Snate@binkert.org # part of the symbol table, then only trigger it for 1776657Snate@binkert.org # Actions, States, Events, etc. 1786657Snate@binkert.org 1796657Snate@binkert.org for action in trans.actions: 1806657Snate@binkert.org action.used = True 1816657Snate@binkert.org 1826999Snate@binkert.org index = (trans.state, trans.event) 1836657Snate@binkert.org if index in table: 1846657Snate@binkert.org table[index].warning("Duplicate transition: %s" % table[index]) 1856657Snate@binkert.org trans.error("Duplicate transition: %s" % trans) 1866657Snate@binkert.org table[index] = trans 1876657Snate@binkert.org 1886657Snate@binkert.org # Look at all actions to make sure we used them all 1896657Snate@binkert.org for action in self.actions.itervalues(): 1907007Snate@binkert.org if not action.used: 1917007Snate@binkert.org error_msg = "Unused action: %s" % action.ident 1926657Snate@binkert.org if "desc" in action: 1937002Snate@binkert.org error_msg += ", " + action.desc 1947002Snate@binkert.org action.warning(error_msg) 1959466Snilay@cs.wisc.edu self.table = table 1966657Snate@binkert.org 1976657Snate@binkert.org # determine the port->msg buffer mappings 1986657Snate@binkert.org def getBufferMaps(self, ident): 1996657Snate@binkert.org msg_bufs = [] 2006657Snate@binkert.org port_to_buf_map = {} 2016657Snate@binkert.org in_msg_bufs = {} 2026657Snate@binkert.org for port in self.in_ports: 2036657Snate@binkert.org buf_name = "m_%s_ptr" % port.pairs["buffer_expr"].name 2046657Snate@binkert.org msg_bufs.append(buf_name) 2056657Snate@binkert.org port_to_buf_map[port] = msg_bufs.index(buf_name) 2066657Snate@binkert.org if buf_name not in in_msg_bufs: 2076657Snate@binkert.org in_msg_bufs[buf_name] = [port] 2087007Snate@binkert.org else: 2097007Snate@binkert.org in_msg_bufs[buf_name].append(port) 2106657Snate@binkert.org return port_to_buf_map, in_msg_bufs, msg_bufs 2119466Snilay@cs.wisc.edu 2126657Snate@binkert.org def writeCodeFiles(self, path, includes): 2136657Snate@binkert.org self.printControllerPython(path) 2149466Snilay@cs.wisc.edu self.printControllerHH(path) 2159508Snilay@cs.wisc.edu self.printControllerCC(path, includes) 2169466Snilay@cs.wisc.edu self.printCSwitch(path) 2179466Snilay@cs.wisc.edu self.printCWakeup(path, includes) 2189466Snilay@cs.wisc.edu 2196657Snate@binkert.org def printControllerPython(self, path): 2206657Snate@binkert.org code = self.symtab.codeFormatter() 2216657Snate@binkert.org ident = self.ident 2226657Snate@binkert.org 2236657Snate@binkert.org py_ident = "%s_Controller" % ident 2246657Snate@binkert.org c_ident = "%s_Controller" % self.ident 2256657Snate@binkert.org 2266657Snate@binkert.org code(''' 2276657Snate@binkert.orgfrom m5.params import * 2286657Snate@binkert.orgfrom m5.SimObject import SimObject 2296657Snate@binkert.orgfrom m5.objects.Controller import RubyController 2306657Snate@binkert.org 2316657Snate@binkert.orgclass $py_ident(RubyController): 2326657Snate@binkert.org type = '$py_ident' 2336657Snate@binkert.org cxx_header = 'mem/protocol/${c_ident}.hh' 2346657Snate@binkert.org''') 2356657Snate@binkert.org code.indent() 2367453Snate@binkert.org for param in self.config_parameters: 2377453Snate@binkert.org dflt_str = '' 2387453Snate@binkert.org 2397453Snate@binkert.org if param.rvalue is not None: 2407453Snate@binkert.org dflt_str = str(param.rvalue.inline()) + ', ' 2417453Snate@binkert.org 2427453Snate@binkert.org if python_class_map.has_key(param.type_ast.type.c_ident): 2437453Snate@binkert.org python_type = python_class_map[param.type_ast.type.c_ident] 2447453Snate@binkert.org code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")') 2457453Snate@binkert.org 2467453Snate@binkert.org else: 2477453Snate@binkert.org self.error("Unknown c++ to python class conversion for c++ " \ 2487453Snate@binkert.org "type: '%s'. Please update the python_class_map " \ 2497453Snate@binkert.org "in StateMachine.py", param.type_ast.type.c_ident) 2507453Snate@binkert.org 2517453Snate@binkert.org code.dedent() 2527453Snate@binkert.org code.write(path, '%s.py' % py_ident) 2536657Snate@binkert.org 2546657Snate@binkert.org 2556657Snate@binkert.org def printControllerHH(self, path): 2566657Snate@binkert.org '''Output the method declarations for the class declaration''' 2579466Snilay@cs.wisc.edu code = self.symtab.codeFormatter() 2586657Snate@binkert.org ident = self.ident 2599466Snilay@cs.wisc.edu c_ident = "%s_Controller" % self.ident 2609508Snilay@cs.wisc.edu 2619466Snilay@cs.wisc.edu code(''' 2626657Snate@binkert.org/** \\file $c_ident.hh 2636657Snate@binkert.org * 2646657Snate@binkert.org * Auto generated C++ code started by $__file__:$__line__ 2656657Snate@binkert.org * Created by slicc definition of Module "${{self.short}}" 2669466Snilay@cs.wisc.edu */ 2679466Snilay@cs.wisc.edu 2689466Snilay@cs.wisc.edu#ifndef __${ident}_CONTROLLER_HH__ 2699466Snilay@cs.wisc.edu#define __${ident}_CONTROLLER_HH__ 2706657Snate@binkert.org 2716657Snate@binkert.org#include <iostream> 2726657Snate@binkert.org#include <sstream> 2736657Snate@binkert.org#include <string> 2746657Snate@binkert.org 2756657Snate@binkert.org#include "mem/protocol/TransitionResult.hh" 2766657Snate@binkert.org#include "mem/protocol/Types.hh" 2776657Snate@binkert.org#include "mem/ruby/common/Consumer.hh" 2786657Snate@binkert.org#include "mem/ruby/slicc_interface/AbstractController.hh" 2796657Snate@binkert.org#include "params/$c_ident.hh" 2806657Snate@binkert.org 2819466Snilay@cs.wisc.edu''') 28210472Sandreas.hansson@arm.com 28310472Sandreas.hansson@arm.com seen_types = set() 28410472Sandreas.hansson@arm.com for var in self.objects: 28510472Sandreas.hansson@arm.com if var.type.ident not in seen_types and not var.type.isPrimitive: 28610472Sandreas.hansson@arm.com code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 28710472Sandreas.hansson@arm.com seen_types.add(var.type.ident) 28810472Sandreas.hansson@arm.com 28910472Sandreas.hansson@arm.com # for adding information to the protocol debug trace 29010472Sandreas.hansson@arm.com code(''' 29110472Sandreas.hansson@arm.comextern std::stringstream ${ident}_transitionComment; 2927453Snate@binkert.org 2937007Snate@binkert.orgclass $c_ident : public AbstractController 2947007Snate@binkert.org{ 2957453Snate@binkert.org public: 2967007Snate@binkert.org typedef ${c_ident}Params Params; 2976657Snate@binkert.org $c_ident(const Params *p); 2986657Snate@binkert.org static int getNumControllers(); 2996657Snate@binkert.org void init(); 3006657Snate@binkert.org 3016657Snate@binkert.org MessageBuffer *getMandatoryQueue() const; 3026657Snate@binkert.org MessageBuffer *getMemoryQueue() const; 3036657Snate@binkert.org void initNetQueues(); 3046657Snate@binkert.org 3056657Snate@binkert.org void print(std::ostream& out) const; 3066657Snate@binkert.org void wakeup(); 3077007Snate@binkert.org void resetStats(); 3087007Snate@binkert.org void regStats(); 3097007Snate@binkert.org void collateStats(); 3107007Snate@binkert.org 3117007Snate@binkert.org void recordCacheTrace(int cntrl, CacheRecorder* tr); 3126657Snate@binkert.org Sequencer* getCPUSequencer() const; 3136657Snate@binkert.org GPUCoalescer* getGPUCoalescer() const; 3146657Snate@binkert.org 3156657Snate@binkert.org int functionalWriteBuffers(PacketPtr&); 3166657Snate@binkert.org 3176657Snate@binkert.org void countTransition(${ident}_State state, ${ident}_Event event); 3186657Snate@binkert.org void possibleTransition(${ident}_State state, ${ident}_Event event); 3196657Snate@binkert.org uint64_t getEventCount(${ident}_Event event); 3206657Snate@binkert.org bool isPossible(${ident}_State state, ${ident}_Event event); 3217007Snate@binkert.org uint64_t getTransitionCount(${ident}_State state, ${ident}_Event event); 3227007Snate@binkert.org 3237007Snate@binkert.orgprivate: 3247007Snate@binkert.org''') 3257007Snate@binkert.org 3266657Snate@binkert.org code.indent() 3276657Snate@binkert.org # added by SS 3286657Snate@binkert.org for param in self.config_parameters: 3296657Snate@binkert.org if param.pointer: 3306657Snate@binkert.org code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 3316657Snate@binkert.org else: 3326657Snate@binkert.org code('${{param.type_ast.type}} m_${{param.ident}};') 3337007Snate@binkert.org 3347007Snate@binkert.org code(''' 3357007Snate@binkert.orgTransitionResult doTransition(${ident}_Event event, 3367007Snate@binkert.org''') 3377007Snate@binkert.org 3386657Snate@binkert.org if self.EntryType != None: 3396657Snate@binkert.org code(''' 3407002Snate@binkert.org ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 3416657Snate@binkert.org''') 3426657Snate@binkert.org if self.TBEType != None: 3436657Snate@binkert.org code(''' 3446657Snate@binkert.org ${{self.TBEType.c_ident}}* m_tbe_ptr, 3456657Snate@binkert.org''') 3466657Snate@binkert.org 3476657Snate@binkert.org code(''' 3486657Snate@binkert.org Addr addr); 3496657Snate@binkert.org 3506657Snate@binkert.orgTransitionResult doTransitionWorker(${ident}_Event event, 3516657Snate@binkert.org ${ident}_State state, 3526657Snate@binkert.org ${ident}_State& next_state, 3536657Snate@binkert.org''') 3546657Snate@binkert.org 3556657Snate@binkert.org if self.TBEType != None: 3566657Snate@binkert.org code(''' 3576657Snate@binkert.org ${{self.TBEType.c_ident}}*& m_tbe_ptr, 3586657Snate@binkert.org''') 3596657Snate@binkert.org if self.EntryType != None: 3606657Snate@binkert.org code(''' 3616657Snate@binkert.org ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 3627007Snate@binkert.org''') 3636657Snate@binkert.org 3647007Snate@binkert.org code(''' 3656657Snate@binkert.org Addr addr); 36610307Snilay@cs.wisc.edu 36710307Snilay@cs.wisc.eduint m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 36810307Snilay@cs.wisc.eduint m_event_counters[${ident}_Event_NUM]; 3699298Snilay@cs.wisc.edubool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 3709298Snilay@cs.wisc.edu 3719298Snilay@cs.wisc.edustatic std::vector<Stats::Vector *> eventVec; 3726657Snate@binkert.orgstatic std::vector<std::vector<Stats::Vector *> > transVec; 3736657Snate@binkert.orgstatic int m_num_controllers; 3746657Snate@binkert.org 3756657Snate@binkert.org// Internal functions 3767055Snate@binkert.org''') 3777007Snate@binkert.org 3786657Snate@binkert.org for func in self.functions: 3796657Snate@binkert.org proto = func.prototype 3807002Snate@binkert.org if proto: 3816657Snate@binkert.org code('$proto') 3826657Snate@binkert.org 3836657Snate@binkert.org if self.EntryType != None: 3847007Snate@binkert.org code(''' 3856657Snate@binkert.org 3866657Snate@binkert.org// Set and Reset for cache_entry variable 3876657Snate@binkert.orgvoid set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 3886657Snate@binkert.orgvoid unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 3896657Snate@binkert.org''') 3906999Snate@binkert.org 3916657Snate@binkert.org if self.TBEType != None: 3926657Snate@binkert.org code(''' 3936657Snate@binkert.org 3946657Snate@binkert.org// Set and Reset for tbe variable 3956657Snate@binkert.orgvoid set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 3966657Snate@binkert.orgvoid unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 3976657Snate@binkert.org''') 3987002Snate@binkert.org 39910472Sandreas.hansson@arm.com # Prototype the actions that the controller can take 4007002Snate@binkert.org code(''' 4016657Snate@binkert.org 4029499Snilay@cs.wisc.edu// Actions 4039499Snilay@cs.wisc.edu''') 4047002Snate@binkert.org if self.TBEType != None and self.EntryType != None: 4057002Snate@binkert.org for action in self.actions.itervalues(): 4066657Snate@binkert.org code('/** \\brief ${{action.desc}} */') 4076657Snate@binkert.org code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 4086657Snate@binkert.org 'm_tbe_ptr, ${{self.EntryType.c_ident}}*& ' 4096657Snate@binkert.org 'm_cache_entry_ptr, Addr addr);') 4107007Snate@binkert.org elif self.TBEType != None: 4117007Snate@binkert.org for action in self.actions.itervalues(): 4126657Snate@binkert.org code('/** \\brief ${{action.desc}} */') 4136657Snate@binkert.org code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 4146657Snate@binkert.org 'm_tbe_ptr, Addr addr);') 4156657Snate@binkert.org elif self.EntryType != None: 4166657Snate@binkert.org for action in self.actions.itervalues(): 4176657Snate@binkert.org code('/** \\brief ${{action.desc}} */') 4186657Snate@binkert.org code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& ' 4196657Snate@binkert.org 'm_cache_entry_ptr, Addr addr);') 4206657Snate@binkert.org else: 4216657Snate@binkert.org for action in self.actions.itervalues(): 4229206Snilay@cs.wisc.edu code('/** \\brief ${{action.desc}} */') 4236657Snate@binkert.org code('void ${{action.ident}}(Addr addr);') 4246657Snate@binkert.org 4256657Snate@binkert.org # the controller internal variables 4266657Snate@binkert.org code(''' 4276657Snate@binkert.org 4286657Snate@binkert.org// Objects 4296657Snate@binkert.org''') 43010307Snilay@cs.wisc.edu for var in self.objects: 43110307Snilay@cs.wisc.edu th = var.get("template", "") 43210307Snilay@cs.wisc.edu code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;') 4339298Snilay@cs.wisc.edu 4346657Snate@binkert.org code.dedent() 4356657Snate@binkert.org code('};') 4366657Snate@binkert.org code('#endif // __${ident}_CONTROLLER_H__') 4376999Snate@binkert.org code.write(path, '%s.hh' % c_ident) 4386657Snate@binkert.org 4396657Snate@binkert.org def printControllerCC(self, path, includes): 4406657Snate@binkert.org '''Output the actions for performing the actions''' 4416657Snate@binkert.org 4426657Snate@binkert.org code = self.symtab.codeFormatter() 4437007Snate@binkert.org ident = self.ident 4447007Snate@binkert.org c_ident = "%s_Controller" % self.ident 4457007Snate@binkert.org 4466657Snate@binkert.org code(''' 4477002Snate@binkert.org/** \\file $c_ident.cc 4487002Snate@binkert.org * 4497002Snate@binkert.org * Auto generated C++ code started by $__file__:$__line__ 4508086SBrad.Beckmann@amd.com * Created by slicc definition of Module "${{self.short}}" 4518086SBrad.Beckmann@amd.com */ 4528086SBrad.Beckmann@amd.com 4538086SBrad.Beckmann@amd.com#include <sys/types.h> 4548602Snilay@cs.wisc.edu#include <unistd.h> 4558602Snilay@cs.wisc.edu 4568602Snilay@cs.wisc.edu#include <cassert> 4578602Snilay@cs.wisc.edu#include <sstream> 4588602Snilay@cs.wisc.edu#include <string> 4598086SBrad.Beckmann@amd.com#include <typeinfo> 4606657Snate@binkert.org 4617007Snate@binkert.org#include "base/compiler.hh" 4626657Snate@binkert.org#include "mem/ruby/common/BoolVec.hh" 4636657Snate@binkert.org#include "base/cprintf.hh" 4646657Snate@binkert.org 4656657Snate@binkert.org''') 4666657Snate@binkert.org for f in self.debug_flags: 4676657Snate@binkert.org code('#include "debug/${{f}}.hh"') 4686657Snate@binkert.org code(''' 4696657Snate@binkert.org#include "mem/protocol/${ident}_Controller.hh" 4706657Snate@binkert.org#include "mem/protocol/${ident}_Event.hh" 4716657Snate@binkert.org#include "mem/protocol/${ident}_State.hh" 4726657Snate@binkert.org#include "mem/protocol/Types.hh" 4736862Sdrh5@cs.wisc.edu#include "mem/ruby/network/Network.hh" 4746862Sdrh5@cs.wisc.edu#include "mem/ruby/system/RubySystem.hh" 4756862Sdrh5@cs.wisc.edu 4766862Sdrh5@cs.wisc.edu''') 4776657Snate@binkert.org for include_path in includes: 4786657Snate@binkert.org code('#include "${{include_path}}"') 4796657Snate@binkert.org 4806657Snate@binkert.org code(''' 4816657Snate@binkert.org 4827007Snate@binkert.orgusing namespace std; 4837007Snate@binkert.org''') 4847002Snate@binkert.org 4857007Snate@binkert.org # include object classes 4867007Snate@binkert.org seen_types = set() 4877002Snate@binkert.org for var in self.objects: 4887007Snate@binkert.org if var.type.ident not in seen_types and not var.type.isPrimitive: 4897007Snate@binkert.org code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 4906657Snate@binkert.org seen_types.add(var.type.ident) 4916657Snate@binkert.org 4926657Snate@binkert.org num_in_ports = len(self.in_ports) 4936657Snate@binkert.org 4946657Snate@binkert.org code(''' 4956657Snate@binkert.org$c_ident * 4966657Snate@binkert.org${c_ident}Params::create() 4976657Snate@binkert.org{ 4986657Snate@binkert.org return new $c_ident(this); 4996657Snate@binkert.org} 5006657Snate@binkert.org 5016657Snate@binkert.orgint $c_ident::m_num_controllers = 0; 5026657Snate@binkert.orgstd::vector<Stats::Vector *> $c_ident::eventVec; 5038602Snilay@cs.wisc.edustd::vector<std::vector<Stats::Vector *> > $c_ident::transVec; 5048602Snilay@cs.wisc.edu 5058602Snilay@cs.wisc.edu// for adding information to the protocol debug trace 5068602Snilay@cs.wisc.edustringstream ${ident}_transitionComment; 5078602Snilay@cs.wisc.edu 5088602Snilay@cs.wisc.edu#ifndef NDEBUG 5098602Snilay@cs.wisc.edu#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 5108602Snilay@cs.wisc.edu#else 5118602Snilay@cs.wisc.edu#define APPEND_TRANSITION_COMMENT(str) do {} while (0) 5128086SBrad.Beckmann@amd.com#endif 5138086SBrad.Beckmann@amd.com 5148086SBrad.Beckmann@amd.com/** \\brief constructor */ 5158086SBrad.Beckmann@amd.com$c_ident::$c_ident(const Params *p) 5168086SBrad.Beckmann@amd.com : AbstractController(p) 5178086SBrad.Beckmann@amd.com{ 5188086SBrad.Beckmann@amd.com m_machineID.type = MachineType_${ident}; 5198086SBrad.Beckmann@amd.com m_machineID.num = m_version; 5206657Snate@binkert.org m_num_controllers++; 5216657Snate@binkert.org 5227002Snate@binkert.org m_in_ports = $num_in_ports; 5236657Snate@binkert.org''') 5247007Snate@binkert.org code.indent() 5256657Snate@binkert.org 5266657Snate@binkert.org # 5276657Snate@binkert.org # After initializing the universal machine parameters, initialize the 5286657Snate@binkert.org # this machines config parameters. Also if these configuration params 5296657Snate@binkert.org # include a sequencer, connect the it to the controller. 5306999Snate@binkert.org # 5316657Snate@binkert.org for param in self.config_parameters: 5326657Snate@binkert.org if param.pointer: 5336657Snate@binkert.org code('m_${{param.ident}}_ptr = p->${{param.ident}};') 5346657Snate@binkert.org else: 5356657Snate@binkert.org code('m_${{param.ident}} = p->${{param.ident}};') 5366657Snate@binkert.org 5377832Snate@binkert.org if re.compile("sequencer").search(param.ident) or \ 5387002Snate@binkert.org param.type_ast.type.c_ident == "GPUCoalescer" or \ 5397002Snate@binkert.org param.type_ast.type.c_ident == "VIPERCoalescer": 5407002Snate@binkert.org code(''' 5417805Snilay@cs.wisc.eduif (m_${{param.ident}}_ptr != NULL) { 5426657Snate@binkert.org m_${{param.ident}}_ptr->setController(this); 5436657Snate@binkert.org} 5447002Snate@binkert.org''') 5457002Snate@binkert.org 5466657Snate@binkert.org code(''' 5476657Snate@binkert.org 5488086SBrad.Beckmann@amd.comfor (int state = 0; state < ${ident}_State_NUM; state++) { 5498086SBrad.Beckmann@amd.com for (int event = 0; event < ${ident}_Event_NUM; event++) { 5508086SBrad.Beckmann@amd.com m_possible[state][event] = false; 5518086SBrad.Beckmann@amd.com m_counters[state][event] = 0; 5528086SBrad.Beckmann@amd.com } 5538086SBrad.Beckmann@amd.com} 5548086SBrad.Beckmann@amd.comfor (int event = 0; event < ${ident}_Event_NUM; event++) { 5558086SBrad.Beckmann@amd.com m_event_counters[event] = 0; 5568086SBrad.Beckmann@amd.com} 5578086SBrad.Beckmann@amd.com''') 5588086SBrad.Beckmann@amd.com code.dedent() 5598086SBrad.Beckmann@amd.com code(''' 5608086SBrad.Beckmann@amd.com} 5618086SBrad.Beckmann@amd.com 5628086SBrad.Beckmann@amd.comvoid 5638086SBrad.Beckmann@amd.com$c_ident::initNetQueues() 5648086SBrad.Beckmann@amd.com{ 5658086SBrad.Beckmann@amd.com MachineType machine_type = string_to_MachineType("${{self.ident}}"); 5668086SBrad.Beckmann@amd.com int base M5_VAR_USED = MachineType_base_number(machine_type); 5678086SBrad.Beckmann@amd.com 5688086SBrad.Beckmann@amd.com''') 5696657Snate@binkert.org code.indent() 5706657Snate@binkert.org 5719773Snilay@cs.wisc.edu # set for maintaining the vnet, direction pairs already seen for this 5729773Snilay@cs.wisc.edu # machine. This map helps in implementing the check for avoiding 57310301Snilay@cs.wisc.edu # multiple message buffers being mapped to the same vnet. 5746657Snate@binkert.org vnet_dir_set = set() 5756657Snate@binkert.org 5767007Snate@binkert.org for var in self.config_parameters: 5777007Snate@binkert.org vid = "m_%s_ptr" % var.ident 5787007Snate@binkert.org if "network" in var: 5796657Snate@binkert.org vtype = var.type_ast.type 5806657Snate@binkert.org code('assert($vid != NULL);') 5816657Snate@binkert.org 5826657Snate@binkert.org # Network port object 5836657Snate@binkert.org network = var["network"] 5846657Snate@binkert.org 5857007Snate@binkert.org if "virtual_network" in var: 5867007Snate@binkert.org vnet = var["virtual_network"] 5877007Snate@binkert.org vnet_type = var["vnet_type"] 5886657Snate@binkert.org 5896657Snate@binkert.org assert (vnet, network) not in vnet_dir_set 5906657Snate@binkert.org vnet_dir_set.add((vnet,network)) 5916657Snate@binkert.org 5926657Snate@binkert.org code(''' 5936657Snate@binkert.orgm_net_ptr->set${network}NetQueue(m_version + base, $vid->getOrdered(), $vnet, 5946657Snate@binkert.org "$vnet_type", $vid); 5956657Snate@binkert.org''') 5966657Snate@binkert.org # Set Priority 5976657Snate@binkert.org if "rank" in var: 5986657Snate@binkert.org code('$vid->setPriority(${{var["rank"]}})') 5996657Snate@binkert.org 6006657Snate@binkert.org code.dedent() 6016657Snate@binkert.org code(''' 6027805Snilay@cs.wisc.edu} 6036657Snate@binkert.org 6046657Snate@binkert.orgvoid 6056657Snate@binkert.org$c_ident::init() 6067007Snate@binkert.org{ 6077007Snate@binkert.org // initialize objects 6087007Snate@binkert.org''') 6096657Snate@binkert.org 6106657Snate@binkert.org code.indent() 6116657Snate@binkert.org 6126657Snate@binkert.org for var in self.objects: 6137007Snate@binkert.org vtype = var.type 6146657Snate@binkert.org vid = "m_%s_ptr" % var.ident 6156657Snate@binkert.org if "network" not in var: 6166657Snate@binkert.org # Not a network port object 6176657Snate@binkert.org if "primitive" in vtype: 6187007Snate@binkert.org code('$vid = new ${{vtype.c_ident}};') 6196657Snate@binkert.org if "default" in var: 6206657Snate@binkert.org code('(*$vid) = ${{var["default"]}};') 6216657Snate@binkert.org else: 6226657Snate@binkert.org # Normal Object 6237805Snilay@cs.wisc.edu th = var.get("template", "") 6246657Snate@binkert.org expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 6256657Snate@binkert.org args = "" 6266657Snate@binkert.org if "non_obj" not in vtype and not vtype.isEnumeration: 6277007Snate@binkert.org args = var.get("constructor", "") 6287007Snate@binkert.org 6297007Snate@binkert.org code('$expr($args);') 6307007Snate@binkert.org code('assert($vid != NULL);') 6316657Snate@binkert.org 6326657Snate@binkert.org if "default" in var: 6336657Snate@binkert.org code('*$vid = ${{var["default"]}}; // Object default') 6346657Snate@binkert.org elif "default" in vtype: 6356657Snate@binkert.org comment = "Type %s default" % vtype.ident 6366657Snate@binkert.org code('*$vid = ${{vtype["default"]}}; // $comment') 6376657Snate@binkert.org 6386657Snate@binkert.org # Set the prefetchers 6396657Snate@binkert.org code() 6407007Snate@binkert.org for prefetcher in self.prefetchers: 6417007Snate@binkert.org code('${{prefetcher.code}}.setController(this);') 6426657Snate@binkert.org 6436657Snate@binkert.org code() 6446657Snate@binkert.org for port in self.in_ports: 6456657Snate@binkert.org # Set the queue consumers 6467007Snate@binkert.org code('${{port.code}}.setConsumer(this);') 6477007Snate@binkert.org 6486657Snate@binkert.org # Initialize the transition profiling 6496657Snate@binkert.org code() 6506657Snate@binkert.org for trans in self.transitions: 6516657Snate@binkert.org # Figure out if we stall 6526657Snate@binkert.org stall = False 6536657Snate@binkert.org for action in trans.actions: 6546657Snate@binkert.org if action.ident == "z_stall": 6556657Snate@binkert.org stall = True 6566657Snate@binkert.org 6576657Snate@binkert.org # Only possible if it is not a 'z' case 6586657Snate@binkert.org if not stall: 6596657Snate@binkert.org state = "%s_State_%s" % (self.ident, trans.state.ident) 6606657Snate@binkert.org event = "%s_Event_%s" % (self.ident, trans.event.ident) 6616657Snate@binkert.org code('possibleTransition($state, $event);') 6626657Snate@binkert.org 6636657Snate@binkert.org code.dedent() 6646657Snate@binkert.org code(''' 6657805Snilay@cs.wisc.edu AbstractController::init(); 6666657Snate@binkert.org resetStats(); 6676657Snate@binkert.org} 6686657Snate@binkert.org''') 6696657Snate@binkert.org 6706657Snate@binkert.org mq_ident = "NULL" 6717007Snate@binkert.org for port in self.in_ports: 6726657Snate@binkert.org if port.code.find("mandatoryQueue_ptr") >= 0: 6737007Snate@binkert.org mq_ident = "m_mandatoryQueue_ptr" 6747007Snate@binkert.org 6756657Snate@binkert.org memq_ident = "NULL" 6766657Snate@binkert.org for port in self.in_ports: 6776657Snate@binkert.org if port.code.find("responseFromMemory_ptr") >= 0: 6786657Snate@binkert.org memq_ident = "m_responseFromMemory_ptr" 6796657Snate@binkert.org 6806657Snate@binkert.org seq_ident = "NULL" 6816657Snate@binkert.org for param in self.config_parameters: 6826657Snate@binkert.org if param.ident == "sequencer": 6836657Snate@binkert.org assert(param.pointer) 6846657Snate@binkert.org seq_ident = "m_%s_ptr" % param.ident 6856657Snate@binkert.org 6866657Snate@binkert.org coal_ident = "NULL" 6876657Snate@binkert.org for param in self.config_parameters: 6886657Snate@binkert.org if param.ident == "coalescer": 6897805Snilay@cs.wisc.edu assert(param.pointer) 6906657Snate@binkert.org coal_ident = "m_%s_ptr" % param.ident 6916657Snate@binkert.org 6926657Snate@binkert.org if seq_ident != "NULL": 6936657Snate@binkert.org code(''' 6946657Snate@binkert.orgSequencer* 6956657Snate@binkert.org$c_ident::getCPUSequencer() const 6966657Snate@binkert.org{ 6976657Snate@binkert.org if (NULL != $seq_ident && $seq_ident->isCPUSequencer()) { 6987007Snate@binkert.org return $seq_ident; 6997007Snate@binkert.org } else { 7006657Snate@binkert.org return NULL; 7016657Snate@binkert.org } 7026657Snate@binkert.org} 7036657Snate@binkert.org''') 7046657Snate@binkert.org else: 7056657Snate@binkert.org code(''' 7066657Snate@binkert.org 7076657Snate@binkert.orgSequencer* 7086657Snate@binkert.org$c_ident::getCPUSequencer() const 7099773Snilay@cs.wisc.edu{ 7109773Snilay@cs.wisc.edu return NULL; 7119773Snilay@cs.wisc.edu} 7129773Snilay@cs.wisc.edu''') 7139773Snilay@cs.wisc.edu 7146657Snate@binkert.org if coal_ident != "NULL": 7156657Snate@binkert.org code(''' 7166657Snate@binkert.orgGPUCoalescer* 7176657Snate@binkert.org$c_ident::getGPUCoalescer() const 7186657Snate@binkert.org{ 7196657Snate@binkert.org if (NULL != $coal_ident && !$coal_ident->isCPUSequencer()) { 7207805Snilay@cs.wisc.edu return $coal_ident; 7216657Snate@binkert.org } else { 7226657Snate@binkert.org return NULL; 7236657Snate@binkert.org } 7246657Snate@binkert.org} 7256657Snate@binkert.org''') 7266657Snate@binkert.org else: 7276657Snate@binkert.org code(''' 7286657Snate@binkert.org 7297007Snate@binkert.orgGPUCoalescer* 7307007Snate@binkert.org$c_ident::getGPUCoalescer() const 7316657Snate@binkert.org{ 7326657Snate@binkert.org return NULL; 7336657Snate@binkert.org} 7346657Snate@binkert.org''') 7356657Snate@binkert.org 7366657Snate@binkert.org code(''' 7379773Snilay@cs.wisc.edu 7389773Snilay@cs.wisc.eduvoid 7399773Snilay@cs.wisc.edu$c_ident::regStats() 7409773Snilay@cs.wisc.edu{ 7419773Snilay@cs.wisc.edu AbstractController::regStats(); 7426657Snate@binkert.org 7436657Snate@binkert.org if (m_version == 0) { 7446657Snate@binkert.org for (${ident}_Event event = ${ident}_Event_FIRST; 7456657Snate@binkert.org event < ${ident}_Event_NUM; ++event) { 7466657Snate@binkert.org Stats::Vector *t = new Stats::Vector(); 7477805Snilay@cs.wisc.edu t->init(m_num_controllers); 7486657Snate@binkert.org t->name(params()->ruby_system->name() + ".${c_ident}." + 7496657Snate@binkert.org ${ident}_Event_to_string(event)); 7506657Snate@binkert.org t->flags(Stats::pdf | Stats::total | Stats::oneline | 7516657Snate@binkert.org Stats::nozero); 7528602Snilay@cs.wisc.edu 7538602Snilay@cs.wisc.edu eventVec.push_back(t); 7548602Snilay@cs.wisc.edu } 7558602Snilay@cs.wisc.edu 7568602Snilay@cs.wisc.edu for (${ident}_State state = ${ident}_State_FIRST; 7578602Snilay@cs.wisc.edu state < ${ident}_State_NUM; ++state) { 7588602Snilay@cs.wisc.edu 7598602Snilay@cs.wisc.edu transVec.push_back(std::vector<Stats::Vector *>()); 7608602Snilay@cs.wisc.edu 7618602Snilay@cs.wisc.edu for (${ident}_Event event = ${ident}_Event_FIRST; 7628602Snilay@cs.wisc.edu event < ${ident}_Event_NUM; ++event) { 7638602Snilay@cs.wisc.edu 7648602Snilay@cs.wisc.edu Stats::Vector *t = new Stats::Vector(); 7658602Snilay@cs.wisc.edu t->init(m_num_controllers); 7668602Snilay@cs.wisc.edu t->name(params()->ruby_system->name() + ".${c_ident}." + 7678602Snilay@cs.wisc.edu ${ident}_State_to_string(state) + 7688602Snilay@cs.wisc.edu "." + ${ident}_Event_to_string(event)); 7698602Snilay@cs.wisc.edu 7708602Snilay@cs.wisc.edu t->flags(Stats::pdf | Stats::total | Stats::oneline | 7718602Snilay@cs.wisc.edu Stats::nozero); 7728602Snilay@cs.wisc.edu transVec[state].push_back(t); 7736657Snate@binkert.org } 7746657Snate@binkert.org } 7756657Snate@binkert.org } 7766657Snate@binkert.org} 777 778void 779$c_ident::collateStats() 780{ 781 for (${ident}_Event event = ${ident}_Event_FIRST; 782 event < ${ident}_Event_NUM; ++event) { 783 for (unsigned int i = 0; i < m_num_controllers; ++i) { 784 RubySystem *rs = params()->ruby_system; 785 std::map<uint32_t, AbstractController *>::iterator it = 786 rs->m_abstract_controls[MachineType_${ident}].find(i); 787 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 788 (*eventVec[event])[i] = 789 (($c_ident *)(*it).second)->getEventCount(event); 790 } 791 } 792 793 for (${ident}_State state = ${ident}_State_FIRST; 794 state < ${ident}_State_NUM; ++state) { 795 796 for (${ident}_Event event = ${ident}_Event_FIRST; 797 event < ${ident}_Event_NUM; ++event) { 798 799 for (unsigned int i = 0; i < m_num_controllers; ++i) { 800 RubySystem *rs = params()->ruby_system; 801 std::map<uint32_t, AbstractController *>::iterator it = 802 rs->m_abstract_controls[MachineType_${ident}].find(i); 803 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 804 (*transVec[state][event])[i] = 805 (($c_ident *)(*it).second)->getTransitionCount(state, event); 806 } 807 } 808 } 809} 810 811void 812$c_ident::countTransition(${ident}_State state, ${ident}_Event event) 813{ 814 assert(m_possible[state][event]); 815 m_counters[state][event]++; 816 m_event_counters[event]++; 817} 818void 819$c_ident::possibleTransition(${ident}_State state, 820 ${ident}_Event event) 821{ 822 m_possible[state][event] = true; 823} 824 825uint64_t 826$c_ident::getEventCount(${ident}_Event event) 827{ 828 return m_event_counters[event]; 829} 830 831bool 832$c_ident::isPossible(${ident}_State state, ${ident}_Event event) 833{ 834 return m_possible[state][event]; 835} 836 837uint64_t 838$c_ident::getTransitionCount(${ident}_State state, 839 ${ident}_Event event) 840{ 841 return m_counters[state][event]; 842} 843 844int 845$c_ident::getNumControllers() 846{ 847 return m_num_controllers; 848} 849 850MessageBuffer* 851$c_ident::getMandatoryQueue() const 852{ 853 return $mq_ident; 854} 855 856MessageBuffer* 857$c_ident::getMemoryQueue() const 858{ 859 return $memq_ident; 860} 861 862void 863$c_ident::print(ostream& out) const 864{ 865 out << "[$c_ident " << m_version << "]"; 866} 867 868void $c_ident::resetStats() 869{ 870 for (int state = 0; state < ${ident}_State_NUM; state++) { 871 for (int event = 0; event < ${ident}_Event_NUM; event++) { 872 m_counters[state][event] = 0; 873 } 874 } 875 876 for (int event = 0; event < ${ident}_Event_NUM; event++) { 877 m_event_counters[event] = 0; 878 } 879 880 AbstractController::resetStats(); 881} 882''') 883 884 if self.EntryType != None: 885 code(''' 886 887// Set and Reset for cache_entry variable 888void 889$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 890{ 891 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 892} 893 894void 895$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 896{ 897 m_cache_entry_ptr = 0; 898} 899''') 900 901 if self.TBEType != None: 902 code(''' 903 904// Set and Reset for tbe variable 905void 906$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 907{ 908 m_tbe_ptr = m_new_tbe; 909} 910 911void 912$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 913{ 914 m_tbe_ptr = NULL; 915} 916''') 917 918 code(''' 919 920void 921$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 922{ 923''') 924 # 925 # Record cache contents for all associated caches. 926 # 927 code.indent() 928 for param in self.config_parameters: 929 if param.type_ast.type.ident == "CacheMemory": 930 assert(param.pointer) 931 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 932 933 code.dedent() 934 code(''' 935} 936 937// Actions 938''') 939 if self.TBEType != None and self.EntryType != None: 940 for action in self.actions.itervalues(): 941 if "c_code" not in action: 942 continue 943 944 code(''' 945/** \\brief ${{action.desc}} */ 946void 947$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 948{ 949 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 950 try { 951 ${{action["c_code"]}} 952 } catch (const RejectException & e) { 953 fatal("Error in action ${{ident}}:${{action.ident}}: " 954 "executed a peek statement with the wrong message " 955 "type specified. "); 956 } 957} 958 959''') 960 elif self.TBEType != None: 961 for action in self.actions.itervalues(): 962 if "c_code" not in action: 963 continue 964 965 code(''' 966/** \\brief ${{action.desc}} */ 967void 968$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, Addr addr) 969{ 970 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 971 ${{action["c_code"]}} 972} 973 974''') 975 elif self.EntryType != None: 976 for action in self.actions.itervalues(): 977 if "c_code" not in action: 978 continue 979 980 code(''' 981/** \\brief ${{action.desc}} */ 982void 983$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 984{ 985 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 986 ${{action["c_code"]}} 987} 988 989''') 990 else: 991 for action in self.actions.itervalues(): 992 if "c_code" not in action: 993 continue 994 995 code(''' 996/** \\brief ${{action.desc}} */ 997void 998$c_ident::${{action.ident}}(Addr addr) 999{ 1000 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 1001 ${{action["c_code"]}} 1002} 1003 1004''') 1005 for func in self.functions: 1006 code(func.generateCode()) 1007 1008 # Function for functional writes to messages buffered in the controller 1009 code(''' 1010int 1011$c_ident::functionalWriteBuffers(PacketPtr& pkt) 1012{ 1013 int num_functional_writes = 0; 1014''') 1015 for var in self.objects: 1016 vtype = var.type 1017 if vtype.isBuffer: 1018 vid = "m_%s_ptr" % var.ident 1019 code('num_functional_writes += $vid->functionalWrite(pkt);') 1020 1021 for var in self.config_parameters: 1022 vtype = var.type_ast.type 1023 if vtype.isBuffer: 1024 vid = "m_%s_ptr" % var.ident 1025 code('num_functional_writes += $vid->functionalWrite(pkt);') 1026 1027 code(''' 1028 return num_functional_writes; 1029} 1030''') 1031 1032 code.write(path, "%s.cc" % c_ident) 1033 1034 def printCWakeup(self, path, includes): 1035 '''Output the wakeup loop for the events''' 1036 1037 code = self.symtab.codeFormatter() 1038 ident = self.ident 1039 1040 outputRequest_types = True 1041 if len(self.request_types) == 0: 1042 outputRequest_types = False 1043 1044 code(''' 1045// Auto generated C++ code started by $__file__:$__line__ 1046// ${ident}: ${{self.short}} 1047 1048#include <sys/types.h> 1049#include <unistd.h> 1050 1051#include <cassert> 1052#include <typeinfo> 1053 1054#include "base/logging.hh" 1055 1056''') 1057 for f in self.debug_flags: 1058 code('#include "debug/${{f}}.hh"') 1059 code(''' 1060#include "mem/protocol/${ident}_Controller.hh" 1061#include "mem/protocol/${ident}_Event.hh" 1062#include "mem/protocol/${ident}_State.hh" 1063 1064''') 1065 1066 if outputRequest_types: 1067 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1068 1069 code(''' 1070#include "mem/protocol/Types.hh" 1071#include "mem/ruby/system/RubySystem.hh" 1072 1073''') 1074 1075 1076 for include_path in includes: 1077 code('#include "${{include_path}}"') 1078 1079 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1080 1081 code(''' 1082 1083using namespace std; 1084 1085void 1086${ident}_Controller::wakeup() 1087{ 1088 int counter = 0; 1089 while (true) { 1090 unsigned char rejected[${{len(msg_bufs)}}]; 1091 memset(rejected, 0, sizeof(unsigned char)*${{len(msg_bufs)}}); 1092 // Some cases will put us into an infinite loop without this limit 1093 assert(counter <= m_transitions_per_cycle); 1094 if (counter == m_transitions_per_cycle) { 1095 // Count how often we are fully utilized 1096 m_fully_busy_cycles++; 1097 1098 // Wakeup in another cycle and try again 1099 scheduleEvent(Cycles(1)); 1100 break; 1101 } 1102''') 1103 1104 code.indent() 1105 code.indent() 1106 1107 # InPorts 1108 # 1109 for port in self.in_ports: 1110 code.indent() 1111 code('// ${ident}InPort $port') 1112 if port.pairs.has_key("rank"): 1113 code('m_cur_in_port = ${{port.pairs["rank"]}};') 1114 else: 1115 code('m_cur_in_port = 0;') 1116 if port in port_to_buf_map: 1117 code('try {') 1118 code.indent() 1119 code('${{port["c_code_in_port"]}}') 1120 1121 if port in port_to_buf_map: 1122 code.dedent() 1123 code(''' 1124 } catch (const RejectException & e) { 1125 rejected[${{port_to_buf_map[port]}}]++; 1126 } 1127''') 1128 code.dedent() 1129 code('') 1130 1131 code.dedent() 1132 code.dedent() 1133 code(''' 1134 // If we got this far, we have nothing left todo or something went 1135 // wrong''') 1136 for buf_name, ports in in_msg_bufs.items(): 1137 if len(ports) > 1: 1138 # only produce checks when a buffer is shared by multiple ports 1139 code(''' 1140 if (${{buf_name}}->isReady(clockEdge()) && rejected[${{port_to_buf_map[ports[0]]}}] == ${{len(ports)}}) 1141 { 1142 // no port claimed the message on the top of this buffer 1143 panic("Runtime Error at Ruby Time: %d. " 1144 "All ports rejected a message. " 1145 "You are probably sending a message type to this controller " 1146 "over a virtual network that do not define an in_port for " 1147 "the incoming message type.\\n", 1148 Cycles(1)); 1149 } 1150''') 1151 code(''' 1152 break; 1153 } 1154} 1155''') 1156 1157 code.write(path, "%s_Wakeup.cc" % self.ident) 1158 1159 def printCSwitch(self, path): 1160 '''Output switch statement for transition table''' 1161 1162 code = self.symtab.codeFormatter() 1163 ident = self.ident 1164 1165 code(''' 1166// Auto generated C++ code started by $__file__:$__line__ 1167// ${ident}: ${{self.short}} 1168 1169#include <cassert> 1170 1171#include "base/logging.hh" 1172#include "base/trace.hh" 1173#include "debug/ProtocolTrace.hh" 1174#include "debug/RubyGenerated.hh" 1175#include "mem/protocol/${ident}_Controller.hh" 1176#include "mem/protocol/${ident}_Event.hh" 1177#include "mem/protocol/${ident}_State.hh" 1178#include "mem/protocol/Types.hh" 1179#include "mem/ruby/system/RubySystem.hh" 1180 1181#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1182 1183#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1184#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1185 1186TransitionResult 1187${ident}_Controller::doTransition(${ident}_Event event, 1188''') 1189 if self.EntryType != None: 1190 code(''' 1191 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1192''') 1193 if self.TBEType != None: 1194 code(''' 1195 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1196''') 1197 code(''' 1198 Addr addr) 1199{ 1200''') 1201 code.indent() 1202 1203 if self.TBEType != None and self.EntryType != None: 1204 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1205 elif self.TBEType != None: 1206 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1207 elif self.EntryType != None: 1208 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1209 else: 1210 code('${ident}_State state = getState(addr);') 1211 1212 code(''' 1213${ident}_State next_state = state; 1214 1215DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %#x\\n", 1216 *this, curCycle(), ${ident}_State_to_string(state), 1217 ${ident}_Event_to_string(event), addr); 1218 1219TransitionResult result = 1220''') 1221 if self.TBEType != None and self.EntryType != None: 1222 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1223 elif self.TBEType != None: 1224 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1225 elif self.EntryType != None: 1226 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1227 else: 1228 code('doTransitionWorker(event, state, next_state, addr);') 1229 1230 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1231 1232 code(''' 1233 1234if (result == TransitionResult_Valid) { 1235 DPRINTF(RubyGenerated, "next_state: %s\\n", 1236 ${ident}_State_to_string(next_state)); 1237 countTransition(state, event); 1238 1239 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %#x %s\\n", 1240 curTick(), m_version, "${ident}", 1241 ${ident}_Event_to_string(event), 1242 ${ident}_State_to_string(state), 1243 ${ident}_State_to_string(next_state), 1244 printAddress(addr), GET_TRANSITION_COMMENT()); 1245 1246 CLEAR_TRANSITION_COMMENT(); 1247''') 1248 if self.TBEType != None and self.EntryType != None: 1249 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1250 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1251 elif self.TBEType != None: 1252 code('setState(m_tbe_ptr, addr, next_state);') 1253 code('setAccessPermission(addr, next_state);') 1254 elif self.EntryType != None: 1255 code('setState(m_cache_entry_ptr, addr, next_state);') 1256 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1257 else: 1258 code('setState(addr, next_state);') 1259 code('setAccessPermission(addr, next_state);') 1260 1261 code(''' 1262} else if (result == TransitionResult_ResourceStall) { 1263 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1264 curTick(), m_version, "${ident}", 1265 ${ident}_Event_to_string(event), 1266 ${ident}_State_to_string(state), 1267 ${ident}_State_to_string(next_state), 1268 printAddress(addr), "Resource Stall"); 1269} else if (result == TransitionResult_ProtocolStall) { 1270 DPRINTF(RubyGenerated, "stalling\\n"); 1271 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1272 curTick(), m_version, "${ident}", 1273 ${ident}_Event_to_string(event), 1274 ${ident}_State_to_string(state), 1275 ${ident}_State_to_string(next_state), 1276 printAddress(addr), "Protocol Stall"); 1277} 1278 1279return result; 1280''') 1281 code.dedent() 1282 code(''' 1283} 1284 1285TransitionResult 1286${ident}_Controller::doTransitionWorker(${ident}_Event event, 1287 ${ident}_State state, 1288 ${ident}_State& next_state, 1289''') 1290 1291 if self.TBEType != None: 1292 code(''' 1293 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1294''') 1295 if self.EntryType != None: 1296 code(''' 1297 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1298''') 1299 code(''' 1300 Addr addr) 1301{ 1302 switch(HASH_FUN(state, event)) { 1303''') 1304 1305 # This map will allow suppress generating duplicate code 1306 cases = OrderedDict() 1307 1308 for trans in self.transitions: 1309 case_string = "%s_State_%s, %s_Event_%s" % \ 1310 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1311 1312 case = self.symtab.codeFormatter() 1313 # Only set next_state if it changes 1314 if trans.state != trans.nextState: 1315 if trans.nextState.isWildcard(): 1316 # When * is encountered as an end state of a transition, 1317 # the next state is determined by calling the 1318 # machine-specific getNextState function. The next state 1319 # is determined before any actions of the transition 1320 # execute, and therefore the next state calculation cannot 1321 # depend on any of the transitionactions. 1322 case('next_state = getNextState(addr);') 1323 else: 1324 ns_ident = trans.nextState.ident 1325 case('next_state = ${ident}_State_${ns_ident};') 1326 1327 actions = trans.actions 1328 request_types = trans.request_types 1329 1330 # Check for resources 1331 case_sorter = [] 1332 res = trans.resources 1333 for key,val in res.iteritems(): 1334 val = ''' 1335if (!%s.areNSlotsAvailable(%s, clockEdge())) 1336 return TransitionResult_ResourceStall; 1337''' % (key.code, val) 1338 case_sorter.append(val) 1339 1340 # Check all of the request_types for resource constraints 1341 for request_type in request_types: 1342 val = ''' 1343if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1344 return TransitionResult_ResourceStall; 1345} 1346''' % (self.ident, request_type.ident) 1347 case_sorter.append(val) 1348 1349 # Emit the code sequences in a sorted order. This makes the 1350 # output deterministic (without this the output order can vary 1351 # since Map's keys() on a vector of pointers is not deterministic 1352 for c in sorted(case_sorter): 1353 case("$c") 1354 1355 # Record access types for this transition 1356 for request_type in request_types: 1357 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1358 1359 # Figure out if we stall 1360 stall = False 1361 for action in actions: 1362 if action.ident == "z_stall": 1363 stall = True 1364 break 1365 1366 if stall: 1367 case('return TransitionResult_ProtocolStall;') 1368 else: 1369 if self.TBEType != None and self.EntryType != None: 1370 for action in actions: 1371 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1372 elif self.TBEType != None: 1373 for action in actions: 1374 case('${{action.ident}}(m_tbe_ptr, addr);') 1375 elif self.EntryType != None: 1376 for action in actions: 1377 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1378 else: 1379 for action in actions: 1380 case('${{action.ident}}(addr);') 1381 case('return TransitionResult_Valid;') 1382 1383 case = str(case) 1384 1385 # Look to see if this transition code is unique. 1386 if case not in cases: 1387 cases[case] = [] 1388 1389 cases[case].append(case_string) 1390 1391 # Walk through all of the unique code blocks and spit out the 1392 # corresponding case statement elements 1393 for case,transitions in cases.iteritems(): 1394 # Iterative over all the multiple transitions that share 1395 # the same code 1396 for trans in transitions: 1397 code(' case HASH_FUN($trans):') 1398 code(' $case\n') 1399 1400 code(''' 1401 default: 1402 panic("Invalid transition\\n" 1403 "%s time: %d addr: %#x event: %s state: %s\\n", 1404 name(), curCycle(), addr, event, state); 1405 } 1406 1407 return TransitionResult_Valid; 1408} 1409''') 1410 code.write(path, "%s_Transitions.cc" % self.ident) 1411 1412 1413 # ************************** 1414 # ******* HTML Files ******* 1415 # ************************** 1416 def frameRef(self, click_href, click_target, over_href, over_num, text): 1417 code = self.symtab.codeFormatter(fix_newlines=False) 1418 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1419 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1420 parent.frames[$over_num].location='$over_href' 1421 }\"> 1422 ${{html.formatShorthand(text)}} 1423 </A>""") 1424 return str(code) 1425 1426 def writeHTMLFiles(self, path): 1427 # Create table with no row hilighted 1428 self.printHTMLTransitions(path, None) 1429 1430 # Generate transition tables 1431 for state in self.states.itervalues(): 1432 self.printHTMLTransitions(path, state) 1433 1434 # Generate action descriptions 1435 for action in self.actions.itervalues(): 1436 name = "%s_action_%s.html" % (self.ident, action.ident) 1437 code = html.createSymbol(action, "Action") 1438 code.write(path, name) 1439 1440 # Generate state descriptions 1441 for state in self.states.itervalues(): 1442 name = "%s_State_%s.html" % (self.ident, state.ident) 1443 code = html.createSymbol(state, "State") 1444 code.write(path, name) 1445 1446 # Generate event descriptions 1447 for event in self.events.itervalues(): 1448 name = "%s_Event_%s.html" % (self.ident, event.ident) 1449 code = html.createSymbol(event, "Event") 1450 code.write(path, name) 1451 1452 def printHTMLTransitions(self, path, active_state): 1453 code = self.symtab.codeFormatter() 1454 1455 code(''' 1456<HTML> 1457<BODY link="blue" vlink="blue"> 1458 1459<H1 align="center">${{html.formatShorthand(self.short)}}: 1460''') 1461 code.indent() 1462 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1463 mid = machine.ident 1464 if i != 0: 1465 extra = " - " 1466 else: 1467 extra = "" 1468 if machine == self: 1469 code('$extra$mid') 1470 else: 1471 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1472 code.dedent() 1473 1474 code(""" 1475</H1> 1476 1477<TABLE border=1> 1478<TR> 1479 <TH> </TH> 1480""") 1481 1482 for event in self.events.itervalues(): 1483 href = "%s_Event_%s.html" % (self.ident, event.ident) 1484 ref = self.frameRef(href, "Status", href, "1", event.short) 1485 code('<TH bgcolor=white>$ref</TH>') 1486 1487 code('</TR>') 1488 # -- Body of table 1489 for state in self.states.itervalues(): 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 text = html.formatShorthand(state.short) 1499 ref = self.frameRef(click, "Table", over, "1", state.short) 1500 code(''' 1501<TR> 1502 <TH bgcolor=$color>$ref</TH> 1503''') 1504 1505 # -- One column for each event 1506 for event in self.events.itervalues(): 1507 trans = self.table.get((state,event), None) 1508 if trans is None: 1509 # This is the no transition case 1510 if state == active_state: 1511 color = "#C0C000" 1512 else: 1513 color = "lightgrey" 1514 1515 code('<TD bgcolor=$color> </TD>') 1516 continue 1517 1518 next = trans.nextState 1519 stall_action = False 1520 1521 # -- Get the actions 1522 for action in trans.actions: 1523 if action.ident == "z_stall" or \ 1524 action.ident == "zz_recycleMandatoryQueue": 1525 stall_action = True 1526 1527 # -- Print out "actions/next-state" 1528 if stall_action: 1529 if state == active_state: 1530 color = "#C0C000" 1531 else: 1532 color = "lightgrey" 1533 1534 elif active_state and next.ident == active_state.ident: 1535 color = "aqua" 1536 elif state == active_state: 1537 color = "yellow" 1538 else: 1539 color = "white" 1540 1541 code('<TD bgcolor=$color>') 1542 for action in trans.actions: 1543 href = "%s_action_%s.html" % (self.ident, action.ident) 1544 ref = self.frameRef(href, "Status", href, "1", 1545 action.short) 1546 code(' $ref') 1547 if next != state: 1548 if trans.actions: 1549 code('/') 1550 click = "%s_table_%s.html" % (self.ident, next.ident) 1551 over = "%s_State_%s.html" % (self.ident, next.ident) 1552 ref = self.frameRef(click, "Table", over, "1", next.short) 1553 code("$ref") 1554 code("</TD>") 1555 1556 # -- Each row 1557 if state == active_state: 1558 color = "yellow" 1559 else: 1560 color = "white" 1561 1562 click = "%s_table_%s.html" % (self.ident, state.ident) 1563 over = "%s_State_%s.html" % (self.ident, state.ident) 1564 ref = self.frameRef(click, "Table", over, "1", state.short) 1565 code(''' 1566 <TH bgcolor=$color>$ref</TH> 1567</TR> 1568''') 1569 code(''' 1570<!- Column footer-> 1571<TR> 1572 <TH> </TH> 1573''') 1574 1575 for event in self.events.itervalues(): 1576 href = "%s_Event_%s.html" % (self.ident, event.ident) 1577 ref = self.frameRef(href, "Status", href, "1", event.short) 1578 code('<TH bgcolor=white>$ref</TH>') 1579 code(''' 1580</TR> 1581</TABLE> 1582</BODY></HTML> 1583''') 1584 1585 1586 if active_state: 1587 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1588 else: 1589 name = "%s_table.html" % self.ident 1590 code.write(path, name) 1591 1592__all__ = [ "StateMachine" ] 1593