OpenASIP 2.2
Loading...
Searching...
No Matches
ExecutionPipeline.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2009 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 ExecutionPipeline.cc
26 *
27 * Implementation of class ExecutionPipeline.
28 *
29 * @author Lasse Laasonen 2003 (lasse.laasonen-no.spam-tut.fi)
30 * @note rating: red
31 */
32
33#include "ExecutionPipeline.hh"
34#include "HWOperation.hh"
35#include "FunctionUnit.hh"
36#include "PipelineElement.hh"
37#include "FUPort.hh"
38#include "MachineTester.hh"
39#include "MOMTextGenerator.hh"
40#include "Application.hh"
41#include "ContainerTools.hh"
42#include "AssocTools.hh"
43#include "MapTools.hh"
44#include "ObjectState.hh"
45
46using std::string;
47using std::pair;
48using std::set;
49using boost::format;
50
51namespace TTAMachine {
52
53// initialization of static data members
54const string ExecutionPipeline::OSNAME_PIPELINE = "pipeline";
55const string ExecutionPipeline::OSNAME_RESOURCE_USAGE = "resource_usage";
56const string ExecutionPipeline::OSNAME_OPERAND_READ = "op_read";
57const string ExecutionPipeline::OSNAME_OPERAND_WRITE = "op_write";
58const string ExecutionPipeline::OSKEY_RESOURCE_NAME = "res_name";
59const string ExecutionPipeline::OSKEY_OPERAND = "operand";
60const string ExecutionPipeline::OSKEY_START_CYCLE = "start_cycle";
61const string ExecutionPipeline::OSKEY_CYCLES = "cycles";
62
63/**
64 * Constructor.
65 *
66 * @param parentOperation The parent operation which uses the pipeline.
67 */
69 SubComponent(), parent_(&parentOperation) {
70
71 // run time sanity check
73}
74
75
76/**
77 * Destructor.
78 */
82
83/**
84 * Returns the parent HWOperation.
85 *
86 * @return The parent.
87 */
88const HWOperation*
92
93/**
94 * Adds use for the given pipeline element.
95 *
96 * If the function unit does not have a pipeline element by the given name
97 * the pipeline element is added to the function unit. Pipeline is valid only
98 * if it starts at cycle 0 or 1.
99 *
100 * @param name Name of the pipeline element.
101 * @param start First cycle in which the element is used relative to
102 * operation start cycle.
103 * @param duration Number of cycles the element is used.
104 * @exception OutOfRange If given start cycle or duration is out of range.
105 * @exception InvalidName If the given name is not a valid component name.
106 * @exception StartTooLate If the pipeline does not start by resource usage
107 * or operand read at cycle 0 or 1.
108 * @exception NotAvailable If the given resource is already in use at a
109 * cycle in the given time interval.
110 */
111void
113 const std::string& name, int start, int duration) {
114 const string procName = "ExecutionPipeline::addResourceUse";
115
116 checkStartCycle(start);
117 checkDuration(duration);
118 checkResourceName(name);
119 checkResourceAvailability(name, start, duration);
120
121 internalAddResourceUse(name, start, duration);
122}
123
124/**
125 * Adds read usage of an operand.
126 *
127 * @param operand The operand to be read.
128 * @param start Start cycle of the usage.
129 * @param duration Duration of the usage.
130 * @exception OutOfRange If the given cycle is less than 0 or if duration or
131 * operand is less than 1.
132 * @exception WrongOperandType If the given operand is not an input operand,
133 * that is, if a port write is already added with
134 * the given operand.
135 * @exception StartTooLate If the pipeline does not start by resource usage
136 * or operand read at cycle 0 or 1.
137 * @exception NotAvailable If the given operand is already read at a cycle in
138 * the given time interval.
139 */
140void
141ExecutionPipeline::addPortRead(int operand, int start, int duration) {
142 const string procName = "ExecutionPipeline::addPortRead";
143
144 checkStartCycle(start);
145 checkDuration(duration);
146 checkInputOperand(operand);
147 checkOperandAvailability(operand, start, duration);
148
149 internalAddPortUse(operand, start, duration, opReads_);
150}
151
152/**
153 * Adds write usage of an operand.
154 *
155 * @param operand The operand to be written.
156 * @param start Start cycle of the usage.
157 * @param duration Duration of the usage.
158 * @exception OutOfRange If the given cycle is less than 0 or if duration or
159 * operand is less than 1.
160 * @exception WrongOperandType If the given operand is not an output operand,
161 * that is, if a port read is already added with
162 * the given operand.
163 * @exception NotAvailable If the given operand is already written at a cycle
164 * in the given time interval.
165 */
166void
167ExecutionPipeline::addPortWrite(int operand, int start, int duration) {
168 const string procName = "ExecutionPipeline::addPortWrite";
169
170 if (start < 0) {
171 throw OutOfRange(__FILE__, __LINE__, procName);
172 }
173
174 checkDuration(duration);
175 checkOutputOperand(operand);
176 checkOperandAvailability(operand, start, duration);
177
178 internalAddPortUse(operand, start, duration, opWrites_);
179}
180
181/**
182 * Removes any usage of given pipeline element in the pipeline.
183 *
184 * @param name Name of the pipeline element.
185 * @exception StartTooLate If the pipeline does not start by resource usage
186 * or operand read at cycle 0 or 1.
187 */
188void
189ExecutionPipeline::removeResourceUse(const std::string& name) {
190 const string procName = "ExecutionPipeline::removeResourceUse";
191
193 if (!fu->hasPipelineElement(name)) {
194 return;
195 }
196
197 if (firstCycleWithoutResource(name) > 1) {
198 throw StartTooLate(__FILE__, __LINE__, procName);
199 }
200
202}
203
204/**
205 * Removes any usage of given pipeline element in given cycle from the
206 * pipeline.
207 *
208 * @param name Name of the pipeline element.
209 * @param cycle Cycle in which element use is to be removed.
210 * @exception OutOfRange If the given cycle is negative.
211 * @exception StartTooLate If the pipeline does not start by resource usage
212 * or operand read at cycle 0 or 1.
213 */
214void
215ExecutionPipeline::removeResourceUse(const std::string& name, int cycle) {
216 const string procName = "ExecutionPipeline::removeResourceUse";
217
218 if (pipelineElement(name) == NULL) {
219 return;
220 }
221
222 if (cycle < 0) {
223 throw OutOfRange(__FILE__, __LINE__, procName);
224 }
225
226 if (latency() <= cycle) {
227 return;
228 }
229
230 if (cycle == 0 || cycle == 1) {
231 if (firstCycleWithoutResource(name, cycle) > 1) {
232 throw StartTooLate(__FILE__, __LINE__, procName);
233 }
234 }
235
236 internalRemoveResourceUse(name, cycle, 1);
237}
238
239/**
240 * Removes the all the usages of resources.
241 */
242void
244
246
247 resourceUsage_.clear();
248 opWrites_.clear();
249 opReads_.clear();
250
251 FunctionUnit* parent = parent_->parentUnit();
252
253 // clean up pipeline elements
254 for (ResourceSet::const_iterator iter = usedResources.begin();
255 iter != usedResources.end(); iter++) {
256 parent->cleanup((*iter)->name());
257 }
258}
259
260
261/**
262 * Removes reads and writes of the given operand at the given cycle.
263 *
264 * @param operand The operand.
265 * @param cycle The cycle.
266 * @exception OutOfRange If the given cycle is less than 0 or the given
267 * operand is smaller than 1.
268 * @exception StartTooLate If the pipeline does not start by resource usage
269 * or operand read at cycle 0 or 1.
270 */
271void
272ExecutionPipeline::removeOperandUse(int operand, int cycle) {
273 const string procName = "ExecutionPipeline::removeOperandUse";
274
275 if (cycle < 0 || operand < 1) {
276 throw OutOfRange(__FILE__, __LINE__, procName);
277 }
278
279 if (latency() <= cycle) {
280 return;
281 }
282
283 if (firstCycleWithoutOperandUse(operand, cycle) > 1) {
284 throw StartTooLate(__FILE__, __LINE__, procName);
285 }
286
287 internalRemoveOperandUse(operand, cycle, 1);
288}
289
290/**
291 * Tells whether a given pipeline element is used in the given cycle by this
292 * pipeline.
293 *
294 * @param name Name of the pipeline element.
295 * @param cycle Cycle in which element use is to be tested.
296 * @return True if the element is in use in the given cycle.
297 * @exception OutOfRange If the given cycle is negative.
298 */
299bool
300ExecutionPipeline::isResourceUsed(const std::string& name, int cycle) const {
301 if (cycle < 0) {
302 const string procName = "ExecutionPipeline::isResourceUsed";
303 throw OutOfRange(__FILE__, __LINE__, procName);
304 }
305
306 if (latency() <= cycle) {
307 return false;
308 }
309
310 PipelineElement* resource = pipelineElement(name);
311 if (resource == NULL) {
312 return false;
313 }
314
316 return (AssocTools::containsKey(usedResources, resource));
317}
318
319/**
320 * Returns the resource usages in the given cycle.
321 *
322 * @param cycle Cycle of which resource usages to return.
323 * @return True if the element is in use in the given cycle.
324 * @exception OutOfRange If the given cycle is negative.
325 */
328 if (cycle < 0) {
329 const string procName = "ExecutionPipeline::isResourceUsed";
330 throw OutOfRange(__FILE__, __LINE__, procName);
331 }
332
333 if (latency() <= cycle) {
334 return ResourceSet();
335 }
336
337 return resourceUsage_[cycle];
338}
339
340/**
341 * Checks whether the given port is used at the given cycle by the pipeline.
342 *
343 * @param port The port.
344 * @param cycle The cycle.
345 * @return True if the port is used, otherwise false.
346 * @exception OutOfRange If the given cycle is negative.
347 */
348bool
349ExecutionPipeline::isPortUsed(const FUPort& port, int cycle) const {
350 return isPortRead(port, cycle) || isPortWritten(port, cycle);
351}
352
353/**
354 * Checks whether the given port is read at the given cycle by the pipeline.
355 *
356 * @param port The port.
357 * @param cycle The cycle.
358 * @return True if the port is read, otherwise false.
359 * @exception OutOfRange If the given cycle is negative.
360 */
361bool
362ExecutionPipeline::isPortRead(const FUPort& port, int cycle) const {
363 if (cycle < 0) {
364 const string procName = "ExecutionPipeline::isPortRead";
365 throw OutOfRange(__FILE__, __LINE__, procName);
366 }
367
368 if (cycle >= latency()) {
369 return false;
370 }
371
373 return (isOperandBound(port, readOperands));
374}
375
376/**
377 * Checks whether the given port is written at the given cycle by the
378 * pipeline.
379 *
380 * @param port The port.
381 * @param cycle The cycle.
382 * @return True if the port is written, otherwise false.
383 * @exception OutOfRange If the given cycle is negative.
384 */
385bool
386ExecutionPipeline::isPortWritten(const FUPort& port, int cycle) const {
387 if (cycle < 0) {
388 const string procName = "ExecutionPipeline::isPortRead";
389 throw OutOfRange(__FILE__, __LINE__, procName);
390 }
391
392 if (cycle >= latency()) {
393 return false;
394 }
395
397 return (isOperandBound(port, writtenOperands));
398}
399
400/**
401 * Returns the operands that are read at the given cycle.
402 *
403 * @param cycle The cycle.
404 * @return Set of operand indexes.
405 * @exception OutOfRange If the cycle is smaller than 0.
406 */
409 if (cycle < 0) {
410 const string procName = "ExecutionPipeline::readOperands";
411 throw OutOfRange(__FILE__, __LINE__, procName);
412 }
413
414 if (cycle >= latency()) {
415 return OperandSet();
416 }
417
418 return opReads_[cycle];
419}
420
421/**
422 * Returns the operands that are written at the given cycle.
423 *
424 * @param cycle The cycle.
425 * @return Set of operand indexes.
426 * @exception OutOfRange If the given cycle is smaller than 0.
427 */
430 if (cycle < 0) {
431 const string procName = "ExecutionPipeline::readOperands";
432 throw OutOfRange(__FILE__, __LINE__, procName);
433 }
434
435 if (cycle >= latency()) {
436 return OperandSet();
437 }
438
439 return opWrites_[cycle];
440}
441
442/**
443 * Returns a set of operands that are read by this pipeline.
444 *
445 * @return The operand set.
446 */
449 OperandSet operands;
450 for (int i = 0; i < latency(); i++) {
451 OperandSet cycleOperands = readOperands(i);
452 operands.insert(cycleOperands.begin(), cycleOperands.end());
453 }
454 return operands;
455}
456
457
458/**
459 * Returns a set of operands that are written by this pipeline.
460 *
461 * @return The operand set.
462 */
465 OperandSet operands;
466 for (int i = 0; i < latency(); i++) {
467 OperandSet cycleOperands = writtenOperands(i);
468 operands.insert(cycleOperands.begin(), cycleOperands.end());
469 }
470 return operands;
471}
472
473
474/**
475 * Returns the latency of the pipeline.
476 *
477 * If the pipeline is totally empty, returns 0.
478 *
479 * @return The latency of the pipeline.
480 */
481int
483 assert(resourceUsage_.size() == opReads_.size());
484 assert(resourceUsage_.size() == opWrites_.size());
485 return resourceUsage_.size();
486}
487
488
489/**
490 * Returns the latency for the given output.
491 *
492 * @param output The number of the output.
493 * @return The latency for the given output.
494 * @exception IllegalParameters If the given output is not written in the
495 * pipeline.
496 */
497int
498ExecutionPipeline::latency(int output) const {
499 int cycle = latency();
500 for (IOUsage::const_reverse_iterator iter = opWrites_.rbegin();
501 iter != opWrites_.rend(); iter++) {
502 if (AssocTools::containsKey(*iter, output)) {
503 return cycle;
504 }
505 cycle--;
506 }
507
508 const string msg =
509 (boost::format("Latency for operand index %d was not found for "
510 "operation '%s' on unit '%s'!") % output % parent_->name()
511 % parent_->parentUnit()->name()).str();
512 throw IllegalParameters(__FILE__, __LINE__, __func__, msg);
513}
514
515/**
516 * Returns the slack of the given input.
517 *
518 * The slack tells how many cycles AFTER the trigger, opcode-setting move is
519 * scheduled, can the operand be scheduled (and still affect correctly the
520 * result of the operation).
521 *
522 * @param input The number of the input.
523 * @return The slack of the given input.
524 * @exception IllegalParameters If the given input is not read in the
525 * pipeline.
526 */
527int
528ExecutionPipeline::slack(int input) const {
529 int slack(0);
530 for (IOUsage::const_iterator iter = opReads_.begin();
531 iter != opReads_.end(); iter++) {
532 if (AssocTools::containsKey(*iter, input)) {
533 return slack;
534 }
535 slack++;
536 }
537
538 const string errMessage = "Propably broken operand binding in operation:"
539 + parent_->name() + " in FU: " + parent_->parentUnit()->name();
540
541 const string procName = "ExecutionPipeline::slack";
542 throw IllegalParameters(__FILE__, __LINE__, procName, errMessage);
543}
544
545/**
546 * Saves the pipeline to ObjectState tree.
547 *
548 * @return The newly created ObjectState tree.
549 */
552
553 ObjectState* pipelineState = new ObjectState(OSNAME_PIPELINE);
554
555 // save resources usages in different ObjectState instances
556 int cycle = 0;
557 for (ResourceUsage::const_iterator resUsageIter = resourceUsage_.begin();
558 resUsageIter != resourceUsage_.end(); resUsageIter++) {
559
560 ResourceSet cycleUsage = *resUsageIter;
561 for (ResourceSet::const_iterator cycleUsageIter = cycleUsage.begin();
562 cycleUsageIter != cycleUsage.end(); cycleUsageIter++) {
563 PipelineElement* element = *cycleUsageIter;
564 saveResourceUse(element, cycle, pipelineState);
565 }
566 cycle++;
567 }
568
569 // save operand reads in different ObjectState instances
570 cycle = 0;
571 for (IOUsage::const_iterator readsIter = opReads_.begin();
572 readsIter != opReads_.end(); readsIter++) {
573
574 OperandSet operands = *readsIter;
575 for (OperandSet::const_iterator opIter = operands.begin();
576 opIter != operands.end(); opIter++) {
577 int operand = *opIter;
579 operand, cycle, pipelineState, OSNAME_OPERAND_READ);
580 }
581 cycle++;
582 }
583
584 // save operand writes in different ObjectState instances
585 cycle = 0;
586 for (IOUsage::const_iterator writesIter = opWrites_.begin();
587 writesIter != opWrites_.end(); writesIter++) {
588
589 OperandSet operands = *writesIter;
590 for (OperandSet::const_iterator opIter = operands.begin();
591 opIter != operands.end(); opIter++) {
592 int operand = *opIter;
594 operand, cycle, pipelineState, OSNAME_OPERAND_WRITE);
595 }
596 cycle++;
597 }
598
599 return pipelineState;
600}
601
602
603/**
604 * Loads the state of pipeline from the given ObjectState tree.
605 *
606 * @param pipelineState An ObjectState tree representing state of a pipeline.
607 * @exception ObjectStateLoadingException If an error occurs while loading
608 * state.
609 */
610void
612 const string procName = "ExecutionPipeline::loadState";
613
614 if (pipelineState->name() != OSNAME_PIPELINE) {
615 throw ObjectStateLoadingException(__FILE__, __LINE__, procName);
616 }
617
619 ObjectStateTable childTable = sortResourceUsages(pipelineState);
620 MOMTextGenerator textGen;
621
622 try {
623 for (ObjectStateTable::const_iterator iter = childTable.begin();
624 iter != childTable.end(); iter++) {
625 const ObjectState* usage = *iter;
626 int startCycle = usage->intAttribute(OSKEY_START_CYCLE);
627 int cycles = usage->intAttribute(OSKEY_CYCLES);
628 int operand = 0;
629 string resourceName;
630
631 try {
632
633 if (usage->name() == OSNAME_RESOURCE_USAGE) {
634 resourceName = usage->stringAttribute(
636 addResourceUse(resourceName, startCycle, cycles);
637 } else if (usage->name() == OSNAME_OPERAND_READ) {
638 operand = usage->intAttribute(OSKEY_OPERAND);
639 addPortRead(operand, startCycle, cycles);
640 } else if (usage->name() == OSNAME_OPERAND_WRITE) {
641 operand = usage->intAttribute(OSKEY_OPERAND);
642 addPortWrite(operand, startCycle, cycles);
643 } else {
645 __FILE__, __LINE__, procName);
646 }
647
648 } catch (const WrongOperandType&) {
649 format errorMsg = textGen.text(
651 errorMsg % operand % parent_->name() %
652 parent_->parentUnit()->name();
654 __FILE__, __LINE__, procName, errorMsg.str());
655
656 } catch (const InvalidName&) {
657 format errorMsg = textGen.text(
659 errorMsg % resourceName;
661 __FILE__, __LINE__, procName, errorMsg.str());
662
663 } catch (const StartTooLate&) {
664 format errorMsg = textGen.text(
666 errorMsg % parent_->name() % parent_->parentUnit()->name() %
667 startCycle;
669 __FILE__, __LINE__, procName, errorMsg.str());
670
671 } catch (const NotAvailable&) {
672 format errorMsg = textGen.text(
674 errorMsg % parent_->name() % parent_->parentUnit()->name();
676 __FILE__, __LINE__, errorMsg.str());
677 }
678 }
679
680 } catch (const Exception& exception) {
682 __FILE__, __LINE__, procName, exception.errorMessage());
683 }
684}
685
686/**
687 * Compares two ExecutionPipeline architectures.
688 *
689 * @param pipeline ExecutionPipeline to compare with.
690 * @return True if the two ExecutionPipeline architectures are equal.
691 */
692bool
694 const ExecutionPipeline* pipeline) const {
695
696 for (unsigned int i = 0; i < resourceUsage_.size(); i++) {
697 ResourceSet::const_iterator iter = resourceUsage_[i].begin();
698 for (; iter != resourceUsage_[i].end(); iter++) {
699 if (!pipeline->isResourceUsed((*iter)->name(), i)) {
700 return false;
701 }
702 }
703 }
704 if (readOperands() != pipeline->readOperands()) {
705 return false;
706 }
707 if (writtenOperands() != pipeline->writtenOperands()) {
708 return false;
709 }
710 return true;
711}
712
713
714/**
715 * Checks whether the pipeline would start too late if a new resource usage
716 * or operand read was added starting at given cycle.
717 *
718 * @param startCycle The start cycle.
719 * @exception OutOfRange If the given cycle is negative.
720 * @exception StartTooLate If the pipeline would start too late.
721 */
722void
724 const string procName = "ExecutionPipeline::checkStartCycle";
725
726 if (startCycle < 0) {
727 throw OutOfRange(__FILE__, __LINE__, procName);
728 }
729
730 if (startCycle > 1) {
731 if (latency() == 0) {
732 throw StartTooLate(__FILE__, __LINE__, procName);
733 } else if (latency() == 1 && resourceUsage_[0].empty() &&
734 opReads_[0].empty()) {
735 throw StartTooLate(__FILE__, __LINE__, procName);
736 } else if (latency() >= 2 && resourceUsage_[0].empty() &&
737 resourceUsage_[1].empty() && opReads_[0].empty() &&
738 opReads_[1].empty()) {
739 throw StartTooLate(__FILE__, __LINE__, procName);
740 }
741 }
742}
743
744/**
745 * Checks whether the given value is valid for duration of resource usage.
746 *
747 * @param duration The duration value.
748 * @exception OutOfRange If the value is not in a valid range.
749 */
750void
752 if (duration < 1) {
753 const string procName = "ExecutionPipeline::checkDuration";
754 throw OutOfRange(__FILE__, __LINE__, procName);
755 }
756}
757
758/**
759 * Checks whether the given name is valid for pipeline resource.
760 *
761 * @param name The name.
762 * @exception InvalidName If the name is not valid for pipeline resource.
763 */
764void
765ExecutionPipeline::checkResourceName(const std::string& name) {
767 const string procName = "ExecutionPipeline::checkResourceName";
768 throw InvalidName(__FILE__, __LINE__, procName);
769 }
770}
771
772/**
773 * Checks whether the given operand is an input operand.
774 *
775 * The operand is an input operand if it is read by the pipeline already.
776 *
777 * @param operand The operand.
778 * @exception OutOfRange If the given operand is smaller than 1.
779 * @exception WrongOperandType If the operand is written by the pipeline.
780 */
781void
783 const string procName = "ExecutionPipeline::checkInputOperand";
784
785 if (operand < 1) {
786 throw OutOfRange(__FILE__, __LINE__, procName);
787 }
788
789 if (isOperandWritten(operand)) {
790 throw WrongOperandType(__FILE__, __LINE__, procName);
791 }
792}
793
794/**
795 * Checks whether the given operand is an output operand.
796 *
797 * The operand is an output operand if it is written by the pipeline already.
798 *
799 * @param operand The operand.
800 * @exception OutOfRange If the given operand is smaller than 1.
801 * @exception WrongOperandType If the operand is read by the pipeline.
802 */
803void
805 const string procName = "ExecutionPipeline::checkOutputOperand";
806
807 if (operand < 1) {
808 throw OutOfRange(__FILE__, __LINE__, procName);
809 }
810
811 if (isOperandRead(operand)) {
812 throw WrongOperandType(__FILE__, __LINE__, procName);
813 }
814}
815
816/**
817 * Checks whether the given resource is available all the time of the given
818 * time interval.
819 *
820 * @param resource Name of the pipeline resource.
821 * @param start The start cycle.
822 * @param duration Duration of the usage.
823 * @exception NotAvailable If the given resource is not available.
824 */
825void
827 const std::string& resource, int start, int duration) const {
828 PipelineElement* element = pipelineElement(resource);
829 if (element == NULL) {
830 return;
831 }
832
833 int end = start + duration - 1;
834 if (end >= latency()) {
835 end = latency() - 1;
836 }
837
838 for (int cycle = start; cycle <= end; cycle++) {
839 if (AssocTools::containsKey(resourceUsage_[cycle], element)) {
840 const string procName =
841 "ExecutionPipeline::checkResourceAvailability";
842 throw NotAvailable(__FILE__, __LINE__, procName);
843 }
844 }
845}
846
847/**
848 * Checks whether the given operand is not read or written at the given time
849 * interval.
850 *
851 * @param operand The operand.
852 * @param start The start cycle.
853 * @param duration Duration of the usage.
854 * @exception NotAvailable If the given operand is used at the given time
855 * interval.
856 */
857void
859 int operand, int start, int duration) const {
860 int end = start + duration - 1;
861 if (end >= latency()) {
862 end = latency() - 1;
863 }
864
865 for (int cycle = start; cycle <= end; cycle++) {
866 if (AssocTools::containsKey(opReads_[cycle], operand) ||
867 AssocTools::containsKey(opWrites_[cycle], operand)) {
868 const string procName =
869 "ExecutionPipeline::checkOperandAvailability";
870 throw NotAvailable(__FILE__, __LINE__, procName);
871 }
872 }
873}
874
875/**
876 * Internally adds the resource usage of the given resource at the given
877 * time interval.
878 *
879 * @param name Name of the resource.
880 * @param start The start cycle.
881 * @param duration The duration of the usage.
882 */
883void
885 const std::string& name,
886 int start,
887 int duration) {
888
889 PipelineElement* used = pipelineElement(name);
890 if (used == NULL) {
891 used = addPipelineElement(name);
892 }
893
894 adjustLatency(start + duration);
895
896 for (int cycle = start; cycle < start + duration; cycle++) {
897 resourceUsage_[cycle].insert(used);
898 }
899}
900
901
902/**
903 * Internally adds use of the given operand.
904 *
905 * @param operand The operand to add the usage for.
906 * @param start The start cycle of the operand usage.
907 * @param duration Duration of the operand usage.
908 * @param toModify The IOUsage to modify.
909 */
910void
912 int operand,
913 int start,
914 int duration,
915 IOUsage& toModify) {
916
917 if (start + duration > latency()) {
918 adjustLatency(start + duration);
919 }
920
921 for (int cycle = start; cycle < start + duration; cycle++) {
922 toModify[cycle].insert(operand);
923 }
924}
925
926
927/**
928 * Internally removes the resource usage of the given resource at the given
929 * time interval.
930 *
931 * @param name Name of the resource.
932 * @param start The start cycle.
933 * @param duration The duration of the usage to be removed.
934 */
935void
937 const std::string& name,
938 int start,
939 int duration) {
940
941 PipelineElement* toRemove = pipelineElement(name);
942 if (toRemove == NULL) {
943 return;
944 }
945
946 int end = start + duration - 1;
947 if (end >= latency()) {
948 end = latency() - 1;
949 }
950
951 for (int cycle = start; cycle <= end; cycle++) {
953 }
954
955 adjustLatency(0);
956
958 fu->cleanup(name);
959}
960
961
962/**
963 * Internally removes the operand usage of the given operand at the given
964 * time interval.
965 *
966 * @param operand The operand.
967 * @param start The start cycle.
968 * @param duration The duration of the usage to be removed.
969 */
970void
972 int operand,
973 int start,
974 int duration) {
975
976 int end = start + duration - 1;
977 if (end >= latency()) {
978 end = latency() - 1;
979 }
980
981 for (int cycle = start; cycle <= end; cycle++) {
984 }
985
986 adjustLatency(0);
987}
988
989
990/**
991 * Adjusts the size of usage vectors for the given latency.
992 *
993 * If the given latency is greater than the current latency, sizes of
994 * the usage vectors are increased. If the given latency is smaller
995 * than the current latency (vector size), sizes of the vectors are
996 * tried to decrease to match with the given latency. However, if
997 * there are non-empty elements in the usage vectors, they are not
998 * removed.
999 *
1000 * @param newLatency The new latency.
1001 */
1002void
1004
1005 if (newLatency > latency()) {
1006 resourceUsage_.resize(newLatency);
1007 opReads_.resize(newLatency);
1008 opWrites_.resize(newLatency);
1009
1010 } else if (newLatency < latency()) {
1011 for (int cycle = latency() - 1; cycle >= newLatency; cycle--) {
1012 if (resourceUsage_[cycle].empty() && opReads_[cycle].empty() &&
1013 opWrites_[cycle].empty()) {
1014 resourceUsage_.resize(cycle);
1015 opReads_.resize(cycle);
1016 opWrites_.resize(cycle);
1017 } else {
1018 break;
1019 }
1020 }
1021 }
1022}
1023
1024
1025/**
1026 * Checks whether the given port is bound to one of the operands in the given
1027 * operand set.
1028 *
1029 * @param port The port.
1030 * @param operands The operands.
1031 * @return True if at least one of the operands is bound to the given port,
1032 * otherwise false.
1033 */
1034bool
1036 const FUPort& port,
1037 const OperandSet& operands) const {
1038
1039 for (OperandSet::const_iterator iter = operands.begin();
1040 iter != operands.end(); iter++) {
1041 if (parent_->port(*iter) == &port) {
1042 return true;
1043 }
1044 }
1045
1046 return false;
1047}
1048
1049
1050/**
1051 * Checks whether the given operand is written by the pipeline.
1052 *
1053 * @param operand The operand.
1054 * @return True if the operand is written, otherwise false.
1055 */
1056bool
1058 int latency = this->latency();
1059 for (int cycle = 0; cycle < latency; cycle++) {
1060 OperandSet cycleWrites = opWrites_[cycle];
1061 if (AssocTools::containsKey(cycleWrites, operand)) {
1062 return true;
1063 }
1064 }
1065 return false;
1066}
1067
1068
1069/**
1070 * Checks whether the given operand is read by the pipeline.
1071 *
1072 * @param operand The operand.
1073 * @return True if the operand is read, otherwise false.
1074 */
1075bool
1077 int latency = this->latency();
1078 for (int cycle = 0; cycle < latency; cycle++) {
1079 OperandSet cycleReads = opReads_[cycle];
1080 if (AssocTools::containsKey(cycleReads, operand)) {
1081 return true;
1082 }
1083 }
1084 return false;
1085}
1086
1087
1088/**
1089 * Returns the first cycle when a resource is used or a port read by this
1090 * pipeline.
1091 *
1092 * Returns -1 if no resource is used or port read by this pipeline.
1093 *
1094 * @return The first cycle or -1.
1095 */
1096int
1098
1099 int latency = this->latency();
1100
1101 for (int cycle = 0; cycle < latency; cycle++) {
1102 if (!resourceUsage_[cycle].empty() || !opReads_[cycle].empty()) {
1103 return cycle;
1104 }
1105 }
1106
1107 return -1;
1108}
1109
1110
1111/**
1112 * Returns the first cycle when a resource is used or port read by this
1113 * pipeline if the given pipeline resource is not used.
1114 *
1115 * Returns -1 if no resource is used or port read.
1116 *
1117 * @param resource Name of the pipeline resource.
1118 * @return The first cycle or -1.
1119 */
1120int
1122 const std::string& resource) const {
1123
1124 PipelineElement* element = pipelineElement(resource);
1125 if (element == NULL) {
1126 return firstCycle();
1127 }
1128
1129 int latency = this->latency();
1130 for (int i = 0; i < latency; i++) {
1131 if (!opReads_[i].empty()) {
1132 return i;
1133 }
1134 if (resourceUsage_[i].size() > 1 ||
1135 (resourceUsage_[i].size() == 1 &&
1136 !AssocTools::containsKey(resourceUsage_[i], element))) {
1137 return i;
1138 }
1139 }
1140
1141 return -1;
1142}
1143
1144
1145/**
1146 * Returns the first cycle when a resource is used or port read if usage of
1147 * the given resource is removed from the given cycle.
1148 *
1149 * Returns -1 if no resource is used or port read.
1150 *
1151 * @param resource Name of the pipeline resource.
1152 * @param cycle The cycle when the pipeline resource is not used.
1153 * @return The first cycle or -1.
1154 */
1155int
1157 const std::string& resource,
1158 int cycle) const {
1159
1160 int currentFirstCycle = firstCycle();
1161 if (currentFirstCycle != cycle) {
1162 return currentFirstCycle;
1163 }
1164
1165 PipelineElement* element = pipelineElement(resource);
1166 if (element == NULL) {
1167 return currentFirstCycle;
1168 }
1169
1170 if (!opReads_[cycle].empty()) {
1171 return cycle;
1172 }
1173 if (resourceUsage_[cycle].size() > 1 ||
1174 (resourceUsage_[cycle].size() == 1 &&
1175 !AssocTools::containsKey(resourceUsage_[cycle], element))) {
1176 return cycle;
1177 }
1178
1179 int latency = this->latency();
1180 for (int i = cycle + 1; i < latency; i++) {
1181 if (!opReads_[i].empty() || !resourceUsage_[i].empty()) {
1182 return i;
1183 }
1184 }
1185
1186 return -1;
1187}
1188
1189
1190/**
1191 * Returns the first cycle when a resource is used or port read if usage of
1192 * the given operand is removed from the given cycle.
1193 *
1194 * Returns -1 if no resource is used.
1195 *
1196 * @param operand The operand.
1197 * @param cycle The cycle.
1198 * @return The first cycle or -1.
1199 */
1200int
1202 int operand,
1203 int cycle) const {
1204
1205 int currentFirstCycle = firstCycle();
1206 if (currentFirstCycle != cycle) {
1207 return currentFirstCycle;
1208 }
1209
1210
1211 if (opReads_[cycle].size() > 1 ||
1212 (opReads_[cycle].size() == 1 &&
1213 !AssocTools::containsKey(opReads_[cycle], operand))) {
1214 return cycle;
1215 }
1216
1217 if (!resourceUsage_[cycle].empty()) {
1218 return cycle;
1219 }
1220
1221 int latency = this->latency();
1222 for (int i = cycle + 1; i < latency; i++) {
1223 if (!resourceUsage_[i].empty() || !opReads_[i].empty()) {
1224 return i;
1225 }
1226 }
1227
1228 return -1;
1229}
1230
1231
1232/**
1233 * Returns the pipeline resources used by this pipeline.
1234 *
1235 * @return The pipeline resources used by this pipeline.
1236 */
1239
1240 ResourceSet resources;
1241 int latency = this->latency();
1242
1243 for (int cycle = 0; cycle < latency; cycle++) {
1244 ResourceSet cycleResources = resourceUsage_[cycle];
1245 resources.insert(cycleResources.begin(), cycleResources.end());
1246 }
1247
1248 return resources;
1249}
1250
1251
1252/**
1253 * Returns the pipeline element by the given name.
1254 *
1255 * @param name The name.
1256 * @return The pipeline element or NULL if there is no such pipeline element.
1257 */
1259ExecutionPipeline::pipelineElement(const std::string& name) const {
1261 return fu->pipelineElement(name);
1262}
1263
1264
1265/**
1266 * Creates a pipeline element by the given name.
1267 *
1268 * @param name The name of the pipeline element.
1269 * @return The pipeline element that was created.
1270 */
1272ExecutionPipeline::addPipelineElement(const std::string& name) const {
1274 if (!fu->hasPipelineElement(name)) {
1275 new PipelineElement(name, *fu);
1276 }
1277 return fu->pipelineElement(name);
1278}
1279
1280
1281/**
1282 * Saves usage of a pipeline element to ObjectState tree.
1283 *
1284 * @param element The pipelineElement used.
1285 * @param cycleToSave The cycle to save.
1286 * @param pipelineState ObjectState instance representing the state of the
1287 * pipeline.
1288 */
1289void
1291 const PipelineElement* element,
1292 int cycleToSave,
1293 ObjectState* pipelineState) {
1294
1295 string elementName = element->name();
1296 bool resourceFound = false;
1297
1298 for (int i = 0; i < pipelineState->childCount(); i++) {
1299 ObjectState* child = pipelineState->child(i);
1300 if (child->name() == OSNAME_RESOURCE_USAGE &&
1301 child->stringAttribute(OSKEY_RESOURCE_NAME) == elementName) {
1302
1303 int cycles = child->intAttribute(OSKEY_CYCLES);
1304 if (child->intAttribute(OSKEY_START_CYCLE) + cycles ==
1305 cycleToSave) {
1306 child->setAttribute(OSKEY_CYCLES, cycles + 1);
1307 resourceFound = true;
1308 break;
1309 }
1310 }
1311 }
1312
1313 if (!resourceFound) {
1315 pipelineState->addChild(resource);
1316 resource->setAttribute(OSKEY_RESOURCE_NAME, elementName);
1317 resource->setAttribute(OSKEY_START_CYCLE, cycleToSave);
1318 resource->setAttribute(OSKEY_CYCLES, 1);
1319 }
1320}
1321
1322
1323/**
1324 * Saves use of an operand to ObjectState tree.
1325 *
1326 * @param operand The operand.
1327 * @param cycleToSave The cycle to save.
1328 * @param pipelineState ObjectState instance representing the state of the
1329 * pipeline.
1330 * @param osName Name of the ObjectState instance in which to save the
1331 * operand use.
1332 */
1333void
1335 int operand,
1336 int cycleToSave,
1337 ObjectState* pipelineState,
1338 const std::string& osName) {
1339
1340 bool found = false;
1341
1342 for (int i = 0; i < pipelineState->childCount(); i++) {
1343 ObjectState* child = pipelineState->child(i);
1344 if (child->name() == osName &&
1345 child->intAttribute(OSKEY_OPERAND) == operand) {
1346
1347 int cycles = child->intAttribute(OSKEY_CYCLES);
1348 if (child->intAttribute(OSKEY_START_CYCLE) + cycles ==
1349 cycleToSave) {
1350 child->setAttribute(OSKEY_CYCLES, cycles + 1);
1351 found = true;
1352 break;
1353 }
1354 }
1355 }
1356
1357 if (!found) {
1358 ObjectState* operandUsage = new ObjectState(osName);
1359 pipelineState->addChild(operandUsage);
1360 operandUsage->setAttribute(OSKEY_OPERAND, operand);
1361 operandUsage->setAttribute(OSKEY_START_CYCLE, cycleToSave);
1362 operandUsage->setAttribute(OSKEY_CYCLES, 1);
1363 }
1364}
1365
1366
1367/**
1368 * Sorts the resource and operand usages by the start cycle of the usage.
1369 *
1370 * @param pipelineState An ObjectState instance representing an execution
1371 * pipeline.
1372 * @return A vector of ObjectState instances each of them representing a
1373 * resource or operand usage.
1374 * @exception ObjectStateLoadingException If the given ObjectState instance
1375 * is invalid.
1376 */
1379 ObjectStateTable usages;
1380 for (int i = 0; i < pipelineState->childCount(); i++) {
1381 ObjectState* usageState = pipelineState->child(i);
1382 addResourceUsage(usages, usageState);
1383 }
1384
1385 return usages;
1386}
1387
1388/**
1389 * Adds the given ObjectState instance representing a resource usage to the
1390 * given set of usages to correct position.
1391 *
1392 * The correct position is determined by the start cycle of the resource
1393 * usage.
1394 *
1395 * @param usages The set of resource usages where to add the given usage.
1396 * @param usageState The usageState to add.
1397 * @exception ObjectStateLoadingException If the given ObjectState instance
1398 * is invalid.
1399 */
1400void
1402 ObjectStateTable& usages, const ObjectState* usageState) const {
1403 try {
1404 int startCycle = usageState->intAttribute(OSKEY_START_CYCLE);
1405 for (ObjectStateTable::iterator iter = usages.begin();
1406 iter != usages.end(); iter++) {
1407 const ObjectState* usage = *iter;
1408 int usageStart = usage->intAttribute(OSKEY_START_CYCLE);
1409 if (startCycle < usageStart) {
1410 usages.insert(iter, usageState);
1411 return;
1412 }
1413 }
1414 } catch (const Exception& exception) {
1415 string procName = "ExecutionPipeline::addResourceUsage";
1417 __FILE__, __LINE__, procName, exception.errorMessage());
1418 }
1419
1420 usages.push_back(usageState);
1421}
1422}
#define __func__
#define assert(condition)
static bool containsKey(const ContainerType &aContainer, const KeyType &aKey)
static bool removeValueIfExists(ContainerType &aContainer, const ElementType &aKey)
std::string errorMessage() const
Definition Exception.cc:123
static bool isValidComponentName(const std::string &name)
void setAttribute(const std::string &name, const std::string &value)
ObjectState * child(int index) const
void addChild(ObjectState *child)
std::string stringAttribute(const std::string &name) const
int intAttribute(const std::string &name) const
std::string name() const
int childCount() const
virtual TCEString name() const
void checkOutputOperand(int operand) const
ExecutionPipeline(HWOperation &parentOperation)
OperandSet writtenOperands(int cycle) const
ObjectStateTable sortResourceUsages(const ObjectState *pipelineState) const
static void checkResourceName(const std::string &name)
void loadState(const ObjectState *state)
bool isPortUsed(const FUPort &port, int cycle) const
static void checkDuration(int duration)
bool isArchitectureEqual(const ExecutionPipeline *pipeline) const
std::vector< const ObjectState * > ObjectStateTable
Vector for ObjectState pointers.
void addResourceUse(const std::string &name, int start, int duration)
void checkInputOperand(int operand) const
void internalRemoveOperandUse(int operand, int start, int duration)
PipelineElement * pipelineElement(const std::string &name) const
static const std::string OSKEY_RESOURCE_NAME
ObjectState attribute key for name of resource.
void addResourceUsage(ObjectStateTable &usages, const ObjectState *usageState) const
static const std::string OSNAME_OPERAND_WRITE
ObjectState name for operand write.
int firstCycleWithoutOperandUse(int operand, int cycle) const
void internalRemoveResourceUse(const std::string &name, int start, int duration)
void addPortRead(int operand, int start, int duration)
bool isOperandWritten(int operand) const
void removeOperandUse(int operand, int cycle)
OperandSet readOperands(int cycle) const
IOUsage opWrites_
Operand writes.
std::set< int > OperandSet
Set for operand indexes.
static void saveOperandUse(int operand, int cycleToSave, ObjectState *pipelineState, const std::string &osName)
static const std::string OSKEY_START_CYCLE
ObjectState attribute key for start cycle of a resource usage.
bool isOperandBound(const FUPort &port, const OperandSet &operands) const
void checkStartCycle(int startCycle) const
static const std::string OSKEY_OPERAND
ObjectState attribute key for operand number.
HWOperation * parent_
The parent operation.
void internalAddResourceUse(const std::string &name, int start, int duration)
static const std::string OSNAME_OPERAND_READ
ObjectState name for operand read.
void internalAddPortUse(int operand, int start, int duration, IOUsage &toModify)
ResourceSet resourceUsages(int cycle) const
void addPortWrite(int operand, int start, int duration)
bool isPortWritten(const FUPort &port, int cycle) const
bool isPortRead(const FUPort &port, int cycle) const
void removeResourceUse(const std::string &name)
int firstCycleWithoutResource(const std::string &resource) const
void checkOperandAvailability(int operand, int start, int duration) const
bool isResourceUsed(const std::string &name, int cycle) const
static const std::string OSNAME_PIPELINE
ObjectState name for ExecutionPipeline.
static const std::string OSNAME_RESOURCE_USAGE
ObjectState name for pipeline resource usage.
std::set< PipelineElement *, PipelineElement::Comparator > ResourceSet
Set for pipeline elements.
static const std::string OSKEY_CYCLES
ObjectState attribute key for duration of a resource usage.
ResourceUsage resourceUsage_
Resource usage.
bool isOperandRead(int operand) const
const HWOperation * parentOperation() const
void checkResourceAvailability(const std::string &resource, int start, int duration) const
std::vector< OperandSet > IOUsage
Vector for operand sets.
static void saveResourceUse(const PipelineElement *element, int cycleToSave, ObjectState *pipelineState)
PipelineElement * addPipelineElement(const std::string &name) const
virtual bool hasPipelineElement(const std::string &name) const
virtual void cleanup(const std::string &resource)
virtual PipelineElement * pipelineElement(int index) const
ExecutionPipeline * pipeline() const
virtual FUPort * port(int operand) const
const std::string & name() const
FunctionUnit * parentUnit() const
const std::string & name() const
virtual boost::format text(int textId)