OpenASIP 2.2
Loading...
Searching...
No Matches
Program.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2016 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 Program.cc
26 *
27 * Implementation of Program class.
28 *
29 * @author Ari Metsähalme 2005 (ari.metsahalme-no.spam-tut.fi)
30 * @author Pekka Jääskeläinen 2006,2011,2016 (pekka.jaaskelainen-no.spam-tut.fi)
31 * @note rating: red
32 */
33
34#include <string>
35
36#include "Program.hh"
37#include "NullInstruction.hh"
38#include "Procedure.hh"
39#include "NullProcedure.hh"
40#include "CodeLabel.hh"
41#include "Terminal.hh"
42#include "TerminalAddress.hh"
43#include "Move.hh"
46#include "NullProgram.hh"
47#include "AddressSpace.hh"
48#include "DataMemory.hh"
49#include "DataDefinition.hh"
51#include "AssocTools.hh"
52#include "ControlUnit.hh"
53#include "UniversalMachine.hh"
54#include "SequenceTools.hh"
55#include "DataLabel.hh"
56#include "BinaryStream.hh"
57#include "BinaryReader.hh"
58#include "TPEFProgramFactory.hh"
59#include "UniversalMachine.hh"
60#include "Application.hh"
61#include "ProgramWriter.hh"
62#include "BinaryWriter.hh"
63#include "TPEFWriter.hh"
64#include "Immediate.hh"
65#include "MathTools.hh"
67#include "POMDisassembler.hh"
68#include "hash_set.hh"
69#include "GlobalScope.hh"
70
71using std::string;
72
73using namespace TTAMachine;
74
75namespace TTAProgram {
76
77/////////////////////////////////////////////////////////////////////////////
78// Program
79/////////////////////////////////////////////////////////////////////////////
80
81/**
82 * Constructor.
83 *
84 * Creates an empty program in given address space. A default value
85 * zero is used for start and entry addresses. Automatically creates
86 * an empty global scope to store all program symbols with external
87 * linkage.
88 *
89 * @param space The address space of the program.
90 */
92 start_(0, space), entry_(0, space), umach_(NULL), finalized_(false),
93 instructionPerAddress_(true) {
96}
97
98/**
99 * Deprecated.
100 *
101 * Use UniversalMachine::instance() directly.
102 */
107
108/**
109 * Constructor.
110 *
111 * Alternative constructor that takes the start address as a parameter.
112 *
113 * @param space The address space of the program.
114 * @param start The start address of the program.
115 */
117 start_(start), entry_(0, space), umach_(NULL), finalized_(false),
118 instructionPerAddress_(true) {
121}
122
123/**
124 * Constructor.
125 *
126 * Alternative constructor that takes the start and entry addresses as
127 * parameters.
128 *
129 * @param space The address space of the program.
130 * @param start The start address of the program.
131 * @param entry The entry address of the program.
132 */
134 const AddressSpace&, Address start, Address entry):
135 start_(start), entry_(entry), umach_(NULL), finalized_(false),
136 instructionPerAddress_(true) {
139}
140
141/**
142 * The destructor.
143 */
145 cleanup();
146 delete globalScope_;
147 globalScope_ = NULL;
148 delete refManager_;
149 refManager_ = NULL;
150 // NOTE: we cannot delete universal machine anymore because after linking
151 // the Program to another Program, the new Program refers to the,
152 // TODO: make UniversalMachine a singleton and start hiding it from APIs.
153 // delete umach_;
154 // umach_ = NULL;
155}
156
157/**
158 * Cleans up the program to a state it was at the construction.
159 */
160void
173
174/**
175 * Returns the global scope of the program.
176 *
177 * @return The global scope of the program.
178 */
181 return *globalScope_;
182}
183
184/**
185 * Returns the global scope of the program.
186 *
187 * Const version.
188 *
189 * @return The global scope of the program.
190 */
191const GlobalScope&
193 return *globalScope_;
194}
195
196/**
197 * Returns the target TTA processor of the program.
198 *
199 * @return The target TTA processor of the program.
200 */
201Machine&
203 return *start_.space().machine();
204}
205
206/**
207 * Returns the first procedure of the program.
208 *
209 * @return The first procedure of the prgram.
210 * @exception InstanceNotFound if there are no procedures.
211 */
214 if (procedureCount() > 0) {
215 return *procedures_.at(0);
216 } else {
217 throw InstanceNotFound(
218 __FILE__, __LINE__, __func__,
219 "There are no procedures in the program.");
220 }
221}
222
223/**
224 * Returns the last procedure of the program.
225 *
226 * @return The last procedure of the prgram.
227 * @exception InstanceNotFound if there are no procedures.
228 */
231 if (procedureCount() > 0) {
232 return *procedures_.at(procedureCount() - 1);
233 } else {
234 throw InstanceNotFound(
235 __FILE__, __LINE__, __func__,
236 "There are no procedures in the program.");
237 }
238}
239
240/**
241 * Returns the procedure following the given procedure.
242 *
243 * @return The procedure following the given procedure or a null procedure,
244 * if the given procedure is the last procedure in the program.
245 * @param proc The following procedure of this parameter is returned.
246 * @exception IllegalRegistration if the given procedure does not belong
247 * to this program.
248 */
251 if (!proc.isInProgram() || &proc.parent() != this) {
253 __FILE__, __LINE__, __func__,
254 "The procedure given in parameter doesn't "
255 "belong to this program.");
256 }
257
258 if (&proc != &lastProcedure()) {
259 int i = 0;
260 for (; i < procedureCount(); i++) {
261 if (procedures_.at(i) == &proc) {
262 break;
263 }
264 }
265 assert(i < procedureCount() - 1);
266 return *procedures_.at(i + 1);
267
268 } else {
270 }
271}
272
273/**
274 * Returns the start (lowest) address of the program.
275 *
276 * The start address of the program is not necessarily the lowest address of
277 * the instruction address space.
278 *
279 * @note Preserving this value is not implemented in TPEFProgramFactory
280 * and ProgramWriter, however implementation of property is already
281 * specified in TPEF specs.
282 *
283 * @return The start (lowest) address of the program.
284 */
287 return start_;
288}
289
290/**
291 * Sets the start (lowest) address of the program.
292 *
293 * The start address of the program is not necessarily the lowest address of
294 * the instruction address space. Relocates instructions to start from the
295 * address.
296 *
297 * @note Preserving this value is not implemented in TPEFProgramFactory
298 * and ProgramWriter, however implementation of property is already
299 * specified in TPEF specs.
300 *
301 * @param start The start (lowest) address of the program.
302 */
303void
305
306 start_ = start;
307
308 // move procedures before the new starting address
309 if (procedureCount() > 0 &&
310 firstProcedure().startAddress().location() < start_.location()) {
313 start_.location() - firstProcedure().startAddress().location());
314 }
315}
316
317/**
318 * Returns the address of the program entry point.
319 *
320 * The entry point is not necessarily the instruction of the program with
321 * the lowest address.
322 *
323 * @note Preserving this value is not implemented in TPEFProgramFactory
324 * and ProgramWriter, however implementation of property is already
325 * specified in TPEF specs.
326 *
327 * @return The address of the program entry point.
328 */
331 return entry_;
332}
333
334/**
335 * Sets the entry address of the program.
336 *
337 * @note Preserving this value is not implemented in TPEFProgramFactory
338 * and ProgramWriter, however implementation of property is already
339 * specified in TPEF specs.
340 */
341void
343 entry_ = address;
344}
345
346/**
347 * Returns the first instruction of the program.
348 *
349 * @return The first instruction of the program.
350 * @exception InstanceNotFound There is no instructions in program.
351 */
354 if (!procedures_.empty()) {
356 } else {
357 throw InstanceNotFound(
358 __FILE__, __LINE__, __func__,
359 "There is no instructions in the program.");
360 }
361}
362
363/**
364 * Returns the instruction at a given address.
365 *
366 * The address space of the address is implied, since there is only
367 * one address space for instructions.
368 *
369 * @param address The address of the instruction.
370 * @exception KeyNotFound if given address is illegal.
371 * @return The instruction at the given address.
372 */
375 for (ProcIter iter = procedures_.begin(); iter != procedures_.end();
376 iter++) {
377
378 if ((*iter)->startAddress().location() <= address &&
379 (*iter)->endAddress().location() > address) {
380 return (*iter)->instructionAt(address);
381 }
382 }
383
384 throw KeyNotFound(
385 __FILE__, __LINE__, __func__,
386 "No instruction at address: " +
387 Conversion::toString(address));
388}
389
390/**
391 * Returns the next instruction in the instruction stream.
392 *
393 * @return The next instruction in the instruction stream or a special
394 * null instruction if the given instruction is the last instruction
395 * of the program.
396 *
397 * @exception IllegalRegistration If given instruction does not belong
398 * to the program.
399 * @note This method is very slow, do not use it for traversing the
400 * whole program!
401 */
404 if (!ins.isInProcedure() || !ins.parent().isInProgram() ||
405 &ins.parent().parent() != this) {
406
408 __FILE__, __LINE__, __func__,
409 "Instruction in parameter doesn't belong to this program.");
410 }
411
412 unsigned int insAddress = ins.address().location();
413
414 // Check first the basic case of having the next instruction in the same
415 // procedure. Find the instruction and return its next iterator.
416 Instruction* nextInstr = &ins.parent().nextInstruction(ins);
417 if (nextInstr != &NullInstruction::instance())
418 return *nextInstr;
419
420 ProcIter iter = procedures_.begin();
421 while (iter != procedures_.end()) {
422
423 // if the current instruction address fits procedure's
424 // address space
425 if ((*iter)->startAddress().location() <= insAddress &&
426 (*iter)->endAddress().location() > insAddress) {
427
428 // return next instruction, if it's in the same procedure
429 if ((*iter)->hasNextInstruction(ins)) {
430 return (*iter)->nextInstruction(ins);
431
432 // otherwise find the next non-empty procedure and return
433 // its first instruction
434 } else {
435 iter++;
436 while (iter != procedures_.end()) {
437 if ((*iter)->instructionCount() != 0) {
438 return (*iter)->instructionAt(
439 (*iter)->startAddress().location());
440 }
441 iter++;
442 }
443
444 // if no non-empty procedures found, return null instruction
446 }
447 }
448 iter++;
449 }
450
451 // no procedure where current instruction fits was found
452 // (should throw exception?)
454}
455
456/**
457 * Returns the last instruction of the program.
458 *
459 * @return The last instruction of the program.
460 * @exception InstanceNotFound There is no instructions in the program.
461 */
464 if (!procedures_.empty()) {
466 } else {
467 throw InstanceNotFound(
468 __FILE__, __LINE__, __func__,
469 "There is no instructions in the program.");
470 }
471}
472
473/**
474 * Returns a move at given location, counting from beginning, zero
475 * @param number zero-beginning count of move's location
476 * @return a reference to the found move
477 * @exception KeyNotFound if the move wasn't found at the given location
478 */
479const TTAProgram::Move&
480Program::moveAt(int number) const {
481 if (number < 0 || number >= static_cast<int>(moves_.size())) {
482 throw KeyNotFound(__FILE__, __LINE__, __FUNCTION__,
483 "Move not found at location: " + Conversion::toString(number));
484 }
485 return *moves_.at(number);
486}
487
488/**
489 * Returns the total count of moves used in the program
490 *
491 * @return the total count of moves used in the program
492 */
493int
495 return static_cast<int>(moves_.size());
496}
497
498/**
499 * Returns the procedure at a given index in the container of procedures.
500 *
501 * This method is for quickly traversing through all the procedures within
502 * time critical loops.
503 *
504 * @param index The procedure index in the list of procedures.
505 * @return The Procedure at the given index.
506 */
507const Procedure&
509 return *procedures_.at(index);
510}
511
512/**
513 * Insert the given procedure as the last procedure of the program.
514 *
515 * The ownership of the procedure will be passed to the program. Labels
516 * must be added explicitely by client because only it knows the scope
517 * where to add the labels.
518 *
519 * @param proc The procedure to be inserted.
520 * @exception IllegalRegistration if the procedure belongs to another
521 * program.
522 */
523void
525 if (proc->isInProgram()) {
527 __FILE__, __LINE__, __func__,
528 "Procedure is already in program.");
529 } else {
530
531 proc->setParent(*this);
532 if (!procedures_.empty()) {
533 proc->setStartAddress(procedures_.back()->endAddress());
534 } else {
535 proc->setStartAddress(start_);
536 }
537
538 procedures_.push_back(proc);
539 }
540}
541
542/**
543 * Insert the given instruction as the instruction of the last
544 * procedure of the program.
545 *
546 * The ownership of the instruction will be passed to the procedure in which
547 * the instruction is inserted.
548 *
549 * @param ins The instruction to be inserted.
550 * @exception IllegalRegistration if the instruction belongs to a
551 * procedure or there are no procedures in the program.
552 */
553void
555 if (procedures_.empty()) {
557 __FILE__, __LINE__, __func__,
558 "No procedures in the program.");
559 }
560
561 // add all moves of an instruction to the move list
562 for (int i = 0; i < ins->moveCount(); ++i) {
563 moves_.push_back(&ins->move(i));
564 }
565
566 if (!ins->isInProcedure()) {
567 procedures_.back()->add(ins);
568 } else {
570 __FILE__, __LINE__, __func__,
571 "Instruction already belongs to a procedure.");
572 }
573}
574
575/**
576 * Moves the given procedure and its succeeding procedures the given
577 * count of instructions.
578 *
579 * @note If the given count is negative, does not perform any checking for
580 * overlapping procedures, thus the relocated procedure might end up
581 * sharing instruction indices with the preceeding procedure,
582 * which means a corrupted program.
583 *
584 * @param proc The procedure to move.
585 * @param howMuch How many instructions the procedure should be moved.
586 */
587void
589 unsigned int index;
590 // skip procedures before given procedure
591 for (index = 0; index < procedures_.size(); index++) {
592 if (procedures_[index] == &proc) {
593 break;
594 }
595 }
596 // only update procedures after.
597 for (;index < procedures_.size(); index++) {
598 Procedure* p2 = procedures_[index];
599 UIntWord oldAddr = p2->startAddress().location();
600 p2->setStartAddress(Address(oldAddr + howMuch, start_.space()));
601 }
602}
603
604/**
605 * Returns the number of procedures in the program.
606 *
607 * @return The number of procedures in the program.
608 */
609int
611 return procedures_.size();
612}
613
614/**
615 * Returns the procedure at the given index.
616 *
617 * @param index The position index.
618 * @return The procedure at the given index.
619 * @exception OutOfRange if the index is out of range.
620 */
622Program::procedure(int index) const {
623 if (index >= 0 &&
624 static_cast<unsigned int>(index) < procedures_.size()) {
625 return *procedures_.at(index);
626 } else {
627 throw OutOfRange(
628 __FILE__, __LINE__, __func__,
629 "There is no procedure by index: " +
630 Conversion::toString(index));
631 }
632}
633
634/**
635 * Returns the procedure at the given index.
636 *
637 * @param index The position index.
638 * @return The procedure at the given index.
639 * @exception OutOfRange if the index is out of range.
640 */
641Procedure&
642Program::operator[](size_t index) {
643 return *procedures_[index];
644}
645
646/**
647 * Returns the procedure with the given name.
648 *
649 * @param name The procedure name.
650 * @return The procedure with given name.
651 * @exception KeyNotFound if the procedure cannot be found.
652 */
654Program::procedure(const std::string& name) const {
655 ProcList::const_iterator i = procedures_.begin();
656 while (i != procedures_.end()) {
657 if ((*i)->name() == name) {
658 return *(*i);
659 }
660 ++i;
661 }
662
663 throw KeyNotFound(
664 __FILE__, __LINE__, __func__,
665 "No procedure found with name: " +
666 name);
667}
668
669/**
670 * Returns true in case the program has a procedure with the given name.
671 */
672bool
673Program::hasProcedure(const std::string& name) const {
674 ProcList::const_iterator i = procedures_.begin();
675 while (i != procedures_.end()) {
676 if ((*i)->name() == name) {
677 return true;
678 }
679 ++i;
680 }
681 return false;
682}
683
684/**
685 * Return the instruction reference manager.
686 */
691
692/**
693 * Assignment operator.
694 *
695 * Replaces the contents of this program with the given program.
696 *
697 * @param newProgram The Program instance to be assigned
698 * @return The assigned Program instance.
699 */
700Program&
701Program::operator=(const Program& newProgram) {
702 copyFrom(newProgram);
703 return *this;
704}
705
706/**
707 * Creates an exact copy of the program.
708 *
709 * References to external object models will remain untouched.
710 *
711 * @return An exact copy of the program.
712 */
713Program*
715
716 Program* newProgram = new Program(
717 startAddress().space(), startAddress(), entryAddress());
718
719 newProgram->copyFrom(*this);
720 return newProgram;
721}
722
723/**
724 * Copies data from another program to itself.
725 *
726 * References to external object models will remain untouched. The old data
727 * is cleaned first. this->copyFrom(another) is equivalent to *this = another.
728 *
729 * @return source The other program to copy from.
730 */
731void
733
734 // cleanup the old data first
735 cleanup();
736
737 for (int k = 0; k < source.procedureCount(); k++) {
738 Procedure& proc = source.procedure(k);
739 Procedure* newProc =
740 new Procedure(
741 proc.name(), proc.startAddress().space(),
742 proc.startAddress().location());
743 addProcedure(newProc);
744
745 for (int j = 0; j < proc.instructionCount(); j++) {
746 Instruction &ins = proc.instructionAtIndex(j);
747
748 Instruction* newIns = ins.copy();
749 newProc->add(newIns);
750 }
751 }
752
754 copyDataMemoriesFrom(source);
755
756 // set addresses
759
760 delete globalScope_;
761 globalScope_ = dynamic_cast<GlobalScope*>(
762 source.globalScopeConst().copyAndRelocate(*this));
763
764}
765
766/**
767 * Fix instruction references to point to the corresponding instructions
768 * of this Program.
769 *
770 * This should be called after copying procedures from
771 * other programs to transform the instruction references to
772 * point to the current program instead of the old one.
773 */
774void
776 for (int k = 0; k < procedureCount(); k++) {
777 Procedure& proc = procedure(k);
778 for (int j = 0; j < proc.instructionCount(); j++) {
779 Instruction& ins = proc.instructionAtIndex(j);
780
781 // sources of all moves.
782 for (int i = 0; i < ins.moveCount(); i++) {
783 Terminal& source = ins.move(i).source();
784
785 if (source.isInstructionAddress()) {
786 Instruction& oldRefIns =
788
789 // Fix the reference via
790 // a procedure offset to not break references
791 // inside Procedures copied from another Program
792 InstructionAddress procStartAddr =
793 procedure(dynamic_cast<Procedure&>(oldRefIns.parent()).name()).
795
796 Instruction& newRefIns =
798 procStartAddr +
799 oldRefIns.address().location() -
800 oldRefIns.parent().startAddress().location());
801
802 InstructionReference newRef =
804 newRefIns);
805 source.setInstructionReference(newRef);
806 }
807 }
808 // values of all immediates
809 for (int i = 0; i < ins.immediateCount(); i++) {
810 Terminal& value = ins.immediate(i).value();
811 if (value.isInstructionAddress()) {
812
813 Instruction& oldRefIns =
815
816
817 InstructionAddress procStartAddr =
818 procedure(dynamic_cast<Procedure&>(oldRefIns.parent()).name()).
820
821 Instruction& newRefIns =
823 procStartAddr +
824 oldRefIns.address().location() -
825 oldRefIns.parent().startAddress().location());
826
827 InstructionReference newRef =
829 newRefIns);
830 value.setInstructionReference(newRef);
831 }
832 }
833 }
834 }
835}
836
837/**
838 * Copy data memories from source program to destination and fixes
839 * data->code references to use InstructionReferenceManager of the
840 * instance.
841 *
842 * @param srcProg Program from which data is copied.
843 */
844void
846
847 // copy data memories
848 for (int i = 0; i < srcProg.dataMemoryCount(); i++) {
849 DataMemory& currMem = srcProg.dataMemory(i);
850
851 DataMemory* newDataMem = new DataMemory(currMem.addressSpace());
852
853 for (int j = 0; j < currMem.dataDefinitionCount(); j++) {
854 DataDefinition& currDef = currMem.dataDefinition(j);
855
856 DataDefinition* newDef = NULL;
857
858 if (currDef.isInstructionAddress()) {
859 Instruction& dstInstr = instructionAt(
860 currDef.destinationAddress().location());
861
862 InstructionReference dstRef =
864 dstInstr);
865
866 newDef = new DataInstructionAddressDef(
867 currDef.startAddress(), currDef.size(), dstRef,
868 targetProcessor().isLittleEndian());
869
870 } else {
871 newDef = currDef.copy();
872 }
873
874 newDataMem->addDataDefinition(newDef);
875 }
876
877 addDataMemory(newDataMem);
878 }
879}
880
881/**
882 * Remove procedure from the program.
883 *
884 * The procedure becomes independent (it is not deleted). All
885 * instructions following the removed procedure are relocated
886 * appropriately. All code labels attached to the removed procedure
887 * are deleted from the Program.
888 *
889 * @note Possible references to instructions in this procedure elsewhere
890 * in the program are not automatically fixed! It's a responsibility of
891 * the caller to fix the Program back to a consistent state.
892 *
893 * @todo Copy the deleted CodeLabels to the removed procedure's own
894 * Scope objects.
895 *
896 * @param proc Procedure to remove.
897 * @exception IllegalRegistration If procedure does not belong to the
898 * program.
899 */
900void
902 if (&proc.parent() != this) {
904 __FILE__, __LINE__, __func__,
905 "Procedure doesn't belong to this program.");
906 }
907
908 const InstructionAddress firstAddress = proc.startAddress().location();
909 const InstructionAddress lastAddress = proc.endAddress().location() - 1;
910
911 for (InstructionAddress addr = firstAddress;
912 addr <= lastAddress;
913 ++addr) {
914
916 }
917
918 if (&proc != &lastProcedure()) {
920 nextProcedure(proc),
921 proc.startAddress().location() - proc.endAddress().location());
922 }
923
924 for (ProcList::iterator iter = procedures_.begin();
925 iter != procedures_.end(); iter++) {
926
927 if ((*iter) == &proc) {
928 procedures_.erase(iter);
929 break;
930 }
931 }
932
934}
935
936/**
937 * Returns the number of data memories accessed by the program.
938 *
939 * @return The number of data memories accessed by the program.
940 */
941int
943 return dataMems_.size();
944}
945
946/**
947 * Insert the given data memory to the program.
948 *
949 * @param dataMem The data memory to be inserted.
950 * @exception IllegalRegistration Memory with the same address space is
951 * found from the program.
952 */
953void
955 // TODO: check that there is no another data mem with same address space...
956 dataMems_.push_back(dataMem);
957}
958
959/**
960 * Returns the data memory at the given index.
961 *
962 * @param index The position index.
963 * @return The data memory at the given index.
964 * @exception OutOfRange the index is out of range.
965 */
967Program::dataMemory(int index) const {
968 if (index >= 0 &&
969 static_cast<unsigned int>(index) < dataMems_.size()) {
970 return *dataMems_.at(index);
971 } else {
972 throw OutOfRange(
973 __FILE__, __LINE__, __func__,
974 "There is no data memory with index: " +
975 Conversion::toString(index));
976 }
977}
978
979/**
980 * Returns the data memory with the given address space name.
981 *
982 * @param aSpaceName The address space name of the memory.
983 * @return The data memory with given address space name.
984 * @exception KeyNotFound if the data memory cannot be found.
985 */
987Program::dataMemory(const std::string& aSpaceName) const {
988 for (int i = 0; i < dataMemoryCount(); i++) {
989 if (dataMemory(i).addressSpace().name() == aSpaceName) {
990 return dataMemory(i);
991 }
992 }
993
994 throw KeyNotFound(
995 __FILE__, __LINE__, __func__,
996 "No data memory found by address space name: " +
997 aSpaceName);
998}
999
1000/**
1001 * Replace instruction and data address space of a sequential program
1002 * with real ones of the target machine.
1003 *
1004 * Only the data address space of the target machine that corresponds
1005 * to the universal data address space is required. Target machine and
1006 * instruction address space are replaced implicitly.
1007 *
1008 * @param space New data address space.
1009 * @note Use only to convert a sequential program to use a real machine!
1010 */
1011void
1013
1014 if (dynamic_cast<UniversalMachine*>(start_.space().machine()) == NULL) {
1015 abortWithError("Address space not connected to a machine.");
1016 }
1017
1018 AddressSpace& instructionAS =
1019 *space.machine()->controlUnit()->addressSpace();
1020
1021 start_ = Address(start_.location(), instructionAS);
1022 entry_ = Address(entry_.location(), instructionAS);
1023
1024
1025 for (int k = 0; k < procedureCount(); k++) {
1026 Procedure& proc = procedure(k);
1027 for (int j = 0; j < proc.instructionCount(); j++) {
1028 Instruction &ins = proc.instructionAtIndex(j);
1029 for (int i = 0; i < ins.moveCount(); i++) {
1030 Move& move = ins.move(i);
1031 Terminal& source = move.source();
1032 if (source.isAddress() && !source.isInstructionAddress()) {
1033 TerminalAddress* newSource = new TerminalAddress(
1034 source.value(), const_cast<AddressSpace&>(space));
1035 move.setSource(newSource);
1036 }
1037 }
1038 }
1039 }
1040
1041 if (dataMemoryCount() > 1) {
1042 throw IllegalProgram(
1043 __FILE__, __LINE__, __func__,
1044 "There should be less than two data memories. Number of memories: " +
1046 }
1047
1048 if (dataMemoryCount() == 0) {
1049 // TODO: what to do when there is no data used in program...
1050 } else if (dataMemoryCount() == 1) {
1051 DataMemory& dataMem = dataMemory(0);
1052 dataMem.setAddressSpace(const_cast<AddressSpace&>(space));
1053
1054 // fix dest addresses in data defs to point to the new single data AS
1055 for (int i = 0; i < dataMem.dataDefinitionCount(); i++) {
1056 DataDefinition& def = dataMem.dataDefinition(i);
1057 if (def.isAddress() && !def.isInstructionAddress()) {
1059 Address(def.destinationAddress().location(), space));
1060 }
1061 }
1062
1063 assert(dataMemoryCount() == 1);
1065
1066 } else {
1067 throw IllegalProgram(
1068 __FILE__, __LINE__, __func__,
1069 "There should be less than two data memories. Number of memories: " +
1071 }
1072}
1073
1074/**
1075 * A shortcut for loading a partially scheduled program from a TPEF file.
1076 *
1077 * @param tpefFileName The file name of the TPEF.
1078 * @param theMachine The target machine.
1079 * @return Created program.
1080 * @exception Exception if the TPEF or program in it is somehow broken.
1081 */
1082Program*
1084 const std::string& tpefFileName, const TTAMachine::Machine& theMachine) {
1085 TPEF::BinaryStream binaryStream(tpefFileName);
1086
1087 // read to TPEF Handler Module
1088 TPEF::Binary* tpef = TPEF::BinaryReader::readBinary(binaryStream);
1089
1090 if (tpef == NULL) {
1091 throw IOException(
1092 __FILE__, __LINE__, __func__, "Loading TPEF failed.");
1093 }
1094
1095 // convert the loaded TPEF to POM
1096 TTAProgram::TPEFProgramFactory factory(*tpef, theMachine);
1097 Program* prog = factory.build();
1098 delete tpef;
1099 tpef = NULL;
1100 return prog;
1101}
1102
1103/**
1104 * A shortcut for loading a scheduled program from a TPEF file.
1105 *
1106 * @param tpefFileName The file name of the TPEF.
1107 * @param theMachine The target machine.
1108 * @return Created program.
1109 * @exception Exception if the TPEF or program in it is somehow broken.
1110 */
1111Program*
1113 const std::string& tpefFileName, const TTAMachine::Machine& theMachine) {
1114 TPEF::BinaryStream binaryStream(tpefFileName);
1115
1116 // read to TPEF Handler Module
1117 TPEF::Binary* tpef = TPEF::BinaryReader::readBinary(binaryStream);
1118
1119 if (tpef == NULL) {
1120 throw IOException(
1121 __FILE__, __LINE__, __func__, "Loading TPEF failed.");
1122 }
1123
1124 // convert the loaded TPEF to POM
1125 TTAProgram::TPEFProgramFactory factory(*tpef, theMachine);
1126 Program* prog = factory.build();
1127 delete tpef;
1128 tpef = NULL;
1129 return prog;
1130}
1131
1132/**
1133 * A shortcut for loading a sequential program (from the old gcc 2.7.0
1134 * frontend) from a TPEF file.
1135 *
1136 * @param tpefFileName The file name of the TPEF.
1137 * @param umach The universal machine for the unscheduled parts.
1138 * @return Created program.
1139 * @exception Exception if the TPEF or program in it is somehow broken.
1140 */
1141Program*
1142Program::loadFromUnscheduledTPEF(const std::string& tpefFileName) {
1143 TPEF::BinaryStream binaryStream(tpefFileName);
1144
1145 // read to TPEF Handler Module
1146 TPEF::Binary* tpef = TPEF::BinaryReader::readBinary(binaryStream);
1147
1148 if (tpef == NULL) {
1149 throw IOException(
1150 __FILE__, __LINE__, __func__, "Loading TPEF failed.");
1151 }
1152
1153 // convert the loaded TPEF to POM
1155 Program* prog = factory.build();
1156 delete tpef;
1157 tpef = NULL;
1158 return prog;
1159}
1160
1161/**
1162 * A shortcut for writing a program to a TPEF file.
1163 *
1164 * @param program The program to write.
1165 * @param tpefFileName The file name of the TPEF.
1166 * @exception Exception if the TPEF or program in it is somehow broken.
1167 */
1168void
1170 const TTAProgram::Program& program, const std::string& tpefFileName) {
1171 std::ofstream outputFile(
1172 tpefFileName.c_str(),
1173 std::ios_base::out|std::ios_base::trunc|std::ios_base::binary);
1174 TPEF::BinaryStream binaryStream(outputFile);
1175
1177 TPEF::Binary* tpefBin = writer.createBinary();
1178
1179 TPEF::TPEFWriter::instance().writeBinary(binaryStream, tpefBin);
1180
1181 delete tpefBin;
1182 tpefBin = NULL;
1183}
1184
1185/**
1186 * Returns all Instructions in the program as random accessible vector.
1187 *
1188 * The returned vector can be used for faster traversal of the program's
1189 * instruction. It should be used instead of nextInstruction() or similar
1190 * very slow methods when traversing through the whole program. Note
1191 * that the Instruction* inside the vector should not be destroyed by
1192 * the client as they are owned by the Program. The InstructionVector
1193 * is not updated automatically as the Program changes!
1194 */
1197 InstructionVector instructions;
1198 for (std::size_t p = 0; p < procedures_.size(); ++p) {
1199 Procedure& proc = *procedures_.at(p);
1200 for (int i = 0; i < proc.instructionCount(); ++i) {
1201 Instruction* instr = &proc.instructionAtIndex(i);
1202 instructions.push_back(instr);
1203 }
1204 }
1205 return instructions;
1206}
1207
1208int
1210 if (procedureCount() == 0) {
1211 return 0;
1212 }
1213 return lastProcedure().startAddress().location() +
1215 start_.location();
1216}
1217
1218/**
1219 * Converts single TerminalSymbolReference into
1220 * InstructionReference to the symbol or TerminalImmediate into the
1221 * data label.
1222 *
1223 * @TODO: Use CodeLabels instead of procedure?
1224 */
1227 TCEString procName = tsr.toString();
1228 if (!hasProcedure(procName)) {
1229 if (procName == "_end") {
1230 for (int i = 0; i < globalScope_->globalDataLabelCount(); i++) {
1231 const DataLabel& dl = globalScope_->globalDataLabel(i);
1232 if (dl.name() == "_end") {
1233 // we do not know if this is going to sing- or zero
1234 // extending immediate, lets be sure it fits and use
1235 // signed. zero extends broke sign-extending ADFs
1237 SimValue(
1238 dl.address().location(),
1240 }
1241 }
1242 throw InstanceNotFound(__FILE__,__LINE__,__func__,
1243 "_end not found in program!");
1244 }
1245 throw InstanceNotFound(__FILE__,__LINE__,__func__,
1246 TCEString("procedure '")
1247 + procName + TCEString("' not found!"));
1248 }
1249 const Procedure& target = procedure(procName);
1250 assert(target.instructionCount() > 0);
1253 target.firstInstruction()));
1254}
1255
1256/**
1257 * Converts all TerminalSymbolReferences into InstructionReferences pointing to
1258 * instructions or TerminalImmediates into data label.
1259 *
1260 * @param ignoreUnfoundSymbols if set to true, just skips symbol references for which
1261 * the symbol is not found. Otherwise throws in that case.
1262 */
1263void
1264Program::convertSymbolRefsToInsRefs(bool ignoreUnfoundSymbols) {
1265 for (int i = 0; i < procedureCount();i++) {
1266 Procedure& proc = procedure(i);
1267 for (int j = 0; j < proc.instructionCount(); j++) {
1269 for (int k = 0; k < ins.moveCount(); k++) {
1270 TTAProgram::Move& move = ins.move(k);
1271 TTAProgram::Terminal& src = move.source();
1272
1273 if (src.isCodeSymbolReference()) {
1274
1275 TCEString procName = src.toString();
1276 if (!hasProcedure(procName) && ignoreUnfoundSymbols)
1277 continue;
1278
1279 move.setSource(convertSymbolRef(src));
1280 }
1281 }
1282 for (int k = 0; k < ins.immediateCount(); k++) {
1283 TTAProgram::Immediate& imm = ins.immediate(k);
1284 TTAProgram::Terminal& immVal = imm.value();
1285
1286 if (immVal.isCodeSymbolReference()) {
1287
1288 TCEString procName = immVal.toString();
1289 if (!hasProcedure(procName) && ignoreUnfoundSymbols)
1290 continue;
1291
1292 imm.setValue(convertSymbolRef(immVal));
1293 }
1294 }
1295 }
1296 }
1297}
1298
1299/**
1300 * Links the given Program with this one.
1301 *
1302 * "Linking" here means copying all the procedures to this Program and
1303 * fixing all fixable (external) symbol references. That is, in case
1304 * either this or the other Program contained calls to external
1305 * functions that are now found, the references are fixed to point
1306 * to the actual Procedures.
1307 */
1308void
1310
1311 if (other.procedureCount() == 0) return;
1312
1313 for (int i = 0; i < other.procedureCount(); ++i) {
1314 addProcedure(dynamic_cast<Procedure*>(other.procedure(i).copy()));
1315 }
1316 copyDataMemoriesFrom(other);
1319
1320 // todo merge GlobalScope (to retain labels)
1321}
1322
1323/**
1324 * Dump the Program as a disassembly string.
1325 */
1328 return POMDisassembler::disassemble(*this, true);
1329}
1330
1331/**
1332 * This should be called if the program has been fully constructed and won't
1333 * get new instructions added anymore.
1334 *
1335 * Computes and updates the final Instruction addresses with the best available
1336 * accuracy. Before this method is called, instruction per address indexing is
1337 * used, which is fast but might not reflect the final instruction addresses.
1338 * After this method has been called, the user of the Program can also assume
1339 * all the Instructions are attached to a Procedure and Procedures to the
1340 * Program.
1341 */
1342void
1344
1345 InstructionVector instructions = instructionVector();
1346
1347 if (instructions.size() == 0) return;
1348
1349 InstructionAddress previousAddress = startAddress().location();
1350
1351 POMDisassembler* disasm =
1353
1354 InstructionAddress currentSize =
1355 disasm->instructionSize(*instructions[0]);
1356
1357 instructions[0]->setFinalAddress(previousAddress);
1358 instructions[0]->setSize(currentSize);
1359
1360 bool newInstructionPerAddress = instructionPerAddress_;
1361 // From now on assume there's not an instruction per address layout.
1362 instructionPerAddress_ = false;
1363
1364 if (currentSize != 1)
1365 newInstructionPerAddress = false;
1366
1367 for (size_t i = 1; i < instructions.size(); ++i) {
1368 TTAProgram::Instruction* instr = instructions[i];
1369 currentSize = disasm->instructionSize(*instr);
1370 instr->setSize(currentSize);
1371 InstructionAddress newAddress = previousAddress + currentSize;
1372 instr->setFinalAddress(newAddress);
1373 previousAddress = newAddress;
1374 if (currentSize != 1)
1375 newInstructionPerAddress = false;
1376 }
1377
1378 instructionPerAddress_ = newInstructionPerAddress;
1379
1380 // Fix the procedure start and end addresses.
1381 ProcIter iter = procedures_.begin();
1382 while (iter != procedures_.end()) {
1383 Procedure& proc = **iter;
1385 // End address is the first address that doesn't store
1386 // instructions of the procedure.
1387 proc.setEndAddress(
1389 proc.lastInstruction().size(),
1390 proc.lastInstruction().address().space()));
1391 ++iter;
1392 }
1393
1394 finalized_ = true;
1395 delete disasm;
1396}
1397
1398} // namespace TTAProgram
1399
#define __func__
#define abortWithError(message)
#define assert(condition)
Word UIntWord
Definition BaseType.hh:144
UInt32 InstructionAddress
Definition BaseType.hh:175
find Finds info of the inner loops in the program
find Finds info of the inner loops in the false
static std::string toString(const T &source)
static int requiredBitsSigned(SLongWord number)
static POMDisassembler * disassembler(const TTAMachine::Machine &mach, const TTAProgram::Program &program)
static std::string disassemble(const TTAProgram::Move &move)
virtual size_t instructionSize(const TTAProgram::Instruction &)
Returns the size of the instruction in memory addresses, if known. Falls back to address per instruct...
static void deleteAllItems(SequenceType &aSequence)
static Binary * readBinary(BinaryStream &stream)
void writeBinary(BinaryStream &stream, const Binary *bin) const
static const BinaryWriter & instance()
Definition TPEFWriter.cc:70
virtual Machine * machine() const
virtual TCEString name() const
virtual AddressSpace * addressSpace() const
virtual ControlUnit * controlUnit() const
Definition Machine.cc:345
const TTAMachine::AddressSpace & space() const
InstructionAddress location() const
virtual Instruction & nextInstruction(const Instruction &ins) const
virtual void setParent(Program &prog)
virtual Address endAddress() const
virtual Instruction & firstInstruction() const
virtual bool isInProgram() const
virtual int instructionCount() const
virtual void setStartAddress(Address start)
virtual Program & parent() const
virtual Address startAddress() const
virtual Instruction & lastInstruction() const
virtual void setEndAddress(Address end)
virtual Instruction & instructionAtIndex(int index) const
virtual Address startAddress() const
virtual bool isAddress() const
virtual Address destinationAddress() const
virtual bool isInstructionAddress() const
virtual void setDestinationAddress(Address dest)
virtual DataDefinition * copy() const
void setAddressSpace(const TTAMachine::AddressSpace &space)
void addDataDefinition(DataDefinition *dataDef)
Definition DataMemory.cc:66
DataDefinition & dataDefinition(Address address) const
Definition DataMemory.cc:79
int dataDefinitionCount() const
const TTAMachine::AddressSpace & addressSpace() const
virtual void setDataLabelAddressSpace(const TTAMachine::AddressSpace &space)
const DataLabel & globalDataLabel(Address address, int index) const
virtual Scope * copyAndRelocate(const TTAProgram::Program &program) const
virtual void removeCodeLabels(InstructionAddress address)
int globalDataLabelCount(Address address) const
void setValue(TerminalImmediate *value)
Definition Immediate.cc:114
TerminalImmediate & value() const
Definition Immediate.cc:103
InstructionReference createReference(Instruction &ins)
Instruction * copy() const
void setSize(short size)
Move & move(int i) const
Address address() const
Immediate & immediate(int i) const
void setFinalAddress(InstructionAddress addr)
CodeSnippet & parent() const
std::string name() const
Definition Label.cc:74
virtual Address address() const
Definition Label.cc:84
void setSource(Terminal *src)
Definition Move.cc:312
Terminal & source() const
Definition Move.cc:302
static NullInstruction & instance()
static NullProcedure & instance()
static NullProgram & instance()
void add(Instruction *ins)
Definition Procedure.cc:160
CodeSnippet * copy() const
Definition Procedure.cc:137
TCEString name() const
Definition Procedure.hh:66
TPEF::Binary * createBinary() const
std::vector< Instruction * > InstructionVector
Vector for instructions.
Definition Program.hh:66
static Program * loadFromTPEF(const std::string &tpefFileName, const TTAMachine::Machine &theMachine)
Definition Program.cc:1112
GlobalScope & globalScope()
Definition Program.cc:180
Procedure & procedure(int index) const
Definition Program.cc:622
Program(const TTAMachine::AddressSpace &space)
Definition Program.cc:91
static void writeToTPEF(const TTAProgram::Program &program, const std::string &tpefFileName)
Definition Program.cc:1169
Instruction & nextInstruction(const Instruction &) const
Definition Program.cc:403
Instruction & firstInstruction() const
Definition Program.cc:353
ProcList::const_iterator ProcIter
Iterator for the procedure list.
Definition Program.hh:156
TerminalImmediate * convertSymbolRef(Terminal &tsr)
Definition Program.cc:1226
bool hasProcedure(const std::string &name) const
Definition Program.cc:673
ProcList procedures_
The procedures in the program.
Definition Program.hh:177
bool finalized_
True in case the program is not (and must not be) updated anymore and it has its final instruction ad...
Definition Program.hh:200
GlobalScope * globalScope_
Global scope of the program.
Definition Program.hh:174
void moveProcedure(Procedure &proc, int howMuch)
Definition Program.cc:588
Program * copy() const
Definition Program.cc:714
TCEString toString() const
Definition Program.cc:1327
InstructionReferenceManager * refManager_
Keeps book of all instruction to instruction (jumps and calls) references in the program.
Definition Program.hh:192
virtual ~Program()
Definition Program.cc:144
void fixInstructionReferences()
Definition Program.cc:775
const Move & moveAt(int number) const
Definition Program.cc:480
Address entryAddress() const
Definition Program.cc:330
Instruction & lastInstruction() const
Definition Program.cc:463
const Procedure & procedureAtIndex(int index) const
Definition Program.cc:508
void replaceUniversalAddressSpaces(const TTAMachine::AddressSpace &space)
Definition Program.cc:1012
Procedure & operator[](size_t index)
Definition Program.cc:642
Address startAddress() const
Definition Program.cc:286
MoveList moves_
List of all the moves of the program.
Definition Program.hh:183
void copyDataMemoriesFrom(const Program &srcProg)
Definition Program.cc:845
Program & operator=(const Program &old)
Definition Program.cc:701
const GlobalScope & globalScopeConst() const
Definition Program.cc:192
TTAMachine::Machine & targetProcessor() const
Definition Program.cc:202
void setEntryAddress(Address address)
Definition Program.cc:342
int moveCount() const
Definition Program.cc:494
DataMemory & dataMemory(int index) const
Definition Program.cc:967
void removeProcedure(Procedure &proc)
Definition Program.cc:901
Procedure & nextProcedure(const Procedure &proc) const
Definition Program.cc:250
void addDataMemory(DataMemory *dataMem)
Definition Program.cc:954
void addProcedure(Procedure *proc)
Definition Program.cc:524
Instruction & instructionAt(InstructionAddress address) const
Definition Program.cc:374
bool instructionPerAddress_
True in case the program is instruction indexed, that is, each instruction is assumed to be in a sing...
Definition Program.hh:204
int procedureCount() const
Definition Program.cc:610
void addInstruction(Instruction *ins)
Definition Program.cc:554
InstructionReferenceManager & instructionReferenceManager() const
Definition Program.cc:688
UniversalMachine & universalMachine() const
Definition Program.cc:104
void setStartAddress(Address start)
Definition Program.cc:304
Address entry_
The entry address of the program.
Definition Program.hh:188
int instructionCount() const
Definition Program.cc:1209
static Program * loadFromUnscheduledTPEF(const std::string &tpefFileName, const TTAMachine::Machine &theMachine)
Definition Program.cc:1083
void link(const TTAProgram::Program &other)
Definition Program.cc:1309
DataMemList dataMems_
The data memories in the program.
Definition Program.hh:180
void convertSymbolRefsToInsRefs(bool ignoreUnfoundSymbols=false)
Definition Program.cc:1264
InstructionVector instructionVector() const
Definition Program.cc:1196
Procedure & lastProcedure() const
Definition Program.cc:230
void copyFrom(const Program &source)
Definition Program.cc:732
Procedure & firstProcedure() const
Definition Program.cc:213
int dataMemoryCount() const
Definition Program.cc:942
Address start_
The start address of the program.
Definition Program.hh:186
virtual SimValue value() const
Definition Terminal.cc:178
virtual bool isAddress() const
Definition Terminal.cc:75
virtual bool isCodeSymbolReference() const
Definition Terminal.cc:154
virtual const InstructionReference & instructionReference() const
Definition Terminal.cc:188
virtual void setInstructionReference(InstructionReference ref)
Definition Terminal.cc:404
virtual bool isInstructionAddress() const
Definition Terminal.cc:87
virtual TCEString toString() const =0
static UniversalMachine & instance()