OpenASIP  2.0
FUGen.cc
Go to the documentation of this file.
1 /*
2  Copyright (c) 2017-2019 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 FUGen.cc
26  *
27  * @author Lasse Lehtonen 2017 (lasse.lehtonen-no.spam-tut.fi)
28  * @author Kati Tervo 2017-2019 (kati.tervo-no.spam-tuni.fi)
29  * @author Topi Leppänen 2019 (topi.leppanen-no.spam-tuni.fi)
30  */
31 
32 #include <regex>
33 #include "IPXact.hh"
34 #include "FUGen.hh"
35 #include "ProGeTools.hh"
36 #include "ContainerTools.hh"
37 #include "ConstantNode.hh"
38 #include "FUPort.hh"
39 #include "FunctionUnit.hh"
40 #include "HDBManager.hh"
41 #include "HWOperation.hh"
42 #include "NetlistPort.hh"
43 #include "Operand.hh"
44 #include "Operation.hh"
45 #include "OperationIndex.hh"
46 #include "OperationNode.hh"
47 #include "OperationPool.hh"
48 #include "ProGeTypes.hh"
49 #include "TerminalNode.hh"
50 #include "WidthTransformations.hh"
51 #include "BinaryOps.hh"
52 #include "OperationPimpl.hh"
53 #include "Signal.hh"
54 #include "SignalGroupTypes.hh"
55 #include "NetlistPortGroup.hh"
56 #include "MemoryBusInterface.hh"
57 
58 using namespace HDLGenerator;
59 
60 bool
61 FUGen::hasToken(std::string line, std::string token) {
62  auto regex = std::regex("\\b" + token + "\\b");
63  return std::regex_search(line, regex);
64 }
65 
66 std::string
67 FUGen::replaceToken(std::string line, Replace replace) {
68  auto regex = std::regex("\\b" + replace.first + "\\b");
69  return std::regex_replace(line, regex, replace.second);
70 }
71 
74  if (options_.language == ProGe::HDL::VHDL) {
75  return Language::VHDL;
76  } else {
77  return Language::Verilog;
78  }
79 }
80 
81 std::deque<std::string>
82 FUGen::readFile(std::string filename) {
83  std::deque<std::string> file;
84  // replace temps in operation implmentations and keep track of
85  // read temps.
86  if (filename == "") {
87  return file;
88  }
89 
90  std::ifstream implStream(findAbsolutePath(filename));
91  for (std::string line; std::getline(implStream, line);) {
92  file.emplace_back(StringTools::stringToLower(line));
93  }
94  return file;
95 }
96 
97 /**
98  * Searches for file in TCE folders and makes the path absolute.
99  */
100 std::string
101 FUGen::findAbsolutePath(std::string file) {
102  if (file.length() > 4 && file.substr(0, 4) == "tce:") {
103  file = file.substr(4);
104  }
105  std::vector<std::string> paths = Environment::hdbPaths();
106  for (auto file : options_.hdbList) {
107  paths.emplace_back(FileSystem::directoryOfPath(file));
108  }
109  return FileSystem::findFileInSearchPaths(paths, file);
110 }
111 
112 std::string
114  if (stage == 0) {
115  return "operation_in";
116  } else {
117  return "operation_" + std::to_string(stage) + "_r";
118  }
119 }
120 
121 std::string
123  if (stage == 0) {
124  return "load_" + triggerPort_ + "_in";
125  } else {
126  return "optrig_" + std::to_string(stage) + "_r";
127  }
128 }
129 
130 std::string
131 FUGen::opcodeConstant(std::string operation) {
132  return "op_" + operation + "_c";
133 }
134 
135 std::string
136 FUGen::operandSignal(std::string operation, int id) {
137  return operation + "_op" + std::to_string(id);
138 }
139 
140 std::string
142  return "op" + std::to_string(id);
143 }
144 
145 std::string
146 FUGen::pipelineName(std::string port, int cycle) {
147  if (cycle == 0) {
148  return "data_" + port;
149  } else {
150  return "data_" + port + "_" + std::to_string(cycle) + "_r";
151  }
152 }
153 
154 std::string
155 FUGen::pipelineValid(std::string port, int cycle) {
156  return "data_" + port + "_" + std::to_string(cycle) + "_valid_r";
157 }
158 
159 std::string
161  int id;
162  std::string op = node->referencedOperation().name();
164  if (nodeImplementations_.count(node->nodeID())) {
165  id = nodeImplementations_[node->nodeID()];
166  } else {
167  if (!subOpCount_.count(op)) {
168  subOpCount_[op] = 0;
169  }
170  id = subOpCount_[op];
171  subOpCount_[op] += 1;
172  nodeImplementations_[node->nodeID()] = id;
173  }
174  return "subop_" + op + "_" + std::to_string(id);
175 }
176 
177 std::string
179  int id;
180  std::string op = dag->operation().name();
182  if (dagConstants_.count(node->nodeID())) {
183  id = dagConstants_[node->nodeID()].id;
184  } else {
185  if (!dagConstantCount_.count(op)) {
186  dagConstantCount_[op] = 0;
187  }
188  id = dagConstantCount_[op];
189  dagConstantCount_[op] += 1;
190  dagConstants_[node->nodeID()] = {op, node->value(), id};
191  }
192  return constantName(dagConstants_[node->nodeID()]);
193 }
194 
195 std::string
197  return "dag_" + dagc.operation + "_" + std::to_string(dagc.id) + "_c";
198 }
199 
200 int
202  OperationDAGNode& node, int id, OperationDAG* dag) {
203  auto operation = dynamic_cast<OperationNode*>(&node);
204  auto terminal = dynamic_cast<TerminalNode*>(&node);
205  auto constant = dynamic_cast<ConstantNode*>(&node);
206 
207  OperationPool opPool;
208  std::string opName;
209  if (operation) {
210  opName = operation->referencedOperation().name();
211  } else if (terminal) {
212  opName = dag->operation().name();
213  } else if (constant) {
214  return MathTools::requiredBitsSigned(constant->value());
215  } else {
216  assert(false && "Shouldn't be possible to get here.");
217  }
218 
219  opName = StringTools::stringToLower(opName);
220  Operation& op = opPool.operation(opName.c_str());
221  return op.operand(id).width();
222 }
223 
224 /**
225  * Creates the header comment for fu.
226  */
227 void
229  fu_.appendToHeader("Function Unit: " + fug_.name());
230  fu_.appendToHeader("");
231  fu_.appendToHeader("Operations:");
232 
233  if (adfFU_->operationCount() > 1) {
234  size_t maxOpNameLen = 0;
235  for (int i = 0; i < adfFU_->operationCount(); ++i) {
236  TTAMachine::HWOperation* hwop = adfFU_->operation(i);
237  maxOpNameLen = std::max(maxOpNameLen, hwop->name().size());
238  }
239  int opDigits =
240  static_cast<int>(std::ceil(std::log10(adfFU_->operationCount())));
241  for (int i = 0; i < adfFU_->operationCount(); ++i) {
242  TTAMachine::HWOperation* hwop = adfFU_->operation(i);
243  operations_.emplace_back(hwop->name());
244  }
245  std::sort(operations_.begin(), operations_.end());
246  int opcode = 0;
247  for (auto&& op : operations_) {
248  fu_ << BinaryConstant(opcodeConstant(op), opcodeWidth_, opcode);
249  std::ostringstream comment;
250  comment << boost::format(
251  " %-" + std::to_string(maxOpNameLen) + "s : %" +
252  std::to_string(opDigits) + "s") %
253  op % std::to_string(opcode);
254  fu_.appendToHeader(comment.str());
255  opcode++;
256  }
257 
258  } else {
259  TTAMachine::HWOperation* hwop = adfFU_->operation(0);
260  operations_.emplace_back(hwop->name());
261  fu_.appendToHeader(" " + hwop->name() + " : 0");
262  }
263  fu_.appendToHeader("");
264 }
265 
266 void
268  std::string file, std::string format, bool isSynthesizable) {
269  file = findAbsolutePath(file);
270  const std::string DS = FileSystem::DIRECTORY_SEPARATOR;
271  std::string dir = options_.outputDirectory + DS;
272  if (isSynthesizable) {
273  dir += format == "VHDL" ? "vhdl" : "verilog";
274  } else {
275  dir += "blackbox" + DS;
276  dir += format == "VHDL simulation" ? "vhdl" : "verilog";
277  }
278  std::string target =
280  if (!FileSystem::fileExists(target)) {
282  FileSystem::copy(file, target);
283  }
284 }
285 
286 /*
287  * Create actual HDL files.
288  */
289 void
291  if (options_.language == ProGe::HDL::VHDL) {
292  Path dir = Path(options_.outputDirectory) / "vhdl";
293  FileSystem::createDirectory(dir.string());
294  Path file = dir / (fu_.name() + ".vhd");
295  std::ofstream ofs(file);
296  fu_.implement(ofs, Language::VHDL);
297  } else if (options_.language == ProGe::HDL::Verilog) {
298  Path dir = Path(options_.outputDirectory) / "verilog";
299  FileSystem::createDirectory(dir.string());
300  Path file = dir / (fu_.name() + ".v");
301  std::ofstream ofs(file);
302  fu_.implement(ofs, Language::Verilog);
303  }
304 
305  // Copy synthesis files and simulation models.
306  for (auto&& opInfo : fug_.operations()) {
307  std::string hdb = opInfo.hdb;
308  hdb = findAbsolutePath(hdb);
311  manager.OperationImplementationByID(opInfo.id);
312  for (auto&& r : opImpl.resources) {
313  for (size_t i = 0; i < r.simFiles.size(); ++i) {
314  copyImplementation(r.simFiles[i], r.simFormats[i], false);
315  }
316  for (size_t i = 0; i < r.synFiles.size(); ++i) {
317  copyImplementation(r.synFiles[i], r.synFormats[i], true);
318  }
319  }
320  }
321 }
322 
323 /*
324  * Create ports that are always there.
325  */
326 void
328  std::string resetPort;
329  if (ProGeTools::findInOptionList("active low reset", globalOptions_)) {
330  resetPort = "rstx";
331  } else {
332  resetPort = "rst";
333  }
334 
335  fu_ << InPort("clk") << InPort(resetPort) << InPort("glock_in")
336  << OutPort("glockreq_out");
337 
338  if (adfFU_->operationCount() > 1) {
339  fu_ << InPort("operation_in", opcodeWidth_, WireType::Vector);
340  }
341 
342  // operand ports.
343  for (int i = 0; i < adfFU_->portCount(); ++i) {
344  TTAMachine::FUPort* adfPort =
345  static_cast<TTAMachine::FUPort*>(adfFU_->port(i));
346 
347  if (adfPort->isInput()) {
348  fu_ << InPort(
349  "data_" + adfPort->name() + "_in", adfPort->width(),
351  fu_ << InPort("load_" + adfPort->name() + "_in");
352  } else {
353  fu_ << OutPort(
354  "data_" + adfPort->name() + "_out", adfPort->width(),
356  }
357  }
358 
359  if (addressWidth_ > 0) {
360  fu_ << IntegerConstant("addrw_c", addressWidth_);
361  }
362 }
363 
364 void
366  // Check that we can implement the FU.
367  // Cannot implement if FU has multioutput operation that has
368  // different latencies for the outputs.
369  for (auto&& op : operations_) {
370  TTAMachine::HWOperation* hwOp = adfFU_->operation(op);
371  int hwOpOperands = hwOp->operandCount();
372  int prevLatency = -1;
373  for (int operand = 0; operand < hwOpOperands; ++operand) {
374  TTAMachine::FUPort* fuPort = hwOp->port(operand + 1);
375 
376  if (!fuPort->isOutput()) {
377  continue;
378  }
379 
380  int latency = hwOp->latency(operand + 1);
381  if (prevLatency == -1) {
382  prevLatency = latency;
383  } else if (prevLatency != latency) {
384  // TODO: probably not true anymore, but needs to be tested
385  throw std::runtime_error(
386  "FUGen cannot implement multioutput operations (" + op +
387  ") which have different latencies for"
388  " its outputs.");
389  }
390  }
391  }
392 }
393 
394 std::vector<FUGen::Replace>
395 FUGen::buildReplaces(std::string name) {
396  OperationSchedule& schedule = scheduledOperations_[name];
397  std::string op = schedule.baseOp;
398  std::vector<FUGen::Replace> replaces;
399 
400  replaces.emplace_back("glock", "glock_in");
401  replaces.emplace_back("trigger", triggerSignal(schedule.initialCycle));
402 
403  for (auto&& operand : schedule.operands) {
404  int id = operand.id;
405  replaces.emplace_back(
406  operandPlaceholder(id), operandSignal(name, id));
407  }
408  for (int id : schedule.results) {
409  replaces.emplace_back(
410  operandPlaceholder(id), operandSignal(name, id));
411  }
412 
413  if (!baseOperations_.count(op)) {
414  return replaces;
415  }
416 
417  // Resources
418  for (auto&& r : baseOperations_[op].resources) {
419  std::string rName = StringTools::stringToLower(r.name);
420  if (!schedule.resourceOffsets.count(rName)) {
421  assert(false && "Couldn't find resource offset.");
422  }
423  int offset = schedule.resourceOffsets[rName];
424 
425  for (int i = 0; i < r.count; ++i) {
426  int portID = i + 1;
427  int resID = i + offset + 1;
428  std::string file = findAbsolutePath(r.ipxact);
430  for (auto&& p : resource.ports) {
431  std::string pName = StringTools::stringToLower(p.name);
432  std::string replace = pName + "_" + std::to_string(portID);
433  std::string with =
434  rName + "_" + std::to_string(resID) + "_" + pName;
435 
436  replaces.emplace_back(replace, with);
437  }
438  }
439  }
440 
441  // Variables
442  for (auto&& v : baseOperations_[op].variables) {
443  std::string replica;
444  if (v.rename) {
445  replica = name + "_" + v.name;
446  replaces.emplace_back(v.name, replica);
447  } else {
448  bool nameFound = false;
449  for (auto&& old_var : renamedVariables_) {
450  if (old_var.name == v.name) {
451  nameFound = true;
452  }
453  }
454  if (nameFound) {
455  continue;
456  }
457  replica = v.name;
458  }
459  HDB::Variable var = {replica, v.width, v.type, v.rename};
460  renamedVariables_.emplace_back(var);
461  }
462  // Global signals
463  for (auto&& s : baseOperations_[op].globalsignals) {
464  std::string replica;
465  // Not renaming the signals allows them to be directly shared between
466  // ops
467  if (s.rename) {
468  replica = name + "_" + s.name;
469  replaces.emplace_back(s.name, replica);
470  } else {
471  // don't add the same signal multiple times
472  bool nameFound = false;
473  for (auto&& old_var : renamedGlobalSignals_) {
474  if (old_var.name == s.name) {
475  nameFound = true;
476  }
477  }
478  if (nameFound) {
479  continue;
480  }
481  replica = s.name;
482  }
483 
484  HDB::Variable var = {replica, s.width, s.type, s.rename};
485  renamedGlobalSignals_.emplace_back(var);
486  }
487 
488  return replaces;
489 }
490 
491 void
493  std::string filename, std::string opName, std::deque<std::string>& sink) {
494  // replace temps in operation implmentations and keep track of
495  // read temps.
496  std::ifstream implStream(findAbsolutePath(filename));
497  for (std::string line; std::getline(implStream, line);) {
498  line = StringTools::stringToLower(line);
499  for (auto&& p : replacesPerOp_[opName]) {
500  line = replaceToken(line, p);
501  }
502 
503  sink.emplace_back(line);
504  }
505 }
506 
507 /**
508  * (Ugly) heuristics for identifying an LSU data memory port.
509  *
510  * The identification is made by partial match of the port's name.
511  *
512  * @param portName The port name given in HDB.
513  * @return True if the port is LSU data memory port.
514  */
515 bool
516 FUGen::isLSUDataPort(const std::string& portName) {
517  if (!adfFU_->hasAddressSpace()) {
518  return false;
519  }
520 
521  static const std::set<std::string> magicWords{
522  "avalid", "aready", "aaddr", "awren", "astrb",
523  "rvalid", "rready", "rdata", "adata"};
524 
525  for (auto magicWord : magicWords) {
526  if (portName.find(magicWord) != std::string::npos) {
527  //Assume the FU is an LSU
528  isLSU_ = true;
529  return true;
530  }
531  }
532 
533  return false;
534 }
535 /**
536  * (Ugly) heuristics for mapping FUGen generated LSU signal types
537  *
538  * @param portName Name of the port
539  * @return SignalType
540  */
542 FUGen::inferLSUSignal(const std::string& portName) const {
543  size_t pos = 0;
544  using SigT = ProGe::SignalType;
545  if (((pos = portName.find("avalid")) != std::string::npos)) {
546  return SigT::AVALID;
547  } else if (((pos = portName.find("aready")) != std::string::npos)) {
548  return SigT::AREADY;
549  } else if (((pos = portName.find("aaddr")) != std::string::npos)) {
550  return SigT::AADDR;
551  } else if (((pos = portName.find("awren")) != std::string::npos)) {
552  return SigT::AWREN;
553  } else if (((pos = portName.find("astrb")) != std::string::npos)) {
554  return SigT::ASTRB;
555  } else if (((pos = portName.find("rvalid")) != std::string::npos)) {
556  return SigT::RVALID;
557  } else if (((pos = portName.find("rready")) != std::string::npos)) {
558  return SigT::RREADY;
559  } else if (((pos = portName.find("rdata")) != std::string::npos)) {
560  return SigT::RDATA;
561  } else if (((pos = portName.find("adata")) != std::string::npos)) {
562  return SigT::ADATA;
563  }
564  return SigT::UNDEFINED;
565 }
566 
567 void
568 FUGen::createExternalInterfaces(bool genIntegrator) {
569  std::set<std::pair<ProGe::NetlistPort*, ProGe::NetlistPort*>> lsuPorts;
570  Replace replaceAddress = {"addrw_c", std::to_string(addressWidth_)};
571  for (auto&& ei : extIfaces_) {
573  for (auto&& port : info.ports) {
574  std::string width = port.width;
575  if (addressWidth_ > 0) {
576  width = replaceToken(width, replaceAddress);
577  }
578  ProGe::Direction dir;
579  if (port.direction == "out") {
580  fu_ << OutPort(
581  port.name, width, HDLGenerator::WireType::Vector);
582  extOutputs_.emplace(port.name, port.defaultValue);
583  dir = ProGe::Direction::OUT;
584  } else {
585  fu_ << InPort(
586  port.name, width, HDLGenerator::WireType::Vector);
587  extInputs_.emplace(port.name);
588  dir = ProGe::Direction::IN;
589  }
590 
591  std::string extName = moduleName_ + "_" + port.name;
592  ProGe::NetlistPort* ext = NULL;
593  ProGe::NetlistPort* internal = new ProGe::NetlistPort(
594  port.name, width, ProGe::DataType::BIT_VECTOR, dir,
595  *netlistBlock_);
596  if (isLSUDataPort(extName) && !genIntegrator) {
597  ext = new ProGe::NetlistPort(
598  extName, width, ProGe::DataType::BIT_VECTOR, dir, *core_,
599  inferLSUSignal(extName));
600  lsuPorts.insert(std::make_pair(internal, ext));
601  } else {
602  ext = new ProGe::NetlistPort(
603  extName, width, ProGe::DataType::BIT_VECTOR, dir, *core_);
604  core_->netlist().connect(*ext, *internal);
605  }
606  }
607  }
608  if (lsuPorts.empty()) {
609  return;
610  }
611  // Handle LSU data ports.
612  TCEString asName("");
613  if (adfFU_->hasAddressSpace()) {
614  asName = adfFU_->addressSpace()->name();
615  }
616 
617  ProGe::NetlistPortGroup* dmemPortGroup = nullptr;
618  for (auto portPair : lsuPorts) {
619  dmemPortGroup =
620  dmemPortGroup
621  ? dmemPortGroup
624  dmemPortGroup->addPort(*portPair.second);
625  core_->netlist().connect(*portPair.first, *portPair.second);
626  }
627  if (dmemPortGroup != nullptr) {
628  core_->addPortGroup(dmemPortGroup);
629  dmemPortGroup = nullptr;
630  }
631 }
632 
633 void
635  std::map<std::string, int> instantiatedResources;
636  for (auto&& rs : baseOperations_) {
637  for (auto&& r : rs.second.resources) {
638  if (!instantiatedResources.count(r.name)) {
639  instantiatedResources[r.name] = 0;
640  }
641  std::string file = findAbsolutePath(r.ipxact);
642  std::string rName = StringTools::stringToLower(r.name);
643  int rCount = resourceCount_[rName];
644 
645  for (int i = instantiatedResources[r.name]; i < rCount; ++i) {
646  auto module = ipxact::parseComponent(file);
647  Module resource(module, i + 1);
648  resource.set_prefix(rName);
649  fu_ << resource;
650  for (auto&& p : module.ports) {
651  std::string wName = StringTools::stringToLower(
652  rName + "_" + std::to_string(i + 1) + "_" + p.name);
653  if (p.vector) {
654  fu_ << Wire(wName, p.width);
655  } else {
656  fu_ << Wire(wName);
657  }
658 
659  if (p.direction == "in") {
660  resourceInputs_.emplace_back(wName);
661  } else {
662  resourceOutputs_.emplace_back(wName);
663  }
664  }
665  }
666  instantiatedResources[r.name] = rCount;
667  }
668  }
669 }
670 
671 void
673  Asynchronous operationCp("operations_actual_cp");
674  CodeBlock defaultValues;
675  CodeBlock defaultSnippets;
676  CodeBlock triggeredSnippets;
677 
678  for (auto&& d : extOutputs_) {
679  operationCp << DefaultAssign(d.first, d.second);
680  }
681 
682  for (std::string signal : resourceInputs_) {
683  // Zero initialize this configuration to avoid simulation warnings
684  if (isLSU_ && minLatency_ < 3) {
685  operationCp << DefaultAssign(signal, "0");
686  } else {
687  operationCp << DefaultAssign(signal, "-");
688  }
689  }
690 
691  for (auto&& pair : dagConstants_) {
692  auto spec = pair.second;
693  std::string name = constantName(spec);
694  int width = MathTools::requiredBitsSigned(spec.value);
695  fu_ << BinaryConstant(name, width, spec.value);
696  }
697 
698  for (std::string signal : resourceOutputs_) {
699  operationCp.reads(signal);
700  }
701 
702  for (std::string signal : extInputs_) {
703  operationCp.reads(signal);
704  }
705 
706  std::set<std::string> defaultStatements;
707  for (auto&& pair : scheduledOperations_) {
708  auto schedule = pair.second;
709  std::string name = pair.first;
710 
711  for (int id : schedule.results) {
712  std::string source = operandSignal(name, id);
713  // Zero initialize this configuration to avoid simulation warnings
714  if (isLSU_ && minLatency_ < 3) {
715  defaultValues.append(DefaultAssign(source, "0"));
716  } else {
717  defaultValues.append(DefaultAssign(source, "-"));
718  }
719  }
720 
721  for (auto&& operand : schedule.operands) {
722  int id = operand.id;
723 
724  std::string source = operand.signalName;
725  std::string destination = operandSignal(name, id);
726  if (operand.portWidth > operand.operandWidth) {
727  defaultValues.append(Assign(
728  destination,
729  Splice(source, operand.operandWidth - 1, 0)));
730  } else if (operand.portWidth < operand.operandWidth) {
731  defaultValues.append(Assign(
732  destination,
733  Ext(source, operand.operandWidth, operand.portWidth)));
734  } else {
735  defaultValues.append(Assign(destination, LHSSignal(source)));
736  }
737 
738  if (!operand.isOutput) {
739  operationCp.reads(destination);
740  }
741  }
742 
743  replacesPerOp_[name] = buildReplaces(name);
744 
745  std::string baseOp = schedule.baseOp;
746  auto& initial = baseOperations_[baseOp].initial;
747  if (!initial.empty()) {
748  prepareSnippet(name, initial, defaultSnippets, defaultStatements);
749  }
750  }
751 
752  for (int cycle = 0; cycle <= maxLatency_; ++cycle) {
753  Switch opSwitch(LHSSignal(opcodeSignal(cycle)));
754  bool emptySwitch = true;
755 
756  for (std::string op : operations_) {
757  CodeBlock onTrigger;
758  bool emptyBlock = true;
759  auto schedule = scheduledOperations_[op];
760 
761  std::vector<std::string> schedules = schedule.subOperations;
762  schedules.push_back(op);
763 
764  for (std::string subop : schedules) {
765  auto schedule = scheduledOperations_[subop];
766  std::string baseOp = schedule.baseOp;
767  if (schedule.initialCycle == cycle) {
768  auto& impl = baseOperations_[baseOp].implementation;
769  if (!impl.empty()) {
770  std::set<std::string> statements;
771  prepareSnippet(subop, impl, onTrigger, statements);
772  }
773  emptyBlock = false;
774  }
775 
776  if (schedule.finalCycle == cycle) {
777  auto& postOp = baseOperations_[baseOp].postOp;
778  if (!postOp.empty()) {
779  std::set<std::string> statements;
780  prepareSnippet(subop, postOp, onTrigger, statements);
781  }
782  emptyBlock = false;
783  }
784  }
785 
786  if (emptyBlock) {
787  continue;
788  }
789 
790  if (operations_.size() > 1) {
791  Case opCase(opcodeConstant(op));
792  opCase << onTrigger;
793  opSwitch.addCase(opCase);
794  emptySwitch = false;
795  } else {
796  If opIf(
797  Equals(
798  LHSSignal(triggerSignal(cycle)), BinaryLiteral("1")),
799  onTrigger);
800  triggeredSnippets.append(opIf);
801  }
802  }
803 
804  if (!emptySwitch) {
805  opSwitch.addCase(DefaultCase());
806  If opIf(
807  Equals(LHSSignal(triggerSignal(cycle)), BinaryLiteral("1")),
808  opSwitch);
809  triggeredSnippets.append(opIf);
810  }
811  }
812 
813  if (useGlock_) {
814  operationCp.reads("glock_in");
815  }
816 
817  if (useGlockRequest_) {
818  defaultValues.append(Assign("glockreq", BinaryLiteral("0")));
819  }
820 
821  for (auto&& v : renamedVariables_) {
822  int w = std::stoi(v.width);
823  if (v.type == "Logic") {
824  operationCp.addVariable(LogicVariable(v.name, w));
825  } else if (v.type == "Unsigned") {
826  operationCp.addVariable(UnsignedVariable(v.name, w));
827  } else {
828  operationCp.addVariable(SignedVariable(v.name, w));
829  }
830  // Zero initialize this configuration to avoid simulation warnings
831  if (isLSU_ && minLatency_ < 3) {
832  operationCp << DefaultAssign(v.name, "0");
833  } else {
834  operationCp << DefaultAssign(v.name, "-");
835  }
836  }
837  for (auto&& s : renamedGlobalSignals_) {
838  int w = std::stoi(s.width);
839  fu_ << Wire(s.name, w); // creates the signal declaration
840  operationCp.reads(s.name); // adds it to sensitivity list
841  // Zero initialize this configuration to avoid simulation warnings
842  if (isLSU_ && minLatency_ < 3) {
843  operationCp << DefaultAssign(s.name, "0");
844  } else {
845  operationCp << DefaultAssign(s.name, "-");
846  }
847  }
848 
849  operationCp << defaultValues << defaultSnippets << triggeredSnippets;
850  behaviour_ << operationCp;
851 }
852 
853 void
855  std::string name, std::deque<std::string> statements, CodeBlock& sink,
856  std::set<std::string>& addedStatements) {
857  std::deque<std::string> snippet;
858  std::set<std::string> lines;
859  for (std::string line : statements) {
860  std::string replaced = StringTools::stringToLower(line);
861  for (Replace rep : replacesPerOp_[name]) {
862  replaced = replaceToken(replaced, rep);
863  }
864 
865  // Cosmetic improvement: do not repeat statements in the same context
866  if (addedStatements.count(replaced)) {
867  continue;
868  }
869  lines.insert(replaced);
870 
871  snippet.push_back(replaced);
872 
873  if (hasToken(line, "glockreq")) {
874  useGlockRequest_ = true;
875  }
876  if (hasToken(line, "glock")) {
877  useGlock_ = true;
878  }
879  }
880 
881  for (std::string line : lines) {
882  addedStatements.insert(line);
883  }
884 
885  sink.append(HDLOperation(name, snippet, selectedLanguage()));
886 }
887 
888 void
890  // Create lock request wires
891  if (useGlockRequest_) {
892  fu_ << Wire("glockreq");
893  behaviour_ << Assign("glockreq_out", LHSSignal("glockreq"));
894  } else {
895  behaviour_ << Assign("glockreq_out", BinaryLiteral("0"));
896  }
897 
898  // Finalize and set global options.
899  fu_ << behaviour_;
900  for (auto&& option : globalOptions_) {
901  fu_ << Option(option);
902  }
903 }
904 
905 void
907  OperationPool opPool;
908  std::vector<std::string> dagOperations;
909 
910  for (auto&& op : fug_.operations()) {
911  BaseOperation opInfo;
912  opInfo.name = op.operationName;
913  opInfo.latency = op.latency;
914 
915  std::string opHDB = findAbsolutePath(op.hdb);
916  HDB::CachedHDBManager& manager =
919  manager.OperationImplementationByID(op.id);
920 
921  std::string implFile;
922  if (options_.language == ProGe::HDL::VHDL) {
923  opInfo.variables = opImpl.vhdlVariables;
924  opInfo.globalsignals = opImpl.vhdlGlobalSignals;
925  opInfo.implementation = readFile(opImpl.implFileVhdl);
926  opInfo.initial = readFile(opImpl.initialImplFileVhdl);
927  opInfo.postOp = readFile(opImpl.postOpImplFileVhdl);
928  } else {
929  if (opImpl.implFileVerilog == "") {
930  const std::string msg =
931  "Cannot generate operation \"" + opInfo.name +
932  "\" due to missing verilog operation implementation";
933  throw std::runtime_error(msg);
934  }
935  opInfo.variables = opImpl.verilogVariables;
936  opInfo.globalsignals = opImpl.verilogGlobalSignals;
937  opInfo.implementation = readFile(opImpl.implFileVerilog);
938  opInfo.initial = readFile(opImpl.initialImplFileVerilog);
939  opInfo.postOp = readFile(opImpl.postOpImplFileVerilog);
940  }
941  opInfo.resources = opImpl.resources;
942 
943  implLatency_[opInfo.name] = op.latency;
944 
945  baseOperations_.emplace(opInfo.name, opInfo);
946 
947  std::string ifPath = opImpl.absBusDefFile;
948  if (!ifPath.empty()) {
949  extIfaces_.insert(findAbsolutePath(ifPath));
950  }
951  }
952 
953  maxLatency_ = 0;
954  minLatency_ = INT_MAX;
955  for (auto&& op : operations_) {
956  TTAMachine::HWOperation* hwOp = adfFU_->operation(op);
957  int hwOpOperands = hwOp->operandCount();
958  OperationPool opPool;
959 
960  for (int operand = 0; operand < hwOpOperands; ++operand) {
961  TTAMachine::FUPort* fuPort = hwOp->port(operand + 1);
962 
963  if (fuPort->isOutput()) {
964  std::string portName = fuPort->name();
965  int latency = hwOp->latency(operand + 1);
966 
967  auto search = operationCycles_.find(op);
968  if (search != operationCycles_.end()) {
969  operationCycles_[op] = std::max(search->second, latency);
970  } else {
971  operationCycles_[op] = latency;
972  }
973  maxLatency_ = std::max(maxLatency_, latency);
974  minLatency_ = std::min(minLatency_, latency);
975  }
976  }
977 
978  if (baseOperations_.find(op) == baseOperations_.end()) {
979  dagOperations.emplace_back(op);
980  }
981  }
982 
983  for (auto&& op : dagOperations) {
984  int dagCount;
985  {
986  OperationPool opPool;
987  Operation& osalOp = opPool.operation(op.c_str());
988  dagCount = osalOp.dagCount();
989  }
990 
991  if (dagCount < 1) {
992  throw std::runtime_error(op + " has no dags to implement.");
993  }
994 
995  bool implementable = false;
996  for (int i = 0; i < dagCount; ++i) {
997  OperationDAG* dagPtr;
998  {
999  OperationPool opPool;
1000  OperationIndex& index = opPool.index();
1001  Operation* osalOp = index.effectiveOperation(op);
1002  dagPtr = &osalOp->dag(i);
1003  }
1004 
1006  *dagPtr, fug_.operations(), nullptr)) {
1007  continue;
1008  } else {
1009  implementable = true;
1010  implementapleDAGs_[op] = dagPtr;
1011  implLatency_[op] =
1012  ProGeTools::dagLatency(*dagPtr, implLatency_);
1013  break;
1014  }
1015  }
1016 
1017  if (!implementable) {
1018  throw std::runtime_error(op + " has no valid dags to implement.");
1019  }
1020  }
1021 }
1022 
1025  OperationDAG* dag, OperationDAGEdge* edge, bool isOutput) {
1026  OperationDAGNode& srcNode = dag->tailNode(*edge);
1027  int srcID = edge->srcOperand();
1028  int srcWidth = DAGNodeOperandWidth(srcNode, srcID, dag);
1029 
1030  OperationDAGNode& dstNode = dag->headNode(*edge);
1031  int dstID = edge->dstOperand();
1032  int dstWidth = DAGNodeOperandWidth(dstNode, dstID, dag);
1033  auto dstTerminal = dynamic_cast<TerminalNode*>(&dstNode);
1034  if (dstTerminal) {
1035  dstID = dstTerminal->operandIndex();
1036  }
1037 
1038  auto operation = dynamic_cast<OperationNode*>(&srcNode);
1039  auto terminal = dynamic_cast<TerminalNode*>(&srcNode);
1040  auto constant = dynamic_cast<ConstantNode*>(&srcNode);
1041 
1042  std::string signalName;
1043  if (operation) {
1044  std::string srcOp = subOpName(operation);
1045  srcOp = StringTools::stringToLower(srcOp);
1046  signalName = operandSignal(srcOp, srcID);
1047  } else if (terminal) {
1048  std::string srcOp = dag->operation().name();
1049  srcOp = StringTools::stringToLower(srcOp);
1050  srcID = terminal->operandIndex();
1051  signalName = operandSignal(srcOp, srcID);
1052  } else if (constant) {
1053  signalName = constantName(constant, dag);
1054  } else {
1055  assert(false && "It shouldn't be possible to get here.");
1056  }
1057 
1058  FUGen::OperandConnection conn = {
1059  dstID, srcWidth, dstWidth, signalName, isOutput};
1060  return conn;
1061 }
1062 
1063 void
1065  std::set<std::string> instantiatedWires;
1066  for (auto&& op : operations_) {
1067  OperationSchedule schedule;
1068  schedule.baseOp = op;
1069 
1070  if (frontRegistered_) {
1071  schedule.initialCycle = operationCycles_[op] - implLatency_[op];
1072  schedule.finalCycle = operationCycles_[op];
1073  } else if (middleRegistered_) {
1074  schedule.initialCycle =
1075  operationCycles_[op] - implLatency_[op] - 1;
1076  schedule.finalCycle = schedule.initialCycle + implLatency_[op];
1077  } else { // Back-registered
1078  schedule.initialCycle = 0;
1079  schedule.finalCycle = implLatency_[op];
1080  }
1081  assert(
1082  schedule.initialCycle >= 0 &&
1083  "Failure likely due to mis-selected operation implementation");
1084 
1085  OperationPool opPool;
1086  Operation& osalOp = opPool.operation(op.c_str());
1087  TTAMachine::HWOperation* hwOp = adfFU_->operation(op);
1088  for (int i = 1; i <= hwOp->operandCount(); ++i) {
1089  Operand& osalOperand = osalOp.operand(i);
1090  TTAMachine::FUPort* fuPort = hwOp->port(i);
1091  std::string port = fuPort->name();
1092  int width = osalOperand.width();
1093  int accessCycle;
1094  ProGe::Direction dir;
1095 
1096  OperandConnection oper = {
1097  i, fuPort->width(), width,
1098  pipelineName(port, schedule.initialCycle), false};
1099  if (osalOperand.isInput()) {
1100  accessCycle = schedule.initialCycle;
1101  schedule.operands.push_back(oper);
1102  dir = ProGe::Direction::IN;
1103  } else {
1104  accessCycle = operationCycles_[op] - schedule.finalCycle;
1105  schedule.results.insert(i);
1106  dir = ProGe::Direction::OUT;
1107  OutputConnection out = {
1108  width, i, schedule.finalCycle, accessCycle, op};
1109  portInputs_.emplace(port, out);
1110  }
1111 
1112  assert(
1113  accessCycle >= 0 &&
1114  "Failure likely due to mis-selected operation "
1115  "implementation");
1116 
1117  std::string newWire = operandSignal(op, i);
1118  if (!instantiatedWires.count(newWire)) {
1119  fu_ << Wire(newWire, width);
1120  instantiatedWires.insert(newWire);
1121  }
1122 
1123  if (pipelineLength_.find(port) == pipelineLength_.end()) {
1124  pipelineLength_[port] = accessCycle;
1125  } else {
1126  pipelineLength_[port] =
1127  std::max(accessCycle, pipelineLength_[port]);
1128  }
1129 
1130  if (portDirection_.find(port) == portDirection_.end()) {
1131  portDirection_[port] = dir;
1132  } else {
1133  if (portDirection_[port] != dir) {
1134  throw std::runtime_error(
1135  "Unsupported bidirectional port " + port +
1136  ", aborting.");
1137  }
1138  }
1139  }
1140 
1141  if (baseOperations_.find(op) != baseOperations_.end()) {
1142  // No need to arbitrate between suboperations here,
1143  // just use the first resource
1144  for (auto&& res : baseOperations_[op].resources) {
1145  std::string resName = StringTools::stringToLower(res.name);
1146  schedule.resourceOffsets[resName] = 0;
1147  resourceCount_[res.name] =
1148  std::max(resourceCount_[res.name], res.count);
1149  }
1150  } else {
1151  assert(implementapleDAGs_.find(op) != implementapleDAGs_.end());
1152  auto dag = implementapleDAGs_[op];
1153  std::unordered_map<std::string, int> dagResourceCount;
1154 
1155  for (int n = 0; n < dag->nodeCount(); ++n) {
1156  OperationSchedule subopSchedule;
1157  OperationDAGNode& node = dag->node(n);
1158 
1159  OperationNode* operationNode =
1160  dynamic_cast<OperationNode*>(&node);
1161 
1162  if (!operationNode) {
1163  continue;
1164  }
1165 
1166  std::string subOp =
1167  operationNode->referencedOperation().name();
1168  subOp = StringTools::stringToLower(subOp);
1169 
1170  std::string name = subOpName(operationNode);
1171  schedule.subOperations.push_back(name);
1172  subopSchedule.baseOp = subOp;
1173  // Start counting subopcycles from the upper op's initCycle.
1174  subopSchedule.initialCycle =
1175  schedule.initialCycle +
1177  *dag, node, implLatency_, false);
1178  subopSchedule.finalCycle =
1179  subopSchedule.initialCycle + implLatency_[subOp];
1180 
1181  for (auto&& input : dag->inEdges(node)) {
1182  int dstID = input->dstOperand();
1183  int width = DAGNodeOperandWidth(
1184  dag->headNode(*input), dstID, dag);
1185 
1186  std::string newWire = operandSignal(name, dstID);
1187  if (!instantiatedWires.count(newWire)) {
1188  fu_ << Wire(newWire, width);
1189  instantiatedWires.insert(newWire);
1190  }
1191 
1192  subopSchedule.operands.push_back(
1193  subOpConnection(dag, input, false));
1194  }
1195 
1196  for (auto&& output : dag->outEdges(node)) {
1197  int srcID = output->srcOperand();
1198  int width = DAGNodeOperandWidth(
1199  dag->tailNode(*output), srcID, dag);
1200 
1201  std::string newWire = operandSignal(name, srcID);
1202  if (!instantiatedWires.count(newWire)) {
1203  fu_ << Wire(newWire, width);
1204  instantiatedWires.insert(newWire);
1205  }
1206 
1207  subopSchedule.results.insert(srcID);
1208 
1209  auto terminal =
1210  dynamic_cast<TerminalNode*>(&dag->headNode(*output));
1211 
1212  if (terminal) {
1213  schedule.operands.push_back(
1214  subOpConnection(dag, output, true));
1215  }
1216  }
1217 
1218  // TODO: make sure same resource doesn't get used by different
1219  // operations on _different_ pipeline cycles
1220  for (auto&& r : baseOperations_[subOp].resources) {
1221  std::string resName = StringTools::stringToLower(r.name);
1222  if (!dagResourceCount.count(resName)) {
1223  dagResourceCount[resName] = 0;
1224  }
1225  subopSchedule.resourceOffsets[resName] =
1226  dagResourceCount[resName];
1227  dagResourceCount[resName] += r.count;
1228  }
1229 
1230  scheduledOperations_[name] = subopSchedule;
1231  }
1232 
1233  for (auto&& d : dagResourceCount) {
1234  resourceCount_[d.first] =
1235  std::max(resourceCount_[d.first], d.second);
1236  }
1237  }
1238  scheduledOperations_[op] = schedule;
1239  }
1240 }
1241 
1242 void
1244  std::vector<std::string> inOperands;
1245  std::unordered_set<std::string> registeredInOperands;
1246  std::unordered_map<std::string, std::string> currentName;
1247  std::unordered_map<std::string, int> portWidth;
1248 
1249  for (int i = 0; i < adfFU_->portCount(); ++i) {
1250  TTAMachine::FUPort* adfPort =
1251  static_cast<TTAMachine::FUPort*>(adfFU_->port(i));
1252  portWidth[adfPort->name()] = adfPort->width();
1253 
1254  if (adfPort->isInput()) {
1255  currentName[adfPort->name()] = "data_" + adfPort->name() + "_in";
1256 
1257  if (adfPort->isTriggering()) {
1258  triggerPort_ = adfPort->name();
1259  }
1260 
1261  inOperands.emplace_back(adfPort->name());
1262  if (!adfPort->noRegister()) {
1263  registeredInOperands.emplace(adfPort->name());
1264  }
1265 
1266  std::string name = pipelineName(adfPort->name(), 0);
1267  fu_ << Wire(name, adfPort->width());
1268  } else {
1269  currentName[adfPort->name()] = "data_" + adfPort->name() + "_out";
1270  }
1271  }
1272 
1273  if (ProGeTools::findInOptionList(fug_.name(), options_.fuIcGateList)) {
1274  for (auto&& p : inOperands) {
1275  std::string newName = "data_" + p + "_gated";
1276  auto gate = LHSSignal(currentName[p]) &
1277  Sext("load_" + p + "_in", portWidth[p], 1);
1278  behaviour_ << Assign(newName, gate);
1279  currentName[p] = newName;
1280  fu_ << Wire(newName, portWidth[p]);
1281  }
1282  }
1283 
1284  for (auto&& p : inOperands) {
1285  std::string dataPort = currentName[p];
1286  std::string output = pipelineName(p, 0);
1287  if (p != triggerPort_ &&
1288  registeredInOperands.find(p) != registeredInOperands.end()) {
1289  std::string loadPort = "load_" + p + "_in";
1290  std::string shadowReg = "shadow_" + p + "_r";
1291 
1292  fu_ << Register(shadowReg, portWidth[p], ResetOption::Optional);
1293 
1294  auto noLock = Equals(LHSSignal("glock_in"), BinaryLiteral("0"));
1295  auto portLoad = Equals(LHSSignal(loadPort), BinaryLiteral("1"));
1296  If iffi(
1297  noLock && portLoad, Assign(shadowReg, LHSSignal(dataPort)));
1298 
1299  behaviour_ << (Synchronous("shadow_" + p + "_sp") << iffi);
1300 
1301  auto triggerLoad = Equals(
1302  LHSSignal("load_" + triggerPort_ + "_in"),
1303  BinaryLiteral("1"));
1304  If cpIf(
1305  triggerLoad && portLoad,
1306  Assign(output, LHSSignal("data_" + p + "_in")));
1307  cpIf.elseClause(Assign(output, LHSSignal(shadowReg)));
1308 
1309  behaviour_ << (Asynchronous("shadow_" + p + "_cp") << cpIf);
1310  } else {
1311  behaviour_ << Assign(output, LHSSignal(dataPort));
1312  }
1313  }
1314 }
1315 
1316 void
1318  CodeBlock pipelineAssignments;
1319  CodeBlock firstStage;
1320 
1321  // Pipeline for opcode and trigger
1322  // TODO: This might generate some unnecessary registers for some FUs,
1323  // but these should be removed by the synthesis tool
1324  for (int i = 0; i < maxLatency_; ++i) {
1325  if (operations_.size() > 1) {
1326  std::string prevOpcode = opcodeSignal(i);
1327  std::string nextOpcode = opcodeSignal(i + 1);
1328  addRegisterIfMissing(nextOpcode, opcodeWidth_, WireType::Vector);
1329  if (i == 0) {
1330  firstStage.append(Assign(nextOpcode, LHSSignal(prevOpcode)));
1331  } else {
1332  pipelineAssignments.append(
1333  Assign(nextOpcode, LHSSignal(prevOpcode)));
1334  }
1335  }
1336  std::string prevTrigger = triggerSignal(i);
1337  std::string nextTrigger = triggerSignal(i + 1);
1338  addRegisterIfMissing(nextTrigger, 1);
1339  pipelineAssignments.append(
1340  Assign(nextTrigger, LHSSignal(prevTrigger)));
1341  }
1342 
1343  // Pipelines for operand data
1344  for (int i = 0; i < adfFU_->portCount(); ++i) {
1345  auto port = adfFU_->port(i);
1346  int length = pipelineLength_[port->name()];
1347  int width = port->width();
1348  if (portDirection_[port->name()] != ProGe::Direction::IN) {
1349  continue;
1350  }
1351 
1352  for (int i = 0; i < length; ++i) {
1353  std::string prevReg = pipelineName(port->name(), i);
1354  std::string nextReg = pipelineName(port->name(), i + 1);
1355  addRegisterIfMissing(nextReg, width, WireType::Vector);
1356  if (i == 0) {
1357  firstStage.append(Assign(nextReg, LHSSignal(prevReg)));
1358  } else {
1359  pipelineAssignments.append(
1360  Assign(nextReg, LHSSignal(prevReg)));
1361  }
1362  }
1363  }
1364 
1365  If operationTrigger(
1366  Equals(LHSSignal(triggerSignal(0)), BinaryLiteral("1")), firstStage);
1367  pipelineAssignments.append(operationTrigger);
1368  If glock_low(
1369  Equals(LHSSignal("glock_in"), BinaryLiteral("0")),
1370  pipelineAssignments);
1371  Synchronous pipeline("input_pipeline_sp");
1372  pipeline << glock_low;
1373  behaviour_ << pipeline;
1374 }
1375 
1376 void
1377 FUGen::addRegisterIfMissing(std::string name, int width, WireType wt) {
1378  if (!ContainerTools::containsValue(registers_, name)) {
1379  fu_ << Register(name, width, wt, ResetOption::Optional);
1380  registers_.emplace_back(name);
1381  }
1382 }
1383 
1384 void
1386  CodeBlock outputPipeline;
1387  CodeBlock lastStage;
1388 
1389  for (int i = 0; i < adfFU_->portCount(); ++i) {
1390  auto port = adfFU_->port(i);
1391  int length = pipelineLength_[port->name()];
1392  int width = port->width();
1393  if (portDirection_[port->name()] != ProGe::Direction::OUT) {
1394  continue;
1395  }
1396 
1397  auto inputs = portInputs_.equal_range(port->name());
1398  for (int cycle = length; cycle >= 0; --cycle) {
1399  bool cycleActive = false;
1400 
1401  std::string nextReg = pipelineName(port->name(), cycle);
1402  std::string prevReg = pipelineName(port->name(), cycle + 1);
1403  std::string valid = pipelineValid(port->name(), cycle);
1404 
1405  if (cycle == 0) {
1406  fu_ << Wire(nextReg, width, WireType::Vector);
1407  } else {
1408  outputPipeline.append(Assign(valid, BinaryLiteral("1")));
1409  addRegisterIfMissing(nextReg, width, WireType::Vector);
1410  addRegisterIfMissing(valid, 1);
1411  }
1412 
1413  // TODO: build a mux if all operations come from the same cycle
1414  If validOperations(BinaryLiteral("1"), DefaultAssign("dummy"));
1415  for (auto it = inputs.first; it != inputs.second; ++it) {
1416  auto connection = it->second;
1417  if (connection.pipelineStage != cycle) {
1418  continue;
1419  }
1420 
1421  Equals triggered(
1422  LHSSignal(triggerSignal(connection.sourceCycle)),
1423  BinaryLiteral("1"));
1424  LogicalAnd active(
1425  Equals(
1426  LHSSignal(opcodeSignal(connection.sourceCycle)),
1427  LHSSignal(opcodeConstant(connection.operation))),
1428  triggered);
1429 
1430  Ext source(
1431  operandSignal(connection.operation, connection.operandID),
1432  width, connection.operandWidth);
1433 
1434  if (cycleActive) {
1435  if (operations_.size() == 1) {
1436  validOperations.elseIfClause(
1437  triggered, Assign(nextReg, source));
1438  } else {
1439  validOperations.elseIfClause(
1440  active, Assign(nextReg, source));
1441  }
1442  } else {
1443  if (operations_.size() == 1) {
1444  validOperations =
1445  If(triggered, Assign(nextReg, source));
1446  } else {
1447  validOperations = If(active, Assign(nextReg, source));
1448  }
1449  }
1450  cycleActive = true;
1451  }
1452 
1453  bool skip_last_assign = false;
1454  // No need for this on first cycle
1455  if (cycle != length) {
1456  std::string prevValid =
1457  pipelineValid(port->name(), cycle + 1);
1458 
1459  Equals isValid(LHSSignal(prevValid), BinaryLiteral("1"));
1460  if (cycleActive) {
1461  validOperations.elseIfClause(
1462  isValid, Assign(nextReg, LHSSignal(prevReg)));
1463  } else {
1464  if (cycle == 0) {
1465  skip_last_assign = true;
1466  lastStage.append(Assign(nextReg, LHSSignal(prevReg)));
1467  } else {
1468  validOperations =
1469  If(isValid, Assign(nextReg, LHSSignal(prevReg)));
1470  }
1471  }
1472  cycleActive = true;
1473  }
1474 
1475  if (cycle == 0) {
1476  std::string outReg = nextReg + "_r";
1477  addRegisterIfMissing(outReg, width, WireType::Vector);
1478  outputPipeline.append(Assign(outReg, LHSSignal(nextReg)));
1479 
1480  Assign finalStep(nextReg, LHSSignal(outReg));
1481  if (!skip_last_assign) {
1482  if (cycleActive) {
1483  validOperations.elseClause(finalStep);
1484  lastStage.append(validOperations);
1485  } else {
1486  lastStage.append(finalStep);
1487  }
1488  }
1489  } else {
1490  validOperations.elseClause(Assign(valid, BinaryLiteral("0")));
1491  outputPipeline.append(validOperations);
1492  }
1493  }
1494  lastStage.append(Assign(
1495  "data_" + port->name() + "_out",
1496  LHSSignal(pipelineName(port->name(), 0))));
1497  }
1498 
1499  Synchronous sync("output_pipeline_sp");
1500  sync << If(
1501  Equals(LHSSignal("glock_in"), BinaryLiteral("0")), outputPipeline);
1502  behaviour_ << sync;
1503 
1504  Asynchronous async("output_pipeline_cp");
1505  async << lastStage;
1506  behaviour_ << async;
1507 }
1508 
1509 /**
1510  *
1511  * Generate all FUGen FUs.
1512  *
1513  */
1514 void
1516  const ProGeOptions& options, std::vector<std::string> globalOptions,
1517  const std::vector<IDF::FUGenerated>& generatetFUs,
1519  // Generate FU innards.
1520  for (auto fug : generatetFUs) {
1521  FUGen fugen(options, globalOptions, fug, machine, core);
1522 
1523  // Some repetition to have named FUs override an "all"
1524  // e.g. --fu-front-register=all --fu-back-register=lsu
1526  fug.name(), options.fuFrontRegistered, false)) {
1527  fugen.frontRegistered_ = true;
1528  } else if (ProGeTools::findInOptionList(
1529  fug.name(), options.fuMiddleRegistered, false)) {
1530  fugen.middleRegistered_ = true;
1531  } else if (ProGeTools::findInOptionList(
1532  fug.name(), options.fuBackRegistered, false)) {
1533  fugen.backRegistered_ = true;
1534  } else if (ProGeTools::findInOptionList(
1535  fug.name(), options.fuFrontRegistered)) {
1536  fugen.frontRegistered_ = true;
1537  } else if (ProGeTools::findInOptionList(
1538  fug.name(), options.fuMiddleRegistered)) {
1539  fugen.middleRegistered_ = true;
1540  } else { // Default to back-register
1541  fugen.backRegistered_ = true;
1542  }
1543 
1544  fugen.createFUHeaderComment();
1545  fugen.checkForValidity();
1546 
1547  fugen.parseOperations();
1548  fugen.scheduleOperations();
1549  fugen.createMandatoryPorts();
1550  fugen.createExternalInterfaces(!options.integratorName.empty());
1551  fugen.createOperationResources();
1552 
1553  fugen.createShadowRegisters();
1554  fugen.createPortPipeline();
1555  fugen.buildOperations();
1556  fugen.createOutputPipeline();
1557 
1558  fugen.finalizeHDL();
1559  fugen.createImplementationFiles();
1560  }
1561 }
Operand
Definition: Operand.hh:52
FUGen::parseOperations
void parseOperations()
Definition: FUGen.cc:906
FUGen::BaseOperation::latency
int latency
Definition: FUGen.hh:129
OperationDAGEdge::dstOperand
int dstOperand() const
Definition: OperationDAGEdge.cc:54
TTAMachine::FUPort::noRegister
bool noRegister() const
Definition: FUPort.cc:469
FUGen::createShadowRegisters
void createShadowRegisters()
Definition: FUGen.cc:1243
HDB::OperationImplementation::initialImplFileVerilog
std::string initialImplFileVerilog
Definition: OperationImplementation.hh:55
HDLGenerator::ResetOption::Optional
@ Optional
Path
Definition: FileSystem.hh:197
FUGen::pipelineValid
std::string pipelineValid(std::string port, int cycle)
Definition: FUGen.cc:155
OperationPool::operation
Operation & operation(const char *name)
Definition: OperationPool.cc:99
HDLGenerator::If::elseIfClause
void elseIfClause(LHSValue cls, SS ifBlock)
Definition: HDLGenerator.hh:797
FUGen::BaseOperation::resources
std::vector< HDB::OperationImplementationResource > resources
Definition: FUGen.hh:132
HDLGenerator::UnsignedVariable
Definition: HDLGenerator.hh:501
OperationPimpl::name
TCEString name() const
Definition: OperationPimpl.cc:121
FUGen::findAbsolutePath
std::string findAbsolutePath(std::string file)
Definition: FUGen.cc:101
HDLGenerator::BinaryLiteral
Definition: LHSValue.hh:71
HDLGenerator::LogicalAnd
Definition: BinaryOps.hh:51
HDLGenerator::CodeBlock
Definition: HDLGenerator.hh:876
HDLGenerator
Definition: BinaryOps.hh:35
ProGe::SignalGroupType::BYTEMASKED_SRAM_PORT
@ BYTEMASKED_SRAM_PORT
Signal group type for one port SRAM having read and write capability and bitmask for writing with sep...
FUGen::selectedLanguage
HDLGenerator::Language selectedLanguage()
Definition: FUGen.cc:73
BoostGraph::tailNode
virtual Node & tailNode(const Edge &edge) const
FUGen::triggerSignal
std::string triggerSignal(int stage)
Definition: FUGen.cc:122
FileSystem::createDirectory
static bool createDirectory(const std::string &path)
Definition: FileSystem.cc:400
ProGe::NetlistBlock
Definition: NetlistBlock.hh:61
FUGen::replaceToken
std::string replaceToken(std::string line, Replace replace)
Definition: FUGen.cc:67
ProGe::Verilog
@ Verilog
Verilog.
Definition: ProGeTypes.hh:42
FUGen::BaseOperation::globalsignals
std::vector< HDB::Variable > globalsignals
Definition: FUGen.hh:131
FUGen::BaseOperation
Definition: FUGen.hh:127
FUGen::OperationSchedule::subOperations
std::vector< std::string > subOperations
Definition: FUGen.hh:124
HDLGenerator::HDLOperation
Definition: HDLGenerator.hh:140
machine
TTAMachine::Machine * machine
the architecture definition of the estimated processor
Definition: EstimatorCmdLineUI.cc:59
BoostGraph::headNode
virtual Node & headNode(const Edge &edge) const
FUGen::finalizeHDL
void finalizeHDL()
Definition: FUGen.cc:889
TTAMachine::HWOperation
Definition: HWOperation.hh:52
HDLGenerator::DefaultAssign
Definition: HDLGenerator.hh:366
FUGen::checkForValidity
void checkForValidity()
Definition: FUGen.cc:365
HDLGenerator::SignedVariable
Definition: HDLGenerator.hh:516
ProGe::BIT_VECTOR
@ BIT_VECTOR
Several bits.
Definition: ProGeTypes.hh:48
FUGen::hasToken
bool hasToken(std::string line, std::string token)
Definition: FUGen.cc:61
FUGen::subOpName
std::string subOpName(OperationNode *node)
Definition: FUGen.cc:160
BinaryOps.hh
HDB::OperationImplementation::initialImplFileVhdl
std::string initialImplFileVhdl
Definition: OperationImplementation.hh:56
FUGen::BaseOperation::initial
std::deque< std::string > initial
Definition: FUGen.hh:134
HDLGenerator::Asynchronous::addVariable
void addVariable(Var op)
Definition: HDLGenerator.hh:913
FUGen::frontRegistered_
bool frontRegistered_
Definition: FUGen.hh:257
FUGen::BaseOperation::postOp
std::deque< std::string > postOp
Definition: FUGen.hh:135
ProGeOptions
Definition: ProGeOptions.hh:41
HDLGenerator::Module
Definition: HDLGenerator.hh:1163
HDLGenerator::CodeBlock::append
void append(SS cc)
Definition: HDLGenerator.hh:881
HDLGenerator::Module::set_prefix
void set_prefix(std::string prefix)
Definition: HDLGenerator.hh:1202
Operand::width
virtual int width() const
Definition: Operand.cc:318
HDB::OperationImplementation::postOpImplFileVerilog
std::string postOpImplFileVerilog
Definition: OperationImplementation.hh:54
FUGen::createOperationResources
void createOperationResources()
Definition: FUGen.cc:634
ipxact::BusInfo
Definition: IPXact.hh:59
FUGen::OperationSchedule::resourceOffsets
std::map< std::string, int > resourceOffsets
Definition: FUGen.hh:123
GraphNode::nodeID
int nodeID() const
ipxact::parseBus
BusInfo parseBus(std::string file)
Definition: IPXact.cc:39
HDLGenerator::If::elseClause
void elseClause(SS elseBlock)
Definition: HDLGenerator.hh:804
TerminalNode
Definition: TerminalNode.hh:47
OperationPool::index
OperationIndex & index()
Definition: OperationPool.cc:109
HDB::Variable
Definition: OperationImplementation.hh:40
FUGen::createOutputPipeline
void createOutputPipeline()
Definition: FUGen.cc:1385
FUGen::DAGConstant
Definition: FUGen.hh:138
MemoryBusInterface.hh
FUGen::BaseOperation::name
std::string name
Definition: FUGen.hh:128
HDLGenerator::Sext
Definition: WidthTransformations.hh:82
OperationNode::referencedOperation
Operation & referencedOperation() const
Definition: OperationNode.cc:70
HDLGenerator::Switch::addCase
void addCase(Case rhs)
Definition: HDLGenerator.hh:748
HDLGenerator::BinaryConstant
Definition: HDLGenerator.hh:244
FUGen::createMandatoryPorts
void createMandatoryPorts()
Definition: FUGen.cc:327
FUGen::OutputConnection
Definition: FUGen.hh:108
HDB::Variable::width
std::string width
Definition: OperationImplementation.hh:42
OperationNode
Definition: OperationNode.hh:47
FUGen::scheduleOperations
void scheduleOperations()
Definition: FUGen.cc:1064
HDLGenerator::Splice
Definition: WidthTransformations.hh:68
TTAMachine::FUPort::isTriggering
virtual bool isTriggering() const
Definition: FUPort.cc:182
Operation::name
virtual TCEString name() const
Definition: Operation.cc:93
HDB::OperationImplementation::postOpImplFileVhdl
std::string postOpImplFileVhdl
Definition: OperationImplementation.hh:53
ipxact::ModuleInfo::ports
std::vector< Port > ports
Definition: IPXact.hh:56
OperationDAGEdge
Definition: OperationDAGEdge.hh:38
FileSystem::fileOfPath
static std::string fileOfPath(const std::string pathName)
Definition: FileSystem.cc:101
FUGen::implement
static void implement(const ProGeOptions &options, std::vector< std::string > globalOptions, const std::vector< IDF::FUGenerated > &generatetFUs, const TTAMachine::Machine &machine, ProGe::NetlistBlock *core)
Definition: FUGen.cc:1515
FUGen::DAGConstant::operation
std::string operation
Definition: FUGen.hh:139
HDB::CachedHDBManager
Definition: CachedHDBManager.hh:63
FUGen::BaseOperation::implementation
std::deque< std::string > implementation
Definition: FUGen.hh:133
HDLGenerator::Option
Definition: HDLGenerator.hh:207
HDB::OperationImplementation::verilogVariables
std::vector< Variable > verilogVariables
Definition: OperationImplementation.hh:60
HDLGenerator::Wire
Definition: HDLGenerator.hh:315
NetlistPortGroup.hh
ProGeTools::dagLatency
int dagLatency(const OperationDAG &dag, const std::unordered_map< std::string, int > &maxOpLatency)
Definition: ProGeTools.cc:234
assert
#define assert(condition)
Definition: Application.hh:86
FUGen::middleRegistered_
bool middleRegistered_
Definition: FUGen.hh:258
FUGen::readFile
std::deque< std::string > readFile(std::string filename)
Definition: FUGen.cc:82
TTAMachine::HWOperation::port
virtual FUPort * port(int operand) const
Definition: HWOperation.cc:320
HDLGenerator::Equals
Definition: BinaryOps.hh:81
FUGen::OperationSchedule::operands
std::vector< OperandConnection > operands
Definition: FUGen.hh:121
FUGen::OperationSchedule::results
std::set< int > results
Definition: FUGen.hh:122
TTAMachine::FUPort
Definition: FUPort.hh:46
ProGe::NetlistPortGroup
Definition: NetlistPortGroup.hh:53
HDLGenerator::Case
Definition: HDLGenerator.hh:645
HDB::OperationImplementation::verilogGlobalSignals
std::vector< Variable > verilogGlobalSignals
Definition: OperationImplementation.hh:62
FUGen::createFUHeaderComment
void createFUHeaderComment()
Definition: FUGen.cc:228
ProGe::VHDL
@ VHDL
VHDL.
Definition: ProGeTypes.hh:41
HWOperation.hh
TTAMachine::HWOperation::name
const std::string & name() const
Definition: HWOperation.cc:141
HDLGenerator::Asynchronous::reads
virtual void reads(const std::string &var) override
Definition: HDLGenerator.hh:918
OperationDAGEdge::srcOperand
int srcOperand() const
Definition: OperationDAGEdge.cc:49
OperationDAGNode
Definition: OperationDAGNode.hh:45
Environment::hdbPaths
static std::vector< std::string > hdbPaths(bool libraryPathsOnly=false)
Definition: Environment.cc:683
FUGen::createExternalInterfaces
void createExternalInterfaces(bool genIntegrator)
Definition: FUGen.cc:568
FUGen::Replace
std::pair< std::string, std::string > Replace
Definition: FUGen.hh:98
HDB::OperationImplementation::implFileVerilog
std::string implFileVerilog
Definition: OperationImplementation.hh:52
ProGeTools.hh
HDLGenerator::OutPort
Definition: HWGen/HDLPort.hh:99
NetlistPort.hh
ProGe::MemoryBusInterface
Definition: MemoryBusInterface.hh:46
OperationIndex.hh
HDLGenerator::WireType
WireType
Definition: HWGenTools.hh:34
OperationDAG
Definition: OperationDAG.hh:43
FileSystem::directoryOfPath
static std::string directoryOfPath(const std::string fileName)
Definition: FileSystem.cc:79
FUGen::DAGNodeOperandWidth
int DAGNodeOperandWidth(OperationDAGNode &node, int id, OperationDAG *dag)
Definition: FUGen.cc:201
FUGen::OperationSchedule
Definition: FUGen.hh:116
ConstantNode
Definition: ConstantNode.hh:43
FileSystem::copy
static void copy(const std::string &source, const std::string &target)
Definition: FileSystem.cc:524
HDLGenerator::Language::Verilog
@ Verilog
HDLGenerator::IntegerConstant
Definition: HDLGenerator.hh:287
ProGe::NetlistPortGroup::addPort
void addPort(NetlistPort &port)
Definition: NetlistPortGroup.cc:93
FUGen::operandPlaceholder
std::string operandPlaceholder(int id)
Definition: FUGen.cc:141
HDLGenerator::Generatable::width
virtual Width width(const std::string &name)
Definition: Generatable.hh:134
Operation.hh
HDLGenerator::Synchronous
Definition: HDLGenerator.hh:982
FUGen::addRegisterIfMissing
void addRegisterIfMissing(std::string name, int width, HDLGenerator::WireType wt=HDLGenerator::WireType::Auto)
Definition: FUGen.cc:1377
FUGen::buildOperations
void buildOperations()
Definition: FUGen.cc:672
OperationPimpl.hh
FUGen::opcodeConstant
std::string opcodeConstant(std::string operation)
Definition: FUGen.cc:131
FUGen::backRegistered_
bool backRegistered_
Definition: FUGen.hh:259
IPXact.hh
ProGeTypes.hh
FUGen::constantName
std::string constantName(ConstantNode *node, OperationDAG *dag)
Definition: FUGen.cc:178
HDLGenerator::Language
Language
Definition: HWGenTools.hh:33
Signal.hh
HDLGenerator::If
Definition: HDLGenerator.hh:786
TTAMachine::Port::isOutput
virtual bool isOutput() const
Definition: Port.cc:308
FUGen.hh
Operation
Definition: Operation.hh:59
FUGen::opcodeSignal
std::string opcodeSignal(int stage)
Definition: FUGen.cc:113
WidthTransformations.hh
FUGen::OperationSchedule::baseOp
std::string baseOp
Definition: FUGen.hh:117
HDB::OperationImplementation::resources
std::vector< OperationImplementationResource > resources
Definition: OperationImplementation.hh:58
HDLGenerator::LHSSignal
Definition: LHSValue.hh:66
HDB::OperationImplementation::vhdlVariables
std::vector< Variable > vhdlVariables
Definition: OperationImplementation.hh:59
HDLGenerator::Asynchronous
Definition: HDLGenerator.hh:900
FileSystem::DIRECTORY_SEPARATOR
static const std::string DIRECTORY_SEPARATOR
Definition: FileSystem.hh:189
Operand.hh
options
static MachInfoCmdLineOptions options
Definition: MachInfo.cc:46
HDB::OperationImplementation::absBusDefFile
std::string absBusDefFile
Definition: OperationImplementation.hh:57
TTAMachine::HWOperation::operandCount
int operandCount() const
Definition: HWOperation.cc:306
ProGe::SignalType
SignalType
Definition: SignalTypes.hh:42
ipxact::BusInfo::ports
std::vector< Port > ports
Definition: IPXact.hh:61
HDLGenerator::InPort
Definition: HWGen/HDLPort.hh:110
Operation::operand
virtual Operand & operand(int id) const
Definition: Operation.cc:541
Operation::dagCount
virtual int dagCount() const
Definition: Operation.cc:134
HDLGenerator::Ext
Definition: WidthTransformations.hh:39
FUGen::operandSignal
std::string operandSignal(std::string operation, int id)
Definition: FUGen.cc:136
HDLGenerator::DefaultCase
Definition: HDLGenerator.hh:614
HDB::HDBManager::OperationImplementationByID
OperationImplementation OperationImplementationByID(RowID id) const
Definition: HDBManager.cc:2248
ConstantNode::value
virtual long value() const
Definition: ConstantNode.cc:60
ProGeTools::maxLatencyToNode
int maxLatencyToNode(const OperationDAG &dag, OperationDAGNode &node, const std::unordered_map< std::string, int > &maxOpLatency, bool allowDifference=true)
Definition: ProGeTools.cc:274
FUGen
Definition: FUGen.hh:58
FUGen::readImplementation
void readImplementation(std::string filename, std::string opName, std::deque< std::string > &sink)
Definition: FUGen.cc:492
FUGen::buildReplaces
std::vector< Replace > buildReplaces(std::string opName)
Definition: FUGen.cc:395
FileSystem::fileExists
static bool fileExists(const std::string fileName)
OperationIndex::effectiveOperation
Operation * effectiveOperation(const TCEString &name)
Definition: OperationIndex.cc:454
HDLGenerator::LogicVariable
Definition: HDLGenerator.hh:482
TTAMachine::Port::name
virtual std::string name() const
Definition: Port.cc:141
ipxact::ModuleInfo
Definition: IPXact.hh:53
FUGen::DAGConstant::id
int id
Definition: FUGen.hh:141
TCEString
Definition: TCEString.hh:53
SignalGroupTypes.hh
FUPort.hh
OperationIndex
Definition: OperationIndex.hh:58
TerminalNode.hh
HDB::IN
@ IN
Input port.
Definition: HDBTypes.hh:41
FUGen::isLSUDataPort
bool isLSUDataPort(const std::string &portName)
Definition: FUGen.cc:516
FUGen::OperandConnection
Definition: FUGen.hh:100
ProGeTools::canGenerateFromDAG
bool canGenerateFromDAG(const OperationDAG &dag, const std::vector< IDF::FUGenerated::Info > infos, std::vector< IDF::FUGenerated::Info > *subops)
Definition: ProGeTools.cc:194
FUGen::BaseOperation::variables
std::vector< HDB::Variable > variables
Definition: FUGen.hh:130
TTAMachine::Port::isInput
virtual bool isInput() const
Definition: Port.cc:298
HDLGenerator::Assign
Definition: HDLGenerator.hh:539
HDLGenerator::WireType::Vector
@ Vector
ProGe::NetlistPort
Definition: NetlistPort.hh:70
HDLGenerator::Register
Definition: HDLRegister.hh:51
ConstantNode.hh
ContainerTools::containsValue
static bool containsValue(const ContainerType &aContainer, const ElementType &aKey)
OperationNode.hh
TTAMachine::HWOperation::latency
int latency() const
Definition: HWOperation.cc:216
FUGen::createImplementationFiles
void createImplementationFiles()
Definition: FUGen.cc:290
OperationPool
Definition: OperationPool.hh:52
HDLGenerator::Switch
Definition: HDLGenerator.hh:743
HDBManager.hh
DS
#define DS
Definition: LLVMBackend.cc:124
HDB::OperationImplementation::vhdlGlobalSignals
std::vector< Variable > vhdlGlobalSignals
Definition: OperationImplementation.hh:61
Operand::isInput
virtual bool isInput() const
Definition: Operand.cc:145
FileSystem::findFileInSearchPaths
static std::string findFileInSearchPaths(const std::vector< std::string > &searchPaths, const std::string &file)
Definition: FileSystem.cc:562
ProGe::Signal
Definition: Signal.hh:46
HDLGenerator::Language::VHDL
@ VHDL
ProGe::Direction
Direction
Direction of the port.
Definition: ProGeTypes.hh:52
FUGen::copyImplementation
void copyImplementation(std::string file, std::string format, bool isSynthesizable)
Definition: FUGen.cc:267
OperationPool.hh
OperationDAG::operation
const class OperationPimpl & operation() const
Definition: OperationDAG.hh:59
FUGen::createPortPipeline
void createPortPipeline()
Definition: FUGen.cc:1317
MathTools::requiredBitsSigned
static int requiredBitsSigned(SLongWord number)
FUGen::subOpConnection
OperandConnection subOpConnection(OperationDAG *dag, OperationDAGEdge *edge, bool isOutput)
Definition: FUGen.cc:1024
FUGen::pipelineName
std::string pipelineName(std::string port, int cycle)
Definition: FUGen.cc:146
ipxact::parseComponent
ModuleInfo parseComponent(std::string file)
Definition: IPXact.cc:86
ProGeTools::findInOptionList
bool findInOptionList(const std::string &option, std::vector< std::string > list, bool enableAll=true)
Definition: ProGeTools.cc:124
FUGen::OperationSchedule::initialCycle
int initialCycle
Definition: FUGen.hh:119
FUGen::prepareSnippet
void prepareSnippet(std::string name, std::deque< std::string > statements, HDLGenerator::CodeBlock &sink, std::set< std::string > &addedStatements)
Definition: FUGen.cc:854
HDB::OUT
@ OUT
Output port.
Definition: HDBTypes.hh:42
Operation::dag
virtual OperationDAG & dag(int index) const
Definition: Operation.cc:148
FUGen::inferLSUSignal
ProGe::Signal inferLSUSignal(const std::string &portName) const
Definition: FUGen.cc:542
StringTools::stringToLower
static std::string stringToLower(const std::string &source)
Definition: StringTools.cc:160
TerminalNode::operandIndex
virtual int operandIndex() const
Definition: TerminalNode.cc:60
FUGen::OperationSchedule::finalCycle
int finalCycle
Definition: FUGen.hh:120
HDB::OperationImplementation
Definition: OperationImplementation.hh:47
TTAMachine::BaseFUPort::width
virtual int width() const
Definition: BaseFUPort.cc:109
HDB::OperationImplementation::implFileVhdl
std::string implFileVhdl
Definition: OperationImplementation.hh:51
TTAMachine::Machine
Definition: Machine.hh:73
FunctionUnit.hh
ContainerTools.hh
HDB::CachedHDBManager::instance
static CachedHDBManager & instance(const std::string &hdbFile)
Definition: CachedHDBManager.cc:89