OpenASIP 2.2
Loading...
Searching...
No Matches
ProGeTools.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2017 Tampere University.
3
4 This file is part of TTA-Based Codesign Environment (TCE).
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.
23 */
24/**
25 * @file ProGeTools.cc
26 *
27 * Tools for automated TTA generation.
28 *
29 * @author Lasse Lehtonen 2017 (lasse.lehtonen-no.spam-tut.fi)
30 * @author Topi Leppänen 2019 (topi.leppanen-no.spam-tuni.fi)
31 */
32
33#include "StringTools.hh"
34#include "ProGeTools.hh"
36#include "CachedHDBManager.hh"
37#include "FUArchitecture.hh"
38#include "FUEntry.hh"
39#include "FUImplementation.hh"
40#include "FileSystem.hh"
41#include "HWOperation.hh"
42#include "Operation.hh"
43#include "OperationDAG.hh"
44#include "OperationIndex.hh"
45#include "OperationModule.hh"
46#include "OperationNode.hh"
47#include "OperationPool.hh"
48#include "OperationPool.hh"
49#include "RFArchitecture.hh"
50#include "RFEntry.hh"
51#include "RFImplementation.hh"
52#include "TerminalNode.hh"
53
54/**
55 * Check if given fu can be generated. If so return it in fug.
56 *
57 */
58bool
61 IDF::FUGenerated& fug, const std::vector<IDF::FUGenerated::Info>& infos,
62 const std::vector<IDF::FUGenerated::DAGOperation> dagops) {
63 std::vector<TTAMachine::HWOperation*> operations;
64 std::vector<std::string> genops;
65
66 for (int i = 0; i < fu.operationCount(); ++i) {
67 operations.emplace_back(fu.operation(i));
68 }
69
70 for (auto&& op : operations) {
71 int maxLatency;
73 fug.name(), options.fuFrontRegistered, false)) {
74 maxLatency = op->latency() - 1;
76 fug.name(), options.fuMiddleRegistered, false)) {
77 maxLatency = op->latency() - 2;
79 fug.name(), options.fuBackRegistered, false)) {
80 maxLatency = op->latency();
82 fug.name(), options.fuFrontRegistered)) {
83 maxLatency = op->latency() - 1;
85 fug.name(), options.fuMiddleRegistered)) {
86 maxLatency = op->latency() - 2;
87 } else { // Default to back-register
88 maxLatency = op->latency();
89 }
90 for (auto&& info : infos) {
91 if (op->name() == info.operationName &&
92 maxLatency >= info.latency) {
93 fug.addOperation(info);
94 genops.emplace_back(info.operationName);
95 break;
96 }
97 }
98 }
99
100 for (auto&& op : operations) {
101 for (auto&& dop : dagops) {
102 if (std::find(genops.begin(), genops.end(), op->name()) ==
103 genops.end() &&
104 op->name() == dop.operationName) {
105 fug.addOperation(dop);
106 genops.emplace_back(dop.operationName);
107 }
108 }
109 }
110
111 size_t neededFUops = fu.operationCount();
112
113 if (genops.size() == neededFUops) {
114 return true;
115 } else {
116 return false;
117 }
118}
119
120/**
121 * Check if option is in the list or list has 'ALL' in it.
122 */
123bool
125 const std::string& option, std::vector<std::string> list,
126 bool enableAll) {
127 std::string lowered_option = StringTools::stringToLower(option);
128 for (auto&& item : list) {
129 std::string lowered_item = StringTools::stringToLower(item);
130 if (lowered_item == lowered_option ||
131 (enableAll && lowered_item == "all")) {
132 return true;
133 }
134 }
135 return false;
136}
137
138/**
139 * Find out all operations we can generate from DAG.
140 */
141std::vector<IDF::FUGenerated::DAGOperation>
143 const std::vector<IDF::FUGenerated::Info> infos, std::ostream& verbose) {
144 std::vector<IDF::FUGenerated::DAGOperation> dagops;
145 std::set<std::string> opNames;
146
147 verbose << " can implement DAG operations that use:\n ";
148 std::string sep;
149 for (auto&& info : infos) {
150 verbose << sep << info.operationName;
151 sep = ", ";
152 }
153 verbose << "\n";
154
155 OperationPool opPool;
156 OperationIndex& opIndex = opPool.index();
157 for (int i = 0; i < opIndex.moduleCount(); ++i) {
158 OperationModule& module = opIndex.module(i);
159 for (int j = 0; j < opIndex.operationCount(module); ++j) {
160 std::string opName = opIndex.operationName(j, module);
161 if (opNames.count(opName) > 0) {
162 continue;
163 }
164 Operation& op = opPool.operation(opName.c_str());
165 for (int d = 0; d < op.dagCount(); ++d) {
166 std::vector<IDF::FUGenerated::Info> subops;
167 if (canGenerateFromDAG(op.dag(d), infos, &subops)) {
168 opName = StringTools::stringToLower(opName);
169 dagops.emplace_back(
170 IDF::FUGenerated::DAGOperation{opName, subops});
171 opNames.insert(opName);
172 break;
173 }
174 }
175 }
176 }
177
178 verbose << " can implement DAG operations:\n ";
179 sep = "";
180 for (auto&& op : dagops) {
181 verbose << sep << op.operationName;
182 sep = ", ";
183 }
184 verbose << "\n";
185
186 return dagops;
187}
188
189/**
190 * Checks if DAG operation can be implemented, i.e. all basic operations
191 * can be implemented
192 */
193bool
195 const OperationDAG& dag, const std::vector<IDF::FUGenerated::Info> infos,
196 std::vector<IDF::FUGenerated::Info>* subops) {
197 if (dag.isNull()) {
198 return false;
199 }
200
201 bool canImplement = true;
202 for (int n = 0; n < dag.nodeCount(); ++n) {
203 OperationNode* operationNode =
204 dynamic_cast<OperationNode*>(&dag.node(n));
205 if (operationNode) {
206 std::string operation =
207 operationNode->referencedOperation().name();
208 operation = StringTools::stringToLower(operation);
209
210 bool foundOperation = false;
211 for (auto&& info : infos) {
212 if (info.operationName == operation) {
213 foundOperation = true;
214 if (subops) {
215 subops->emplace_back(info);
216 }
217 break;
218 }
219 }
220 if (foundOperation == false) {
221 canImplement = false;
222 break;
223 }
224 }
225 }
226 return canImplement;
227}
228
229/**
230 * Finds the maximum latency of the dag. Uses maxOpLatency for
231 * the node latencies.
232 */
233int
235 const OperationDAG& dag,
236 const std::unordered_map<std::string, int>& maxOpLatency) {
237 assert(!dag.isNull());
238
239 int maxLatency = 0;
240
241 // To find the global critical path, go through every end terminal's
242 // critical path and find the maximum.
243 auto sinkNodes = dag.sinkNodes();
244 for (auto node : sinkNodes) {
245 int latency = maxLatencyToNode(dag, *node, maxOpLatency);
246 maxLatency = std::max(latency, maxLatency);
247 }
248 return maxLatency;
249}
250
251int
253 OperationDAGNode& node,
254 const std::unordered_map<std::string, int>& maxOpLatency) {
255 int latency = 0;
256
257 OperationNode* operationNode = dynamic_cast<OperationNode*>(&node);
258 if (operationNode) {
259 std::string subOpName = operationNode->referencedOperation().name();
260 subOpName = StringTools::stringToLower(subOpName);
261 if (maxOpLatency.find(subOpName) != maxOpLatency.end()) {
262 latency = maxOpLatency.at(subOpName);
263 }
264 }
265
266 return latency;
267}
268
269/*
270 Starting from the given node, find the maximum implementation
271 latency. Used to schedule the starting cycles of node operations.
272*/
273int
275 const OperationDAG& dag, OperationDAGNode& node,
276 const std::unordered_map<std::string, int>& maxOpLatency,
277 bool allowDifference) {
278 // Go through all the parents.
279 int maxLeafLatency = -1;
280 for (auto&& e : dag.inEdges(node)) {
281 OperationDAGNode& nextNode = dag.tailNode(*e);
282 // Recursive call to parent nodes
283 int parentLatency = maxLatencyToNode(dag, nextNode, maxOpLatency) +
284 nodeLatency(nextNode, maxOpLatency);
285
286 if (!allowDifference && maxLeafLatency != -1) {
287 assert(
288 maxLeafLatency == parentLatency &&
289 "Two input edges of DAG node have different latency!");
290 }
291
292 maxLeafLatency = std::max(maxLeafLatency, parentLatency);
293 }
294
295 // For nodes without children
296 maxLeafLatency = std::max(maxLeafLatency, 0);
297
298 // Return only the longest leaf latency.
299 return maxLeafLatency;
300}
301
302/**
303 * Parses all given hdbs for operation implementations.
304 */
305std::vector<IDF::FUGenerated::Info>
307 const ProGeOptions& options, std::ostream& verbose) {
308 std::vector<IDF::FUGenerated::Info> infos;
309
310 for (auto&& hdb : options.hdbList) {
311 std::string hdbPath = findHDBPath(hdb);
312 verbose << " searching implementations from " << hdbPath << "\n";
313 HDB::CachedHDBManager& manager =
315 std::set<RowID> rows = manager.OperationImplementationIDs();
316 std::vector<IDF::FUGenerated::Info> newInfos;
317 for (auto&& row : rows) {
318 auto opimpl = manager.OperationImplementationByID(row);
319 newInfos.emplace_back(IDF::FUGenerated::Info{
320 opimpl.name, hdbPath, opimpl.id, opimpl.latency});
321 }
322
323 std::sort(
324 newInfos.begin(), newInfos.end(),
326 return a.latency > b.latency;
327 });
328
329 infos.insert(infos.end(), newInfos.begin(), newInfos.end());
330 }
331
332 return infos;
333}
334
335/**
336 * Tries to find full path for hdb file.
337 */
338std::string
339ProGeTools::findHDBPath(std::string name) {
340 if (FileSystem::fileExists(name)) {
341 return name;
342 }
343
344 std::vector<std::string> paths = Environment::hdbPaths();
345 return FileSystem::findFileInSearchPaths(paths, name);
346}
347
348/**
349 * Checks if FU has an implementation in hdbs.
350 */
351bool
354 IDF::FUImplementationLocation& loc, std::ostream& verbose) {
355 (void)verbose;
356 for (auto&& hdb : options.hdbList) {
357 std::string hdbPath = findHDBPath(hdb);
358 HDB::CachedHDBManager& manager =
360 std::set<RowID> rows = manager.fuEntryIDs();
361 for (auto&& row : rows) {
362 auto fuEntry = manager.fuByEntryID(row);
363 if (!fuEntry->hasImplementation() ||
364 !fuEntry->hasArchitecture()) {
365 continue;
366 }
367 auto arch = fuEntry->architecture();
368 auto impl = fuEntry->implementation();
369 // Check that operations match.
370 if (fu.operationCount() != arch.architecture().operationCount()) {
371 continue;
372 }
373 bool wrongLanguage = false;
374 for (int i = 0; i < impl.implementationFileCount(); ++i) {
375 auto f = impl.file(i);
376 if (f.format() ==
378 options.language == ProGe::HDL::Verilog) {
379 wrongLanguage = true;
380 break;
381 } else if (
382 f.format() ==
384 options.language == ProGe::HDL::VHDL) {
385 wrongLanguage = true;
386 break;
387 }
388 }
389 if (wrongLanguage) {
390 continue;
391 }
392 bool found = true;
393 for (int i = 0; i < fu.operationCount(); ++i) {
394 auto op = fu.operation(i);
395 if (!arch.architecture().hasOperation(op->name())) {
396 found = false;
397 break;
398 }
399 if (op->latency() !=
400 arch.architecture().operation(op->name())->latency()) {
401 found = false;
402 break;
403 }
404 }
405 if (!found) {
406 continue;
407 }
408
409 loc.setID(row);
410 loc.setHDBFile(hdbPath);
411 return true;
412 }
413 }
414
415 return false;
416}
417
418/**
419 * Checks if RF has an implementation in hdbs.
420 */
421bool
424 IDF::RFImplementationLocation& loc, std::ostream& verbose) {
425 (void)verbose;
426 for (auto&& hdb : options.hdbList) {
427 std::string hdbPath = findHDBPath(hdb);
428 HDB::CachedHDBManager& manager =
430 std::set<RowID> rows = manager.rfEntryIDs();
431 for (auto&& row : rows) {
432 auto rfEntry = manager.rfByEntryID(row);
433 // Exclude these:
434 if (!rfEntry->hasImplementation() ||
435 !rfEntry->hasArchitecture()) {
436 continue;
437 }
438 auto arch = rfEntry->architecture();
439 auto impl = rfEntry->implementation();
440 bool wrongLanguage = false;
441 for (int i = 0; i < impl.implementationFileCount(); ++i) {
442 auto f = impl.file(i);
443 if (f.format() ==
445 options.language == ProGe::HDL::Verilog) {
446 wrongLanguage = true;
447 break;
448 } else if (
449 f.format() ==
451 options.language == ProGe::HDL::VHDL) {
452 wrongLanguage = true;
453 break;
454 }
455 }
456 if (wrongLanguage) {
457 continue;
458 }
459 if (rf.isUsedAsGuard() != arch.hasGuardSupport()) {
460 continue;
461 }
462 if (rf.outputPortCount() != arch.readPortCount()) {
463 continue;
464 }
465 if (rf.inputPortCount() != arch.writePortCount()) {
466 continue;
467 }
468 if (rf.bidirPortCount() != arch.bidirPortCount()) {
469 continue;
470 }
471 if (1 != arch.latency()) {
472 continue;
473 }
474 if (rf.guardLatency() != arch.guardLatency()) {
475 continue;
476 }
477 if (!arch.hasParameterizedWidth() &&
478 (rf.width() != arch.width())) {
479 continue;
480 }
481 if (!arch.hasParameterizedSize() && (rf.size() != arch.size())) {
482 continue;
483 }
484 if (rf.zeroRegister() != arch.zeroRegister()) {
485 continue;
486 }
487 // Must be a perfect choise.
488 loc.setID(row);
489 loc.setHDBFile(hdbPath);
490 return true;
491 }
492 }
493 return false;
494}
495
496/**
497 * Checks if RF has an implementation in hdbs.
498 */
499bool
502 IDF::IUImplementationLocation& loc, std::ostream& verbose) {
503 (void)verbose;
504 for (auto&& hdb : options.hdbList) {
505 std::string hdbPath = findHDBPath(hdb);
506 HDB::CachedHDBManager& manager =
508 std::set<RowID> rows = manager.rfEntryIDs();
509 for (auto&& row : rows) {
510 auto rfEntry = manager.rfByEntryID(row);
511 // Exclude these:
512 if (!rfEntry->hasImplementation() ||
513 !rfEntry->hasArchitecture()) {
514 continue;
515 }
516 auto arch = rfEntry->architecture();
517 auto impl = rfEntry->implementation();
518 bool wrongLanguage = false;
519 for (int i = 0; i < impl.implementationFileCount(); ++i) {
520 auto f = impl.file(i);
521 if (f.format() ==
523 options.language == ProGe::HDL::Verilog) {
524 wrongLanguage = true;
525 break;
526 } else if (
527 f.format() ==
529 options.language == ProGe::HDL::VHDL) {
530 wrongLanguage = true;
531 break;
532 }
533 }
534 if (wrongLanguage) {
535 continue;
536 }
537 if (iu.isUsedAsGuard() != arch.hasGuardSupport()) {
538 continue;
539 }
540 if (iu.maxReads() != arch.readPortCount()) {
541 continue;
542 }
543 if (1 != arch.writePortCount()) {
544 continue;
545 }
546 if (iu.latency() != arch.latency()) {
547 continue;
548 }
549 if (!arch.hasParameterizedWidth() &&
550 (iu.width() != arch.width())) {
551 continue;
552 }
553 if (!arch.hasParameterizedSize() && (iu.size() != arch.size())) {
554 continue;
555 }
556 // Must be a perfect choise.
557 loc.setID(row);
558 loc.setHDBFile(hdbPath);
559 return true;
560 }
561 }
562 return false;
563}
#define assert(condition)
static MachInfoCmdLineOptions options
Definition MachInfo.cc:46
int nodeCount() const
Node & node(const int index) const
virtual Node & tailNode(const Edge &edge) const
virtual NodeSet sinkNodes() const
virtual EdgeSet inEdges(const Node &node) const
static std::vector< std::string > hdbPaths(bool libraryPathsOnly=false)
static std::string findFileInSearchPaths(const std::vector< std::string > &searchPaths, const std::string &file)
static bool fileExists(const std::string fileName)
static CachedHDBManager & instance(const std::string &hdbFile)
FUArchitecture & architecture() const
Definition FUEntry.cc:129
FUEntry * fuByEntryID(RowID id) const
std::set< RowID > OperationImplementationIDs() const
OperationImplementation OperationImplementationByID(RowID id) const
std::set< RowID > rfEntryIDs() const
RFEntry * rfByEntryID(RowID id) const
std::set< RowID > fuEntryIDs() const
RFArchitecture & architecture() const
Definition RFEntry.cc:145
void addOperation(const Info &op)
std::string name() const
virtual void setHDBFile(std::string file)
bool isNull() const
std::string operationName(int i, const OperationModule &om)
int operationCount(const OperationModule &om)
int moduleCount() const
Operation & referencedOperation() const
OperationIndex & index()
Operation & operation(const char *name)
virtual OperationDAG & dag(int index) const
Definition Operation.cc:148
virtual TCEString name() const
Definition Operation.cc:93
virtual int dagCount() const
Definition Operation.cc:134
static std::string stringToLower(const std::string &source)
virtual int size() const
virtual int width() const
virtual HWOperation * operation(const std::string &name) const
virtual int operationCount() const
virtual int latency() const
virtual int maxReads() const
virtual bool zeroRegister() const
virtual int guardLatency() const
virtual bool isUsedAsGuard() const
virtual int bidirPortCount() const
Definition Unit.cc:174
virtual int inputPortCount(bool countBidir=false) const
Definition Unit.cc:160
virtual int outputPortCount(bool countBidir=false) const
Definition Unit.cc:145
bool checkForSelectableIU(const ProGeOptions &options, TTAMachine::ImmediateUnit &iu, IDF::IUImplementationLocation &loc, std::ostream &verbose)
bool checkForGeneratableFU(const ProGeOptions &options, TTAMachine::FunctionUnit &fu, IDF::FUGenerated &fug, const std::vector< IDF::FUGenerated::Info > &infos, const std::vector< IDF::FUGenerated::DAGOperation > dagops)
Definition ProGeTools.cc:59
std::string findHDBPath(std::string name)
bool checkForSelectableFU(const ProGeOptions &options, TTAMachine::FunctionUnit &fu, IDF::FUImplementationLocation &loc, std::ostream &verbose)
bool findInOptionList(const std::string &option, std::vector< std::string > list, bool enableAll=true)
bool checkForSelectableRF(const ProGeOptions &options, TTAMachine::RegisterFile &rf, IDF::RFImplementationLocation &loc, std::ostream &verbose)
int nodeLatency(OperationDAGNode &node, const std::unordered_map< std::string, int > &maxOpLatency)
int maxLatencyToNode(const OperationDAG &dag, OperationDAGNode &node, const std::unordered_map< std::string, int > &maxOpLatency, bool allowDifference=true)
std::vector< IDF::FUGenerated::Info > createFUGeneratableOperationInfos(const ProGeOptions &options, std::ostream &verbose)
int dagLatency(const OperationDAG &dag, const std::unordered_map< std::string, int > &maxOpLatency)
std::vector< IDF::FUGenerated::DAGOperation > generateableDAGOperations(const std::vector< IDF::FUGenerated::Info > infos, std::ostream &verbose)
bool canGenerateFromDAG(const OperationDAG &dag, const std::vector< IDF::FUGenerated::Info > infos, std::vector< IDF::FUGenerated::Info > *subops)
@ Verilog
Verilog.
Definition ProGeTypes.hh:42
@ VHDL
VHDL.
Definition ProGeTypes.hh:41