OpenASIP 2.2
Loading...
Searching...
No Matches
ImplementationTester.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2010 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 ImplementationTester.cc
26 *
27 * Implementation of ImplementationTester class.
28 *
29 * @author Pekka Jääskeläinen 2006,2010 (pekka.jaaskelainen-no.spam-tut.fi)
30 * @author Otto Esko 2010 (otto.esko-no.spam-tut.fi)
31 * @note rating: red
32 */
33#include <iostream>
34#include <cstdlib>
35#include <iostream>
36#include <fstream>
37#include <string>
38#include <sstream>
39#include <fstream>
40#include <vector>
41#include <map>
42#include <stdint.h>
43
45#include "HDBManager.hh"
46#include "CachedHDBManager.hh"
47#include "FUEntry.hh"
48#include "FUArchitecture.hh"
49#include "FUImplementation.hh"
50#include "RFEntry.hh"
51#include "RFArchitecture.hh"
52#include "RFImplementation.hh"
53#include "FunctionUnit.hh"
54#include "Machine.hh"
55#include "MachineState.hh"
57#include "MemorySystem.hh"
58#include "OutputPortState.hh"
59#include "InputPortState.hh"
63#include "GhdlSimulator.hh"
64#include "ModelsimSimulator.hh"
66
67using std::string;
68using std::vector;
69using std::ofstream;
70
71/**
72 * Default constructor
73 */
75 hdbFile_(""),
76 hdb_(NULL),
77 simulator_(SIM_GHDL), verbose_(false), leaveDirty_(false), tempDir_("") {
78}
79
80/**
81 * Constructor
82 *
83 * @param hdbFile Name of the hdb file
84 * @param simulator Name of the HDL simulator to be used
85 */
87 std::string hdbFile, VhdlSim simulator):
88 hdbFile_(hdbFile),
89 hdb_(NULL),
90 simulator_(simulator),
91 verbose_(false), leaveDirty_(false), tempDir_("") {
92
95}
96
97
98/**
99 * Constructor
100 *
101 * @param hdbFile Name of the hdb file
102 * @param simulator Name of the HDL simulator to be used
103 * @param verbose Enable verbose messages
104 * @param leaveDirty Don't delete created testbench files
105 */
107 std::string hdbFile, VhdlSim simulator, bool verbose, bool leaveDirty):
108 hdbFile_(hdbFile),
109 hdb_(NULL),
110 simulator_(simulator),
111 verbose_(verbose), leaveDirty_(leaveDirty), tempDir_("") {
112
115}
116
117/**
118 * Destructor
119 */
121 if (leaveDirty_) {
122 if (tempDir_.empty()) {
123 std::cout << "No testbench files created" << std::endl;
124 } else {
125 std::cout << "Testbench files are stored at " << tempDir_
126 << std::endl;
127 }
128 } else {
129 // clear created files
130 if (!tempDir_.empty()) {
132 }
133 }
134}
135
136
137/**
138 * Set VHDL simulator to be used in simulation
139 *
140 * @param simulator Name of the HDL simulator to be used
141 */
142void
146
147
148/**
149 * Tries to open hdb file
150 *
151 * @param hdbFile Name of the hdb file
152 */
153void
154ImplementationTester::openHdb(std::string hdbFile) {
155
156 try {
158 } catch (const Exception& e) {
159 InvalidData excep(
160 __FILE__, __LINE__, "ImplementationTester",
161 "Error while loading input data: " + e.errorMessage());
162 throw excep;
163 }
164 hdbFile_ = hdbFile;
165}
166
167/**
168 * Tests whether a FU can be tested
169 *
170 * @param entryID Entry ID of the FU
171 * @param reason If FU can't be tested this string holds the reason why
172 * @return True if can be tested
173 */
174bool
175ImplementationTester::canTestFU(const int entryID, std::string& reason) {
176
177 bool canTest = true;
178 HDB::FUEntry* fuEntry = NULL;
179 try {
180 fuEntry = fuEntryFromHdb(entryID);
181 } catch (KeyNotFound& e) {
182 std::ostringstream errorStream;
183 errorStream << "ID " << entryID << " does not exist in HDB "
184 << hdbFile_;
185 reason = errorStream.str();
186 return false;
187 }
188 if (!fuEntry->hasArchitecture()) {
189 reason = "FU entry does not have architecture";
190 canTest = false;
191 } else if (!fuEntry->hasImplementation()) {
192 reason = "FU entry does not have implementation";
193 canTest = false;
194 } else if (fuHasMemoryAccess(fuEntry)) {
195 reason = "Simulation of memory accessing FUs is not supported";
196 canTest = false;
197 } else if (!fuFullyPipelined(fuEntry)) {
198 reason = "Simulation of non-pipelined FUs in not supported";
199 canTest = false;
200 } else if (fuHasExternalPorts(fuEntry)) {
201 reason = "Simulation of FUs with external ports is not supported";
202 canTest = false;
203 } else if (fuHasOnePort(fuEntry)) {
204 reason = "FU has only one port";
205 canTest = false;
206 }
207 delete fuEntry;
208 return canTest;
209}
210
211/**
212 * Tests whether a RF can be tested
213 *
214 * @param entryID Entry ID of the RF
215 * @param reason If RF can't be tested this string holds the reason why
216 * @return True if can be tested
217 */
218bool
219ImplementationTester::canTestRF(const int entryID, std::string& reason) {
220
221 bool canTest = true;
222 HDB::RFEntry* rfEntry = NULL;
223 try {
224 rfEntry = rfEntryFromHdb(entryID);
225 } catch (KeyNotFound& e) {
226 std::ostringstream errorStream;
227 errorStream << "ID " << entryID << " does not exist in HDB "
228 << hdbFile_;
229 reason = errorStream.str();
230 return false;
231 }
232 if (!rfEntry->hasArchitecture()) {
233 reason = "RF entry does not have architecture";
234 canTest = false;
235 } else if (!rfEntry->hasImplementation()) {
236 reason = "RF entry does not have implementation";
237 canTest = false;
238 } else if (rfEntry->architecture().readPortCount() == 0) {
239 reason = "RF does not have a read port";
240 canTest = false;
241 } else if (rfEntry->architecture().writePortCount() == 0) {
242 reason = "RF does not have a write port";
243 canTest = false;
244 } else if (rfEntry->architecture().bidirPortCount() != 0) {
245 reason = "RF has bidirectional ports";
246 canTest = false;
247 } else if (rfEntry->architecture().latency() != 1) {
248 reason = "RF does not have latency of 1 cycle";
249 canTest = false;
250 }
251 delete rfEntry;
252 return canTest;
253}
254
255/**
256 * Validates that FU behaviour model and implementation are equal
257 *
258 * @param entryID Entry ID of the FU
259 * @param errors Error messages from the validation process
260 * @return True if there were no errors
261 */
262bool
264 const int entryID, std::vector<std::string>& errors) {
265
266 if (tempDir_.empty()) {
267 if (!createTempDir()) {
268 IOException exp(__FILE__, __LINE__, "ImplementationTester",
269 "Couldn't create temp directory");
270 throw exp;
271 }
272 }
273
274 string reason;
275 if (!canTestFU(entryID, reason)) {
276 InvalidData e(
277 __FILE__, __LINE__, "ImplementationTester",
278 "Cannot test FU: " + reason);
279 throw e;
280 }
281
282 HDB::FUEntry* fuEntry = NULL;
283 try {
284 fuEntry = fuEntryFromHdb(entryID);
285 } catch (KeyNotFound& e) {
286 std::ostringstream errorStream;
287 errorStream << "ID " << entryID << " does not exist in HDB "
288 << hdbFile_;
289 string errorMsg = errorStream.str();
290 errors.push_back(errorMsg);
291 return false;
292 }
293
294 FUTestbenchGenerator tbGen(fuEntry);
295
296 ofstream fileStream;
297 string tbName = fuTbName(entryID);
298
299 createTestbench(&tbGen, tbName);
300
301 bool success =
302 simulateTestbench(tbName, &fuEntry->implementation(), errors);
303
304 if (!leaveDirty_) {
306 }
307
308 delete fuEntry;
309 return success;
310}
311
312
313/**
314 * Validates that RF behaviour model and implementation are equal
315 *
316 * @param entryID Entry ID of the RF
317 * @param errors Error messages from the validation process
318 * @return True if there were no errors
319 */
320bool
322 const int entryID, std::vector<std::string>& errors) {
323
324 if (tempDir_.empty()) {
325 if (!createTempDir()) {
326 IOException exp(__FILE__, __LINE__, "ImplementationTester",
327 "Couldn't create temp directory");
328 throw exp;
329 }
330 }
331
332 string reason;
333 if (!canTestRF(entryID, reason)) {
334 InvalidData e(
335 __FILE__, __LINE__, "ImplementationTester",
336 "Cannot test RF: " + reason);
337 throw e;
338 }
339
340 HDB::RFEntry* rfEntry = NULL;
341 try {
342 rfEntry = rfEntryFromHdb(entryID);
343 } catch (KeyNotFound& e) {
344 std::ostringstream errorStream;
345 errorStream << "ID " << entryID << " does not exist in HDB "
346 << hdbFile_;
347 string errorMsg = errorStream.str();
348 errors.push_back(errorMsg);
349 return false;
350 }
351
352 RFTestbenchGenerator tbGen(rfEntry);
353 string tbName = rfTbName(entryID);
354
355 createTestbench(&tbGen, tbName);
356
357 bool success =
358 simulateTestbench(tbName, &rfEntry->implementation(), errors);
359
360 if (!leaveDirty_) {
362 }
363 delete rfEntry;
364 return success;
365}
366
367
368std::set<int>
370
371 if (!hdb_) {
372 InvalidData e(
373 __FILE__, __LINE__, "ImplementationTester",
374 "HDB is not defined");
375 throw e;
376 }
377 return hdb_->fuEntryIDs();
378}
379
380
381std::set<int>
383
384 if (!hdb_) {
385 InvalidData e(
386 __FILE__, __LINE__, "ImplementationTester",
387 "HDB is not defined");
388 throw e;
389 }
390 return hdb_->rfEntryIDs();
391}
392
393
394bool
396
397 HDB::FUArchitecture arch = fuEntry->architecture();
398 return arch.architecture().hasAddressSpace();
399}
400
401
402bool
404
405 HDB::FUArchitecture arch = fuEntry->architecture();
406 return arch.architecture().pipelineElementCount() == 0;
407}
408
409
410bool
412
413 HDB::FUImplementation* fuImpl = &fuEntry->implementation();
414 return fuImpl->externalPortCount() != 0;
415}
416
417
418bool
420
421 HDB::FUImplementation* fuImpl = &fuEntry->implementation();
422 return fuImpl->architecturePortCount() == 1;
423}
424
425
428
429 if (!hdb_) {
430 InvalidData e(
431 __FILE__, __LINE__, "ImplementationTester",
432 "HDB is not defined");
433 throw e;
434 }
435 return hdb_->fuByEntryID(entryID);
436}
437
438
441
442 if (!hdb_) {
443 InvalidData e(
444 __FILE__, __LINE__, "ImplementationTester",
445 "HDB is not defined");
446 throw e;
447 }
448 return hdb_->rfByEntryID(entryID);
449}
450
451
452bool
458
459
460/**
461 * Creates name for the testbench file
462 *
463 * @param id ID number of the FU
464 * @return testbench name
465 */
466std::string
468
469 std::ostringstream name;
471 << "tb_fu_" << id << ".vhdl";
472 return name.str();
473}
474
475/**
476 * Creates name for the testbench file
477 *
478 * @param id ID number of the RF
479 * @return testbench name
480 */
481std::string
483
484 std::ostringstream name;
486 << "tb_rf_" << id << ".vhdl";
487 return name.str();
488}
489
490
491void
493 std::ofstream& fileStream, std::string fileName) const {
494
495 fileStream.open(fileName.c_str());
496 if (!fileStream) {
497 IOException(__FILE__, __LINE__, "ImplementationTester",
498 "Failed to open file " + fileName + " for writing!");
499 }
500}
501
502
503/**
504 * Creates a list of HDL files of a FU/RF implementation
505 *
506 * @param impl FU/RF implementation
507 * @param files Vector containing the HDL files
508 */
509void
511 const HDB::HWBlockImplementation* impl,
512 std::vector<std::string>& files) const {
513
514 for (int i = 0; i < impl->implementationFileCount(); i++) {
515 string fullPath = "";
516 string filename = impl->file(i).pathToFile();
517 if (FileSystem::isAbsolutePath(filename)) {
518 fullPath = filename;
519 } else {
520 string hdbPath = FileSystem::directoryOfPath(hdbFile_);
521 fullPath = hdbPath + FileSystem::DIRECTORY_SEPARATOR + filename;
522 }
523 files.push_back(fullPath);
524 }
525}
526
527/**
528 * Compiles and simulates the testbech
529 *
530 * @param testbench Name of the testbench file
531 * @param implementation Implementation of the FU/RF
532 * @param errors Error messages from the compilation/simulation
533 * @return True if compilation and simulation were successfull
534 */
535bool
537 std::string testbench,
539 std::vector<std::string>& errors) const {
540
541 vector<string> hdlFiles;
543
544 ImplementationSimulator* sim = NULL;
545 if (simulator_ == SIM_GHDL) {
546 sim = new GhdlSimulator(testbench, hdlFiles, verbose_, leaveDirty_);
547 } else if (simulator_ == SIM_MODELSIM) {
548 sim = new ModelsimSimulator(
549 testbench, hdlFiles, verbose_, leaveDirty_);
550 }
551
552 if (!sim->compile(errors)) {
553 delete sim;
554 return false;
555 }
556
557 bool success = true;
558 if (!sim->simulate(errors)) {
559 success = false;
560 }
561 delete sim;
562 return success;
563}
564
565void
567 TestbenchGenerator* tbGen, std::string tbName) const {
568
569 ofstream fileStream;
570 openTbFile(fileStream, tbName);
571 tbGen->generateTestbench(fileStream);
572 fileStream.close();
573}
IDF::MachineImplementation * implementation
the implementation definition of the estimated processor
find Finds info of the inner loops in the false
std::string errorMessage() const
Definition Exception.cc:123
static std::string absolutePathOf(const std::string &pathName)
static bool isAbsolutePath(const std::string &pathName)
static bool removeFileOrDirectory(const std::string &path)
static const std::string DIRECTORY_SEPARATOR
static std::string createTempDirectory(const std::string &path="/tmp", const std::string &tempDirPrefix="tmp_tce_")
static std::string directoryOfPath(const std::string fileName)
Definition FileSystem.cc:79
static CachedHDBManager & instance(const std::string &hdbFile)
TTAMachine::FunctionUnit & architecture() const
FUImplementation & implementation() const
Definition FUEntry.cc:86
virtual bool hasImplementation() const
Definition FUEntry.cc:74
FUArchitecture & architecture() const
Definition FUEntry.cc:129
virtual bool hasArchitecture() const
Definition FUEntry.cc:117
FUEntry * fuByEntryID(RowID id) const
std::set< RowID > rfEntryIDs() const
RFEntry * rfByEntryID(RowID id) const
std::set< RowID > fuEntryIDs() const
BlockImplementationFile & file(int index) const
virtual bool hasImplementation() const
Definition RFEntry.cc:74
RFArchitecture & architecture() const
Definition RFEntry.cc:145
virtual bool hasArchitecture() const
Definition RFEntry.cc:117
RFImplementation & implementation() const
Definition RFEntry.cc:102
virtual bool compile(std::vector< std::string > &errors)=0
virtual bool simulate(std::vector< std::string > &errors)=0
HDB::FUEntry * fuEntryFromHdb(int entryID) const
void createListOfSimulationFiles(const HDB::HWBlockImplementation *impl, std::vector< std::string > &files) const
bool fuHasMemoryAccess(HDB::FUEntry *fuEntry) const
void createTestbench(TestbenchGenerator *tbGen, std::string tbName) const
std::set< int > fuEntryIDs() const
bool canTestRF(const int entryID, std::string &reason)
std::string fuTbName(int id) const
bool fuHasExternalPorts(HDB::FUEntry *fuEntry) const
bool canTestFU(const int entryID, std::string &reason)
bool simulateTestbench(std::string testbench, const HDB::HWBlockImplementation *implementation, std::vector< std::string > &errors) const
bool validateRF(const int entryID, std::vector< std::string > &errors)
bool fuHasOnePort(HDB::FUEntry *fuEntry) const
void openTbFile(std::ofstream &fileStream, std::string fileName) const
void openHdb(std::string hdbFile)
void setVhdlSimulator(VhdlSim simulator)
std::string rfTbName(int id) const
HDB::RFEntry * rfEntryFromHdb(int entryID) const
std::set< int > rfEntryIDs() const
bool fuFullyPipelined(HDB::FUEntry *fuEntry) const
bool validateFU(const int entryID, std::vector< std::string > &errors)
virtual int pipelineElementCount() const
virtual bool hasAddressSpace() const
virtual void generateTestbench(std::ofstream &file)=0