OpenASIP  2.0
FUState.cc
Go to the documentation of this file.
1 /*
2  Copyright (c) 2002-2017 Tampere University.
3 
4  This file is part of TTA-Based Codesign Environment (TCE).
5 
6  Permission is hereby granted, free of charge, to any person obtaining a
7  copy of this software and associated documentation files (the "Software"),
8  to deal in the Software without restriction, including without limitation
9  the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  and/or sell copies of the Software, and to permit persons to whom the
11  Software is furnished to do so, subject to the following conditions:
12 
13  The above copyright notice and this permission notice shall be included in
14  all copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  DEALINGS IN THE SOFTWARE.
23  */
24 /**
25  * @file FUState.cc
26  *
27  * Definition of FUState class.
28  *
29  * @author Jussi Nykänen 2004 (nykanen-no.spam-cs.tut.fi)
30  * @author Pekka Jääskeläinen 2005,2010,2017 (pjaaskel-no.spam-cs.tut.fi)
31  * @note rating: red
32  */
33 
34 #include "FUState.hh"
35 #include "Operation.hh"
36 #include "OperationExecutor.hh"
39 #include "InputPortState.hh"
42 #include "PortState.hh"
43 #include "Application.hh"
44 #include "OperationContext.hh"
45 #include "OutputPortState.hh"
46 #include "OperationContext.hh"
47 #include "SimulatorToolbox.hh"
48 #include "OperationPool.hh"
49 #include "Application.hh"
50 #include "SequenceTools.hh"
51 #include "Conversion.hh"
54 
55 using std::vector;
56 using std::string;
57 
58 //////////////////////////////////////////////////////////////////////////////
59 // FUState
60 //////////////////////////////////////////////////////////////////////////////
61 
62 /**
63  * Constructor (no explicitly given FU name).
64  *
65  * @param lock Global lock signal.
66  */
68  ClockedState(), idle_(false), trigger_(false),
69  nextOperation_(NULL), nextExecutor_(NULL),
70  operationContext_(DEFAULT_FU_NAME),
71  activeExecutors_(0), detailedModel_(NULL) {
72 }
73 
74 /**
75  * Constructor (with explicitly given FU name).
76  *
77  * @param lock Global lock signal.
78  */
80  ClockedState(), idle_(false), trigger_(false),
81  nextOperation_(NULL), nextExecutor_(NULL), operationContext_(name),
82  activeExecutors_(0), detailedModel_(NULL) {
83 }
84 
85 /**
86  * Destructor.
87  */
89  clearPorts();
91 }
92 
93 /**
94  * Clears input and output ports.
95  */
96 void
98  inputPorts_.clear();
99  outputPorts_.clear();
100 }
101 
102 void
104  for (ExecutorContainer::iterator i = executors_.begin();
105  i != executors_.end(); ++i) {
106  Operation* op = (*i).first;
107  // Ensure the init state is called again.
108  op->deleteState(context());
109  op->createState(context());
110  // Reset the internal state of executor
111  (*i).second->reset();
112  }
113 }
114 
115 /**
116  * Handles actions that take place in the end of the clock cycle.
117  *
118  * If operation is triggered, startOperation() of the executor of the
119  * operation is called.
120  */
121 void
123  if (trigger_) {
124  if (nextOperation_ == NULL) {
125  throw Exception(
126  __FILE__, __LINE__, __func__,
127  "Tried to trigger FU without operation code.");
128  }
129  if (nextExecutor_ == NULL) {
130  ExecutorContainer::iterator iter = executors_.find(nextOperation_);
131  assert(iter != executors_.end());
132  nextExecutor_ = (*iter).second;
133  }
134  // set this flag to false before actually handling the trigger
135  // condition because startOperation() can cause a runtime error
136  // exception
137  trigger_ = false;
141  idle_ = false;
142  }
143  }
144 }
145 
146 /**
147  * Handles actions that take place while clock cycle changes.
148  *
149  * advanceClock() of all active operation executors are called.
150  */
151 void
153 
154  if (detailedModel_ != NULL)
156 
157  // in case there are no active operations and there are no states
158  // which need clock advancing, the FU is in idle state
159  if (activeExecutors_ == 0 && context().isEmpty()) {
160  idle_ = true;
161  return;
162  } else if (activeExecutors_ == 1 && nextExecutor_ != NULL &&
164  // a special case for sequential simulation:
165  // if there's only one active executor, and it's the one
166  // triggered previously in endClock(), we can use
167  // nextExecutor_ and avoid traversing the whole list of executors
170  activeExecutors_ = 1;
171  idle_ = false;
172  } else {
173  activeExecutors_ = 0;
174  idle_ = true;
175  }
176  // advance clock of all operations with state
177  /// @todo detect if there are *clocked* state objects
178  if (!context().isEmpty()) {
179  context().advanceClock();
180  }
181  return;
182  }
183 
184  activeExecutors_ = 0;
185  size_t execListSize = execList_.size();
186  for (size_t i = 0; i < execListSize; ++i) {
187  OperationExecutor* opexec = execList_[i];
188  if (opexec->hasPendingOperations()) {
189  opexec->advanceClock();
190  // check if it's still active
191  if (opexec->hasPendingOperations()) {
193  }
194  }
195  }
196  // advance clock of all operations with state
197  /// @todo detect if there are *clocked* state objects
198  if (!context().isEmpty()) {
199  context().advanceClock();
200  }
201 
202  idle_ = (activeExecutors_ == 0 && context().isEmpty());
203 }
204 
205 /**
206  * Adds new input port state.
207  *
208  * @param port New input port state.
209  */
210 void
212  inputPorts_.push_back(&port);
213 }
214 
215 /**
216  * Adds new output port state.
217  *
218  * @param port New output port state.
219  */
220 void
222  outputPorts_.push_back(&port);
223 }
224 
225 /**
226  * Adds operation executor for a given operation.
227  *
228  * @param opExec Operation executor to be added.
229  * @param op Operation which executor is added.
230  */
231 void
233 
234  op.createState(context());
235 
236  // do not use same operation executor even if the latency and operand
237  // bindings are equal between the operations, because the executor
238  // properties can be different (especially, one of the executors can
239  // have conflict detection)
240  OperationExecutor* newExecutor = opExec.copy();
241  execList_.push_back(newExecutor);
242  newExecutor->setContext(context());
243  executors_[&op] = newExecutor;
244 }
245 
246 /**
247  * Replaces the operation executor model for an operation.
248  *
249  * Does not copy the operation executor but uses the given instance.
250  * The method copies the I/O bindings and sets the parent FUState from
251  * the old model.
252  *
253  * @param op Operation of which executor is added.
254  * @param newExecutor Operation executor to be set.
255  */
256 void
258  Operation& op,
259  OperationExecutor* newExecutor) {
260 
261  op.createState(context());
262  newExecutor->setContext(context());
263 
264  OperationExecutor* oldExecutor = executors_[&op];
265  newExecutor->setParent(oldExecutor->parent());
266 
267  /* Copy the operand-port bindings. */
268  for (int ioId = 1;
269  ioId <= op.numberOfInputs() + op.numberOfOutputs(); ++ioId) {
270  newExecutor->addBinding(ioId, oldExecutor->binding(ioId));
271  }
272  assert(sameBindings(*oldExecutor, *newExecutor, op));
273 
274  /* Replace the executor in the execution list. */
275  for (std::size_t i = 0; i < execList_.size(); ++i) {
276  if (execList_.at(i) == oldExecutor) {
277  execList_[i] = newExecutor;
278  break;
279  }
280  }
281  executors_[&op] = newExecutor;
282  delete oldExecutor;
283 }
284 
285 /**
286  * Sets a detailed operation simulation model for all operations in
287  * the FU.
288  */
289 void
291  Operation& op,
293 
295  dynamic_cast<MultiLatencyOperationExecutor*>(executor(op));
296  assert (oe != NULL && "Can only add details to a complex executor.");
297  oe->setOperationSimulator(sim);
298 }
299 
300 /**
301  * Sets a detailed operation simulation model for all operations in the FU.
302  */
303 void
305 
306  for (ExecutorContainer::iterator i = executors_.begin();
307  i != executors_.end(); ++i) {
308  Operation* op = (*i).first;
309  setOperationSimulator(*op, sim);
310  }
311  detailedModel_ = &sim;
312 }
313 
314 
315 /**
316  * Returns true if the two OperationExecutors have the same bindings.
317  *
318  * @param exec1 First OperationExecutor.
319  * @param exec2 Second OperationExecutor.
320  * @param op Operation to be executed with executors.
321  * @return True if the two executors have same bindings.
322  */
323 bool
325  OperationExecutor& exec1,
326  OperationExecutor& exec2,
327  Operation& op) {
328 
329  for (int i = 1; i <= op.numberOfInputs() + op.numberOfOutputs(); i++) {
330 
331  PortState* port1 = NULL;
332  try {
333  port1 = &exec1.binding(i);
334  } catch (const OutOfRange& o) {
335  return false;
336  }
337 
338  PortState* port2 = NULL;
339  try {
340  port2 = &exec2.binding(i);
341  } catch (const OutOfRange& o) {
342  return false;
343  }
344 
345  if (port1 != port2) {
346  return false;
347  }
348  }
349  return true;
350 }
351 
352 /**
353  * Returns OperationExecutor for the given operation.
354  *
355  * @param op The operation of the wanted OperationExecutor.
356  */
359  ExecutorContainer::iterator iter = executors_.find(&op);
360  if (iter == executors_.end()) {
361  return NULL;
362  } else {
363  return (*iter).second;
364  }
365 }
366 
367 /**
368  * Returns the operation context.
369  *
370  * This is a "template method" to allow differently initialized
371  * OperationContext-classes in FUState subclasses.
372  *
373  * @return The operation context for the FU.
374  */
377  return operationContext_;
378 }
379 
380 //////////////////////////////////////////////////////////////////////////////
381 // NullFUState
382 //////////////////////////////////////////////////////////////////////////////
383 
385 
386 /**
387  * Returns the instance of NullFUState.
388  *
389  * @return Instance of NullFUState.
390  */
393  return instance_;
394 }
395 
396 /**
397  * Constructor.
398  */
400 }
401 
402 /**
403  * Destructor.
404  */
406 }
407 
408 /**
409  * Aborts the program with error message.
410  */
411 void
413  Application::abortWithError("endClock()");
414 }
415 
416 /**
417  * Aborts the program with error message.
418  */
419 void
421  Application::abortWithError("advanceClock()");
422 }
423 
424 /**
425  * Aborts the program with error message.
426  */
427 void
429  Application::abortWithError("addInputPortState()");
430 }
431 
432 /**
433  * Aborts the program with error message.
434  */
435 void
437  Application::abortWithError("addOutputPortState()");
438 }
439 
440 /**
441  * Aborts the program with error message.
442  */
443 void
445  Application::abortWithError("addOperationExecutor()");
446 }
447 
448 /**
449  * Aborts the program with error message.
450  *
451  * @return Never returns.
452  */
455  Application::abortWithError("executor()");
456  return NULL;
457 }
458 
FUState::inputPorts_
std::vector< PortState * > inputPorts_
Input ports of the function unit.
Definition: FUState.hh:131
FUState::nextExecutor_
OperationExecutor * nextExecutor_
OperationExecutor to be used for the next operation (an optimization).
Definition: FUState.hh:123
FUState::advanceClock
virtual void advanceClock()
Definition: FUState.cc:152
FUState::sameBindings
bool sameBindings(OperationExecutor &exec1, OperationExecutor &exec2, Operation &op)
Definition: FUState.cc:324
FUState::operationContext_
OperationContext operationContext_
The operation context for this FU.
Definition: FUState.hh:125
FUState::trigger_
bool trigger_
True if operation is triggered in current clock cycle.
Definition: FUState.hh:119
DetailedOperationSimulator.hh
OperationExecutor::addBinding
void addBinding(int io, PortState &port)
Definition: OperationExecutor.cc:67
ClockedState
Definition: ClockedState.hh:40
FUState::endClock
virtual void endClock()
Definition: FUState.cc:122
OperationContext
Definition: OperationContext.hh:56
OutOfRange
Definition: Exception.hh:320
SequenceTools.hh
FUState::addOperationExecutor
virtual void addOperationExecutor(OperationExecutor &opExec, Operation &op)
Definition: FUState.cc:232
Operation::numberOfInputs
virtual int numberOfInputs() const
Definition: Operation.cc:192
FUState::outputPorts_
std::vector< PortState * > outputPorts_
Output ports of the function unit.
Definition: FUState.hh:133
FUState.hh
OperationExecutor::copy
virtual OperationExecutor * copy()=0
FUState::addInputPortState
virtual void addInputPortState(PortState &port)
Definition: FUState.cc:211
MultiLatencyOperationExecutor.hh
DetailedOperationSimulator
Definition: DetailedOperationSimulator.hh:49
FUState::detailedModel_
DetailedOperationSimulator * detailedModel_
Optional detailed operation simulation model. Assume there's one such model per FU or none at all for...
Definition: FUState.hh:140
OperationExecutor::setContext
virtual void setContext(OperationContext &context)=0
FUState::nextOperation_
Operation * nextOperation_
Operation to be triggered next.
Definition: FUState.hh:121
DEFAULT_FU_NAME
#define DEFAULT_FU_NAME
Definition: OperationContext.hh:47
OperationExecutor::hasPendingOperations
bool hasPendingOperations() const
NullFUState::addInputPortState
virtual void addInputPortState(PortState &port)
Definition: FUState.cc:428
OperationExecutor::advanceClock
virtual void advanceClock()=0
NullFUState::advanceClock
virtual void advanceClock()
Definition: FUState.cc:420
OutputPortState.hh
InputPortState.hh
assert
#define assert(condition)
Definition: Application.hh:86
NullFUState::addOperationExecutor
virtual void addOperationExecutor(OperationExecutor &opExec, Operation &op)
Definition: FUState.cc:444
FUState::~FUState
virtual ~FUState()
Definition: FUState.cc:88
OperationContext::isEmpty
bool isEmpty() const
Definition: OperationContext.cc:224
SequenceTools::deleteAllItems
static void deleteAllItems(SequenceType &aSequence)
MultiLatencyOperationExecutor::setOperationSimulator
virtual void setOperationSimulator(DetailedOperationSimulator &sim)
Definition: MultiLatencyOperationExecutor.hh:74
SimulatorToolbox.hh
OperationExecutor::startOperation
virtual void startOperation(Operation &op)=0
FUState::FUState
FUState()
Definition: FUState.cc:67
abortWithError
#define abortWithError(message)
Definition: Application.hh:72
FUState::executors_
ExecutorContainer executors_
All operation executors.
Definition: FUState.hh:127
FUState::replaceOperationExecutor
virtual void replaceOperationExecutor(Operation &op, OperationExecutor *newExecutor)
Definition: FUState.cc:257
Conversion.hh
FUState::execList_
ExecutorList execList_
All the different instances of OperationExecutors.
Definition: FUState.hh:129
NullFUState::instance
static NullFUState & instance()
Definition: FUState.cc:392
NullFUState::~NullFUState
virtual ~NullFUState()
Definition: FUState.cc:405
OneCycleOperationExecutor.hh
OperationExecutor.hh
Application.hh
__func__
#define __func__
Definition: Application.hh:67
FUState::setOperationSimulator
virtual void setOperationSimulator(DetailedOperationSimulator &sim)
Definition: FUState.cc:304
DetailedOperationSimulator::simulateCycleStart
virtual void simulateCycleStart()
Definition: DetailedOperationSimulator.hh:77
Operation.hh
Exception
Definition: Exception.hh:54
MultiLatencyOperationExecutor
Definition: MultiLatencyOperationExecutor.hh:61
PortState
Definition: PortState.hh:51
FUState::activeExecutors_
std::size_t activeExecutors_
Count of active executors (to allow returning instantly from advanceClock())
Definition: FUState.hh:136
Operation::deleteState
virtual void deleteState(OperationContext &context) const
Definition: Operation.cc:601
NullFUState
Definition: FUState.hh:152
OperationExecutor
Definition: OperationExecutor.hh:49
Operation
Definition: Operation.hh:59
NullFUState::NullFUState
NullFUState()
Definition: FUState.cc:399
FUState::reset
virtual void reset()
this is called at (re)initialization of the simulation
Definition: FUState.cc:103
NullFUState::executor
virtual OperationExecutor * executor(Operation &op)
Definition: FUState.cc:454
OperationExecutor::parent
FUState & parent() const
FUState::idle_
bool idle_
The idle status of the FU. The derived classes should alway set this to true when possible to avoid u...
Definition: FUState.hh:95
Operation::createState
virtual void createState(OperationContext &context) const
Definition: Operation.cc:590
false
find Finds info of the inner loops in the false
Definition: InnerLoopFinder.cc:81
TCEString
Definition: TCEString.hh:53
TriggeringInputPortState.hh
FUState::clearPorts
void clearPorts()
Definition: FUState.cc:97
FUState::addOutputPortState
virtual void addOutputPortState(PortState &port)
Definition: FUState.cc:221
OperationExecutor::setParent
void setParent(FUState &parent)
Definition: OperationExecutor.hh:56
NullFUState::instance_
static NullFUState instance_
Unique instance of NullFUState.
Definition: FUState.hh:177
SimpleOperationExecutor.hh
FUState::executor
virtual OperationExecutor * executor(Operation &op)
Definition: FUState.cc:358
NullFUState::addOutputPortState
virtual void addOutputPortState(PortState &port)
Definition: FUState.cc:436
OperationContext::advanceClock
void advanceClock()
Definition: OperationContext.cc:108
OperationPool.hh
Operation::numberOfOutputs
virtual int numberOfOutputs() const
Definition: Operation.cc:202
OperationExecutor::binding
PortState & binding(int io) const
OperationContext.hh
PortState.hh
OpcodeSettingVirtualInputPortState.hh
NullFUState::endClock
virtual void endClock()
Definition: FUState.cc:412
FUState::context
virtual OperationContext & context()
Definition: FUState.cc:376