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