CGRA-ME
Module.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * The software programs comprising "CGRA-ME" and the documentation provided
3  * with them are copyright by its authors and the University of Toronto. Only
4  * non-commercial, not-for-profit use of this software is permitted without ex-
5  * plicit permission. This software is provided "as is" with no warranties or
6  * guarantees of support. See the LICENCE for more details. You should have re-
7  * ceived a copy of the full licence along with this software. If not, see
8  * <http://cgra-me.ece.utoronto.ca/license/>.
9  ******************************************************************************/
10 
11 // Define statements included in .h file
12 #include <CGRA/Module.h>
13 #include <CGRA/ModuleProcedures.h>
14 #include <CGRA/ModuleElastic.h>
15 
16 #include <coreir/passes/analysis/coreirjson.h>
17 
18 #include <ios>
19 #include <fstream>
20 #include <ostream>
21 #include <sstream>
22 #include <regex>
23 
24 namespace {
25  std::string makeParameterListSyntaxItem(const std::vector<ResolvedVeroligModuleParameter>& resolved_params) {
26  if (resolved_params.empty()) {
27  return "";
28  } else {
29  std::string paramstr = "#(";
30 
31  for (const auto& resolved_param : resolved_params) {
32  paramstr += '.' + resolved_param.name + '(' + resolved_param.value + "), ";
33  }
34 
35  paramstr[paramstr.size() - 2] = ')'; // overwrite trailing comma with closing paren! (keep the space)
36  return paramstr;
37  }
38  }
39 
40  std::pair<Port,Port> splitBidirPort(const Port& p) {
41  auto result = std::make_pair(p, p);
42  result.first.name += "_in";
43  result.second.name += "_out";
44  result.first.pt = PORT_INPUT;
45  result.second.pt = PORT_OUTPUT;
46  return result;
47  }
48 
49  std::string makePortDeclaration(const Port& p, const char* indent) {
50  std::string result;
51  if (p.pt == PORT_BIDIR) {
52  const auto ioport_copies = splitBidirPort(p);
53  result += indent + ioport_copies.first.makeVerilogDeclaration() + '\n';
54  result += indent + ioport_copies.second.makeVerilogDeclaration() + '\n';
55  } else {
56  result += indent + p.makeVerilogDeclaration() + '\n';
57  }
58  return result;
59  }
60 
61  template<typename Ports, typename Ports2>
62  std::string makePortsDeclaration(const Ports& ports, const Ports2& portsToPropagate, const char* indent) {
63  std::string result;
64  for (auto& port : ports) {
65  result += makePortDeclaration(*port.second, SET_INDENT);
66  }
67  for (auto& port : portsToPropagate) {
68  result += makePortDeclaration(port, SET_INDENT);
69  }
70  return result;
71  }
72 
73  template<typename Ports, typename Ports2>
74  nlohmann::json makeCoreIRInterface(const Ports& ports, const Ports2& portsToPropagate) {
75  nlohmann::json result = {};
76 
77  for (auto& port : ports) {
78  if (port.second->pt == port_type::PORT_BIDIR) {
79  const auto ioport_copies = splitBidirPort(*port.second);
80  result.push_back(ioport_copies.first.name);
81  result.push_back(ioport_copies.second.name);
82  } else {
83  std::string portName = port.second->getName();
84  result.push_back(portName);
85  }
86  }
87 
88  for (auto& port : portsToPropagate) {
89  std::string portName = port.getName();
90  result.push_back(portName);
91  }
92 
93  return result;
94  }
95 
96 } // end anon namespace
97 
98 std::ostream& operator<<(std::ostream& os, VerilogType vt) {
99  switch(vt) {
100  case VerilogType::CGRAME: return os << "CGRAME";
101  case VerilogType::CoreIR: return os << "CoreIR";
102 
103  default: return os << "FIXME_UNHANDLED_VerilogType_PRINTED";
104  }
105 }
106 
107 std::string Port::makeVerilogDeclaration() const {
108  std::string result;
109  switch (pt) {
110  case port_type::PORT_INPUT: result += "input"; break;
111  case port_type::PORT_OUTPUT: result += "output"; break;
112  case port_type::PORT_OUTPUT_REG: result += "output reg"; break;
113  case port_type::PORT_BIDIR: result += "inout"; break;
114  default: throw make_from_stream<cgrame_error>([&](auto&& s) {
115  s << "unhandled port_type " << pt << " in " << __func__;
116  });
117  }
118  if (not parameter.empty()) {
119  result += " [" + parameter + "-1:0]";
120  } else {
121  result += " [" + std::to_string(size - 1) + ":0]";
122  }
123 
124  result += ' ' + name + ';';
125 
126  return result;
127 }
128 
129 // Constructor
130 Module::Module(std::string name, Location loc, unsigned size, bool isElastic)
131  : Module(name, "", loc, size, isElastic)
132 { }
133 
134 Module::Module(std::string name, std::string template_name, Location loc, unsigned size, bool isElastic)
135  : parameterlist()
136  , ports()
137  , connections()
138  , submodules()
139  , configcells()
140  , parent(nullptr)
141  , data_size(size)
142  , templateName(template_name)
143  , name(name)
144  , adds_synchronous_circuitry(false)
145  , isElastic(isElastic)
146  , loc(loc)
147 { }
148 
149 // Destructor, handling dynamically declared data
151 {
152  for(auto it = connections.begin(); it != connections.end(); ++it) // Deleting connections
153  delete it->second;
154  for(auto it = ports.begin(); it != ports.end(); ++it) // Deleting ports
155  delete it->second;
156  for(auto it = submodules.begin(); it != submodules.end(); ++it) // Deleting submodules
157  delete it->second;
158  for(auto it = configcells.begin(); it != configcells.end(); ++it) // Deleting configcells
159  delete it->second;
160 }
161 
162 // Function that returns ALL the modules that have config cells attached to them, and their order
163 // This is a void function insead of a std::vector<Module*> function because it would otherwise use lots of memory (as it is recursive)
164 void Module::genConfigOrder(std::vector<ConfigCell*> & ConfigTable) const
165 {
166  for(const auto& name_and_configcell : configcells) {
167  ConfigTable.push_back(name_and_configcell.second);
168  }
169 
170  for(const auto& name_and_submodule : submodules) {
171  name_and_submodule.second->genConfigOrder(ConfigTable);
172  }
173 }
174 
175 void Module::genVerilogCGRAME(std::string dir) {
176  std::set<std::string> PrintedModules; // Data structure to keep track of the modules that were printed
177  std::queue<Module*> ToPrint; // Modules to print
178  GetModulesToPrint(ToPrint, PrintedModules); // Get the modules that need to be printed (puts them in queue)
179  // FIXME: currently follows how modules are queued;
180  // however, these variable names are horrible and
181  // needs an update
182  std::set<unsigned> PrintedConfigs;
183  std::queue<ConfigCell*> ConfigsToPrint;
184  GetConfigsToPrint(ConfigsToPrint, PrintedConfigs);
185 
186  while (!ToPrint.empty()) // Printing out the module prototypes in the queue
187  {
188  std::string filename = dir + ToPrint.front()->GenericName() + ".v";
189  std::cout << " Generating \"" << filename << "\" ... ";
190 
191  std::streambuf* original_sbuf = std::cout.rdbuf();
192  std::ofstream hdl_filebuf(filename);
193  std::cout.rdbuf(hdl_filebuf.rdbuf()); // Redirects to new file
194 
195  // Dumping module Verilog
196  ToPrint.front()->GenModuleVerilog(); // Printing the top
197  ToPrint.pop(); // Shrinking the queue
198 
199  std::cout.rdbuf(original_sbuf); // Restores printout
200  std::cout << "Done!" << std::endl;
201  }
202  while (!ConfigsToPrint.empty())
203  {
204  std::string cellSize = std::to_string(ConfigsToPrint.front()->getStorageSize());
205  std::string filename = dir + "configCell_" + cellSize + "b.v";
206  std::cout << " Generating \"" << filename << "\" ... ";
207 
208  std::streambuf* original_sbuf = std::cout.rdbuf();
209  std::ofstream hdl_filebuf(filename);
210  std::cout.rdbuf(hdl_filebuf.rdbuf()); // Redirects to new file
211  ConfigsToPrint.front()->GenModuleVerilog();
212  ConfigsToPrint.pop();
213 
214  std::cout.rdbuf(original_sbuf); // Restores printout
215  std::cout << "Done!" << std::endl;
216  }
217 }
218 
219 // Determine the modules necessary to print out
220 void Module::GetModulesToPrint(std::queue<Module*> & ToPrint, std::set<std::string> & PrintedModules)
221 {
222  // Checking to see if the module has been processed already
223  std::string UniqueModuleName = GenericName(); // Getting unique string to identify the module
224 
225  // Check to see if the module was processed
226  if (PrintedModules.find(UniqueModuleName) != PrintedModules.end()) // Already set to be printed
227  return;
228 
229  // Otherwise, the module has not been printed yet, add it to the printed module list and generate verilog code (IMPORTANT TO DO THIS AFTER SUBMODULE CALLS)
230  PrintedModules.insert(UniqueModuleName); // Mappping the hash to the name of the function that will be printed
231  ToPrint.push(this); // Adding the print job to the queue
232 
233  // Recursive calls for submodules - get necessary submodules to print
234  for(const auto& name_and_submodule : submodules)
235  name_and_submodule.second->GetModulesToPrint(ToPrint, PrintedModules);
236 }
237 
238 // Use `uniq` as reference to determine whether module itself contains config
239 // cell of new size, and populate `q`
240 void Module::GetConfigsToPrint(std::queue<ConfigCell*>& q, std::set<unsigned>& uniq)
241 {
242  if (hasConfigCells())
243  {
244  for (const auto& it : configcells)
245  {
246  auto ccell = it.second;
247  auto size = ccell->getStorageSize();
248  if (uniq.find(size) == uniq.end()) // new size found
249  {
250  uniq.insert(size);
251  q.push(ccell);
252  }
253  }
254  }
255  for(const auto& it : submodules)
256  it.second->GetConfigsToPrint(q, uniq);
257 }
258 
259 // This generates a generic name for a module... This can be overriden!
260 std::string Module::GenericName()
261 {
262  //NOTE: This method used to return the name member after removing
263  //all numeric characters within the string, for unclear reasons
264  return this->templateName;
265 }
266 
267 // Generates the Verilog code for a module
269 {
270  // Determining if there are config cells in the module
271  bool HasConfig = moduleRequiresConfigPorts(*this);
272  // Determining if there are any registers in the module
273  bool HasRegs = moduleRequiresClockPorts(*this);
274 
275  // Printing out the module header
276  GenModuleHeader(HasConfig, HasRegs);
277 
278  // Generating the parameters of the module
279  GenParameters();
280 
281  // Printing out the port specifications (input or output)
282  GenPortSpecs(HasConfig, HasRegs);
283 
284  // Printing out verilog for connections and submodules
285  GenConnections();
286 
287  // Then add the module's functionality
289 
290  // Printing out the end of the module
291  std::cout << "endmodule\n\n";
292 }
293 
295  return [
296  has_synchronous_cells = moduleRequiresClockPorts(*this),
297  needs_config_ports = moduleRequiresConfigPorts(*this),
298  is_cgra_top = this->name == "CGRA",
299  size = getSize(),
300  ports = this->ports,
301  portsToPropagate = this->portsToPropagate
302  ] (
303  CoreIR::Context* c, CoreIR::Values genargs
304  ) -> CoreIR::RecordType* {
305  CoreIR::RecordParams interface = {};
306  if (needs_config_ports) {
307  interface.push_back({"ConfigIn", c->BitIn()});
308  interface.push_back({"ConfigOut", c->Bit()});
309  interface.push_back({"Config_Clock", c->BitIn()});
310  interface.push_back({"Config_Reset", c->BitIn()});
311  interface.push_back({"CGRA_Clock", c->BitIn()});
312  interface.push_back({"CGRA_Reset", c->BitIn()});
313  interface.push_back({"CGRA_Enable", c->BitIn()});
314  } else if (has_synchronous_cells) {
315  interface.push_back({"CGRA_Clock", c->BitIn()});
316  interface.push_back({"CGRA_Reset", c->BitIn()});
317  interface.push_back({"CGRA_Enable", c->BitIn()});
318  }
319 
320  for (auto& port : ports)
321  {
322  std::string portName = port.second->getName();
323  port_type portType = port.second->pt;
324  unsigned portSize = port.second->size;
325  unsigned portSizeForInterface; // Stores the port size, after checking for parameters
326  if (portSize == PARAMETERIZED)
327  {
328  CoreIR::Value* paramArg = genargs.at(port.second->parameter); // Use the stored parameter name to get the port size from input arguments
329  portSizeForInterface = (portSize > 0)? portSize : paramArg->get<int>();
330  }
331  else
332  {
333  portSizeForInterface = portSize;
334  }
335  CoreIR::ArrayType* portTypeForInterface; // Stores the port type in CoreIR's desired format
336  if(portType == port_type::PORT_INPUT)
337  {
338  portTypeForInterface= c->Array(portSizeForInterface,c->BitIn());
339  }
340  else if (portType == port_type::PORT_OUTPUT || portType == port_type::PORT_OUTPUT_REG)
341  {
342  // CoreIR doesn't care if the output of an in-memory representation is a reg or not (reg is implemented in the actual verilog printing)
343  portTypeForInterface = c->Array(portSizeForInterface,c->Bit());
344  }
345  else if (portType == port_type::PORT_BIDIR)
346  {
347  // replace bidirs with and in+out; CoreIR verilog gen doesn't support bidirs
348  const auto ioport_copies = splitBidirPort(*port.second);
349  interface.push_back({ioport_copies.first.name, c->Array(portSizeForInterface,c->BitIn())});
350  interface.push_back({ioport_copies.second.name, c->Array(portSizeForInterface,c->Bit())});
351  continue;
352  // portTypeForInterface = c->Array(portSizeForInterface,c->BitInOut()); // Adding an inout port portSizeForInterface bits wide
353  } else {
354  throw make_from_stream<cgrame_error>([&](auto& s) {
355  s << __func__ << " port "<< portName << " doesn't handle " << portType << " port type";
356  });
357  }
358  interface.push_back({port.second->getName(), portTypeForInterface});
359  }
360 
361  for (auto& port : portsToPropagate)
362  {
363  std::string portName = port.getName();
364  if (ports.find(portName) != ports.end()) {
365  continue;
366  }
367  port_type portType = port.pt;
368  unsigned portSize = port.size;
369  unsigned portSizeForInterface; // Stores the port size, after checking for parameters
370  if (portSize == PARAMETERIZED)
371  {
372  CoreIR::Value* paramArg = genargs.at(port.parameter); // Use the stored parameter name to get the port size from input arguments
373  portSizeForInterface = (portSize > 0)? portSize : paramArg->get<int>();
374  }
375  else
376  {
377  portSizeForInterface = portSize;
378  }
379  CoreIR::ArrayType* portTypeForInterface; // Stores the port type in CoreIR's desired format
380  if(portType == port_type::PORT_INPUT)
381  {
382  portTypeForInterface= c->Array(portSizeForInterface,c->BitIn());
383  }
384  else if (portType == port_type::PORT_OUTPUT || portType == port_type::PORT_OUTPUT_REG)
385  {
386  // CoreIR doesn't care if the output of an in-memory representation is a reg or not (reg is implemented in the actual verilog printing)
387  portTypeForInterface = c->Array(portSizeForInterface,c->Bit());
388  }
389  else if (portType == port_type::PORT_BIDIR)
390  {
391  // replace bidirs with and in+out; CoreIR verilog gen doesn't support bidirs
392  const auto ioport_copies = splitBidirPort(port);
393  interface.push_back({ioport_copies.first.name, c->Array(portSizeForInterface,c->BitIn())});
394  interface.push_back({ioport_copies.second.name, c->Array(portSizeForInterface,c->Bit())});
395  continue;
396  // portTypeForInterface = c->Array(portSizeForInterface,c->BitInOut()); // Adding an inout port portSizeForInterface bits wide
397  } else {
398  throw make_from_stream<cgrame_error>([&](auto& s) {
399  s << __func__ << " doesn't handle " << portType << " port type";
400  });
401  }
402  interface.push_back({port.getName(), portTypeForInterface});
403  }
404 
405  return c->Record(interface);
406  };
407 }
408 
410  return [
411  =
412  ] (
413  CoreIR::Context* c, CoreIR::Values genargs, CoreIR::ModuleDef* def
414  ) -> void {
415  (void)genargs;
416  // Add submodules
417  for (auto submodule : submodules)
418  {
419  CoreIR::Generator* submodGen = c->getGenerator("cgrame." + submodule.second->GenericName());
420  // Change/add submodule parameters below ( {"size", CoreIR::Const::make(c, 32)} )
421  CoreIR::Values submoduleParams = {};
422  CoreIR::Module* submod = submodGen->getModule(submoduleParams);
423  // Change submodule values/initializing values below ( {"value", CoreIR::Const::make(c, 1)} )
424  CoreIR::Values submoduleInitializer = {};
425  CoreIR::Instance* submoduleinstance = def->addInstance(submodule.first, submod, submoduleInitializer);
426  (void)submoduleinstance;
427  }
428 
429  // Add ConfigCells
430  for (auto configcell : configcells)
431  {
432  CoreIR::Generator* configGen = c->getGenerator("cgrame." + configcell.second->GenericName());
433 
434  // Change/add ConfigCell parameters below ( {"size", CoreIR::Const::make(c, 32)} )
435  CoreIR::Values configCellParams = {};
436  CoreIR::Module* configMod = configGen->getModule(configCellParams);
437  // Change ConfigCell values/initializing values below ( {"value", CoreIR::Const::make(c, 1)} )
438  CoreIR::Values configCellInitializer = {};
439  CoreIR::Instance* configCellInstance = def->addInstance(configcell.first, configMod, configCellInitializer);
440  (void)configCellInstance;
441  }
442 
443  // Add connections
444  // Special Cases:
445  auto is_cgra_top = this->name == "CGRA";
446  for (auto submodule : submodules)
447  {
448  if (moduleRequiresConfigPorts(*submodule.second))
449  {
450  def->connect("self.Config_Clock", submodule.first + ".Config_Clock");
451  def->connect("self.Config_Reset", submodule.first + ".Config_Reset");
452  def->connect("self.CGRA_Clock", submodule.first + ".CGRA_Clock");
453  def->connect("self.CGRA_Reset", submodule.first + ".CGRA_Reset");
454  def->connect("self.CGRA_Enable", submodule.first + ".CGRA_Enable");
455  }
456  else if (moduleRequiresClockPorts(*submodule.second))
457  {
458  def->connect("self.CGRA_Clock", submodule.first + ".CGRA_Clock");
459  def->connect("self.CGRA_Reset", submodule.first + ".CGRA_Reset");
460  def->connect("self.CGRA_Enable", submodule.first + ".CGRA_Enable");
461  }
462  }
463 
464  for (auto configCell : configcells)
465  {
466  def->connect("self.CGRA_Clock", configCell.first + ".CGRA_Clock");
467  def->connect("self.CGRA_Reset", configCell.first + ".CGRA_Reset");
468  def->connect("self.CGRA_Enable", configCell.first + ".CGRA_Enable");
469  def->connect("self.Config_Clock", configCell.first + ".Config_Clock");
470  def->connect("self.Config_Reset", configCell.first + ".Config_Reset");
471  }
472 
473  const auto addModulePath = [this_ptr=this](const Module& m, const std::string& port_name) {
474  if (&m == this_ptr) {
475  return "self." + port_name;
476  } else {
477  return m.getName() + '.' + port_name;
478  }
479  };
480 
481  // Submodule->Submodule / Submodule->Port connections:
482  for (auto portAndConnection : connections)
483  {
484  Connection* connectionSpecifier = portAndConnection.second;
485 
486  for (auto dstConnection : connectionSpecifier->dst)
487  {
488  const Port* src = connectionSpecifier->src;
489  const Port* dst = dstConnection;
490  if (&src->getModule() == this) { std::swap(src,dst); }
491 
492  const auto src_ioport_copy = splitBidirPort(*src);
493  const auto dst_ioport_copy = splitBidirPort(*dst);
494  const bool src_is_bidir = src->pt == PORT_BIDIR;
495  const bool dst_is_bidir = dst->pt == PORT_BIDIR;
496 
497  std::string srcPortName = src->getName();
498  std::string dstPortName = dst->getName();
499  if (src_is_bidir) {
500  switch (dst->pt) {
504  srcPortName = src_ioport_copy.second.getName();
505  break;
507  srcPortName = src_ioport_copy.first.getName();
508  break;
509  default: break;
510  }
511  }
512  if (dst_is_bidir) {
513  switch (src->pt) {
517  dstPortName = dst_ioport_copy.second.getName();
518  break;
520  dstPortName = dst_ioport_copy.first.getName();
521  break;
522  default: break;
523  }
524  }
525 
526  def->connect(
527  addModulePath(src->getModule(), srcPortName),
528  addModulePath(dst->getModule(), dstPortName)
529  );
530 
531  // the above will handle out <-> out, so also connect in <-> in
532  if (src_is_bidir && dst_is_bidir) {
533  def->connect(
534  addModulePath(src->getModule(), src_ioport_copy.first.getName()),
535  addModulePath(dst->getModule(), dst_ioport_copy.first.getName())
536  );
537  }
538  }
539  }
540 
541  // ConfigCell->Submodule / ConfigCell->Port connections:
542  std::string srcConfigInstance;
543  std::string srcConfig;
544  std::string stopSrcConfig;
545  std::string validSrcConfig;
546  std::string dstConfigInstance;
547  std::string dstConfigPortName;
548  std::string dstConfig;
549  std::string stopDstConfig;
550  std::string validDstConfig;
551  for (auto configCell : configcells)
552  {
553  srcConfigInstance = configCell.second->getName();
554  srcConfig = srcConfigInstance + ".select";
555  validDstConfig = srcConfigInstance + ".valid";
556  stopDstConfig = srcConfigInstance + ".stop";
557  for (auto configCellConnection : configCell.second->getAllConnectedPorts())
558  {
559  if (&(configCellConnection->getModule()) == this)
560  {
561  dstConfigInstance = "self";
562  }
563  else
564  {
565  dstConfigInstance = configCellConnection->getModule().getName();
566  }
567  dstConfigPortName = configCellConnection->getName();
568  dstConfig = dstConfigInstance + "." + dstConfigPortName;
569  validSrcConfig = dstConfig + "_valid_upstream";
570  stopSrcConfig = dstConfig + "_stop_upstream";
571  def->connect(srcConfig, dstConfig);
572 
573  if (dynamic_cast<ElasticConfigCell*>(configCell.second)) {
574  def->connect(validDstConfig, validSrcConfig);
575  def->connect(stopDstConfig, stopSrcConfig);
576  }
577  }
578  }
579 
580  // Configuration Cell chain
581  std::string PreviousWire = "self.ConfigIn";
582  std::string ConfigInput;
583  for (auto configCell : configcells)
584  {
585  ConfigInput = PreviousWire;
586  def->connect(ConfigInput, configCell.second->getName() + ".ConfigIn");
587  PreviousWire = configCell.second->getName() + ".ConfigOut";
588  }
589  for (auto submodule : submodules)
590  {
591  if (moduleRequiresConfigPorts(*submodule.second))
592  {
593  ConfigInput = PreviousWire;
594  def->connect(ConfigInput, submodule.first + ".ConfigIn");
595  PreviousWire = submodule.first + ".ConfigOut";
596  }
597  }
598  if(moduleRequiresConfigPorts(*this))
599  {
600  def->connect(PreviousWire, "self.ConfigOut"); // End the ConfigCell chain at the ConfigOut port if there were actually ConfigCells inside the module
601  }
602  };
603 }
604 
605 // Generates the coreIR in-memory representation of a module
606 void Module::CoreIRGenModuleVerilog(CoreIR::Context* c, int contexts)
607 {
608  CoreIR::Namespace* cgrame = c->getNamespace("cgrame");
609  const auto makeIntParameter = [c](auto& param) -> CoreIR::Params::value_type { return {param.first, c->Int()}; };
610  const auto makeConstParameter = [c](auto& param) -> CoreIR::Values::value_type { return {param.first, CoreIR::Const::make(c, param.second)}; };
611 
612  CoreIR::Params moduleParams;
613  if (dynamic_cast<const ConfigCell*>(this)) {
614  parameterlist.emplace("contexts", dynamic_cast<const ConfigCell*>(this)->l_contexts);
615  }
616  std::transform(parameterlist.begin(), parameterlist.end(), std::inserter(moduleParams, moduleParams.end()), makeIntParameter);
617  moduleParams.insert({"contexts", c->Int()});
618  CoreIR::Values defaultArgs = {};
619  std::transform(parameterlist.begin(), parameterlist.end(), std::inserter(defaultArgs, defaultArgs.end()), makeConstParameter);
620  defaultArgs.insert({"contexts", CoreIR::Const::make(c, contexts)});
621 
622  CoreIR::TypeGen* tg = cgrame->newTypeGen(GenericName() + "tg", moduleParams, makeCoreIRInterfaceGenerator());
623  CoreIR::Generator* modGen = cgrame->newGeneratorDecl(GenericName(), tg, moduleParams);
624  modGen->addDefaultGenArgs(defaultArgs);
625 
626  if (submodules.empty() && !hasConfigCells()) {
627  // Case A: If the module is a primitive (no submodules or ConfigCells)
628  modGen->getMetaData()["verilog"] = CoreIRGenFunctionality();
629  std::vector<std::string> portNames;
630  } else {
631  // Case B: The Module is a composite: (has submodules and/or ConfigCells)
632  modGen->setGeneratorDefFromFun(makeCoreIRModuleDefinitonGenerator());
633  }
634 
635  std::vector<std::string> portNames;
636  for (auto & port : portsToPropagate) {
637  portNames.push_back(port.getName());
638  }
639  if (!portNames.empty()) {
640  modGen->getMetaData()["propagatePorts"] = portNames;
641  }
642 }
643 
644 // Generating the module header in Verilog code
645 void Module::GenModuleHeader(bool HasConfig, bool HasRegisters)
646 {
647  std::vector<std::string> PortList; // Buffer that contains ports that we want to print out
648  std::cout << "module " << GenericName() << "("; // Printing module header and name, e.g. "module MyModuleName ( "
649  if (HasConfig) // If there are config cells inside, we need to add some extra ports
650  {
651  PortList.push_back("Config_Clock");
652  PortList.push_back("Config_Reset");
653  PortList.push_back("ConfigIn");
654  PortList.push_back("ConfigOut");
655  }
656  else if (HasRegisters) // If there are registers inside, we want to add some other extra ports
657  {
658  PortList.push_back("CGRA_Clock");
659  PortList.push_back("CGRA_Reset");
660  }
661  // Getting all the ports that the module has (port specifications such as input, output, inout come later)
662  for(const auto& name_and_port : ports)
663  PortList.push_back(name_and_port.second->name);
664 
665  for (unsigned i = 0; i < PortList.size(); i++) // For all ports
666  {
667  std::cout << PortList[i]; // Print it out
668  if (i != PortList.size() - 1) // Space out the ports with commas
669  std::cout << ", ";
670  }
671  std::cout << ");\n"; // Ending the module header
672 }
673 
674 // Printing out the parameters in the verilog module
676 {
677  for(std::map<std::string,unsigned>::iterator it = parameterlist.begin(); it != parameterlist.end(); ++it) // For all parameters
678  {
679  std::cout << SET_INDENT << "parameter " << it->first << " = " << it->second << ";\n"; // Print it along with its default size
680  }
681 }
682 
683 // Printing out all the ports, and their specifications (input or output)
684 void Module::GenPortSpecs(bool HasConfig, bool HasRegisters)
685 {
686  std::cout << SET_INDENT << "// Specifying the ports\n"; // Port generation comment
687  if (HasConfig) // If there are config cells, declare the following port specifications
688  {
689  std::cout << SET_INDENT << "input Config_Clock, Config_Reset, ConfigIn;\n";
690  std::cout << SET_INDENT << "output ConfigOut;\n";
691  }
692  if (HasRegisters)
693  std::cout << SET_INDENT << "input CGRA_Clock, CGRA_Reset;\n";
694  // Now, go through all the other ports and print their specifications
695  for(std::map<std::string,Port*>::iterator it = ports.begin(); it != ports.end(); ++it)
696  {
697  Port* curPort = it->second;
698  if (curPort->pt == PORT_INPUT) // If port is input
699  std::cout << SET_INDENT << "input ";
700  else if (curPort->pt == PORT_OUTPUT) // If the port is output
701  std::cout << SET_INDENT << "output ";
702  else if (curPort->pt == PORT_OUTPUT_REG) // If the port is output reg
703  std::cout << SET_INDENT << "output reg ";
704  else if (curPort->pt == PORT_BIDIR) // If the port is a bidirectional
705  std::cout << SET_INDENT << "inout ";
706  else // Otherwise, print out an error message
707  std::cout << "<ERROR: DID NOT DECLARE PORT SPECIFICATION!>";
708 
709  // Printing the size of the port
710  if (curPort->size == PARAMETERIZED) // If the port size is parameterized, include the parameter name in there
711  std::cout << "[" << curPort->parameter << "-1:0] ";
712  if (curPort->size > 1) // If the port size is greater than one, use array notation
713  std::cout << "[" << curPort->size-1 << ":0] ";
714  // Printing out the port name
715  std::cout << curPort->name << ";\n";
716  }
717 }
718 
719 // Generates the verilog for connections
721 {
722  StringMatrix Matrix; // Declaring a matrix to hold connection information
723  PrintList WireList, SubmodList, AssignList; // Buffers that will contain output... wirelist->wires, submodulelist->submodules and configcells, assignlist->assign statements
724  GenerateMatrix(Matrix); // Generating the matrix
725 
726  // Deals with how to generate verilog code to describe all the connections between the module, submodule, and config cells. Also generates necessary wires
727  DetermineConnections(Matrix, WireList, SubmodList, AssignList); // The verilog information will be stored in the three buffers (WireList, SubmodList, and AssignList)
728 
729  // Printing out those buffers (that contain the actual verilog code to be printed)
730  WireList.print();
731  SubmodList.print();
732  AssignList.print();
733 }
734 
735 // This function exists to be overridden
737 {
738  // Currently set to do nothing
739 }
740 
741 // Generating the matrix that will hold all the connections between submodules
743 {
744  // Intialization of matrix size (this does not change later)
745  for(std::map<std::string,Module*>::iterator it = submodules.begin(); it != submodules.end(); ++it)
746  {
747  std::vector<std::string> StringVector;
748  // XXX: This leaves dangling connections being hard-wired to 0s
749  for (auto& port : it->second->ports)
750  {
751  StringVector.push_back("." + port.first + "(0) " + PORT_DEFAULT_CONNECTION); // overwritten by valid connections afterwards
752  }
753  Matrix.push_back(StringVector); // Adding vector to matrix
754  }
755 }
756 
758 {
759  throw make_from_stream<cgrame_error>([&](auto&& s) {
760  s << "module has no Module::CoreIRGenFunctionality";
761  });
762 }
763 
764 // Deals with how to generate verilog describing the connections between the module, submodule, and config cells. Also generates necessary wires
765 void Module::DetermineConnections(StringMatrix & Matrix, PrintList & WireList, PrintList & SubmodList, PrintList & AssignList)
766 {
767  std::stringstream buffer; // Buffers to append strings
768  std::string Signal; // Holds the wire name
769  std::string PreviousWire, ConfigInput, ConfigOutput; // Stores the names of verilog ports/wires
770  int SubmodIndex, PortIndex; // Variables used to keep track of position in matrix
771 
772  PreviousWire = "ConfigIn";
773 
774  // ************** CONFIG CELL WIRING IN MODULE ************** //
775 
776  if (!configcells.empty()) // If there are config cells, add comments
777  {
778  WireList.add({"\n", SET_INDENT, "// Wires for the the config cells\n"});
779  SubmodList.add({"\n", SET_INDENT, "// Declaring the config cells\n"});
780  }
781  for(std::map<std::string, ConfigCell*>::iterator it = configcells.begin(); it != configcells.end(); ++it) // For all the config cells in the module
782  {
783  buffer << it->second->name << "_sig"; // Naming the wire (that will connect to the submodule)
784  Signal = buffer.str();
785  buffer.str(std::string()); // Clearing the buffer
786 
787  // Declaring the verilog wire for connecting the config cell to submodule
788  if (it->second->getStorageSize() > 1) // If size is greater than one,
789  WireList.add({SET_INDENT, "wire [", std::to_string(it->second->getStorageSize() - 1), ":0] ", Signal, ";\n"});
790  else // Otherwise, if the size is 1
791  WireList.add({SET_INDENT, "wire ", Signal, ";\n"});
792 
793  ConfigInput = PreviousWire; // Otherwise, wire the previous wire in to ConfigIn. This is to make a chain of config cells
794 
795  // Declaring the verilog wire necessary to connect the config cell chain
796  buffer << it->second->name << "_config";
797  ConfigOutput = buffer.str();
798  buffer.str(std::string()); // Clearing the buffer
799  WireList.add({SET_INDENT, "wire ", ConfigOutput, ";\n"});
800  PreviousWire = ConfigOutput; // Setting the previous wire (necessary for making the chain)
801 
802  // Declaring the config cell
803  SubmodList.add({SET_INDENT , "configCell_", std::to_string(it->second->getStorageSize()), "b ", it->second->name, " (\n",
804  SET_DOUBLE_INDENT, ".CGRA_Clock(CGRA_Clock),\n", SET_DOUBLE_INDENT, ".CGRA_Reset(CGRA_Reset),\n",
805  SET_DOUBLE_INDENT, ".Config_Clock(Config_Clock),\n", SET_DOUBLE_INDENT, ".Config_Reset(Config_Reset),\n",
806  SET_DOUBLE_INDENT, ".ConfigIn(", ConfigInput, "),\n", SET_DOUBLE_INDENT, ".ConfigOut(" , ConfigOutput , "),\n",
807  SET_DOUBLE_INDENT, ".select(", Signal, "));\n"});
808 
809  // Modify the matrix to show the connection between config cell and submodule
810  for (auto* port : it->second->getAllConnectedPorts())
811  {
812  SubmodIndex = FindSubmoduleIndex(port->parent->name); // Find submodule index
813  if (SubmodIndex < 0) continue; // Case: connecting to port instead of submodule
814  PortIndex = port->parent->FindPortIndex(port->name); // Find port index that it is connected to
815  Matrix[SubmodIndex][PortIndex] = "." + port->name + "(" + Signal + ")"; // Update that entry in the matrix
816  }
817  }
818 
819  // ************** END OF CONFIG CELL WIRING IN MODULE ************** //
820 
821  // ************** WIRING OTHER CONNECTIONS WITHIN MODULE (between module and submodules, configcells excluded) ************** //
822 
823  if (!connections.empty()) // If there are connections, write a comment
824  WireList.add({"\n",SET_INDENT, "// Wires connecting the main module and submodules\n"});
825 
826  // For all connection objects, between modules/submodules (config cells not included)
827  for(std::map<Port*,Connection*>::iterator it = connections.begin(); it != connections.end(); ++it)
828  {
829  if (it->second->src->parent == this) // If the source port is one of the main module's inputs
830  {
831  for(unsigned j = 0; j < it->second->dst.size(); j++) // For all destination ports
832  {
833  if (it->second->dst[j]->parent == this) // If the destination port is not in a submodule, connect directly to output
834  {
835  AssignList.add({SET_INDENT, "assign ", it->second->dst[j]->name, " = ", Signal, ";\n"});
836  continue;
837  }
838  // Otherwise it is a submodule, and assign its connection appropriately
839  SubmodIndex = FindSubmoduleIndex(it->second->dst[j]->parent->name); // Finding the submodule that the destination is connected
840  PortIndex = it->second->dst[j]->parent->FindPortIndex(it->second->dst[j]->name); // Go to that submodule, and then find the port index of that port name
841  buffer << "." << it->second->dst[j]->name << "(" << it->second->src->name << ")";
842  Matrix[SubmodIndex][PortIndex] = buffer.str();
843  buffer.str(std::string()); // Clearing the buffer
844  }
845  }
846  else // If the source port is in one of the submodules
847  {
848  if (it->second->dst.size() == 1 && it->second->dst[0]->parent == this) // If we only have one port connection and its connected to the main module's port, we do not want a wire
849  {
850  int SubmodIndex = FindSubmoduleIndex(it->second->src->parent->name); // Finding the submodule that the destination is connected
851  int PortIndex = it->second->src->parent->FindPortIndex(it->second->src->name); // Go to that submodule, and then find the port index of that port name
852  buffer << "." << it->second->src->name << "(" << it->second->dst[0]->name << ")";
853  Matrix[SubmodIndex][PortIndex] = buffer.str();
854  buffer.str(std::string()); // Clearing the buffer
855  continue;
856  }
857  // Naming and declaring the verilog wire necessary
858  buffer << it->second->src->parent->name << "_" << it->second->src->name << "_sig"; // Naming the wire
859  Signal = buffer.str(); // Assigning the wire the name
860  buffer.str(std::string()); // Clearing the buffer
861 
862  // Declaring the verilog wire
863  if (it->second->src->size == PARAMETERIZED && it->second->src->parameter == "size")
864  {
865  WireList.add({SET_INDENT , "wire [" , std::to_string(it->second->src->parent->getSize() - 1) , ":0] " , Signal , ";\n"});
866  }
867  else if (it->second->src->size > 1) // If the size is greater than one
868  WireList.add({SET_INDENT , "wire [" , std::to_string(it->second->src->size - 1) , ":0] " , Signal , ";\n"});
869  else // Otherwise, if the size is 1
870  WireList.add({SET_INDENT , "wire " , Signal , ";\n"});
871 
872  // Assigning that wire to the corresponding input
873  int SubmodIndex = FindSubmoduleIndex(it->second->src->parent->name); // Finding the submodule that the destination is connected
874  int PortIndex = it->second->src->parent->FindPortIndex(it->second->src->name); // Go to that submodule, and then find the port index of that port name
875  buffer << "." << it->second->src->name << "(" << Signal << ")";
876  Matrix[SubmodIndex][PortIndex] = buffer.str();
877  buffer.str(std::string()); // Clearing the buffer
878 
879  // Now, send this wire to all the destination ports
880  for(unsigned j = 0; j < it->second->dst.size(); j++) // For all destination ports
881  {
882  if (it->second->dst[j]->parent == this) // If the destination port is not in a submodule, connect directly to output
883  {
884  AssignList.add({SET_INDENT, "assign ", it->second->dst[j]->name, " = ", Signal, ";\n"});
885  continue;
886  }
887 
888  // Otherwise it is a submodule, and assign its connection appropriately
889  SubmodIndex = FindSubmoduleIndex(it->second->dst[j]->parent->name); // Finding the submodule that the destination is connected
890  PortIndex = it->second->dst[j]->parent->FindPortIndex(it->second->dst[j]->name); // Go to that submodule, and then find the port index of that port name
891  buffer << "." << it->second->dst[j]->name << "(" << Signal << ")";
892  Matrix[SubmodIndex][PortIndex] = buffer.str();
893  buffer.str(std::string()); // Clearing the buffer
894  }
895  }
896  }
897 
898  // ************** END OF WIRING OTHER CONNECTIONS WITHIN MODULE ************** //
899 
900 
901  // ************** DEAL WITH DECLARATION OF SUBMODULES (Wiring of them to create necessary config cell chain also handled!) ************** //
902 
903  // std::string PreviousWire, ConfigInput, ConfigOutput has been previously declared in above section!
904  buffer.str(std::string()); // Clearing the previously declared buffer
905  int i = 0; // Loop variable
906 
907  if (!submodules.empty()) // If there are submodules, add a comment
908  SubmodList.add({"\n", SET_INDENT, "// Declaring the submodules\n"});
909 
910  for(std::map<std::string,Module*>::iterator it = submodules.begin(); it != submodules.end(); ++it) // For each submodule, print it and its connections
911  {
912  const auto& resolved_params = it->second->ResolveVerilogParameters();
913  const auto& parameter_string = makeParameterListSyntaxItem(resolved_params);
914  SubmodList.add({SET_INDENT, it->second->GenericName(), " ", parameter_string, it->second->name, "(\n"}); // Printing beginning of submodule
915  if (moduleRequiresConfigPorts(*it->second)) // If the module has config cells somewhere inside it
916  {
917  ConfigInput = PreviousWire; // Otherwise, wire the previous module into ConfigIn (to create a chain)
918  // Declaring the verilog wire for the config cell chain, and wiring it in
919  buffer << it->second->name << "_config";
920  ConfigOutput = buffer.str();
921  buffer.str(std::string()); // Clearing the buffer
922  PreviousWire = ConfigOutput;
923  WireList.add({SET_INDENT, "wire ", PreviousWire, ";\n"});
924 
925  // Adding the config cell ports in (required if there are config cells)
926  SubmodList.add({SET_DOUBLE_INDENT, ".Config_Clock(Config_Clock),\n", SET_DOUBLE_INDENT, ".Config_Reset(Config_Reset),\n", SET_DOUBLE_INDENT, ".ConfigIn(", ConfigInput, "),\n",
927  SET_DOUBLE_INDENT, ".ConfigOut(", ConfigOutput, ")"});
928  SubmodList.add({",\n"}); // This needs to be on a seperate line, to indicate a comma was added last (this information is used below when printing the other ports)
929  }
930  if (moduleRequiresClockPorts(*it->second))
931  {
932  SubmodList.add({SET_DOUBLE_INDENT, ".CGRA_Clock(CGRA_Clock),\n", SET_DOUBLE_INDENT, ".CGRA_Reset(CGRA_Reset)"});
933  SubmodList.add({",\n"}); // This needs to be on a seperate line, to indicate a comma was added last (this information is used below when printing the other ports)
934  }
935  // Now, print out the remaining ports that the module has
936  for(unsigned j = 0; j < Matrix[i].size(); j++)
937  {
938  SubmodList.add({SET_DOUBLE_INDENT, Matrix[i][j]}); // Add the connection element
939  // If the port currently being printed is not the last one...
940  if (j+1 != Matrix[i].size())
941  SubmodList.add({",\n"}); // Add a comma
942  }
943  SubmodList.add({");\n"}); // Printing end of submodule
944  // Ending the module header
945  i++; // Incrementing the index
946  }
947  // If there were submodules with config cells, we need to assign ConfigOut to complete the chain
948  if (PreviousWire != "ConfigIn")
949  AssignList.add({SET_INDENT, "assign ConfigOut = ", PreviousWire, ";\n"});
950 
951  // ************** END OF DEAL WITH DECLARATION OF SUBMODULES ************** //
952 }
953 
954 std::vector<ResolvedVeroligModuleParameter> Module::ResolveVerilogParameters() const
955 {
956  std::vector<ResolvedVeroligModuleParameter> result;
957 
958  for (auto& name_and_val : parameterlist) {
959  result.emplace_back(ResolvedVeroligModuleParameter{
960  name_and_val.first,
961  std::to_string(name_and_val.second)
962  });
963  }
964 
965  return result;
966 }
967 
968 // Finds the index in the module for a given port name, returns -1 if string is not found (0 is first index)
969 int Module::FindPortIndex(std::string PortName)
970 {
971  int index = 0;
972  for(std::map<std::string,Port*>::iterator it = ports.begin(); it != ports.end(); ++it)
973  {
974  if (it->second->name == PortName) // Compare the port name with the specified one
975  return index; // If port name is found, return index location
976  index++;
977  }
978  return -1; // If the string is not found, return -1
979 }
980 
981 
982 // Finds the index in the module for a given submodule name, returns -1 if string is not found (0 is first index)
983 int Module::FindSubmoduleIndex(std::string SubmoduleName)
984 {
985  int index = 0;
986  for(std::map<std::string,Module*>::iterator it = submodules.begin(); it != submodules.end(); ++it)
987  {
988  if (it->second->name == SubmoduleName) // Compare the port name with the specified one
989  return index; // If port name is found, return index location
990  index++;
991  }
992  return -1; // If the string is not found, return -1
993 }
994 
995 // Debug information: Printing out module information
997 {
998  std::cout << this->name << ":\n";
999  std::cout << "ports:\n";
1000  print_ports();
1001  std::cout << "connections:\n";
1003  std::cout << "submodules:\n";
1004  print_submodules();
1005 }
1006 
1007 
1009 {
1010  // print node info
1011  std::cout << this->name << ";\n";
1012  // for all src ports
1013  for(std::map<Port*,Connection*>::iterator it = connections.begin(); it != connections.end(); ++it)
1014  // print all edges
1015  for(unsigned j = 0; j < it->second->dst.size(); j++)
1016  {
1017  std::cout << it->first->parent->name << "." << it->first->name << "->" << it->second->dst[j]->parent->name << "." << it->second->dst[j]->name << ";\n";
1018  }
1019 
1020  // print for all composite submodules
1021  for(std::map<std::string,Module*>::iterator it = submodules.begin(); it != submodules.end(); ++it)
1022  {
1023  it->second->print_dot();
1024  }
1025 }
1026 
1028 {
1029  for(std::map<std::string,Port*>::iterator it = ports.begin(); it != ports.end(); ++it)
1030  std::cout << it->second->name << "\n";
1031 
1032 }
1033 
1035 {
1036  for(std::map<Port*,Connection*>::iterator it = connections.begin(); it != connections.end(); ++it)
1037  {
1038  // print all edges
1039  for(unsigned j = 0; j < it->second->dst.size(); j++)
1040  {
1041  std::cout << this->name << "<-" << it->second->dst[j]->parent->name << ";\n";
1042  }
1043  }
1044 }
1045 
1047 {
1048  // print for all composite submodules
1049  for(std::map<std::string,Module*>::iterator it = submodules.begin(); it != submodules.end(); ++it)
1050  {
1051  std::cout << it->second->name << "\n";
1052  }
1053 }
1054 
1056 {
1057  // print for all composite submodules
1058  for(std::map<std::string,ConfigCell*>::iterator it = configcells.begin(); it != configcells.end(); ++it)
1059  {
1060  std::cout << it->second->name << "\n";
1061  }
1062 }
1063 
1064 // Function that gives the module and port names, given a string
1065 static bool getmoduleport(std::string name, std::string* module, std::string* port)
1066 {
1067  std::size_t dot_loc;
1068  if(std::string::npos != (dot_loc = name.find_first_of(".")))
1069  {
1070  *module = name.substr(0,dot_loc);
1071  }
1072  *port = name.substr(dot_loc + 1);
1073 
1074  return (std::string::npos == port->find_first_of("."));
1075 }
1076 
1077 void Module::addConfig(std::string name, std::vector<std::string> ConnectTo, int contexts, bool isElastic) {
1078  if (isElastic) {
1079  addConfig(new ElasticConfigCell(name, contexts), ConnectTo);
1080  } else {
1081  addConfig(new ConfigCell(name, contexts), ConnectTo);
1082  }
1083 }
1084 
1085 // Function that adds a config cell to a module
1086 // Takes config cell, and vector of ports (via string name) to connect to
1087 void Module::addConfig(ConfigCell* c, std::vector<std::string> ConnectTo)
1088 {
1089 
1090  if(configcells.find(c->name) != configcells.end()) // If the config cell name already exists
1091  {
1092  auto error = make_from_stream<cgrame_model_error>([&](auto&& s) {
1093  s << "a config cell called " << c->name << " already exists";
1094  });
1095  delete c; // Delete the dynamically allocated memory
1096  throw error;
1097  }
1098 
1099  std::vector<Port*> new_ports_to_connect_to;
1100  // Now... find if the ports specified exists
1101  for (unsigned i = 0; i < ConnectTo.size(); i++) // For all the ports specified
1102  {
1103  Module* module = getModuleFromPortName(ConnectTo[i]);
1104  if (!module){
1105  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1106  s << "Connection ERROR!(" << ConnectTo[i] << "): module and port do not exist\n";
1107  });
1108  }
1109  if (dynamic_cast<const ConfigCell*>(module)) {
1110  delete c;
1111  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1112  s << "Connection ERROR!(" << this->name << "): cannot connect a config cell to another config cell ("<< ConnectTo[i] << ")\n";
1113  });
1114  }
1115  Port* port = getPort(ConnectTo[i]);
1116  new_ports_to_connect_to.push_back(port);
1117  }
1118 
1119  c->addControledPorts(new_ports_to_connect_to);
1120  configcells[c->name] = c; // Add config cell to the list
1121 }
1122 
1123 // Function that adds a submodule to the module
1125 {
1126  // If the submodule name exists, we do not add it again
1127  if(submodules[m->name])
1128  {
1129  std::stringstream msg;
1130  msg << "Submodule with same name: " << m->name << " already exists\n";
1131  delete m;
1132  throw cgrame_model_error(msg.str());
1133  }
1134  // Otherwise, add it
1135  m->parent = this; // Setting the parent
1136  submodules[m->name] = m; // Adding the module to list of submodules
1137 }
1138 
1139 // Function that adds a submodule to the module with position information
1140 void Module::addSubModule(Module* m, double xPos, double yPos, double width, double height)
1141 {
1142  addSubModule(m);
1143  submodule_relative_position[m->name] = {xPos, yPos, width, height};
1144 }
1145 
1146 // Returns a pointer to a submodule
1148 {
1149  // If the submodule name exists, we do not add it again
1150  if(!submodules[m])
1151  {
1152  std::stringstream msg;
1153  msg << "Could not find submodule: '" << m << "'\n";
1154  throw cgrame_model_error(msg.str());
1155  }
1156  return submodules[m];
1157 }
1158 
1159 // Returns a true/false value if this is a submodule of this module
1160 bool Module::isSubModule(Module* subModule) {
1161  // If the submodule name exists, we do not add it again
1162  if (submodules.end() != submodules.find(subModule->getName())) {
1163  return (submodules[subModule->getName()] == subModule);
1164  }
1165  return false;
1166 }
1167 Module* Module::getModule(std::string module_name, std::string err_context) {
1168  // find module and port
1169  Module* module = NULL;
1170  if (module_name == "this") {
1171  module = this;
1172  } else if (submodules.find(module_name) != submodules.end()) {
1173  module = submodules[module_name];
1174  } else if (configcells.find(module_name) != configcells.end()) {
1175  module = configcells[module_name];
1176  }
1177  if (module == NULL) { // Error with finding module
1178  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1179  s << err_context << "\nMODULE NOT FOUND!(" << this->name <<
1180  "): module not found ("<< module_name << ")";
1181  });
1182  }
1183  return module;
1184 }
1185 
1186 Module* Module::getModuleFromPortName(std::string full_port_name, std::string err_context) {
1187  std::string module_name;
1188  std::string port_name;
1189 
1190  // split names
1191  if (!getmoduleport(full_port_name, &module_name, &port_name)) {
1192  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1193  s << err_context << "\nMODULE NOT FOUND!(" << this->name <<
1194  "): incorrect module.port (" << full_port_name << ") name";
1195  });
1196  }
1197  Module* module = getModule(module_name, err_context);
1198  return module;
1199 }
1200 
1201 Port* Module::getPort(std::string full_port_name, std::string err_context) {
1202  std::string module_name;
1203  std::string port_name;
1204 
1205  // split names
1206  if (!getmoduleport(full_port_name, &module_name, &port_name)) {
1207  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1208  s << err_context<< "\nPORT NOT FOUND!(" << this->name <<
1209  "): incorrect module.port (" << full_port_name << ") name";
1210  });
1211  }
1212  // find module 1 and port
1213  Module* module = getModule(module_name, err_context);
1214  if (module == NULL) {
1215  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1216  s << err_context << "\nmodule not found!(" << this->name <<
1217  "): port not found ("<< port_name <<
1218  ") in module (" << module_name << ")";
1219  });
1220  }
1221  if (module->ports.find(port_name) == module->ports.end()) {
1222  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1223  s << err_context << "\nPORT NOT FOUND!(" << this->name <<
1224  "): port not found ("<< port_name <<
1225  ") in module (" <<module->name << ")";
1226  });
1227  }
1228  return module->ports[port_name];;
1229 }
1230 
1231 // name1 is src, name2 is dst
1232 void Module::connectPorts(std::string name1, std::string name2, bool isElastic) {
1233  if (isElastic) {
1234  addElasticConnection(name1, name2);
1235  } else {
1236  addConnection(name1, name2);
1237  }
1238 }
1239 
1240 // name1 is src, name2 is dst
1241 void Module::addConnection(std::string name1, std::string name2, bool isInMRRG)
1242 {
1243  const auto& print_context = [&](auto&& s) {
1244  s << "Connection ERROR! Could not make connection \"" << name1
1245  << "\" to \""<< name2 << "\" within module \"" << this->name << "\"";
1246  };
1247 
1248  std::string context = "Connection ERROR! Could not make connection \""
1249  + name1 + "\" to \"" + name2 + "\" within module \"" + this->name + "\"";
1250 
1251  Module* module1 = getModuleFromPortName(name1, context);
1252  Module* module2 = getModuleFromPortName(name2, context);
1253 
1254  Port* port1 = getPort(name1, context);
1255  Port* port2 = getPort(name2, context);
1256 
1257  // Setting the source and destionation ports
1258  Port* srcport; // Source port
1259  Port* dstport; // Destination port
1260  if (((port1->pt == PORT_OUTPUT || port1->pt == port_type::PORT_OUTPUT_REG)&& module1 != this) ||
1261  (port1->pt == PORT_INPUT && module1 == this)) {
1262  srcport = port1;
1263  } else if (((port2->pt == PORT_OUTPUT || port2->pt == port_type::PORT_OUTPUT_REG) && module2 != this) ||
1264  (port2->pt == PORT_INPUT && module2 == this)) {
1265  srcport = port2;
1266  } else{
1267  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1268  print_context(s);
1269  s << "\nConnection ERROR!(" << this->name << "): source port could not be found. port 1 ("<< name1 << ") or port 2 ("<< name2 << ") are wrong";
1270  });
1271 
1272  }
1273 
1274  if ((port1->pt == PORT_INPUT && module1 != this) ||
1275  ((port1->pt == PORT_OUTPUT || port1->pt == port_type::PORT_OUTPUT_REG) && module1 == this)) {
1276  dstport = port1;
1277  } else if ((port2->pt == PORT_INPUT && module2 != this) ||
1278  ((port2->pt == PORT_OUTPUT || port2->pt == port_type::PORT_OUTPUT_REG) && module2 == this)) {
1279  dstport = port2;
1280  }else {
1281  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1282  print_context(s);
1283  s << "\nConnection ERROR!(" << this->name << "): destination port could not be found. port 1 ("<< name1 << ") or port 2 ("<< name2 <<") are wrong";
1284  });
1285 
1286  }
1287 
1288  if (port1->size != port2->size){
1289  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1290  print_context(s);
1291  s << "\nConnection ERROR!(" << this->name << "): source port and destination port do not have the same size. port 1 ("<< name1 << ") size 1 ("<<port1->size<<") and port 2 ("<< name2 << ") size 2 ("<<port2->size<<") ";
1292  });
1293  }
1294 
1295  // Make sure that the destination port is not already connected to anything
1296  for(auto & c : connections)
1297  {
1298  for(auto & d : c.second->dst)
1299  {
1300  if(d == dstport)
1301  {
1302  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1303  print_context(s);
1304  s << "\nConnection ERROR! In module (" << this->name << "): destination(" << name2 << ") destination port ( "<<dstport->name << " ) already connected to (" << c.second->src->parent->name << "." << c.second->src->name <<")" ;
1305  });
1306  }
1307  }
1308  }
1309 
1310  if(!connections[srcport]) // If there is no connection object for the given source port, make one
1311  {
1312  connections[srcport] = new Connection();
1313  connections[srcport]->src = srcport;
1314  }
1315  else
1316  {
1317  // if we already have a srcport entry, check that we are not adding a previous dst
1318  for(auto & d: connections[srcport]->dst)
1319  {
1320  if(d == dstport)
1321  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1322  print_context(s); s << "\nConnection ERROR! destination already added";
1323  });
1324  }
1325  }
1326 
1327  // Add the connection
1328  connections[srcport]->dst.push_back(dstport);
1329 
1330  // Set the flag that specifies whether the source port is in the MRRG
1331  connections[srcport]->isInMRRG = isInMRRG;
1332 
1333  // If debug mode is on, print out connection information
1335  std::cout << "New Connection:" << connections[srcport]->src->parent->name << "."
1336  << connections[srcport]->src->name << "->"
1337  << connections[srcport]->dst.back()->parent->name << "."
1338  << connections[srcport]->dst.back()->name << "\n";
1339 }
1340 
1341 void Module::addPort(std::string portname, port_type pt, unsigned size, bool isElastic)
1342 {
1343  if (isElastic) {
1344  addElasticPort(portname, pt, size);
1345  } else {
1346  if (pt == PORT_CONFIG) {
1347  pt = PORT_INPUT;
1348  }
1349  addPort(portname, pt, size);
1350  }
1351 
1352 }
1353 
1354 void Module::addPort(std::string portname, port_type pt, unsigned size)
1355 {
1356  if(ports[portname]) // If the port already exists
1357  {
1358  std::stringstream msg;
1359  msg << "Port " << portname << " already exists\n";
1360  throw cgrame_model_error(msg.str());
1361  }
1362 
1363  // Assigning port parameters
1364  Port* p = new Port(); // Create port
1365  p->name = portname; // Assign name
1366  p->pt = pt; // Assign port type
1367  p->size = size; // Assign port size
1368  p->parent = this; // Connect port to its parent
1369  ports[portname] = p; // Adding port to list
1370 
1371  if (MODULE_DEBUG_PRINTING) // Debug information
1372  std::cout << this->name << ": added port - " << p->name << "\n";
1373 }
1374 
1375 void Module::addPort(std::string portname, port_type pt, std::string parameterName, unsigned size, bool isElastic)
1376 {
1377  if (isElastic) {
1378  addElasticPort(portname, pt, parameterName, size);
1379  } else {
1380  if (pt == PORT_CONFIG) {
1381  pt = PORT_INPUT;
1382  }
1383  addPort(portname, pt, parameterName, size);
1384  }
1385 
1386 }
1387 
1388 void Module::addPort(std::string portname, port_type pt, std::string ParameterName, unsigned size)
1389 {
1390  if(ports[portname]) // If the port already exists
1391  {
1392  std::stringstream msg;
1393  msg << "Port " << portname << " already exists\n";
1394  throw cgrame_model_error(msg.str());
1395  }
1396 
1397  // Assigning port parameters
1398  Port* p = new Port(); // Create port
1399  p->name = portname; // Assign name
1400  p->pt = pt; // Assign port type
1401  p->size = size; // PARAMETERIZED = 0: it's a flag to say that the port is parameterized
1402  p->parameter = ParameterName; // Set the parameter name
1403  p->parent = this; // Connect port to parent
1404  ports[portname] = p; // Add port to list
1405  parameterlist[ParameterName] = size; // Setting the default size of the parameter
1406 
1407  if (MODULE_DEBUG_PRINTING) // Debug information
1408  std::cout << this->name << ": added port - " << p->name << p->size << "\n";
1409 }
1410 
1411 void Module::addElasticPort(std::string portname, port_type pt, std::string parameterName, unsigned size)
1412 {
1413  std::string stream;
1414  port_type stop_port;
1415  port_type valid_port;
1416  if (pt == port_type::PORT_INPUT){
1417  stop_port = PORT_OUTPUT_REG;
1418  valid_port = PORT_INPUT;
1419  stream = "upstream";
1420  } else if (pt == port_type::PORT_OUTPUT || pt == port_type::PORT_OUTPUT_REG){
1421  stop_port = PORT_INPUT;
1422  valid_port = pt;
1423  stream = "downstream";
1424  } else if (pt == port_type::PORT_CONFIG) {
1425  stop_port = PORT_OUTPUT;
1426  valid_port = PORT_OUTPUT;
1427  pt = PORT_INPUT;
1428  stream = "upstream";
1429  } else {
1430  std::stringstream msg;
1431  msg << "Port type is not supported for elastic\n";
1432  throw cgrame_model_error(msg.str());
1433  }
1434 
1435  addPort(portname, pt, parameterName, size);
1436  addPort(portname + "_valid_" + stream, valid_port, 1);
1437  addPort(portname + "_stop_" + stream, stop_port, 1);
1438 }
1439 
1440 void Module::addElasticPort(std::string portname, port_type pt, unsigned size)
1441 {
1442  std::string stream;
1443  port_type stop_port;
1444  port_type valid_port;
1445  if (pt == port_type::PORT_INPUT){
1446  stop_port = PORT_OUTPUT_REG;
1447  valid_port = PORT_INPUT;
1448  stream = "upstream";
1449  } else if (pt == port_type::PORT_OUTPUT || pt == port_type::PORT_OUTPUT_REG){
1450  stop_port = PORT_INPUT;
1451  valid_port = pt;
1452  stream = "downstream";
1453  } else if (pt == port_type::PORT_CONFIG) {
1454  stop_port = PORT_OUTPUT;
1455  valid_port = PORT_OUTPUT;
1456  pt = PORT_INPUT;
1457  stream = "upstream";
1458  } else {
1459  std::stringstream msg;
1460  msg << "Port type is not supported for elastic\n";
1461  throw cgrame_model_error(msg.str());
1462  }
1463 
1464  addPort(portname, pt, size);
1465  addPort(portname + "_valid_" + stream, valid_port, 1);
1466  addPort(portname + "_stop_" + stream, stop_port, 1);
1467 }
1468 
1469 void Module::addElasticConnection(std::string name1, std::string name2) {
1470  Port* port1 = getPort(name1);
1471  Port* port2 = getPort(name2);
1472 
1473 
1474  std::string stream1;
1475  if (port1->pt == port_type::PORT_INPUT){
1476  stream1 = "upstream";
1477  } else if (port1->pt == port_type::PORT_OUTPUT || port1->pt == port_type::PORT_OUTPUT_REG){
1478  stream1 = "downstream";
1479  } else {
1480  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1481  s << "\nPORT NOT FOUND!(" << this->name << "): incorrect module.port (" << name1 << ")";
1482  });
1483  }
1484 
1485 
1486  std::string stream2;
1487  if (port2->pt == port_type::PORT_INPUT){
1488  stream2 = "upstream";
1489  } else if (port2->pt == port_type::PORT_OUTPUT || port2->pt == port_type::PORT_OUTPUT_REG){
1490  stream2 = "downstream";
1491  } else {
1492  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1493  s << "\nPORT NOT FOUND!(" << this->name << "): incorrect module.port (" << name2 << ")";
1494  });
1495  }
1496 
1497 
1498  addConnection(name1, name2);
1499  addConnection(name1 + "_valid_" + stream1, name2 + "_valid_" + stream2, false);
1500  addConnection(name2 + "_stop_" + stream2, name1 + "_stop_" + stream1, false);
1501 }
1502 
1503 void Module::addParameter(std::string parameterName, unsigned parameterValue)
1504 {
1505  if(parameterlist[parameterName]) // If the port already exists
1506  {
1507  std::stringstream msg;
1508  msg << "Parameter " << parameterName << " already exists\n";
1509  throw cgrame_model_error(msg.str());
1510  }
1511 
1512  parameterlist[parameterName] = parameterValue;
1513 }
1514 
1515 void Module::addVerilogPort(std::string name, port_type pt, std::string parameter, unsigned size) {
1516  portsToPropagate.emplace_back(Port{name, pt, parameter, size, this});
1517 }
1518 
1519 
1521 {
1522  std::map<std::string, std::unique_ptr<MRRG>> subMRRGs;
1523  // create MRRG for all sub modules
1524  for(auto& name_and_submod : submodules)
1525  {
1526  auto temp = std::unique_ptr<MRRG>(name_and_submod.second->createMRRG(II));
1527  subMRRGs[name_and_submod.first] = std::move(temp);
1528  }
1529 
1530  // create current MRRG with port nodes
1531  MRRG* result_ptr = new MRRG(II);
1532  auto& result = *result_ptr;
1533 
1534  // for all ports, create and add node to MRRG
1535  int portNumber = 0;
1536  for(auto& name_and_port : ports)
1537  {
1538  for(unsigned i = 0; i < II; i++)
1539  {
1540  result.insert(MRRGNode::make_routing(this, this->getSize(), i, name_and_port.first));
1541 
1542  if (node_relative_position.find(name_and_port.first) == node_relative_position.end()) {
1543  node_relative_position.insert({name_and_port.first, {0.9, static_cast<double>(portNumber+0.5)/(ports.size()*2)}});
1544  portNumber++;
1545  }
1546  }
1547  }
1548  // also add all subMRRG nodes to this graph
1549  for(auto& submod_name_and_mrrg : subMRRGs)
1550  {
1551  for(auto& nodes_in_cycle : submod_name_and_mrrg.second->nodes)
1552  {
1553  for(auto& name_and_node : nodes_in_cycle)
1554  {
1555  // Copying MRRGNodes is unsupported ATM, so migrate all the nodes over
1556  // so the fanout, fanin, and operation pointer lists still work
1557  // Need to change the name to something unique, though
1558  auto& node = submod_name_and_mrrg.second->getNodeRef(name_and_node.second.get());
1559  node.name = submod_name_and_mrrg.first + '.' + node.name;
1560  result.nodes[node.getContextNum()][node.name] = std::move(name_and_node.second);
1561  }
1562  }
1563  }
1564 
1565  // make all connections
1566  // for all src ports
1567  for(auto& port_and_connection : connections)
1568  {
1569  const auto& port = *port_and_connection.first;
1570  const auto& connection = *port_and_connection.second;
1571  // TODO: this is hacky .... need to look at verilog generation to simplify the number of port types we have
1572  if(port.pt != PORT_INPUT && port.pt != PORT_OUTPUT && port.pt != PORT_OUTPUT_REG && port.pt != PORT_BIDIR)
1573  continue;
1574 
1575  const auto& src_module_name = port.parent->name;
1576  const auto& src_module_port_name = port.name;
1577 
1578  // Check if the ports that are being connected are actually in the MRRG, if they aren't don't connect them
1579  if (!connection.isInMRRG)
1580  continue;
1581 
1582  // connect to all destinations
1583  for(unsigned j = 0; j < connection.dst.size(); j++)
1584  {
1585  const auto& dst_module_name = connection.dst[j]->parent->name;
1586  const auto& dst_module_port_name = connection.dst[j]->name;
1587 
1588  for(unsigned k = 0; k < II; k++)
1589  {
1590  if (this->isElastic){
1591  for (unsigned l = 0; l < II; l++){
1592  const auto& src_ndesc = result.getNode(k, ( src_module_name == name ? "" : src_module_name + '.' ) + src_module_port_name);
1593  const auto& dst_ndesc = result.getNode(l, ( dst_module_name == name ? "" : dst_module_name + '.' ) + dst_module_port_name);
1594  if (!src_ndesc) {
1595  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1596  s << "MRRG port not found for port (" << src_module_port_name<< ") in MODULE (" << src_module_name << ")";
1597  });
1598  }
1599  if (!dst_ndesc) {
1600  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1601  s << "MRRG port not found for port (" << dst_module_port_name<< ") in MODULE (" << dst_module_name << ")";
1602  });
1603  }
1604  result.link(src_ndesc, dst_ndesc);
1605  }
1606  }else {
1607  const auto& src_ndesc = result.getNode(k, ( src_module_name == name ? "" : src_module_name + '.' ) + src_module_port_name);
1608  const auto& dst_ndesc = result.getNode(k, ( dst_module_name == name ? "" : dst_module_name + '.' ) + dst_module_port_name);
1609  if (!src_ndesc) {
1610  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1611  s << "MRRG port not found for port (" << src_module_port_name<< ") in MODULE (" << src_module_name << ")";
1612  });
1613  }
1614  if (!dst_ndesc) {
1615  throw make_from_stream<cgrame_model_error>([&](auto&& s) {
1616  s << "MRRG port not found for port (" << dst_module_port_name<< ") in MODULE (" << dst_module_name << ")";
1617  });
1618  }
1619  result.link(src_ndesc, dst_ndesc);
1620  }
1621  }
1622  }
1623  }
1624 
1625  return result_ptr;
1626 }
1627 
1628 
1629 std::pair<bool, std::pair<double, double>> Module::getSubModulePosition(const std::string & submodName) {
1630  if (name != submodName && parent != nullptr) {
1631  return parent->getSubModulePosition(submodName);
1632  }
1633  else if (parent == nullptr) {
1634  return {false, {}};
1635  }
1636  // std::cout << "In submodule " << name << " looking for " << submodName << "\n"; // Debugging
1637 
1638  float xPos, yPos;
1639  std::string cName = submodName;
1640  Module* cParent = parent;
1641 
1642  VisualPositionRect rel_pos;
1643 
1644  if (cParent->submodule_relative_position.find(cName) == cParent->submodule_relative_position.end()) {
1645  return{false, {}};
1646  }
1647  rel_pos = cParent->submodule_relative_position.at(cName); // This should not throw an exception
1648 
1649  // Put module in the top left corner of its box"
1650  xPos = rel_pos.x;
1651  yPos = rel_pos.y;
1652 
1653  cName = cParent->name;
1654  cParent = cParent->parent;
1655  while (cParent != nullptr) {
1656  if (cParent->submodule_relative_position.find(cName) == cParent->submodule_relative_position.end()) {
1657  return{false, {}};
1658  }
1659 
1660  rel_pos = cParent->submodule_relative_position.at(cName); // This should not throw an exception
1661 
1662  xPos = rel_pos.x + xPos*rel_pos.w;
1663  yPos = rel_pos.y + yPos*rel_pos.h;
1664 
1665  cName = cParent->name;
1666  cParent = cParent->parent;
1667  }
1668  return {true, {xPos, yPos}};
1669 }
1670 
1671 bool Module::setNodePosition(const std::string & nodeName, double x, double y) {
1672  node_relative_position.insert({nodeName,{x, y}});
1673 
1674  return true;
1675 }
1676 
1677 
1678 std::pair<bool, std::pair<double, double>> Module::getNodePosition(const std::string & nodeName) {
1679  // std::cout << "In submodule " << name << " looking for node" << nodeName << "\n"; // Debugging
1680 
1681  double xPos, yPos;
1682  if (node_relative_position.find(nodeName) == node_relative_position.end()) {
1683  return {false, {-1, -1}};
1684  }
1685 
1686  const auto node_pos = node_relative_position.at(nodeName);
1687 
1688  // Put module in the center of its "box"
1689  xPos = node_pos.x;
1690  yPos = node_pos.y;
1691 
1692  std::string cName = name;
1693  Module* cParent = parent;
1694  while (cParent != nullptr) {
1695  if (cParent->submodule_relative_position.find(cName) == cParent->submodule_relative_position.end()) {
1696  return{false, {-1, -1}};
1697  }
1698  const auto rel_pos = cParent->submodule_relative_position.at(cName); // This should not throw an exception
1699 
1700  xPos = rel_pos.x + xPos*rel_pos.w;
1701  yPos = rel_pos.y + yPos*rel_pos.h;
1702 
1703  cName = cParent->name;
1704  cParent = cParent->parent;
1705  }
1706  return {true, {xPos, yPos}};
1707 }
1708 
1709 /************ TriState **********/
1710 TriState::TriState(Mode mode, std::string name, Location loc, unsigned size, bool isElastic)
1711  : Module(name, loc, size, isElastic)
1712  , mode(mode)
1713 {
1714  // adding ports
1715  addPort("enable", PORT_CONFIG, 1, isElastic);
1716  addPort("in", PORT_INPUT, "size", size, isElastic);
1717  addPort("out", PORT_OUTPUT,"size", size, isElastic);
1718 
1719  addVerilogPort("bidir_in", PORT_INPUT, "size", size);
1720  addVerilogPort("bidir_out", PORT_OUTPUT, "size", size);
1721  if(isElastic) {
1722  addVerilogPort("bidir_in_valid_upstream", PORT_INPUT, "", 1);
1723  addVerilogPort("bidir_in_stop_upstream", PORT_OUTPUT, "", 1);
1724  addVerilogPort("bidir_out_valid_downstream", PORT_OUTPUT, "", 1);
1725  addVerilogPort("bidir_out_stop_downstream", PORT_INPUT, "", 1);
1726  }
1727  node_relative_position.insert({"io", {0.5, 0}});
1728  node_relative_position.insert({"in", {0.5, 0.33}});
1729 }
1730 
1732 {
1733  std::cout << SET_INDENT << "assign out = enable ? in : {size{1'bZ}};\n";
1734  std::cout << SET_INDENT << "assign bidir_out = out;\n";
1735 }
1736 
1737 // CoreIR Implementation of GenFunctionality
1738 nlohmann::json TriState::CoreIRGenFunctionality() // Virtual function override
1739 {
1740  nlohmann::json vjson;
1741 
1742  // Construct Header
1743  vjson["prefix"] = "cgrame_";
1744  vjson["parameters"] = {};
1745  for (auto& parameter : parameterlist) {
1746  vjson["parameters"].push_back(parameter.first);
1747  }
1748  vjson["interface"] = makeCoreIRInterface(ports, portsToPropagate);
1749 
1750  // Module Definition
1751  std::string moduleDefinition = makePortsDeclaration(ports, portsToPropagate, SET_INDENT);
1752 
1753  if (isElastic) {
1754  moduleDefinition += std::string(SET_INDENT) + "assign out = enable ? in : bidir_in;\n";
1755  moduleDefinition += std::string(SET_INDENT) + "assign out_valid_downstream = enable ? in_valid_upstream : bidir_in_valid_upstream;\n";
1756  moduleDefinition += std::string(SET_INDENT) + "assign in_stop_upstream = enable ? bidir_out_stop_downstream : out_stop_downstream;\n";
1757  moduleDefinition += std::string(SET_INDENT) + "assign bidir_out = out;\n";
1758  moduleDefinition += std::string(SET_INDENT) + "assign bidir_out_valid_downstream = out_valid_downstream;\n";
1759  moduleDefinition += std::string(SET_INDENT) + "assign bidir_in_stop_upstream = in_stop_upstream;\n";
1760  } else {
1761  moduleDefinition += std::string(SET_INDENT) + "assign out = enable ? in : bidir_in;\n";
1762  moduleDefinition += std::string(SET_INDENT) + "assign bidir_out = out;";
1763  }
1764  vjson["definition"] = moduleDefinition;
1765 
1766  return vjson;
1767 }
1768 
1770  const MRRG& mrrg, const OpGraph & og,
1771  const Mapping& map,
1772  const ConfigCell& ccell,
1773  const std::map<OpGraphOp*,std::set<MRRG::NodeDescriptor>>& mrrg_nodes_from_op_node,
1774  const std::map<OpGraphVal*, std::set<MRRG::NodeDescriptor>>& mrrg_nodes_from_val_node
1775 ) const {
1776  const std::regex in_regex("\\.in$");
1777  const std::regex out_regex("\\.out$");
1778  (void)ccell;
1779  (void)mrrg_nodes_from_op_node;
1780 
1781  BitConfig bitConfig(mrrg.initiationInterval());
1782 
1783  // Organize nodes mapping by cycle
1784  std::vector<MRRGNodesFromValNode> valNodesByCycle(mrrg.initiationInterval());
1785  for (const auto& val_and_mrrg_nodes : mrrg_nodes_from_val_node) {
1786  for (const auto& mrrg_node : val_and_mrrg_nodes.second) {
1787  while (mrrg_node->cycle >= valNodesByCycle.size()) {
1788  valNodesByCycle.push_back({});
1789  }
1790  valNodesByCycle[mrrg_node->cycle][val_and_mrrg_nodes.first].insert(mrrg_node);
1791  }
1792  }
1793 
1794  int cycle = 0;
1795  int used_cycles = 0;
1796  for (auto & mrrg_nodes_from_val_by_cycle : valNodesByCycle) {
1797  if (mrrg_nodes_from_val_by_cycle.empty()) {
1798  bitConfig.add( {BitSetting::LOW}, cycle);
1799  } else if (mrrg_nodes_from_val_by_cycle.size() != 1) {
1800  throw cgrame_error("expect one val node");
1801  } else {
1802  // const auto& val_node = begin(mrrg_nodes_from_val_node)->first;
1803  const auto& mrrg_nodes = begin(mrrg_nodes_from_val_by_cycle)->second;
1804  if (mrrg_nodes.size() != 1) {
1805  throw cgrame_error("expect one MRRG node");
1806  } else {
1807  const auto& mrrg_node = **begin(mrrg_nodes);
1808  const auto& name = mrrg_node.getHierarchyQualifiedName();
1809  if (regex_search(name, in_regex)) {
1810  used_cycles++;
1811  bitConfig.add( {BitSetting::HIGH}, cycle);
1812  } else if (regex_search(name, out_regex)) {
1813  used_cycles++;
1814  bitConfig.add( {BitSetting::LOW}, cycle);
1815  } else {
1816  throw cgrame_error("unexpected MRRG node");
1817  }
1818  }
1819  }
1820  ++cycle;
1821  }
1822  bitConfig.setUsedCycles(used_cycles);
1823  return bitConfig;
1824 }
1825 
1826 MRRG* TriState::createMRRG(unsigned II = 1)
1827 {
1828  MRRG* result_ptr = new MRRG(II);
1829  auto& result = *result_ptr;
1830  for(unsigned i = 0; i < II; i++)
1831  {
1832  // create nodes
1833  MRRG::NodeDescriptor io = result.insert([&]() {
1834  if (mode == Mode::PROVIDES_IO_OP) {
1835  return MRRGNode::make_function(this, data_size, i, "io", 0,
1837  );
1838  } else if (mode == Mode::PROVIDES_IO_PRED_OP) {
1839  return MRRGNode::make_function(this, data_size, i, "io", 0,
1841  );
1842  } else {
1843  return MRRGNode::make_routing(this, data_size, i, "io");
1844  }
1845  }()).first;
1846  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "out")).first;
1847 
1848 
1849 
1850  MRRG::NodeDescriptor in = result.insert(MRRGNode::make_routing(this, data_size, i, "in")).first;
1851 
1852  // in is an input into the io block, which will be output from the CGRA
1853  // out is an output from the io block, which will be an input to the CGRA
1854  result.link(in, io);
1855  result.link(io, out);
1856  }
1857 
1858  return result_ptr;
1859 }
1860 
1862 {
1863  std::string elas = isElastic ? "elastic_" : "";
1864  return elas + "tristate_" + std::to_string(getSize()) + "b";
1865 }
1866 
1868 {
1869 }
1870 
1871 
1872 /************ IO **********/
1873 IO::IO(std::string name, Location loc, unsigned size, int contexts, bool isElastic)
1874 : Module(name, loc, size, isElastic)
1875 {
1876  // adding ports
1877  addPort("in", PORT_INPUT, size, isElastic);
1878  addPort("out", PORT_OUTPUT, size, isElastic);
1879  if (contexts > 1)
1880  addPort("Context", PORT_INPUT, ceil(log2(contexts)));
1881 
1882  node_relative_position.insert({"in", {0, 0}});
1883  node_relative_position.insert({"out", {0, 0.67}});
1884 
1885  addSubModule(new Register("reg_in", loc, size, isElastic), 0.1, 0.2, 0.9, 0.33);
1886  addSubModule(new Register("reg_out", loc, size, isElastic), 0.1, 0.5, 0.9, 0.33);
1887  addSubModule(new TriState(((size == 1)?TriState::Mode::PROVIDES_IO_PRED_OP : TriState::Mode::PROVIDES_IO_OP), "IOPin", loc, size, isElastic), 0.1, 0.33, 0.9, 0.33);
1888 
1889  addConfig("IOPinConfig", {"IOPin.enable"}, contexts, isElastic);
1890  addConfig("RegInConfig", {"reg_in.enable"}, contexts, isElastic);
1891  addConfig("RegOutConfig", {"reg_out.enable"}, contexts, isElastic);
1892  if (contexts > 1) {
1893  addConnection("this.Context", "IOPinConfig.Context", false);
1894  addConnection("this.Context", "RegInConfig.Context", false);
1895  addConnection("this.Context", "RegOutConfig.Context", false);
1896  }
1897 
1898  connectPorts("this.in", "reg_in.in", isElastic);
1899  connectPorts("reg_in.out", "IOPin.in", isElastic);
1900  connectPorts("IOPin.out", "reg_out.in", isElastic);
1901  connectPorts("reg_out.out", "this.out", isElastic);
1902 }
1903 
1904 std::string IO::GenericName()
1905 {
1906  return "io_" + std::to_string(getSize()) + "b";
1907 }
1908 
1910 {
1911 }
1912 
1913 DisconnectedSource::DisconnectedSource(std::string name, Location loc, unsigned size, int value)
1914  : Module(name, loc, size)
1915  , value(value)
1916 {
1917  addPort("out", PORT_OUTPUT, "size", size);
1918 }
1919 
1920 std::string DisconnectedSource::GenericName() { return "disconnected_source_" + std::to_string(getSize()) + "b" + std::to_string(value); }
1922 
1924  std::cout << SET_INDENT << "assign out = " << getSize() << "'d" << value << ";\n";
1925 }
1926 
1928  nlohmann::json vjson;
1929 
1930  // Construct Header
1931  vjson["prefix"] = "cgrame_";
1932  vjson["parameters"] = {};
1933  for (auto& parameter : parameterlist) {
1934  vjson["parameters"].push_back(parameter.first);
1935  }
1936  vjson["interface"] = makeCoreIRInterface(ports, portsToPropagate);
1937 
1938  // Module Definition
1939  std::string moduleDefinition = makePortsDeclaration(ports, portsToPropagate, SET_INDENT);
1940  moduleDefinition += SET_INDENT;
1941  moduleDefinition += "assign out = " + std::to_string(getSize()) + "'d" + std::to_string(value) + ";\n";
1942  vjson["definition"] = moduleDefinition;
1943  return vjson;
1944 }
1945 
1946 DisconnectedSink::DisconnectedSink(std::string name, Location loc, unsigned size)
1947  : Module(name, loc, size)
1948 {
1949  addPort("in", PORT_INPUT, "size", size);
1950 }
1951 
1952 std::string DisconnectedSink::GenericName() { return "disconnected_sink_" + std::to_string(getSize()) + "b"; }
1954 
1956  std::cout << SET_INDENT << "// purposefully left blank\n";
1957 }
1958 
1960  nlohmann::json vjson;
1961 
1962  // Construct Header
1963  vjson["prefix"] = "cgrame_";
1964  vjson["parameters"] = {};
1965  for (auto& parameter : parameterlist) {
1966  vjson["parameters"].push_back(parameter.first);
1967  }
1968  vjson["interface"] = makeCoreIRInterface(ports, portsToPropagate);
1969 
1970  // Module Definition
1971  std::string moduleDefinition = makePortsDeclaration(ports, portsToPropagate, SET_INDENT);
1972  moduleDefinition += SET_INDENT;
1973  moduleDefinition += "// purposefully left blank\n";
1974  vjson["definition"] = moduleDefinition;
1975  return vjson;
1976 }
1977 
1978 /************ CustomModule **********/
1979 CustomModule::CustomModule(std::string name, Location loc, std::vector<std::string> Function, unsigned size, std::string pred)
1980  : Module(name, loc, size)
1981  , Function(Function)
1982 {
1983  // Create ports
1984  addPort("a", PORT_INPUT, "size", size);
1985  addPort("b", PORT_INPUT, "size", size);
1986  addPort("c", PORT_OUTPUT, "size", size);
1987  if(!pred.empty()){
1988  addPort(pred, PORT_INPUT, 1);
1989  }
1990 }
1991 
1992 // Virtual function that overrides Module::GetFunctionality. Generates the functionality for CustomModule
1994 {
1995  for (unsigned i = 0; i < Function.size(); i++)
1996  std::cout << SET_INDENT << Function[i] << "\n";
1997 }
1998 
1999 // CoreIR Implementation of GenFunctionality
2000 nlohmann::json CustomModule::CoreIRGenFunctionality() // Virtual function override
2001 {
2002  nlohmann::json vjson;
2003 
2004  // Construct Header
2005  vjson["prefix"] = "cgrame_";
2006  vjson["parameters"] = {};
2007  for (auto& parameter : parameterlist) {
2008  vjson["parameters"].push_back(parameter.first);
2009  }
2010  vjson["interface"] = {};
2011  for (auto& port : ports) {
2012  if (port.second->pt == port_type::PORT_BIDIR) {
2013  const auto ioport_copies = splitBidirPort(*port.second);
2014  vjson["interface"].push_back(ioport_copies.first.name);
2015  vjson["interface"].push_back(ioport_copies.second.name);
2016  } else {
2017  std::string portName = port.second->getName();
2018  vjson["interface"].push_back(portName);
2019  }
2020  }
2021 
2022  // Module Definition
2023  std::string moduleDefinition;
2024  for (auto& port : ports) {
2025  moduleDefinition += makePortDeclaration(*port.second, SET_INDENT);
2026  }
2027 
2028  // Functional Definition
2029  for (unsigned i = 0; i < Function.size(); i++)
2030  {
2031  moduleDefinition += std::string(SET_INDENT) + Function[i] + "\n";
2032  }
2033  vjson["definition"] = moduleDefinition;
2034  return vjson;
2035 }
2036 
2038 {
2039  return name;
2040 }
2041 
2043 {
2044 }
2045 
2046 /************ CustomModuleSingleInput **********/
2047 CustomModuleSingleInput::CustomModuleSingleInput(std::string name, Location loc, std::vector<std::string> Function, unsigned size, std::string pred)
2048  : Module(name, loc, size)
2049  , Function(Function)
2050 {
2051  // Create ports
2052  addPort("a", PORT_INPUT, "size", size);
2053  addPort("c", PORT_OUTPUT, "size", size);
2054  if(!pred.empty()){
2055  addPort(pred, PORT_INPUT, 1);
2056  }
2057 }
2058 
2059 // Virtual function that overrides Module::GetFunctionality. Generates the functionality for CustomModuleSingleInput
2061 {
2062  for (unsigned i = 0; i < Function.size(); i++)
2063  std::cout << SET_INDENT << Function[i] << "\n";
2064 }
2065 
2066 // CoreIR Implementation of GenFunctionality
2067 nlohmann::json CustomModuleSingleInput::CoreIRGenFunctionality() // Virtual function override
2068 {
2069  nlohmann::json vjson;
2070 
2071  // Construct Header
2072  vjson["prefix"] = "cgrame_";
2073  vjson["parameters"] = {};
2074  for (auto& parameter : parameterlist) {
2075  vjson["parameters"].push_back(parameter.first);
2076  }
2077  vjson["interface"] = {};
2078  for (auto& port : ports) {
2079  if (port.second->pt == port_type::PORT_BIDIR) {
2080  const auto ioport_copies = splitBidirPort(*port.second);
2081  vjson["interface"].push_back(ioport_copies.first.name);
2082  vjson["interface"].push_back(ioport_copies.second.name);
2083  } else {
2084  std::string portName = port.second->getName();
2085  vjson["interface"].push_back(portName);
2086  }
2087  }
2088 
2089  // Module Definition
2090  std::string moduleDefinition;
2091  for (auto& port : ports) {
2092  moduleDefinition += makePortDeclaration(*port.second, SET_INDENT);
2093  }
2094 
2095  // Functional Definition
2096  for (unsigned i = 0; i < Function.size(); i++)
2097  {
2098  moduleDefinition += std::string(SET_INDENT) + Function[i] + "\n";
2099  }
2100  vjson["definition"] = moduleDefinition;
2101  return vjson;
2102 }
2103 
2105 {
2106  return name;
2107 }
2108 
2110 {
2111 }
2112 
2113 /************ UserModule **********/
2114 UserModule::UserModule(std::string prototype, std::string name, Location loc, std::vector<std::string> Ports)
2115  : Module(name, loc)
2116  , prototype(prototype)
2117 {
2118 
2119  // adding ports
2120  for (unsigned i = 0; i < Ports.size(); i++)
2121  {
2122  addPort(Ports[i], PORT_UNSPECIFIED, DEFAULT_SIZE); // We do not care if the port is input or output
2123  }
2124 
2125 }
2126 
2127 // Virtual function that overrides Module::GenericName. Returns generic name of the object
2128 std::string UserModule::GenericName() // Virtual function override
2129 {
2130  return prototype;
2131 }
2132 
2134 {
2135 }
2136 
2137 /************ ConfigCell **********/
2138 ConfigCell::ConfigCell(std::string name, int contexts, Location loc)
2139  : Module(name, loc, 0)
2140  , connected_ports()
2141  , l_contexts(contexts)
2142 {
2143  parameterlist.emplace("size", getSize());
2144  addPort("select", port_type::PORT_OUTPUT, "size", PARAMETERIZED);
2145  if (contexts > 1) addPort("Context", PORT_INPUT, ceil(log2(contexts)));
2147 }
2148 
2149 // Prints out the Verilog code for the config cell
2151 {
2152  std::string cellSize = std::to_string(getStorageSize());
2153  // Module header
2154  std::cout << "module configCell_" + cellSize + "b(ConfigIn, ConfigOut, Config_Clock, Config_Reset, select);\n";
2155  // Parameter specification
2156  std::cout << " parameter size = " + cellSize + ";\n";
2157  // Port specifications
2158  std::cout << " input Config_Clock, Config_Reset, ConfigIn;\n";
2159  std::cout << " output ConfigOut;\n";
2160  std::cout << " output [size-1:0] select;\n";
2161  // Functionality
2162  std::cout << " reg [size-1:0] temp;\n\n";
2163  std::cout << " always @(posedge Config_Clock, posedge Config_Reset)\n";
2164  std::cout << " if (Config_Reset)\n";
2165  std::cout << " temp = 0;\n";
2166  std::cout << " else\n";
2167  std::cout << " begin\n";
2168  std::cout << " temp = temp >> 1;\n";
2169  std::cout << " temp[size-1] = ConfigIn;\n";
2170  std::cout << " end\n";
2171  std::cout << " assign select = temp;\n";
2172  std::cout << " assign ConfigOut = temp[0];\n";
2173  std::cout << "endmodule\n";
2174 }
2175 
2176 void ConfigCell::addControledPorts(const std::vector<Port*>& new_ports) {
2177 
2178  const auto port_is_new = [&](auto&& port) { auto& cp = connected_ports; return cp.end() == std::find(cp.begin(), cp.end(), port); };
2179  std::copy_if(new_ports.begin(), new_ports.end(), std::back_inserter(connected_ports), port_is_new);
2180 
2181  for (auto& port : connected_ports) {
2182  int port_size = port->size;
2183  if (port->size == PARAMETERIZED) {
2184  port_size = port->parent->parameterlist.at(port->parameter);
2185  }
2186  data_size = std::max(getSize(), port_size);
2187  }
2188  parameterlist["size"] = getSize(); // manually sync the param with data_size
2189 }
2190 
2192 {
2193  auto context_size = (parameterlist["contexts"] == 1) ? "0" : "$clog2(contexts)-1";
2194  nlohmann::json vjson;
2195 
2196  // Construct Header
2197  vjson["prefix"] = "cgrame_";
2198  vjson["parameters"] = {};
2199  for (auto& parameter : parameterlist)
2200  {
2201  vjson["parameters"].push_back(parameter.first);
2202  }
2203  vjson["interface"] = {};
2204  vjson["interface"].push_back("ConfigIn");
2205  vjson["interface"].push_back("ConfigOut");
2206  vjson["interface"].push_back("Config_Clock");
2207  vjson["interface"].push_back("Config_Reset");
2208  vjson["interface"].push_back("CGRA_Clock");
2209  vjson["interface"].push_back("CGRA_Reset");
2210  vjson["interface"].push_back("CGRA_Enable");
2211  if (l_contexts > 1) vjson["interface"].push_back("Context");
2212  vjson["interface"].push_back("select");
2213 
2214  // module definition
2215  std::string moduleDefinition;
2216  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
2217  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
2218  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
2219  moduleDefinition += std::string(SET_INDENT) + "input ConfigIn;\n";
2220  moduleDefinition += std::string(SET_INDENT) + "input Config_Clock;\n";
2221  moduleDefinition += std::string(SET_INDENT) + "input Config_Reset;\n";
2222  if (l_contexts > 1) moduleDefinition += std::string(SET_INDENT) + "input [" + context_size + ":0] Context;\n";
2223  moduleDefinition += std::string(SET_INDENT) + "output ConfigOut;\n";
2224  moduleDefinition += std::string(SET_INDENT) + "output [size-1:0] select;\n";
2225  moduleDefinition += std::string(SET_INDENT) + "reg [size-1:0] config_reg [contexts-1:0];\n\n";
2226  moduleDefinition += std::string(SET_INDENT) + "reg [contexts-1:0] context_counter = {size{1'b0}};\n\n";
2227  moduleDefinition += std::string(SET_INDENT) + "integer i;\n\n";
2228 
2229  moduleDefinition += std::string(SET_INDENT) + "always @(posedge Config_Clock, posedge Config_Reset)\n";
2230  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if (Config_Reset) begin\n";
2231  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "for (i = 0; i < contexts; i = i+1) begin\n";
2232  moduleDefinition += std::string(SET_QUAD_INDENT) + "config_reg[i] <= 'd0;\n";
2233  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
2234  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
2235  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "else begin\n";
2236  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "for (i = 0; i < contexts; i = i+1) begin\n";
2237  moduleDefinition += std::string(SET_QUAD_INDENT) + "if(i == 0) begin\n";
2238 
2239  if (parameterlist["size"] > 1) {
2240  moduleDefinition += std::string(SET_PENTA_INDENT) + "config_reg[i] <= {ConfigIn,config_reg[i][size-1:1]};\n";
2241  moduleDefinition += std::string(SET_QUAD_INDENT) + "end\n";
2242  moduleDefinition += std::string(SET_QUAD_INDENT) + "else begin\n";
2243  moduleDefinition += std::string(SET_PENTA_INDENT) + "config_reg[i] <= {config_reg[i-1][0],config_reg[i][size-1:1]};\n";
2244  }
2245  else {
2246  moduleDefinition += std::string(SET_PENTA_INDENT) + "config_reg[i] <= ConfigIn;\n";
2247  moduleDefinition += std::string(SET_QUAD_INDENT) + "end\n";
2248  moduleDefinition += std::string(SET_QUAD_INDENT) + "else begin\n";
2249  moduleDefinition += std::string(SET_PENTA_INDENT) + "config_reg[i] <= config_reg[i-1];\n";
2250  }
2251 
2252  moduleDefinition += std::string(SET_QUAD_INDENT) + "end\n";
2253  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
2254  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n\n";
2255  if (l_contexts <= 1) {
2256  moduleDefinition += std::string(SET_INDENT) + "assign select = config_reg[0];\n";
2257  moduleDefinition += std::string(SET_INDENT) + "assign ConfigOut = config_reg[contexts-1][0];";
2258  } else {
2259  moduleDefinition += std::string(SET_INDENT) + "assign select = config_reg[Context];\n";
2260  moduleDefinition += std::string(SET_INDENT) + "assign ConfigOut = config_reg[contexts-1][0];";
2261  }
2262 
2263  vjson["definition"] = moduleDefinition;
2264  return vjson;
2265 }
2266 
2268 {
2269  return "configcell_context_II_" + std::to_string(l_contexts) + "_" + std::to_string((contexts.size() > 0) ? contexts.size() : 1) + "_size" + std::to_string(getStorageSize());
2270 }
2271 /************ ContextCounter **********/
2272 /* Context counters are binary counters present in PEs, IOs, MemPorts and RegisterFiles to count the context for
2273  * multi-context support in CGRAs. The Context port with the context count is connected to the configuration cells in
2274  * the tile. Having separate counters in each tile in the CGRA counting in tandem reduces the fan-out of the counter
2275  * when compared to having a single counter in the CGRA connected to all configuration cells in the CGRA*/
2276 ContextCounter::ContextCounter(std::string name, int contexts, Location loc)
2277  : Module(name, loc, 0)
2278 {
2279  addPort("Context_Used", PORT_INPUT, ceil(log2(contexts)));
2280  addPort("Context", PORT_OUTPUT_REG, ceil(log2(contexts)));
2281  parameterlist.emplace("size", getSize());
2282  parameterlist.emplace("contexts", contexts);
2284 }
2285 
2287 {
2288  auto context_size = (parameterlist["contexts"] == 1) ? "0" : "$clog2(contexts)-1";
2289  nlohmann::json vjson;
2290 
2291  // Construct Header
2292  vjson["prefix"] = "cgrame_";
2293  vjson["parameters"] = {};
2294  for (auto& parameter : parameterlist)
2295  {
2296  vjson["parameters"].push_back(parameter.first);
2297  }
2298  vjson["interface"] = {};
2299  vjson["interface"].push_back("CGRA_Clock");
2300  vjson["interface"].push_back("CGRA_Reset");
2301  vjson["interface"].push_back("CGRA_Enable");
2302  vjson["interface"].push_back("Context_Used");
2303  vjson["interface"].push_back("Context");
2304 
2305  // module definition
2306  std::string moduleDefinition;
2307  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
2308  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
2309  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
2310  moduleDefinition += std::string(SET_INDENT) + "input [" + context_size + ":0] Context_Used;\n";
2311  moduleDefinition += std::string(SET_INDENT) + "output reg [" + context_size + ":0] Context;\n\n";
2312  moduleDefinition += std::string(SET_INDENT) + "integer i;\n\n";
2313 
2314  moduleDefinition += std::string(SET_INDENT) + "always @(posedge CGRA_Clock, posedge CGRA_Reset)\n";
2315  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if (CGRA_Reset) begin\n";
2316  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "Context <= 'd0;\n";
2317  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
2318  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "else if (CGRA_Enable) begin\n";
2319  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "if (Context < Context_Used) begin\n";
2320  moduleDefinition += std::string(SET_QUAD_INDENT) + "Context <= (Context+1);\n";
2321  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
2322  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "else begin\n";
2323  moduleDefinition += std::string(SET_QUAD_INDENT) + "Context <= 'd0;\n";
2324  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
2325  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end";
2326 
2327  vjson["definition"] = moduleDefinition;
2328  return vjson;
2329 }
2330 
2332 {
2333  return "contextcounter";
2334 }
2335 
2336 /************ ContextCell **********/
2337 /* ContextCell stores the number of contexts to be used by the CGRA (i.e. initiation interval, II). So, a CGRA
2338  * with supported number of contexts, contexts, can be mapped with an application to work in any number of contexts
2339  * 1<=II<=contexts. The II of the mapped application is configured into the CGRA with the configuration bitstream
2340  * and is stored in ContextCell. The Context_Used port is connected to all ContextCounters in the CGRA tiles. */
2341 ContextCell::ContextCell(std::string name, int contexts, Location loc)
2342  : Module(name, loc, 0),
2343  l_contexts(contexts)
2344 {
2345  addPort("Context_Used", PORT_OUTPUT, ceil(log2(contexts)));
2346  parameterlist.emplace("size", getSize());
2347  parameterlist.emplace("contexts", contexts);
2348  addConfig(new ConfigCell("ContextsUsed", 1), {"this.Context_Used"});
2349 }
2350 
2352  const MRRG& mrrg, const OpGraph & og,
2353  const Mapping& map,
2354  const ConfigCell& ccell,
2355  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
2356  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
2357 ) const {
2358  (void)ccell;
2359 
2360  BitConfig bitConfig(1);
2361  std::vector<BitSetting> result = bitsettings_from_int(mrrg.initiationInterval() - 1, ceil(log2(l_contexts)));
2362  bitConfig.add(result, 0);
2363 
2364  return bitConfig;
2365 }
2367 {
2368  return "contextcell";
2369 }
2370 
2371 /************ Extractor ***********/
2372 static const std::map<std::string, port_type> port_type_map =
2373 {
2374  {"input", PORT_INPUT},
2375  {"output", PORT_OUTPUT},
2376  {"output-reg", PORT_OUTPUT_REG},
2377  {"bidir", PORT_BIDIR},
2378  {"unspecified", PORT_UNSPECIFIED},
2379 };
2380 
2381 std::istream& operator >>(std::istream &is, port_type &type)
2382 {
2383  std::string str;
2384  is >> str;
2385  if (port_type_map.count(str) > 0)
2386  type = port_type_map.at(str);
2387  else
2388  is.setstate(std::ios_base::failbit);
2389 
2390  return is;
2391 }
Module::VisualPositionRect::w
double w
Definition: Module.h:351
Module::submodules
std::map< std::string, Module * > submodules
Definition: Module.h:227
DisconnectedSink::GenericName
virtual std::string GenericName() override
Definition: Module.cpp:1952
Module::GenPortSpecs
void GenPortSpecs(bool HasConfig, bool HasRegisters)
Definition: Module.cpp:684
BitSetting::HIGH
@ HIGH
BitConfig
Definition: BitSetting.h:58
Module::name
std::string name
Definition: Module.h:341
Module::FindPortIndex
int FindPortIndex(std::string PortName)
Definition: Module.cpp:969
ConfigCell
Definition: Module.h:825
Module::connections
std::map< Port *, Connection * > connections
Definition: Module.h:226
DisconnectedSink::DisconnectedSink
DisconnectedSink(std::string name, Location, unsigned size)
Definition: Module.cpp:1946
IO::GenericName
virtual std::string GenericName() override
Definition: Module.cpp:1904
Connection
Definition: Module.h:99
CustomModuleSingleInput::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: Module.cpp:2067
Port::name
std::string name
Definition: Module.h:91
Module::GetConfigsToPrint
void GetConfigsToPrint(std::queue< ConfigCell * > &q, std::set< unsigned > &uniq)
Definition: Module.cpp:240
port_type_map
static const std::map< std::string, port_type > port_type_map
Definition: Module.cpp:2372
ContextCounter::ContextCounter
ContextCounter(std::string name, int contexts, Location loc={0, 0})
Definition: Module.cpp:2276
DisconnectedSink::GenFunctionality
virtual void GenFunctionality() override
Definition: Module.cpp:1955
Module::genVerilogCGRAME
void genVerilogCGRAME(std::string dir)
Definition: Module.cpp:175
CustomModule::Function
std::vector< std::string > Function
Definition: Module.h:800
UserModule::UserModule
UserModule(std::string prototype, std::string name, Location, std::vector< std::string > Ports)
Definition: Module.cpp:2114
CustomModuleSingleInput::GenFunctionality
virtual void GenFunctionality() override
Definition: Module.cpp:2060
SET_TRIPLE_INDENT
const char *const SET_TRIPLE_INDENT
Definition: Module.h:39
MRRG
Definition: MRRG.h:216
PORT_OUTPUT_REG
@ PORT_OUTPUT_REG
Definition: Module.h:65
Module::print_configcells
void print_configcells()
Definition: Module.cpp:1055
MRRGNodesFromOpNode
std::map< OpGraphOp *, std::set< MRRG::NodeDescriptor > > MRRGNodesFromOpNode
Definition: Module.h:146
Module::isSubModule
bool isSubModule(Module *)
Definition: Module.cpp:1160
DisconnectedSource::GenericName
virtual std::string GenericName() override
Definition: Module.cpp:1920
Module::DetermineConnections
void DetermineConnections(StringMatrix &Matrix, PrintList &WireList, PrintList &SubmodList, PrintList &AssignList)
Definition: Module.cpp:765
Location
Definition: Module.h:156
Module::data_size
unsigned data_size
Definition: Module.h:338
ContextCell::ContextCell
ContextCell(std::string name, int contexts, Location loc={0, 0})
Definition: Module.cpp:2341
VerilogType
VerilogType
Definition: Module.h:150
Module::templateName
std::string templateName
Definition: Module.h:340
ModuleElastic.h
PrintList::add
void add(std::vector< std::string > Data)
Definition: Module.h:112
Port::pt
port_type pt
Definition: Module.h:92
TriState::getBitConfig
virtual BitConfig getBitConfig(const MRRG &mrrg, const OpGraph &og, const Mapping &map, const ConfigCell &ccell, const MRRGNodesFromOpNode &mrrg_nodes_from_op_node, const MRRGNodesFromValNode &mrrg_nodes_from_val_node) const override
Definition: Module.cpp:1769
Module::addConnection
void addConnection(std::string src, std::string dst, bool isInMRRG=true)
Definition: Module.cpp:1241
begin
auto begin(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:137
SET_PENTA_INDENT
const char *const SET_PENTA_INDENT
Definition: Module.h:41
PrintList
Definition: Module.h:109
Module.h
Module::getSubModulePosition
std::pair< bool, std::pair< double, double > > getSubModulePosition(const std::string &submodName)
Definition: Module.cpp:1629
TriState::createMRRG
virtual MRRG * createMRRG(unsigned II) override
Definition: Module.cpp:1826
Module::addParameter
void addParameter(std::string parameterName, unsigned parameterValue)
Definition: Module.cpp:1503
Module::adds_synchronous_circuitry
bool adds_synchronous_circuitry
Definition: Module.h:370
TriState::TriState
TriState(Mode mode, std::string, Location, unsigned size=DEFAULT_SIZE, bool isElastic=false)
Definition: Module.cpp:1710
Module::parent
Module * parent
Definition: Module.h:243
Module::getSubModule
Module * getSubModule(std::string)
Definition: Module.cpp:1147
Module::print_submodules
void print_submodules()
Definition: Module.cpp:1046
Module::setNodePosition
bool setNodePosition(const std::string &nodeName, double x, double y)
Definition: Module.cpp:1671
Module::parameterlist
std::map< std::string, unsigned > parameterlist
Definition: Module.h:224
ConfigCell::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: Module.cpp:2191
DisconnectedSink::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: Module.cpp:1959
Port
Definition: Module.h:84
Register
A simple latency element with an enable signal; a data flip-flop.
Definition: Module.h:566
PrintList::print
void print()
Definition: Module.h:120
BitConfig::add
void add(std::vector< BitSetting > bitsetting, int cycle)
Definition: BitSetting.h:63
Port::getName
const std::string & getName() const
Definition: Module.h:86
CustomModule::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: Module.cpp:2000
Module::addPort
void addPort(std::string portname, port_type pt, unsigned size)
Definition: Module.cpp:1354
Module::VisualPositionRect::x
double x
Definition: Module.h:351
Module::node_relative_position
std::map< std::string, VisualPositionPoint > node_relative_position
Definition: Module.h:360
Module::print
void print()
Definition: Module.cpp:996
Module::FindSubmoduleIndex
int FindSubmoduleIndex(std::string SubmoduleName)
Definition: Module.cpp:983
ConfigCell::GenModuleVerilog
void GenModuleVerilog() override
Definition: Module.cpp:2150
PORT_DEFAULT_CONNECTION
const char *const PORT_DEFAULT_CONNECTION
Definition: Module.h:44
Port::getModule
Module & getModule() const
Definition: Module.h:87
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
Connection::src
Port * src
Definition: Module.h:102
ConfigCell::connected_ports
std::vector< Port * > connected_ports
Definition: Module.h:843
MRRG::insert
std::pair< NodeDescriptor, bool > insert(MRRGNode node)
Definition: MRRG.cpp:91
StringMatrix
std::vector< std::vector< std::string > > StringMatrix
Definition: Module.h:35
MRRGNodesFromValNode
std::map< OpGraphVal *, std::set< MRRG::NodeDescriptor > > MRRGNodesFromValNode
Definition: Module.h:147
Module::getModuleFromPortName
Module * getModuleFromPortName(std::string full_port_name, std::string err_context="")
Definition: Module.cpp:1186
Module::GenConnections
virtual void GenConnections()
Definition: Module.cpp:720
ModuleProcedures.h
BitSetting::LOW
@ LOW
Mapping
Definition: Mapping.h:31
Module::hasConfigCells
bool hasConfigCells() const
Definition: Module.h:255
ContextCell::GenericName
virtual std::string GenericName() override
Definition: Module.cpp:2366
PORT_CONFIG
@ PORT_CONFIG
Definition: Module.h:67
VerilogType::CoreIR
@ CoreIR
Module::GenericName
virtual std::string GenericName()
Definition: Module.cpp:260
Module::configcells
std::map< std::string, ConfigCell * > configcells
Definition: Module.h:228
ContextCounter::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: Module.cpp:2286
ConfigCell::ConfigCell
ConfigCell(std::string name, int contexts=1, Location loc={0, 0})
Definition: Module.cpp:2138
ResolvedVeroligModuleParameter
Definition: Module.h:141
DisconnectedSource::~DisconnectedSource
virtual ~DisconnectedSource()
Definition: Module.cpp:1921
CustomModule::CustomModule
CustomModule(std::string name, Location, std::vector< std::string > Function, unsigned size=DEFAULT_SIZE, std::string pred="")
Definition: Module.cpp:1979
Module::addElasticConnection
void addElasticConnection(std::string src, std::string dst)
Definition: Module.cpp:1469
cgrame_model_error
Definition: Exception.h:48
UserModule::GenericName
virtual std::string GenericName() override
Definition: Module.cpp:2128
getmoduleport
static bool getmoduleport(std::string name, std::string *module, std::string *port)
Definition: Module.cpp:1065
OpCode::INPUT
@ INPUT
ContextCell::getBitConfig
virtual BitConfig getBitConfig(const MRRG &mrrg, const OpGraph &og, const Mapping &map, const ConfigCell &ccell, const MRRGNodesFromOpNode &mrrg_nodes_from_op_node, const MRRGNodesFromValNode &mrrg_nodes_from_val_node) const override
Definition: Module.cpp:2351
MRRGNode::make_function
static MRRGNode make_function(Module *parent, int bitwidth, int cycle, STR &&name, int latency, SupportedOps supported_ops, int max_cap=1, bool is_const_unit=false)
Definition: MRRG.h:191
Module::GenModuleHeader
void GenModuleHeader(bool HasConfig, bool HasRegisters)
Definition: Module.cpp:645
IO::IO
IO(std::string, Location, unsigned size=DEFAULT_SIZE, int contexts=1, bool isElastic=false)
Definition: Module.cpp:1873
Module::VisualPositionRect::h
double h
Definition: Module.h:351
Module::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality()
Definition: Module.cpp:757
OpCode::INPUT_PRED
@ INPUT_PRED
DisconnectedSource::GenFunctionality
virtual void GenFunctionality() override
Definition: Module.cpp:1923
TriState::GenericName
virtual std::string GenericName() override
Definition: Module.cpp:1861
SET_INDENT
const char *const SET_INDENT
Definition: Module.h:37
Module
Definition: Module.h:163
VerilogType::CGRAME
@ CGRAME
TriState::GenFunctionality
virtual void GenFunctionality() override
Definition: Module.cpp:1731
Module::print_ports
void print_ports()
Definition: Module.cpp:1027
MODULE_DEBUG_PRINTING
const bool MODULE_DEBUG_PRINTING
Definition: Module.h:46
PORT_INPUT
@ PORT_INPUT
Definition: Module.h:63
Module::getModule
Module * getModule(std::string, std::string err_context="")
Definition: Module.cpp:1167
Module::print_dot
void print_dot()
Definition: Module.cpp:1008
Module::portsToPropagate
std::vector< Port > portsToPropagate
Definition: Module.h:229
Module::addVerilogPort
void addVerilogPort(std::string name, port_type pt, std::string parameter, unsigned size)
Definition: Module.cpp:1515
Module::CoreIRGenModuleVerilog
virtual void CoreIRGenModuleVerilog(CoreIR::Context *c, int contexts)
Definition: Module.cpp:606
DisconnectedSink::~DisconnectedSink
virtual ~DisconnectedSink()
Definition: Module.cpp:1953
Connection::dst
std::vector< Port * > dst
Definition: Module.h:103
IO::~IO
virtual ~IO()
Definition: Module.cpp:1909
CustomModule::GenericName
virtual std::string GenericName() override
Definition: Module.cpp:2037
Module::VisualPositionRect::y
double y
Definition: Module.h:351
operator<<
std::ostream & operator<<(std::ostream &os, VerilogType vt)
Definition: Module.cpp:98
Module::genConfigOrder
void genConfigOrder(std::vector< ConfigCell * > &ConfigTable) const
Definition: Module.cpp:164
Module::GetModulesToPrint
void GetModulesToPrint(std::queue< Module * > &ToPrint, std::set< std::string > &PrintedModMap)
Definition: Module.cpp:220
Module::~Module
virtual ~Module()
Definition: Module.cpp:150
Module::addConfig
void addConfig(ConfigCell *c, std::vector< std::string > ConnectTo)
Definition: Module.cpp:1087
Module::getPort
Port * getPort(std::string full_port_name, std::string err_context="")
Definition: Module.cpp:1201
Module::makeCoreIRModuleDefinitonGenerator
CoreIR::ModuleDefGenFun makeCoreIRModuleDefinitonGenerator()
Definition: Module.cpp:409
ConfigCell::addControledPorts
void addControledPorts(const std::vector< Port * > &new_ports)
Definition: Module.cpp:2176
OpGraphVal
Definition: OpGraph.h:178
UserModule::~UserModule
virtual ~UserModule()
Definition: Module.cpp:2133
UserModule::prototype
std::string prototype
Definition: Module.h:822
PARAMETERIZED
const int PARAMETERIZED
Definition: Module.h:50
moduleRequiresClockPorts
bool moduleRequiresClockPorts(const Module &m)
Definition: ModuleProcedures.cpp:3
ElasticConfigCell
Definition: ModuleElastic.h:318
OpGraphOp
Definition: OpGraph.h:131
MRRGNode
Definition: MRRG.h:60
TriState::mode
Mode mode
Definition: Module.h:752
Module::getSize
int getSize() const
Definition: Module.h:246
Module::addElasticPort
void addElasticPort(std::string portname, port_type pt, unsigned size)
Definition: Module.cpp:1440
TriState::Mode::PROVIDES_IO_OP
@ PROVIDES_IO_OP
Module::submodule_relative_position
std::map< std::string, VisualPositionRect > submodule_relative_position
Definition: Module.h:359
CustomModuleSingleInput::CustomModuleSingleInput
CustomModuleSingleInput(std::string name, Location, std::vector< std::string > Function, unsigned size=DEFAULT_SIZE, std::string pred="")
Definition: Module.cpp:2047
Module::addSubModule
void addSubModule(Module *m)
Definition: Module.cpp:1124
Module::getName
auto & getName() const
Definition: Module.h:247
OpCode::OUTPUT
@ OUTPUT
BitConfig::setUsedCycles
void setUsedCycles(int uc)
Definition: BitSetting.h:67
DisconnectedSource::value
int value
Definition: Module.h:779
Module::isElastic
bool isElastic
Definition: Module.h:236
SET_DOUBLE_INDENT
const char *const SET_DOUBLE_INDENT
Definition: Module.h:38
Module::Module
Module(std::string name, Location, unsigned size=DEFAULT_SIZE, bool isElastic=false)
Definition: Module.cpp:130
Module::ports
std::map< std::string, Port * > ports
Definition: Module.h:225
OpCode::OUTPUT_PRED
@ OUTPUT_PRED
Module::makeCoreIRInterfaceGenerator
CoreIR::TypeGenFun makeCoreIRInterfaceGenerator()
Definition: Module.cpp:294
Module::ResolveVerilogParameters
virtual std::vector< ResolvedVeroligModuleParameter > ResolveVerilogParameters() const
Definition: Module.cpp:954
Module::createMRRG
virtual MRRG * createMRRG(unsigned contexts)
Definition: Module.cpp:1520
TriState::~TriState
virtual ~TriState()
Definition: Module.cpp:1867
Module::loc
Location loc
Definition: Module.h:239
moduleRequiresConfigPorts
bool moduleRequiresConfigPorts(const Module &m)
Definition: ModuleProcedures.cpp:17
CustomModuleSingleInput::~CustomModuleSingleInput
virtual ~CustomModuleSingleInput()
Definition: Module.cpp:2109
TriState::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: Module.cpp:1738
MRRG::initiationInterval
int initiationInterval() const
Definition: MRRG.h:346
ConfigCell::GenericName
virtual std::string GenericName() override
Definition: Module.cpp:2267
Module::GenModuleVerilog
virtual void GenModuleVerilog()
Definition: Module.cpp:268
PORT_BIDIR
@ PORT_BIDIR
Definition: Module.h:66
CustomModuleSingleInput::Function
std::vector< std::string > Function
Definition: Module.h:811
CustomModule::~CustomModule
virtual ~CustomModule()
Definition: Module.cpp:2042
CustomModule::GenFunctionality
virtual void GenFunctionality() override
Definition: Module.cpp:1993
MRRGNode::make_routing
static MRRGNode make_routing(Module *parent, int bitwidth, int cycle, STR &&name, int latency=0, int max_cap=1)
Definition: MRRG.h:151
port_type
port_type
Definition: Module.h:61
ConfigCell::contexts
std::vector< unsigned > contexts
Definition: Module.h:844
TriState::Mode::PROVIDES_IO_PRED_OP
@ PROVIDES_IO_PRED_OP
Port::parameter
std::string parameter
Definition: Module.h:93
TriState
Definition: Module.h:730
Module::GenParameters
void GenParameters()
Definition: Module.cpp:675
ContextCounter::GenericName
virtual std::string GenericName() override
Definition: Module.cpp:2331
ContextCell::l_contexts
int l_contexts
Definition: Module.h:875
Module::connectPorts
void connectPorts(std::string src, std::string dst, bool isElastic)
Definition: Module.cpp:1232
DisconnectedSource::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: Module.cpp:1927
Module::getNodePosition
std::pair< bool, std::pair< double, double > > getNodePosition(const std::string &nodeName)
Definition: Module.cpp:1678
Port::parent
Module * parent
Definition: Module.h:95
Module::VisualPositionRect
Definition: Module.h:344
DisconnectedSource::DisconnectedSource
DisconnectedSource(std::string name, Location, unsigned size, int value=0)
Definition: Module.cpp:1913
PORT_UNSPECIFIED
@ PORT_UNSPECIFIED
Definition: Module.h:68
Port::makeVerilogDeclaration
std::string makeVerilogDeclaration() const
Definition: Module.cpp:107
Port::size
unsigned size
Definition: Module.h:94
CustomModuleSingleInput::GenericName
virtual std::string GenericName() override
Definition: Module.cpp:2104
ConfigCell::l_contexts
int l_contexts
Definition: Module.h:840
Module::GenerateMatrix
void GenerateMatrix(StringMatrix &Matrix)
Definition: Module.cpp:742
OpGraph
Definition: OpGraph.h:215
Module::GenFunctionality
virtual void GenFunctionality()
Definition: Module.cpp:736
TriState::Mode
Mode
Definition: Module.h:732
DEFAULT_SIZE
const int DEFAULT_SIZE
Definition: Module.h:48
ConfigCell::getStorageSize
int getStorageSize() const
Definition: Module.h:832
operator>>
std::istream & operator>>(std::istream &is, port_type &type)
Definition: Module.cpp:2381
cgrame_error
Definition: Exception.h:20
Module::print_connections
void print_connections()
Definition: Module.cpp:1034
PORT_OUTPUT
@ PORT_OUTPUT
Definition: Module.h:64
SET_QUAD_INDENT
const char *const SET_QUAD_INDENT
Definition: Module.h:40
bitsettings_from_int
std::vector< BitSetting > bitsettings_from_int(const INTEGRAL &value, int num_bits)
Definition: BitSetting.h:52