CGRA-ME
ModulePredicationUnit.cpp
Go to the documentation of this file.
1 /*
2 oftware programs comprising "CGRA-ME" and the documentation provided
3  * with them are copyright by its authors and the University of Toronto. Only
4  * non-commercial, not-for-profit use of this software is permitted without ex-
5  * plicit permission. This software is provided "as is" with no warranties or
6  * guarantees of support. See the LICENCE for more details. You should have re-
7  * ceived a copy of the full licence along with this software. If not, see
8  * <http://cgra-me.ece.utoronto.ca/license/>.
9  ******************************************************************************/
10 
11 #include <CGRA/Module.h>
12 
13 #include <regex>
14 // maps for the modes of each type of comparator
15 const std::map<OpGraphOpCode, LLVMMode> Compare::all_modes =
16  {
17  {OpCode::CMP, {"op_icmp", "cmp", {"cmp"}, "cmp_sel"}},
18 };
19 
20 /************ Compare **********/
21 Compare::Compare(std::string name, Location loc, unsigned size, int II)
22  : Module(name, loc, size)
23 {
25  // Create ports
26  addPort("in_a", PORT_INPUT, size);
27  addPort("in_b", PORT_INPUT, size);
28  addPort("out", PORT_OUTPUT, size);
29  addPort("select", PORT_CONFIG, 3);
30 
31  // add position for visualization
32 };
33 
34 // Virtual function that overrides Module::GenericName. Returns generic name of the object
35 std::string Compare::GenericName() // Virtual function override
36 {
37  return "Compare_" + std::to_string(getSize()) + "b";
38 }
39 
40 // CoreIR Implementation of GenFunctionality
41 nlohmann::json Compare::CoreIRGenFunctionality() // Virtual function override
42 {
43  nlohmann::json vjson;
44 
45  // Create Header
46  vjson["prefix"] = "cgrame_";
47  vjson["parameters"] = {};
48 
49  for (auto &parameter : parameterlist)
50  {
51  vjson["parameters"].push_back(parameter.first);
52  }
53  vjson["interface"] = {};
54  //vjson["interface"].push_back("CGRA_PHI_Enable");
55 
56  for (auto &port : ports)
57  {
58  std::string portName = port.second->getName();
59  vjson["interface"].push_back(portName);
60  }
61 
62  // module definition
63  std::string moduleDefinition;
64 
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 
100  // Functionality
101  moduleDefinition += std::string(SET_INDENT) + "wire pred;\n";
102  moduleDefinition += std::string(SET_INDENT) + "always @(*) begin\n";
103  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if (select == 3'b000) begin\n";
104  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "out <= 1b'0;\n";
105  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end else if (select == 3'b001) begin\n";
106  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "out <= in_a == in_b;\n";
107  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end else if (select == 3'b010) begin\n";
108  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "out <= in_a != in_b;\n";
109  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end else if (select == 3'b011) begin\n";
110  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "out <= in_a > in_b;\n";
111  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end else if (select == 3'b100) begin\n";
112  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "out <= in_a >= in_b;\n";
113  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end else if (select == 3'b101) begin\n";
114  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "out <= in_a < in_b;\n";
115  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end else if (select == 3'b110) begin\n";
116  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "out <= in_a <= in_b;\n";
117  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end else begin\n";
118  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "pred <= 1b'0;\n";
119  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
120  moduleDefinition += std::string(SET_INDENT) + "end\n";
121  moduleDefinition += std::string(SET_INDENT) + "assign out = {pred} \n";
122 
123  vjson["definition"] = moduleDefinition;
124 
125  return vjson;
126 }
127 
129 {
130 }
131 
132 MRRG *Compare::createMRRG(unsigned II = 1)
133 {
134 
135  MRRG *result_ptr = new MRRG(II);
136  auto &result = *result_ptr;
137 
138  for (unsigned i = 0; i < II; i++)
139  {
140 
141  // input and function node
142  MRRG::NodeDescriptor in = result.insert(MRRGNode::make_routing(this, data_size, i, "in")).first;
143  MRRG::NodeDescriptor cmp = result.insert(MRRGNode::make_function(this, data_size, i, "cmp_inst", 0, {OpCode::CMP})).first;
144  // output node
145  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "out")).first;
146  // Linking the function to the inputs and the outputs
147  result.link(in, cmp);
148  result.link(cmp, out);
149  }
150 
151  return result_ptr;
152 }
153 
155  const MRRG &mrrg, const OpGraph &og,
156  const Mapping &map,
157  const ConfigCell &ccell,
158  const MRRGNodesFromOpNode &mrrg_nodes_from_op_node,
159  const MRRGNodesFromValNode &mrrg_nodes_from_val_node) const
160 {
161  (void)ccell;
162 
163  BitConfig bitConfig(mrrg.initiationInterval());
164 
165  // Organize nodes mapping by cycle
166  std::vector<MRRGNodesFromOpNode> opNodesByCycle(mrrg.initiationInterval());
167  for (const auto &op_and_mrrg_nodes : mrrg_nodes_from_op_node)
168  {
169  for (const auto &mrrg_node : op_and_mrrg_nodes.second)
170  {
171  opNodesByCycle[mrrg_node->cycle][op_and_mrrg_nodes.first].insert(mrrg_node);
172  }
173  }
174 
175  int cycle = 0;
176  for (auto &mrrg_nodes_from_op_node_per_cycle : opNodesByCycle)
177  {
178  if (mrrg_nodes_from_op_node_per_cycle.empty())
179  {
180  bitConfig.add({2, BitSetting::LOW}, cycle);
181  }
182  else
183  {
184  if (mrrg_nodes_from_op_node_per_cycle.size() != 1)
185  {
186  make_and_throw<std::logic_error>([&](auto &&s)
187  { s << "This opgraph_op node is mapped to multiple MRRG nodes\n"; });
188  }
189  else if (std::begin(mrrg_nodes_from_op_node_per_cycle)->first->opcode != OpCode::CMP)
190  {
191  make_and_throw<std::logic_error>([&](auto &&s)
192  { s << "A non compare op was mapped to this compare unit\n"; });
193  }
194  std::string cmpMode = std::begin(mrrg_nodes_from_op_node_per_cycle)->first->cmpMode;
195  std::vector<BitSetting> result;
196  if (cmpMode.compare("EQ") == 0)
197  {
198  bitConfig.add(bitsettings_from_int((int)1, 2), cycle);
199  }
200  else if (cmpMode.compare("NE") == 0)
201  {
202  bitConfig.add(bitsettings_from_int((int)2, 2), cycle);
203  }
204  else if (cmpMode.compare("GT") == 0)
205  {
206  bitConfig.add(bitsettings_from_int((int)3, 2), cycle);
207  }
208  else if (cmpMode.compare("GE") == 0)
209  {
210  bitConfig.add(bitsettings_from_int((int)4, 2), cycle);
211  }
212  else if (cmpMode.compare("LT") == 0)
213  {
214  bitConfig.add(bitsettings_from_int((int)5, 2), cycle);
215  }
216  else if (cmpMode.compare("LE") == 0)
217  {
218  bitConfig.add(bitsettings_from_int((int)6, 2), cycle);
219  }
220  else
221  {
222  make_and_throw<std::logic_error>([&](auto &&s)
223  { s << "An unrecognized compare instruction mode entered\n"; });
224  }
225  // bitConfig.add(result, cycle);
226  }
227  ++cycle;
228  }
229 
230  return bitConfig;
231 }
232 
233 /************ SelMultiplexer **********/
234 const std::map<OpGraphOpCode, LLVMMode> SelMultiplexer::all_modes =
235  {
236  {OpCode::SELECT, {"op_sel", "sel", {"sel"}, "sel_sel"}},
237  {OpCode::PHI, {"op_phi", "phi", {"phi"}, "phi_sel"}}
238  };
239 
240 /************ SelMultiplexer **********/
241 SelMultiplexer::SelMultiplexer(std::string name, Location loc, unsigned mux_size_, unsigned size, bool isElastic)
242  : Module(name, loc, size, isElastic)
243  , mux_size(mux_size_)
244  {
245 
247  if (mux_size <= 1) { make_and_throw<cgrame_error>([&](auto&& s) {
248  s << "Multiplexer doesn't support mux_size <= 1. mux_size = " << mux_size;
249  });}
250 
251  // Create ports
252  for(int i = 0; i < mux_size; i++) {
253  addPort("in" + std::to_string(i), PORT_INPUT, "size", size, isElastic);
254  }
255 
256  addPort("out", PORT_OUTPUT_REG, "size", size, isElastic);
257 
258  // select port to control small mux
259  addPort("select", PORT_CONFIG, 2* ceil(log2(mux_size)), isElastic);
260 
261  // select port to control the bigger mux
262  addPort("selectpred", PORT_INPUT, 1, isElastic);
263 
264 }
265 // Virtual function that overrides Module::GenericName. Returns generic name of the object
266 std::string SelMultiplexer::GenericName() // Virtual function override
267 {
268  return "sel_mux_" + std::to_string(mux_size) + "to1_" + std::to_string(getSize()) + "b";
269 }
270 
271 // CoreIR Implementation of GenFunctionality
272 nlohmann::json SelMultiplexer::CoreIRGenFunctionality() // Virtual function override
273 {
274  nlohmann::json vjson;
275 
276  // Create Header
277  vjson["prefix"] = "cgrame_"; //module prefix
278  vjson["parameters"] = {};
279  for (auto& parameter : parameterlist)
280  {
281  vjson["parameters"].push_back(parameter.first);
282  }
283  vjson["interface"] = {};
284  vjson["interface"].push_back("CGRA_Clock");
285  vjson["interface"].push_back("CGRA_Reset");
286  vjson["interface"].push_back("CGRA_Enable");
287 
288  for (auto& port : ports)
289  {
290  std::string portName = port.second->getName();
291  vjson["interface"].push_back(portName);
292  }
293 
294  // module definition
295  std::string moduleDefinition;
296  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
297  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
298  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
299  //moduleDefinition += std::string(SET_INDENT) + "input CGRA_PHI_Enable;\n";
300 
301  for (auto& port : ports)
302  {
303  port_type portType = port.second->pt;
304  std::string portTypeString = {};
305  if(portType == port_type::PORT_INPUT)
306  {
307  portTypeString = "input";
308  }
309  else if (portType == port_type::PORT_OUTPUT)
310  {
311  portTypeString = "output";
312  }
313  else if (portType == port_type::PORT_OUTPUT_REG)
314  {
315  portTypeString = "output reg";
316  }
317  else
318  {
319  portTypeString = "inout";
320  }
321  std::string portSizeString;
322  //std::string portSizeString1b;
323 
324  if (!(port.second->parameter).empty()) // Check if size is parameterized
325  {
326  std::string portParameterName = port.second->parameter;
327  portSizeString = "[" + portParameterName + "-1:0]";
328  //portSizeString1b = "[" + portParameterName + "0:0]";
329  }
330  else
331  {
332  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
333  }
334  std::string portName = port.second->getName();
335 
336  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
337  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
338 
339  //std::string portDeclaration1b = portTypeString + " " + portSizeString1b + " " + portName + ";\n";
340  //moduleDefinition += std::string(SET_INDENT) + portDeclaration;
341  }
342 
343 
344  // Functionality
345 
346 
347  int ss = (int)ceil(log2(mux_size));
348  std::string selectSize = std::to_string(ss);
349 
350  moduleDefinition += std::string(SET_INDENT) + "wire [" + std::to_string(ss-1) + ":0] x;\n";
351  moduleDefinition += std::string(SET_INDENT) + "assign x = selectpred ? select["+ std::to_string(2*ss-1) + ":" +std::to_string(ss) +"] : select["+ std::to_string(ss-1) + ":0];\n";
352 
353  // Functionality
354  if (isElastic) {
355  moduleDefinition += std::string(SET_INDENT) + "always @(*)\n";
356  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "case (x)\n";
357  for (int i = 0; i < mux_size; ++i)
358  {
359  std::string stringI = std::to_string(i);
360  moduleDefinition += std::string(SET_TRIPLE_INDENT) + stringI + ":begin\n";
361  moduleDefinition += std::string(SET_QUAD_INDENT) + " out = in" + stringI + ";\n";
362  moduleDefinition += std::string(SET_QUAD_INDENT) + " out_valid_downstream = in" + stringI + "_valid_upstream;\n";
363  for (int j = 0; j < mux_size; ++j){
364  std::string stringJ = std::to_string(j);
365  if (j == i)
366  moduleDefinition += std::string(SET_QUAD_INDENT) + " in" + stringJ + "_stop_upstream = out_stop_downstream;\n";
367  else
368  moduleDefinition += std::string(SET_QUAD_INDENT) +" in" + stringJ + "_stop_upstream = 1'b1;\n";
369  }
370  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
371  }
372  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "default: out = {size{1'bx}};\n";
373  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "endcase\n";
374  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "assign select_stop_upstream = out_stop_downstream;\n";
375  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "assign select_valid_upstream = out_valid_downstream;\n";
376  } else {
377  moduleDefinition += std::string(SET_INDENT) + "always @(*)\n";
378  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "case (x)\n";
379  for (int i = 0; i < mux_size; ++i)
380  {
381  std::string stringI = std::to_string(i);
382  moduleDefinition += std::string(SET_TRIPLE_INDENT) + stringI + ": out = in" + stringI + ";\n";
383  }
384  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "default: out = {size{1'bx}};\n";
385  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "endcase";
386  }
387 
388  vjson["definition"] = moduleDefinition;
389  return vjson;
390 }
391 
393 {
394 }
395 
397 {
398  MRRG* result_ptr = new MRRG(II);
399  auto& result = *result_ptr;
400 
401  for(unsigned i = 0; i < II; i++)
402  {
403  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "out")).first;
405  MRRG::NodeDescriptor selectpred = result.insert(MRRGNode::make_operand_pin(this, data_size, i, "selectpred", {Operands::PREDICATE})).first;
406  //MRRG::NodeDescriptor selectpred = result.insert(MRRGNode::make_routing(this, i, "selectpred")).first;
407  result.link(mux, out);
408  result.link(selectpred, mux);
409 
410  for(int j = 0; j < mux_size; j++)
411  {
412  MRRG::NodeDescriptor in = result.insert(MRRGNode::make_routing(this, data_size, i, "in" + std::to_string(j))).first;
413 
414  result.link(in, mux);
415  }
416  }
417  return result_ptr;
418 }
419 
421  const MRRG& mrrg, const OpGraph & og,
422  const Mapping& map,
423  const ConfigCell& ccell,
424  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
425  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
426 ) const {
427  (void)ccell;
428  (void)mrrg_nodes_from_op_node;
429  const std::vector<std::regex> required_node_regexes {
430  std::regex("\\.out$"),
431  };
432  const std::regex in_regex("\\.in([0-9]+)$");
433 
434  const std::vector<std::regex> required_op_node_regexes {
435  std::regex("\\.out$"),
436  std::regex("\\.sel_inst"),
437  };
438  BitConfig bitConfig(mrrg.initiationInterval());
439 
440  // Organize value and op nodes mapping by cycle
441  std::vector<MRRGNodesFromValNode> valNodesByCycle(mrrg.initiationInterval());
442  for (const auto& val_and_mrrg_nodes : mrrg_nodes_from_val_node) {
443  for (const auto& mrrg_node : val_and_mrrg_nodes.second) {
444  valNodesByCycle[mrrg_node->cycle][val_and_mrrg_nodes.first].insert(mrrg_node);
445  }
446  }
447 
448  std::vector<MRRGNodesFromOpNode> opNodesByCycle(mrrg.initiationInterval());
449  for (const auto& op_and_mrrg_nodes : mrrg_nodes_from_op_node) {
450  for (const auto& mrrg_node : op_and_mrrg_nodes.second) {
451  opNodesByCycle[mrrg_node->cycle][op_and_mrrg_nodes.first].insert(mrrg_node);
452  }
453  }
454 
455  int cycle = 0;
456  int used_cycles = 0;
457  for (int i = 0; i < valNodesByCycle.size(); i++) {
458  std::set<int> inputs_used;
459  int left = 0;
460  int right = 0;
461  if (!opNodesByCycle[i].empty()){
462  auto mrrg_nodes_from_op_per_cycle = opNodesByCycle[i];
463 
464  int required_node_types_found = 0;
465  std::vector<OpGraphOp*> phiNodes;
466 
467  for (const auto& op_node_and_mrrg_nodes : mrrg_nodes_from_op_per_cycle) {
468  for (const auto& req_node_regex : required_op_node_regexes) {
469  for (const auto& mrrg_node : op_node_and_mrrg_nodes.second) {
470  std::smatch match_results;
471  if (std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, req_node_regex)) {
472  if (required_node_types_found > 2) {
473  throw cgrame_error("found a node that matched two required node regexes");
474  } else {
475  required_node_types_found++;
476  phiNodes.push_back(op_node_and_mrrg_nodes.first);
477  }
478  }
479  }
480  }
481  }
482 
483  bool leftFound = false;
484  bool rightFound = false;
485  auto mrrg_nodes_from_val_per_cycle = valNodesByCycle[i];
486  for (const auto& val_node_and_mrrg_nodes : mrrg_nodes_from_val_per_cycle) { //added
487  if (required_node_types_found > 0) {
488  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
489  std::smatch match_results;
490  std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, in_regex);
491  if (match_results.size() == 2) {
492  if( val_node_and_mrrg_nodes.first->getOperandForOutput(phiNodes[0]) == Operands::BINARY_LHS){
493  if(leftFound) throw cgrame_error("Error: 2 LHS inputs specfied for phi op" + phiNodes[0]->getName());
494  else{
495  leftFound = true;
496  left = stoi(match_results[1].str());
497  }
498  //break;
499  }
500  else if ( val_node_and_mrrg_nodes.first->getOperandForOutput(phiNodes[0]) == Operands::BINARY_RHS){
501  if(rightFound) throw cgrame_error("Error: 2 RHS inputs specfied for phi op" + phiNodes[0]->getName());
502  else{
503  rightFound = true;
504  right = stoi(match_results[1].str());
505  }
506  //break;
507  } else if ( val_node_and_mrrg_nodes.first->getOperandForOutput(phiNodes[0]) == Operands::PREDICATE) {
508  continue;
509  } else{
510  throw cgrame_error("Error: Must specify LHS/RHS for phi op " + phiNodes[0]->getName() + " " + val_node_and_mrrg_nodes.first->getName() + " " + val_node_and_mrrg_nodes.first->getOperandForOutput(phiNodes[0]));
511  }
512  inputs_used.insert(stoi(match_results[1].str()));
513  }
514  }
515  } else {
516  // ignore the val
517  }
518  }
519  } else {
520  auto mrrg_nodes_from_val_per_cycle = valNodesByCycle[i];
521  for (const auto& val_node_and_mrrg_nodes : mrrg_nodes_from_val_per_cycle) {
522  std::vector<bool> required_node_types_found;
523  for (const auto& req_node_regex : required_node_regexes) {
524  required_node_types_found.push_back(false);
525  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
526  std::smatch match_results;
527  if (std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, req_node_regex)) {
528  if (required_node_types_found.back()) {
529  throw cgrame_error("found a node that matched two required node regexes");
530  } else {
531  required_node_types_found.back() = true;
532  }
533  }
534  }
535  }
536 
537  if (std::all_of(begin(required_node_types_found), end(required_node_types_found), [&](auto&& v) { return v; })) {
538  for (const auto& mrrg_node : val_node_and_mrrg_nodes.second) {
539  std::smatch match_results;
540  std::regex_search(mrrg_node->getHierarchyQualifiedName(), match_results, in_regex);
541  if (match_results.size() == 2) {
542  inputs_used.insert(stoi(match_results[1].str()));
543  }
544  }
545  } else {
546  // ignore the val
547  }
548  }
549 
550  }
551  if (inputs_used.empty()) {
552  bitConfig.add({2* (size_t)std::lround(ceil(log2(mux_size))), BitSetting::DONT_CARE_PREFER_LOW}, cycle);
553  } else if (inputs_used.size() == 1) {
554  used_cycles++;
555  std::vector<BitSetting> first_vec = bitsettings_from_int(*begin(inputs_used), (int)std::lround(ceil(log2(mux_size))));
556  std::vector<BitSetting> sec_vec = bitsettings_from_int(*begin(inputs_used), (int)std::lround(ceil(log2(mux_size))));
557  first_vec.insert(first_vec.end(), sec_vec.begin(), sec_vec.end() );
558  bitConfig.add(first_vec, cycle);
559  } else if(inputs_used.size() == 2){
560  used_cycles++;
561  std::vector<BitSetting> first_vec = bitsettings_from_int(left, (int)std::lround(ceil(log2(mux_size))));
562  int sec = *std::next(inputs_used.begin(), 1);
563  std::vector<BitSetting> sec_vec = bitsettings_from_int(right, (int)std::lround(ceil(log2(mux_size))));
564  first_vec.insert(first_vec.end(), sec_vec.begin(), sec_vec.end());
565  bitConfig.add(first_vec, cycle);
566  } else {
567  throw cgrame_error("ERROR: predicate MUX has to have two inputs");
568  }
569  cycle++;
570  }
571  bitConfig.setUsedCycles(used_cycles);
572  return bitConfig;
573 }
574 
575 /************ EventTransitionTable **********/
576 /* EventTransitionTable stores the branches of an application within a table. So, a CGRA
577  * with supported number of contexts, SII, can map an application with conditional branches. */
578 
579 const std::map<OpGraphOpCode, LLVMMode> EventTransitionTable::all_modes =
580 {
581  {OpCode::BR, {"op_br", "br", {"br"}, "sel_br"}
582  },
583 };
584 
586  : Module(name, loc, 0)
587 {
588  addPort("current_event", PORT_INPUT, 1);
589 
590  parameterlist.emplace("size", getSize());
591  parameterlist.emplace("contexts", SII);
592 }
593 
595  auto context_size = (parameterlist["contexts"] == 1) ? "0" : "$clog2(contexts)-1";
596  nlohmann::json vjson;
597 
598  // Construct Header
599  vjson["prefix"] = "cgrame_";
600  vjson["parameters"] = {};
601  for (auto &parameter : parameterlist) {
602  vjson["parameters"].push_back(parameter.first);
603  }
604  vjson["interface"] = {};
605  vjson["interface"].push_back("ConfigIn");
606  vjson["interface"].push_back("ConfigOut");
607  vjson["interface"].push_back("Config_Clock");
608  vjson["interface"].push_back("Config_Reset");
609  vjson["interface"].push_back("CGRA_Clock");
610  vjson["interface"].push_back("CGRA_Reset");
611  vjson["interface"].push_back("CGRA_Enable");
612  //vjson["interface"].push_back("CGRA_PHI_Enable");
613  vjson["interface"].push_back("next_state");
614  vjson["interface"].push_back("current_state");
615  vjson["interface"].push_back("branch");
616 
617 
618  for (auto& port : ports)
619  {
620  std::string portName = port.second->getName();
621  vjson["interface"].push_back(portName);
622  }
623 
624  // module definition
625  std::string moduleDefinition;
626  for (auto& port : ports)
627  {
628  port_type portType = port.second->pt;
629  std::string portTypeString = {};
630  if(portType == port_type::PORT_INPUT)
631  {
632  portTypeString = "input";
633  }
634  else if (portType == port_type::PORT_OUTPUT)
635  {
636  portTypeString = "output";
637  }
638  else if (portType == port_type::PORT_OUTPUT_REG)
639  {
640  portTypeString = "output reg";
641  }
642  else
643  {
644  portTypeString = "inout";
645  }
646  std::string portSizeString;
647  if (!(port.second->parameter).empty()) // Check if size is parameterized
648  {
649  std::string portParameterName = port.second->parameter;
650  portSizeString = "[" + portParameterName + "-1:0]";
651  }
652  else
653  {
654  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
655  }
656  std::string portName = port.second->getName();
657  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
658  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
659  }
660  // module definition
661  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Clock;\n";
662  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Reset;\n";
663  moduleDefinition += std::string(SET_INDENT) + "input CGRA_Enable;\n";
664  //moduleDefinition += std::string(SET_INDENT) + "input CGRA_PHI_Enable;\n";
665  moduleDefinition += std::string(SET_INDENT) + "input ConfigIn;\n";
666  moduleDefinition += std::string(SET_INDENT) + "input Config_Clock;\n";
667  moduleDefinition += std::string(SET_INDENT) + "input Config_Reset;\n";
668  moduleDefinition += std::string(SET_INDENT) + "output ConfigOut;\n";
669  moduleDefinition += std::string(SET_INDENT) + "output reg [" + context_size + ":0] next_state;\n";
670  moduleDefinition += std::string(SET_INDENT) + "output reg branch;\n";
671  moduleDefinition += std::string(SET_INDENT) + "input [" + context_size + ":0] current_state;\n";
672 
673  moduleDefinition += std::string(SET_INDENT) + "reg [" + context_size + "-1:0] event_stt_next_state [" + context_size + "-1:0];\n";
674  moduleDefinition += std::string(SET_INDENT) + "reg [" + context_size + "-1:0] event_stt_state [" + context_size + "-1:0];\n";
675  moduleDefinition += std::string(SET_INDENT) + "reg event_stt_event [" + context_size + "-1:0];\n";
676  moduleDefinition += std::string(SET_INDENT) + "integer i;\n";
677 
678  moduleDefinition += std::string(SET_INDENT) + "always @(posedge Config_Clock) begin\n";
679  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "if (Config_Reset) begin\n";
680  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "for (i = 0; i < " + context_size + "; i = i+1) begin\n";
681  moduleDefinition += std::string(SET_QUAD_INDENT) + "event_stt_state[i] <= 0;\n";
682  moduleDefinition += std::string(SET_QUAD_INDENT) + "event_stt_event[i] <= 0;\n";
683  moduleDefinition += std::string(SET_QUAD_INDENT) + "event_stt_next_state[i] <= 0;\n";
684  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
685  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
686  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "else begin\n";
687  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "for (i = 0; i < " + context_size + "; i = i+1) begin\n";
688  moduleDefinition += std::string(SET_QUAD_INDENT) + "if(i == 0) begin\n";
689  moduleDefinition += std::string(SET_PENTA_INDENT) + "event_stt_state[i] <= {ConfigIn,event_stt_state[i][" + context_size + "-1:1]};\n";
690  moduleDefinition += std::string(SET_PENTA_INDENT) + "event_stt_event[i] <= event_stt_state[" + context_size + "-1][0];\n";
691  moduleDefinition += std::string(SET_PENTA_INDENT) + "event_stt_next_state[i] <= {event_stt_event[0],event_stt_next_state[i][$clog2(" + context_size + ")-1:1]};\n";
692  moduleDefinition += std::string(SET_QUAD_INDENT) + " end\n";
693  moduleDefinition += std::string(SET_QUAD_INDENT) + " else begin\n";
694  moduleDefinition += std::string(SET_PENTA_INDENT) + "event_stt_state[i] <= {event_stt_state[i-1][0],event_stt_state[i][$clog2(" + context_size + ")-1:1]};\n";
695  moduleDefinition += std::string(SET_PENTA_INDENT) + "event_stt_event[i] <= event_stt_event[i-1];\n";
696  moduleDefinition += std::string(SET_PENTA_INDENT) + "event_stt_next_state[i] <= {event_stt_next_state[i-1][0],event_stt_next_state[i][$clog2(" + context_size + ")-1:1]};\n";
697  moduleDefinition += std::string(SET_QUAD_INDENT) + "end\n";
698  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
699  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
700  moduleDefinition += std::string(SET_INDENT) + "end\n";
701 
702  moduleDefinition += std::string(SET_INDENT) + "always @(*) begin\n";
703  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "branch = 1'b0;\n";
704  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "for (i = 0; i < " + context_size + "; i = i+1) begin\n";
705  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "if (event_stt_state[i] == current_state && event_stt_event[i] == current_event) begin\n";
706  moduleDefinition += std::string(SET_QUAD_INDENT) + "next_state = event_stt_next_state[i];\n";
707  moduleDefinition += std::string(SET_QUAD_INDENT) + "branch = 1'b1;\n";
708  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
709  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
710  moduleDefinition += std::string(SET_INDENT) + "end\n";
711 
712  moduleDefinition += std::string(SET_INDENT) + "assign config_out = event_stt_next_state[" + context_size + "-1][0];\n";
713 
714  vjson["definition"] = moduleDefinition;
715  return vjson;
716 }
717 
719 {
720  return "EventTransitionTable";
721 }
722 
724 {
725  MRRG* result_ptr = new MRRG(II);
726  auto& result = *result_ptr;
727 
728  for(unsigned i = 0; i < II; i++)
729  {
730  MRRG::NodeDescriptor current_event = result.insert(MRRGNode::make_routing(this, data_size, i, "current_event")).first;
731  MRRG::NodeDescriptor br = result.insert(MRRGNode::make_routing_function(this, data_size, i, "br_inst", 0, {Operands::BINARY_ANY}, {OpCode::BR}, 1)).first;
732  result.link(br, current_event);
733 
734  }
735  return result_ptr;
736 }
737 
739  const MRRG &mrrg, const OpGraph &og,
740  const Mapping &map,
741  const ConfigCell &ccell,
742  const MRRGNodesFromOpNode &mrrg_nodes_from_op_node,
743  const MRRGNodesFromValNode &mrrg_nodes_from_val_node) const
744 {
745  (void)ccell;
746 
747  BitConfig bitConfig(mrrg.initiationInterval());
748 
749  // Organize nodes mapping by cycle
750  std::vector<MRRGNodesFromOpNode> opNodesByCycle(mrrg.initiationInterval());
751  for (const auto &op_and_mrrg_nodes : mrrg_nodes_from_op_node)
752  {
753  for (const auto &mrrg_node : op_and_mrrg_nodes.second)
754  {
755  opNodesByCycle[mrrg_node->cycle][op_and_mrrg_nodes.first].insert(mrrg_node);
756  }
757  }
758 
759  int cycle = 0;
760  for (auto &mrrg_nodes_from_op_node_per_cycle : opNodesByCycle)
761  {
762 
763  }
764 
765  return bitConfig;
766 }
OpCode::BR
@ BR
BitConfig
Definition: BitSetting.h:58
ConfigCell
Definition: Module.h:825
Compare::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: ModulePredicationUnit.cpp:154
SelMultiplexer::~SelMultiplexer
virtual ~SelMultiplexer()
Definition: ModulePredicationUnit.cpp:392
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
Location
Definition: Module.h:156
Module::data_size
unsigned data_size
Definition: Module.h:338
Operands::BINARY_LHS
static constexpr auto & BINARY_LHS
Definition: OpGraph.h:89
begin
auto begin(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:137
SET_PENTA_INDENT
const char *const SET_PENTA_INDENT
Definition: Module.h:41
Module.h
SelMultiplexer::SelMultiplexer
SelMultiplexer(std::string, Location, unsigned mux_size, unsigned size=DEFAULT_SIZE, bool isElastic=false)
Definition: ModulePredicationUnit.cpp:241
Module::adds_synchronous_circuitry
bool adds_synchronous_circuitry
Definition: Module.h:370
OpCode::SELECT
@ SELECT
Module::parameterlist
std::map< std::string, unsigned > parameterlist
Definition: Module.h:224
BitSetting::DONT_CARE_PREFER_LOW
@ DONT_CARE_PREFER_LOW
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
OpCode::CMP
@ CMP
Compare::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModulePredicationUnit.cpp:41
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
Compare::all_modes
static const std::map< OpGraphOpCode, LLVMMode > all_modes
Definition: Module.h:914
Compare::createMRRG
MRRG * createMRRG(unsigned II) override
Definition: ModulePredicationUnit.cpp:132
MRRGNodesFromValNode
std::map< OpGraphVal *, std::set< MRRG::NodeDescriptor > > MRRGNodesFromValNode
Definition: Module.h:147
BitSetting::LOW
@ LOW
Mapping
Definition: Mapping.h:31
PORT_CONFIG
@ PORT_CONFIG
Definition: Module.h:67
Operands::BINARY_RHS
static constexpr auto & BINARY_RHS
Definition: OpGraph.h:90
EventTransitionTable::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModulePredicationUnit.cpp:594
SelMultiplexer::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: ModulePredicationUnit.cpp:420
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
MRRGNode::make_function
static MRRGNode make_function(Module *parent, int bitwidth, int cycle, STR &&name, int latency, SupportedOps supported_ops, int max_cap=1, bool is_const_unit=false)
Definition: MRRG.h:191
EventTransitionTable::createMRRG
virtual MRRG * createMRRG(unsigned II) override
Definition: ModulePredicationUnit.cpp:723
SET_INDENT
const char *const SET_INDENT
Definition: Module.h:37
Module
Definition: Module.h:163
PORT_INPUT
@ PORT_INPUT
Definition: Module.h:63
Compare::GenericName
virtual std::string GenericName() override
Definition: ModulePredicationUnit.cpp:35
Compare::~Compare
virtual ~Compare()
Definition: ModulePredicationUnit.cpp:128
EventTransitionTable::all_modes
static const std::map< OpGraphOpCode, LLVMMode > all_modes
Definition: Module.h:849
end
auto end(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:138
Compare::Compare
Compare(std::string name, Location, unsigned size, int II)
Definition: ModulePredicationUnit.cpp:21
EventTransitionTable::EventTransitionTable
EventTransitionTable(std::string name, int contexts, Location loc={0, 0})
Definition: ModulePredicationUnit.cpp:585
MRRGNode
Definition: MRRG.h:60
Module::getSize
int getSize() const
Definition: Module.h:246
SelMultiplexer::createMRRG
MRRG * createMRRG(unsigned II) override
Definition: ModulePredicationUnit.cpp:396
Module::getName
auto & getName() const
Definition: Module.h:247
SelMultiplexer::mux_size
int mux_size
Definition: Module.h:665
BitConfig::setUsedCycles
void setUsedCycles(int uc)
Definition: BitSetting.h:67
Module::isElastic
bool isElastic
Definition: Module.h:236
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
SelMultiplexer::GenericName
virtual std::string GenericName() override
Definition: ModulePredicationUnit.cpp:266
MRRG::initiationInterval
int initiationInterval() const
Definition: MRRG.h:346
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
SelMultiplexer::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModulePredicationUnit.cpp:272
EventTransitionTable::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: ModulePredicationUnit.cpp:738
EventTransitionTable::GenericName
virtual std::string GenericName() override
Definition: ModulePredicationUnit.cpp:718
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
Operands::PREDICATE
static constexpr auto & PREDICATE
Definition: OpGraph.h:88
OpGraph
Definition: OpGraph.h:215
cgrame_error
Definition: Exception.h:20
PORT_OUTPUT
@ PORT_OUTPUT
Definition: Module.h:64
SelMultiplexer::all_modes
static const std::map< OpGraphOpCode, LLVMMode > all_modes
Definition: Module.h:649
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