1# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
2# Copyright (c) 2009 The Hewlett-Packard Development Company
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met: redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer;
9# redistributions in binary form must reproduce the above copyright
10# notice, this list of conditions and the following disclaimer in the
11# documentation and/or other materials provided with the distribution;
12# neither the name of the copyright holders nor the names of its
13# contributors may be used to endorse or promote products derived from
14# this software without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28from m5.util import orderdict
29
30from slicc.symbols.Symbol import Symbol
31from slicc.symbols.Var import Var
32import slicc.generate.html as html
33import re
34
35python_class_map = {
36 "int": "Int",
37 "uint32_t" : "UInt32",
38 "std::string": "String",
39 "bool": "Bool",
40 "CacheMemory": "RubyCache",
41 "WireBuffer": "RubyWireBuffer",
42 "Sequencer": "RubySequencer",
43 "DirectoryMemory": "RubyDirectoryMemory",
44 "MemoryControl": "MemoryControl",
45 "DMASequencer": "DMASequencer",
46 "Prefetcher":"Prefetcher",
47 "Cycles":"Cycles",
48 }
49
50class StateMachine(Symbol):
51 def __init__(self, symtab, ident, location, pairs, config_parameters):
52 super(StateMachine, self).__init__(symtab, ident, location, pairs)
53 self.table = None
54 self.config_parameters = config_parameters
55 self.prefetchers = []
56
57 for param in config_parameters:
58 if param.pointer:
59 var = Var(symtab, param.name, location, param.type_ast.type,
60 "(*m_%s_ptr)" % param.name, {}, self)
61 else:
62 var = Var(symtab, param.name, location, param.type_ast.type,
63 "m_%s" % param.name, {}, self)
64 self.symtab.registerSym(param.name, var)
65 if str(param.type_ast.type) == "Prefetcher":
66 self.prefetchers.append(var)
67
68 self.states = orderdict()
69 self.events = orderdict()
70 self.actions = orderdict()
71 self.request_types = orderdict()
72 self.transitions = []
73 self.in_ports = []
74 self.functions = []
75 self.objects = []
76 self.TBEType = None
77 self.EntryType = None
78
79 def __repr__(self):
80 return "[StateMachine: %s]" % self.ident
81
82 def addState(self, state):
83 assert self.table is None
84 self.states[state.ident] = state
85
86 def addEvent(self, event):
87 assert self.table is None
88 self.events[event.ident] = event
89
90 def addAction(self, action):
91 assert self.table is None
92
93 # Check for duplicate action
94 for other in self.actions.itervalues():
95 if action.ident == other.ident:
96 action.warning("Duplicate action definition: %s" % action.ident)
97 action.error("Duplicate action definition: %s" % action.ident)
98 if action.short == other.short:
99 other.warning("Duplicate action shorthand: %s" % other.ident)
100 other.warning(" shorthand = %s" % other.short)
101 action.warning("Duplicate action shorthand: %s" % action.ident)
102 action.error(" shorthand = %s" % action.short)
103
104 self.actions[action.ident] = action
105
106 def addRequestType(self, request_type):
107 assert self.table is None
108 self.request_types[request_type.ident] = request_type
109
110 def addTransition(self, trans):
111 assert self.table is None
112 self.transitions.append(trans)
113
114 def addInPort(self, var):
115 self.in_ports.append(var)
116
117 def addFunc(self, func):
118 # register func in the symbol table
119 self.symtab.registerSym(str(func), func)
120 self.functions.append(func)
121
122 def addObject(self, obj):
123 self.objects.append(obj)
124
125 def addType(self, type):
126 type_ident = '%s' % type.c_ident
127
128 if type_ident == "%s_TBE" %self.ident:
129 if self.TBEType != None:
130 self.error("Multiple Transaction Buffer types in a " \
131 "single machine.");
132 self.TBEType = type
133
134 elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
135 if self.EntryType != None:
136 self.error("Multiple AbstractCacheEntry types in a " \
137 "single machine.");
138 self.EntryType = type
139
140 # Needs to be called before accessing the table
141 def buildTable(self):
142 assert self.table is None
143
144 table = {}
145
146 for trans in self.transitions:
147 # Track which actions we touch so we know if we use them
148 # all -- really this should be done for all symbols as
149 # part of the symbol table, then only trigger it for
150 # Actions, States, Events, etc.
151
152 for action in trans.actions:
153 action.used = True
154
155 index = (trans.state, trans.event)
156 if index in table:
157 table[index].warning("Duplicate transition: %s" % table[index])
158 trans.error("Duplicate transition: %s" % trans)
159 table[index] = trans
160
161 # Look at all actions to make sure we used them all
162 for action in self.actions.itervalues():
163 if not action.used:
164 error_msg = "Unused action: %s" % action.ident
165 if "desc" in action:
166 error_msg += ", " + action.desc
167 action.warning(error_msg)
168 self.table = table
169
170 def writeCodeFiles(self, path, includes):
171 self.printControllerPython(path)
172 self.printControllerHH(path)
173 self.printControllerCC(path, includes)
174 self.printCSwitch(path)
175 self.printCWakeup(path, includes)
176 self.printProfilerCC(path)
177 self.printProfilerHH(path)
178 self.printProfileDumperCC(path)
179 self.printProfileDumperHH(path)
176
177 def printControllerPython(self, path):
178 code = self.symtab.codeFormatter()
179 ident = self.ident
180 py_ident = "%s_Controller" % ident
181 c_ident = "%s_Controller" % self.ident
182 code('''
183from m5.params import *
184from m5.SimObject import SimObject
185from Controller import RubyController
186
187class $py_ident(RubyController):
188 type = '$py_ident'
189 cxx_header = 'mem/protocol/${c_ident}.hh'
190''')
191 code.indent()
192 for param in self.config_parameters:
193 dflt_str = ''
194 if param.default is not None:
195 dflt_str = str(param.default) + ', '
196 if python_class_map.has_key(param.type_ast.type.c_ident):
197 python_type = python_class_map[param.type_ast.type.c_ident]
198 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
199 else:
200 self.error("Unknown c++ to python class conversion for c++ " \
201 "type: '%s'. Please update the python_class_map " \
202 "in StateMachine.py", param.type_ast.type.c_ident)
203 code.dedent()
204 code.write(path, '%s.py' % py_ident)
205
206
207 def printControllerHH(self, path):
208 '''Output the method declarations for the class declaration'''
209 code = self.symtab.codeFormatter()
210 ident = self.ident
211 c_ident = "%s_Controller" % self.ident
212
213 code('''
214/** \\file $c_ident.hh
215 *
216 * Auto generated C++ code started by $__file__:$__line__
217 * Created by slicc definition of Module "${{self.short}}"
218 */
219
220#ifndef __${ident}_CONTROLLER_HH__
221#define __${ident}_CONTROLLER_HH__
222
223#include <iostream>
224#include <sstream>
225#include <string>
226
231#include "mem/protocol/${ident}_ProfileDumper.hh"
232#include "mem/protocol/${ident}_Profiler.hh"
227#include "mem/protocol/TransitionResult.hh"
228#include "mem/protocol/Types.hh"
229#include "mem/ruby/common/Consumer.hh"
230#include "mem/ruby/common/Global.hh"
231#include "mem/ruby/slicc_interface/AbstractController.hh"
232#include "params/$c_ident.hh"
233''')
234
235 seen_types = set()
236 has_peer = False
237 for var in self.objects:
238 if var.type.ident not in seen_types and not var.type.isPrimitive:
239 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
240 if "network" in var and "physical_network" in var:
241 has_peer = True
242 seen_types.add(var.type.ident)
243
244 # for adding information to the protocol debug trace
245 code('''
246extern std::stringstream ${ident}_transitionComment;
247
248class $c_ident : public AbstractController
249{
250 public:
251 typedef ${c_ident}Params Params;
252 $c_ident(const Params *p);
253 static int getNumControllers();
254 void init();
255 MessageBuffer* getMandatoryQueue() const;
256 const int & getVersion() const;
257 const std::string toString() const;
258 const std::string getName() const;
259 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
260
261 void print(std::ostream& out) const;
262 void wakeup();
263 void printStats(std::ostream& out) const;
264 void clearStats();
265 void regStats();
266 void collateStats();
267
268 void blockOnQueue(Address addr, MessageBuffer* port);
269 void unblock(Address addr);
270 void recordCacheTrace(int cntrl, CacheRecorder* tr);
271 Sequencer* getSequencer() const;
272
273 bool functionalReadBuffers(PacketPtr&);
274 uint32_t functionalWriteBuffers(PacketPtr&);
275
276 void countTransition(${ident}_State state, ${ident}_Event event);
277 void possibleTransition(${ident}_State state, ${ident}_Event event);
278 uint64 getEventCount(${ident}_Event event);
279 bool isPossible(${ident}_State state, ${ident}_Event event);
280 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
281
282private:
283''')
284
285 code.indent()
286 # added by SS
287 for param in self.config_parameters:
288 if param.pointer:
289 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
290 else:
291 code('${{param.type_ast.type}} m_${{param.ident}};')
292
293 code('''
294TransitionResult doTransition(${ident}_Event event,
295''')
296
297 if self.EntryType != None:
298 code('''
299 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
300''')
301 if self.TBEType != None:
302 code('''
303 ${{self.TBEType.c_ident}}* m_tbe_ptr,
304''')
305
306 code('''
307 const Address& addr);
308
309TransitionResult doTransitionWorker(${ident}_Event event,
310 ${ident}_State state,
311 ${ident}_State& next_state,
312''')
313
314 if self.TBEType != None:
315 code('''
316 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
317''')
318 if self.EntryType != None:
319 code('''
320 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
321''')
322
323 code('''
324 const Address& addr);
325
322static ${ident}_ProfileDumper s_profileDumper;
323${ident}_Profiler m_profiler;
326int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
327int m_event_counters[${ident}_Event_NUM];
328bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
329
330static std::vector<Stats::Vector *> eventVec;
331static std::vector<std::vector<Stats::Vector *> > transVec;
332static int m_num_controllers;
333
334// Internal functions
335''')
336
337 for func in self.functions:
338 proto = func.prototype
339 if proto:
340 code('$proto')
341
342 if has_peer:
343 code('void getQueuesFromPeer(AbstractController *);')
344 if self.EntryType != None:
345 code('''
346
347// Set and Reset for cache_entry variable
348void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
349void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
350''')
351
352 if self.TBEType != None:
353 code('''
354
355// Set and Reset for tbe variable
356void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
357void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
358''')
359
360 code('''
361
362// Actions
363''')
364 if self.TBEType != None and self.EntryType != None:
365 for action in self.actions.itervalues():
366 code('/** \\brief ${{action.desc}} */')
367 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
368 elif self.TBEType != None:
369 for action in self.actions.itervalues():
370 code('/** \\brief ${{action.desc}} */')
371 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
372 elif self.EntryType != None:
373 for action in self.actions.itervalues():
374 code('/** \\brief ${{action.desc}} */')
375 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
376 else:
377 for action in self.actions.itervalues():
378 code('/** \\brief ${{action.desc}} */')
379 code('void ${{action.ident}}(const Address& addr);')
380
381 # the controller internal variables
382 code('''
383
384// Objects
385''')
386 for var in self.objects:
387 th = var.get("template", "")
388 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
389
390 code.dedent()
391 code('};')
392 code('#endif // __${ident}_CONTROLLER_H__')
393 code.write(path, '%s.hh' % c_ident)
394
395 def printControllerCC(self, path, includes):
396 '''Output the actions for performing the actions'''
397
398 code = self.symtab.codeFormatter()
399 ident = self.ident
400 c_ident = "%s_Controller" % self.ident
401 has_peer = False
402
403 code('''
404/** \\file $c_ident.cc
405 *
406 * Auto generated C++ code started by $__file__:$__line__
407 * Created by slicc definition of Module "${{self.short}}"
408 */
409
410#include <sys/types.h>
411#include <unistd.h>
412
413#include <cassert>
414#include <sstream>
415#include <string>
416
417#include "base/compiler.hh"
418#include "base/cprintf.hh"
419#include "debug/RubyGenerated.hh"
420#include "debug/RubySlicc.hh"
421#include "mem/protocol/${ident}_Controller.hh"
422#include "mem/protocol/${ident}_Event.hh"
423#include "mem/protocol/${ident}_State.hh"
424#include "mem/protocol/Types.hh"
425#include "mem/ruby/common/Global.hh"
426#include "mem/ruby/system/System.hh"
427''')
428 for include_path in includes:
429 code('#include "${{include_path}}"')
430
431 code('''
432
433using namespace std;
434''')
435
436 # include object classes
437 seen_types = set()
438 for var in self.objects:
439 if var.type.ident not in seen_types and not var.type.isPrimitive:
440 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
441 seen_types.add(var.type.ident)
442
443 code('''
444$c_ident *
445${c_ident}Params::create()
446{
447 return new $c_ident(this);
448}
449
450int $c_ident::m_num_controllers = 0;
443${ident}_ProfileDumper $c_ident::s_profileDumper;
451std::vector<Stats::Vector *> $c_ident::eventVec;
452std::vector<std::vector<Stats::Vector *> > $c_ident::transVec;
453
454// for adding information to the protocol debug trace
455stringstream ${ident}_transitionComment;
456#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
457
458/** \\brief constructor */
459$c_ident::$c_ident(const Params *p)
460 : AbstractController(p)
461{
462 m_name = "${ident}";
463''')
464 #
465 # max_port_rank is used to size vectors and thus should be one plus the
466 # largest port rank
467 #
468 max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1
469 code(' m_max_in_port_rank = $max_port_rank;')
470 code.indent()
471
472 #
473 # After initializing the universal machine parameters, initialize the
474 # this machines config parameters. Also detemine if these configuration
475 # params include a sequencer. This information will be used later for
476 # contecting the sequencer back to the L1 cache controller.
477 #
478 contains_dma_sequencer = False
479 sequencers = []
480 for param in self.config_parameters:
481 if param.name == "dma_sequencer":
482 contains_dma_sequencer = True
483 elif re.compile("sequencer").search(param.name):
484 sequencers.append(param.name)
485 if param.pointer:
486 code('m_${{param.name}}_ptr = p->${{param.name}};')
487 else:
488 code('m_${{param.name}} = p->${{param.name}};')
489
490 #
491 # For the l1 cache controller, add the special atomic support which
492 # includes passing the sequencer a pointer to the controller.
493 #
494 for seq in sequencers:
495 code('''
496m_${{seq}}_ptr->setController(this);
497 ''')
498
499 #
500 # For the DMA controller, pass the sequencer a pointer to the
501 # controller.
502 #
503 if self.ident == "DMA":
504 if not contains_dma_sequencer:
505 self.error("The DMA controller must include the sequencer " \
506 "configuration parameter")
507
508 code('''
509m_dma_sequencer_ptr->setController(this);
510''')
511
512 code('m_num_controllers++;')
513 for var in self.objects:
514 if var.ident.find("mandatoryQueue") >= 0:
515 code('''
516m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
517m_${{var.c_ident}}_ptr->setReceiver(this);
518''')
519 else:
520 if "network" in var and "physical_network" in var and \
521 var["network"] == "To":
522 has_peer = True
523 code('''
524m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
525peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr;
526m_${{var.c_ident}}_ptr->setSender(this);
527''')
528
529 code('''
530if (p->peer != NULL)
531 connectWithPeer(p->peer);
532
533for (int state = 0; state < ${ident}_State_NUM; state++) {
534 for (int event = 0; event < ${ident}_Event_NUM; event++) {
535 m_possible[state][event] = false;
536 m_counters[state][event] = 0;
537 }
538}
539for (int event = 0; event < ${ident}_Event_NUM; event++) {
540 m_event_counters[event] = 0;
541}
542''')
543 code.dedent()
544 code('''
545}
546
547void
548$c_ident::init()
549{
531 MachineType machine_type;
532 int base;
533 machine_type = string_to_MachineType("${{var.machine.ident}}");
534 base = MachineType_base_number(machine_type);
550 MachineType machine_type = string_to_MachineType("${{var.machine.ident}}");
551 int base = MachineType_base_number(machine_type);
552
553 m_machineID.type = MachineType_${ident};
554 m_machineID.num = m_version;
555
556 // initialize objects
540 m_profiler.setVersion(m_version);
541 s_profileDumper.registerProfiler(&m_profiler);
557
558''')
559
560 code.indent()
561 for var in self.objects:
562 vtype = var.type
563 vid = "m_%s_ptr" % var.c_ident
564 if "network" not in var:
565 # Not a network port object
566 if "primitive" in vtype:
567 code('$vid = new ${{vtype.c_ident}};')
568 if "default" in var:
569 code('(*$vid) = ${{var["default"]}};')
570 else:
571 # Normal Object
572 if var.ident.find("mandatoryQueue") < 0:
573 th = var.get("template", "")
574 expr = "%s = new %s%s" % (vid, vtype.c_ident, th)
575 args = ""
576 if "non_obj" not in vtype and not vtype.isEnumeration:
577 args = var.get("constructor", "")
578 code('$expr($args);')
579
580 code('assert($vid != NULL);')
581
582 if "default" in var:
583 code('*$vid = ${{var["default"]}}; // Object default')
584 elif "default" in vtype:
585 comment = "Type %s default" % vtype.ident
586 code('*$vid = ${{vtype["default"]}}; // $comment')
587
588 # Set ordering
589 if "ordered" in var:
590 # A buffer
591 code('$vid->setOrdering(${{var["ordered"]}});')
592
593 # Set randomization
594 if "random" in var:
595 # A buffer
596 code('$vid->setRandomization(${{var["random"]}});')
597
598 # Set Priority
599 if vtype.isBuffer and "rank" in var:
600 code('$vid->setPriority(${{var["rank"]}});')
601
602 # Set sender and receiver for trigger queue
603 if var.ident.find("triggerQueue") >= 0:
604 code('$vid->setSender(this);')
605 code('$vid->setReceiver(this);')
606 elif vtype.c_ident == "TimerTable":
607 code('$vid->setClockObj(this);')
608 elif var.ident.find("optionalQueue") >= 0:
609 code('$vid->setSender(this);')
610 code('$vid->setReceiver(this);')
611
612 else:
613 # Network port object
614 network = var["network"]
615 ordered = var["ordered"]
616
617 if "virtual_network" in var:
618 vnet = var["virtual_network"]
619 vnet_type = var["vnet_type"]
620
621 assert var.machine is not None
622 code('''
623$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
624assert($vid != NULL);
625''')
626
627 # Set the end
628 if network == "To":
629 code('$vid->setSender(this);')
630 else:
631 code('$vid->setReceiver(this);')
632
633 # Set ordering
634 if "ordered" in var:
635 # A buffer
636 code('$vid->setOrdering(${{var["ordered"]}});')
637
638 # Set randomization
639 if "random" in var:
640 # A buffer
641 code('$vid->setRandomization(${{var["random"]}});')
642
643 # Set Priority
644 if "rank" in var:
645 code('$vid->setPriority(${{var["rank"]}})')
646
647 # Set buffer size
648 if vtype.isBuffer:
649 code('''
650if (m_buffer_size > 0) {
651 $vid->resize(m_buffer_size);
652}
653''')
654
655 # set description (may be overriden later by port def)
656 code('''
657$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
658
659''')
660
661 if vtype.isBuffer:
662 if "recycle_latency" in var:
663 code('$vid->setRecycleLatency( ' \
664 'Cycles(${{var["recycle_latency"]}}));')
665 else:
666 code('$vid->setRecycleLatency(m_recycle_latency);')
667
668 # Set the prefetchers
669 code()
670 for prefetcher in self.prefetchers:
671 code('${{prefetcher.code}}.setController(this);')
672
673 code()
674 for port in self.in_ports:
675 # Set the queue consumers
676 code('${{port.code}}.setConsumer(this);')
677 # Set the queue descriptions
678 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
679
680 # Initialize the transition profiling
681 code()
682 for trans in self.transitions:
683 # Figure out if we stall
684 stall = False
685 for action in trans.actions:
686 if action.ident == "z_stall":
687 stall = True
688
689 # Only possible if it is not a 'z' case
690 if not stall:
691 state = "%s_State_%s" % (self.ident, trans.state.ident)
692 event = "%s_Event_%s" % (self.ident, trans.event.ident)
678 code('m_profiler.possibleTransition($state, $event);')
693 code('possibleTransition($state, $event);')
694
695 code.dedent()
696 code('''
697 AbstractController::init();
698 clearStats();
699}
700''')
701
702 has_mandatory_q = False
703 for port in self.in_ports:
704 if port.code.find("mandatoryQueue_ptr") >= 0:
705 has_mandatory_q = True
706
707 if has_mandatory_q:
708 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
709 else:
710 mq_ident = "NULL"
711
712 seq_ident = "NULL"
713 for param in self.config_parameters:
714 if param.name == "sequencer":
715 assert(param.pointer)
716 seq_ident = "m_%s_ptr" % param.name
717
718 code('''
719
720void
721$c_ident::regStats()
722{
723 if (m_version == 0) {
724 for (${ident}_Event event = ${ident}_Event_FIRST;
725 event < ${ident}_Event_NUM; ++event) {
726 Stats::Vector *t = new Stats::Vector();
727 t->init(m_num_controllers);
728 t->name(name() + "." + ${ident}_Event_to_string(event));
729 t->flags(Stats::pdf | Stats::total | Stats::oneline |
730 Stats::nozero);
731
732 eventVec.push_back(t);
733 }
734
735 for (${ident}_State state = ${ident}_State_FIRST;
736 state < ${ident}_State_NUM; ++state) {
737
738 transVec.push_back(std::vector<Stats::Vector *>());
739
740 for (${ident}_Event event = ${ident}_Event_FIRST;
741 event < ${ident}_Event_NUM; ++event) {
742
743 Stats::Vector *t = new Stats::Vector();
744 t->init(m_num_controllers);
745 t->name(name() + "." + ${ident}_State_to_string(state) +
746 "." + ${ident}_Event_to_string(event));
747
748 t->flags(Stats::pdf | Stats::total | Stats::oneline |
749 Stats::nozero);
750 transVec[state].push_back(t);
751 }
752 }
753 }
754}
755
756void
757$c_ident::collateStats()
758{
759 for (${ident}_Event event = ${ident}_Event_FIRST;
760 event < ${ident}_Event_NUM; ++event) {
761 for (unsigned int i = 0; i < m_num_controllers; ++i) {
762 std::map<uint32_t, AbstractController *>::iterator it =
763 g_abs_controls[MachineType_${ident}].find(i);
764 assert(it != g_abs_controls[MachineType_${ident}].end());
765 (*eventVec[event])[i] =
766 (($c_ident *)(*it).second)->getEventCount(event);
767 }
768 }
769
770 for (${ident}_State state = ${ident}_State_FIRST;
771 state < ${ident}_State_NUM; ++state) {
772
773 for (${ident}_Event event = ${ident}_Event_FIRST;
774 event < ${ident}_Event_NUM; ++event) {
775
776 for (unsigned int i = 0; i < m_num_controllers; ++i) {
777 std::map<uint32_t, AbstractController *>::iterator it =
778 g_abs_controls[MachineType_${ident}].find(i);
779 assert(it != g_abs_controls[MachineType_${ident}].end());
780 (*transVec[state][event])[i] =
781 (($c_ident *)(*it).second)->getTransitionCount(state, event);
782 }
783 }
784 }
785}
786
787void
788$c_ident::countTransition(${ident}_State state, ${ident}_Event event)
789{
790 assert(m_possible[state][event]);
791 m_counters[state][event]++;
792 m_event_counters[event]++;
793}
794void
795$c_ident::possibleTransition(${ident}_State state,
796 ${ident}_Event event)
797{
798 m_possible[state][event] = true;
799}
800
801uint64
802$c_ident::getEventCount(${ident}_Event event)
803{
804 return m_event_counters[event];
805}
806
807bool
808$c_ident::isPossible(${ident}_State state, ${ident}_Event event)
809{
810 return m_possible[state][event];
811}
812
813uint64
814$c_ident::getTransitionCount(${ident}_State state,
815 ${ident}_Event event)
816{
817 return m_counters[state][event];
818}
819
820int
821$c_ident::getNumControllers()
822{
823 return m_num_controllers;
824}
825
826MessageBuffer*
827$c_ident::getMandatoryQueue() const
828{
829 return $mq_ident;
830}
831
832Sequencer*
833$c_ident::getSequencer() const
834{
835 return $seq_ident;
836}
837
838const int &
839$c_ident::getVersion() const
840{
841 return m_version;
842}
843
844const string
845$c_ident::toString() const
846{
847 return "$c_ident";
848}
849
850const string
851$c_ident::getName() const
852{
853 return m_name;
854}
855
856void
857$c_ident::blockOnQueue(Address addr, MessageBuffer* port)
858{
859 m_is_blocking = true;
860 m_block_map[addr] = port;
861}
862
863void
864$c_ident::unblock(Address addr)
865{
866 m_block_map.erase(addr);
867 if (m_block_map.size() == 0) {
868 m_is_blocking = false;
869 }
870}
871
872void
873$c_ident::print(ostream& out) const
874{
875 out << "[$c_ident " << m_version << "]";
876}
877
878void
879$c_ident::printStats(ostream& out) const
880{
881''')
882 #
883 # Cache and Memory Controllers have specific profilers associated with
884 # them. Print out these stats before dumping state transition stats.
885 #
886 for param in self.config_parameters:
771 if param.type_ast.type.ident == "DirectoryMemory" or \
772 param.type_ast.type.ident == "MemoryControl":
887 if param.type_ast.type.ident == "DirectoryMemory":
888 assert(param.pointer)
889 code(' m_${{param.ident}}_ptr->printStats(out);')
890
891 code('''
777 if (m_version == 0) {
778 s_profileDumper.dumpStats(out);
779 }
892}
893
782void $c_ident::clearStats() {
783''')
784 #
785 # Cache and Memory Controllers have specific profilers associated with
786 # them. These stats must be cleared too.
787 #
788 for param in self.config_parameters:
789 if param.type_ast.type.ident == "MemoryControl":
790 assert(param.pointer)
791 code(' m_${{param.ident}}_ptr->clearStats();')
894void $c_ident::clearStats()
895{
896 for (int state = 0; state < ${ident}_State_NUM; state++) {
897 for (int event = 0; event < ${ident}_Event_NUM; event++) {
898 m_counters[state][event] = 0;
899 }
900 }
901
793 code('''
794 m_profiler.clearStats();
902 for (int event = 0; event < ${ident}_Event_NUM; event++) {
903 m_event_counters[event] = 0;
904 }
905
906 AbstractController::clearStats();
907}
908''')
909
910 if self.EntryType != None:
911 code('''
912
913// Set and Reset for cache_entry variable
914void
915$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
916{
917 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
918}
919
920void
921$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
922{
923 m_cache_entry_ptr = 0;
924}
925''')
926
927 if self.TBEType != None:
928 code('''
929
930// Set and Reset for tbe variable
931void
932$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
933{
934 m_tbe_ptr = m_new_tbe;
935}
936
937void
938$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
939{
940 m_tbe_ptr = NULL;
941}
942''')
943
944 code('''
945
946void
947$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
948{
949''')
950 #
951 # Record cache contents for all associated caches.
952 #
953 code.indent()
954 for param in self.config_parameters:
955 if param.type_ast.type.ident == "CacheMemory":
956 assert(param.pointer)
957 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
958
959 code.dedent()
960 code('''
961}
962
963// Actions
964''')
965 if self.TBEType != None and self.EntryType != None:
966 for action in self.actions.itervalues():
967 if "c_code" not in action:
968 continue
969
970 code('''
971/** \\brief ${{action.desc}} */
972void
973$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
974{
975 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
976 ${{action["c_code"]}}
977}
978
979''')
980 elif self.TBEType != None:
981 for action in self.actions.itervalues():
982 if "c_code" not in action:
983 continue
984
985 code('''
986/** \\brief ${{action.desc}} */
987void
988$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
989{
990 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
991 ${{action["c_code"]}}
992}
993
994''')
995 elif self.EntryType != None:
996 for action in self.actions.itervalues():
997 if "c_code" not in action:
998 continue
999
1000 code('''
1001/** \\brief ${{action.desc}} */
1002void
1003$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
1004{
1005 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
1006 ${{action["c_code"]}}
1007}
1008
1009''')
1010 else:
1011 for action in self.actions.itervalues():
1012 if "c_code" not in action:
1013 continue
1014
1015 code('''
1016/** \\brief ${{action.desc}} */
1017void
1018$c_ident::${{action.ident}}(const Address& addr)
1019{
1020 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
1021 ${{action["c_code"]}}
1022}
1023
1024''')
1025 for func in self.functions:
1026 code(func.generateCode())
1027
1028 # Function for functional reads from messages buffered in the controller
1029 code('''
1030bool
1031$c_ident::functionalReadBuffers(PacketPtr& pkt)
1032{
1033''')
1034 for var in self.objects:
1035 vtype = var.type
1036 if vtype.isBuffer:
1037 vid = "m_%s_ptr" % var.c_ident
1038 code('if ($vid->functionalRead(pkt)) { return true; }')
1039 code('''
1040 return false;
1041}
1042''')
1043
1044 # Function for functional writes to messages buffered in the controller
1045 code('''
1046uint32_t
1047$c_ident::functionalWriteBuffers(PacketPtr& pkt)
1048{
1049 uint32_t num_functional_writes = 0;
1050''')
1051 for var in self.objects:
1052 vtype = var.type
1053 if vtype.isBuffer:
1054 vid = "m_%s_ptr" % var.c_ident
1055 code('num_functional_writes += $vid->functionalWrite(pkt);')
1056 code('''
1057 return num_functional_writes;
1058}
1059''')
1060
1061 # Check if this controller has a peer, if yes then write the
1062 # function for connecting to the peer.
1063 if has_peer:
1064 code('''
1065
1066void
1067$c_ident::getQueuesFromPeer(AbstractController *peer)
1068{
1069''')
1070 for var in self.objects:
1071 if "network" in var and "physical_network" in var and \
1072 var["network"] == "From":
1073 code('''
1074m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}});
1075assert(m_${{var.c_ident}}_ptr != NULL);
1076m_${{var.c_ident}}_ptr->setReceiver(this);
1077
1078''')
1079 code('}')
1080
1081 code.write(path, "%s.cc" % c_ident)
1082
1083 def printCWakeup(self, path, includes):
1084 '''Output the wakeup loop for the events'''
1085
1086 code = self.symtab.codeFormatter()
1087 ident = self.ident
1088
1089 outputRequest_types = True
1090 if len(self.request_types) == 0:
1091 outputRequest_types = False
1092
1093 code('''
1094// Auto generated C++ code started by $__file__:$__line__
1095// ${ident}: ${{self.short}}
1096
1097#include <sys/types.h>
1098#include <unistd.h>
1099
1100#include <cassert>
1101
1102#include "base/misc.hh"
1103#include "debug/RubySlicc.hh"
1104#include "mem/protocol/${ident}_Controller.hh"
1105#include "mem/protocol/${ident}_Event.hh"
1106#include "mem/protocol/${ident}_State.hh"
1107''')
1108
1109 if outputRequest_types:
1110 code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1111
1112 code('''
1113#include "mem/protocol/Types.hh"
1114#include "mem/ruby/common/Global.hh"
1115#include "mem/ruby/system/System.hh"
1116''')
1117
1118
1119 for include_path in includes:
1120 code('#include "${{include_path}}"')
1121
1122 code('''
1123
1124using namespace std;
1125
1126void
1127${ident}_Controller::wakeup()
1128{
1129 int counter = 0;
1130 while (true) {
1131 // Some cases will put us into an infinite loop without this limit
1132 assert(counter <= m_transitions_per_cycle);
1133 if (counter == m_transitions_per_cycle) {
1134 // Count how often we are fully utilized
1135 m_fully_busy_cycles++;
1136
1137 // Wakeup in another cycle and try again
1138 scheduleEvent(Cycles(1));
1139 break;
1140 }
1141''')
1142
1143 code.indent()
1144 code.indent()
1145
1146 # InPorts
1147 #
1148 for port in self.in_ports:
1149 code.indent()
1150 code('// ${ident}InPort $port')
1151 if port.pairs.has_key("rank"):
1152 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1153 else:
1154 code('m_cur_in_port_rank = 0;')
1155 code('${{port["c_code_in_port"]}}')
1156 code.dedent()
1157
1158 code('')
1159
1160 code.dedent()
1161 code.dedent()
1162 code('''
1163 break; // If we got this far, we have nothing left todo
1164 }
1165}
1166''')
1167
1168 code.write(path, "%s_Wakeup.cc" % self.ident)
1169
1170 def printCSwitch(self, path):
1171 '''Output switch statement for transition table'''
1172
1173 code = self.symtab.codeFormatter()
1174 ident = self.ident
1175
1176 code('''
1177// Auto generated C++ code started by $__file__:$__line__
1178// ${ident}: ${{self.short}}
1179
1180#include <cassert>
1181
1182#include "base/misc.hh"
1183#include "base/trace.hh"
1184#include "debug/ProtocolTrace.hh"
1185#include "debug/RubyGenerated.hh"
1186#include "mem/protocol/${ident}_Controller.hh"
1187#include "mem/protocol/${ident}_Event.hh"
1188#include "mem/protocol/${ident}_State.hh"
1189#include "mem/protocol/Types.hh"
1190#include "mem/ruby/common/Global.hh"
1191#include "mem/ruby/system/System.hh"
1192
1193#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1194
1195#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1196#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1197
1198TransitionResult
1199${ident}_Controller::doTransition(${ident}_Event event,
1200''')
1201 if self.EntryType != None:
1202 code('''
1203 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1204''')
1205 if self.TBEType != None:
1206 code('''
1207 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1208''')
1209 code('''
1210 const Address &addr)
1211{
1212''')
1213 if self.TBEType != None and self.EntryType != None:
1214 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1215 elif self.TBEType != None:
1216 code('${ident}_State state = getState(m_tbe_ptr, addr);')
1217 elif self.EntryType != None:
1218 code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1219 else:
1220 code('${ident}_State state = getState(addr);')
1221
1222 code('''
1223 ${ident}_State next_state = state;
1224
1225 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1226 *this, curCycle(), ${ident}_State_to_string(state),
1227 ${ident}_Event_to_string(event), addr);
1228
1229 TransitionResult result =
1230''')
1231 if self.TBEType != None and self.EntryType != None:
1232 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1233 elif self.TBEType != None:
1234 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1235 elif self.EntryType != None:
1236 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1237 else:
1238 code('doTransitionWorker(event, state, next_state, addr);')
1239
1240 code('''
1241 if (result == TransitionResult_Valid) {
1242 DPRINTF(RubyGenerated, "next_state: %s\\n",
1243 ${ident}_State_to_string(next_state));
1133 m_profiler.countTransition(state, event);
1244 countTransition(state, event);
1245 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1246 curTick(), m_version, "${ident}",
1247 ${ident}_Event_to_string(event),
1248 ${ident}_State_to_string(state),
1249 ${ident}_State_to_string(next_state),
1250 addr, GET_TRANSITION_COMMENT());
1251
1252 CLEAR_TRANSITION_COMMENT();
1253''')
1254 if self.TBEType != None and self.EntryType != None:
1255 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1256 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1257 elif self.TBEType != None:
1258 code('setState(m_tbe_ptr, addr, next_state);')
1259 code('setAccessPermission(addr, next_state);')
1260 elif self.EntryType != None:
1261 code('setState(m_cache_entry_ptr, addr, next_state);')
1262 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1263 else:
1264 code('setState(addr, next_state);')
1265 code('setAccessPermission(addr, next_state);')
1266
1267 code('''
1268 } else if (result == TransitionResult_ResourceStall) {
1269 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %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 addr, "Resource Stall");
1275 } else if (result == TransitionResult_ProtocolStall) {
1276 DPRINTF(RubyGenerated, "stalling\\n");
1277 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1278 curTick(), m_version, "${ident}",
1279 ${ident}_Event_to_string(event),
1280 ${ident}_State_to_string(state),
1281 ${ident}_State_to_string(next_state),
1282 addr, "Protocol Stall");
1283 }
1284
1285 return result;
1286}
1287
1288TransitionResult
1289${ident}_Controller::doTransitionWorker(${ident}_Event event,
1290 ${ident}_State state,
1291 ${ident}_State& next_state,
1292''')
1293
1294 if self.TBEType != None:
1295 code('''
1296 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1297''')
1298 if self.EntryType != None:
1299 code('''
1300 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1301''')
1302 code('''
1303 const Address& addr)
1304{
1305 switch(HASH_FUN(state, event)) {
1306''')
1307
1308 # This map will allow suppress generating duplicate code
1309 cases = orderdict()
1310
1311 for trans in self.transitions:
1312 case_string = "%s_State_%s, %s_Event_%s" % \
1313 (self.ident, trans.state.ident, self.ident, trans.event.ident)
1314
1315 case = self.symtab.codeFormatter()
1316 # Only set next_state if it changes
1317 if trans.state != trans.nextState:
1318 ns_ident = trans.nextState.ident
1319 case('next_state = ${ident}_State_${ns_ident};')
1320
1321 actions = trans.actions
1322 request_types = trans.request_types
1323
1324 # Check for resources
1325 case_sorter = []
1326 res = trans.resources
1327 for key,val in res.iteritems():
1328 if key.type.ident != "DNUCAStopTable":
1329 val = '''
1330if (!%s.areNSlotsAvailable(%s))
1331 return TransitionResult_ResourceStall;
1332''' % (key.code, val)
1333 case_sorter.append(val)
1334
1335 # Check all of the request_types for resource constraints
1336 for request_type in request_types:
1337 val = '''
1338if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1339 return TransitionResult_ResourceStall;
1340}
1341''' % (self.ident, request_type.ident)
1342 case_sorter.append(val)
1343
1344 # Emit the code sequences in a sorted order. This makes the
1345 # output deterministic (without this the output order can vary
1346 # since Map's keys() on a vector of pointers is not deterministic
1347 for c in sorted(case_sorter):
1348 case("$c")
1349
1350 # Record access types for this transition
1351 for request_type in request_types:
1352 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1353
1354 # Figure out if we stall
1355 stall = False
1356 for action in actions:
1357 if action.ident == "z_stall":
1358 stall = True
1359 break
1360
1361 if stall:
1362 case('return TransitionResult_ProtocolStall;')
1363 else:
1364 if self.TBEType != None and self.EntryType != None:
1365 for action in actions:
1366 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1367 elif self.TBEType != None:
1368 for action in actions:
1369 case('${{action.ident}}(m_tbe_ptr, addr);')
1370 elif self.EntryType != None:
1371 for action in actions:
1372 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1373 else:
1374 for action in actions:
1375 case('${{action.ident}}(addr);')
1376 case('return TransitionResult_Valid;')
1377
1378 case = str(case)
1379
1380 # Look to see if this transition code is unique.
1381 if case not in cases:
1382 cases[case] = []
1383
1384 cases[case].append(case_string)
1385
1386 # Walk through all of the unique code blocks and spit out the
1387 # corresponding case statement elements
1388 for case,transitions in cases.iteritems():
1389 # Iterative over all the multiple transitions that share
1390 # the same code
1391 for trans in transitions:
1392 code(' case HASH_FUN($trans):')
1393 code(' $case')
1394
1395 code('''
1396 default:
1397 fatal("Invalid transition\\n"
1398 "%s time: %d addr: %s event: %s state: %s\\n",
1399 name(), curCycle(), addr, event, state);
1400 }
1401 return TransitionResult_Valid;
1402}
1403''')
1404 code.write(path, "%s_Transitions.cc" % self.ident)
1405
1295 def printProfileDumperHH(self, path):
1296 code = self.symtab.codeFormatter()
1297 ident = self.ident
1406
1299 code('''
1300// Auto generated C++ code started by $__file__:$__line__
1301// ${ident}: ${{self.short}}
1302
1303#ifndef __${ident}_PROFILE_DUMPER_HH__
1304#define __${ident}_PROFILE_DUMPER_HH__
1305
1306#include <cassert>
1307#include <iostream>
1308#include <vector>
1309
1310#include "${ident}_Event.hh"
1311#include "${ident}_Profiler.hh"
1312
1313typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1314
1315class ${ident}_ProfileDumper
1316{
1317 public:
1318 ${ident}_ProfileDumper();
1319 void registerProfiler(${ident}_Profiler* profiler);
1320 void dumpStats(std::ostream& out) const;
1321
1322 private:
1323 ${ident}_profilers m_profilers;
1324};
1325
1326#endif // __${ident}_PROFILE_DUMPER_HH__
1327''')
1328 code.write(path, "%s_ProfileDumper.hh" % self.ident)
1329
1330 def printProfileDumperCC(self, path):
1331 code = self.symtab.codeFormatter()
1332 ident = self.ident
1333
1334 code('''
1335// Auto generated C++ code started by $__file__:$__line__
1336// ${ident}: ${{self.short}}
1337
1338#include "mem/protocol/${ident}_ProfileDumper.hh"
1339
1340${ident}_ProfileDumper::${ident}_ProfileDumper()
1341{
1342}
1343
1344void
1345${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1346{
1347 if (profiler->getVersion() >= m_profilers.size())
1348 m_profilers.resize(profiler->getVersion() + 1);
1349 m_profilers[profiler->getVersion()] = profiler;
1350}
1351
1352void
1353${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1354{
1355 out << " --- ${ident} ---\\n";
1356 out << " - Event Counts -\\n";
1357 for (${ident}_Event event = ${ident}_Event_FIRST;
1358 event < ${ident}_Event_NUM;
1359 ++event) {
1360 out << (${ident}_Event) event << " [";
1361 uint64 total = 0;
1362 for (int i = 0; i < m_profilers.size(); i++) {
1363 out << m_profilers[i]->getEventCount(event) << " ";
1364 total += m_profilers[i]->getEventCount(event);
1365 }
1366 out << "] " << total << "\\n";
1367 }
1368 out << "\\n";
1369 out << " - Transitions -\\n";
1370 for (${ident}_State state = ${ident}_State_FIRST;
1371 state < ${ident}_State_NUM;
1372 ++state) {
1373 for (${ident}_Event event = ${ident}_Event_FIRST;
1374 event < ${ident}_Event_NUM;
1375 ++event) {
1376 if (m_profilers[0]->isPossible(state, event)) {
1377 out << (${ident}_State) state << " "
1378 << (${ident}_Event) event << " [";
1379 uint64 total = 0;
1380 for (int i = 0; i < m_profilers.size(); i++) {
1381 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1382 total += m_profilers[i]->getTransitionCount(state, event);
1383 }
1384 out << "] " << total << "\\n";
1385 }
1386 }
1387 out << "\\n";
1388 }
1389}
1390''')
1391 code.write(path, "%s_ProfileDumper.cc" % self.ident)
1392
1393 def printProfilerHH(self, path):
1394 code = self.symtab.codeFormatter()
1395 ident = self.ident
1396
1397 code('''
1398// Auto generated C++ code started by $__file__:$__line__
1399// ${ident}: ${{self.short}}
1400
1401#ifndef __${ident}_PROFILER_HH__
1402#define __${ident}_PROFILER_HH__
1403
1404#include <cassert>
1405#include <iostream>
1406
1407#include "mem/protocol/${ident}_Event.hh"
1408#include "mem/protocol/${ident}_State.hh"
1409#include "mem/ruby/common/TypeDefines.hh"
1410
1411class ${ident}_Profiler
1412{
1413 public:
1414 ${ident}_Profiler();
1415 void setVersion(int version);
1416 int getVersion();
1417 void countTransition(${ident}_State state, ${ident}_Event event);
1418 void possibleTransition(${ident}_State state, ${ident}_Event event);
1419 uint64 getEventCount(${ident}_Event event);
1420 bool isPossible(${ident}_State state, ${ident}_Event event);
1421 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1422 void clearStats();
1423
1424 private:
1425 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1426 int m_event_counters[${ident}_Event_NUM];
1427 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1428 int m_version;
1429};
1430
1431#endif // __${ident}_PROFILER_HH__
1432''')
1433 code.write(path, "%s_Profiler.hh" % self.ident)
1434
1435 def printProfilerCC(self, path):
1436 code = self.symtab.codeFormatter()
1437 ident = self.ident
1438
1439 code('''
1440// Auto generated C++ code started by $__file__:$__line__
1441// ${ident}: ${{self.short}}
1442
1443#include <cassert>
1444
1445#include "mem/protocol/${ident}_Profiler.hh"
1446
1447${ident}_Profiler::${ident}_Profiler()
1448{
1449 for (int state = 0; state < ${ident}_State_NUM; state++) {
1450 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1451 m_possible[state][event] = false;
1452 m_counters[state][event] = 0;
1453 }
1454 }
1455 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1456 m_event_counters[event] = 0;
1457 }
1458}
1459
1460void
1461${ident}_Profiler::setVersion(int version)
1462{
1463 m_version = version;
1464}
1465
1466int
1467${ident}_Profiler::getVersion()
1468{
1469 return m_version;
1470}
1471
1472void
1473${ident}_Profiler::clearStats()
1474{
1475 for (int state = 0; state < ${ident}_State_NUM; state++) {
1476 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1477 m_counters[state][event] = 0;
1478 }
1479 }
1480
1481 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1482 m_event_counters[event] = 0;
1483 }
1484}
1485void
1486${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1487{
1488 assert(m_possible[state][event]);
1489 m_counters[state][event]++;
1490 m_event_counters[event]++;
1491}
1492void
1493${ident}_Profiler::possibleTransition(${ident}_State state,
1494 ${ident}_Event event)
1495{
1496 m_possible[state][event] = true;
1497}
1498
1499uint64
1500${ident}_Profiler::getEventCount(${ident}_Event event)
1501{
1502 return m_event_counters[event];
1503}
1504
1505bool
1506${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1507{
1508 return m_possible[state][event];
1509}
1510
1511uint64
1512${ident}_Profiler::getTransitionCount(${ident}_State state,
1513 ${ident}_Event event)
1514{
1515 return m_counters[state][event];
1516}
1517
1518''')
1519 code.write(path, "%s_Profiler.cc" % self.ident)
1520
1407 # **************************
1408 # ******* HTML Files *******
1409 # **************************
1410 def frameRef(self, click_href, click_target, over_href, over_num, text):
1411 code = self.symtab.codeFormatter(fix_newlines=False)
1412 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1413 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1414 parent.frames[$over_num].location='$over_href'
1415 }\">
1416 ${{html.formatShorthand(text)}}
1417 </A>""")
1418 return str(code)
1419
1420 def writeHTMLFiles(self, path):
1421 # Create table with no row hilighted
1422 self.printHTMLTransitions(path, None)
1423
1424 # Generate transition tables
1425 for state in self.states.itervalues():
1426 self.printHTMLTransitions(path, state)
1427
1428 # Generate action descriptions
1429 for action in self.actions.itervalues():
1430 name = "%s_action_%s.html" % (self.ident, action.ident)
1431 code = html.createSymbol(action, "Action")
1432 code.write(path, name)
1433
1434 # Generate state descriptions
1435 for state in self.states.itervalues():
1436 name = "%s_State_%s.html" % (self.ident, state.ident)
1437 code = html.createSymbol(state, "State")
1438 code.write(path, name)
1439
1440 # Generate event descriptions
1441 for event in self.events.itervalues():
1442 name = "%s_Event_%s.html" % (self.ident, event.ident)
1443 code = html.createSymbol(event, "Event")
1444 code.write(path, name)
1445
1446 def printHTMLTransitions(self, path, active_state):
1447 code = self.symtab.codeFormatter()
1448
1449 code('''
1450<HTML>
1451<BODY link="blue" vlink="blue">
1452
1453<H1 align="center">${{html.formatShorthand(self.short)}}:
1454''')
1455 code.indent()
1456 for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1457 mid = machine.ident
1458 if i != 0:
1459 extra = " - "
1460 else:
1461 extra = ""
1462 if machine == self:
1463 code('$extra$mid')
1464 else:
1465 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1466 code.dedent()
1467
1468 code("""
1469</H1>
1470
1471<TABLE border=1>
1472<TR>
1473 <TH> </TH>
1474""")
1475
1476 for event in self.events.itervalues():
1477 href = "%s_Event_%s.html" % (self.ident, event.ident)
1478 ref = self.frameRef(href, "Status", href, "1", event.short)
1479 code('<TH bgcolor=white>$ref</TH>')
1480
1481 code('</TR>')
1482 # -- Body of table
1483 for state in self.states.itervalues():
1484 # -- Each row
1485 if state == active_state:
1486 color = "yellow"
1487 else:
1488 color = "white"
1489
1490 click = "%s_table_%s.html" % (self.ident, state.ident)
1491 over = "%s_State_%s.html" % (self.ident, state.ident)
1492 text = html.formatShorthand(state.short)
1493 ref = self.frameRef(click, "Table", over, "1", state.short)
1494 code('''
1495<TR>
1496 <TH bgcolor=$color>$ref</TH>
1497''')
1498
1499 # -- One column for each event
1500 for event in self.events.itervalues():
1501 trans = self.table.get((state,event), None)
1502 if trans is None:
1503 # This is the no transition case
1504 if state == active_state:
1505 color = "#C0C000"
1506 else:
1507 color = "lightgrey"
1508
1509 code('<TD bgcolor=$color>&nbsp;</TD>')
1510 continue
1511
1512 next = trans.nextState
1513 stall_action = False
1514
1515 # -- Get the actions
1516 for action in trans.actions:
1517 if action.ident == "z_stall" or \
1518 action.ident == "zz_recycleMandatoryQueue":
1519 stall_action = True
1520
1521 # -- Print out "actions/next-state"
1522 if stall_action:
1523 if state == active_state:
1524 color = "#C0C000"
1525 else:
1526 color = "lightgrey"
1527
1528 elif active_state and next.ident == active_state.ident:
1529 color = "aqua"
1530 elif state == active_state:
1531 color = "yellow"
1532 else:
1533 color = "white"
1534
1535 code('<TD bgcolor=$color>')
1536 for action in trans.actions:
1537 href = "%s_action_%s.html" % (self.ident, action.ident)
1538 ref = self.frameRef(href, "Status", href, "1",
1539 action.short)
1540 code(' $ref')
1541 if next != state:
1542 if trans.actions:
1543 code('/')
1544 click = "%s_table_%s.html" % (self.ident, next.ident)
1545 over = "%s_State_%s.html" % (self.ident, next.ident)
1546 ref = self.frameRef(click, "Table", over, "1", next.short)
1547 code("$ref")
1548 code("</TD>")
1549
1550 # -- Each row
1551 if state == active_state:
1552 color = "yellow"
1553 else:
1554 color = "white"
1555
1556 click = "%s_table_%s.html" % (self.ident, state.ident)
1557 over = "%s_State_%s.html" % (self.ident, state.ident)
1558 ref = self.frameRef(click, "Table", over, "1", state.short)
1559 code('''
1560 <TH bgcolor=$color>$ref</TH>
1561</TR>
1562''')
1563 code('''
1564<!- Column footer->
1565<TR>
1566 <TH> </TH>
1567''')
1568
1569 for event in self.events.itervalues():
1570 href = "%s_Event_%s.html" % (self.ident, event.ident)
1571 ref = self.frameRef(href, "Status", href, "1", event.short)
1572 code('<TH bgcolor=white>$ref</TH>')
1573 code('''
1574</TR>
1575</TABLE>
1576</BODY></HTML>
1577''')
1578
1579
1580 if active_state:
1581 name = "%s_table_%s.html" % (self.ident, active_state.ident)
1582 else:
1583 name = "%s_table.html" % self.ident
1584 code.write(path, name)
1585
1586__all__ = [ "StateMachine" ]