Deleted Added
sdiff udiff text old ( 9630:a3525ee464b8 ) new ( 9692:67d9da312ef0 )
full compact
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)
180
181 def printControllerPython(self, path):
182 code = self.symtab.codeFormatter()
183 ident = self.ident
184 py_ident = "%s_Controller" % ident
185 c_ident = "%s_Controller" % self.ident
186 code('''
187from m5.params import *
188from m5.SimObject import SimObject
189from Controller import RubyController
190
191class $py_ident(RubyController):
192 type = '$py_ident'
193 cxx_header = 'mem/protocol/${c_ident}.hh'
194''')
195 code.indent()
196 for param in self.config_parameters:
197 dflt_str = ''
198 if param.default is not None:
199 dflt_str = str(param.default) + ', '
200 if python_class_map.has_key(param.type_ast.type.c_ident):
201 python_type = python_class_map[param.type_ast.type.c_ident]
202 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
203 else:
204 self.error("Unknown c++ to python class conversion for c++ " \
205 "type: '%s'. Please update the python_class_map " \
206 "in StateMachine.py", param.type_ast.type.c_ident)
207 code.dedent()
208 code.write(path, '%s.py' % py_ident)
209
210
211 def printControllerHH(self, path):
212 '''Output the method declarations for the class declaration'''
213 code = self.symtab.codeFormatter()
214 ident = self.ident
215 c_ident = "%s_Controller" % self.ident
216
217 code('''
218/** \\file $c_ident.hh
219 *
220 * Auto generated C++ code started by $__file__:$__line__
221 * Created by slicc definition of Module "${{self.short}}"
222 */
223
224#ifndef __${ident}_CONTROLLER_HH__
225#define __${ident}_CONTROLLER_HH__
226
227#include <iostream>
228#include <sstream>
229#include <string>
230
231#include "mem/protocol/${ident}_ProfileDumper.hh"
232#include "mem/protocol/${ident}_Profiler.hh"
233#include "mem/protocol/TransitionResult.hh"
234#include "mem/protocol/Types.hh"
235#include "mem/ruby/common/Consumer.hh"
236#include "mem/ruby/common/Global.hh"
237#include "mem/ruby/slicc_interface/AbstractController.hh"
238#include "params/$c_ident.hh"
239''')
240
241 seen_types = set()
242 has_peer = False
243 for var in self.objects:
244 if var.type.ident not in seen_types and not var.type.isPrimitive:
245 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
246 if "network" in var and "physical_network" in var:
247 has_peer = True
248 seen_types.add(var.type.ident)
249
250 # for adding information to the protocol debug trace
251 code('''
252extern std::stringstream ${ident}_transitionComment;
253
254class $c_ident : public AbstractController
255{
256 public:
257 typedef ${c_ident}Params Params;
258 $c_ident(const Params *p);
259 static int getNumControllers();
260 void init();
261 MessageBuffer* getMandatoryQueue() const;
262 const int & getVersion() const;
263 const std::string toString() const;
264 const std::string getName() const;
265 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
266 void print(std::ostream& out) const;
267 void wakeup();
268 void printStats(std::ostream& out) const;
269 void clearStats();
270 void blockOnQueue(Address addr, MessageBuffer* port);
271 void unblock(Address addr);
272 void recordCacheTrace(int cntrl, CacheRecorder* tr);
273 Sequencer* getSequencer() const;
274
275 bool functionalReadBuffers(PacketPtr&);
276 uint32_t functionalWriteBuffers(PacketPtr&);
277
278private:
279''')
280
281 code.indent()
282 # added by SS
283 for param in self.config_parameters:
284 if param.pointer:
285 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
286 else:
287 code('${{param.type_ast.type}} m_${{param.ident}};')
288
289 code('''
290TransitionResult doTransition(${ident}_Event event,
291''')
292
293 if self.EntryType != None:
294 code('''
295 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
296''')
297 if self.TBEType != None:
298 code('''
299 ${{self.TBEType.c_ident}}* m_tbe_ptr,
300''')
301
302 code('''
303 const Address& addr);
304
305TransitionResult doTransitionWorker(${ident}_Event event,
306 ${ident}_State state,
307 ${ident}_State& next_state,
308''')
309
310 if self.TBEType != None:
311 code('''
312 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
313''')
314 if self.EntryType != None:
315 code('''
316 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
317''')
318
319 code('''
320 const Address& addr);
321
322static ${ident}_ProfileDumper s_profileDumper;
323${ident}_Profiler m_profiler;
324static int m_num_controllers;
325
326// Internal functions
327''')
328
329 for func in self.functions:
330 proto = func.prototype
331 if proto:
332 code('$proto')
333
334 if has_peer:
335 code('void getQueuesFromPeer(AbstractController *);')
336 if self.EntryType != None:
337 code('''
338
339// Set and Reset for cache_entry variable
340void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
341void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
342''')
343
344 if self.TBEType != None:
345 code('''
346
347// Set and Reset for tbe variable
348void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
349void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
350''')
351
352 code('''
353
354// Actions
355''')
356 if self.TBEType != None and self.EntryType != None:
357 for action in self.actions.itervalues():
358 code('/** \\brief ${{action.desc}} */')
359 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
360 elif self.TBEType != None:
361 for action in self.actions.itervalues():
362 code('/** \\brief ${{action.desc}} */')
363 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
364 elif self.EntryType != None:
365 for action in self.actions.itervalues():
366 code('/** \\brief ${{action.desc}} */')
367 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
368 else:
369 for action in self.actions.itervalues():
370 code('/** \\brief ${{action.desc}} */')
371 code('void ${{action.ident}}(const Address& addr);')
372
373 # the controller internal variables
374 code('''
375
376// Objects
377''')
378 for var in self.objects:
379 th = var.get("template", "")
380 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
381
382 code.dedent()
383 code('};')
384 code('#endif // __${ident}_CONTROLLER_H__')
385 code.write(path, '%s.hh' % c_ident)
386
387 def printControllerCC(self, path, includes):
388 '''Output the actions for performing the actions'''
389
390 code = self.symtab.codeFormatter()
391 ident = self.ident
392 c_ident = "%s_Controller" % self.ident
393 has_peer = False
394
395 code('''
396/** \\file $c_ident.cc
397 *
398 * Auto generated C++ code started by $__file__:$__line__
399 * Created by slicc definition of Module "${{self.short}}"
400 */
401
402#include <sys/types.h>
403#include <unistd.h>
404
405#include <cassert>
406#include <sstream>
407#include <string>
408
409#include "base/compiler.hh"
410#include "base/cprintf.hh"
411#include "debug/RubyGenerated.hh"
412#include "debug/RubySlicc.hh"
413#include "mem/protocol/${ident}_Controller.hh"
414#include "mem/protocol/${ident}_Event.hh"
415#include "mem/protocol/${ident}_State.hh"
416#include "mem/protocol/Types.hh"
417#include "mem/ruby/common/Global.hh"
418#include "mem/ruby/system/System.hh"
419''')
420 for include_path in includes:
421 code('#include "${{include_path}}"')
422
423 code('''
424
425using namespace std;
426''')
427
428 # include object classes
429 seen_types = set()
430 for var in self.objects:
431 if var.type.ident not in seen_types and not var.type.isPrimitive:
432 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
433 seen_types.add(var.type.ident)
434
435 code('''
436$c_ident *
437${c_ident}Params::create()
438{
439 return new $c_ident(this);
440}
441
442int $c_ident::m_num_controllers = 0;
443${ident}_ProfileDumper $c_ident::s_profileDumper;
444
445// for adding information to the protocol debug trace
446stringstream ${ident}_transitionComment;
447#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
448
449/** \\brief constructor */
450$c_ident::$c_ident(const Params *p)
451 : AbstractController(p)
452{
453 m_name = "${ident}";
454''')
455 #
456 # max_port_rank is used to size vectors and thus should be one plus the
457 # largest port rank
458 #
459 max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1
460 code(' m_max_in_port_rank = $max_port_rank;')
461 code.indent()
462
463 #
464 # After initializing the universal machine parameters, initialize the
465 # this machines config parameters. Also detemine if these configuration
466 # params include a sequencer. This information will be used later for
467 # contecting the sequencer back to the L1 cache controller.
468 #
469 contains_dma_sequencer = False
470 sequencers = []
471 for param in self.config_parameters:
472 if param.name == "dma_sequencer":
473 contains_dma_sequencer = True
474 elif re.compile("sequencer").search(param.name):
475 sequencers.append(param.name)
476 if param.pointer:
477 code('m_${{param.name}}_ptr = p->${{param.name}};')
478 else:
479 code('m_${{param.name}} = p->${{param.name}};')
480
481 #
482 # For the l1 cache controller, add the special atomic support which
483 # includes passing the sequencer a pointer to the controller.
484 #
485 for seq in sequencers:
486 code('''
487m_${{seq}}_ptr->setController(this);
488 ''')
489
490 #
491 # For the DMA controller, pass the sequencer a pointer to the
492 # controller.
493 #
494 if self.ident == "DMA":
495 if not contains_dma_sequencer:
496 self.error("The DMA controller must include the sequencer " \
497 "configuration parameter")
498
499 code('''
500m_dma_sequencer_ptr->setController(this);
501''')
502
503 code('m_num_controllers++;')
504 for var in self.objects:
505 if var.ident.find("mandatoryQueue") >= 0:
506 code('''
507m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
508m_${{var.c_ident}}_ptr->setReceiver(this);
509''')
510 else:
511 if "network" in var and "physical_network" in var and \
512 var["network"] == "To":
513 has_peer = True
514 code('''
515m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
516peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr;
517m_${{var.c_ident}}_ptr->setSender(this);
518''')
519
520 code('''
521if (p->peer != NULL)
522 connectWithPeer(p->peer);
523''')
524 code.dedent()
525 code('''
526}
527
528void
529$c_ident::init()
530{
531 MachineType machine_type;
532 int base;
533 machine_type = string_to_MachineType("${{var.machine.ident}}");
534 base = MachineType_base_number(machine_type);
535
536 m_machineID.type = MachineType_${ident};
537 m_machineID.num = m_version;
538
539 // initialize objects
540 m_profiler.setVersion(m_version);
541 s_profileDumper.registerProfiler(&m_profiler);
542
543''')
544
545 code.indent()
546 for var in self.objects:
547 vtype = var.type
548 vid = "m_%s_ptr" % var.c_ident
549 if "network" not in var:
550 # Not a network port object
551 if "primitive" in vtype:
552 code('$vid = new ${{vtype.c_ident}};')
553 if "default" in var:
554 code('(*$vid) = ${{var["default"]}};')
555 else:
556 # Normal Object
557 if var.ident.find("mandatoryQueue") < 0:
558 th = var.get("template", "")
559 expr = "%s = new %s%s" % (vid, vtype.c_ident, th)
560 args = ""
561 if "non_obj" not in vtype and not vtype.isEnumeration:
562 args = var.get("constructor", "")
563 code('$expr($args);')
564
565 code('assert($vid != NULL);')
566
567 if "default" in var:
568 code('*$vid = ${{var["default"]}}; // Object default')
569 elif "default" in vtype:
570 comment = "Type %s default" % vtype.ident
571 code('*$vid = ${{vtype["default"]}}; // $comment')
572
573 # Set ordering
574 if "ordered" in var:
575 # A buffer
576 code('$vid->setOrdering(${{var["ordered"]}});')
577
578 # Set randomization
579 if "random" in var:
580 # A buffer
581 code('$vid->setRandomization(${{var["random"]}});')
582
583 # Set Priority
584 if vtype.isBuffer and "rank" in var:
585 code('$vid->setPriority(${{var["rank"]}});')
586
587 # Set sender and receiver for trigger queue
588 if var.ident.find("triggerQueue") >= 0:
589 code('$vid->setSender(this);')
590 code('$vid->setReceiver(this);')
591 elif vtype.c_ident == "TimerTable":
592 code('$vid->setClockObj(this);')
593 elif var.ident.find("optionalQueue") >= 0:
594 code('$vid->setSender(this);')
595 code('$vid->setReceiver(this);')
596
597 else:
598 # Network port object
599 network = var["network"]
600 ordered = var["ordered"]
601
602 if "virtual_network" in var:
603 vnet = var["virtual_network"]
604 vnet_type = var["vnet_type"]
605
606 assert var.machine is not None
607 code('''
608$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
609assert($vid != NULL);
610''')
611
612 # Set the end
613 if network == "To":
614 code('$vid->setSender(this);')
615 else:
616 code('$vid->setReceiver(this);')
617
618 # Set ordering
619 if "ordered" in var:
620 # A buffer
621 code('$vid->setOrdering(${{var["ordered"]}});')
622
623 # Set randomization
624 if "random" in var:
625 # A buffer
626 code('$vid->setRandomization(${{var["random"]}});')
627
628 # Set Priority
629 if "rank" in var:
630 code('$vid->setPriority(${{var["rank"]}})')
631
632 # Set buffer size
633 if vtype.isBuffer:
634 code('''
635if (m_buffer_size > 0) {
636 $vid->resize(m_buffer_size);
637}
638''')
639
640 # set description (may be overriden later by port def)
641 code('''
642$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
643
644''')
645
646 if vtype.isBuffer:
647 if "recycle_latency" in var:
648 code('$vid->setRecycleLatency( ' \
649 'Cycles(${{var["recycle_latency"]}}));')
650 else:
651 code('$vid->setRecycleLatency(m_recycle_latency);')
652
653 # Set the prefetchers
654 code()
655 for prefetcher in self.prefetchers:
656 code('${{prefetcher.code}}.setController(this);')
657
658 code()
659 for port in self.in_ports:
660 # Set the queue consumers
661 code('${{port.code}}.setConsumer(this);')
662 # Set the queue descriptions
663 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
664
665 # Initialize the transition profiling
666 code()
667 for trans in self.transitions:
668 # Figure out if we stall
669 stall = False
670 for action in trans.actions:
671 if action.ident == "z_stall":
672 stall = True
673
674 # Only possible if it is not a 'z' case
675 if not stall:
676 state = "%s_State_%s" % (self.ident, trans.state.ident)
677 event = "%s_Event_%s" % (self.ident, trans.event.ident)
678 code('m_profiler.possibleTransition($state, $event);')
679
680 code.dedent()
681 code('''
682 AbstractController::init();
683 clearStats();
684}
685''')
686
687 has_mandatory_q = False
688 for port in self.in_ports:
689 if port.code.find("mandatoryQueue_ptr") >= 0:
690 has_mandatory_q = True
691
692 if has_mandatory_q:
693 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
694 else:
695 mq_ident = "NULL"
696
697 seq_ident = "NULL"
698 for param in self.config_parameters:
699 if param.name == "sequencer":
700 assert(param.pointer)
701 seq_ident = "m_%s_ptr" % param.name
702
703 code('''
704int
705$c_ident::getNumControllers()
706{
707 return m_num_controllers;
708}
709
710MessageBuffer*
711$c_ident::getMandatoryQueue() const
712{
713 return $mq_ident;
714}
715
716Sequencer*
717$c_ident::getSequencer() const
718{
719 return $seq_ident;
720}
721
722const int &
723$c_ident::getVersion() const
724{
725 return m_version;
726}
727
728const string
729$c_ident::toString() const
730{
731 return "$c_ident";
732}
733
734const string
735$c_ident::getName() const
736{
737 return m_name;
738}
739
740void
741$c_ident::blockOnQueue(Address addr, MessageBuffer* port)
742{
743 m_is_blocking = true;
744 m_block_map[addr] = port;
745}
746
747void
748$c_ident::unblock(Address addr)
749{
750 m_block_map.erase(addr);
751 if (m_block_map.size() == 0) {
752 m_is_blocking = false;
753 }
754}
755
756void
757$c_ident::print(ostream& out) const
758{
759 out << "[$c_ident " << m_version << "]";
760}
761
762void
763$c_ident::printStats(ostream& out) const
764{
765''')
766 #
767 # Cache and Memory Controllers have specific profilers associated with
768 # them. Print out these stats before dumping state transition stats.
769 #
770 for param in self.config_parameters:
771 if param.type_ast.type.ident == "DirectoryMemory" or \
772 param.type_ast.type.ident == "MemoryControl":
773 assert(param.pointer)
774 code(' m_${{param.ident}}_ptr->printStats(out);')
775
776 code('''
777 if (m_version == 0) {
778 s_profileDumper.dumpStats(out);
779 }
780}
781
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();')
792
793 code('''
794 m_profiler.clearStats();
795 AbstractController::clearStats();
796}
797''')
798
799 if self.EntryType != None:
800 code('''
801
802// Set and Reset for cache_entry variable
803void
804$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
805{
806 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
807}
808
809void
810$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
811{
812 m_cache_entry_ptr = 0;
813}
814''')
815
816 if self.TBEType != None:
817 code('''
818
819// Set and Reset for tbe variable
820void
821$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
822{
823 m_tbe_ptr = m_new_tbe;
824}
825
826void
827$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
828{
829 m_tbe_ptr = NULL;
830}
831''')
832
833 code('''
834
835void
836$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
837{
838''')
839 #
840 # Record cache contents for all associated caches.
841 #
842 code.indent()
843 for param in self.config_parameters:
844 if param.type_ast.type.ident == "CacheMemory":
845 assert(param.pointer)
846 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
847
848 code.dedent()
849 code('''
850}
851
852// Actions
853''')
854 if self.TBEType != None and self.EntryType != None:
855 for action in self.actions.itervalues():
856 if "c_code" not in action:
857 continue
858
859 code('''
860/** \\brief ${{action.desc}} */
861void
862$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
863{
864 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
865 ${{action["c_code"]}}
866}
867
868''')
869 elif self.TBEType != None:
870 for action in self.actions.itervalues():
871 if "c_code" not in action:
872 continue
873
874 code('''
875/** \\brief ${{action.desc}} */
876void
877$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
878{
879 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
880 ${{action["c_code"]}}
881}
882
883''')
884 elif self.EntryType != None:
885 for action in self.actions.itervalues():
886 if "c_code" not in action:
887 continue
888
889 code('''
890/** \\brief ${{action.desc}} */
891void
892$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
893{
894 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
895 ${{action["c_code"]}}
896}
897
898''')
899 else:
900 for action in self.actions.itervalues():
901 if "c_code" not in action:
902 continue
903
904 code('''
905/** \\brief ${{action.desc}} */
906void
907$c_ident::${{action.ident}}(const Address& addr)
908{
909 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
910 ${{action["c_code"]}}
911}
912
913''')
914 for func in self.functions:
915 code(func.generateCode())
916
917 # Function for functional reads from messages buffered in the controller
918 code('''
919bool
920$c_ident::functionalReadBuffers(PacketPtr& pkt)
921{
922''')
923 for var in self.objects:
924 vtype = var.type
925 if vtype.isBuffer:
926 vid = "m_%s_ptr" % var.c_ident
927 code('if ($vid->functionalRead(pkt)) { return true; }')
928 code('''
929 return false;
930}
931''')
932
933 # Function for functional writes to messages buffered in the controller
934 code('''
935uint32_t
936$c_ident::functionalWriteBuffers(PacketPtr& pkt)
937{
938 uint32_t num_functional_writes = 0;
939''')
940 for var in self.objects:
941 vtype = var.type
942 if vtype.isBuffer:
943 vid = "m_%s_ptr" % var.c_ident
944 code('num_functional_writes += $vid->functionalWrite(pkt);')
945 code('''
946 return num_functional_writes;
947}
948''')
949
950 # Check if this controller has a peer, if yes then write the
951 # function for connecting to the peer.
952 if has_peer:
953 code('''
954
955void
956$c_ident::getQueuesFromPeer(AbstractController *peer)
957{
958''')
959 for var in self.objects:
960 if "network" in var and "physical_network" in var and \
961 var["network"] == "From":
962 code('''
963m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}});
964assert(m_${{var.c_ident}}_ptr != NULL);
965m_${{var.c_ident}}_ptr->setReceiver(this);
966
967''')
968 code('}')
969
970 code.write(path, "%s.cc" % c_ident)
971
972 def printCWakeup(self, path, includes):
973 '''Output the wakeup loop for the events'''
974
975 code = self.symtab.codeFormatter()
976 ident = self.ident
977
978 outputRequest_types = True
979 if len(self.request_types) == 0:
980 outputRequest_types = False
981
982 code('''
983// Auto generated C++ code started by $__file__:$__line__
984// ${ident}: ${{self.short}}
985
986#include <sys/types.h>
987#include <unistd.h>
988
989#include <cassert>
990
991#include "base/misc.hh"
992#include "debug/RubySlicc.hh"
993#include "mem/protocol/${ident}_Controller.hh"
994#include "mem/protocol/${ident}_Event.hh"
995#include "mem/protocol/${ident}_State.hh"
996''')
997
998 if outputRequest_types:
999 code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1000
1001 code('''
1002#include "mem/protocol/Types.hh"
1003#include "mem/ruby/common/Global.hh"
1004#include "mem/ruby/system/System.hh"
1005''')
1006
1007
1008 for include_path in includes:
1009 code('#include "${{include_path}}"')
1010
1011 code('''
1012
1013using namespace std;
1014
1015void
1016${ident}_Controller::wakeup()
1017{
1018 int counter = 0;
1019 while (true) {
1020 // Some cases will put us into an infinite loop without this limit
1021 assert(counter <= m_transitions_per_cycle);
1022 if (counter == m_transitions_per_cycle) {
1023 // Count how often we are fully utilized
1024 m_fully_busy_cycles++;
1025
1026 // Wakeup in another cycle and try again
1027 scheduleEvent(Cycles(1));
1028 break;
1029 }
1030''')
1031
1032 code.indent()
1033 code.indent()
1034
1035 # InPorts
1036 #
1037 for port in self.in_ports:
1038 code.indent()
1039 code('// ${ident}InPort $port')
1040 if port.pairs.has_key("rank"):
1041 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1042 else:
1043 code('m_cur_in_port_rank = 0;')
1044 code('${{port["c_code_in_port"]}}')
1045 code.dedent()
1046
1047 code('')
1048
1049 code.dedent()
1050 code.dedent()
1051 code('''
1052 break; // If we got this far, we have nothing left todo
1053 }
1054}
1055''')
1056
1057 code.write(path, "%s_Wakeup.cc" % self.ident)
1058
1059 def printCSwitch(self, path):
1060 '''Output switch statement for transition table'''
1061
1062 code = self.symtab.codeFormatter()
1063 ident = self.ident
1064
1065 code('''
1066// Auto generated C++ code started by $__file__:$__line__
1067// ${ident}: ${{self.short}}
1068
1069#include <cassert>
1070
1071#include "base/misc.hh"
1072#include "base/trace.hh"
1073#include "debug/ProtocolTrace.hh"
1074#include "debug/RubyGenerated.hh"
1075#include "mem/protocol/${ident}_Controller.hh"
1076#include "mem/protocol/${ident}_Event.hh"
1077#include "mem/protocol/${ident}_State.hh"
1078#include "mem/protocol/Types.hh"
1079#include "mem/ruby/common/Global.hh"
1080#include "mem/ruby/system/System.hh"
1081
1082#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1083
1084#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1085#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1086
1087TransitionResult
1088${ident}_Controller::doTransition(${ident}_Event event,
1089''')
1090 if self.EntryType != None:
1091 code('''
1092 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1093''')
1094 if self.TBEType != None:
1095 code('''
1096 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1097''')
1098 code('''
1099 const Address &addr)
1100{
1101''')
1102 if self.TBEType != None and self.EntryType != None:
1103 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1104 elif self.TBEType != None:
1105 code('${ident}_State state = getState(m_tbe_ptr, addr);')
1106 elif self.EntryType != None:
1107 code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1108 else:
1109 code('${ident}_State state = getState(addr);')
1110
1111 code('''
1112 ${ident}_State next_state = state;
1113
1114 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1115 *this, curCycle(), ${ident}_State_to_string(state),
1116 ${ident}_Event_to_string(event), addr);
1117
1118 TransitionResult result =
1119''')
1120 if self.TBEType != None and self.EntryType != None:
1121 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1122 elif self.TBEType != None:
1123 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1124 elif self.EntryType != None:
1125 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1126 else:
1127 code('doTransitionWorker(event, state, next_state, addr);')
1128
1129 code('''
1130 if (result == TransitionResult_Valid) {
1131 DPRINTF(RubyGenerated, "next_state: %s\\n",
1132 ${ident}_State_to_string(next_state));
1133 m_profiler.countTransition(state, event);
1134 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1135 curTick(), m_version, "${ident}",
1136 ${ident}_Event_to_string(event),
1137 ${ident}_State_to_string(state),
1138 ${ident}_State_to_string(next_state),
1139 addr, GET_TRANSITION_COMMENT());
1140
1141 CLEAR_TRANSITION_COMMENT();
1142''')
1143 if self.TBEType != None and self.EntryType != None:
1144 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1145 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1146 elif self.TBEType != None:
1147 code('setState(m_tbe_ptr, addr, next_state);')
1148 code('setAccessPermission(addr, next_state);')
1149 elif self.EntryType != None:
1150 code('setState(m_cache_entry_ptr, addr, next_state);')
1151 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1152 else:
1153 code('setState(addr, next_state);')
1154 code('setAccessPermission(addr, next_state);')
1155
1156 code('''
1157 } else if (result == TransitionResult_ResourceStall) {
1158 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1159 curTick(), m_version, "${ident}",
1160 ${ident}_Event_to_string(event),
1161 ${ident}_State_to_string(state),
1162 ${ident}_State_to_string(next_state),
1163 addr, "Resource Stall");
1164 } else if (result == TransitionResult_ProtocolStall) {
1165 DPRINTF(RubyGenerated, "stalling\\n");
1166 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1167 curTick(), m_version, "${ident}",
1168 ${ident}_Event_to_string(event),
1169 ${ident}_State_to_string(state),
1170 ${ident}_State_to_string(next_state),
1171 addr, "Protocol Stall");
1172 }
1173
1174 return result;
1175}
1176
1177TransitionResult
1178${ident}_Controller::doTransitionWorker(${ident}_Event event,
1179 ${ident}_State state,
1180 ${ident}_State& next_state,
1181''')
1182
1183 if self.TBEType != None:
1184 code('''
1185 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1186''')
1187 if self.EntryType != None:
1188 code('''
1189 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1190''')
1191 code('''
1192 const Address& addr)
1193{
1194 switch(HASH_FUN(state, event)) {
1195''')
1196
1197 # This map will allow suppress generating duplicate code
1198 cases = orderdict()
1199
1200 for trans in self.transitions:
1201 case_string = "%s_State_%s, %s_Event_%s" % \
1202 (self.ident, trans.state.ident, self.ident, trans.event.ident)
1203
1204 case = self.symtab.codeFormatter()
1205 # Only set next_state if it changes
1206 if trans.state != trans.nextState:
1207 ns_ident = trans.nextState.ident
1208 case('next_state = ${ident}_State_${ns_ident};')
1209
1210 actions = trans.actions
1211 request_types = trans.request_types
1212
1213 # Check for resources
1214 case_sorter = []
1215 res = trans.resources
1216 for key,val in res.iteritems():
1217 if key.type.ident != "DNUCAStopTable":
1218 val = '''
1219if (!%s.areNSlotsAvailable(%s))
1220 return TransitionResult_ResourceStall;
1221''' % (key.code, val)
1222 case_sorter.append(val)
1223
1224 # Check all of the request_types for resource constraints
1225 for request_type in request_types:
1226 val = '''
1227if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1228 return TransitionResult_ResourceStall;
1229}
1230''' % (self.ident, request_type.ident)
1231 case_sorter.append(val)
1232
1233 # Emit the code sequences in a sorted order. This makes the
1234 # output deterministic (without this the output order can vary
1235 # since Map's keys() on a vector of pointers is not deterministic
1236 for c in sorted(case_sorter):
1237 case("$c")
1238
1239 # Record access types for this transition
1240 for request_type in request_types:
1241 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1242
1243 # Figure out if we stall
1244 stall = False
1245 for action in actions:
1246 if action.ident == "z_stall":
1247 stall = True
1248 break
1249
1250 if stall:
1251 case('return TransitionResult_ProtocolStall;')
1252 else:
1253 if self.TBEType != None and self.EntryType != None:
1254 for action in actions:
1255 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1256 elif self.TBEType != None:
1257 for action in actions:
1258 case('${{action.ident}}(m_tbe_ptr, addr);')
1259 elif self.EntryType != None:
1260 for action in actions:
1261 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1262 else:
1263 for action in actions:
1264 case('${{action.ident}}(addr);')
1265 case('return TransitionResult_Valid;')
1266
1267 case = str(case)
1268
1269 # Look to see if this transition code is unique.
1270 if case not in cases:
1271 cases[case] = []
1272
1273 cases[case].append(case_string)
1274
1275 # Walk through all of the unique code blocks and spit out the
1276 # corresponding case statement elements
1277 for case,transitions in cases.iteritems():
1278 # Iterative over all the multiple transitions that share
1279 # the same code
1280 for trans in transitions:
1281 code(' case HASH_FUN($trans):')
1282 code(' $case')
1283
1284 code('''
1285 default:
1286 fatal("Invalid transition\\n"
1287 "%s time: %d addr: %s event: %s state: %s\\n",
1288 name(), curCycle(), addr, event, state);
1289 }
1290 return TransitionResult_Valid;
1291}
1292''')
1293 code.write(path, "%s_Transitions.cc" % self.ident)
1294
1295 def printProfileDumperHH(self, path):
1296 code = self.symtab.codeFormatter()
1297 ident = self.ident
1298
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
1521 # **************************
1522 # ******* HTML Files *******
1523 # **************************
1524 def frameRef(self, click_href, click_target, over_href, over_num, text):
1525 code = self.symtab.codeFormatter(fix_newlines=False)
1526 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1527 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1528 parent.frames[$over_num].location='$over_href'
1529 }\">
1530 ${{html.formatShorthand(text)}}
1531 </A>""")
1532 return str(code)
1533
1534 def writeHTMLFiles(self, path):
1535 # Create table with no row hilighted
1536 self.printHTMLTransitions(path, None)
1537
1538 # Generate transition tables
1539 for state in self.states.itervalues():
1540 self.printHTMLTransitions(path, state)
1541
1542 # Generate action descriptions
1543 for action in self.actions.itervalues():
1544 name = "%s_action_%s.html" % (self.ident, action.ident)
1545 code = html.createSymbol(action, "Action")
1546 code.write(path, name)
1547
1548 # Generate state descriptions
1549 for state in self.states.itervalues():
1550 name = "%s_State_%s.html" % (self.ident, state.ident)
1551 code = html.createSymbol(state, "State")
1552 code.write(path, name)
1553
1554 # Generate event descriptions
1555 for event in self.events.itervalues():
1556 name = "%s_Event_%s.html" % (self.ident, event.ident)
1557 code = html.createSymbol(event, "Event")
1558 code.write(path, name)
1559
1560 def printHTMLTransitions(self, path, active_state):
1561 code = self.symtab.codeFormatter()
1562
1563 code('''
1564<HTML>
1565<BODY link="blue" vlink="blue">
1566
1567<H1 align="center">${{html.formatShorthand(self.short)}}:
1568''')
1569 code.indent()
1570 for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1571 mid = machine.ident
1572 if i != 0:
1573 extra = " - "
1574 else:
1575 extra = ""
1576 if machine == self:
1577 code('$extra$mid')
1578 else:
1579 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1580 code.dedent()
1581
1582 code("""
1583</H1>
1584
1585<TABLE border=1>
1586<TR>
1587 <TH> </TH>
1588""")
1589
1590 for event in self.events.itervalues():
1591 href = "%s_Event_%s.html" % (self.ident, event.ident)
1592 ref = self.frameRef(href, "Status", href, "1", event.short)
1593 code('<TH bgcolor=white>$ref</TH>')
1594
1595 code('</TR>')
1596 # -- Body of table
1597 for state in self.states.itervalues():
1598 # -- Each row
1599 if state == active_state:
1600 color = "yellow"
1601 else:
1602 color = "white"
1603
1604 click = "%s_table_%s.html" % (self.ident, state.ident)
1605 over = "%s_State_%s.html" % (self.ident, state.ident)
1606 text = html.formatShorthand(state.short)
1607 ref = self.frameRef(click, "Table", over, "1", state.short)
1608 code('''
1609<TR>
1610 <TH bgcolor=$color>$ref</TH>
1611''')
1612
1613 # -- One column for each event
1614 for event in self.events.itervalues():
1615 trans = self.table.get((state,event), None)
1616 if trans is None:
1617 # This is the no transition case
1618 if state == active_state:
1619 color = "#C0C000"
1620 else:
1621 color = "lightgrey"
1622
1623 code('<TD bgcolor=$color>&nbsp;</TD>')
1624 continue
1625
1626 next = trans.nextState
1627 stall_action = False
1628
1629 # -- Get the actions
1630 for action in trans.actions:
1631 if action.ident == "z_stall" or \
1632 action.ident == "zz_recycleMandatoryQueue":
1633 stall_action = True
1634
1635 # -- Print out "actions/next-state"
1636 if stall_action:
1637 if state == active_state:
1638 color = "#C0C000"
1639 else:
1640 color = "lightgrey"
1641
1642 elif active_state and next.ident == active_state.ident:
1643 color = "aqua"
1644 elif state == active_state:
1645 color = "yellow"
1646 else:
1647 color = "white"
1648
1649 code('<TD bgcolor=$color>')
1650 for action in trans.actions:
1651 href = "%s_action_%s.html" % (self.ident, action.ident)
1652 ref = self.frameRef(href, "Status", href, "1",
1653 action.short)
1654 code(' $ref')
1655 if next != state:
1656 if trans.actions:
1657 code('/')
1658 click = "%s_table_%s.html" % (self.ident, next.ident)
1659 over = "%s_State_%s.html" % (self.ident, next.ident)
1660 ref = self.frameRef(click, "Table", over, "1", next.short)
1661 code("$ref")
1662 code("</TD>")
1663
1664 # -- Each row
1665 if state == active_state:
1666 color = "yellow"
1667 else:
1668 color = "white"
1669
1670 click = "%s_table_%s.html" % (self.ident, state.ident)
1671 over = "%s_State_%s.html" % (self.ident, state.ident)
1672 ref = self.frameRef(click, "Table", over, "1", state.short)
1673 code('''
1674 <TH bgcolor=$color>$ref</TH>
1675</TR>
1676''')
1677 code('''
1678<!- Column footer->
1679<TR>
1680 <TH> </TH>
1681''')
1682
1683 for event in self.events.itervalues():
1684 href = "%s_Event_%s.html" % (self.ident, event.ident)
1685 ref = self.frameRef(href, "Status", href, "1", event.short)
1686 code('<TH bgcolor=white>$ref</TH>')
1687 code('''
1688</TR>
1689</TABLE>
1690</BODY></HTML>
1691''')
1692
1693
1694 if active_state:
1695 name = "%s_table_%s.html" % (self.ident, active_state.ident)
1696 else:
1697 name = "%s_table.html" % self.ident
1698 code.write(path, name)
1699
1700__all__ = [ "StateMachine" ]