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