StateMachine.py revision 11309
14661Sksewell@umich.edu# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 24661Sksewell@umich.edu# Copyright (c) 2009 The Hewlett-Packard Development Company 34661Sksewell@umich.edu# Copyright (c) 2013 Advanced Micro Devices, Inc. 44661Sksewell@umich.edu# All rights reserved. 54661Sksewell@umich.edu# 64661Sksewell@umich.edu# Redistribution and use in source and binary forms, with or without 74661Sksewell@umich.edu# modification, are permitted provided that the following conditions are 84661Sksewell@umich.edu# met: redistributions of source code must retain the above copyright 94661Sksewell@umich.edu# notice, this list of conditions and the following disclaimer; 104661Sksewell@umich.edu# redistributions in binary form must reproduce the above copyright 114661Sksewell@umich.edu# notice, this list of conditions and the following disclaimer in the 124661Sksewell@umich.edu# documentation and/or other materials provided with the distribution; 134661Sksewell@umich.edu# neither the name of the copyright holders nor the names of its 144661Sksewell@umich.edu# contributors may be used to endorse or promote products derived from 154661Sksewell@umich.edu# this software without specific prior written permission. 164661Sksewell@umich.edu# 174661Sksewell@umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 184661Sksewell@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 194661Sksewell@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 204661Sksewell@umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 214661Sksewell@umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 224661Sksewell@umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 234661Sksewell@umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 244661Sksewell@umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 254661Sksewell@umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 264661Sksewell@umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 274661Sksewell@umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 284661Sksewell@umich.edu 294661Sksewell@umich.edufrom m5.util import orderdict 304661Sksewell@umich.edu 314661Sksewell@umich.edufrom slicc.symbols.Symbol import Symbol 324661Sksewell@umich.edufrom slicc.symbols.Var import Var 334661Sksewell@umich.eduimport slicc.generate.html as html 344661Sksewell@umich.eduimport re 354661Sksewell@umich.edu 364661Sksewell@umich.edupython_class_map = { 374661Sksewell@umich.edu "int": "Int", 384661Sksewell@umich.edu "NodeID": "Int", 394661Sksewell@umich.edu "uint32_t" : "UInt32", 404661Sksewell@umich.edu "std::string": "String", 414661Sksewell@umich.edu "bool": "Bool", 424661Sksewell@umich.edu "CacheMemory": "RubyCache", 434661Sksewell@umich.edu "WireBuffer": "RubyWireBuffer", 444661Sksewell@umich.edu "Sequencer": "RubySequencer", 454661Sksewell@umich.edu "GPUCoalescer" : "RubyGPUCoalescer", 464661Sksewell@umich.edu "VIPERCoalescer" : "VIPERCoalescer", 474661Sksewell@umich.edu "DirectoryMemory": "RubyDirectoryMemory", 484661Sksewell@umich.edu "PerfectCacheMemory": "RubyPerfectCacheMemory", 494661Sksewell@umich.edu "MemoryControl": "MemoryControl", 504661Sksewell@umich.edu "MessageBuffer": "MessageBuffer", 514661Sksewell@umich.edu "DMASequencer": "DMASequencer", 524661Sksewell@umich.edu "Prefetcher":"Prefetcher", 534661Sksewell@umich.edu "Cycles":"Cycles", 544661Sksewell@umich.edu } 554661Sksewell@umich.edu 564661Sksewell@umich.educlass StateMachine(Symbol): 574661Sksewell@umich.edu def __init__(self, symtab, ident, location, pairs, config_parameters): 584661Sksewell@umich.edu super(StateMachine, self).__init__(symtab, ident, location, pairs) 594661Sksewell@umich.edu self.table = None 604661Sksewell@umich.edu 614661Sksewell@umich.edu # Data members in the State Machine that have been declared before 624661Sksewell@umich.edu # the opening brace '{' of the machine. Note that these along with 634661Sksewell@umich.edu # the members in self.objects form the entire set of data members. 644661Sksewell@umich.edu self.config_parameters = config_parameters 654661Sksewell@umich.edu 664661Sksewell@umich.edu self.prefetchers = [] 674661Sksewell@umich.edu 684661Sksewell@umich.edu for param in config_parameters: 694661Sksewell@umich.edu if param.pointer: 704661Sksewell@umich.edu var = Var(symtab, param.ident, location, param.type_ast.type, 714661Sksewell@umich.edu "(*m_%s_ptr)" % param.ident, {}, self) 724661Sksewell@umich.edu else: 734661Sksewell@umich.edu var = Var(symtab, param.ident, location, param.type_ast.type, 744661Sksewell@umich.edu "m_%s" % param.ident, {}, self) 754661Sksewell@umich.edu 764661Sksewell@umich.edu self.symtab.registerSym(param.ident, var) 774661Sksewell@umich.edu 784661Sksewell@umich.edu if str(param.type_ast.type) == "Prefetcher": 794661Sksewell@umich.edu self.prefetchers.append(var) 804661Sksewell@umich.edu 814661Sksewell@umich.edu self.states = orderdict() 824661Sksewell@umich.edu self.events = orderdict() 834661Sksewell@umich.edu self.actions = orderdict() 844661Sksewell@umich.edu self.request_types = orderdict() 854661Sksewell@umich.edu self.transitions = [] 864661Sksewell@umich.edu self.in_ports = [] 874661Sksewell@umich.edu self.functions = [] 884661Sksewell@umich.edu 894661Sksewell@umich.edu # Data members in the State Machine that have been declared inside 904661Sksewell@umich.edu # the {} machine. Note that these along with the config params 914661Sksewell@umich.edu # form the entire set of data members of the machine. 924661Sksewell@umich.edu self.objects = [] 934661Sksewell@umich.edu self.TBEType = None 944661Sksewell@umich.edu self.EntryType = None 954661Sksewell@umich.edu self.debug_flags = set() 964661Sksewell@umich.edu self.debug_flags.add('RubyGenerated') 974661Sksewell@umich.edu self.debug_flags.add('RubySlicc') 984661Sksewell@umich.edu 994661Sksewell@umich.edu def __repr__(self): 1004661Sksewell@umich.edu return "[StateMachine: %s]" % self.ident 1014661Sksewell@umich.edu 1024661Sksewell@umich.edu def addState(self, state): 1034661Sksewell@umich.edu assert self.table is None 1044661Sksewell@umich.edu self.states[state.ident] = state 1054661Sksewell@umich.edu 1064661Sksewell@umich.edu def addEvent(self, event): 1074661Sksewell@umich.edu assert self.table is None 1084661Sksewell@umich.edu self.events[event.ident] = event 1094661Sksewell@umich.edu 1104661Sksewell@umich.edu def addAction(self, action): 1114661Sksewell@umich.edu assert self.table is None 1124661Sksewell@umich.edu 1134661Sksewell@umich.edu # Check for duplicate action 1144661Sksewell@umich.edu for other in self.actions.itervalues(): 1154661Sksewell@umich.edu if action.ident == other.ident: 1164661Sksewell@umich.edu action.warning("Duplicate action definition: %s" % action.ident) 1174661Sksewell@umich.edu action.error("Duplicate action definition: %s" % action.ident) 1184661Sksewell@umich.edu if action.short == other.short: 1194661Sksewell@umich.edu other.warning("Duplicate action shorthand: %s" % other.ident) 1204661Sksewell@umich.edu other.warning(" shorthand = %s" % other.short) 1214661Sksewell@umich.edu action.warning("Duplicate action shorthand: %s" % action.ident) 1224661Sksewell@umich.edu action.error(" shorthand = %s" % action.short) 1234661Sksewell@umich.edu 1244661Sksewell@umich.edu self.actions[action.ident] = action 1254661Sksewell@umich.edu 1264661Sksewell@umich.edu def addDebugFlag(self, flag): 1274661Sksewell@umich.edu self.debug_flags.add(flag) 1284661Sksewell@umich.edu 1294661Sksewell@umich.edu def addRequestType(self, request_type): 1304661Sksewell@umich.edu assert self.table is None 1314661Sksewell@umich.edu self.request_types[request_type.ident] = request_type 1324661Sksewell@umich.edu 1334661Sksewell@umich.edu def addTransition(self, trans): 1344661Sksewell@umich.edu assert self.table is None 1354661Sksewell@umich.edu self.transitions.append(trans) 1364661Sksewell@umich.edu 1374661Sksewell@umich.edu def addInPort(self, var): 1384661Sksewell@umich.edu self.in_ports.append(var) 1394661Sksewell@umich.edu 1404661Sksewell@umich.edu def addFunc(self, func): 1414661Sksewell@umich.edu # register func in the symbol table 1424661Sksewell@umich.edu self.symtab.registerSym(str(func), func) 1434661Sksewell@umich.edu self.functions.append(func) 1444661Sksewell@umich.edu 1454661Sksewell@umich.edu def addObject(self, obj): 1464661Sksewell@umich.edu self.symtab.registerSym(str(obj), obj) 1474661Sksewell@umich.edu self.objects.append(obj) 1484661Sksewell@umich.edu 1494661Sksewell@umich.edu def addType(self, type): 1504661Sksewell@umich.edu type_ident = '%s' % type.c_ident 1514661Sksewell@umich.edu 1524661Sksewell@umich.edu if type_ident == "%s_TBE" %self.ident: 1534661Sksewell@umich.edu if self.TBEType != None: 1544661Sksewell@umich.edu self.error("Multiple Transaction Buffer types in a " \ 1554661Sksewell@umich.edu "single machine."); 1564661Sksewell@umich.edu self.TBEType = type 1574661Sksewell@umich.edu 1584661Sksewell@umich.edu elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 1594661Sksewell@umich.edu if "main" in type and "false" == type["main"].lower(): 1604661Sksewell@umich.edu pass # this isn't the EntryType 1614661Sksewell@umich.edu else: 1624661Sksewell@umich.edu if self.EntryType != None: 1634661Sksewell@umich.edu self.error("Multiple AbstractCacheEntry types in a " \ 1644661Sksewell@umich.edu "single machine."); 1654661Sksewell@umich.edu self.EntryType = type 1664661Sksewell@umich.edu 1674661Sksewell@umich.edu # Needs to be called before accessing the table 1684661Sksewell@umich.edu def buildTable(self): 1694661Sksewell@umich.edu assert self.table is None 1704661Sksewell@umich.edu 1714661Sksewell@umich.edu table = {} 1724661Sksewell@umich.edu 1734661Sksewell@umich.edu for trans in self.transitions: 1744661Sksewell@umich.edu # Track which actions we touch so we know if we use them 1754661Sksewell@umich.edu # all -- really this should be done for all symbols as 1764661Sksewell@umich.edu # part of the symbol table, then only trigger it for 1774661Sksewell@umich.edu # Actions, States, Events, etc. 1784661Sksewell@umich.edu 1794661Sksewell@umich.edu for action in trans.actions: 1804661Sksewell@umich.edu action.used = True 1814661Sksewell@umich.edu 1824661Sksewell@umich.edu index = (trans.state, trans.event) 1834661Sksewell@umich.edu if index in table: 1844661Sksewell@umich.edu table[index].warning("Duplicate transition: %s" % table[index]) 1854661Sksewell@umich.edu trans.error("Duplicate transition: %s" % trans) 1864661Sksewell@umich.edu table[index] = trans 1874661Sksewell@umich.edu 1884661Sksewell@umich.edu # Look at all actions to make sure we used them all 1894661Sksewell@umich.edu for action in self.actions.itervalues(): 1904661Sksewell@umich.edu if not action.used: 1914661Sksewell@umich.edu error_msg = "Unused action: %s" % action.ident 1924661Sksewell@umich.edu if "desc" in action: 1934661Sksewell@umich.edu error_msg += ", " + action.desc 1944661Sksewell@umich.edu action.warning(error_msg) 1954661Sksewell@umich.edu self.table = table 1964661Sksewell@umich.edu 1974661Sksewell@umich.edu # determine the port->msg buffer mappings 1984661Sksewell@umich.edu def getBufferMaps(self, ident): 1994661Sksewell@umich.edu msg_bufs = [] 2004661Sksewell@umich.edu port_to_buf_map = {} 2014661Sksewell@umich.edu in_msg_bufs = {} 2024661Sksewell@umich.edu for port in self.in_ports: 2034661Sksewell@umich.edu buf_name = "m_%s_ptr" % port.pairs["buffer_expr"].name 2044661Sksewell@umich.edu msg_bufs.append(buf_name) 2054661Sksewell@umich.edu port_to_buf_map[port] = msg_bufs.index(buf_name) 2064661Sksewell@umich.edu if buf_name not in in_msg_bufs: 2074661Sksewell@umich.edu in_msg_bufs[buf_name] = [port] 2084661Sksewell@umich.edu else: 2094661Sksewell@umich.edu in_msg_bufs[buf_name].append(port) 2104661Sksewell@umich.edu return port_to_buf_map, in_msg_bufs, msg_bufs 2114661Sksewell@umich.edu 2124661Sksewell@umich.edu def writeCodeFiles(self, path, includes): 2134661Sksewell@umich.edu self.printControllerPython(path) 2144661Sksewell@umich.edu self.printControllerHH(path) 2154661Sksewell@umich.edu self.printControllerCC(path, includes) 2164661Sksewell@umich.edu self.printCSwitch(path) 2174661Sksewell@umich.edu self.printCWakeup(path, includes) 2184661Sksewell@umich.edu 2194661Sksewell@umich.edu def printControllerPython(self, path): 2204661Sksewell@umich.edu code = self.symtab.codeFormatter() 2214661Sksewell@umich.edu ident = self.ident 2224661Sksewell@umich.edu 2234661Sksewell@umich.edu py_ident = "%s_Controller" % ident 2244661Sksewell@umich.edu c_ident = "%s_Controller" % self.ident 2254661Sksewell@umich.edu 2264661Sksewell@umich.edu code(''' 2274661Sksewell@umich.edufrom m5.params import * 2284661Sksewell@umich.edufrom m5.SimObject import SimObject 2294661Sksewell@umich.edufrom Controller import RubyController 2304661Sksewell@umich.edu 2314661Sksewell@umich.educlass $py_ident(RubyController): 2324661Sksewell@umich.edu type = '$py_ident' 2334661Sksewell@umich.edu cxx_header = 'mem/protocol/${c_ident}.hh' 2344661Sksewell@umich.edu''') 2354661Sksewell@umich.edu code.indent() 2364661Sksewell@umich.edu for param in self.config_parameters: 2374661Sksewell@umich.edu dflt_str = '' 2384661Sksewell@umich.edu 2394661Sksewell@umich.edu if param.rvalue is not None: 2404661Sksewell@umich.edu dflt_str = str(param.rvalue.inline()) + ', ' 2414661Sksewell@umich.edu 2424661Sksewell@umich.edu if python_class_map.has_key(param.type_ast.type.c_ident): 2434661Sksewell@umich.edu python_type = python_class_map[param.type_ast.type.c_ident] 2444661Sksewell@umich.edu code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")') 2454661Sksewell@umich.edu 2464661Sksewell@umich.edu else: 2474661Sksewell@umich.edu self.error("Unknown c++ to python class conversion for c++ " \ 2484661Sksewell@umich.edu "type: '%s'. Please update the python_class_map " \ 2494661Sksewell@umich.edu "in StateMachine.py", param.type_ast.type.c_ident) 2504661Sksewell@umich.edu 2514661Sksewell@umich.edu code.dedent() 2524661Sksewell@umich.edu code.write(path, '%s.py' % py_ident) 2534661Sksewell@umich.edu 2544661Sksewell@umich.edu 2554661Sksewell@umich.edu def printControllerHH(self, path): 2564661Sksewell@umich.edu '''Output the method declarations for the class declaration''' 2574661Sksewell@umich.edu code = self.symtab.codeFormatter() 2584661Sksewell@umich.edu ident = self.ident 2594661Sksewell@umich.edu c_ident = "%s_Controller" % self.ident 2604661Sksewell@umich.edu 2614661Sksewell@umich.edu code(''' 2624661Sksewell@umich.edu/** \\file $c_ident.hh 2634661Sksewell@umich.edu * 2644661Sksewell@umich.edu * Auto generated C++ code started by $__file__:$__line__ 2654661Sksewell@umich.edu * Created by slicc definition of Module "${{self.short}}" 2664661Sksewell@umich.edu */ 2674661Sksewell@umich.edu 2684661Sksewell@umich.edu#ifndef __${ident}_CONTROLLER_HH__ 2694661Sksewell@umich.edu#define __${ident}_CONTROLLER_HH__ 2704661Sksewell@umich.edu 2714661Sksewell@umich.edu#include <iostream> 2724661Sksewell@umich.edu#include <sstream> 2734661Sksewell@umich.edu#include <string> 2744661Sksewell@umich.edu 2754661Sksewell@umich.edu#include "mem/protocol/TransitionResult.hh" 2764661Sksewell@umich.edu#include "mem/protocol/Types.hh" 2774661Sksewell@umich.edu#include "mem/ruby/common/Consumer.hh" 2784661Sksewell@umich.edu#include "mem/ruby/slicc_interface/AbstractController.hh" 2794661Sksewell@umich.edu#include "params/$c_ident.hh" 2804661Sksewell@umich.edu 2814661Sksewell@umich.edu''') 2824661Sksewell@umich.edu 2834661Sksewell@umich.edu seen_types = set() 2844661Sksewell@umich.edu for var in self.objects: 2854661Sksewell@umich.edu if var.type.ident not in seen_types and not var.type.isPrimitive: 2864661Sksewell@umich.edu code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 2874661Sksewell@umich.edu seen_types.add(var.type.ident) 2884661Sksewell@umich.edu 2894661Sksewell@umich.edu # for adding information to the protocol debug trace 2904661Sksewell@umich.edu code(''' 2914661Sksewell@umich.eduextern std::stringstream ${ident}_transitionComment; 2924661Sksewell@umich.edu 2934661Sksewell@umich.educlass $c_ident : public AbstractController 2944661Sksewell@umich.edu{ 2954661Sksewell@umich.edu public: 2964661Sksewell@umich.edu typedef ${c_ident}Params Params; 2974661Sksewell@umich.edu $c_ident(const Params *p); 2984661Sksewell@umich.edu static int getNumControllers(); 2994661Sksewell@umich.edu void init(); 3004661Sksewell@umich.edu 3014661Sksewell@umich.edu MessageBuffer *getMandatoryQueue() const; 3024661Sksewell@umich.edu MessageBuffer *getMemoryQueue() const; 3034661Sksewell@umich.edu void initNetQueues(); 3044661Sksewell@umich.edu 3054661Sksewell@umich.edu void print(std::ostream& out) const; 3064661Sksewell@umich.edu void wakeup(); 3074661Sksewell@umich.edu void resetStats(); 3084661Sksewell@umich.edu void regStats(); 3094661Sksewell@umich.edu void collateStats(); 3104661Sksewell@umich.edu 3114661Sksewell@umich.edu void recordCacheTrace(int cntrl, CacheRecorder* tr); 3124661Sksewell@umich.edu Sequencer* getCPUSequencer() const; 3134661Sksewell@umich.edu GPUCoalescer* getGPUCoalescer() const; 3144661Sksewell@umich.edu 3154661Sksewell@umich.edu int functionalWriteBuffers(PacketPtr&); 3164661Sksewell@umich.edu 3174661Sksewell@umich.edu void countTransition(${ident}_State state, ${ident}_Event event); 3184661Sksewell@umich.edu void possibleTransition(${ident}_State state, ${ident}_Event event); 3194661Sksewell@umich.edu uint64_t getEventCount(${ident}_Event event); 3204661Sksewell@umich.edu bool isPossible(${ident}_State state, ${ident}_Event event); 3214661Sksewell@umich.edu uint64_t getTransitionCount(${ident}_State state, ${ident}_Event event); 3224661Sksewell@umich.edu 3234661Sksewell@umich.eduprivate: 3244661Sksewell@umich.edu''') 3254661Sksewell@umich.edu 3264661Sksewell@umich.edu code.indent() 3274661Sksewell@umich.edu # added by SS 3284661Sksewell@umich.edu for param in self.config_parameters: 3294661Sksewell@umich.edu if param.pointer: 3304661Sksewell@umich.edu code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 3314661Sksewell@umich.edu else: 3324661Sksewell@umich.edu code('${{param.type_ast.type}} m_${{param.ident}};') 3334661Sksewell@umich.edu 3344661Sksewell@umich.edu code(''' 3354661Sksewell@umich.eduTransitionResult doTransition(${ident}_Event event, 3364661Sksewell@umich.edu''') 3374661Sksewell@umich.edu 3384661Sksewell@umich.edu if self.EntryType != None: 3394661Sksewell@umich.edu code(''' 3404661Sksewell@umich.edu ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 3414661Sksewell@umich.edu''') 3424661Sksewell@umich.edu if self.TBEType != None: 3434661Sksewell@umich.edu code(''' 3444661Sksewell@umich.edu ${{self.TBEType.c_ident}}* m_tbe_ptr, 3454661Sksewell@umich.edu''') 3464661Sksewell@umich.edu 3474661Sksewell@umich.edu code(''' 3484661Sksewell@umich.edu Addr addr); 3494661Sksewell@umich.edu 3504661Sksewell@umich.eduTransitionResult doTransitionWorker(${ident}_Event event, 3514661Sksewell@umich.edu ${ident}_State state, 3524661Sksewell@umich.edu ${ident}_State& next_state, 3534661Sksewell@umich.edu''') 3544661Sksewell@umich.edu 3554661Sksewell@umich.edu if self.TBEType != None: 3564661Sksewell@umich.edu code(''' 3574661Sksewell@umich.edu ${{self.TBEType.c_ident}}*& m_tbe_ptr, 3584661Sksewell@umich.edu''') 3594661Sksewell@umich.edu if self.EntryType != None: 3604661Sksewell@umich.edu code(''' 3614661Sksewell@umich.edu ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 3624661Sksewell@umich.edu''') 3634661Sksewell@umich.edu 3644661Sksewell@umich.edu code(''' 3654661Sksewell@umich.edu Addr addr); 3664661Sksewell@umich.edu 3674661Sksewell@umich.eduint m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 3684661Sksewell@umich.eduint m_event_counters[${ident}_Event_NUM]; 3694661Sksewell@umich.edubool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 3704661Sksewell@umich.edu 3714661Sksewell@umich.edustatic std::vector<Stats::Vector *> eventVec; 3724661Sksewell@umich.edustatic std::vector<std::vector<Stats::Vector *> > transVec; 3734661Sksewell@umich.edustatic int m_num_controllers; 3744661Sksewell@umich.edu 3754661Sksewell@umich.edu// Internal functions 3764661Sksewell@umich.edu''') 3774661Sksewell@umich.edu 3784661Sksewell@umich.edu for func in self.functions: 3794661Sksewell@umich.edu proto = func.prototype 3804661Sksewell@umich.edu if proto: 3814661Sksewell@umich.edu code('$proto') 3824661Sksewell@umich.edu 3834661Sksewell@umich.edu if self.EntryType != None: 3844661Sksewell@umich.edu code(''' 3854661Sksewell@umich.edu 3864661Sksewell@umich.edu// Set and Reset for cache_entry variable 3874661Sksewell@umich.eduvoid set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 3884661Sksewell@umich.eduvoid unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 3894661Sksewell@umich.edu''') 3904661Sksewell@umich.edu 3914661Sksewell@umich.edu if self.TBEType != None: 3924661Sksewell@umich.edu code(''' 3934661Sksewell@umich.edu 3944661Sksewell@umich.edu// Set and Reset for tbe variable 3954661Sksewell@umich.eduvoid set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 3964661Sksewell@umich.eduvoid unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 3974661Sksewell@umich.edu''') 3984661Sksewell@umich.edu 3994661Sksewell@umich.edu # Prototype the actions that the controller can take 4004661Sksewell@umich.edu code(''' 4014661Sksewell@umich.edu 4024661Sksewell@umich.edu// Actions 4034661Sksewell@umich.edu''') 4044661Sksewell@umich.edu if self.TBEType != None and self.EntryType != None: 4054661Sksewell@umich.edu for action in self.actions.itervalues(): 4064661Sksewell@umich.edu code('/** \\brief ${{action.desc}} */') 4074661Sksewell@umich.edu code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 4084661Sksewell@umich.edu 'm_tbe_ptr, ${{self.EntryType.c_ident}}*& ' 4094661Sksewell@umich.edu 'm_cache_entry_ptr, Addr addr);') 4104661Sksewell@umich.edu elif self.TBEType != None: 4114661Sksewell@umich.edu for action in self.actions.itervalues(): 4124661Sksewell@umich.edu code('/** \\brief ${{action.desc}} */') 4134661Sksewell@umich.edu code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 4144661Sksewell@umich.edu 'm_tbe_ptr, Addr addr);') 4154661Sksewell@umich.edu elif self.EntryType != None: 4164661Sksewell@umich.edu for action in self.actions.itervalues(): 4174661Sksewell@umich.edu code('/** \\brief ${{action.desc}} */') 4184661Sksewell@umich.edu code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& ' 4194661Sksewell@umich.edu 'm_cache_entry_ptr, Addr addr);') 4204661Sksewell@umich.edu else: 4214661Sksewell@umich.edu for action in self.actions.itervalues(): 4224661Sksewell@umich.edu code('/** \\brief ${{action.desc}} */') 4234661Sksewell@umich.edu code('void ${{action.ident}}(Addr addr);') 4244661Sksewell@umich.edu 4254661Sksewell@umich.edu # the controller internal variables 4264661Sksewell@umich.edu code(''' 4274661Sksewell@umich.edu 4284661Sksewell@umich.edu// Objects 4294661Sksewell@umich.edu''') 4304661Sksewell@umich.edu for var in self.objects: 4314661Sksewell@umich.edu th = var.get("template", "") 4324661Sksewell@umich.edu code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;') 4334661Sksewell@umich.edu 4344661Sksewell@umich.edu code.dedent() 4354661Sksewell@umich.edu code('};') 4364661Sksewell@umich.edu code('#endif // __${ident}_CONTROLLER_H__') 4374661Sksewell@umich.edu code.write(path, '%s.hh' % c_ident) 4384661Sksewell@umich.edu 4394661Sksewell@umich.edu def printControllerCC(self, path, includes): 4404661Sksewell@umich.edu '''Output the actions for performing the actions''' 4414661Sksewell@umich.edu 4424661Sksewell@umich.edu code = self.symtab.codeFormatter() 4434661Sksewell@umich.edu ident = self.ident 4444661Sksewell@umich.edu c_ident = "%s_Controller" % self.ident 4454661Sksewell@umich.edu 4464661Sksewell@umich.edu code(''' 4474661Sksewell@umich.edu/** \\file $c_ident.cc 4484661Sksewell@umich.edu * 4494661Sksewell@umich.edu * Auto generated C++ code started by $__file__:$__line__ 4504661Sksewell@umich.edu * Created by slicc definition of Module "${{self.short}}" 4514661Sksewell@umich.edu */ 4524661Sksewell@umich.edu 4534661Sksewell@umich.edu#include <sys/types.h> 4544661Sksewell@umich.edu#include <unistd.h> 4554661Sksewell@umich.edu 4564661Sksewell@umich.edu#include <cassert> 4574661Sksewell@umich.edu#include <sstream> 4584661Sksewell@umich.edu#include <string> 4594661Sksewell@umich.edu#include <typeinfo> 4604661Sksewell@umich.edu 4614661Sksewell@umich.edu#include "base/compiler.hh" 4624661Sksewell@umich.edu#include "base/cprintf.hh" 4634661Sksewell@umich.edu 4644661Sksewell@umich.edu''') 465 for f in self.debug_flags: 466 code('#include "debug/${{f}}.hh"') 467 code(''' 468#include "mem/protocol/${ident}_Controller.hh" 469#include "mem/protocol/${ident}_Event.hh" 470#include "mem/protocol/${ident}_State.hh" 471#include "mem/protocol/Types.hh" 472#include "mem/ruby/system/RubySystem.hh" 473 474''') 475 for include_path in includes: 476 code('#include "${{include_path}}"') 477 478 code(''' 479 480using namespace std; 481''') 482 483 # include object classes 484 seen_types = set() 485 for var in self.objects: 486 if var.type.ident not in seen_types and not var.type.isPrimitive: 487 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 488 seen_types.add(var.type.ident) 489 490 num_in_ports = len(self.in_ports) 491 492 code(''' 493$c_ident * 494${c_ident}Params::create() 495{ 496 return new $c_ident(this); 497} 498 499int $c_ident::m_num_controllers = 0; 500std::vector<Stats::Vector *> $c_ident::eventVec; 501std::vector<std::vector<Stats::Vector *> > $c_ident::transVec; 502 503// for adding information to the protocol debug trace 504stringstream ${ident}_transitionComment; 505 506#ifndef NDEBUG 507#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 508#else 509#define APPEND_TRANSITION_COMMENT(str) do {} while (0) 510#endif 511 512/** \\brief constructor */ 513$c_ident::$c_ident(const Params *p) 514 : AbstractController(p) 515{ 516 m_machineID.type = MachineType_${ident}; 517 m_machineID.num = m_version; 518 m_num_controllers++; 519 520 m_in_ports = $num_in_ports; 521''') 522 code.indent() 523 524 # 525 # After initializing the universal machine parameters, initialize the 526 # this machines config parameters. Also if these configuration params 527 # include a sequencer, connect the it to the controller. 528 # 529 for param in self.config_parameters: 530 if param.pointer: 531 code('m_${{param.ident}}_ptr = p->${{param.ident}};') 532 else: 533 code('m_${{param.ident}} = p->${{param.ident}};') 534 535 if re.compile("sequencer").search(param.ident) or \ 536 param.type_ast.type.c_ident == "GPUCoalescer" or \ 537 param.type_ast.type.c_ident == "VIPERCoalescer": 538 code(''' 539if (m_${{param.ident}}_ptr != NULL) { 540 m_${{param.ident}}_ptr->setController(this); 541} 542''') 543 544 code(''' 545 546for (int state = 0; state < ${ident}_State_NUM; state++) { 547 for (int event = 0; event < ${ident}_Event_NUM; event++) { 548 m_possible[state][event] = false; 549 m_counters[state][event] = 0; 550 } 551} 552for (int event = 0; event < ${ident}_Event_NUM; event++) { 553 m_event_counters[event] = 0; 554} 555''') 556 code.dedent() 557 code(''' 558} 559 560void 561$c_ident::initNetQueues() 562{ 563 MachineType machine_type = string_to_MachineType("${{self.ident}}"); 564 int base M5_VAR_USED = MachineType_base_number(machine_type); 565 566''') 567 code.indent() 568 569 # set for maintaining the vnet, direction pairs already seen for this 570 # machine. This map helps in implementing the check for avoiding 571 # multiple message buffers being mapped to the same vnet. 572 vnet_dir_set = set() 573 574 for var in self.config_parameters: 575 vid = "m_%s_ptr" % var.ident 576 if "network" in var: 577 vtype = var.type_ast.type 578 code('assert($vid != NULL);') 579 580 # Network port object 581 network = var["network"] 582 583 if "virtual_network" in var: 584 vnet = var["virtual_network"] 585 vnet_type = var["vnet_type"] 586 587 assert (vnet, network) not in vnet_dir_set 588 vnet_dir_set.add((vnet,network)) 589 590 code(''' 591m_net_ptr->set${network}NetQueue(m_version + base, $vid->getOrdered(), $vnet, 592 "$vnet_type", $vid); 593''') 594 # Set Priority 595 if "rank" in var: 596 code('$vid->setPriority(${{var["rank"]}})') 597 598 code.dedent() 599 code(''' 600} 601 602void 603$c_ident::init() 604{ 605 // initialize objects 606''') 607 608 code.indent() 609 610 for var in self.objects: 611 vtype = var.type 612 vid = "m_%s_ptr" % var.ident 613 if "network" not in var: 614 # Not a network port object 615 if "primitive" in vtype: 616 code('$vid = new ${{vtype.c_ident}};') 617 if "default" in var: 618 code('(*$vid) = ${{var["default"]}};') 619 else: 620 # Normal Object 621 th = var.get("template", "") 622 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 623 args = "" 624 if "non_obj" not in vtype and not vtype.isEnumeration: 625 args = var.get("constructor", "") 626 627 code('$expr($args);') 628 code('assert($vid != NULL);') 629 630 if "default" in var: 631 code('*$vid = ${{var["default"]}}; // Object default') 632 elif "default" in vtype: 633 comment = "Type %s default" % vtype.ident 634 code('*$vid = ${{vtype["default"]}}; // $comment') 635 636 # Set the prefetchers 637 code() 638 for prefetcher in self.prefetchers: 639 code('${{prefetcher.code}}.setController(this);') 640 641 code() 642 for port in self.in_ports: 643 # Set the queue consumers 644 code('${{port.code}}.setConsumer(this);') 645 646 # Initialize the transition profiling 647 code() 648 for trans in self.transitions: 649 # Figure out if we stall 650 stall = False 651 for action in trans.actions: 652 if action.ident == "z_stall": 653 stall = True 654 655 # Only possible if it is not a 'z' case 656 if not stall: 657 state = "%s_State_%s" % (self.ident, trans.state.ident) 658 event = "%s_Event_%s" % (self.ident, trans.event.ident) 659 code('possibleTransition($state, $event);') 660 661 code.dedent() 662 code(''' 663 AbstractController::init(); 664 resetStats(); 665} 666''') 667 668 mq_ident = "NULL" 669 for port in self.in_ports: 670 if port.code.find("mandatoryQueue_ptr") >= 0: 671 mq_ident = "m_mandatoryQueue_ptr" 672 673 memq_ident = "NULL" 674 for port in self.in_ports: 675 if port.code.find("responseFromMemory_ptr") >= 0: 676 memq_ident = "m_responseFromMemory_ptr" 677 678 seq_ident = "NULL" 679 for param in self.config_parameters: 680 if param.ident == "sequencer": 681 assert(param.pointer) 682 seq_ident = "m_%s_ptr" % param.ident 683 684 coal_ident = "NULL" 685 for param in self.config_parameters: 686 if param.ident == "coalescer": 687 assert(param.pointer) 688 coal_ident = "m_%s_ptr" % param.ident 689 690 if seq_ident != "NULL": 691 code(''' 692Sequencer* 693$c_ident::getCPUSequencer() const 694{ 695 if (NULL != $seq_ident && $seq_ident->isCPUSequencer()) { 696 return $seq_ident; 697 } else { 698 return NULL; 699 } 700} 701''') 702 else: 703 code(''' 704 705Sequencer* 706$c_ident::getCPUSequencer() const 707{ 708 return NULL; 709} 710''') 711 712 if coal_ident != "NULL": 713 code(''' 714GPUCoalescer* 715$c_ident::getGPUCoalescer() const 716{ 717 if (NULL != $coal_ident && !$coal_ident->isCPUSequencer()) { 718 return $coal_ident; 719 } else { 720 return NULL; 721 } 722} 723''') 724 else: 725 code(''' 726 727GPUCoalescer* 728$c_ident::getGPUCoalescer() const 729{ 730 return NULL; 731} 732''') 733 734 code(''' 735 736void 737$c_ident::regStats() 738{ 739 AbstractController::regStats(); 740 741 if (m_version == 0) { 742 for (${ident}_Event event = ${ident}_Event_FIRST; 743 event < ${ident}_Event_NUM; ++event) { 744 Stats::Vector *t = new Stats::Vector(); 745 t->init(m_num_controllers); 746 t->name(params()->ruby_system->name() + ".${c_ident}." + 747 ${ident}_Event_to_string(event)); 748 t->flags(Stats::pdf | Stats::total | Stats::oneline | 749 Stats::nozero); 750 751 eventVec.push_back(t); 752 } 753 754 for (${ident}_State state = ${ident}_State_FIRST; 755 state < ${ident}_State_NUM; ++state) { 756 757 transVec.push_back(std::vector<Stats::Vector *>()); 758 759 for (${ident}_Event event = ${ident}_Event_FIRST; 760 event < ${ident}_Event_NUM; ++event) { 761 762 Stats::Vector *t = new Stats::Vector(); 763 t->init(m_num_controllers); 764 t->name(params()->ruby_system->name() + ".${c_ident}." + 765 ${ident}_State_to_string(state) + 766 "." + ${ident}_Event_to_string(event)); 767 768 t->flags(Stats::pdf | Stats::total | Stats::oneline | 769 Stats::nozero); 770 transVec[state].push_back(t); 771 } 772 } 773 } 774} 775 776void 777$c_ident::collateStats() 778{ 779 for (${ident}_Event event = ${ident}_Event_FIRST; 780 event < ${ident}_Event_NUM; ++event) { 781 for (unsigned int i = 0; i < m_num_controllers; ++i) { 782 RubySystem *rs = params()->ruby_system; 783 std::map<uint32_t, AbstractController *>::iterator it = 784 rs->m_abstract_controls[MachineType_${ident}].find(i); 785 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 786 (*eventVec[event])[i] = 787 (($c_ident *)(*it).second)->getEventCount(event); 788 } 789 } 790 791 for (${ident}_State state = ${ident}_State_FIRST; 792 state < ${ident}_State_NUM; ++state) { 793 794 for (${ident}_Event event = ${ident}_Event_FIRST; 795 event < ${ident}_Event_NUM; ++event) { 796 797 for (unsigned int i = 0; i < m_num_controllers; ++i) { 798 RubySystem *rs = params()->ruby_system; 799 std::map<uint32_t, AbstractController *>::iterator it = 800 rs->m_abstract_controls[MachineType_${ident}].find(i); 801 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 802 (*transVec[state][event])[i] = 803 (($c_ident *)(*it).second)->getTransitionCount(state, event); 804 } 805 } 806 } 807} 808 809void 810$c_ident::countTransition(${ident}_State state, ${ident}_Event event) 811{ 812 assert(m_possible[state][event]); 813 m_counters[state][event]++; 814 m_event_counters[event]++; 815} 816void 817$c_ident::possibleTransition(${ident}_State state, 818 ${ident}_Event event) 819{ 820 m_possible[state][event] = true; 821} 822 823uint64_t 824$c_ident::getEventCount(${ident}_Event event) 825{ 826 return m_event_counters[event]; 827} 828 829bool 830$c_ident::isPossible(${ident}_State state, ${ident}_Event event) 831{ 832 return m_possible[state][event]; 833} 834 835uint64_t 836$c_ident::getTransitionCount(${ident}_State state, 837 ${ident}_Event event) 838{ 839 return m_counters[state][event]; 840} 841 842int 843$c_ident::getNumControllers() 844{ 845 return m_num_controllers; 846} 847 848MessageBuffer* 849$c_ident::getMandatoryQueue() const 850{ 851 return $mq_ident; 852} 853 854MessageBuffer* 855$c_ident::getMemoryQueue() const 856{ 857 return $memq_ident; 858} 859 860void 861$c_ident::print(ostream& out) const 862{ 863 out << "[$c_ident " << m_version << "]"; 864} 865 866void $c_ident::resetStats() 867{ 868 for (int state = 0; state < ${ident}_State_NUM; state++) { 869 for (int event = 0; event < ${ident}_Event_NUM; event++) { 870 m_counters[state][event] = 0; 871 } 872 } 873 874 for (int event = 0; event < ${ident}_Event_NUM; event++) { 875 m_event_counters[event] = 0; 876 } 877 878 AbstractController::resetStats(); 879} 880''') 881 882 if self.EntryType != None: 883 code(''' 884 885// Set and Reset for cache_entry variable 886void 887$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 888{ 889 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 890} 891 892void 893$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 894{ 895 m_cache_entry_ptr = 0; 896} 897''') 898 899 if self.TBEType != None: 900 code(''' 901 902// Set and Reset for tbe variable 903void 904$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 905{ 906 m_tbe_ptr = m_new_tbe; 907} 908 909void 910$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 911{ 912 m_tbe_ptr = NULL; 913} 914''') 915 916 code(''' 917 918void 919$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 920{ 921''') 922 # 923 # Record cache contents for all associated caches. 924 # 925 code.indent() 926 for param in self.config_parameters: 927 if param.type_ast.type.ident == "CacheMemory": 928 assert(param.pointer) 929 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 930 931 code.dedent() 932 code(''' 933} 934 935// Actions 936''') 937 if self.TBEType != None and self.EntryType != None: 938 for action in self.actions.itervalues(): 939 if "c_code" not in action: 940 continue 941 942 code(''' 943/** \\brief ${{action.desc}} */ 944void 945$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 946{ 947 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 948 try { 949 ${{action["c_code"]}} 950 } catch (const RejectException & e) { 951 fatal("Error in action ${{ident}}:${{action.ident}}: " 952 "executed a peek statement with the wrong message " 953 "type specified. "); 954 } 955} 956 957''') 958 elif self.TBEType != None: 959 for action in self.actions.itervalues(): 960 if "c_code" not in action: 961 continue 962 963 code(''' 964/** \\brief ${{action.desc}} */ 965void 966$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, Addr addr) 967{ 968 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 969 ${{action["c_code"]}} 970} 971 972''') 973 elif self.EntryType != None: 974 for action in self.actions.itervalues(): 975 if "c_code" not in action: 976 continue 977 978 code(''' 979/** \\brief ${{action.desc}} */ 980void 981$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 982{ 983 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 984 ${{action["c_code"]}} 985} 986 987''') 988 else: 989 for action in self.actions.itervalues(): 990 if "c_code" not in action: 991 continue 992 993 code(''' 994/** \\brief ${{action.desc}} */ 995void 996$c_ident::${{action.ident}}(Addr addr) 997{ 998 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 999 ${{action["c_code"]}} 1000} 1001 1002''') 1003 for func in self.functions: 1004 code(func.generateCode()) 1005 1006 # Function for functional writes to messages buffered in the controller 1007 code(''' 1008int 1009$c_ident::functionalWriteBuffers(PacketPtr& pkt) 1010{ 1011 int num_functional_writes = 0; 1012''') 1013 for var in self.objects: 1014 vtype = var.type 1015 if vtype.isBuffer: 1016 vid = "m_%s_ptr" % var.ident 1017 code('num_functional_writes += $vid->functionalWrite(pkt);') 1018 1019 for var in self.config_parameters: 1020 vtype = var.type_ast.type 1021 if vtype.isBuffer: 1022 vid = "m_%s_ptr" % var.ident 1023 code('num_functional_writes += $vid->functionalWrite(pkt);') 1024 1025 code(''' 1026 return num_functional_writes; 1027} 1028''') 1029 1030 code.write(path, "%s.cc" % c_ident) 1031 1032 def printCWakeup(self, path, includes): 1033 '''Output the wakeup loop for the events''' 1034 1035 code = self.symtab.codeFormatter() 1036 ident = self.ident 1037 1038 outputRequest_types = True 1039 if len(self.request_types) == 0: 1040 outputRequest_types = False 1041 1042 code(''' 1043// Auto generated C++ code started by $__file__:$__line__ 1044// ${ident}: ${{self.short}} 1045 1046#include <sys/types.h> 1047#include <unistd.h> 1048 1049#include <cassert> 1050#include <typeinfo> 1051 1052#include "base/misc.hh" 1053 1054''') 1055 for f in self.debug_flags: 1056 code('#include "debug/${{f}}.hh"') 1057 code(''' 1058#include "mem/protocol/${ident}_Controller.hh" 1059#include "mem/protocol/${ident}_Event.hh" 1060#include "mem/protocol/${ident}_State.hh" 1061 1062''') 1063 1064 if outputRequest_types: 1065 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1066 1067 code(''' 1068#include "mem/protocol/Types.hh" 1069#include "mem/ruby/system/RubySystem.hh" 1070 1071''') 1072 1073 1074 for include_path in includes: 1075 code('#include "${{include_path}}"') 1076 1077 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1078 1079 code(''' 1080 1081using namespace std; 1082 1083void 1084${ident}_Controller::wakeup() 1085{ 1086 int counter = 0; 1087 while (true) { 1088 unsigned char rejected[${{len(msg_bufs)}}]; 1089 memset(rejected, 0, sizeof(unsigned char)*${{len(msg_bufs)}}); 1090 // Some cases will put us into an infinite loop without this limit 1091 assert(counter <= m_transitions_per_cycle); 1092 if (counter == m_transitions_per_cycle) { 1093 // Count how often we are fully utilized 1094 m_fully_busy_cycles++; 1095 1096 // Wakeup in another cycle and try again 1097 scheduleEvent(Cycles(1)); 1098 break; 1099 } 1100''') 1101 1102 code.indent() 1103 code.indent() 1104 1105 # InPorts 1106 # 1107 for port in self.in_ports: 1108 code.indent() 1109 code('// ${ident}InPort $port') 1110 if port.pairs.has_key("rank"): 1111 code('m_cur_in_port = ${{port.pairs["rank"]}};') 1112 else: 1113 code('m_cur_in_port = 0;') 1114 if port in port_to_buf_map: 1115 code('try {') 1116 code.indent() 1117 code('${{port["c_code_in_port"]}}') 1118 1119 if port in port_to_buf_map: 1120 code.dedent() 1121 code(''' 1122 } catch (const RejectException & e) { 1123 rejected[${{port_to_buf_map[port]}}]++; 1124 } 1125''') 1126 code.dedent() 1127 code('') 1128 1129 code.dedent() 1130 code.dedent() 1131 code(''' 1132 // If we got this far, we have nothing left todo or something went 1133 // wrong''') 1134 for buf_name, ports in in_msg_bufs.items(): 1135 if len(ports) > 1: 1136 # only produce checks when a buffer is shared by multiple ports 1137 code(''' 1138 if (${{buf_name}}->isReady(clockEdge()) && rejected[${{port_to_buf_map[ports[0]]}}] == ${{len(ports)}}) 1139 { 1140 // no port claimed the message on the top of this buffer 1141 panic("Runtime Error at Ruby Time: %d. " 1142 "All ports rejected a message. " 1143 "You are probably sending a message type to this controller " 1144 "over a virtual network that do not define an in_port for " 1145 "the incoming message type.\\n", 1146 Cycles(1)); 1147 } 1148''') 1149 code(''' 1150 break; 1151 } 1152} 1153''') 1154 1155 code.write(path, "%s_Wakeup.cc" % self.ident) 1156 1157 def printCSwitch(self, path): 1158 '''Output switch statement for transition table''' 1159 1160 code = self.symtab.codeFormatter() 1161 ident = self.ident 1162 1163 code(''' 1164// Auto generated C++ code started by $__file__:$__line__ 1165// ${ident}: ${{self.short}} 1166 1167#include <cassert> 1168 1169#include "base/misc.hh" 1170#include "base/trace.hh" 1171#include "debug/ProtocolTrace.hh" 1172#include "debug/RubyGenerated.hh" 1173#include "mem/protocol/${ident}_Controller.hh" 1174#include "mem/protocol/${ident}_Event.hh" 1175#include "mem/protocol/${ident}_State.hh" 1176#include "mem/protocol/Types.hh" 1177#include "mem/ruby/system/RubySystem.hh" 1178 1179#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1180 1181#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1182#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1183 1184TransitionResult 1185${ident}_Controller::doTransition(${ident}_Event event, 1186''') 1187 if self.EntryType != None: 1188 code(''' 1189 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1190''') 1191 if self.TBEType != None: 1192 code(''' 1193 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1194''') 1195 code(''' 1196 Addr addr) 1197{ 1198''') 1199 code.indent() 1200 1201 if self.TBEType != None and self.EntryType != None: 1202 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1203 elif self.TBEType != None: 1204 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1205 elif self.EntryType != None: 1206 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1207 else: 1208 code('${ident}_State state = getState(addr);') 1209 1210 code(''' 1211${ident}_State next_state = state; 1212 1213DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %#x\\n", 1214 *this, curCycle(), ${ident}_State_to_string(state), 1215 ${ident}_Event_to_string(event), addr); 1216 1217TransitionResult result = 1218''') 1219 if self.TBEType != None and self.EntryType != None: 1220 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1221 elif self.TBEType != None: 1222 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1223 elif self.EntryType != None: 1224 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1225 else: 1226 code('doTransitionWorker(event, state, next_state, addr);') 1227 1228 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1229 1230 code(''' 1231 1232if (result == TransitionResult_Valid) { 1233 DPRINTF(RubyGenerated, "next_state: %s\\n", 1234 ${ident}_State_to_string(next_state)); 1235 countTransition(state, event); 1236 1237 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %#x %s\\n", 1238 curTick(), m_version, "${ident}", 1239 ${ident}_Event_to_string(event), 1240 ${ident}_State_to_string(state), 1241 ${ident}_State_to_string(next_state), 1242 printAddress(addr), GET_TRANSITION_COMMENT()); 1243 1244 CLEAR_TRANSITION_COMMENT(); 1245''') 1246 if self.TBEType != None and self.EntryType != None: 1247 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1248 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1249 elif self.TBEType != None: 1250 code('setState(m_tbe_ptr, addr, next_state);') 1251 code('setAccessPermission(addr, next_state);') 1252 elif self.EntryType != None: 1253 code('setState(m_cache_entry_ptr, addr, next_state);') 1254 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1255 else: 1256 code('setState(addr, next_state);') 1257 code('setAccessPermission(addr, next_state);') 1258 1259 code(''' 1260} else if (result == TransitionResult_ResourceStall) { 1261 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1262 curTick(), m_version, "${ident}", 1263 ${ident}_Event_to_string(event), 1264 ${ident}_State_to_string(state), 1265 ${ident}_State_to_string(next_state), 1266 printAddress(addr), "Resource Stall"); 1267} else if (result == TransitionResult_ProtocolStall) { 1268 DPRINTF(RubyGenerated, "stalling\\n"); 1269 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1270 curTick(), m_version, "${ident}", 1271 ${ident}_Event_to_string(event), 1272 ${ident}_State_to_string(state), 1273 ${ident}_State_to_string(next_state), 1274 printAddress(addr), "Protocol Stall"); 1275} 1276 1277return result; 1278''') 1279 code.dedent() 1280 code(''' 1281} 1282 1283TransitionResult 1284${ident}_Controller::doTransitionWorker(${ident}_Event event, 1285 ${ident}_State state, 1286 ${ident}_State& next_state, 1287''') 1288 1289 if self.TBEType != None: 1290 code(''' 1291 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1292''') 1293 if self.EntryType != None: 1294 code(''' 1295 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1296''') 1297 code(''' 1298 Addr addr) 1299{ 1300 switch(HASH_FUN(state, event)) { 1301''') 1302 1303 # This map will allow suppress generating duplicate code 1304 cases = orderdict() 1305 1306 for trans in self.transitions: 1307 case_string = "%s_State_%s, %s_Event_%s" % \ 1308 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1309 1310 case = self.symtab.codeFormatter() 1311 # Only set next_state if it changes 1312 if trans.state != trans.nextState: 1313 if trans.nextState.isWildcard(): 1314 # When * is encountered as an end state of a transition, 1315 # the next state is determined by calling the 1316 # machine-specific getNextState function. The next state 1317 # is determined before any actions of the transition 1318 # execute, and therefore the next state calculation cannot 1319 # depend on any of the transitionactions. 1320 case('next_state = getNextState(addr);') 1321 else: 1322 ns_ident = trans.nextState.ident 1323 case('next_state = ${ident}_State_${ns_ident};') 1324 1325 actions = trans.actions 1326 request_types = trans.request_types 1327 1328 # Check for resources 1329 case_sorter = [] 1330 res = trans.resources 1331 for key,val in res.iteritems(): 1332 val = ''' 1333if (!%s.areNSlotsAvailable(%s, clockEdge())) 1334 return TransitionResult_ResourceStall; 1335''' % (key.code, val) 1336 case_sorter.append(val) 1337 1338 # Check all of the request_types for resource constraints 1339 for request_type in request_types: 1340 val = ''' 1341if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1342 return TransitionResult_ResourceStall; 1343} 1344''' % (self.ident, request_type.ident) 1345 case_sorter.append(val) 1346 1347 # Emit the code sequences in a sorted order. This makes the 1348 # output deterministic (without this the output order can vary 1349 # since Map's keys() on a vector of pointers is not deterministic 1350 for c in sorted(case_sorter): 1351 case("$c") 1352 1353 # Record access types for this transition 1354 for request_type in request_types: 1355 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1356 1357 # Figure out if we stall 1358 stall = False 1359 for action in actions: 1360 if action.ident == "z_stall": 1361 stall = True 1362 break 1363 1364 if stall: 1365 case('return TransitionResult_ProtocolStall;') 1366 else: 1367 if self.TBEType != None and self.EntryType != None: 1368 for action in actions: 1369 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1370 elif self.TBEType != None: 1371 for action in actions: 1372 case('${{action.ident}}(m_tbe_ptr, addr);') 1373 elif self.EntryType != None: 1374 for action in actions: 1375 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1376 else: 1377 for action in actions: 1378 case('${{action.ident}}(addr);') 1379 case('return TransitionResult_Valid;') 1380 1381 case = str(case) 1382 1383 # Look to see if this transition code is unique. 1384 if case not in cases: 1385 cases[case] = [] 1386 1387 cases[case].append(case_string) 1388 1389 # Walk through all of the unique code blocks and spit out the 1390 # corresponding case statement elements 1391 for case,transitions in cases.iteritems(): 1392 # Iterative over all the multiple transitions that share 1393 # the same code 1394 for trans in transitions: 1395 code(' case HASH_FUN($trans):') 1396 code(' $case\n') 1397 1398 code(''' 1399 default: 1400 panic("Invalid transition\\n" 1401 "%s time: %d addr: %s event: %s state: %s\\n", 1402 name(), curCycle(), addr, event, state); 1403 } 1404 1405 return TransitionResult_Valid; 1406} 1407''') 1408 code.write(path, "%s_Transitions.cc" % self.ident) 1409 1410 1411 # ************************** 1412 # ******* HTML Files ******* 1413 # ************************** 1414 def frameRef(self, click_href, click_target, over_href, over_num, text): 1415 code = self.symtab.codeFormatter(fix_newlines=False) 1416 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1417 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1418 parent.frames[$over_num].location='$over_href' 1419 }\"> 1420 ${{html.formatShorthand(text)}} 1421 </A>""") 1422 return str(code) 1423 1424 def writeHTMLFiles(self, path): 1425 # Create table with no row hilighted 1426 self.printHTMLTransitions(path, None) 1427 1428 # Generate transition tables 1429 for state in self.states.itervalues(): 1430 self.printHTMLTransitions(path, state) 1431 1432 # Generate action descriptions 1433 for action in self.actions.itervalues(): 1434 name = "%s_action_%s.html" % (self.ident, action.ident) 1435 code = html.createSymbol(action, "Action") 1436 code.write(path, name) 1437 1438 # Generate state descriptions 1439 for state in self.states.itervalues(): 1440 name = "%s_State_%s.html" % (self.ident, state.ident) 1441 code = html.createSymbol(state, "State") 1442 code.write(path, name) 1443 1444 # Generate event descriptions 1445 for event in self.events.itervalues(): 1446 name = "%s_Event_%s.html" % (self.ident, event.ident) 1447 code = html.createSymbol(event, "Event") 1448 code.write(path, name) 1449 1450 def printHTMLTransitions(self, path, active_state): 1451 code = self.symtab.codeFormatter() 1452 1453 code(''' 1454<HTML> 1455<BODY link="blue" vlink="blue"> 1456 1457<H1 align="center">${{html.formatShorthand(self.short)}}: 1458''') 1459 code.indent() 1460 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1461 mid = machine.ident 1462 if i != 0: 1463 extra = " - " 1464 else: 1465 extra = "" 1466 if machine == self: 1467 code('$extra$mid') 1468 else: 1469 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1470 code.dedent() 1471 1472 code(""" 1473</H1> 1474 1475<TABLE border=1> 1476<TR> 1477 <TH> </TH> 1478""") 1479 1480 for event in self.events.itervalues(): 1481 href = "%s_Event_%s.html" % (self.ident, event.ident) 1482 ref = self.frameRef(href, "Status", href, "1", event.short) 1483 code('<TH bgcolor=white>$ref</TH>') 1484 1485 code('</TR>') 1486 # -- Body of table 1487 for state in self.states.itervalues(): 1488 # -- Each row 1489 if state == active_state: 1490 color = "yellow" 1491 else: 1492 color = "white" 1493 1494 click = "%s_table_%s.html" % (self.ident, state.ident) 1495 over = "%s_State_%s.html" % (self.ident, state.ident) 1496 text = html.formatShorthand(state.short) 1497 ref = self.frameRef(click, "Table", over, "1", state.short) 1498 code(''' 1499<TR> 1500 <TH bgcolor=$color>$ref</TH> 1501''') 1502 1503 # -- One column for each event 1504 for event in self.events.itervalues(): 1505 trans = self.table.get((state,event), None) 1506 if trans is None: 1507 # This is the no transition case 1508 if state == active_state: 1509 color = "#C0C000" 1510 else: 1511 color = "lightgrey" 1512 1513 code('<TD bgcolor=$color> </TD>') 1514 continue 1515 1516 next = trans.nextState 1517 stall_action = False 1518 1519 # -- Get the actions 1520 for action in trans.actions: 1521 if action.ident == "z_stall" or \ 1522 action.ident == "zz_recycleMandatoryQueue": 1523 stall_action = True 1524 1525 # -- Print out "actions/next-state" 1526 if stall_action: 1527 if state == active_state: 1528 color = "#C0C000" 1529 else: 1530 color = "lightgrey" 1531 1532 elif active_state and next.ident == active_state.ident: 1533 color = "aqua" 1534 elif state == active_state: 1535 color = "yellow" 1536 else: 1537 color = "white" 1538 1539 code('<TD bgcolor=$color>') 1540 for action in trans.actions: 1541 href = "%s_action_%s.html" % (self.ident, action.ident) 1542 ref = self.frameRef(href, "Status", href, "1", 1543 action.short) 1544 code(' $ref') 1545 if next != state: 1546 if trans.actions: 1547 code('/') 1548 click = "%s_table_%s.html" % (self.ident, next.ident) 1549 over = "%s_State_%s.html" % (self.ident, next.ident) 1550 ref = self.frameRef(click, "Table", over, "1", next.short) 1551 code("$ref") 1552 code("</TD>") 1553 1554 # -- Each row 1555 if state == active_state: 1556 color = "yellow" 1557 else: 1558 color = "white" 1559 1560 click = "%s_table_%s.html" % (self.ident, state.ident) 1561 over = "%s_State_%s.html" % (self.ident, state.ident) 1562 ref = self.frameRef(click, "Table", over, "1", state.short) 1563 code(''' 1564 <TH bgcolor=$color>$ref</TH> 1565</TR> 1566''') 1567 code(''' 1568<!- Column footer-> 1569<TR> 1570 <TH> </TH> 1571''') 1572 1573 for event in self.events.itervalues(): 1574 href = "%s_Event_%s.html" % (self.ident, event.ident) 1575 ref = self.frameRef(href, "Status", href, "1", event.short) 1576 code('<TH bgcolor=white>$ref</TH>') 1577 code(''' 1578</TR> 1579</TABLE> 1580</BODY></HTML> 1581''') 1582 1583 1584 if active_state: 1585 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1586 else: 1587 name = "%s_table.html" % self.ident 1588 code.write(path, name) 1589 1590__all__ = [ "StateMachine" ] 1591