CGRA-ME
ModuleElastic.cpp
Go to the documentation of this file.
1 #include <CGRA/Module.h>
2 #include <CGRA/ModuleElastic.h>
3 #include <CGRA/ModuleFPUnit.h>
4 #include <regex>
5 
6 /* Elastic Buffer (FIFO Implementation) */
7 ElasticBufferFifo::ElasticBufferFifo(std::string name, Location loc, int depth_, int size, bool hasEnable_, bool isElastic)
8  : Module(name, loc, size, isElastic), eb_depth(depth_), hasEnable(hasEnable_)
9 {
11  if (isElastic == false) {make_and_throw<cgrame_error>([&](auto&& s) {
12  s << "Elastic buffer needs to be marked as elastic ";
13  });}
14 
15  // Create ports
16  addPort("data_in", PORT_INPUT, "size", size, isElastic);
17  addPort("data_out", PORT_OUTPUT, "size", size, isElastic);
18  if (hasEnable_) {
19  addPort("enable", PORT_CONFIG, 1, isElastic);
20  }
21 
22  // Visualization
23  node_relative_position.insert({"data_in", {0, 0}});
24  node_relative_position.insert({"data_out", {0, 0.5}});
25 }
26 
27 // Virtual function that overrides Module::GenericName. Returns generic name for the object.
29 {
30  std::string enable = hasEnable ? "enable_" : "";
31  return "elastic_buffer_" + enable + std::to_string(getSize()) + "b";
32 }
33 
34 // Virtual function that overrides Module::CoreIRGetFunctionality. Generates the functionality for this module.
36 {
37  nlohmann::json vjson;
38 
39  // Create Header
40  vjson["prefix"] = "cgrame_";
41  vjson["parameters"] = {};
42  for (auto& parameter : parameterlist)
43  {
44  vjson["parameters"].push_back(parameter.first);
45  }
46  vjson["interface"] = {};
47  vjson["interface"].push_back("CGRA_Clock");
48  vjson["interface"].push_back("CGRA_Reset");
49  vjson["interface"].push_back("CGRA_Enable");
50 
51  for (auto& port : ports)
52  {
53  std::string portName = port.second->getName();
54  vjson["interface"].push_back(portName);
55  }
56 
57  // module definition
58  std::string moduleDefinition;
59  moduleDefinition += std::string(SET_INDENT) + "parameter DATA_WIDTH = " + std::to_string(getSize()) + ";\n";
60  moduleDefinition += std::string(SET_INDENT) + "parameter DEPTH = " + std::to_string(getDepth()) + ";\n";
61  moduleDefinition += std::string(SET_INDENT) + "parameter ADDRESS_WIDTH = $clog2(DEPTH);\n";
62  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
63  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
64  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
65  for (auto& port : ports)
66  {
67  port_type portType = port.second->pt;
68  std::string portTypeString = {};
69  if(portType == port_type::PORT_INPUT)
70  {
71  portTypeString = "input";
72  }
73  else if (portType == port_type::PORT_OUTPUT)
74  {
75  portTypeString = "output";
76  }
77  else if (portType == port_type::PORT_OUTPUT_REG)
78  {
79  portTypeString = "output reg";
80  }
81  else
82  {
83  portTypeString = "inout";
84  }
85  std::string portSizeString;
86  if (!(port.second->parameter).empty()) // Check if size is parameterized
87  {
88  std::string portParameterName = port.second->parameter;
89  portSizeString = "[" + portParameterName + "-1:0]";
90  }
91  else
92  {
93  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
94  }
95  std::string portName = port.second->getName();
96  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
97  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
98  }
99  moduleDefinition += std::string(SET_INDENT) + "wire eb_enable;\n";
100  if (hasEnable) {
101  moduleDefinition += std::string(SET_INDENT) + "assign eb_enable = enable;\n";
102  moduleDefinition += std::string(SET_INDENT) + "assign enable_valid_upstream = data_in_valid_upstream;\n";
103  moduleDefinition += std::string(SET_INDENT) + "assign enable_stop_upstream = data_in_stop_upstream;\n";
104  } else {
105  moduleDefinition += std::string(SET_INDENT) + "assign eb_enable = 'b1;\n";
106  }
107  moduleDefinition += std::string(SET_INDENT) + "wire fifo_full, fifo_almost_full, fifo_empty, fifo_almost_empty;\n";
108  moduleDefinition += std::string(SET_INDENT) + "wire [DATA_WIDTH-1:0] fifo_read_data;\n";
109  moduleDefinition += std::string(SET_INDENT) + "wire [ADDRESS_WIDTH:0] fifo_word_count;\n";
110  moduleDefinition += std::string(SET_INDENT) + "wire fifo_write_en, fifo_read_en;\n";
111  moduleDefinition += std::string(SET_INDENT) + "assign fifo_write_en = (data_in_valid_upstream & eb_enable) & ~fifo_full;\n";
112  moduleDefinition += std::string(SET_INDENT) + "assign fifo_read_en = ~fifo_empty & ~data_out_stop_downstream;\n";
113  moduleDefinition += std::string(SET_INDENT) + "assign data_in_stop_upstream = fifo_full;\n";
114  moduleDefinition += std::string(SET_INDENT) + "assign data_out_valid_downstream = ~fifo_empty;\n";
115  moduleDefinition += std::string(SET_INDENT) + "assign data_out = fifo_read_data & {DATA_WIDTH{~fifo_empty}};\n";
116  moduleDefinition += std::string(SET_INDENT) + "// Instantiate FIFO\n";
117  moduleDefinition += std::string(SET_INDENT) + "fwft_fifo FIFO\n";
118  moduleDefinition += std::string(SET_INDENT) + "(\n";
119  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".reset ( CGRA_Reset ),\n";
120  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".clk ( CGRA_Clock ),\n";
121  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".full ( fifo_full ),\n";
122  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".write_en ( fifo_write_en ),\n";
123  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".write_data ( data_in ),\n";
124  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".empty ( fifo_empty ),\n";
125  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".read_en ( fifo_read_en ),\n";
126  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".read_data ( fifo_read_data ),\n";
127  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".usedw ( fifo_word_count )\n";
128  moduleDefinition += std::string(SET_INDENT) + ");\n";
129  moduleDefinition += std::string(SET_INDENT) + "defparam FIFO.width = DATA_WIDTH;\n";
130  moduleDefinition += std::string(SET_INDENT) + "defparam FIFO.widthad = ADDRESS_WIDTH;\n";
131  moduleDefinition += std::string(SET_INDENT) + "defparam FIFO.depth = DEPTH;\n";
132  vjson["definition"] = moduleDefinition;
133  return vjson;
134 }
135 
137  const MRRG& mrrg, const OpGraph & og,
138  const Mapping& map,
139  const ConfigCell& ccell,
140  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
141  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
142 ) const {
143  (void)ccell;
144  (void)mrrg_nodes_from_op_node;
145  BitConfig bitConfig(mrrg.initiationInterval());
146  // Use the m_in node to check if this register is being used
147  const std::regex in_regex("\\.data_in$");
148 
149  // Organize nodes mapping by cycle
150  std::vector<MRRGNodesFromValNode> valNodesByCycle(mrrg.initiationInterval());
151  for (const auto& val_and_mrrg_nodes : mrrg_nodes_from_val_node) {
152  for (const auto& mrrg_node : val_and_mrrg_nodes.second) {
153  valNodesByCycle[mrrg_node->cycle][val_and_mrrg_nodes.first].insert(mrrg_node);
154  }
155  }
156 
157  int cycle = 0;
158  int used_cycles = 0;
159  for (auto & mrrg_nodes_from_val_by_cycle : valNodesByCycle) {
160  if (mrrg_nodes_from_val_by_cycle.empty()) {
161  bitConfig.add({BitSetting::LOW}, cycle);
162  } else {
163  bool enableBuffer = false;
164  for (auto & op_val_and_nodes: mrrg_nodes_from_val_by_cycle) {
165  for (auto & mrrg_node : op_val_and_nodes.second) {
166  auto name = mrrg_node->getHierarchyQualifiedName();
167  if (regex_search(name, in_regex)) {
168  // Considering doing an error check here to see if "m_in" shows up twice
169  enableBuffer = true;
170  break;
171  }
172  }
173  }
174 
175  if (!enableBuffer) {
176  bitConfig.add({(size_t) 1, BitSetting::LOW}, cycle);
177  } else {
178  used_cycles++;
179  bitConfig.add({(size_t) 1, BitSetting::HIGH}, cycle);
180  }
181  }
182  ++cycle;
183  }
184  bitConfig.setUsedCycles(used_cycles);
185  return bitConfig;
186 }
187 
188 
189 
191 { // Empty destructor
192 }
193 
195 {
196  MRRG* result_ptr = new MRRG(II);
197  auto& result = *result_ptr;
198 
199  for (unsigned i = 0; i < II; i++)
200  {
201  // Create nodes, model an EB as a zero delay wire
202  MRRG::NodeDescriptor data_in = result.insert(MRRGNode::make_routing(this, data_size, i, "data_in", 0)).first;
203  MRRG::NodeDescriptor buff = result.insert(MRRGNode::make_routing(this, data_size, i, "buffer", 0)).first;
204  MRRG::NodeDescriptor data_out = result.insert(MRRGNode::make_routing(this, data_size, i, "data_out", 0)).first;
205 
206  // Connect nodes
207  result.link(data_in, buff);
208  result.link(buff, data_out);
209  }
210  return result_ptr;
211 }
212 
213 /* Elastic Eager Fork With Branch*/
214 const std::map<OpGraphOpCode, LLVMMode> ElasticForkBranch::all_modes =
215  {
216  {OpCode::SELECT, {"op_br", "branch", {"br"}, "br_br"}}
217  };
218 ElasticForkBranch::ElasticForkBranch(std::string name, Location loc, int size, int fanout_, bool isElastic)
219  : Module(name, loc, size, isElastic), fanout(fanout_)
220 {
221  if (isElastic == false) {make_and_throw<cgrame_error>([&](auto&& s) {
222  s << "Elastic eager fork needs to be marked as elastic ";
223  });}
225  isElastic = true;
226  // Check module legality
227  if (fanout <= 1) {make_and_throw<cgrame_error>([&](auto&& s) {
228  s << "Elastic fork doesn't support fanout of <=1. Requested fanout was " << fanout;
229  });}
230 
231  // Create ports
232  addPort("in", PORT_INPUT, "size", size, isElastic);
233  addPort("condition", PORT_INPUT, 1, isElastic);
234 
235  for (int i = 0; i < fanout; i++) {
236  addPort("out" + std::to_string(i), PORT_OUTPUT, "size", size, isElastic);
237  }
238 
239  addPort("enable_downstream", PORT_CONFIG, fanout * 2 + 1, isElastic);
240  addParameter("FANOUT", fanout);
241 }
242 
244 {
245  return "elastic_fork_branch_fanout" + std::to_string(fanout) + "_size_" + std::to_string(data_size);
246 }
247 
249 {
250  nlohmann::json vjson;
251 
252  // Create Header
253  vjson["prefix"] = "cgrame_";
254  vjson["parameters"] = {};
255  for (auto& parameter : parameterlist)
256  {
257  vjson["parameters"].push_back(parameter.first);
258  }
259  vjson["interface"] = {};
260  vjson["interface"].push_back("CGRA_Clock");
261  vjson["interface"].push_back("CGRA_Reset");
262  vjson["interface"].push_back("CGRA_Enable");
263 
264  for (auto& port : ports)
265  {
266  std::string portName = port.second->getName();
267  vjson["interface"].push_back(portName);
268  }
269 
270  // module definition
271  std::string moduleDefinition;
272  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
273  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
274  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
275  for (auto& port : ports)
276  {
277  port_type portType = port.second->pt;
278  std::string portTypeString = {};
279  if(portType == port_type::PORT_INPUT)
280  {
281  portTypeString = "input";
282  }
283  else if (portType == port_type::PORT_OUTPUT)
284  {
285  portTypeString = "output";
286  }
287  else if (portType == port_type::PORT_OUTPUT_REG)
288  {
289  portTypeString = "output reg";
290  }
291  else
292  {
293  portTypeString = "inout";
294  }
295  std::string portSizeString;
296  if (!(port.second->parameter).empty()) // Check if size is parameterized
297  {
298  std::string portParameterName = port.second->parameter;
299  portSizeString = "[" + portParameterName + "-1:0]";
300  }
301  else
302  {
303  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
304  }
305  std::string portName = port.second->getName();
306  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
307  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
308  }
309 
310  // Functionality
311  // Internal Variables
312  moduleDefinition += std::string(SET_INDENT) + "wire enable_condition;\n";
313  moduleDefinition += std::string(SET_INDENT) + "wire [(FANOUT-1):0] set_t_f;\n";
314  moduleDefinition += std::string(SET_INDENT) + "wire [(FANOUT-1):0] en_downstream;\n";
315  moduleDefinition += std::string(SET_INDENT) + "wire [(FANOUT-1):0] valid_downstream;\n";
316  moduleDefinition += std::string(SET_INDENT) + "wire [(FANOUT-1):0] stop_downstream;\n";
317  moduleDefinition += std::string(SET_INDENT) + "reg [(FANOUT-1):0] state_regs;\n";
318  moduleDefinition += std::string(SET_INDENT) + "wire [(FANOUT-1):0] masked_state_regs;\n";
319  moduleDefinition += std::string(SET_INDENT) + "wire [(FANOUT-1):0] internal_stops;\n";
320  moduleDefinition += std::string(SET_INDENT) + "wire [(FANOUT-1):0] muxed_condition;\n";
321  moduleDefinition += std::string(SET_INDENT) + "wire internal_vas;\n";
322  moduleDefinition += std::string(SET_INDENT) + "wire mask_valid_cond;\n";
323  moduleDefinition += std::string(SET_INDENT) + "wire mask_cond;\n";
324 
325  // Combinational assignments
326  // Set the configuration bits
327  moduleDefinition += std::string(SET_INDENT) + "assign enable_condition = enable_downstream[0];\n";
328  moduleDefinition += std::string(SET_INDENT) + "assign en_downstream = enable_downstream[FANOUT:1];\n";
329  moduleDefinition += std::string(SET_INDENT) + "assign set_t_f = enable_downstream[FANOUT*2:FANOUT+1];\n";
330 
331  // Mask the condition to pass through
332  moduleDefinition += std::string(SET_INDENT) + "assign mask_cond = !enable_condition | condition;\n";
333  moduleDefinition += std::string(SET_INDENT) + "assign mask_valid_cond = !enable_condition | condition_valid_upstream;\n";
334  moduleDefinition += std::string(SET_INDENT) + "assign condition_stop_upstream = enable_condition & |internal_stops | (|({FANOUT{mask_valid_cond}} & masked_state_regs & {FANOUT{!in_valid_upstream}}));\n";
335 
336  // mux condition to set the true false condition depending if it is enabled or not
337  moduleDefinition += std::string(SET_INDENT) + "assign muxed_condition = enable_condition ? set_t_f & {FANOUT{mask_cond}} & en_downstream | ~set_t_f & {FANOUT{~mask_cond}} & en_downstream : {FANOUT{1'b1}};\n";
338 
339  // Set up the interantional conditions for the stop and valid
340  moduleDefinition += std::string(SET_INDENT) + "assign internal_stops = (stop_downstream & masked_state_regs);\n";
341  moduleDefinition += std::string(SET_INDENT) + "assign internal_vas = (|internal_stops) & in_valid_upstream;\n";
342  moduleDefinition += std::string(SET_INDENT) + "assign masked_state_regs = state_regs & en_downstream & {FANOUT{CGRA_Enable}};\n";
343 
344  // Output assignments
345  moduleDefinition += std::string(SET_INDENT) + "assign in_stop_upstream = |internal_stops | (|({FANOUT{!mask_valid_cond}} & masked_state_regs & {FANOUT{in_valid_upstream}}));\n";
346  moduleDefinition += std::string(SET_INDENT) + "assign valid_downstream = masked_state_regs & {FANOUT{in_valid_upstream}} & muxed_condition & {FANOUT{mask_valid_cond}};\n";
347 
348  // Internal register logic
349  moduleDefinition += std::string(SET_INDENT) + "always @(posedge CGRA_Clock, posedge CGRA_Reset) begin\n";
350  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if (CGRA_Reset) begin\n";
351  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "state_regs <= 'h1;\n";
352  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end else begin\n";
353  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "state_regs <= internal_stops | {FANOUT{~internal_vas}};\n";
354  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
355  moduleDefinition += std::string(SET_INDENT) + "end\n";
356 
357  for (int i = 0; i < fanout; i++)
358  moduleDefinition += std::string(SET_INDENT) + "assign out" + std::to_string(i) + "_valid_downstream = valid_downstream["+std::to_string(i)+"];\n";
359  moduleDefinition += "\n";
360 
361  for (int i = 0; i < fanout; i++)
362  moduleDefinition += std::string(SET_INDENT) + "assign stop_downstream["+std::to_string(i)+"] = out" + std::to_string(i) + "_stop_downstream;\n";
363  moduleDefinition += "\n";
364 
365  for (int i = 0; i < fanout; i++)
366  moduleDefinition += std::string(SET_INDENT) + "assign out" + std::to_string(i) + " = in & {32{CGRA_Enable}};\n";;
367  moduleDefinition += std::string(SET_INDENT) + "assign enable_downstream_valid_upstream = in_valid_upstream;\n";
368  moduleDefinition += std::string(SET_INDENT) + "assign enable_downstream_stop_upstream = in_stop_upstream;\n";
369  vjson["definition"] = moduleDefinition;
370  return vjson;
371 }
372 
374 { // Empty destructor
375 }
376 
378 {
379 
380  MRRG* result_ptr = new MRRG(II);
381  auto& result = *result_ptr;
382 
383  for (unsigned i = 0; i < II; i++)
384  {
385  // Create nodes and link them, we make this module look like a demux to the mapper
386  MRRG::NodeDescriptor in = result.insert(MRRGNode::make_routing(this, data_size, i, "in", 0)).first;
387  MRRG::NodeDescriptor cond = result.insert(MRRGNode::make_operand_pin(this, 1, i, "condition", {Operands::PREDICATE})).first;
389  MRRG::NodeDescriptor fork_out = result.insert(MRRGNode::make_routing(this, data_size, i, "fork_out", 0, true)).first;
390  result.link(cond, fork);
391  result.link(in, fork);
392  result.link(fork, fork_out);
393  for (int j = 0; j < fanout; j++) {
394  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "out" + std::to_string(j), 0)).first;
395  result.link(fork_out, out);
396  }
397  }
398 
399  return result_ptr;
400 }
401 
403  const MRRG& mrrg, const OpGraph & og,
404  const Mapping& map,
405  const ConfigCell& ccell,
406  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
407  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
408 ) const {
409  (void)ccell;
410  (void)mrrg_nodes_from_op_node;
411  const std::vector<std::regex> required_node_regexes {
412  std::regex("\\.fork$"), std::regex("\\.in$"),
413  };
414  const std::regex out_regex("\\.out([0-9]+)$");
415  BitConfig bitConfig(mrrg.initiationInterval());
416 
417  const std::vector<std::regex> required_op_node_regexes {
418  std::regex("\\.fork$"),
419  std::regex("\\.in$"),
420  std::regex("\\.condition$")
421  };
422  // Organize nodes mapping by cycle
423  std::vector<MRRGNodesFromValNode> valNodesByCycle(mrrg.initiationInterval());
424  for (const auto& val_and_mrrg_nodes : mrrg_nodes_from_val_node) {
425  for (const auto& mrrg_node : val_and_mrrg_nodes.second) {
426  valNodesByCycle[mrrg_node->cycle][val_and_mrrg_nodes.first].insert(mrrg_node);
427  }
428  }
429 
430  std::vector<MRRGNodesFromOpNode> opNodesByCycle(mrrg.initiationInterval());
431  for (const auto& op_and_mrrg_nodes : mrrg_nodes_from_op_node) {
432  for (const auto& mrrg_node : op_and_mrrg_nodes.second) {
433  opNodesByCycle[mrrg_node->cycle][op_and_mrrg_nodes.first].insert(mrrg_node);
434  }
435  }
436 
437  int cycle = 0;
438  int used_cycles = 0;
439  bool opNode = false;
440  int false_index = -1;
441  int true_index = -1;
442 
443  for (int i = 0; i < valNodesByCycle.size(); i++) {
444  std::unordered_set<int> inputs_used;
445  if (!opNodesByCycle[i].empty()) {
446  auto mrrg_nodes_from_op_per_cycle = opNodesByCycle[i];
447 
448  int required_node_types_found = 0;
449  std::vector<OpGraphOp*> brNodes;
450  opNode = true;
451  for (const auto& op_node_and_mrrg_nodes : mrrg_nodes_from_op_per_cycle) {
452  for (const auto& req_node_regex : required_op_node_regexes) {
453  for (const auto& mrrg_node : op_node_and_mrrg_nodes.second) {
454  std::smatch match_results;
455  if (std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, req_node_regex)) {
456  if (required_node_types_found > 2) {
457  throw cgrame_error("found a node that matched two required node regexes");
458  } else {
459  required_node_types_found++;
460  brNodes.push_back(op_node_and_mrrg_nodes.first);
461  }
462  }
463  }
464  }
465  }
466  auto mrrg_nodes_from_val_per_cycle = valNodesByCycle[i];
467  for (const auto& val_node_and_mrrg_nodes : mrrg_nodes_from_val_per_cycle) { //added
468  if (required_node_types_found > 0) {
469  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
470  std::smatch match_results;
471  std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, out_regex);
472  if (match_results.size() == 2) {
473  std::vector<MRRG::NodeDescriptor> vals_mapped = map.getMappingList(val_node_and_mrrg_nodes.first);
474  std::queue<const MRRGNode*> to_visit;
475  MRRG::NodeDescriptor last_node = mrrg_node;
476  to_visit.push(mrrg_node);
477  while (!to_visit.empty()) {
478  auto curr = to_visit.front();
479  to_visit.pop();
480  for (auto node : mrrg.fanout(curr)) {
481  if (std::find(vals_mapped.begin(), vals_mapped.end(), node) != vals_mapped.end()) {
482  auto it = std::find(vals_mapped.begin(), vals_mapped.end(), node);
483  last_node = *it;
484  to_visit.push(*it);
485  }
486  }
487  }
488  auto f_node = mrrg.fanout(last_node)[0];
489  if (f_node->type != MRRGNode_Type::MRRG_NODE_FUNCTION && f_node->type != MRRGNode_Type::MRRG_NODE_ROUTING_FUNCTION) {
490  throw cgrame_error("Cannot find the connection for the val ");
491  }
492  int size_vector = og.opNodes().size();
493  OpGraph::OpDescriptor op = nullptr;
494  // loop through all op nodes to find same MRRG node as 'this'
495  // may be very slow
496  for (int i = 0; i < size_vector; i++) {
497  const auto current_node = map.getSingleMapping(og.opNodes()[i]);
498  if (current_node == f_node) {
499  op = og.opNodes()[i];
500  break;
501  }
502  }
503  if (op == nullptr) throw cgrame_error("Cannot find the op ");
504  //const OpGraphOp* output = map.getSingleMapping(f_node);
505  // Need to find the condition of the input used
506  if( val_node_and_mrrg_nodes.first->getPredicateForOutput(op) == false){
507  false_index = stoi(match_results[1].str());
508  } else if ( val_node_and_mrrg_nodes.first->getPredicateForOutput(op) == true){
509  true_index = stoi(match_results[1].str());
510  } else{
511  throw cgrame_error("Error: Must specify must specify branch " + val_node_and_mrrg_nodes.first->getName() + " predicate value ");
512  }
513  inputs_used.insert(stoi(match_results[1].str()));
514  } else {
515 
516  }
517  }
518  }
519  }
520  } else {
521  auto mrrg_nodes_from_val_per_cycle = valNodesByCycle[i];
522  for (const auto& val_node_and_mrrg_nodes : mrrg_nodes_from_val_per_cycle) {
523  // Check for required nodes: .demux and .in
524  std::vector<bool> required_node_types_found;
525  for (const auto& req_node_regex : required_node_regexes) {
526  required_node_types_found.push_back(false);
527  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
528  std::smatch match_results;
529  if (std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, req_node_regex)) {
530  if (required_node_types_found.back()) {
531  throw cgrame_error("found a node that matched two required node regexes");
532  } else {
533  required_node_types_found.back() = true;
534  }
535  }
536  }
537  }
538 
539  // Check for which outputs are used in the mapping
540  if (std::all_of(begin(required_node_types_found), end(required_node_types_found), [&](auto&& v) { return v; })) {
541  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
542  std::smatch match_results;
543  std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, out_regex);
544  if (match_results.size() == 2) {
545  inputs_used.insert(stoi(match_results[1].str()));
546  }
547  }
548  } else {
549  // ignore the val
550  }
551  }
552  }
553  if (inputs_used.empty()) {
554  bitConfig.add({(size_t) fanout *2 + 1, BitSetting::LOW}, cycle);
555 
556  } else if (opNode) {
557  if (inputs_used.size() != 2) throw cgrame_error("Branch cannot point to more than 2 outputs");
558  if (true_index == -1 || false_index == -1) throw cgrame_error("ERROR Branch: must specify the true and false predicates of the branch");
559  // Create the bit settings, in a one-hot manner
560  used_cycles++;
561  unsigned bit_settings = 0;
562  bit_settings |= (1U << (unsigned) 0);
563  for (const auto& input_num : inputs_used) {
564  bit_settings |= (1U << (unsigned) input_num + 1);
565  if (true_index == input_num)
566  bit_settings |= (1U << (unsigned) input_num + fanout + 1);
567  }
568  bitConfig.add(bitsettings_from_int((int) bit_settings, fanout * 2 + 1), cycle);
569 
570  } else {
571  // Create the bit settings, in a one-hot manner
572  used_cycles++;
573  unsigned bit_settings = 0;
574  for (const auto& input_num : inputs_used) {
575  bit_settings |= (1U << (unsigned) input_num + 1);
576  }
577  bitConfig.add(bitsettings_from_int((int) bit_settings, fanout * 2 + 1), cycle);
578  }
579  ++cycle;
580  }
581  bitConfig.setUsedCycles(used_cycles);
582  return bitConfig;
583 }
584 
585 /* Elastic Eager Fork */
586 ElasticEagerFork::ElasticEagerFork(std::string name, Location loc, int size, int fanout_, int unit_fork_fanout_, bool isElastic)
587  : Module(name, loc, size, isElastic), fanout(fanout_), unit_fork_fanout(unit_fork_fanout_)
588 {
589  if (isElastic == false) {make_and_throw<cgrame_error>([&](auto&& s) {
590  s << "Elastic eager fork needs to be marked as elastic ";
591  });}
593  isElastic = true;
594  // Check module legality
595  if (fanout <= 1) {make_and_throw<cgrame_error>([&](auto&& s) {
596  s << "Elastic fork doesn't support fanout of <=1. Requested fanout was " << fanout;
597  });}
598  if (unit_fork_fanout <= 1) {make_and_throw<cgrame_error>([&](auto&& s) {
599  s << "Elastic fork doesn't support unit fanout of <=1. Requested unit fanout was " << unit_fork_fanout;
600  });}
601 
602  // Create ports
603  addPort("in", PORT_INPUT, "size", size, isElastic);
604 
605  for (int i = 0; i < fanout; i++) {
606  addPort("out" + std::to_string(i), PORT_OUTPUT, "size", size, isElastic);
607  }
608 
609  addPort("enable_downstream", PORT_CONFIG, fanout, isElastic);
610 }
611 
613 {
614  return "elastic_eager_fork_1to" + std::to_string(fanout) + "_size_" + std::to_string(data_size);
615 }
616 
618 {
619  nlohmann::json vjson;
620 
621  // Create Header
622  vjson["prefix"] = "cgrame_";
623  vjson["parameters"] = {};
624  for (auto& parameter : parameterlist)
625  {
626  vjson["parameters"].push_back(parameter.first);
627  }
628  vjson["interface"] = {};
629  vjson["interface"].push_back("CGRA_Clock");
630  vjson["interface"].push_back("CGRA_Reset");
631  vjson["interface"].push_back("CGRA_Enable");
632 
633  for (auto& port : ports)
634  {
635  std::string portName = port.second->getName();
636  vjson["interface"].push_back(portName);
637  }
638 
639  // module definition
640  std::string moduleDefinition;
641  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
642  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
643  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
644  for (auto& port : ports)
645  {
646  port_type portType = port.second->pt;
647  std::string portTypeString = {};
648  if(portType == port_type::PORT_INPUT)
649  {
650  portTypeString = "input";
651  }
652  else if (portType == port_type::PORT_OUTPUT)
653  {
654  portTypeString = "output";
655  }
656  else if (portType == port_type::PORT_OUTPUT_REG)
657  {
658  portTypeString = "output reg";
659  }
660  else
661  {
662  portTypeString = "inout";
663  }
664  std::string portSizeString;
665  if (!(port.second->parameter).empty()) // Check if size is parameterized
666  {
667  std::string portParameterName = port.second->parameter;
668  portSizeString = "[" + portParameterName + "-1:0]";
669  }
670  else
671  {
672  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
673  }
674  std::string portName = port.second->getName();
675  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
676  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
677  }
678 
679  // Functionality
680  int fork_layers = std::ceil(std::log(fanout) / std::log(unit_fork_fanout));
681  moduleDefinition += std::string(SET_INDENT) + "wire stop_upstream;";
682  moduleDefinition += std::string(SET_INDENT) + "elastic_eager_fork #(";
683  moduleDefinition += ".FANOUT(" + std::to_string(fanout) + "), ";
684  moduleDefinition += ".FORK_LAYERS(" + std::to_string(fork_layers) + "), ";
685  moduleDefinition += ".UNIT_FORK_FANOUT(" + std::to_string(unit_fork_fanout) + ")) efork (\n";
686  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".clk(CGRA_Clock),\n";
687  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".reset(CGRA_Reset),\n";
688  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".valid_upstream(in_valid_upstream),\n";
689  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".stop_upstream(stop_upstream),\n";
690 
691  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".valid_downstream({";
692  for (int i = fanout-1; i > 0; i--)
693  moduleDefinition += "out" + std::to_string(i) + "_valid_downstream, ";
694  moduleDefinition += "out0_valid_downstream}),\n";
695 
696  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".stop_downstream({";
697  for (int i = fanout-1; i > 0; i--)
698  moduleDefinition += "out" + std::to_string(i) + "_stop_downstream, ";
699  moduleDefinition += "out0_stop_downstream}),\n";
700 
701 
702  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".enable_downstream(enable_downstream)\n";
703  moduleDefinition += std::string(SET_INDENT) + ");\n";
704 
705  moduleDefinition += "\n";
706  for (int i = 0; i < fanout; i++)
707  moduleDefinition += std::string(SET_INDENT) + "assign out" + std::to_string(i) + " = in & {32{CGRA_Enable}};\n";
708  moduleDefinition += std::string(SET_INDENT) + "assign in_stop_upstream = stop_upstream;\n";
709  moduleDefinition += std::string(SET_INDENT) + "assign enable_downstream_valid_upstream = in_valid_upstream;\n";
710  moduleDefinition += std::string(SET_INDENT) + "assign enable_downstream_stop_upstream = in_stop_upstream;\n";
711  vjson["definition"] = moduleDefinition;
712  return vjson;
713 }
714 
716 { // Empty destructor
717 }
718 
720 {
721 
722  MRRG* result_ptr = new MRRG(II);
723  auto& result = *result_ptr;
724 
725  for (unsigned i = 0; i < II; i++)
726  {
727  // Create nodes and link them, we make this module look like a demux to the mapper
728  MRRG::NodeDescriptor in = result.insert(MRRGNode::make_routing(this, data_size, i, "in", 0)).first;
729  MRRG::NodeDescriptor fork = result.insert(MRRGNode::make_routing(this, data_size, i, "fork", 0, true)).first;
730  result.link(in, fork);
731  for (int j = 0; j < fanout; j++) {
732  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "out" + std::to_string(j), 0)).first;
733  result.link(fork, out);
734  }
735  }
736 
737  return result_ptr;
738 }
739 
741  const MRRG& mrrg, const OpGraph & og,
742  const Mapping& map,
743  const ConfigCell& ccell,
744  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
745  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
746 ) const {
747  (void)ccell;
748  (void)mrrg_nodes_from_op_node;
749  const std::vector<std::regex> required_node_regexes {
750  std::regex("\\.fork$"), std::regex("\\.in$"),
751  };
752  const std::regex in_regex("\\.out([0-9]+)$");
753  BitConfig bitConfig(mrrg.initiationInterval());
754 
755  // Organize nodes mapping by cycle
756  std::vector<MRRGNodesFromValNode> valNodesByCycle(mrrg.initiationInterval());
757  for (const auto& val_and_mrrg_nodes : mrrg_nodes_from_val_node) {
758  for (const auto& mrrg_node : val_and_mrrg_nodes.second) {
759  valNodesByCycle[mrrg_node->cycle][val_and_mrrg_nodes.first].insert(mrrg_node);
760  }
761  }
762 
763  int cycle = 0;
764  int used_cycles = 0;
765  for (auto & mrrg_nodes_from_val_per_cycle : valNodesByCycle) {
766  std::unordered_set<int> inputs_used;
767 
768  for (const auto& val_node_and_mrrg_nodes : mrrg_nodes_from_val_per_cycle) {
769  // Check for required nodes: .demux and .in
770  std::vector<bool> required_node_types_found;
771  for (const auto& req_node_regex : required_node_regexes) {
772  required_node_types_found.push_back(false);
773  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
774  std::smatch match_results;
775  if (std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, req_node_regex)) {
776  if (required_node_types_found.back()) {
777  throw cgrame_error("found a node that matched two required node regexes");
778  } else {
779  required_node_types_found.back() = true;
780  }
781  }
782  }
783  }
784 
785  // Check for which outputs are used in the mapping
786  if (std::all_of(begin(required_node_types_found), end(required_node_types_found), [&](auto&& v) { return v; })) {
787  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
788  std::smatch match_results;
789  std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, in_regex);
790  if (match_results.size() == 2) {
791  inputs_used.insert(stoi(match_results[1].str()));
792  }
793  }
794  } else {
795  // ignore the val
796  }
797  }
798 
799  if (inputs_used.empty()) {
800  bitConfig.add({(size_t) fanout, BitSetting::LOW}, cycle);
801 
802  } else {
803  // Create the bit settings, in a one-hot manner
804  used_cycles++;
805  unsigned bit_settings = 0;
806  for (const auto& input_num : inputs_used) {
807  bit_settings |= (1U << (unsigned) input_num);
808  }
809  bitConfig.add(bitsettings_from_int((int) bit_settings, fanout), cycle);
810  }
811  ++cycle;
812  }
813  bitConfig.setUsedCycles(used_cycles);
814  return bitConfig;
815 }
816 
817 /* Elastic Join */
818 ElasticJoin::ElasticJoin(std::string name, Location loc, int size, int fanin_, bool isElastic)
819  : Module(name, loc, size, isElastic), fanin(fanin_)
820 {
822  if (isElastic == false) {make_and_throw<cgrame_error>([&](auto&& s) {
823  s << "Elastic eager fork needs to be marked as elastic ";
824  });}
825  // Check module legality
826  if (fanin <= 1) {make_and_throw<cgrame_error>([&](auto&& s) {
827  s << "Elastic join doesn't support fanin of <=1. Requested fanin was " << fanin;
828  });}
829 
830  // Create ports
831  for (int i = 0; i < fanin; i++) {
832  addPort("in" + std::to_string(i), PORT_INPUT, "size", size, isElastic);
833  node_relative_position.insert({"in" + std::to_string(i), {static_cast<double>(i)/fanin, 0.25}});
834 
835  addPort("out" + std::to_string(i), PORT_OUTPUT, "size", size);
836  node_relative_position.insert({"out", {static_cast<double>(i)/fanin, 0.5}});
837  }
838  addPort("out_stop_downstream", PORT_INPUT, 1);
839  addPort("out_valid_downstream", PORT_OUTPUT, 1);
840  addPort("enable", PORT_CONFIG, fanin, isElastic);
841 }
842 
844 {
845  return "elastic_join_" + std::to_string(fanin) + "to1" + "_size_" + std::to_string(data_size);
846 }
847 
849 {
850  nlohmann::json vjson;
851 
852  // Create Header
853  vjson["prefix"] = "cgrame_";
854  vjson["parameters"] = {};
855  for (auto& parameter : parameterlist)
856  {
857  vjson["parameters"].push_back(parameter.first);
858  }
859  vjson["interface"] = {};
860 
861  for (auto& port : ports)
862  {
863  std::string portName = port.second->getName();
864  vjson["interface"].push_back(portName);
865  }
866 
867  // module definition
868  std::string moduleDefinition;
869  moduleDefinition += "parameter FANIN = " + std::to_string(fanin) + ";\n";
870  for (auto& port : ports)
871  {
872  port_type portType = port.second->pt;
873  std::string portTypeString = {};
874  if(portType == port_type::PORT_INPUT)
875  {
876  portTypeString = "input";
877  }
878  else if (portType == port_type::PORT_OUTPUT)
879  {
880  portTypeString = "output";
881  }
882  else if (portType == port_type::PORT_OUTPUT_REG)
883  {
884  portTypeString = "output reg";
885  }
886  else
887  {
888  portTypeString = "inout";
889  }
890  std::string portSizeString;
891  if (!(port.second->parameter).empty()) // Check if size is parameterized
892  {
893  std::string portParameterName = port.second->parameter;
894  portSizeString = "[" + portParameterName + "-1:0]";
895  }
896  else
897  {
898  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
899  }
900  std::string portName = port.second->getName();
901  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
902  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
903  }
904 
905 
906  moduleDefinition += std::string(SET_INDENT) + "wire [(FANIN-1):0] valid_upstream;\n";
907  moduleDefinition += std::string(SET_INDENT) + "wire [(FANIN-1):0] stop_upstream;\n";
908  moduleDefinition += std::string(SET_INDENT) + "assign valid_upstream = {";
909  for (int i = fanin-1; i > 0; i--)
910  moduleDefinition += "in" + std::to_string(i) + "_valid_upstream, ";
911  moduleDefinition += "in0_valid_upstream};\n";
912 
913  moduleDefinition += std::string(SET_INDENT) + "assign {";
914  for (int i = fanin-1; i > 0; i--)
915  moduleDefinition += "in" + std::to_string(i) + "_stop_upstream, ";
916  moduleDefinition += "in0_stop_upstream} = stop_upstream;\n";
917  // Internal masked upstream valids
918  moduleDefinition += std::string(SET_INDENT) + "wire [(FANIN-1):0] masked_valid_upstream;\n";
919  moduleDefinition += std::string(SET_INDENT) + "assign masked_valid_upstream = valid_upstream | (~enable);\n";
920  moduleDefinition += std::string(SET_INDENT) + "assign out_valid_downstream = &masked_valid_upstream;\n";
921  moduleDefinition += std::string(SET_INDENT) + "assign stop_upstream = {FANIN{out_stop_downstream}} | (masked_valid_upstream & {FANIN{~(out_valid_downstream)}});\n";
922 
923  moduleDefinition += "\n";
924  for (int i = 0; i < fanin; i++)
925  moduleDefinition += std::string(SET_INDENT) + "assign out" + std::to_string(i) + " = in" + std::to_string(i) + ";\n";
926  moduleDefinition += std::string(SET_INDENT) + "assign enable_valid_upstream = out_valid_downstream;\n";
927  moduleDefinition += std::string(SET_INDENT) + "assign enable_stop_upstream = out_stop_downstream;\n";
928 
929  vjson["definition"] = moduleDefinition;
930  return vjson;
931 }
932 
934 { // Empty destructor
935 }
936 
937 MRRG* ElasticJoin::createMRRG(unsigned II = 1)
938 {
939 
940 
941  MRRG* result_ptr = new MRRG(II);
942  auto& result = *result_ptr;
943 
944  for (unsigned i = 0; i < II; i++)
945  {
946  // Create nodes and link them, we make this module look like a demux to the mapper
947  for (int j = 0; j < fanin; j++) {
948  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "out" + std::to_string(j), 0)).first;
949  MRRG::NodeDescriptor in = result.insert(MRRGNode::make_routing(this, data_size, i, "in" + std::to_string(j), 0)).first;
950  result.link(in, out);
951  }
952  MRRG::NodeDescriptor out_result = result.insert(MRRGNode::make_routing(this, data_size, i, "out_result", 0)).first;
953  MRRG::NodeDescriptor in_result = result.insert(MRRGNode::make_routing(this, data_size, i, "in_result", 0)).first;
954  result.link(in_result, out_result);
955  }
956 
957  return result_ptr;
958 }
959 
961  const MRRG& mrrg, const OpGraph & og,
962  const Mapping& map,
963  const ConfigCell& ccell,
964  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
965  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
966 ) const {
967  (void)ccell;
968  (void)mrrg_nodes_from_op_node;
969  const std::vector<std::regex> required_node_regexes {
970  std::regex("\\.out([0-9]+)$"),
971  };
972  const std::regex in_regex("\\.in([0-9]+)$");
973  BitConfig bitConfig(mrrg.initiationInterval());
974 
975  // Organize nodes mapping by cycle
976  std::vector<MRRGNodesFromValNode> valNodesByCycle(mrrg.initiationInterval());
977  for (const auto& val_and_mrrg_nodes : mrrg_nodes_from_val_node) {
978  for (const auto& mrrg_node : val_and_mrrg_nodes.second) {
979  valNodesByCycle[mrrg_node->cycle][val_and_mrrg_nodes.first].insert(mrrg_node);
980  }
981  }
982 
983  int cycle = 0;
984  int used_cycles = 0;
985  for (auto & mrrg_nodes_from_val_per_cycle : valNodesByCycle) {
986  std::unordered_set<int> inputs_used;
987 
988  for (const auto& val_node_and_mrrg_nodes : mrrg_nodes_from_val_per_cycle) {
989  // Check for required nodes
990  std::vector<bool> required_node_types_found;
991  for (const auto& req_node_regex : required_node_regexes) {
992  required_node_types_found.push_back(false);
993  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
994  std::smatch match_results;
995  if (std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, req_node_regex)) {
996  //if (required_node_types_found.back()) {
997  // throw cgrame_error("found a node that matched two required node regexes");
998  //} else {
999  required_node_types_found.back() = true;
1000  //}
1001  }
1002  }
1003  }
1004 
1005  // Check for which inputs are used in the mapping
1006  if (std::all_of(begin(required_node_types_found), end(required_node_types_found), [&](auto&& v) { return v; })) {
1007  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
1008  std::smatch match_results;
1009  std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, in_regex);
1010  if (match_results.size() == 2) {
1011  inputs_used.insert(stoi(match_results[1].str()));
1012  }
1013  }
1014  } else {
1015  // ignore the val
1016  }
1017  }
1018 
1019  if (inputs_used.empty()) {
1020  bitConfig.add({(size_t) fanin, BitSetting::DONT_CARE_PREFER_LOW}, cycle);
1021  } else {
1022  // Create the bit settings, in a one-hot manner
1023  used_cycles++;
1024  unsigned bit_settings = 0;
1025  for (const auto& input_num : inputs_used) {
1026  bit_settings |= (1U << (unsigned) input_num);
1027  }
1028  bitConfig.add(bitsettings_from_int((int) bit_settings, fanin), cycle);
1029  }
1030  ++cycle;
1031  }
1032  bitConfig.setUsedCycles(used_cycles);
1033  return bitConfig;
1034 }
1035 
1036 
1037 /* Elastic Diverge */
1038 ElasticDiverge::ElasticDiverge(std::string name, Location loc, int size, int fanout_)
1039  : Module(name, loc, size), fanout(fanout_)
1040 {
1042  isElastic = true;
1043  // Check module legality
1044  if (fanout <= 1) {make_and_throw<cgrame_error>([&](auto&& s) {
1045  s << "Elastic diverge doesn't support fanout of <=1. Requested fanout was " << fanout;
1046  });}
1047 
1048  // Create ports
1049  // TODO: visualization
1050  addPort("valid_upstream", PORT_INPUT, 1);
1051  addPort("stop_upstream", PORT_OUTPUT, 1);
1052  addPort("data_in", PORT_INPUT, "size", size);
1053  for (int i = 0; i < fanout; i++) {
1054  addPort("valid_downstream" + std::to_string(i), PORT_OUTPUT, 1);
1055  addPort("stop_downstream" + std::to_string(i), PORT_INPUT, 1);
1056  addPort("data_out" + std::to_string(i), PORT_OUTPUT, "size", size);
1057  }
1058  addPort("enable_downstream", PORT_INPUT, fanout);
1059 }
1060 
1062 {
1063  return "elastic_diverge_1to" + std::to_string(fanout) + "_" + std::to_string(getSize()) + "b";
1064 }
1065 
1067 {
1068  nlohmann::json vjson;
1069 
1070  // Create Header
1071  vjson["prefix"] = "cgrame_";
1072  vjson["parameters"] = {};
1073  for (auto& parameter : parameterlist)
1074  {
1075  vjson["parameters"].push_back(parameter.first);
1076  }
1077  vjson["interface"] = {};
1078  vjson["interface"].push_back("CGRA_Clock");
1079  vjson["interface"].push_back("CGRA_Reset");
1080  vjson["interface"].push_back("CGRA_Enable");
1081 
1082  for (auto& port : ports)
1083  {
1084  std::string portName = port.second->getName();
1085  vjson["interface"].push_back(portName);
1086  }
1087 
1088  // module definition
1089  std::string moduleDefinition;
1090  moduleDefinition += std::string(SET_INDENT) + "parameter DATA_WIDTH = " + std::to_string(getSize()) + ";\n";
1091  moduleDefinition += std::string(SET_INDENT) + "parameter FANOUT = " + std::to_string(fanout) + ";\n";
1092  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
1093  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
1094  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
1095  for (auto& port : ports)
1096  {
1097  port_type portType = port.second->pt;
1098  std::string portTypeString = {};
1099  if(portType == port_type::PORT_INPUT)
1100  {
1101  portTypeString = "input";
1102  }
1103  else if (portType == port_type::PORT_OUTPUT)
1104  {
1105  portTypeString = "output";
1106  }
1107  else if (portType == port_type::PORT_OUTPUT_REG)
1108  {
1109  portTypeString = "output reg";
1110  }
1111  else
1112  {
1113  portTypeString = "inout";
1114  }
1115  std::string portSizeString;
1116  if (!(port.second->parameter).empty()) // Check if size is parameterized
1117  {
1118  std::string portParameterName = port.second->parameter;
1119  portSizeString = "[" + portParameterName + "-1:0]";
1120  }
1121  else
1122  {
1123  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
1124  }
1125  std::string portName = port.second->getName();
1126  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
1127  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
1128  }
1129 
1130  moduleDefinition += std::string(SET_INDENT) + "wire [(FANOUT-1):0] valid_downstream;\n";
1131  moduleDefinition += std::string(SET_INDENT) + "wire [(FANOUT-1):0] stop_downstream;\n";
1132  moduleDefinition += std::string(SET_INDENT) + "wire [DATA_WIDTH*FANOUT-1:0] data_out;\n";
1133 
1134  moduleDefinition += std::string(SET_INDENT) + "assign valid_downstream = {";
1135  for (int i = fanout-1; i > 0; i--)
1136  moduleDefinition += "valid_downstream" + std::to_string(i) + ", ";
1137  moduleDefinition += "valid_downstream0};\n";
1138  moduleDefinition += std::string(SET_INDENT) + "assign stop_downstream = {";
1139  for (int i = fanout-1; i > 0; i--)
1140  moduleDefinition += "stop_downstream" + std::to_string(i) + ", ";
1141  moduleDefinition += "stop_downstream0};\n";
1142  moduleDefinition += std::string(SET_INDENT) + "assign {";
1143  for (int i = fanout-1; i > 0; i--)
1144  moduleDefinition += "data_out" + std::to_string(i) + ", ";
1145  moduleDefinition += "data_out0} = data_out;\n";
1146  moduleDefinition += std::string(SET_INDENT) + "wire [FANOUT-1:0] arbiter_request, arbiter_grant;\n";
1147  moduleDefinition += std::string(SET_INDENT) + "assign arbiter_request = ~stop_downstream & enable_downstream;\n";
1148  moduleDefinition += std::string(SET_INDENT) + "// Arbiter module, which we use to select in the case of multiple upstream modules ready\n";
1149  moduleDefinition += std::string(SET_INDENT) + "round_robin_arbiter #(FANOUT) arbiter\n";
1150  moduleDefinition += std::string(SET_INDENT) + " (\n";
1151  moduleDefinition += std::string(SET_INDENT) + " .clk(CGRA_Clock),\n";
1152  moduleDefinition += std::string(SET_INDENT) + " .reset(CGRA_Reset),\n";
1153  moduleDefinition += std::string(SET_INDENT) + " .req_in(arbiter_request),\n";
1154  moduleDefinition += std::string(SET_INDENT) + " .grant_final(arbiter_grant),\n";
1155  moduleDefinition += std::string(SET_INDENT) + " .memory_controller_waitrequest(~valid_upstream) // Upstream valid being low should pause the arbiter\n";
1156  moduleDefinition += std::string(SET_INDENT) + " );\n";
1157  moduleDefinition += std::string(SET_INDENT) + "assign stop_upstream = ~(|arbiter_grant);\n";
1158  moduleDefinition += std::string(SET_INDENT) + "assign valid_downstream = arbiter_grant & {FANOUT{valid_upstream}};\n";
1159  moduleDefinition += std::string(SET_INDENT) + "assign data_out = (valid_downstream) ? {FANOUT{data_in}} : 'bx;\n";
1160  vjson["definition"] = moduleDefinition;
1161  return vjson;
1162 }
1163 
1165 { // Empty destructor
1166 }
1167 
1169 {
1170  // TODO: generate MRRG from module
1171  return new MRRG(II);
1172 }
1173 
1175  const MRRG& mrrg, const OpGraph & og,
1176  const Mapping& map,
1177  const ConfigCell& ccell,
1178  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
1179  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
1180 ) const {
1181  // TODO: generate bitstream for module based on MRRG connectivity
1182  return NULL;
1183 }
1184 
1185 /************ ElasticSelMultiplexer **********/
1186 const std::map<OpGraphOpCode, LLVMMode> ElasticSelMultiplexer::all_modes =
1187  {
1188  {OpCode::SELECT, {"op_sel", "sel", {"sel"}, "sel_sel"}},
1189  {OpCode::PHI, {"op_phi", "phi", {"phi"}, "phi_sel"}}
1190  };
1191 
1192 /************ ElasticSelMultiplexer **********/
1193 ElasticSelMultiplexer::ElasticSelMultiplexer(std::string name, Location loc, unsigned mux_size_, unsigned size, bool isElastic)
1194  : Module(name, loc, size, isElastic)
1195  , mux_size(mux_size_)
1196  {
1197  isElastic = true;
1199  if (mux_size <= 1) { make_and_throw<cgrame_error>([&](auto&& s) {
1200  s << "Multiplexer doesn't support mux_size <= 1. mux_size = " << mux_size;
1201  });}
1202 
1203  // Create ports
1204  for(int i = 0; i < mux_size; i++) {
1205  addPort("in" + std::to_string(i), PORT_INPUT, "size", size, isElastic);
1206  }
1207 
1208  addPort("out", PORT_OUTPUT_REG, "size", size, isElastic);
1209 
1210  // select port to control small mux
1211  addPort("select", PORT_CONFIG, mux_size, isElastic);
1212 }
1213 // Virtual function that overrides Module::GenericName. Returns generic name of the object
1214 std::string ElasticSelMultiplexer::GenericName() // Virtual function override
1215 {
1216  return "elastic_sel_mux_" + std::to_string(mux_size) + "to1_" + std::to_string(getSize()) + "b";
1217 }
1218 
1219 // CoreIR Implementation of GenFunctionality
1220 nlohmann::json ElasticSelMultiplexer::CoreIRGenFunctionality() // Virtual function override
1221 {
1222  nlohmann::json vjson;
1223 
1224  // Create Header
1225  vjson["prefix"] = "cgrame_"; //module prefix
1226  vjson["parameters"] = {};
1227  for (auto& parameter : parameterlist)
1228  {
1229  vjson["parameters"].push_back(parameter.first);
1230  }
1231  vjson["interface"] = {};
1232  vjson["interface"].push_back("CGRA_Clock");
1233  vjson["interface"].push_back("CGRA_Reset");
1234  vjson["interface"].push_back("CGRA_Enable");
1235 
1236  for (auto& port : ports)
1237  {
1238  std::string portName = port.second->getName();
1239  vjson["interface"].push_back(portName);
1240  }
1241 
1242  // module definition
1243  std::string moduleDefinition;
1244  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
1245  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
1246  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
1247  //moduleDefinition += std::string(SET_INDENT) + "input CGRA_PHI_Enable;\n";
1248 
1249  for (auto& port : ports)
1250  {
1251  port_type portType = port.second->pt;
1252  std::string portTypeString = {};
1253  if(portType == port_type::PORT_INPUT)
1254  {
1255  portTypeString = "input";
1256  }
1257  else if (portType == port_type::PORT_OUTPUT)
1258  {
1259  portTypeString = "output";
1260  }
1261  else if (portType == port_type::PORT_OUTPUT_REG)
1262  {
1263  portTypeString = "output reg";
1264  }
1265  else
1266  {
1267  portTypeString = "inout";
1268  }
1269  std::string portSizeString;
1270  //std::string portSizeString1b;
1271 
1272  if (!(port.second->parameter).empty()) // Check if size is parameterized
1273  {
1274  std::string portParameterName = port.second->parameter;
1275  portSizeString = "[" + portParameterName + "-1:0]";
1276  //portSizeString1b = "[" + portParameterName + "0:0]";
1277  }
1278  else
1279  {
1280  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
1281  }
1282  std::string portName = port.second->getName();
1283 
1284  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
1285  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
1286 
1287  //std::string portDeclaration1b = portTypeString + " " + portSizeString1b + " " + portName + ";\n";
1288  //moduleDefinition += std::string(SET_INDENT) + portDeclaration;
1289  }
1290 
1291  // Functionality
1292  moduleDefinition += std::string(SET_INDENT) + "always @(*) begin\n";
1293  for (int i = 0; i < mux_size; ++i)
1294  {
1295  std::string stringI = std::to_string(i);
1296  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if(select[" + stringI + "] && in" + stringI + "_valid_upstream)begin\n";
1297  moduleDefinition += std::string(SET_TRIPLE_INDENT) + " out = in" + stringI + ";\n";
1298  moduleDefinition += std::string(SET_TRIPLE_INDENT) + " out_valid_downstream = in" + stringI + "_valid_upstream;\n";
1299  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end else ";
1300  }
1301  moduleDefinition += "begin\n";
1302  moduleDefinition += std::string(SET_TRIPLE_INDENT) + " out_valid_downstream = 0;\n";
1303  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
1304  moduleDefinition += std::string(SET_INDENT) + "end\n";
1305  for (int j = 0; j < mux_size; ++j){
1306  std::string stringJ = std::to_string(j);
1307  moduleDefinition += std::string(SET_INDENT) + "assign in" + stringJ + "_stop_upstream = out_stop_downstream & select[" + stringJ + "] ;\n";
1308  }
1309  moduleDefinition += std::string(SET_INDENT) + "assign select_stop_upstream = out_stop_downstream;\n";
1310  moduleDefinition += std::string(SET_INDENT) + "assign select_valid_upstream = out_valid_downstream;\n";
1311 
1312 
1313  vjson["definition"] = moduleDefinition;
1314  return vjson;
1315 }
1316 
1318 {
1319 }
1320 
1322 {
1323  MRRG* result_ptr = new MRRG(II);
1324  auto& result = *result_ptr;
1325 
1326  for(unsigned i = 0; i < II; i++)
1327  {
1328  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "out")).first;
1330  result.link(mux, out);
1331  for(int j = 0; j < mux_size; j++)
1332  {
1333  MRRG::NodeDescriptor in = result.insert(MRRGNode::make_routing(this, data_size, i, "in" + std::to_string(j))).first;
1334 
1335  result.link(in, mux);
1336  }
1337  }
1338  return result_ptr;
1339 }
1340 
1342  const MRRG& mrrg, const OpGraph & og,
1343  const Mapping& map,
1344  const ConfigCell& ccell,
1345  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
1346  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
1347 ) const {
1348  (void)ccell;
1349  (void)mrrg_nodes_from_op_node;
1350  const std::vector<std::regex> required_node_regexes {
1351  std::regex("\\.out$"),
1352  };
1353  const std::regex in_regex("\\.in([0-9]+)$");
1354 
1355  const std::vector<std::regex> required_op_node_regexes {
1356  std::regex("\\.out$"),
1357  std::regex("\\.sel_inst"),
1358  };
1359  BitConfig bitConfig(mrrg.initiationInterval());
1360 
1361  // Organize value and op nodes mapping by cycle
1362  std::vector<MRRGNodesFromValNode> valNodesByCycle(mrrg.initiationInterval());
1363  for (const auto& val_and_mrrg_nodes : mrrg_nodes_from_val_node) {
1364  for (const auto& mrrg_node : val_and_mrrg_nodes.second) {
1365  valNodesByCycle[mrrg_node->cycle][val_and_mrrg_nodes.first].insert(mrrg_node);
1366  }
1367  }
1368 
1369  std::vector<MRRGNodesFromOpNode> opNodesByCycle(mrrg.initiationInterval());
1370  for (const auto& op_and_mrrg_nodes : mrrg_nodes_from_op_node) {
1371  for (const auto& mrrg_node : op_and_mrrg_nodes.second) {
1372  opNodesByCycle[mrrg_node->cycle][op_and_mrrg_nodes.first].insert(mrrg_node);
1373  }
1374  }
1375 
1376  int cycle = 0;
1377  int used_cycles = 0;
1378  bool op = false;
1379  for (int i = 0; i < valNodesByCycle.size(); i++) {
1380  std::set<int> inputs_used;
1381  if (!opNodesByCycle[i].empty()){
1382  op = true;
1383  auto mrrg_nodes_from_op_per_cycle = opNodesByCycle[i];
1384 
1385  int required_node_types_found = 0;
1386  std::vector<OpGraphOp*> phiNodes;
1387 
1388  for (const auto& op_node_and_mrrg_nodes : mrrg_nodes_from_op_per_cycle) {
1389  for (const auto& req_node_regex : required_op_node_regexes) {
1390  for (const auto& mrrg_node : op_node_and_mrrg_nodes.second) {
1391  std::smatch match_results;
1392  if (std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, req_node_regex)) {
1393  if (required_node_types_found > 2) {
1394  throw cgrame_error("found a node that matched two required node regexes");
1395  } else {
1396  required_node_types_found++;
1397  phiNodes.push_back(op_node_and_mrrg_nodes.first);
1398  }
1399  }
1400  }
1401  }
1402  }
1403 
1404  auto mrrg_nodes_from_val_per_cycle = valNodesByCycle[i];
1405  for (const auto& val_node_and_mrrg_nodes : mrrg_nodes_from_val_per_cycle) { //added
1406  if (required_node_types_found > 0) {
1407  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
1408  std::smatch match_results;
1409  std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, in_regex);
1410  if (match_results.size() == 2) {
1411  inputs_used.insert(stoi(match_results[1].str()));
1412  }
1413  }
1414  } else {
1415  // ignore the val
1416  }
1417  }
1418  } else {
1419  auto mrrg_nodes_from_val_per_cycle = valNodesByCycle[i];
1420  for (const auto& val_node_and_mrrg_nodes : mrrg_nodes_from_val_per_cycle) {
1421  std::vector<bool> required_node_types_found;
1422  for (const auto& req_node_regex : required_node_regexes) {
1423  required_node_types_found.push_back(false);
1424  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
1425  std::smatch match_results;
1426  if (std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, req_node_regex)) {
1427  if (required_node_types_found.back()) {
1428  throw cgrame_error("found a node that matched two required node regexes");
1429  } else {
1430  required_node_types_found.back() = true;
1431  }
1432  }
1433  }
1434  }
1435 
1436  if (std::all_of(begin(required_node_types_found), end(required_node_types_found), [&](auto&& v) { return v; })) {
1437  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
1438  std::smatch match_results;
1439  std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, in_regex);
1440  if (match_results.size() == 2) {
1441  inputs_used.insert(stoi(match_results[1].str()));
1442  }
1443  }
1444  } else {
1445  // ignore the val
1446  }
1447  }
1448 
1449  }
1450  if (inputs_used.empty()) {
1451  bitConfig.add({(size_t) mux_size, BitSetting::LOW}, cycle);
1452 
1453  } else if (inputs_used.size() > 1 && !op) {
1454  throw cgrame_error("Elastic Select Mux has more than input but it is not used as an select or phi operations");
1455  } else {
1456  // Create the bit settings, in a one-hot manner
1457  used_cycles++;
1458  unsigned bit_settings = 0;
1459  for (const auto& input_num : inputs_used) {
1460  bit_settings |= (1U << (unsigned) input_num);
1461  }
1462  bitConfig.add(bitsettings_from_int((int) bit_settings, mux_size), cycle);
1463  }
1464  cycle++;
1465  }
1466  bitConfig.setUsedCycles(used_cycles);
1467  return bitConfig;
1468 }
1469 
1470 
1471 /* Elastic Merge */
1472 ElasticMerge::ElasticMerge(std::string name, Location loc, int size, int fanin_)
1473  : Module(name, loc, size), fanin(fanin_)
1474 {
1476  isElastic = true;
1477  // Check module legality
1478  if (fanin <= 1) {make_and_throw<cgrame_error>([&](auto&& s) {
1479  s << "Elastic merge doesn't support fanin of <=1. Requested fanin was " << fanin;
1480  });}
1481 
1482  // Create ports
1483  for (int i = 0; i < fanin; i++) {
1484  addPort("valid_upstream" + std::to_string(i), PORT_INPUT, 1);
1485  addPort("stop_upstream" + std::to_string(i), PORT_OUTPUT, 1);
1486  addPort("data_in" + std::to_string(i), PORT_INPUT, "size", size);
1487  node_relative_position.insert({"data_in" + std::to_string(i), {static_cast<double>(i)/fanin, 0.25}});
1488  }
1489  addPort("valid_downstream", PORT_OUTPUT, 1);
1490  addPort("stop_downstream", PORT_INPUT, 1);
1491  addPort("data_out", PORT_OUTPUT, "size", size);
1492  addPort("enable_upstream", PORT_INPUT, fanin);
1493  node_relative_position.insert({"data_out", {0.25, 0.5}});
1494  node_relative_position.insert({"merge", {0.5, 0.5}});
1495 }
1496 
1498 {
1499  return "elastic_merge_" + std::to_string(fanin) + "to1" + "_size_" + std::to_string(data_size);
1500 }
1501 
1503 {
1504  nlohmann::json vjson;
1505 
1506  // Create Header
1507  vjson["prefix"] = "cgrame_";
1508  vjson["parameters"] = {};
1509  for (auto& parameter : parameterlist)
1510  {
1511  vjson["parameters"].push_back(parameter.first);
1512  }
1513  vjson["interface"] = {};
1514  vjson["interface"].push_back("CGRA_Clock");
1515  vjson["interface"].push_back("CGRA_Reset");
1516  vjson["interface"].push_back("CGRA_Enable");
1517 
1518  for (auto& port : ports)
1519  {
1520  std::string portName = port.second->getName();
1521  vjson["interface"].push_back(portName);
1522  }
1523 
1524  // module definition
1525  std::string moduleDefinition;
1526  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
1527  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
1528  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
1529  for (auto& port : ports)
1530  {
1531  port_type portType = port.second->pt;
1532  std::string portTypeString = {};
1533  if(portType == port_type::PORT_INPUT)
1534  {
1535  portTypeString = "input";
1536  }
1537  else if (portType == port_type::PORT_OUTPUT)
1538  {
1539  portTypeString = "output";
1540  }
1541  else if (portType == port_type::PORT_OUTPUT_REG)
1542  {
1543  portTypeString = "output reg";
1544  }
1545  else
1546  {
1547  portTypeString = "inout";
1548  }
1549  std::string portSizeString;
1550  if (!(port.second->parameter).empty()) // Check if size is parameterized
1551  {
1552  std::string portParameterName = port.second->parameter;
1553  portSizeString = "[" + portParameterName + "-1:0]";
1554  }
1555  else
1556  {
1557  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
1558  }
1559  std::string portName = port.second->getName();
1560  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
1561  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
1562  }
1563 
1564  // Functionality
1565  moduleDefinition += std::string(SET_INDENT) + "elastic_merge #(";
1566  moduleDefinition += ".FANIN(" + std::to_string(fanin) + "), ";
1567  moduleDefinition += ".DATA_WIDTH(" + std::to_string(getSize()) + ")) emerge (\n";
1568  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".clk(CGRA_Clock),\n";
1569  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".reset(CGRA_Reset),\n";
1570 
1571  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".valid_upstream({";
1572  for (int i = fanin-1; i > 0; i--)
1573  moduleDefinition += "valid_upstream" + std::to_string(i) + ", ";
1574  moduleDefinition += "valid_upstream0}),\n";
1575 
1576  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".stop_upstream({";
1577  for (int i = fanin-1; i > 0; i--)
1578  moduleDefinition += "stop_upstream" + std::to_string(i) + ", ";
1579  moduleDefinition += "stop_upstream0}),\n";
1580 
1581  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".valid_downstream(valid_downstream),\n";
1582  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".stop_downstream(stop_downstream),\n";
1583 
1584  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".data_in({";
1585  for (int i = fanin-1; i > 0; i--)
1586  moduleDefinition += "data_in" + std::to_string(i) + ", ";
1587  moduleDefinition += "data_in0}),\n";
1588  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".data_out(data_out),\n";
1589 
1590 
1591  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".enable_upstream(enable_upstream)\n";
1592  moduleDefinition += std::string(SET_INDENT) + ");\n";
1593 
1594  vjson["definition"] = moduleDefinition;
1595  return vjson;
1596 }
1597 
1599 { // Empty destructor
1600 }
1601 
1603 {
1604 
1605  MRRG* result_ptr = new MRRG(II);
1606  auto& result = *result_ptr;
1607 
1608  for (unsigned i = 0; i < II; i++)
1609  {
1610  // Create nodes and link them, we make this module look like a demux to the mapper
1611  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "data_out", 0)).first;
1612  MRRG::NodeDescriptor merge = result.insert(MRRGNode::make_routing(this, data_size, i, "merge", 0)).first;
1613  result.link(merge, out);
1614  for (int j = 0; j < fanin; j++) {
1615  MRRG::NodeDescriptor in = result.insert(MRRGNode::make_routing(this, data_size, i, "data_in" + std::to_string(j), 0)).first;
1616  result.link(in, merge);
1617  }
1618  }
1619 
1620  return result_ptr;
1621 }
1622 
1624  const MRRG& mrrg, const OpGraph & og,
1625  const Mapping& map,
1626  const ConfigCell& ccell,
1627  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
1628  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
1629 ) const {
1630  (void)ccell;
1631  (void)mrrg_nodes_from_op_node;
1632  const std::vector<std::regex> required_node_regexes {
1633  std::regex("\\.merge$"), std::regex("\\.data_out$"),
1634  };
1635  const std::regex in_regex("\\.data_in([0-9]+)$");
1636  BitConfig bitConfig(mrrg.initiationInterval());
1637 
1638  // Organize nodes mapping by cycle
1639  std::vector<MRRGNodesFromValNode> valNodesByCycle(mrrg.initiationInterval());
1640  for (const auto& val_and_mrrg_nodes : mrrg_nodes_from_val_node) {
1641  for (const auto& mrrg_node : val_and_mrrg_nodes.second) {
1642  valNodesByCycle[mrrg_node->cycle][val_and_mrrg_nodes.first].insert(mrrg_node);
1643  }
1644  }
1645 
1646  int cycle = 0;
1647  int used_cycles = 0;
1648  for (auto & mrrg_nodes_from_val_per_cycle : valNodesByCycle) {
1649  std::unordered_set<int> inputs_used;
1650 
1651  for (const auto& val_node_and_mrrg_nodes : mrrg_nodes_from_val_per_cycle) {
1652  // Check for required nodes: .demux and .in
1653  std::vector<bool> required_node_types_found;
1654  for (const auto& req_node_regex : required_node_regexes) {
1655  required_node_types_found.push_back(false);
1656  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
1657  std::smatch match_results;
1658  if (std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, req_node_regex)) {
1659  if (required_node_types_found.back()) {
1660  throw cgrame_error("found a node that matched two required node regexes");
1661  } else {
1662  required_node_types_found.back() = true;
1663  }
1664  }
1665  }
1666  }
1667 
1668  // Check for which outputs are used in the mapping
1669  if (std::all_of(begin(required_node_types_found), end(required_node_types_found), [&](auto&& v) { return v; })) {
1670  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
1671  std::smatch match_results;
1672  std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, in_regex);
1673  if (match_results.size() == 2) {
1674  inputs_used.insert(stoi(match_results[1].str()));
1675  }
1676  }
1677  } else {
1678  // ignore the val
1679  }
1680  }
1681 
1682  if (inputs_used.empty()) {
1683  bitConfig.add({(size_t) fanin, BitSetting::DONT_CARE_PREFER_LOW}, cycle);
1684  } else {
1685  // Create the bit settings, in a one-hot manner
1686  used_cycles++;
1687  unsigned bit_settings = 0;
1688  for (const auto& input_num : inputs_used) {
1689  bit_settings |= (1U << (unsigned) input_num);
1690  }
1691  bitConfig.add(bitsettings_from_int((int) bit_settings, fanin), cycle);
1692  }
1693  ++cycle;
1694  }
1695  bitConfig.setUsedCycles(used_cycles);
1696  return bitConfig;
1697 }
1698 
1699 
1700 const std::map<OpGraphOpCode, LLVMMode> FPUnit_wrapper::all_modes =
1701 {
1702  {OpCode::FADD, {"op_add", "add", {"8"}, "add_sel"}}, // janders changed to 8 from Adham's 7
1703  {OpCode::FMUL, {"op_multiply", "multiply", {"0"}, "mul_sel"}},
1704  {OpCode::FDIV, {"op_divide", "divide", {"20"}, "div_sel"}},
1705  {OpCode::SQRT, {"op_sqrt", "sqrt", {"17"}, "sqrt_sel"}},
1706 };
1707 
1708 //module definition
1709 FPUnit_wrapper::FPUnit_wrapper(std::string name, Location loc, int max_latency, std::vector<OpGraphOpCode> supported_modes_)
1710  : Module(name, loc), max_latency(max_latency), supported_modes(std::move(supported_modes_))
1711 {
1712  adds_synchronous_circuitry = true; //Wrapper has sequential elements
1713  isElastic = true;
1714  //Create ports
1715  addPort("opcode", PORT_INPUT, ceil(log2(supported_modes.size())));
1716  addPort("valid_upstream", PORT_INPUT, 1);
1717  addPort("stop_downstream", PORT_INPUT, 1);
1718  addPort("valid_downstream", PORT_OUTPUT_REG, 1);
1719  addPort("stop_upstream", PORT_OUTPUT_REG, 1);
1720 }
1721 
1722 //Virtual function that override Module::GenericName. Returns generic name for the wrapper
1724 {
1725  return "fpunit_wrapper_size_" + std::to_string(data_size);
1726 }
1727 
1728 //Virtual function that overrides Module::CoreIRGetFunctionality. Generates functionality for the wrapper
1730 {
1731  nlohmann::json vjson;
1732 
1733  //Create Header
1734  vjson["prefix"] = "cgrame_";
1735  //No parameters defined
1736  vjson["interface"] = {};
1737  vjson["interface"].push_back("CGRA_Clock");
1738  vjson["interface"].push_back("CGRA_Reset");
1739  vjson["interface"].push_back("CGRA_Enable");
1740 
1741  for (auto& port : ports)
1742  {
1743  std::string portName = port.second->getName();
1744  vjson["interface"].push_back(portName);
1745  }
1746 
1747  //module definition
1748  std::string moduleDefinition;
1749  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
1750  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
1751  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
1752  for (auto& port : ports)
1753  {
1754  port_type portType = port.second->pt;
1755  std::string portTypeString = {};
1756  if(portType == port_type::PORT_INPUT)
1757  {
1758  portTypeString = "input";
1759  }
1760  else if (portType == port_type::PORT_OUTPUT)
1761  {
1762  portTypeString = "output";
1763  }
1764  else if (portType == port_type::PORT_OUTPUT_REG)
1765  {
1766  portTypeString = "output reg";
1767  }
1768  else
1769  {
1770  portTypeString = "inout";
1771  }
1772  std::string portSizeString;
1773  if (!(port.second->parameter).empty()) // Check if size is parameterized
1774  {
1775  std::string portParameterName = port.second->parameter;
1776  portSizeString = "[" + portParameterName + "-1:0]";
1777  }
1778  else
1779  {
1780  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
1781  }
1782  std::string portName = port.second->getName();
1783  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
1784  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
1785  }
1786 
1787  // Functionality
1788  moduleDefinition += std::string(SET_INDENT) + "reg [" + std::to_string(max_latency) + ":0] register;\n";
1789  moduleDefinition += std::string(SET_INDENT) + "reg [" + std::to_string((int)(ceil(log2(supported_modes.size()))-1)) + ":0] curr_opcode;\n";
1790  moduleDefinition += "\n";
1791  moduleDefinition += std::string(SET_INDENT) + "always@(posedge CGRA_Clock) begin\n";
1792  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if (CGRA_Reset) begin\n";
1793  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "stop_upstream <= 0;\n";
1794  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "curr_opcode <= 0;\n";
1795  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
1796  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "else if (opcode != curr_opcode) begin\n";
1797  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "if (|register) begin\n";
1798  moduleDefinition += std::string(SET_DOUBLE_INDENT) + std::string(SET_DOUBLE_INDENT) + "stop_upstream <= 1;\n";
1799  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end else begin\n";
1800  moduleDefinition += std::string(SET_DOUBLE_INDENT) + std::string(SET_DOUBLE_INDENT) + "stop_upstream <= 0;\n";
1801  moduleDefinition += std::string(SET_DOUBLE_INDENT) + std::string(SET_DOUBLE_INDENT) + "curr_opcode <= opcode;\n";
1802  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
1803  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
1804  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "else if (opcode == curr_opcode) begin\n";
1805  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "curr_opcode <= opcode;\n";
1806  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
1807  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if (~stop_downstream) begin\n";
1808  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "stop_upstream <= 0;\n";
1809  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
1810  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "else if (stop_downstream) begin\n";
1811  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "stop_upstream <= 1;\n";
1812  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
1813  moduleDefinition += std::string(SET_INDENT) + "end\n";
1814  moduleDefinition += "\n";
1815  moduleDefinition += std::string(SET_INDENT) + "always@(posedge CGRA_Clock) begin\n";
1816  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if (CGRA_Reset) begin\n";
1817  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "register <= 0;\n";
1818  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
1819  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "else if (~stop_downstream) begin\n";
1820  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "register <= {valid_upstream, register[" + std::to_string(max_latency) + ":1]};\n";
1821  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
1822  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "else if (stop_downstream) begin\n";
1823  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "register <= register;\n";
1824  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
1825  moduleDefinition += std::string(SET_INDENT) + "end\n";
1826  moduleDefinition += "\n";
1827  moduleDefinition += std::string(SET_INDENT) + "always@(*) begin\n";
1828  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if (CGRA_Reset) begin\n";
1829  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "valid_downstream <= 0;\n";
1830  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
1831  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "else begin\n";
1832  for (unsigned i = 0; i < supported_modes.size(); i++)
1833  {
1834  if (i == 0) {
1835  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "if (curr_opcode == " + std::to_string(i) + ") begin\n";
1836  }
1837  else {
1838  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "else if (curr_opcode == " + std::to_string(i) + ") begin\n";
1839  }
1840  if (std::stoi(all_modes.at(supported_modes.at(i)).Functionality.at(0)) != 0) {
1841  moduleDefinition += std::string(SET_TRIPLE_INDENT) + std::string(SET_INDENT) + "if (~register[" + std::to_string((max_latency - std::stoi(all_modes.at(supported_modes.at(i)).Functionality.at(0))) + 1) + "]) begin\n";
1842  moduleDefinition += std::string(SET_DOUBLE_INDENT) + std::string(SET_TRIPLE_INDENT) + "valid_downstream <= 0;\n";
1843  moduleDefinition += std::string(SET_TRIPLE_INDENT) + std::string(SET_INDENT) + "end\n";
1844  moduleDefinition += std::string(SET_TRIPLE_INDENT) + std::string(SET_INDENT) + "else if (register[" + std::to_string(max_latency - std::stoi((all_modes.at(supported_modes.at(i)).Functionality.at(0))) + 1) + "]) begin\n";
1845  moduleDefinition += std::string(SET_DOUBLE_INDENT) + std::string(SET_TRIPLE_INDENT) + "valid_downstream <= 1;\n";
1846  moduleDefinition += std::string(SET_TRIPLE_INDENT) + std::string(SET_INDENT) + "end\n";
1847  } else {
1848  moduleDefinition += std::string(SET_DOUBLE_INDENT) + std::string(SET_TRIPLE_INDENT) + "valid_downstream <= valid_upstream;\n";
1849  }
1850  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
1851  }
1852  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
1853  moduleDefinition += std::string(SET_INDENT) + "end\n";
1854 
1855  vjson["definition"] = moduleDefinition;
1856  return vjson;
1857 
1858 }
1859 
1860 //Class destructor
1862 {
1863  //Empty Destructor
1864 }
1865 
1866 
1867 
1869  const MRRG& mrrg, const OpGraph & og,
1870  const Mapping& map,
1871  const ConfigCell& ccell,
1872  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
1873  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
1874 ) const {
1875  (void)ccell;
1876  (void)mrrg_nodes_from_val_node;
1877  const auto bits_needed = std::lround(ceil(log2(supported_modes.size())));
1878 
1879  BitConfig bitConfig(mrrg.initiationInterval());
1880 
1881  // Organize nodes mapping by cycle
1882  std::vector<MRRGNodesFromOpNode> opNodesByCycle(mrrg.initiationInterval());
1883  for (const auto& op_and_mrrg_nodes : mrrg_nodes_from_op_node) {
1884  for (const auto& mrrg_node : op_and_mrrg_nodes.second) {
1885  opNodesByCycle[mrrg_node->cycle][op_and_mrrg_nodes.first].insert(mrrg_node);
1886  }
1887  }
1888 
1889  int cycle = 0;
1890  int used_cycles = 0;
1891  for (auto & op_and_mrrg_nodes : opNodesByCycle) {
1892  if (op_and_mrrg_nodes.empty()) {
1893  bitConfig.add({ (size_t)bits_needed, BitSetting::DONT_CARE_PREFER_LOW }, cycle);
1894  } else if (op_and_mrrg_nodes.size() == 1) {
1895  const auto find_result = std::find(begin(supported_modes), end(supported_modes), begin(op_and_mrrg_nodes)->first->opcode);
1896  if (find_result == end(supported_modes)) {
1897  throw cgrame_error("couldn't find op in supported modes list");
1898  } else {
1899  used_cycles++;
1900  bitConfig.add( bitsettings_from_int(std::distance(begin(supported_modes), find_result), bits_needed), cycle);
1901  }
1902 
1903  } else {
1904  throw cgrame_error("expect either 0 or 1 op nodes");
1905  }
1906  ++cycle;
1907  }
1908  bitConfig.setUsedCycles(used_cycles);
1909  return bitConfig;
1910 }
1911 
1912 //Creating Module Routing Resource Graph
1914 {
1915 
1916  MRRG* result_ptr = new MRRG(II);
1917  auto& result = *result_ptr;
1918 
1919  for (unsigned i = 0; i < II; i++)
1920  {
1921  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "out" + std::to_string(0), 0)).first;
1922  MRRG::NodeDescriptor in = result.insert(MRRGNode::make_routing(this, data_size, i, "in" + std::to_string(0), 0)).first;
1923  result.link(in, out);
1924  }
1925 
1926  return result_ptr;
1927 }
1928 
1929 /* Elastic Variable-Latency Unit wrapper */
1930 ElasticVLUWrapper::ElasticVLUWrapper(std::string name, Location loc, int size, int input_count_)
1931  : Module(name, loc, size), input_count(input_count_)
1932 {
1934  isElastic = true;
1935  // Create Ports
1936  for (int i = 0; i < input_count; i++) {
1937  addPort("data_in" + std::to_string(i), PORT_INPUT, "size", size);
1938  node_relative_position.insert({"data_in" + std::to_string(i), {0, static_cast<double>(i)/input_count}});
1939  }
1940  addPort("data_out", PORT_OUTPUT, "size", size);
1941  node_relative_position.insert({"data_out", {0.75, 0.5}});
1942 
1943  addPort("valid_upstream", PORT_INPUT, 1);
1944  addPort("stop_upstream", PORT_OUTPUT, 1);
1945  addPort("valid_downstream", PORT_OUTPUT, 1);
1946  addPort("stop_downstream", PORT_INPUT, 1);
1947 
1948  addPort("vlu_go", PORT_OUTPUT, 1);
1949  addPort("vlu_ready", PORT_INPUT, 1);
1950  addPort("vlu_done", PORT_INPUT, 1);
1951  addPort("vlu_ack", PORT_OUTPUT, 1);
1952  for (int i = 0; i < input_count; i++) {
1953  addPort("vlu_data_in" + std::to_string(i), PORT_OUTPUT, "size", size);
1954  node_relative_position.insert({"vlu_data_in" + std::to_string(i), {0.25, static_cast<double>(i) / input_count}});
1955  }
1956  addPort("vlu_data_out", PORT_INPUT, "size", size);
1957  node_relative_position.insert({"vlu_data_out", {0.5, 0.5}});
1958 }
1959 
1961 {
1962  return "elastic_vluwrapper_" + std::to_string(getSize()) + "b";
1963 }
1964 
1966 {
1967  nlohmann::json vjson;
1968 
1969  // Create Header
1970  vjson["prefix"] = "cgrame_";
1971  vjson["parameters"] = {};
1972  for (auto& parameter : parameterlist)
1973  {
1974  vjson["parameters"].push_back(parameter.first);
1975  }
1976  vjson["interface"] = {};
1977 
1978  for (auto& port : ports)
1979  {
1980  std::string portName = port.second->getName();
1981  vjson["interface"].push_back(portName);
1982  }
1983 
1984  // module definition
1985  std::string moduleDefinition;
1986  for (auto& port : ports)
1987  {
1988  port_type portType = port.second->pt;
1989  std::string portTypeString = {};
1990  if(portType == port_type::PORT_INPUT)
1991  {
1992  portTypeString = "input";
1993  }
1994  else if (portType == port_type::PORT_OUTPUT)
1995  {
1996  portTypeString = "output";
1997  }
1998  else if (portType == port_type::PORT_OUTPUT_REG)
1999  {
2000  portTypeString = "output reg";
2001  }
2002  else
2003  {
2004  portTypeString = "inout";
2005  }
2006  std::string portSizeString;
2007  if (!(port.second->parameter).empty()) // Check if size is parameterized
2008  {
2009  std::string portParameterName = port.second->parameter;
2010  portSizeString = "[" + portParameterName + "-1:0]";
2011  }
2012  else
2013  {
2014  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
2015  }
2016  std::string portName = port.second->getName();
2017  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
2018  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
2019  }
2020 
2021  // Functionality
2022  moduleDefinition += std::string(SET_INDENT) + "elastic_vlu_wrapper #(";
2023  moduleDefinition += ".DATA_WIDTH(" + std::to_string(getSize()) + "), ";
2024  moduleDefinition += ".INPUT_COUNT(" + std::to_string(2) + ")) vlu_wrapper (\n";
2025 
2026  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".data_in({";
2027  for (int i = input_count-1; i > 0; i--)
2028  moduleDefinition += "data_in" + std::to_string(i) + ", ";
2029  moduleDefinition += "data_in0}),\n";
2030  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".data_out(data_out),\n";
2031 
2032  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".valid_upstream(valid_upstream),\n";
2033  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".stop_upstream(stop_upstream),\n";
2034  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".valid_downstream(valid_downstream),\n";
2035  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".stop_downstream(stop_downstream),\n";
2036 
2037  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".vlu_go(vlu_go),\n";
2038  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".vlu_ready(vlu_ready),\n";
2039  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".vlu_done(vlu_done),\n";
2040  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".vlu_ack(vlu_ack),\n";
2041 
2042  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".vlu_data_in({";
2043  for (int i = input_count-1; i > 0; i--)
2044  moduleDefinition += "vlu_data_in" + std::to_string(i) + ", ";
2045  moduleDefinition += "vlu_data_in0}),\n";
2046  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".vlu_data_out(vlu_data_out)\n";
2047 
2048  moduleDefinition += std::string(SET_INDENT) + ");\n";
2049 
2050  vjson["definition"] = moduleDefinition;
2051  return vjson;
2052 }
2053 
2055 { // Empty destructor
2056 }
2057 
2059 {
2060 
2061  MRRG* result_ptr = new MRRG(II);
2062  auto& result = *result_ptr;
2063 
2064  for (unsigned i = 0; i < II; i++)
2065  {
2066  // Create nodes and link them, we make this module look like a demux to the mapper
2067  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "data_out", 0)).first;
2068  MRRG::NodeDescriptor vlu_out = result.insert(MRRGNode::make_routing(this, data_size, i, "vlu_data_out", 0)).first;
2069  result.link(vlu_out, out);
2070  for (int j = 0; j < input_count; j++) {
2071  MRRG::NodeDescriptor in = result.insert(MRRGNode::make_routing(this, data_size, i, "data_in" + std::to_string(j), 0)).first;
2072  MRRG::NodeDescriptor vlu_in = result.insert(MRRGNode::make_routing(this, data_size, i, "vlu_data_in" + std::to_string(j), 0)).first;
2073  result.link(in, vlu_in);
2074  }
2075  }
2076 
2077  return result_ptr;
2078 }
2079 
2081 {
2082  return "elastic_func_unit_" + name + "_size_" + std::to_string(data_size);
2083 }
2084 
2085 // Writing this function since the connection among the functional unit and join are not consistent with the rest of the archtecture
2086 // Hence this wrapper code is needed
2087 ElasticFuncUnit::ElasticFuncUnit(std::string name, Location loc, std::vector<OpGraphOpCode> supported_modes_, unsigned size, int II, int latency, bool predExist, bool isElastic, int contexts)
2088  : Module(name, loc, size) {
2089  // If pred exist then token inducer is not needed since there should be no operation feeding into itself
2090  // PORTS
2091  addPort("in_a", PORT_INPUT, "size", size, isElastic);
2092  addPort("in_b", PORT_INPUT, "size", size, isElastic);
2093  addPort("out", PORT_OUTPUT, "size", size, isElastic);
2094 
2095  // Function modules
2096  addSubModule(new ElasticJoin(name + "_join", loc, 32, 2), 0.25, 0.3, 0.5, 0.1);
2097  addSubModule(new FuncUnit(name + "_ALU", loc, supported_modes_, size, II, latency, isElastic), 0, 0.75, 0.5, 0.25);
2098 
2099  // Add Config cells
2100  addConfig(name + "_ALUconfig", {name + "_ALU.select"}, II, false);
2101  addConfig(name + "_InputJoinConfig", {name + "_join.enable"}, II, isElastic);
2102 
2103  //Connections among modules
2104  connectPorts("this.in_a", name + "_join.in0", isElastic);
2105  connectPorts("this.in_b", name + "_join.in1", isElastic);
2106  addConnection(name + "_join.out0", name + "_ALU.in_a");
2107  addConnection(name + "_join.out1", name + "_ALU.in_b");
2108 
2109  if (predExist) {
2110  addConnection(name + "_ALU.out", "this.out");
2111  addConnection(name + "_join.out_valid_downstream", "this.out_valid_downstream", false);
2112  addConnection("this.out_stop_downstream", name + "_join.out_stop_downstream", false);
2113  return;
2114  }
2115 
2116  // Adding token inducer if pred does not exist
2117  addSubModule(new ElasticTokenInducer(name + "_token_inducer", loc, 32, II), 0.5, 0.45, 0.5, 0.05);
2118  addConfig(new ElasticConfigCell(name + "_adapterToken", II), {name + "_token_inducer.token"});
2119  addConnection(name + "_ALU.out", name + "_token_inducer.data_in");
2120  addConnection(name + "_join.out_valid_downstream", name + "_token_inducer.data_in_valid_upstream", false);
2121  addConnection(name + "_token_inducer.data_in_stop_upstream", name + "_join.out_stop_downstream", false);
2122  if ( II > 1) {
2123  addConnection(name + "adapterToken.contexts_used", name + "_token_inducer.contexts_used", false);
2124  }
2125 
2126  connectPorts(name + "_token_inducer.data_out", "this.out", isElastic);
2127 }
2128 
2130 {
2131  return "elastic_fp_unit_" + name + "_size_" + std::to_string(data_size);
2132 }
2133 
2134 // Writing this function since the connection among the functional unit and join are not consistent with the rest of the archtecture
2135 // Hence this wrapper code is needed
2136 ElasticFPUnit::ElasticFPUnit(std::string name, Location loc, std::vector<OpGraphOpCode> supported_modes_, unsigned size, int II, int latency, bool predExist, bool isElastic, int contexts)
2137  : Module(name, loc, size) {
2138  // If pred exist then token inducer is not needed since there should be no operation feeding into itself
2139  // PORTS
2140  addPort("in_a", PORT_INPUT, "size", size, isElastic);
2141  addPort("in_b", PORT_INPUT, "size", size, isElastic);
2142  addPort("out", PORT_OUTPUT, "size", size, isElastic);
2143  addSubModule(new FPUnit(name +"_FPALU", loc, supported_modes_, size, II, latency), 0.5, 0.4, 0.5, 0.1);
2144  // FP wrapper for the elastic protocol. This is needed because the FloPoCo FP units are non-elastic
2145  addSubModule(new FPUnit_wrapper(name + "_fp_wrapper", loc, 22, supported_modes_), 1.0, 0.4, 0.5, 0.1);
2146 
2147  // Function modules
2148  addSubModule(new ElasticJoin(name + "_join", loc, 32, 2), 0.25, 0.3, 0.5, 0.1);
2149 
2150  // Add Config cells
2151  addConfig(name + "_FPUnitConfig",{name + "_FPALU.opcode", name + "_fp_wrapper.opcode"}, II, false);
2152  addConfig(name + "_InputJoinConfig", {name + "_join.enable"}, II, isElastic);
2153 
2154  //Connections among modules
2155  connectPorts("this.in_a", name + "_join.in0", isElastic);
2156  connectPorts("this.in_b", name + "_join.in1", isElastic);
2157  addConnection(name + "_join.out0", name + "_FPALU.in_a");
2158  addConnection(name + "_join.out1", name + "_FPALU.in_b");
2159  addConnection(name + "_join.out_valid_downstream", name +"_fp_wrapper.valid_upstream", false);
2160  addConnection(name + "_fp_wrapper.stop_upstream", name + "_join.out_stop_downstream", false);
2161  addConnection("this.out_stop_downstream", name + "_FPALU.FP_clk_en", false); // OK add clock enable for FloPoCo cores
2162 
2163  if (predExist) {
2164  addConnection(name + "_FPALU.out", "this.out");
2165  addConnection( name + "_fp_wrapper.valid_downstream", "this.out_valid_downstream", false);
2166  addConnection("this.out_stop_downstream", name + "_fp_wrapper.stop_downstream", false);
2167  return;
2168  }
2169 
2170  // Adding token inducer if pred does not exist
2171  addSubModule(new ElasticTokenInducer(name + "_token_inducer", loc, 32, II), 0.5, 0.45, 0.5, 0.05);
2172  addConfig(new ElasticConfigCell(name + "_adapterToken", II), {name + "_token_inducer.token"});
2173  addConnection(name + "_FPALU.out", name + "_token_inducer.data_in");
2174  addConnection(name + "_fp_wrapper.valid_downstream", name + "_token_inducer.data_in_valid_upstream", false);
2175  addConnection(name + "_token_inducer.data_in_stop_upstream", name + "_fp_wrapper.stop_downstream", false);
2176  if ( II > 1) {
2177  addConnection(name + "adapterToken.contexts_used", name + "_token_inducer.contexts_used", false);
2178  }
2179 
2180  connectPorts(name + "_token_inducer.data_out", "this.out", isElastic);
2181 }
2182 
2183 /* Elastic FU-VLU adapter */
2184 ElasticTokenInducer::ElasticTokenInducer(std::string name, Location loc, int size, int II, bool isElastic)
2185  : Module(name, loc, size, isElastic)
2186 {
2187  iteration_interval = II;
2189  if (isElastic == false) {make_and_throw<cgrame_error>([&](auto&& s) {
2190  s << "Elastic eager fork needs to be marked as elastic ";
2191  });}
2192  // Create ports
2193  addPort("data_in", PORT_INPUT, "size", size, isElastic);
2194  addPort("data_out", PORT_OUTPUT, "size", size, isElastic);
2195 
2196  addPort("token", PORT_CONFIG, 1, isElastic);
2197  if (II > 1) {
2198  addPort("contexts_used", PORT_INPUT, ceil(log2(II)));
2199  }
2200  // Visualization
2201  node_relative_position.insert({"data_in", {0, 0}});
2202  node_relative_position.insert({"data_out", {0, 0}});
2203 }
2204 
2206 {
2207  return "elastic_fu_vlu_adapter_" + std::to_string(getSize()) + "b";
2208 }
2209 
2211 {
2212  nlohmann::json vjson;
2213 
2214  // Create Header
2215  vjson["prefix"] = "cgrame_";
2216  vjson["parameters"] = {};
2217  for (auto& parameter : parameterlist)
2218  {
2219  vjson["parameters"].push_back(parameter.first);
2220  }
2221  vjson["interface"] = {};
2222  vjson["interface"].push_back("CGRA_Clock");
2223  vjson["interface"].push_back("CGRA_Reset");
2224  vjson["interface"].push_back("CGRA_Enable");
2225 
2226  for (auto& port : ports)
2227  {
2228  std::string portName = port.second->getName();
2229  vjson["interface"].push_back(portName);
2230  }
2231 
2232  // module definition
2233  std::string moduleDefinition;
2234  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
2235  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
2236  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
2237  for (auto& port : ports)
2238  {
2239  port_type portType = port.second->pt;
2240  std::string portTypeString = {};
2241  if(portType == port_type::PORT_INPUT)
2242  {
2243  portTypeString = "input";
2244  }
2245  else if (portType == port_type::PORT_OUTPUT)
2246  {
2247  portTypeString = "output";
2248  }
2249  else if (portType == port_type::PORT_OUTPUT_REG)
2250  {
2251  portTypeString = "output reg";
2252  }
2253  else
2254  {
2255  portTypeString = "inout";
2256  }
2257  std::string portSizeString;
2258  if (!(port.second->parameter).empty()) // Check if size is parameterized
2259  {
2260  std::string portParameterName = port.second->parameter;
2261  portSizeString = "[" + portParameterName + "-1:0]";
2262  }
2263  else
2264  {
2265  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
2266  }
2267  std::string portName = port.second->getName();
2268  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
2269  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
2270  }
2271 
2272  // Functionality
2273  moduleDefinition += std::string(SET_INDENT) + "reg ["+std::to_string((int)ceil(log2(iteration_interval))) + "-1:0] counter;\n";
2274  moduleDefinition += std::string(SET_INDENT) + "reg pass;\n\n";
2275  moduleDefinition += std::string(SET_INDENT) + "always @(posedge CGRA_Clock, posedge CGRA_Reset) begin\n";
2276  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if (CGRA_Reset == 'b1) begin\n";
2277  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "pass <= 'b0;\n";
2278  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "counter <= 'b0;\n";
2279  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end else if (~data_out_stop_downstream) begin\n";
2280  if (iteration_interval > 1) {
2281  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "if("+std::to_string((int)ceil(log2(iteration_interval))) + " > 0)\n";
2282  moduleDefinition += std::string(SET_QUAD_INDENT) + "if (counter > contexts_used) begin \n";
2283  moduleDefinition += std::string(SET_PENTA_INDENT) + "pass <= 1'b0;\n";
2284  moduleDefinition += std::string(SET_QUAD_INDENT) + "end else begin\n";
2285  moduleDefinition += std::string(SET_PENTA_INDENT) + "pass <= token;\n";
2286  moduleDefinition += std::string(SET_PENTA_INDENT) + "counter <= counter + 1'b1;\n";
2287  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end else begin\n";
2288  }
2289  moduleDefinition += std::string(SET_QUAD_INDENT) + "if (counter == 1) begin \n";
2290  moduleDefinition += std::string(SET_PENTA_INDENT) + "pass <= 1'b0;\n";
2291  moduleDefinition += std::string(SET_QUAD_INDENT) + "end else begin\n";
2292  moduleDefinition += std::string(SET_PENTA_INDENT) + "pass <= token;\n";
2293  moduleDefinition += std::string(SET_PENTA_INDENT) + "counter <= counter + 1'b1;\n";
2294  moduleDefinition += std::string(SET_QUAD_INDENT) + "end\n";
2295  if (iteration_interval > 1) {
2296  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
2297  }
2298  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
2299  moduleDefinition += std::string(SET_INDENT) + "end\n\n";
2300 
2301  moduleDefinition += std::string(SET_INDENT) + "assign data_in_stop_upstream = data_out_stop_downstream;\n";
2302  moduleDefinition += std::string(SET_INDENT) + "assign data_out_valid_downstream = data_in_valid_upstream | pass;\n";
2303  moduleDefinition += std::string(SET_INDENT) + "assign token_stop_upstream = data_in_stop_upstream;\n";
2304  moduleDefinition += std::string(SET_INDENT) + "assign token_valid_upstream = 'b1;\n";
2305  moduleDefinition += std::string(SET_INDENT) + "assign data_out = data_in;\n";
2306 
2307  vjson["definition"] = moduleDefinition;
2308  return vjson;
2309 }
2310 
2312 { // Empty destructor
2313 }
2314 
2316 {
2317 
2318  MRRG* result_ptr = new MRRG(II);
2319  auto& result = *result_ptr;
2320 
2321  for (unsigned i = 0; i < II; i++)
2322  {
2323  // Create nodes, model as a 0-delay wire
2324  MRRG::NodeDescriptor in = result.insert(MRRGNode::make_routing(this, data_size, i, "data_in", 0)).first;
2325  MRRG::NodeDescriptor token_inducer = result.insert(MRRGNode::make_routing(this, data_size, i, "token_inducer", 1)).first;
2326  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "data_out", 0)).first;
2327 
2328  // Connect nodes
2329  const auto& nodes_this_cycle = makeNodeGetterForCycle(result, i);
2330  result.link(nodes_this_cycle("data_in"), nodes_this_cycle("data_out"));
2331  }
2332 
2333  return result_ptr;
2334 }
2335 
2337  const MRRG& mrrg, const OpGraph & og,
2338  const Mapping& map,
2339  const ConfigCell& ccell,
2340  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
2341  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
2342 ) const {
2343  (void)ccell;
2344  (void)mrrg_nodes_from_op_node;
2345  const std::regex in_regex("\\.data_in$");
2346  BitConfig bitConfig(mrrg.initiationInterval());
2347 
2348  // Organize nodes mapping by cycle
2349  std::vector<MRRGNodesFromValNode> valNodesByCycle(mrrg.initiationInterval());
2350 
2351  // create an index from (Module, OpGraphVal) to a set of MRRG nodes mapped to that OpGraphVal within that Module
2352  std::set<const MRRGNode*> mrrgnodes_mapped_to;
2353  for(auto* val : og.valNodes()) {
2354  for(auto* n : map.getMappingList(val)) {
2355  mrrgnodes_mapped_to.insert(n);
2356  }
2357  }
2358 
2359  for(auto* op : map.getOpGraph().opNodes()) {
2360  for (auto* n : map.getMappingList(op)) {
2361  mrrgnodes_mapped_to.insert(n);
2362  }
2363  }
2364 
2365 
2366  for (const auto& val_and_mrrg_nodes : mrrg_nodes_from_val_node) {
2367  for (const auto& mrrg_node : val_and_mrrg_nodes.second) {
2368  valNodesByCycle[mrrg_node->cycle][val_and_mrrg_nodes.first].insert(mrrg_node);
2369  }
2370  }
2371 
2372  int cycle = 0;
2373  int used_cycles = 0;
2374  for (const auto & mrrg_nodes_from_val_per_cycle : valNodesByCycle) {
2375  if (mrrg_nodes_from_val_per_cycle.empty()) {
2376  bitConfig.add({BitSetting::LOW}, cycle);
2377  } else {
2378  bool enableToken;
2379  for (const auto & op_val_and_nodes: mrrg_nodes_from_val_per_cycle) {
2380  for (const auto & mrrg_node : op_val_and_nodes.second) {
2381  auto name = mrrg_node->getHierarchyQualifiedName();
2382 
2383  if (regex_search(name, in_regex)) {
2384  // Considering doing an error check here to see if "m_in" shows up twice
2385  std::set<const MRRGNode*> visited;
2386  enableToken = isNodeInCycle(mrrg_node, mrrg_node, visited, mrrgnodes_mapped_to);
2387  }
2388  }
2389  }
2390  if (enableToken) {
2391  used_cycles++;
2392  bitConfig.add({BitSetting::HIGH}, cycle);
2393  } else {
2394  bitConfig.add({BitSetting::LOW}, cycle);
2395  }
2396  }
2397  ++cycle;
2398  }
2399  bitConfig.setUsedCycles(used_cycles);
2400  return bitConfig;
2401 }
2402 
2403 bool ElasticTokenInducer::isNodeInCycle( const MRRGNode* originNode, const MRRGNode* thisNode, std::set<const MRRGNode*>& visited, std::set<const MRRGNode*>& mrrgnodes_mapped_to) const {
2404 
2405  // Mark the current node as visited
2406  visited.insert(thisNode);
2407 
2408  // Recur for all the fanout vertices
2409  for (const auto& fanoutNode : thisNode->fanout){
2410 
2411  // If a fanout node is not visited, then recur for that node
2412  if (visited.find(fanoutNode) == visited.end() && mrrgnodes_mapped_to.find(fanoutNode) != mrrgnodes_mapped_to.end())
2413  {
2414  if (isNodeInCycle(originNode, fanoutNode, visited, mrrgnodes_mapped_to))
2415  return true;
2416  }
2417  // If a fanout node is visited and
2418  // is the origin node,then there exists a cycle that the node is part of.
2419  else if (fanoutNode == originNode) {
2420  return true;
2421  }
2422  }
2423  return false;
2424 }
2425 
2426 /* Elastic Register File */
2427 ElasticRegisterFile::ElasticRegisterFile(std::string name, Location loc, int numInputPorts_, int numOutputPorts_, int log2Registers_, int size, int contexts, int eb_depth_)
2428  : Module(name, loc, size)
2429  , numInputPorts(numInputPorts_)
2430  , numOutputPorts(numOutputPorts_)
2431  , log2Registers(log2Registers_)
2432  , eb_depth(eb_depth_)
2433 {
2435  isElastic = true;
2436 
2437  if (log2Registers < 1) { make_and_throw<cgrame_error>([&](auto&& s) {
2438  s << "RegisterFile doesn't support less than 2 registers. log2Registers = " << log2Registers;
2439  });}
2440 
2441  // Generating input ports
2442  for (int i = 0; i < numInputPorts; i++)
2443  {
2444  addPort("in" + std::to_string(i), PORT_INPUT, size, isElastic); // input data
2445  addSubModule(new ElasticEagerFork("rf_input_fork" + std::to_string(i), loc, size, 1 << log2Registers, 2), 0.1 + static_cast<double>(i)/numOutputPorts, 0.1, 1.0/numInputPorts, 0.3);
2446  addConfig("rf_INPUTFork" + std::to_string(i) + "Config", {"rf_input_fork" + std::to_string(i) + ".enable_downstream"}, contexts, isElastic);
2447  connectPorts ("this.in" + std::to_string(i), "rf_input_fork" + std::to_string(i) + ".in", isElastic);
2448  }
2449 
2450  // Generating output ports
2451  for (int i = 0; i < numOutputPorts; i++)
2452  {
2453  addPort("out" + std::to_string(i), PORT_OUTPUT_REG, size, isElastic); // output ports/registers
2454  }
2455 
2456  // Generating input muxes and registers
2457  for (int i = 0; i < (1 << log2Registers); ++i) {
2458  addSubModule(new Register("reg" + std::to_string(i), loc, size, isElastic), 0.1 + static_cast<double>(i)/(1 << log2Registers), 0.3, 1.0/(1 << log2Registers),0.2);
2459  addConfig(name + "Reg" + std::to_string(i) + "Config", {"reg" + std::to_string(i) + ".enable"}, contexts, isElastic);
2460 
2461  if (numOutputPorts > 1) {
2462  addSubModule(new ElasticEagerFork("rf_output_fork" + std::to_string(i), loc, size, numOutputPorts, 2), 0.1 + i ,0.1, 1.0/numInputPorts, 0.3);
2463  addConfig("rf_OUTPUTFork" + std::to_string(i) + "Config", {"rf_output_fork" + std::to_string(i) + ".enable_downstream"}, contexts, isElastic);
2464  connectPorts ("reg" + std::to_string(i) + ".out", "rf_output_fork" + std::to_string(i) + ".in", isElastic);
2465  }
2466  if (numInputPorts > 1) {
2467  addSubModule(new Multiplexer("in_mux" + std::to_string(i), loc, numInputPorts, size, isElastic), 0.1 + static_cast<double>(i)/numOutputPorts, 0.1, 1.0/numInputPorts, 0.3);
2468  addConfig(name + "InMux" + std::to_string(i) + "Config", {"in_mux" + std::to_string(i) + ".select"}, contexts, isElastic);
2469 
2470  // Connect input mux to reg
2471  connectPorts ("in_mux" + std::to_string(i) + ".out", "reg" + std::to_string(i) + ".in", isElastic);
2472  for (int j = 0; j < numInputPorts; ++j) {
2473  connectPorts ("rf_input_fork" + std::to_string(j) + ".out" + std::to_string(i), "in_mux" + std::to_string(i) + ".in" + std::to_string(j), isElastic);
2474  }
2475  }
2476  else {
2477  connectPorts ("rf_input_fork0.out" + std::to_string(i), "reg" + std::to_string(i) + ".in", isElastic);
2478  }
2479  }
2480 
2481  // Generating output muxes
2482  for (int i = 0; i < numOutputPorts; ++i) {
2483  addSubModule(new Multiplexer("out_mux" + std::to_string(i), loc, (1 << log2Registers), size, isElastic), 0.1 + static_cast<double>(i)/numOutputPorts, 0.7, 1.0/numOutputPorts, 0.3);
2484  addConfig(name + "OutMux" + std::to_string(i) + "Config", {"out_mux" + std::to_string(i) + ".select"}, contexts, isElastic);
2485 
2486  // Connect every register to this output mux
2487  for (int j = 0; j < (1 << log2Registers); ++j) {
2488 
2489  if ( numOutputPorts > 1) {
2490  connectPorts ("rf_output_fork" + std::to_string(j) + ".out" + std::to_string(i), "out_mux" + std::to_string(i) + ".in" + std::to_string(j), isElastic);
2491  } else {
2492  connectPorts ("reg" + std::to_string(j) + ".out", "out_mux" + std::to_string(i) + ".in" + std::to_string(j), isElastic);
2493  }
2494  }
2495  connectPorts("out_mux" + std::to_string(i) + ".out", "this.out" + std::to_string(i), isElastic);
2496  }
2497 
2498  // Setting positions for nodes
2499  for (int i = 0; i < numInputPorts; i++) {
2500  setNodePosition("in" + std::to_string(i), static_cast<double>(i*log2Registers+1)/(numInputPorts*log2Registers+2), 0.1);
2501  }
2502 
2503  for (int i = 0; i < numOutputPorts; ++i) {
2504  setNodePosition("out" + std::to_string(i), static_cast<double>(i+1)/(numOutputPorts+2), 0.95);
2505  }
2506 
2507 }
2508 
2510 {
2511  return "elastic_registerFile_" + std::to_string(numInputPorts) + "in_" + std::to_string(numOutputPorts) + "out_" + std::to_string(getSize()) + "b";
2512 }
2513 
2515 {
2516 }
2517 
2518 // CoreIR Implementation of GenFunctionality
2519 nlohmann::json ElasticRegisterFile::CoreIRGenFunctionality() // Virtual function override
2520 {
2521  nlohmann::json vjson;
2522 
2523  // Create Header
2524  vjson["prefix"] = "cgrame_"; //module prefix
2525  vjson["parameters"] = {};
2526  for (auto& parameter : parameterlist)
2527  {
2528  vjson["parameters"].push_back(parameter.first);
2529  }
2530  vjson["interface"] = {};
2531  vjson["interface"].push_back("CGRA_Clock");
2532  vjson["interface"].push_back("CGRA_Reset");
2533  vjson["interface"].push_back("CGRA_Enable");
2534  for (auto& port : ports)
2535  {
2536  std::string portName = port.second->getName();
2537  vjson["interface"].push_back(portName);
2538  }
2539 
2540  // module definition
2541  std::string moduleDefinition;
2542  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
2543  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
2544  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
2545  for (auto& port : ports)
2546  {
2547  port_type portType = port.second->pt;
2548  std::string portTypeString = {};
2549  if(portType == port_type::PORT_INPUT)
2550  {
2551  portTypeString = "input";
2552  }
2553  else if (portType == port_type::PORT_OUTPUT)
2554  {
2555  portTypeString = "output";
2556  }
2557  else if (portType == port_type::PORT_OUTPUT_REG)
2558  {
2559  portTypeString = "output reg";
2560  }
2561  else
2562  {
2563  portTypeString = "inout";
2564  }
2565  std::string portSizeString;
2566  if (!(port.second->parameter).empty()) // Check if size is parameterized
2567  {
2568  std::string portParameterName = port.second->parameter;
2569  portSizeString = "[" + portParameterName + "-1:0]";
2570  }
2571  else
2572  {
2573  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
2574  }
2575  std::string portName = port.second->getName();
2576  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
2577  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
2578  }
2579 
2580  // Functionality
2581  moduleDefinition += std::string(SET_INDENT) + "// Setting the always blocks and inside registers\n";
2582  moduleDefinition += std::string(SET_INDENT) + "reg [size-1:0] register[2**log2regs-1:0];\n";
2583  moduleDefinition += std::string(SET_INDENT) + "always@(posedge CGRA_Clock, posedge CGRA_Reset)\n";
2584  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if(CGRA_Reset)\n";
2585  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "begin : RESET\n";
2586  moduleDefinition += std::string(SET_QUAD_INDENT) + "integer i;\n";
2587  moduleDefinition += std::string(SET_QUAD_INDENT) + "for (i = 0; i < 2**log2regs; i = i+1)\n";
2588  moduleDefinition += std::string(SET_PENTA_INDENT) + "register[i] = 0;\n";
2589  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
2590  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "else if (CGRA_Enable)\n";
2591  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "begin\n";
2592  for (int i = 0; i < numOutputPorts; i++)
2593  moduleDefinition += std::string(SET_QUAD_INDENT) + "out" + std::to_string(i) + " = " + "register[address_out" + std::to_string(i) + "];\n";
2594  for (int i = 0; i < numInputPorts; i++)
2595  {
2596  moduleDefinition += std::string(SET_QUAD_INDENT) + "if(WE" + std::to_string(i) + ")\n";
2597  moduleDefinition += std::string(SET_PENTA_INDENT) + "register[address_in" + std::to_string(i) + "] = in" + std::to_string(i) + ";\n";
2598  }
2599  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end";
2600 
2601  vjson["definition"] = moduleDefinition;
2602  return vjson;
2603 }
2604 
2605 /* Elastic Memory port */
2606 ElasticMemPort::ElasticMemPort(std::string name, Location loc, int size, int eb_depth_, int num_connections_, bool pred, int contexts)
2607  : Module(name, loc, size)
2608  , eb_depth(eb_depth_)
2609  , num_connections(num_connections_)
2610 {
2611  isElastic = true;
2612  // Legality checks
2613  if(num_connections < 2) { make_and_throw<cgrame_error>([&](auto&& s) {
2614  s << "ElasticMemPort doesn't support num_connections < 2. num_connections = " << num_connections;
2615  });}
2616 
2617  // Add ports
2618  for (int i = 0; i < num_connections; i++) {
2619  addPort("in" + std::to_string(i), PORT_INPUT, "size", size, isElastic);
2620  addPort("out" + std::to_string(i), PORT_OUTPUT, "size", size, isElastic);
2621  }
2622 
2623  // Add Input forks
2624  for (int i = 0; i < num_connections; i++) {
2625  addSubModule(new ElasticEagerFork("fork_in" + std::to_string(i), loc, size, 2, 2, isElastic), 0, 0, 0, 0);
2626  addConfig("ForkIn" + std::to_string(i) + "Config", {"fork_in" + std::to_string(i) + ".enable_downstream"}, contexts, isElastic);
2627  connectPorts("this.in" + std::to_string(i), "fork_in" + std::to_string(i) + ".in", isElastic);
2628  }
2629 
2630  addSubModule(new ElasticBufferFifo("mem_eb_in" , loc, eb_depth, 32), 0.0, 0.4, 0.5, 0.1);
2631  addSubModule(new ElasticBufferFifo("mem_eb_addr", loc, eb_depth, 32), 0.0, 0.4, 0.5, 0.1);
2632 
2633  //addSubModule(new ElasticBufferFifoWithEnable("mem_eb_out" , eb_depth, 32, false), 0.0, 0.4, 0.5, 0.1);
2634  // Output Fork
2635  addSubModule(new ElasticEagerFork("fork_out", loc, size, num_connections, 2), 0, 0, 0, 0);
2636 
2637  //MemUnit instantiation
2638  addSubModule(new MemoryUnit("mem_unit", loc, size, isElastic, pred), 0, 0, 0, 0);
2639 
2640  if (pred) {
2641  for (int i = 0; i < num_connections; i++)
2642  addPort("pred" + std::to_string(i), PORT_INPUT, 1, isElastic);
2643  addSubModule(new Multiplexer("mux_pred", loc, num_connections, 1, isElastic), 0.6, 0.4, 0.5, 0.2);
2644  for(int i = 0; i < num_connections; i++)
2645  connectPorts("this.pred" + std::to_string(i), "mux_pred.in" + std::to_string(i), isElastic);
2646  connectPorts("mux_pred.out", "mem_unit.pred", isElastic);
2647  addConfig("MuxPred", {"mux_pred.select"}, contexts, isElastic);
2648  }
2649 
2650  addConfig("EBEnableIn", {"mem_eb_in.enable"}, contexts, isElastic);
2651  addConfig("EBEnableAddr", {"mem_eb_addr.enable"}, contexts, isElastic);
2652  //addConfig(new ConfigCell("EBEnableOut"), {"mem_eb_out.enable"});
2653 
2654  // Add address, data MUXes
2655  addSubModule(new Multiplexer("mux_addr", loc, num_connections, size, isElastic), 0.6, 0.2, 0.5, 0.2);
2656  addSubModule(new Multiplexer("mux_data", loc, num_connections, size, isElastic), 0.6, 0.4, 0.5, 0.2);
2657  addSubModule(new Multiplexer("mux_in_out", loc, 2, size, isElastic), 0.6, 0.4, 0.5, 0.2);
2658  addSubModule(new DeMux("demux_in_out", loc, 2, 32, isElastic), 0.0, 0.6, 0.5, 0.1);
2659 
2660  addConfig("ForkOutConfig", {"fork_out.enable_downstream"}, contexts, isElastic);
2661  addConfig("MuxInOut", {"mux_in_out.select"}, contexts, isElastic);
2662  addConfig("DeMuxInOut", {"demux_in_out.select"}, contexts, isElastic);
2663  addConfig("MuxAddr", {"mux_addr.select"}, contexts, isElastic);
2664  addConfig("MuxData", {"mux_data.select"}, contexts, isElastic);
2665  addConfig("WriteEnable", {"mem_unit.w_rq"}, contexts, isElastic);
2666  for (int i = 0; i < num_connections; i++) {
2667  connectPorts("fork_in" + std::to_string(i) + ".out0", "mux_addr.in" + std::to_string(i), isElastic);
2668  connectPorts("fork_in" + std::to_string(i) + ".out1", "mux_data.in" + std::to_string(i), isElastic);
2669  }
2670 
2671  connectPorts("mux_data.out", "mux_in_out.in0", isElastic);
2672  connectPorts("mem_unit.data_out", "mux_in_out.in1", isElastic);
2673  connectPorts("mux_in_out.out", "mem_eb_in.data_in", isElastic);
2674  connectPorts("mem_eb_in.data_out", "demux_in_out.in", isElastic);
2675  connectPorts("demux_in_out.out0", "mem_unit.data_in", isElastic);
2676  connectPorts("demux_in_out.out1", "fork_out.in", isElastic);
2677  connectPorts("mux_addr.out", "mem_eb_addr.data_in", isElastic);
2678  connectPorts("mem_eb_addr.data_out", "mem_unit.addr", isElastic);
2679 
2680  for (int i = 0; i < num_connections; i++) {
2681  connectPorts("fork_out.out" + std::to_string(i) , "this.out" + std::to_string(i), isElastic);
2682  }
2683 }
2684 
2686 {
2687  return "elastic_memport_" + std::to_string(num_connections) + "conn_" + std::to_string(getSize()) + "b";
2688 }
2689 
2691 {
2692 }
2693 
2695 {
2696  return "elastic_crossbar_" + std::to_string(num_inputs) + "in_" + std::to_string(num_outputs) + "out" + "_size_" + std::to_string(data_size);
2697 }
2698 
2699 ElasticCrossbar::ElasticCrossbar(std::string name, Location loc, int num_inputs, int num_outputs, int data_size, int type, bool predExist, std::string pred_type, int contexts)
2700  : Module(name, loc, data_size)
2701  , num_inputs(num_inputs)
2702  , num_outputs(num_outputs)
2703 {
2704  bool isFull = pred_type.compare("full") == 0 & predExist;
2705  bool isPartial = pred_type.compare("partial") == 0 & predExist;
2706  if (pred_type.compare("full") != 0 & pred_type.compare("partial") != 0) {
2707  std::cout << pred_type << std::endl;
2708  throw cgrame_error("Predication type should be full or partial");
2709  }
2710  isElastic = true;
2711  if (type < 0 || type > 5) { make_and_throw<cgrame_error>([&](auto&& s) {
2712  s << "Need to insert type of elastic crossbar " << type <<"\n";
2713  s << "0: no merge and no diverge \n";
2714  s << "1: just merge and no diverge \n";
2715  s << "2: no merge and just all diverge \n";
2716  s << "3: no merge and just diverge for ALU \n";
2717  s << "4: merge and all diverge \n";
2718  s << "5: merge and diverge for ALU \n";
2719  });}
2720  int iter = 0;
2721  if (type == 3 || type == 5) {
2722  iter = 2;
2723  } else if (type == 2 || type == 4) {
2724  iter = num_inputs;
2725  }
2726  isElastic = true;
2727  if (type > 1 && type < 6) {
2728 
2729  for(int i = (num_inputs - iter); i < num_inputs; i++) {
2730  // Demux to choose between fork/diverge
2731  addSubModule(new DeMux("out_demux" + std::to_string(i), loc, 2, data_size, isElastic), 0.0, 0.6, 0.5, 0.1);
2732 
2733  // Output diverge
2734  addSubModule(new ElasticDiverge("output_diverge" + std::to_string(i), loc, data_size, num_outputs), 0.5, 0.7, 0.5, 0.1);
2735 
2736  // Output muxes
2737  for (int j = 0; j < num_outputs; j++) {
2738  addSubModule(new Multiplexer("out_mux" + std::to_string(i) + "_" + std::to_string(j), loc, 2, data_size, isElastic), 0.0, 0.9, 0.5, 0.1);
2739  }
2740  addConfig("DivergeSelectConfig" + std::to_string(i), {"output_diverge" + std::to_string(i) + ".enable_downstream"}, contexts, isElastic);
2741 
2742  std::vector<std::string> mux_out_config_conns;
2743  mux_out_config_conns.push_back("out_demux" + std::to_string(i) + ".select");
2744  for (int j = 0; j < num_outputs; j++) {
2745  mux_out_config_conns.push_back("out_mux" + std::to_string(i) + "_" + std::to_string(j) + ".select");
2746  }
2747  addConfig("MuxOutConfig" + std::to_string(i), mux_out_config_conns, contexts, isElastic);
2748  }
2749  }
2750 
2751  // 1. Create num_output muxes (each num_input in size)
2752  for(int i = 0; i < num_outputs; i++) {
2753  if (type == 0 || type == 2 || type == 3) {
2754  // Connects to regA for HyCube
2755  if (isFull){
2756  //addSubModule(new SelMultiplexer("mux_" + std::to_string(i), loc, num_inputs, data_size, isElastic), 0.2, static_cast<double>(i)/num_outputs, 0.6, 0.8/num_outputs);
2757  addSubModule(new ElasticSelMultiplexer("mux_" + std::to_string(i), loc, num_inputs, data_size, isElastic), 0.2, static_cast<double>(i)/num_outputs, 0.6, 0.8/num_outputs);
2758  }else if (isPartial) {
2759  addSubModule(new SelMultiplexer("mux_" + std::to_string(i), loc, num_inputs, data_size, isElastic), 0.2, static_cast<double>(i)/num_outputs, 0.6, 0.8/num_outputs);
2760  }
2761  else{
2762  addSubModule(new Multiplexer("mux_" + std::to_string(i), loc, num_inputs, data_size, isElastic), 0.2, static_cast<double>(i)/num_outputs, 0.6, 0.8/num_outputs);
2763  }
2764 
2765  }else if (type == 1 || type == 4 || type == 5)
2766  addSubModule(new ElasticMerge("merge_" + std::to_string(i), loc, data_size, num_inputs), 0.2, static_cast<double>(i)/num_outputs, 0.6, 0.8/num_outputs);
2767  }
2768 
2769  // 2. Create the configuration cells for each mux
2770  for(int i = 0; i < num_outputs; i++)
2771  {
2772  if (type == 0 || type == 2 || type == 3)
2773  addConfig("Mux" + std::to_string(i) + "config", {"mux_" + std::to_string(i) + ".select"}, contexts, isElastic);
2774  else if (type == 1 || type == 4 || type == 5)
2775  addConfig("Merge" + std::to_string(i) + "config", {"merge_" + std::to_string(i) + ".enable_upstream"}, contexts, isElastic);
2776  }
2777 
2778  // 3. Wiring and Ports
2779  // 3A. Create input and output ports
2780  // Input ports:
2781  for(int i = 0; i < num_inputs; i++)
2782  {
2784  if (isFull) {
2785  addSubModule(new ElasticForkBranch("fork_crossbar" + std::to_string(i), loc, data_size, num_outputs, true), 0, 0, 0, 0);
2786  } else {
2787  addSubModule(new ElasticEagerFork("fork_crossbar" + std::to_string(i), loc, data_size, num_outputs, 2), 0, 0, 0, 0);
2788  }
2789  addConfig("ForkCrossbar" + std::to_string(i) + "Config", {"fork_crossbar" + std::to_string(i) + ".enable_downstream"}, contexts, isElastic);
2790  node_relative_position.insert({"in" + std::to_string(i), {0, static_cast<double>(i)/num_inputs}}); // Add position for visualization
2791  }
2792  // If pred exist a port to get in the select predicate
2793  if (predExist){
2794  addPort("pred_in", PORT_INPUT, 1, isElastic);
2795  addSubModule(new ElasticEagerFork("fork_predicate", loc, 1, num_inputs, 2), 0, 0, 0, 0);
2796  addConfig("ForkPredicateConf", {"fork_predicate.enable_downstream"}, contexts, isElastic);
2797  connectPorts("this.pred_in", "fork_predicate.in", isElastic);
2798  }
2799 
2800  // Output ports:
2801  for(int i = 0; i < num_outputs; i++)
2802  {
2804  node_relative_position.insert({"out" + std::to_string(i), {1, static_cast<double>(i)/num_outputs}}); // Add position for visualization
2805  }
2806 
2807  for(int i = 0; i < num_inputs; i++)
2808  {
2809  if (isFull) {
2810  connectPorts("fork_predicate.out" + std::to_string(i), "fork_crossbar" + std::to_string(i) + ".condition", isElastic);
2811  }
2812  if (iter == num_inputs || iter >= (num_inputs - i)) {
2813  connectPorts("this.in"+std::to_string(i), "out_demux" + std::to_string(i) + ".in", isElastic);
2814  // Fork/Diverge select demux
2815  connectPorts("out_demux" + std::to_string(i) + ".out0", "fork_crossbar" + std::to_string(i) + ".in", isElastic);
2816  connectPorts("out_demux" + std::to_string(i) + ".out1", "output_diverge" + std::to_string(i) + ".data_in", isElastic); // TODO: change to true when diverge implemented
2817 
2818  // Output fork connections
2819  for (int j = 0; j < (num_outputs); j++) {
2820  // Downstream connections (upstream already connected)
2821  connectPorts("fork_crossbar" + std::to_string(i) + ".out" + std::to_string(j), "out_mux" + std::to_string(i) + "_" + std::to_string(j) + ".in0", isElastic);
2822  }
2823 
2824  // Output diverge connections
2825  for (int j = 0; j < (num_outputs); j++) {
2826  // Diverge -> eb connections
2827  connectPorts("output_diverge" + std::to_string(i) + ".data_out" + std::to_string(j), "out_mux" + std::to_string(i) + "_" + std::to_string(j) + ".in1", isElastic); // TODO: change to true when diverge implemented
2828  }
2829 
2830  } else {
2831  connectPorts("this.in"+std::to_string(i), "fork_crossbar" + std::to_string(i) + ".in", isElastic);
2832  }
2833  }
2834 
2835 
2836  // 3B. Wiring ports to muxes
2837  // Crossbar input ports to mux inputs:
2838  for(int j = 0; j < num_outputs; j++)
2839  {
2840  if (isPartial) {
2841  connectPorts("fork_predicate.out" + std::to_string(j), "mux_" + std::to_string(j) + ".selectpred", isElastic);
2842  }
2843  for(int i = 0; i < num_inputs; i++)
2844  {
2845  if ( type == 0 || type == 2 || type == 3) {
2846  if (iter == num_inputs || iter >= (num_inputs - i)) {
2847  connectPorts("out_mux" + std::to_string(i) + "_" + std::to_string(j) + ".out", "mux_" + std::to_string(j) + ".in" + std::to_string(i), isElastic);
2848  } else {
2849  connectPorts("fork_crossbar" + std::to_string(i) + ".out" + std::to_string(j), "mux_" + std::to_string(j) + ".in" + std::to_string(i), isElastic);
2850  }
2851  } else if ( type == 1 || type == 4 || type == 5) {
2852  if (iter == num_inputs || iter >= (num_inputs - i)) {
2853  connectPorts("out_mux" + std::to_string(i) + "_" + std::to_string(j) + ".out", "merge_" + std::to_string(j) + ".data_in" + std::to_string(i), isElastic);
2854  } else {
2855  connectPorts("fork_crossbar" + std::to_string(i) + ".out" + std::to_string(j), "merge_" + std::to_string(j) + ".data_in" + std::to_string(i), isElastic);
2856  }
2857  }
2858  }
2859  }
2860 
2861  // Mux outputs to crossbar output ports:
2862  for(int i = 0; i < num_outputs; i++)
2863  {
2864  if (type == 0 || type == 2 || type == 3) {
2865  connectPorts("mux_" + std::to_string(i) + ".out", "this.out" + std::to_string(i), isElastic);
2866  } else if (type == 1 || type == 4 || type == 5) {
2867  connectPorts("merge_" + std::to_string(i) + ".data_out", "this.out" + std::to_string(i), isElastic);
2868  }
2869  }
2870 }
2871 
2872 /************ ConfigCell **********/
2873 ElasticConfigCell::ElasticConfigCell(std::string name, int II, Location loc)
2874  : ConfigCell(name, II)
2875 {
2876  configCell_II = II;
2877  addPort("valid", PORT_INPUT, 1);
2878  addPort("stop", PORT_INPUT, 1);
2879  if (configCell_II > 1){
2880  addPort("contexts_used", PORT_OUTPUT, ceil(log2(configCell_II)));
2881  }
2882 }
2883 
2885 {
2886  nlohmann::json vjson;
2887  auto context_size = (parameterlist["contexts"] == 1) ? "0" : "$clog2(contexts)-1";
2888  // Construct Header
2889  vjson["prefix"] = "cgrame_";
2890  vjson["parameters"] = {};
2891  for (auto& parameter : parameterlist)
2892  {
2893  vjson["parameters"].push_back(parameter.first);
2894  }
2895  vjson["interface"] = {};
2896  vjson["interface"].push_back("ConfigIn");
2897  vjson["interface"].push_back("ConfigOut");
2898  vjson["interface"].push_back("Config_Clock");
2899  vjson["interface"].push_back("Config_Reset");
2900  vjson["interface"].push_back("CGRA_Clock");
2901  vjson["interface"].push_back("CGRA_Reset");
2902  vjson["interface"].push_back("CGRA_Enable");
2903  if (configCell_II > 1) {
2904  vjson["interface"].push_back("contexts_used");
2905  }
2906  vjson["interface"].push_back("select");
2907  vjson["interface"].push_back("valid");
2908  vjson["interface"].push_back("stop");
2909 
2910  // module definition
2911  std::string moduleDefinition;
2912  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
2913  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
2914  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
2915  moduleDefinition += std::string(SET_INDENT) + "input ConfigIn;\n";
2916  moduleDefinition += std::string(SET_INDENT) + "input Config_Clock;\n";
2917  moduleDefinition += std::string(SET_INDENT) + "input Config_Reset;\n";
2918  moduleDefinition += std::string(SET_INDENT) + "output ConfigOut;\n";
2919  moduleDefinition += std::string(SET_INDENT) + "input valid;\n";
2920  moduleDefinition += std::string(SET_INDENT) + "input stop;\n";
2921  moduleDefinition += std::string(SET_INDENT) + "output [size-1:0] select;\n";
2922  moduleDefinition += std::string(SET_INDENT) + "reg [size-1:0] config_reg [contexts-1:0];\n\n";
2923  moduleDefinition += std::string(SET_INDENT) + "reg [" + context_size + ":0] context_counter;\n";
2924  if (configCell_II > 1){
2925  moduleDefinition += std::string(SET_INDENT) + "output reg [" + context_size + ":0] contexts_used;\n";
2926  } else {
2927  moduleDefinition += std::string(SET_INDENT) + "reg [" + context_size + ":0] contexts_used;\n";
2928  }
2929  moduleDefinition += std::string(SET_INDENT) + "integer i;\n\n";
2930 
2931  moduleDefinition += std::string(SET_INDENT) + "always @(posedge Config_Clock, posedge Config_Reset)\n";
2932  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if (Config_Reset)\n";
2933  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "begin\n";
2934  moduleDefinition += std::string(SET_QUAD_INDENT) + "for (i = 0; i < contexts; i = i+1) begin\n";
2935  moduleDefinition += std::string(SET_PENTA_INDENT) + "config_reg[i] <= 'd0;\n";
2936  moduleDefinition += std::string(SET_QUAD_INDENT) + "end\n";
2937  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
2938  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "else\n";
2939  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "begin\n";
2940  moduleDefinition += std::string(SET_QUAD_INDENT) + "for (i = 0; i < contexts; i = i+1) begin\n";
2941  moduleDefinition += std::string(SET_PENTA_INDENT) + "if(i == 0) begin\n";
2942  if (parameterlist["size"] > 1) {
2943  if (parameterlist["contexts"] > 1) {
2944  if (parameterlist["contexts"] == 2){
2945  moduleDefinition += std::string(SET_HEXA_INDENT) + "contexts_used <= ConfigIn;\n";
2946  moduleDefinition += std::string(SET_HEXA_INDENT) + "config_reg[i] <= {contexts_used,config_reg[i][size-1:1]};\n";
2947  } else {
2948  moduleDefinition += std::string(SET_HEXA_INDENT) + "contexts_used <= {ConfigIn,contexts_used[" + context_size + ":1]};\n";
2949  moduleDefinition += std::string(SET_HEXA_INDENT) + "config_reg[i] <= {contexts_used[0],config_reg[i][size-1:1]};\n";
2950  }
2951 
2952  }
2953  else {
2954  moduleDefinition += std::string(SET_HEXA_INDENT) + "config_reg[i] <= {ConfigIn,config_reg[i][size-1:1]};\n";
2955  }
2956  moduleDefinition += std::string(SET_PENTA_INDENT) + "end\n";
2957  moduleDefinition += std::string(SET_PENTA_INDENT) + "else begin\n";
2958  moduleDefinition += std::string(SET_HEXA_INDENT) + "config_reg[i] <= {config_reg[i-1][0],config_reg[i][size-1:1]};\n";
2959  }
2960  else {
2961  if (parameterlist["contexts"]> 1) {
2962  if (parameterlist["contexts"] == 2){
2963  moduleDefinition += std::string(SET_HEXA_INDENT) + "contexts_used <= ConfigIn;\n";
2964  moduleDefinition += std::string(SET_HEXA_INDENT) + "config_reg[i] <= contexts_used;\n";
2965  } else {
2966  moduleDefinition += std::string(SET_HEXA_INDENT) + "contexts_used <= {ConfigIn,contexts_used[" + context_size + ":1]};\n";
2967  moduleDefinition += std::string(SET_HEXA_INDENT) + "config_reg[i] <= contexts_used[0];\n";
2968  }
2969  }
2970  else {
2971  moduleDefinition += std::string(SET_HEXA_INDENT) + "config_reg[i] <= ConfigIn;\n";
2972  }
2973  moduleDefinition += std::string(SET_PENTA_INDENT) + "end\n";
2974  moduleDefinition += std::string(SET_PENTA_INDENT) + "else begin\n";
2975  moduleDefinition += std::string(SET_HEXA_INDENT) + "config_reg[i] <= config_reg[i-1];\n";
2976  }
2977 
2978  moduleDefinition += std::string(SET_PENTA_INDENT) + "end\n";
2979  moduleDefinition += std::string(SET_QUAD_INDENT) + "end\n";
2980  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n\n";
2981  if (parameterlist["contexts"]> 1) {
2982  moduleDefinition += std::string(SET_INDENT) + "always @(posedge CGRA_Clock, posedge CGRA_Reset)\n";
2983  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if(CGRA_Reset)\n";
2984  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "begin\n";
2985  moduleDefinition += std::string(SET_QUAD_INDENT) + "context_counter <= 'd0;\n";
2986  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
2987  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "else if (valid && !stop) begin\n";
2988  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if(context_counter > contexts_used)\n";
2989  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "begin\n";
2990  moduleDefinition += std::string(SET_QUAD_INDENT) + "context_counter <= 'd0;\n";
2991  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
2992  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "else if(CGRA_Enable)\n";
2993  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "begin\n";
2994  moduleDefinition += std::string(SET_QUAD_INDENT) + "if(context_counter == contexts_used)\n";
2995  moduleDefinition += std::string(SET_PENTA_INDENT) + "begin\n";
2996  moduleDefinition += std::string(SET_HEXA_INDENT) + "context_counter <= 'd0;\n";
2997  moduleDefinition += std::string(SET_PENTA_INDENT) + "end\n";
2998  moduleDefinition += std::string(SET_QUAD_INDENT) + "else\n";
2999  moduleDefinition += std::string(SET_PENTA_INDENT) + "context_counter <= context_counter + 'b1;\n";
3000  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
3001  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
3002  moduleDefinition += std::string(SET_INDENT) + "assign select = config_reg[context_counter];\n";
3003  } else {
3004  moduleDefinition += std::string(SET_INDENT) + "assign select = config_reg[0];\n";
3005  }
3006  moduleDefinition += std::string(SET_INDENT) + "assign ConfigOut = config_reg[contexts-1][0];";
3007 
3008  vjson["definition"] = moduleDefinition;
3009  return vjson;
3010 }
3011 
3013 {
3014  return "elastic_configcell_context_size" + std::to_string(getStorageSize())+ "II"+std::to_string(configCell_II);
3015 }
3016 
3017 /* Elastic Lazy Fork */
3018 ElasticLazyFork::ElasticLazyFork(std::string name, Location loc, int size, int fanout_, int unit_fork_fanout_, int impl_type_)
3019  : Module(name, loc, size), fanout(fanout_), unit_fork_fanout(unit_fork_fanout_), impl_type(impl_type_)
3020 {
3022  isElastic = true;
3023  // Check module legality
3024  if (fanout <= 1) {make_and_throw<cgrame_error>([&](auto&& s) {
3025  s << "Elastic fork doesn't support fanout of <=1. Requested fanout was " << fanout;
3026  });}
3027  if (unit_fork_fanout <= 1) {make_and_throw<cgrame_error>([&](auto&& s) {
3028  s << "Elastic fork doesn't support unit fanout of <=1. Requested unit fanout was " << unit_fork_fanout;
3029  });}
3030 
3031  // Create ports
3032  addPort("valid_upstream", PORT_INPUT, 1);
3033  addPort("stop_upstream", PORT_OUTPUT, 1);
3034  addPort("in", PORT_INPUT, "size", size);
3035  node_relative_position.insert({"in", {0.25, 0.25}});
3036  node_relative_position.insert({"fork", {0.5, 0.25}});
3037  for (int i = 0; i < fanout; i++) {
3038  addPort("valid_downstream" + std::to_string(i), PORT_OUTPUT, 1);
3039  addPort("stop_downstream" + std::to_string(i), PORT_INPUT, 1);
3040  addPort("out" + std::to_string(i), PORT_OUTPUT, "size", size);
3041  node_relative_position.insert({"out" + std::to_string(i), {static_cast<double>(i)/fanout, 0.5}});
3042  }
3043  addPort("enable_downstream", PORT_INPUT, fanout);
3044 }
3045 
3047 {
3048  return "elastic_lazy_fork_1to" + std::to_string(fanout) + "_size_" + std::to_string(data_size);
3049 }
3050 
3052 {
3053  nlohmann::json vjson;
3054 
3055  // Create Header
3056  vjson["prefix"] = "cgrame_";
3057  vjson["parameters"] = {};
3058  for (auto& parameter : parameterlist)
3059  {
3060  vjson["parameters"].push_back(parameter.first);
3061  }
3062  vjson["interface"] = {};
3063 
3064  for (auto& port : ports)
3065  {
3066  std::string portName = port.second->getName();
3067  vjson["interface"].push_back(portName);
3068  }
3069 
3070  // module definition
3071  std::string moduleDefinition;
3072  for (auto& port : ports)
3073  {
3074  port_type portType = port.second->pt;
3075  std::string portTypeString = {};
3076  if(portType == port_type::PORT_INPUT)
3077  {
3078  portTypeString = "input";
3079  }
3080  else if (portType == port_type::PORT_OUTPUT)
3081  {
3082  portTypeString = "output";
3083  }
3084  else if (portType == port_type::PORT_OUTPUT_REG)
3085  {
3086  portTypeString = "output reg";
3087  }
3088  else
3089  {
3090  portTypeString = "inout";
3091  }
3092  std::string portSizeString;
3093  if (!(port.second->parameter).empty()) // Check if size is parameterized
3094  {
3095  std::string portParameterName = port.second->parameter;
3096  portSizeString = "[" + portParameterName + "-1:0]";
3097  }
3098  else
3099  {
3100  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
3101  }
3102  std::string portName = port.second->getName();
3103  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
3104  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
3105  }
3106 
3107  // Functionality
3108  moduleDefinition += std::string(SET_INDENT) + "elastic_lazy_fork #(";
3109  moduleDefinition += ".FANOUT(" + std::to_string(fanout) + "), ";
3110  moduleDefinition += ".UNIT_FORK_FANOUT(" + std::to_string(unit_fork_fanout) + "), ";
3111  moduleDefinition += ".IMPLEMENTATION_TYPE(" + std::to_string(impl_type) + ") efork (\n";
3112  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".valid_upstream(valid_upstream),\n";
3113  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".stop_upstream(stop_upstream),\n";
3114 
3115  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".valid_downstream({";
3116  for (int i = fanout-1; i > 0; i--)
3117  moduleDefinition += "valid_downstream" + std::to_string(i) + ", ";
3118  moduleDefinition += "valid_downstream0}),\n";
3119 
3120  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".stop_downstream({";
3121  for (int i = fanout-1; i > 0; i--)
3122  moduleDefinition += "stop_downstream" + std::to_string(i) + ", ";
3123  moduleDefinition += "stop_downstream0}),\n";
3124 
3125  moduleDefinition += std::string(SET_DOUBLE_INDENT) + ".enable_downstream(enable_downstream)\n";
3126  moduleDefinition += std::string(SET_INDENT) + ");\n";
3127 
3128  moduleDefinition += "\n";
3129  for (int i = 0; i < fanout; i++)
3130  moduleDefinition += std::string(SET_INDENT) + "assign out" + std::to_string(i) + " = in;\n";
3131 
3132  vjson["definition"] = moduleDefinition;
3133  return vjson;
3134 }
3135 
3137 { // Empty destructor
3138 }
3139 
3141 {
3142 
3143  MRRG* result_ptr = new MRRG(II);
3144  auto& result = *result_ptr;
3145 
3146  for (unsigned i = 0; i < II; i++)
3147  {
3148  // Create nodes and link them, we make this module look like a demux to the mapper
3149  MRRG::NodeDescriptor in = result.insert(MRRGNode::make_routing(this, data_size, i, "in", 0)).first;
3150  MRRG::NodeDescriptor fork = result.insert(MRRGNode::make_routing(this, data_size, i, "fork", 0)).first;
3151  result.link(in, fork);
3152  for (int j = 0; j < fanout; j++) {
3153  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "out" + std::to_string(j), 0)).first;
3154  result.link(fork, out);
3155  }
3156  }
3157 
3158  return result_ptr;
3159 }
3160 
3162  const MRRG& mrrg, const OpGraph & og,
3163  const Mapping& map,
3164  const ConfigCell& ccell,
3165  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
3166  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
3167 ) const {
3168  (void)ccell;
3169  (void)mrrg_nodes_from_op_node;
3170  const std::vector<std::regex> required_node_regexes {
3171  std::regex("\\.fork$"), std::regex("\\.in$"),
3172  };
3173  const std::regex in_regex("\\.out([0-9]+)$");
3174  BitConfig bitConfig(mrrg.initiationInterval());
3175 
3176  // Organize nodes mapping by cycle
3177  std::vector<MRRGNodesFromValNode> valNodesByCycle(mrrg.initiationInterval());
3178  for (const auto& val_and_mrrg_nodes : mrrg_nodes_from_val_node) {
3179  for (const auto& mrrg_node : val_and_mrrg_nodes.second) {
3180  valNodesByCycle[mrrg_node->cycle][val_and_mrrg_nodes.first].insert(mrrg_node);
3181  }
3182  }
3183 
3184  int cycle = 0;
3185  int used_cycles = 0;
3186  for (auto & mrrg_nodes_from_val_per_cycle : valNodesByCycle) {
3187  std::unordered_set<int> inputs_used;
3188 
3189  for (const auto& val_node_and_mrrg_nodes : mrrg_nodes_from_val_per_cycle) {
3190  // Check for required nodes: .demux and .in
3191  std::vector<bool> required_node_types_found;
3192  for (const auto& req_node_regex : required_node_regexes) {
3193  required_node_types_found.push_back(false);
3194  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
3195  std::smatch match_results;
3196  if (std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, req_node_regex)) {
3197  if (required_node_types_found.back()) {
3198  throw cgrame_error("found a node that matched two required node regexes");
3199  } else {
3200  required_node_types_found.back() = true;
3201  }
3202  }
3203  }
3204  }
3205 
3206  // Check for which outputs are used in the mapping
3207  if (std::all_of(begin(required_node_types_found), end(required_node_types_found), [&](auto&& v) { return v; })) {
3208  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
3209  std::smatch match_results;
3210  std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, in_regex);
3211  if (match_results.size() == 2) {
3212  inputs_used.insert(stoi(match_results[1].str()));
3213  }
3214  }
3215  } else {
3216  // ignore the val
3217  }
3218  }
3219 
3220  if (inputs_used.empty()) {
3221  bitConfig.add({(size_t) fanout, BitSetting::DONT_CARE_PREFER_LOW}, cycle);
3222  } else {
3223  // Create the bit settings, in a one-hot manner
3224  used_cycles++;
3225  unsigned bit_settings = 0;
3226  for (const auto& input_num : inputs_used) {
3227  bit_settings |= (1U << (unsigned) input_num);
3228  }
3229  bitConfig.add(bitsettings_from_int((int) bit_settings, fanout), cycle);
3230  }
3231  ++cycle;
3232  }
3233  bitConfig.setUsedCycles(used_cycles);
3234  return bitConfig;
3235 }
ElasticBufferFifo
Definition: ModuleElastic.h:10
OpCode::BR
@ BR
ElasticEagerFork
Definition: ModuleElastic.h:34
MRRG_NODE_ROUTING_FUNCTION
@ MRRG_NODE_ROUTING_FUNCTION
Definition: MRRG.h:47
BitSetting::HIGH
@ HIGH
BitConfig
Definition: BitSetting.h:58
ElasticLazyFork::createMRRG
MRRG * createMRRG(unsigned II) override
Definition: ModuleElastic.cpp:3140
ElasticMerge::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:1497
Module::name
std::string name
Definition: Module.h:341
ConfigCell
Definition: Module.h:825
ElasticLazyFork::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:3046
ElasticEagerFork::ElasticEagerFork
ElasticEagerFork(std::string name, Location, int size, int fanout_=DEFAULT_FANIN_FANOUT, int unit_fork_fanout_=DEFAULT_FANIN_FANOUT, bool isElastic=true)
Definition: ModuleElastic.cpp:586
ElasticVLUWrapper::createMRRG
MRRG * createMRRG(unsigned II) override
Definition: ModuleElastic.cpp:2058
ElasticJoin::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:843
Multiplexer
Zero-cycle latency multiplexer.
Definition: Module.h:592
ElasticMemPort::eb_depth
int eb_depth
Definition: ModuleElastic.h:293
ElasticSelMultiplexer
Definition: ModuleElastic.h:82
ElasticSelMultiplexer::createMRRG
MRRG * createMRRG(unsigned II) override
Definition: ModuleElastic.cpp:1321
ElasticLazyFork::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleElastic.cpp:3051
ElasticDiverge::ElasticDiverge
ElasticDiverge(std::string name, Location, int size=DEFAULT_SIZE, int fanout_=DEFAULT_FANIN_FANOUT)
Definition: ModuleElastic.cpp:1038
FPUnit_wrapper::max_latency
int max_latency
Definition: ModuleElastic.h:221
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
OpCode::PHI
@ PHI
MRRGNodesFromOpNode
std::map< OpGraphOp *, std::set< MRRG::NodeDescriptor > > MRRGNodesFromOpNode
Definition: Module.h:146
ElasticForkBranch::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: ModuleElastic.cpp:402
ElasticEagerFork::createMRRG
MRRG * createMRRG(unsigned II) override
Definition: ModuleElastic.cpp:719
Location
Definition: Module.h:156
ElasticEagerFork::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: ModuleElastic.cpp:740
Module::data_size
unsigned data_size
Definition: Module.h:338
Mapping::getSingleMapping
MRRG::NodeDescriptor getSingleMapping(OpGraph::NodeDescriptor key) const
Definition: Mapping.h:56
Operands::BINARY_LHS
static constexpr auto & BINARY_LHS
Definition: OpGraph.h:89
ModuleElastic.h
ElasticForkBranch::createMRRG
MRRG * createMRRG(unsigned II) override
Definition: ModuleElastic.cpp:377
ElasticMemPort::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:2685
ElasticRegisterFile::numInputPorts
int numInputPorts
Definition: ModuleElastic.h:254
ElasticDiverge::fanout
int fanout
Definition: ModuleElastic.h:165
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
ElasticBufferFifo::ElasticBufferFifo
ElasticBufferFifo(std::string name, Location, int depth_=DEFAULT_EB_DEPTH, int size=DEFAULT_SIZE, bool hasEnable_=true, bool isElastic=true)
Definition: ModuleElastic.cpp:7
SET_PENTA_INDENT
const char *const SET_PENTA_INDENT
Definition: Module.h:41
Module.h
ElasticEagerFork::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleElastic.cpp:617
ElasticRegisterFile::~ElasticRegisterFile
virtual ~ElasticRegisterFile()
Definition: ModuleElastic.cpp:2514
ElasticTokenInducer::~ElasticTokenInducer
virtual ~ElasticTokenInducer()
Definition: ModuleElastic.cpp:2311
ElasticCrossbar::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:2694
Module::addParameter
void addParameter(std::string parameterName, unsigned parameterValue)
Definition: Module.cpp:1503
ElasticSelMultiplexer::all_modes
static const std::map< OpGraphOpCode, LLVMMode > all_modes
Definition: ModuleElastic.h:84
Module::adds_synchronous_circuitry
bool adds_synchronous_circuitry
Definition: Module.h:370
FPUnit_wrapper::supported_modes
std::vector< OpGraphOpCode > supported_modes
Definition: ModuleElastic.h:220
Mapping::getOpGraph
OpGraph & getOpGraph()
Definition: Mapping.h:82
SET_HEXA_INDENT
const char *const SET_HEXA_INDENT
Definition: Module.h:42
makeNodeGetterForCycle
auto makeNodeGetterForCycle(M &mrrg, int cycle)
Definition: MRRG.h:401
OpCode::SELECT
@ SELECT
ElasticLazyFork::unit_fork_fanout
int unit_fork_fanout
Definition: ModuleElastic.h:121
ElasticJoin::~ElasticJoin
virtual ~ElasticJoin()
Definition: ModuleElastic.cpp:933
OpGraph::valNodes
auto & valNodes() const
Definition: OpGraph.h:314
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
BitSetting::DONT_CARE_PREFER_LOW
@ DONT_CARE_PREFER_LOW
Mapping::getMappingList
const std::vector< MRRG::NodeDescriptor > & getMappingList(OpGraph::NodeDescriptor key) const
Definition: Mapping.h:57
Register
A simple latency element with an enable signal; a data flip-flop.
Definition: Module.h:566
ElasticSelMultiplexer::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleElastic.cpp:1220
ElasticJoin::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleElastic.cpp:848
BitConfig::add
void add(std::vector< BitSetting > bitsetting, int cycle)
Definition: BitSetting.h:63
Module::addPort
void addPort(std::string portname, port_type pt, unsigned size)
Definition: Module.cpp:1354
Module::node_relative_position
std::map< std::string, VisualPositionPoint > node_relative_position
Definition: Module.h:360
ElasticTokenInducer::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleElastic.cpp:2210
ElasticMemPort::~ElasticMemPort
virtual ~ElasticMemPort()
Definition: ModuleElastic.cpp:2690
FPUnit_wrapper::FPUnit_wrapper
FPUnit_wrapper(std::string name, Location, int max_latency, std::vector< OpGraphOpCode > supported_modes)
Definition: ModuleElastic.cpp:1709
ElasticLazyFork::~ElasticLazyFork
virtual ~ElasticLazyFork()
Definition: ModuleElastic.cpp:3136
ElasticLazyFork::impl_type
int impl_type
Definition: ModuleElastic.h:123
ElasticDiverge::createMRRG
MRRG * createMRRG(unsigned II) override
Definition: ModuleElastic.cpp:1168
ElasticRegisterFile::log2Registers
int log2Registers
Definition: ModuleElastic.h:256
ElasticLazyFork::ElasticLazyFork
ElasticLazyFork(std::string name, Location, int size=DEFAULT_SIZE, int fanout_=DEFAULT_FANIN_FANOUT, int unit_fork_fanout_=DEFAULT_FANIN_FANOUT, int impl_type_=DEFAULT_LFORK_IMPL)
Definition: ModuleElastic.cpp:3018
ElasticForkBranch::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleElastic.cpp:248
ElasticForkBranch::fanout
int fanout
Definition: ModuleElastic.h:76
ElasticCrossbar::num_outputs
int num_outputs
Definition: ModuleElastic.h:282
ElasticMerge::fanin
int fanin
Definition: ModuleElastic.h:186
ModuleFPUnit.h
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
FPUnit_wrapper
Definition: ModuleElastic.h:202
ElasticForkBranch::ElasticForkBranch
ElasticForkBranch(std::string name, Location, int size, int fanout_=DEFAULT_FANIN_FANOUT, bool isElastic=true)
Definition: ModuleElastic.cpp:218
ElasticEagerFork::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:612
ElasticBufferFifo::getDepth
int getDepth() const
Definition: ModuleElastic.h:18
ElasticSelMultiplexer::~ElasticSelMultiplexer
virtual ~ElasticSelMultiplexer()
Definition: ModuleElastic.cpp:1317
FPUnit_wrapper::~FPUnit_wrapper
virtual ~FPUnit_wrapper()
Definition: ModuleElastic.cpp:1861
ElasticVLUWrapper::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:1960
ElasticJoin::ElasticJoin
ElasticJoin(std::string name, Location, int size=DEFAULT_SIZE, int fanin_=DEFAULT_FANIN_FANOUT, bool isElastic=true)
Definition: ModuleElastic.cpp:818
ElasticTokenInducer::createMRRG
MRRG * createMRRG(unsigned II) override
Definition: ModuleElastic.cpp:2315
ElasticTokenInducer::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: ModuleElastic.cpp:2336
MRRGNodesFromValNode
std::map< OpGraphVal *, std::set< MRRG::NodeDescriptor > > MRRGNodesFromValNode
Definition: Module.h:147
ElasticVLUWrapper::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleElastic.cpp:1965
BitSetting::LOW
@ LOW
ElasticRegisterFile::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleElastic.cpp:2519
Mapping
Definition: Mapping.h:31
ElasticFPUnit::ElasticFPUnit
ElasticFPUnit(std::string name, Location loc, std::vector< OpGraphOpCode > supported_modes_, unsigned size, int II, int latency, bool predExist, bool isElastic, int contexts=1)
Definition: ModuleElastic.cpp:2136
PORT_CONFIG
@ PORT_CONFIG
Definition: Module.h:67
ElasticVLUWrapper::~ElasticVLUWrapper
virtual ~ElasticVLUWrapper()
Definition: ModuleElastic.cpp:2054
Operands::BINARY_RHS
static constexpr auto & BINARY_RHS
Definition: OpGraph.h:90
ElasticTokenInducer::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:2205
ElasticConfigCell::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:3012
MRRG::fanout
auto & fanout(NodeDescriptor ndesc) const
Definition: MRRG.h:288
ElasticTokenInducer::isNodeInCycle
bool isNodeInCycle(const MRRGNode *originNode, const MRRGNode *thisNode, std::set< const MRRGNode * > &visited, std::set< const MRRGNode * > &mrrgnodes_mapped_to) const
Definition: ModuleElastic.cpp:2403
FPUnit_wrapper::all_modes
static const std::map< OpGraphOpCode, LLVMMode > all_modes
Definition: ModuleElastic.h:218
MRRGNode::make_operand_pin
static MRRGNode make_operand_pin(Module *parent, int bitwidth, int cycle, STR &&name, SupportedOpTags operand_tags, int latency=0, int max_cap=1)
Definition: MRRG.h:164
ElasticJoin::fanin
int fanin
Definition: ModuleElastic.h:144
ElasticSelMultiplexer::mux_size
int mux_size
Definition: ModuleElastic.h:100
ElasticForkBranch::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:243
ElasticDiverge::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: ModuleElastic.cpp:1174
ElasticDiverge
Definition: ModuleElastic.h:148
ElasticTokenInducer::ElasticTokenInducer
ElasticTokenInducer(std::string name, Location, int size=DEFAULT_SIZE, int iteration_interval=2, bool isEalstic=true)
Definition: ModuleElastic.cpp:2184
ElasticRegisterFile::ElasticRegisterFile
ElasticRegisterFile(std::string name, Location, int numInputPorts, int numOutputPorts, int log2Registers, int size=DEFAULT_SIZE, int contexts=1, int eb_depth=DEFAULT_EB_DEPTH)
Definition: ModuleElastic.cpp:2427
ElasticMemPort::num_connections
int num_connections
Definition: ModuleElastic.h:294
OpGraph::opNodes
auto & opNodes() const
Definition: OpGraph.h:313
ElasticMerge::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleElastic.cpp:1502
MRRG_NODE_FUNCTION
@ MRRG_NODE_FUNCTION
Definition: MRRG.h:46
FPUnit
Definition: ModuleFPUnit.h:91
ElasticBufferFifo::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleElastic.cpp:35
ElasticForkBranch::all_modes
static const std::map< OpGraphOpCode, LLVMMode > all_modes
Definition: ModuleElastic.h:61
ElasticDiverge::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleElastic.cpp:1066
SET_INDENT
const char *const SET_INDENT
Definition: Module.h:37
Module
Definition: Module.h:163
PORT_INPUT
@ PORT_INPUT
Definition: Module.h:63
ElasticCrossbar::ElasticCrossbar
ElasticCrossbar(std::string name, Location, int num_inputs, int num_outputs, int data_size, int type, bool predExist=false, std::string pred_type="full", int contexts=1)
Definition: ModuleElastic.cpp:2699
OpCode::FMUL
@ FMUL
ElasticMerge::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: ModuleElastic.cpp:1623
ElasticTokenInducer::iteration_interval
int iteration_interval
Definition: ModuleElastic.h:241
FPUnit_wrapper::createMRRG
MRRG * createMRRG(unsigned II) override
Definition: ModuleElastic.cpp:1913
FPUnit_wrapper::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:1723
ElasticJoin
Definition: ModuleElastic.h:127
OpCode::FDIV
@ FDIV
Module::addConfig
void addConfig(ConfigCell *c, std::vector< std::string > ConnectTo)
Definition: Module.cpp:1087
ElasticTokenInducer
Definition: ModuleElastic.h:224
ElasticConfigCell::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleElastic.cpp:2884
end
auto end(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:138
OpCode::SQRT
@ SQRT
ElasticMerge::createMRRG
MRRG * createMRRG(unsigned II) override
Definition: ModuleElastic.cpp:1602
ElasticRegisterFile::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:2509
ElasticForkBranch
Definition: ModuleElastic.h:58
ElasticMerge::~ElasticMerge
virtual ~ElasticMerge()
Definition: ModuleElastic.cpp:1598
ElasticConfigCell
Definition: ModuleElastic.h:318
OpGraphOp
Definition: OpGraph.h:131
ElasticDiverge::~ElasticDiverge
virtual ~ElasticDiverge()
Definition: ModuleElastic.cpp:1164
ElasticMemPort::ElasticMemPort
ElasticMemPort(std::string name, Location, int size=DEFAULT_SIZE, int eb_depth=DEFAULT_EB_DEPTH, int num_connections=2, bool pred=false, int contexts=1)
Definition: ModuleElastic.cpp:2606
MRRGNode
Definition: MRRG.h:60
Module::getSize
int getSize() const
Definition: Module.h:246
ElasticMerge
Definition: ModuleElastic.h:169
ElasticCrossbar::num_inputs
int num_inputs
Definition: ModuleElastic.h:281
ElasticSelMultiplexer::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: ModuleElastic.cpp:1341
ElasticEagerFork::unit_fork_fanout
int unit_fork_fanout
Definition: ModuleElastic.h:52
Module::addSubModule
void addSubModule(Module *m)
Definition: Module.cpp:1124
ElasticBufferFifo::createMRRG
MRRG * createMRRG(unsigned II) override
Definition: ModuleElastic.cpp:194
ElasticFuncUnit::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:2080
MRRGNode::fanout
std::vector< MRRGNode * > fanout
Definition: MRRG.h:113
BitConfig::setUsedCycles
void setUsedCycles(int uc)
Definition: BitSetting.h:67
ElasticEagerFork::~ElasticEagerFork
virtual ~ElasticEagerFork()
Definition: ModuleElastic.cpp:715
MemoryUnit
Single load & store memory operations.
Definition: Module.h:517
Module::isElastic
bool isElastic
Definition: Module.h:236
ElasticEagerFork::fanout
int fanout
Definition: ModuleElastic.h:55
SET_DOUBLE_INDENT
const char *const SET_DOUBLE_INDENT
Definition: Module.h:38
Module::ports
std::map< std::string, Port * > ports
Definition: Module.h:225
Module::loc
Location loc
Definition: Module.h:239
SelMultiplexer
2 Zero-cycle latency multiplexers for predication support.
Definition: Module.h:647
MRRG::initiationInterval
int initiationInterval() const
Definition: MRRG.h:346
ElasticForkBranch::~ElasticForkBranch
virtual ~ElasticForkBranch()
Definition: ModuleElastic.cpp:373
ElasticBufferFifo::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: ModuleElastic.cpp:136
ElasticSelMultiplexer::ElasticSelMultiplexer
ElasticSelMultiplexer(std::string, Location, unsigned mux_size, unsigned size=DEFAULT_SIZE, bool isElastic=false)
Definition: ModuleElastic.cpp:1193
ElasticVLUWrapper::input_count
int input_count
Definition: ModuleElastic.h:199
ElasticLazyFork::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: ModuleElastic.cpp:3161
ElasticConfigCell::ElasticConfigCell
ElasticConfigCell(std::string name, int iteration_interval=1, Location loc={0, 0})
Definition: ModuleElastic.cpp:2873
ElasticFuncUnit::ElasticFuncUnit
ElasticFuncUnit(std::string name, Location loc, std::vector< OpGraphOpCode > supported_modes_, unsigned size, int II, int latency, bool predExist, bool isElastic, int contexts=1)
Definition: ModuleElastic.cpp:2087
DeMux
Zero-cycle latency DeMultiplexer.
Definition: Module.h:676
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
Operands::BINARY_ANY
static constexpr auto & BINARY_ANY
Definition: OpGraph.h:91
port_type
port_type
Definition: Module.h:61
ElasticDiverge::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:1061
FPUnit_wrapper::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: ModuleElastic.cpp:1868
ElasticBufferFifo::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:28
FPUnit_wrapper::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleElastic.cpp:1729
ElasticJoin::createMRRG
MRRG * createMRRG(unsigned II) override
Definition: ModuleElastic.cpp:937
ElasticJoin::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: ModuleElastic.cpp:960
ElasticFPUnit::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:2129
Module::connectPorts
void connectPorts(std::string src, std::string dst, bool isElastic)
Definition: Module.cpp:1232
MRRGNode::make_routing_function
static MRRGNode make_routing_function(Module *parent, int bitwidth, int cycle, STR &&name, int latency, SupportedOpTags operand_tags, SupportedOps supported_ops, int max_cap=1)
Definition: MRRG.h:177
FuncUnit
Functional Unit, does one of a set of arithmetic computations.
Definition: Module.h:406
ElasticMerge::ElasticMerge
ElasticMerge(std::string name, Location, int size=DEFAULT_SIZE, int fanin_=DEFAULT_FANIN_FANOUT)
Definition: ModuleElastic.cpp:1472
Operands::PREDICATE
static constexpr auto & PREDICATE
Definition: OpGraph.h:88
OpCode::FADD
@ FADD
OpGraph
Definition: OpGraph.h:215
ElasticSelMultiplexer::GenericName
virtual std::string GenericName() override
Definition: ModuleElastic.cpp:1214
ElasticVLUWrapper::ElasticVLUWrapper
ElasticVLUWrapper(std::string name, Location, int size=DEFAULT_SIZE, int input_count_=1)
Definition: ModuleElastic.cpp:1930
ElasticBufferFifo::hasEnable
bool hasEnable
Definition: ModuleElastic.h:31
ElasticRegisterFile::numOutputPorts
int numOutputPorts
Definition: ModuleElastic.h:255
ConfigCell::getStorageSize
int getStorageSize() const
Definition: Module.h:832
cgrame_error
Definition: Exception.h:20
ElasticBufferFifo::~ElasticBufferFifo
virtual ~ElasticBufferFifo()
Definition: ModuleElastic.cpp:190
ElasticLazyFork::fanout
int fanout
Definition: ModuleElastic.h:122
ElasticConfigCell::configCell_II
int configCell_II
Definition: ModuleElastic.h:324
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