CGRA-ME
ModuleFracUnit.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * The software programs comprising "CGRA-ME" and the documentation provided
3  * with them are copyright by its authors and the University of Toronto. Only
4  * non-commercial, not-for-profit use of this software is permitted without ex-
5  * plicit permission. This software is provided "as is" with no warranties or
6  * guarantees of support. See the LICENCE for more details. You should have re-
7  * ceived a copy of the full licence along with this software. If not, see
8  * <http://cgra-me.ece.utoronto.ca/license/>.
9  ******************************************************************************/
10 
11 #include <CGRA/Module.h>
12 
13 #include <regex>
14 
15 /************ FuncUnit **********/
16 // Returns a unique name for a funcunit
17 std::string FracUnit::GenericName()
18 {
19  return "frac_" + std::to_string(getSize()) + "b_frac_mul_frac_add"; // Base name is "frac"
20 }
21 
22 FracUnit::FracUnit(std::string name, Location loc, std::vector<OpGraphOpCode> supported_modes_, unsigned size, int II, int latency)
23  : Module(name, loc, size)
24  , pipeline_mode(II, latency)
25  , supported_modes(std::move(supported_modes_))
26 {
27  isElastic = false;
28  if (II != 1) {
29  std::cout << II << '\n';
30  make_and_throw<cgrame_error>([&](auto&& s) { s << "dont support an II other than 1 (given II=" << II << ')'; });
31  }
32 
33  for (const auto& mode : supported_modes) {
34  if (!FracMulUnit::all_modes.count(mode) && !FracAddUnit::all_modes.count(mode)) {
35  make_and_throw<cgrame_error>([&](auto&& s) { s << "fracturable unit does not support opcode: " << mode; });
36  }
37  }
38 
39  parameterlist["latency"] = latency;
40 
41  // Create the ports
42  addPort("in_a", PORT_INPUT, "size", size, isElastic);
43  addPort("in_b", PORT_INPUT, "size", size, isElastic);
44  //addPort("select", PORT_INPUT, ceil(log2(supported_modes.size())));
45  addPort("out", PORT_OUTPUT_REG, "size", size, isElastic);
46 
47 
48  addSubModule(new FracMulUnit("fracMulUnit", loc, size, II, latency));
49  addSubModule(new FracAddUnit("fracAddUnit", loc, size, II, latency));
50  addSubModule(new Multiplexer("fracOutMux", loc, 2, size));
51 
52  addConfig(new ConfigCell("FracMulConfig"), {"fracMulUnit.m_sel"});
53  addConfig(new ConfigCell("FracAddConfig"), {"fracAddUnit.a_sel"});
54  addConfig(new ConfigCell("fracOutMuxConfig"), {"fracOutMux.select"});
55 
56  addConnection("this.in_a", "fracMulUnit.in_a");
57  addConnection("this.in_b", "fracMulUnit.in_b");
58 
59  addConnection("this.in_a", "fracAddUnit.in_a");
60  addConnection("this.in_b", "fracAddUnit.in_b");
61 
62  addConnection("fracMulUnit.out", "fracOutMux.in0");
63  addConnection("fracAddUnit.out", "fracOutMux.in1");
64  addConnection("fracOutMux.out", "this.out");
65 }
66 
67 /*
68 // CoreIR Implementation of GenFunctionality
69 nlohmann::json FracUnit::CoreIRGenFunctionality() // Virtual function override
70 {
71  nlohmann::json vjson;
72 
73  // Create Header
74  vjson["prefix"] = "cgrame_"; //module prefix
75  vjson["parameters"] = {};
76  for (auto& parameter : parameterlist)
77  {
78  vjson["parameters"].push_back(parameter.first);
79  }
80  vjson["interface"] = {};
81  for (auto& port : ports)
82  {
83  std::string portName = port.second->getName();
84  vjson["interface"].push_back(portName);
85  }
86  for (auto& port : portsToPropagate)
87  {
88  std::string portName = port.getName();
89  vjson["interface"].push_back(portName);
90  }
91 
92  // module definition
93  std::string moduleDefinition;
94  for (auto& port : ports)
95  {
96  port_type portType = port.second->pt;
97  std::string portTypeString = {};
98  if(portType == port_type::PORT_INPUT)
99  {
100  portTypeString = "input";
101  }
102  else if (portType == port_type::PORT_OUTPUT)
103  {
104  portTypeString = "output";
105  }
106  else if (portType == port_type::PORT_OUTPUT_REG)
107  {
108  portTypeString = "output reg";
109  }
110  else
111  {
112  portTypeString = "inout";
113  }
114  std::string portSizeString;
115  if (!(port.second->parameter).empty()) // Check if size is parameterized
116  {
117  std::string portParameterName = port.second->parameter;
118  portSizeString = "[" + portParameterName + "-1:0]";
119  }
120  else
121  {
122  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
123  }
124  std::string portName = port.second->getName();
125  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
126  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
127  }
128 
129  // MULTIPLY
130  // Declare wires
131  moduleDefinition += std::string(SET_INDENT) + "wire [size/2-1:0] m0_op1, m0_op2, m1_op1, m1_op2, m2_op1, m2_op2, m3_op1, m3_op2;\n";
132  moduleDefinition += std::string(SET_INDENT) + "wire [size-1:0] m0_out, m1_out, m2_out, m3_out;\n";
133  moduleDefinition += std::string(SET_INDENT) + "wire [size-1:0] out_mul_full_hi, out_mul_half_hi, out_mul_quart_hi, out_mul_full_lo, out_mul_half_lo, out_mul_quart_lo;\n\n";
134 
135  // Configure the inputs of the frac multipliers
136  moduleDefinition += std::string(SET_INDENT) + "assign m0_op1 = (select%3 == 2) ? {in_a[size-1:size/4*3], 8'b0} : in_a[size-1:size/2];\n";
137  moduleDefinition += std::string(SET_INDENT) + "assign m0_op2 = (select%3 == 2) ? {in_b[size-1:size/4*3], 8'b0} : in_b[size-1:size/2];\n";
138  moduleDefinition += std::string(SET_INDENT) + "assign m1_op1 = (select%3 == 2) ? {8'b0, in_a[size/4*3-1:size/2]} : in_a[size-1:size/2];\n";
139  moduleDefinition += std::string(SET_INDENT) + "assign m1_op2 = (select%3 == 2) ? {8'b0, in_b[size/4*3-1:size/2]} : in_b[size/2-1:0];\n";
140  moduleDefinition += std::string(SET_INDENT) + "assign m2_op1 = (select%3 == 2) ? {in_a[size/2-1:size/4], 8'b0} : in_a[size/2-1:0];\n";
141  moduleDefinition += std::string(SET_INDENT) + "assign m2_op2 = (select%3 == 2) ? {in_b[size/2-1:size/4], 8'b0} : in_b[size-1:size/2];\n";
142  moduleDefinition += std::string(SET_INDENT) + "assign m3_op1 = (select%3 == 2) ? {8'b0, in_a[size/4-1:0]} : in_a[size/2-1:0];\n";
143  moduleDefinition += std::string(SET_INDENT) + "assign m3_op2 = (select%3 == 2) ? {8'b0, in_b[size/4-1:0]} : in_b[size/2-1:0];\n\n";
144 
145  moduleDefinition += std::string(SET_INDENT) + "assign m0_out = m0_op1 * m0_op2;\n";
146  moduleDefinition += std::string(SET_INDENT) + "assign m1_out = m1_op1 * m1_op2;\n";
147  moduleDefinition += std::string(SET_INDENT) + "assign m2_out = m2_op1 * m2_op2;\n";
148  moduleDefinition += std::string(SET_INDENT) + "assign m3_out = m3_op1 * m3_op2;\n\n";
149 
150  // Packaging the outputs from frac muls
151  moduleDefinition += std::string(SET_INDENT) + "assign {out_mul_full_hi, out_mul_full_lo} = (m0_out << 32) + ((m1_out + m2_out) << 16) + m3_out;\n";
152  moduleDefinition += std::string(SET_INDENT) + "assign out_mul_half_hi = {m0_out[size-1:size/2], m3_out[size-1:size/2]};\n";
153  moduleDefinition += std::string(SET_INDENT) + "assign out_mul_half_lo = {m0_out[size/2-1:0], m3_out[size/2-1:0]};\n";
154  moduleDefinition += std::string(SET_INDENT) + "assign out_mul_quart_hi = {m0_out[size-1:size/4*3], m1_out[size/2-1:size/4], m2_out[size-1:size/4*3], m3_out[size/2-1:size/4]};\n";
155  moduleDefinition += std::string(SET_INDENT) + "assign out_mul_quart_lo = {m0_out[size/4*3-1:size/2], m1_out[size/4-1:0], m2_out[size/4*3-1:size/2], m3_out[size/4-1:0]};\n\n";
156 
157  // ADD
158  // Declaring wires
159  moduleDefinition += std::string(SET_INDENT) + "wire a1_carry, a2_carry, a3_carry;\n";
160  moduleDefinition += std::string(SET_INDENT) + "wire [size/4-1:0] a0_out, a1_out, a2_out, a3_out;\n";
161  moduleDefinition += std::string(SET_INDENT) + "wire [size/4-1:0] q0, q1, q2, q3;\n";
162  moduleDefinition += std::string(SET_INDENT) + "wire [size/2-1:0] h0, h1;\n";
163  moduleDefinition += std::string(SET_INDENT) + "wire [size-1:0] f0;\n";
164  moduleDefinition += std::string(SET_INDENT) + "wire [size-1:0] out_add_full, out_add_half, out_add_quart;\n\n";
165 
166  // Configure the outputs of the frac adders
167  moduleDefinition += std::string(SET_INDENT) + "assign a0_out = in_a[size-1:size/4*3] + in_b[size-1:size/4*3];\n";
168  moduleDefinition += std::string(SET_INDENT) + "assign {a1_carry, a1_out} = in_a[size/4*3-1:size/2] + in_b[size/4*3-1:size/2];\n";
169  moduleDefinition += std::string(SET_INDENT) + "assign {a2_carry, a2_out} = in_a[size/2-1:size/4] + in_b[size/2-1:size/4];\n";
170  moduleDefinition += std::string(SET_INDENT) + "assign {a3_carry, a3_out} = in_a[size/4-1:0] + in_b[size/4-1:0];\n\n";
171 
172  // Packaging the outputs from frac adders
173  moduleDefinition += std::string(SET_INDENT) + "assign q3 = a3_out;\n";
174  moduleDefinition += std::string(SET_INDENT) + "assign q2 = a2_out;\n";
175  moduleDefinition += std::string(SET_INDENT) + "assign q1 = a1_out;\n";
176  moduleDefinition += std::string(SET_INDENT) + "assign q0 = a0_out;\n";
177  moduleDefinition += std::string(SET_INDENT) + "assign h1 = {(a2_out + a3_carry), a3_out};\n";
178  moduleDefinition += std::string(SET_INDENT) + "assign h0 = {(a0_out + a1_carry), a1_out};\n";
179  moduleDefinition += std::string(SET_INDENT) + "assign f0 = ((a0_out + a1_carry) << (size/4*3)) + ((a1_out + a2_carry) << (size/2)) + ((a2_out + a3_carry) << (size/4)) + a3_out;\n\n";
180 
181  moduleDefinition += std::string(SET_INDENT) + "assign out_add_full = f0;\n";
182  moduleDefinition += std::string(SET_INDENT) + "assign out_add_half = {h0, h1};\n";
183  moduleDefinition += std::string(SET_INDENT) + "assign out_add_quart = {q0, q1, q2, q3};\n\n";
184 
185  // Output select
186  moduleDefinition += std::string(SET_INDENT) + "always @* begin\n";
187  moduleDefinition += std::string(SET_INDENT) + "case (select)\n";
188  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "4'h0: begin\n"; // Mul High
189  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "out = out_mul_full_lo;\n";
190  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
191  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "4'h1: begin\n";
192  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "out = out_mul_half_lo;\n";
193  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
194  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "4'h2: begin\n";
195  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "out = out_mul_quart_lo;\n";
196  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
197  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "4'h3: begin\n"; // Mul Low
198  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "out = out_mul_full_hi;\n";
199  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
200  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "4'h4: begin\n";
201  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "out = out_mul_half_hi;\n";
202  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
203  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "4'h5: begin\n";
204  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "out = out_mul_quart_hi;\n";
205  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
206  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "4'h6: begin\n"; // Add
207  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "out = out_add_full;\n";
208  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
209  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "4'h7: begin\n";
210  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "out = out_add_half;\n";
211  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
212  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "4'h8: begin\n";
213  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "out = out_add_quart;\n";
214  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
215  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "default: begin\n";
216  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "out = 1'bx;\n";
217  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "end\n";
218  moduleDefinition += std::string(SET_INDENT) + "endcase\n";
219  moduleDefinition += std::string(SET_INDENT) + "end";
220 
221  vjson["definition"] = moduleDefinition;
222  return vjson;
223 }
224 
225 BitConfig FracUnit::getBitConfig(
226  const MRRG& mrrg, const OpGraph & og,
227  const ConfigCell& ccell,
228  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
229  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
230 ) const {
231  (void)ccell;
232  (void)mrrg_nodes_from_val_node;
233  const auto bits_needed = std::lround(ceil(log2(supported_modes.size())));
234 
235  BitConfig bitConfig(mrrg.initiationInterval());
236 
237  // Organize nodes mapping by cycle
238  std::vector<MRRGNodesFromOpNode> opNodesByCycle(mrrg.initiationInterval());
239  for (const auto& op_and_mrrg_nodes : mrrg_nodes_from_op_node) {
240  for (const auto& mrrg_node : op_and_mrrg_nodes.second) {
241  opNodesByCycle[mrrg_node->cycle][op_and_mrrg_nodes.first].insert(mrrg_node);
242  }
243  }
244 
245  int cycle = 0;
246  for (auto & op_and_mrrg_nodes : opNodesByCycle) {
247  if (op_and_mrrg_nodes.empty()) {
248  bitConfig.add({ (size_t)bits_needed, BitSetting::LOW }, cycle);
249  } else if (op_and_mrrg_nodes.size() == 1) {
250  const auto find_result = std::find(begin(supported_modes), end(supported_modes), begin(op_and_mrrg_nodes)->first->opcode);
251  if (find_result == end(supported_modes)) {
252  throw cgrame_error("couldn't find op in supported modes list");
253  } else {
254  bitConfig.add( bitsettings_from_int(std::distance(begin(supported_modes), find_result), bits_needed), cycle);
255  }
256 
257  } else {
258  throw cgrame_error("expect either 0 or 1 op nodes");
259  }
260  ++cycle;
261  }
262 
263  return bitConfig;
264 }
265 
266 MRRG* FracUnit::createMRRG(unsigned II = 1)
267 {
268  MRRG* result_ptr = new MRRG(II);
269  auto& result = *result_ptr;
270 
271  for(unsigned i = 0; i < II; i+= getII())
272  {
273  // create nodes
274  MRRG::NodeDescriptor in_a = result.insert(MRRGNode::make_operand_pin(this, i, "in_a", {Operands::BINARY_LHS, Operands::BINARY_ANY})).first;
275 
276  MRRG::NodeDescriptor in_b = result.insert(MRRGNode::make_operand_pin(this, i, "in_b", {Operands::BINARY_RHS, Operands::BINARY_ANY})).first;
277  MRRG::NodeDescriptor fu = result.insert(MRRGNode::make_function(this, i, "frac_unit", getLatency(), supported_modes)).first;
278 
279  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, i, "out")).first;
280 
281  result.link(in_a, fu);
282  result.link(in_b, fu);
283  (void)out;
284  }
285 
286  for(unsigned i = 0; i < II; i+= getII())
287  {
288  MRRG::NodeDescriptor fu = result.getNode(i, "frac_unit");
289  MRRG::NodeDescriptor out_next = result.getNode(MOD_II(i + getLatency()), "out");
290 
291  result.link(fu, out_next);
292  }
293 
294  return result_ptr;
295 }
296 */
297 
299 {
300 }
301 
302 
303 /************ Multiplier **********/
304 const std::map<OpGraphOpCode, LLVMMode> FracMulUnit::all_modes =
305 {
306  // Adding functionality to the funcunit
307  // You can add a mode to the FuncUnit by specifying all_modes.push_back ({"module name", {"functionality"}, "wire name that feeds into the Multiplier"});
308  // Functionality can be multiple lines, hence the reason why it is a vector. Each string represents one line, hence the reason it is a vector
309  {OpCode::MULU_FULL_LO, {"op_multiply_unsigned_full_lo", "multiply_unsigned_full_lo", {"//mulu_full_lo;"}, "mulu_full_lo_sel"}},
310  {OpCode::MULU_HALF_LO, {"op_multiply_unsigned_half_lo", "multiply_unsigned_half_lo", {"//mulu_half_lo;"}, "mulu_half_lo_sel"}},
311  {OpCode::MULU_QUART_LO, {"op_multiply_unsigned_quart_lo", "multiply_unsigned_quart_lo", {"//mulu_quart_lo;"}, "mulu_quart_lo_sel"}},
312  {OpCode::MULU_FULL_HI, {"op_multiply_unsigned_full_hi", "multiply_unsigned_full_hi", {"//mulu_full_hi;"}, "mulu_full_hi_sel"}},
313  {OpCode::MULU_HALF_HI, {"op_multiply_unsigned_half_hi", "multiply_unsigned_half_hi", {"//mulu_half_hi;"}, "mulu_half_hi_sel"}},
314  {OpCode::MULU_QUART_HI, {"op_multiply_unsigned_quart_hi", "multiply_unsigned_quart_hi", {"//mulu_quart_hi;"}, "mulu_quart_hi_sel"}},
315  {OpCode::MULS_FULL_LO, {"op_multiply_signed_full_lo", "multiply_signed_full_lo", {"//muls_full_lo;"}, "muls_full_lo_sel"}},
316  {OpCode::MULS_HALF_LO, {"op_multiply_signed_half_lo", "multiply_signed_half_lo", {"//muls_half_lo;"}, "muls_half_lo_sel"}},
317  {OpCode::MULS_QUART_LO, {"op_multiply_signed_quart_lo", "multiply_signed_quart_lo", {"//muls_quart_lo;"}, "muls_quart_lo_sel"}},
318  {OpCode::MULS_FULL_HI, {"op_multiply_signed_full_hi", "multiply_signed_full_hi", {"//muls_full_hi;"}, "muls_full_hi_sel"}},
319  {OpCode::MULS_HALF_HI, {"op_multiply_signed_half_hi", "multiply_signed_half_hi", {"//muls_half_hi;"}, "muls_half_hi_sel"}},
320  {OpCode::MULS_QUART_HI, {"op_multiply_signed_quart_hi", "multiply_signed_quart_hi", {"//muls_quart_hi;"}, "muls_quart_hi_sel"}}
321 };
322 
323 const std::vector<OpGraphOpCode> FracMulUnit::mul_modes_ordered = {
336 };
337 
338 FracMulUnit::FracMulUnit(std::string name, Location loc, unsigned size, int II, int latency)
339  : Module(name, loc, size)
340  , pipeline_mode(II, latency)
341 {
342  isElastic = false;
343  addPort("in_a", PORT_INPUT, "size", size, isElastic);
344  addPort("in_b", PORT_INPUT, "size", size, isElastic);
345  addPort("m_sel", PORT_INPUT, ceil(log2(mul_modes_ordered.size())), isElastic);
346  addPort("out", PORT_OUTPUT_REG, "size", size), isElastic;
347 }
348 
349 // Virtual function that overrides Module::GenericName. Returns generic name of the object
350 std::string FracMulUnit::GenericName() // Virtual function override
351 {
352  return "frac_mul_unit_" + std::to_string(getSize()) + "b";
353 }
354 
355 nlohmann::json FracMulUnit::CoreIRGenFunctionality() // Virtual function override
356 {
357  nlohmann::json vjson;
358 
359  // Create Header
360  vjson["prefix"] = "cgrame_"; //module prefix
361  vjson["parameters"] = {};
362  for (auto& parameter : parameterlist)
363  {
364  vjson["parameters"].push_back(parameter.first);
365  }
366  vjson["interface"] = {};
367  for (auto& port : ports)
368  {
369  std::string portName = port.second->getName();
370  vjson["interface"].push_back(portName);
371  }
372  for (auto& port : portsToPropagate)
373  {
374  std::string portName = port.getName();
375  vjson["interface"].push_back(portName);
376  }
377 
378  // module definition
379  std::string moduleDefinition;
380  for (auto& port : ports)
381  {
382  port_type portType = port.second->pt;
383  std::string portTypeString = {};
384  if(portType == port_type::PORT_INPUT)
385  {
386  portTypeString = "input";
387  }
388  else if (portType == port_type::PORT_OUTPUT)
389  {
390  portTypeString = "output";
391  }
392  else if (portType == port_type::PORT_OUTPUT_REG)
393  {
394  portTypeString = "output reg";
395  }
396  else
397  {
398  portTypeString = "inout";
399  }
400  std::string portSizeString;
401  if (!(port.second->parameter).empty()) // Check if size is parameterized
402  {
403  std::string portParameterName = port.second->parameter;
404  portSizeString = "[" + portParameterName + "-1:0]";
405  }
406  else
407  {
408  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
409  }
410  std::string portName = port.second->getName();
411  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
412  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
413  }
414 
415  // Signs of inputs and outputs
416  moduleDefinition += std::string(SET_INDENT) + "wire sign_a0, sign_a1, sign_a2, sign_a3, sign_b0, sign_b1, sign_b2, sign_b3, sign_out0, sign_out1, sign_out2, sign_out3;\n";
417  moduleDefinition += std::string(SET_INDENT) + "assign sign_a0 = in_a[size-1];\n";
418  moduleDefinition += std::string(SET_INDENT) + "assign sign_a1 = in_a[size/4*3-1];\n";
419  moduleDefinition += std::string(SET_INDENT) + "assign sign_a2 = in_a[size/2-1];\n";
420  moduleDefinition += std::string(SET_INDENT) + "assign sign_a3 = in_a[size/4-1];\n";
421  moduleDefinition += std::string(SET_INDENT) + "assign sign_b0 = in_b[size-1];\n";
422  moduleDefinition += std::string(SET_INDENT) + "assign sign_b1 = in_b[size/4*3-1];\n";
423  moduleDefinition += std::string(SET_INDENT) + "assign sign_b2 = in_b[size/2-1];\n";
424  moduleDefinition += std::string(SET_INDENT) + "assign sign_b3 = in_b[size/4-1];\n\n";
425 
426  moduleDefinition += std::string(SET_INDENT) + "assign sign_out0 = sign_a0 ^ sign_b0;\n";
427  moduleDefinition += std::string(SET_INDENT) + "assign sign_out1 = sign_a1 ^ sign_b1;\n";
428  moduleDefinition += std::string(SET_INDENT) + "assign sign_out2 = sign_a2 ^ sign_b2;\n";
429  moduleDefinition += std::string(SET_INDENT) + "assign sign_out3 = sign_a3 ^ sign_b3;\n\n";
430 
431  // Changing all operands to unsigned
432  moduleDefinition += std::string(SET_INDENT) + "wire b0, b1, b2;\n";
433  moduleDefinition += std::string(SET_INDENT) + "wire a_c1, a_c2, a_c3, a_carry1, a_carry2, a_carry3;\n";
434  moduleDefinition += std::string(SET_INDENT) + "wire b_c1, b_c2, b_c3, b_carry1, b_carry2, b_carry3;\n";
435  moduleDefinition += std::string(SET_INDENT) + "wire [(size/4)-1:0] comp_a0, comp_a1, comp_a2, comp_a3;\n";
436  moduleDefinition += std::string(SET_INDENT) + " wire [(size/4)-1:0] comp_b0, comp_b1, comp_b2, comp_b3;\n\n";
437 
438  // adding the 1 when 2's complementing
439  moduleDefinition += std::string(SET_INDENT) + "assign b0 = (m_sel==5'd8 | m_sel==5'd11) ? 1'b1 : 1'b0;\n"; // quarter
440  moduleDefinition += std::string(SET_INDENT) + "assign b1 = (m_sel==5'd7 | m_sel==5'd10 | m_sel==5'd8 | m_sel==5'd11) ? 1'b1 : 1'b0;\n"; // half or quarter
441  moduleDefinition += std::string(SET_INDENT) + "assign b2 = (m_sel==5'd8 | m_sel==5'd11) ? 1'b1 : 1'b0;\n\n"; // quarter
442 
443  // to carry or not to carry
444  moduleDefinition += std::string(SET_INDENT) + "assign a_c1 = (m_sel==5'd6 | m_sel==5'd9 | m_sel==5'd7 | m_sel==5'd10) ? a_carry1 : 1'b0;\n"; // full or half
445  moduleDefinition += std::string(SET_INDENT) + "assign a_c2 = (m_sel==5'd6 | m_sel==5'd9) ? a_carry2 : 1'b0;\n"; // full
446  moduleDefinition += std::string(SET_INDENT) + "assign a_c3 = (m_sel==5'd6 | m_sel==5'd9 | m_sel==5'd7 | m_sel==5'd10) ? a_carry3 : 1'b0;\n\n"; // full or half
447 
448  moduleDefinition += std::string(SET_INDENT) + "assign b_c1 = (m_sel==5'd6 | m_sel==5'd9 | m_sel==5'd7 | m_sel==5'd10) ? b_carry1 : 1'b0; // full or half\n";
449  moduleDefinition += std::string(SET_INDENT) + "assign b_c2 = (m_sel==5'd6 | m_sel==5'd9) ? b_carry2 : 1'b0; // full\n";
450  moduleDefinition += std::string(SET_INDENT) + "assign b_c3 = (m_sel==5'd6 | m_sel==5'd9 | m_sel==5'd7 | m_sel==5'd10) ? b_carry3 : 1'b0; // full or half\n\n";
451 
452  // 2's complement
453  moduleDefinition += std::string(SET_INDENT) + "assign comp_a0 = ~in_a[size-1 : size/4*3] + b0;\n";
454  moduleDefinition += std::string(SET_INDENT) + "assign {a_carry1, comp_a1} = ~in_a[(size/4*3)-1 : size/2] + b1;\n";
455  moduleDefinition += std::string(SET_INDENT) + "assign {a_carry2, comp_a2} = ~in_a[(size/2)-1 : size/4] + b2;\n";
456  moduleDefinition += std::string(SET_INDENT) + "assign {a_carry3, comp_a3} = ~in_a[(size/4)-1 : 0] + 1'b1;\n\n";
457 
458  moduleDefinition += std::string(SET_INDENT) + "assign comp_b0 = ~in_b[size-1 : size/4*3] + b0;\n";
459  moduleDefinition += std::string(SET_INDENT) + "assign {b_carry1, comp_b1} = ~in_b[(size/4*3)-1 : size/2] + b1;\n";
460  moduleDefinition += std::string(SET_INDENT) + "assign {b_carry2, comp_b2} = ~in_b[(size/2)-1 : size/4] + b2;\n";
461  moduleDefinition += std::string(SET_INDENT) + "assign {b_carry3, comp_b3} = ~in_b[(size/4)-1 : 0] + 1'b1;\n\n";
462 
463  // packaging
464  moduleDefinition += std::string(SET_INDENT) + "wire [size-1:0] unsigned_a, unsigned_b;\n";
465  moduleDefinition += std::string(SET_INDENT) + "wire [size-1:0] comped_a, comped_b;\n\n";
466 
467  moduleDefinition += std::string(SET_INDENT) + "assign comped_a[size-1 : size/4*3] = sign_a0 ? comp_a0 : in_a[size-1 : size/4*3];\n"; // s0
468  moduleDefinition += std::string(SET_INDENT) + "assign comped_a[(size/4*3)-1 : size/2] = ( (sign_a0 & (m_sel==5'd6 | m_sel==5'd9 | m_sel==5'd7 | m_sel==5'd10)) | (sign_a1 & (m_sel==5'd8 | m_sel==5'd11)) ) ? comp_a1 : in_a[(size/4*3)-1 : size/2];\n"; // [s0 & (F|H)] | [s1 & Q]
469  moduleDefinition += std::string(SET_INDENT) + "assign comped_a[(size/2)-1 : size/4] = ( (sign_a0 & (m_sel==5'd6 | m_sel==5'd9)) | (sign_a2 & (m_sel==5'd7 | m_sel==5'd10 | m_sel==5'd8 | m_sel==5'd11)) ) ? comp_a2 : in_a[(size/2)-1 : size/4];\n"; // [s0 & F] | [s2 & (H|Q)]
470  moduleDefinition += std::string(SET_INDENT) + "assign comped_a[(size/4)-1 : 0] = ( (sign_a0 & (m_sel==5'd6 | m_sel==5'd9)) | (sign_a2 & (m_sel==5'd7 | m_sel==5'd10)) | (sign_a3 & (m_sel==5'd8 | m_sel==5'd11)) ) ? comp_a3 : in_a[(size/4)-1 : 0];\n\n"; // [s0 & F] | [s2 & H] | [s3 & Q]
471 
472  moduleDefinition += std::string(SET_INDENT) + "assign comped_b[size-1 : size/4*3] = sign_b0 ? comp_b0 : in_b[size-1 : size/4*3];\n"; // s0
473  moduleDefinition += std::string(SET_INDENT) + "assign comped_b[(size/4*3)-1 : size/2] = ( (sign_b0 & (m_sel==5'd6 | m_sel==5'd9 | m_sel==5'd7 | m_sel==5'd10)) | (sign_b1 & (m_sel==5'd8 | m_sel==5'd11)) ) ? comp_b1 : in_b[(size/4*3)-1 : size/2];\n"; // [s0 & (F|H)] | [s1 & Q]
474  moduleDefinition += std::string(SET_INDENT) + "assign comped_b[(size/2)-1 : size/4] = ( (sign_b0 & (m_sel==5'd6 | m_sel==5'd9)) | (sign_b2 & (m_sel==5'd7 | m_sel==5'd10 | m_sel==5'd8 | m_sel==5'd11)) ) ? comp_b2 : in_b[(size/2)-1 : size/4];\n"; // [s0 & F] | [s2 & (H|Q)]
475  moduleDefinition += std::string(SET_INDENT) + "assign comped_b[(size/4)-1 : 0] = ( (sign_b0 & (m_sel==5'd6 | m_sel==5'd9)) | (sign_b2 & (m_sel==5'd7 | m_sel==5'd10)) | (sign_b3 & (m_sel==5'd8 | m_sel==5'd11)) ) ? comp_b3 : in_b[(size/4)-1 : 0];\n\n"; // [s0 & F] | [s2 & H] | [s3 & Q]
476 
477  moduleDefinition += std::string(SET_INDENT) + "assign unsigned_a = (m_sel < 5'd6) ? in_a : comped_a;\n";
478  moduleDefinition += std::string(SET_INDENT) + "assign unsigned_b = (m_sel < 5'd6) ? in_b : comped_b;\n\n";
479 
480  // Changing all operands to unsigned ***DEPRECATED***
481  /*
482  moduleDefinition += std::string(SET_INDENT) + "always @* begin\n";
483  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "case (m_sel)\n";
484  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "5'd6, 5'd9: begin // 2's comp entire\n";
485  moduleDefinition += std::string(SET_QUAD_INDENT) + "unsigned_a = sign_a0 ? ~in_a + 1'b1 : in_a;\n";
486  moduleDefinition += std::string(SET_QUAD_INDENT) + "unsigned_b = sign_b0 ? ~in_b + 1'b1 : in_b;\n";
487  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
488  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "5'd7, 5'd10: begin // 2's comp halves\n";
489  moduleDefinition += std::string(SET_QUAD_INDENT) + "unsigned_a = { {sign_a0 ? ~in_a[size-1:size/2] + 1'b1 : in_a[size-1:size/2]}, {sign_a2 ? ~in_a[size/2-1:0] + 1'b1 : in_a[size/2-1:0]} };\n";
490  moduleDefinition += std::string(SET_QUAD_INDENT) + "unsigned_b = { {sign_b0 ? ~in_b[size-1:size/2] + 1'b1 : in_b[size-1:size/2]}, {sign_b2 ? ~in_b[size/2-1:0] + 1'b1 : in_b[size/2-1:0]} };\n";
491  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
492  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "5'd8, 5'd11: begin // 2's comp quarts\n";
493  moduleDefinition += std::string(SET_QUAD_INDENT) + "unsigned_a = { {sign_a0 ? ~in_a[size-1:size/4*3]+1'b1 : in_a[size-1:size/4*3]}, {sign_a1 ? ~in_a[size/4*3-1:size/2]+1'b1 : in_a[size/4*3-1:size/2]}, {sign_a2 ? ~in_a[size/2-1:size/4]+1'b1 : in_a[size/2-1:size/4]}, {sign_a3 ? ~in_a[size/4-1:0]+1'b1 : in_a[size/4-1:0]} };\n";
494  moduleDefinition += std::string(SET_QUAD_INDENT) + "unsigned_b = { {sign_b0 ? ~in_b[size-1:size/4*3]+1'b1 : in_b[size-1:size/4*3]}, {sign_b1 ? ~in_b[size/4*3-1:size/2]+1'b1 : in_b[size/4*3-1:size/2]}, {sign_b2 ? ~in_b[size/2-1:size/4]+1'b1 : in_b[size/2-1:size/4]}, {sign_b3 ? ~in_b[size/4-1:0]+1'b1 : in_b[size/4-1:0]} };\n";
495  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
496  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "default: begin\n";
497  moduleDefinition += std::string(SET_QUAD_INDENT) + "unsigned_a = in_a;\n";
498  moduleDefinition += std::string(SET_QUAD_INDENT) + "unsigned_b = in_b;\n";
499  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
500  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "endcase\n";
501  moduleDefinition += std::string(SET_INDENT) + "end\n\n";*/
502 
503  // Feed into the four separate multipliers, Zeros done by gating (AND)
504  moduleDefinition += std::string(SET_INDENT) + "wire [size/2-1:0] m0_op1, m0_op2, m1_op1, m1_op2, m2_op1, m2_op2, m3_op1, m3_op2;\n";
505 
506  moduleDefinition += std::string(SET_INDENT) + "assign m0_op1 = (m_sel%3 == 2) ? {unsigned_a[size-1:size/4*3], 8'b0} : unsigned_a[size-1:size/2];\n";
507  moduleDefinition += std::string(SET_INDENT) + "assign m0_op2 = (m_sel%3 == 2) ? {unsigned_b[size-1:size/4*3], 8'b0} : unsigned_b[size-1:size/2];\n";
508  moduleDefinition += std::string(SET_INDENT) + "assign m1_op1 = (m_sel%3 == 2) ? {8'b0, unsigned_a[size/4*3-1:size/2]} : unsigned_a[size-1:size/2];\n";
509  moduleDefinition += std::string(SET_INDENT) + "assign m1_op2 = (m_sel%3 == 2) ? {8'b0, unsigned_b[size/4*3-1:size/2]} : unsigned_b[size/2-1:0];\n";
510  moduleDefinition += std::string(SET_INDENT) + "assign m2_op1 = (m_sel%3 == 2) ? {unsigned_a[size/2-1:size/4], 8'b0} : unsigned_a[size/2-1:0];\n";
511  moduleDefinition += std::string(SET_INDENT) + "assign m2_op2 = (m_sel%3 == 2) ? {unsigned_b[size/2-1:size/4], 8'b0} : unsigned_b[size-1:size/2];\n";
512  moduleDefinition += std::string(SET_INDENT) + "assign m3_op1 = (m_sel%3 == 2) ? {8'b0, unsigned_a[size/4-1:0]} : unsigned_a[size/2-1:0];\n";
513  moduleDefinition += std::string(SET_INDENT) + "assign m3_op2 = (m_sel%3 == 2) ? {8'b0, unsigned_b[size/4-1:0]} : unsigned_b[size/2-1:0];\n\n";
514 
515  // Multipliers
516  moduleDefinition += std::string(SET_INDENT) + "wire [size-1:0] m0_out, m1_out, m2_out, m3_out;\n";
517 
518  moduleDefinition += std::string(SET_INDENT) + "assign m0_out = m0_op1 * m0_op2;\n";
519  moduleDefinition += std::string(SET_INDENT) + "assign m1_out = m1_op1 * m1_op2;\n";
520  moduleDefinition += std::string(SET_INDENT) + "assign m2_out = m2_op1 * m2_op2;\n";
521  moduleDefinition += std::string(SET_INDENT) + "assign m3_out = m3_op1 * m3_op2;\n\n";
522 
523  // Concatenating Outputs
524  moduleDefinition += std::string(SET_INDENT) + "wire [2*size-1:0] out_mul_full, out_mul_full_0;\n";
525  moduleDefinition += std::string(SET_INDENT) + "wire [size-1:0] out_mul_half_0, out_mul_half_1;\n";
526  moduleDefinition += std::string(SET_INDENT) + "wire [size/2-1:0] out_mul_quart_0, out_mul_quart_1, out_mul_quart_2, out_mul_quart_3;\n";
527 
528  moduleDefinition += std::string(SET_INDENT) + "assign out_mul_full = (m0_out << size) + ((m1_out + m2_out) << (size/2)) + m3_out;\n";
529  moduleDefinition += std::string(SET_INDENT) + "assign out_mul_full_0 = (sign_out0 & (m_sel >= 6)) ? ~out_mul_full + 1'b1 : out_mul_full;\n";
530  moduleDefinition += std::string(SET_INDENT) + "assign out_mul_half_0 = (sign_out0 & (m_sel >= 6)) ? ~m0_out + 1'b1 : m0_out;\n";
531  moduleDefinition += std::string(SET_INDENT) + "assign out_mul_half_1 = (sign_out2 & (m_sel >= 6)) ? ~m3_out + 1'b1 : m3_out;\n";
532  moduleDefinition += std::string(SET_INDENT) + "assign out_mul_quart_0 = (sign_out0 & (m_sel >= 6)) ? ~m0_out[size-1:size/2] + 1'b1 : m0_out[size-1:size/2];\n";
533  moduleDefinition += std::string(SET_INDENT) + "assign out_mul_quart_1 = (sign_out1 & (m_sel >= 6)) ? ~m1_out[size/2-1:0] + 1'b1 : m1_out[size/2-1:0];\n";
534  moduleDefinition += std::string(SET_INDENT) + "assign out_mul_quart_2 = (sign_out2 & (m_sel >= 6)) ? ~m2_out[size-1:size/2] + 1'b1 : m2_out[size-1:size/2];\n";
535  moduleDefinition += std::string(SET_INDENT) + "assign out_mul_quart_3 = (sign_out3 & (m_sel >= 6)) ? ~m3_out[size/2-1:0] + 1'b1 : m3_out[size/2-1:0];\n\n";
536 
537  moduleDefinition += std::string(SET_INDENT) + "always @(*) begin\n";
538  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "case (m_sel % 6)\n";
539  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "3'd0: begin // lo -----------------\n";
540  moduleDefinition += std::string(SET_QUAD_INDENT) + "out = out_mul_full_0[size-1:0];\n";
541  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
542  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "3'd1: begin\n";
543  moduleDefinition += std::string(SET_QUAD_INDENT) + "out = {out_mul_half_0[size/2-1:0], out_mul_half_1[size/2-1:0]};\n";
544  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
545  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "3'd2: begin\n";
546  moduleDefinition += std::string(SET_QUAD_INDENT) + "out = {out_mul_quart_0[size/4-1:0], out_mul_quart_1[size/4-1:0], out_mul_quart_2[size/4-1:0], out_mul_quart_3[size/4-1:0]};\n";
547  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
548  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "3'd3: begin // hi -----------------\n";
549  moduleDefinition += std::string(SET_QUAD_INDENT) + "out = out_mul_full_0[2*size-1:size];\n";
550  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
551  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "3'd4: begin\n";
552  moduleDefinition += std::string(SET_QUAD_INDENT) + "out = {out_mul_half_0[size-1:size/2], out_mul_half_1[size-1:size/2]};\n";
553  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
554  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "3'd5: begin\n";
555  moduleDefinition += std::string(SET_QUAD_INDENT) + "out = {out_mul_quart_0[size/2-1:size/4], out_mul_quart_1[size/2-1:size/4], out_mul_quart_2[size/2-1:size/4], out_mul_quart_3[size/2-1:size/4]};\n";
556  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
557  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "default: begin\n";
558  moduleDefinition += std::string(SET_QUAD_INDENT) + "out = {size{1'bx}};\n";
559  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
560  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "endcase\n";
561  moduleDefinition += std::string(SET_INDENT) + "end";
562 
563  vjson["definition"] = moduleDefinition;
564  return vjson;
565 }
566 
568  const MRRG& mrrg, const OpGraph & og,
569  const Mapping& map,
570  const ConfigCell& ccell,
571  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
572  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
573 ) const {
574  (void)ccell;
575  (void)mrrg_nodes_from_val_node;
576 
577  const auto bits_needed = std::lround(ceil(log2(mul_modes_ordered.size())));
578  BitConfig bitConfig(mrrg.initiationInterval());
579 
580  // Organize nodes mapping by cycle
581  std::vector<MRRGNodesFromOpNode> opNodesByCycle(mrrg.initiationInterval());
582  for (const auto& op_and_mrrg_nodes : mrrg_nodes_from_op_node) {
583  for (const auto& mrrg_node : op_and_mrrg_nodes.second) {
584  opNodesByCycle[mrrg_node->cycle][op_and_mrrg_nodes.first].insert(mrrg_node);
585  }
586  }
587 
588  int cycle = 0;
589  for (auto & op_and_mrrg_nodes : opNodesByCycle) {
590  if (op_and_mrrg_nodes.empty()) {
591  bitConfig.add({ (size_t)bits_needed, BitSetting::LOW }, cycle);
592  } else if (op_and_mrrg_nodes.size() == 1) {
593  const auto find_result = std::find(begin(mul_modes_ordered), end(mul_modes_ordered), begin(op_and_mrrg_nodes)->first->opcode);
594  if (find_result == end(mul_modes_ordered)) {
595  throw cgrame_error("couldn't find op in supported modes list");
596  } else {
597  bitConfig.add( bitsettings_from_int(std::distance(begin(mul_modes_ordered), find_result), bits_needed), cycle);
598  }
599 
600  } else {
601  throw cgrame_error("expect either 0 or 1 op nodes");
602  }
603  ++cycle;
604  }
605 
606  return bitConfig;
607 }
608 
609 MRRG* FracMulUnit::createMRRG(unsigned II = 1)
610 {
611  MRRG* result_ptr = new MRRG(II);
612  auto& result = *result_ptr;
613 
614  for(unsigned i = 0; i < II; i+= getII())
615  {
616  // create nodes
618 
620  MRRG::NodeDescriptor fu = result.insert(MRRGNode::make_function(this, data_size, i, "frac_mul_unit", getLatency(), mul_modes_ordered)).first;
621 
622  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "out")).first;
623 
624  result.link(in_a, fu);
625  result.link(in_b, fu);
626  (void)out;
627  }
628 
629  for(unsigned i = 0; i < II; i+= getII())
630  {
631  MRRG::NodeDescriptor fu = result.getNode(i, "frac_mul_unit");
632  MRRG::NodeDescriptor out_next = result.getNode(MOD_II(i + getLatency()), "out");
633 
634  result.link(fu, out_next);
635  }
636 
637  return result_ptr;
638 }
639 
641 {
642 }
643 
644 /************ Adder **********/
645 const std::map<OpGraphOpCode, LLVMMode> FracAddUnit::all_modes =
646 {
647  // Adding functionality to the funcunit
648  // You can add a mode to the FuncUnit by specifying all_modes.push_back ({"module name", {"functionality"}, "wire name that feeds into the Multiplier"});
649  // Functionality can be multiple lines, hence the reason why it is a vector. Each string represents one line, hence the reason it is a vector
650  {OpCode::ADD_FULL, {"op_add_full", "add_full", {"//add_full;"}, "add_full_sel"}},
651  {OpCode::ADD_HALF, {"op_add_half", "add_half", {"//add_half;"}, "add_half_sel"}},
652  {OpCode::ADD_QUART, {"op_add_quart", "add_quart", {"//add_quart;"}, "add_quart_sel"}}
653 };
654 
655 const std::vector<OpGraphOpCode> FracAddUnit::add_modes_ordered = {
659 };
660 
661 FracAddUnit::FracAddUnit(std::string name, Location loc, unsigned size, int II, int latency)
662  : Module(name, loc, size)
663  , pipeline_mode(II, latency)
664 {
665  isElastic = false;
666  addPort("in_a", PORT_INPUT, "size", size, isElastic);
667  addPort("in_b", PORT_INPUT, "size", size, isElastic);
668  addPort("a_sel", PORT_INPUT, ceil(log2(add_modes_ordered.size())), isElastic);
669  addPort("out", PORT_OUTPUT_REG, "size", size, isElastic);
670 }
671 
672 // Virtual function that overrides Module::GenericName. Returns generic name of the object
673 std::string FracAddUnit::GenericName() // Virtual function override
674 {
675  return "frac_add_unit_" + std::to_string(getSize()) + "b";
676 }
677 
678 nlohmann::json FracAddUnit::CoreIRGenFunctionality() // Virtual function override
679 {
680  nlohmann::json vjson;
681 
682  // Create Header
683  vjson["prefix"] = "cgrame_"; //module prefix
684  vjson["parameters"] = {};
685  for (auto& parameter : parameterlist)
686  {
687  vjson["parameters"].push_back(parameter.first);
688  }
689  vjson["interface"] = {};
690  for (auto& port : ports)
691  {
692  std::string portName = port.second->getName();
693  vjson["interface"].push_back(portName);
694  }
695  for (auto& port : portsToPropagate)
696  {
697  std::string portName = port.getName();
698  vjson["interface"].push_back(portName);
699  }
700 
701  // module definition
702  std::string moduleDefinition;
703  for (auto& port : ports)
704  {
705  port_type portType = port.second->pt;
706  std::string portTypeString = {};
707  if(portType == port_type::PORT_INPUT)
708  {
709  portTypeString = "input";
710  }
711  else if (portType == port_type::PORT_OUTPUT)
712  {
713  portTypeString = "output";
714  }
715  else if (portType == port_type::PORT_OUTPUT_REG)
716  {
717  portTypeString = "output reg";
718  }
719  else
720  {
721  portTypeString = "inout";
722  }
723  std::string portSizeString;
724  if (!(port.second->parameter).empty()) // Check if size is parameterized
725  {
726  std::string portParameterName = port.second->parameter;
727  portSizeString = "[" + portParameterName + "-1:0]";
728  }
729  else
730  {
731  portSizeString = "[" + std::to_string(port.second->size - 1) + ":0]";
732  }
733  std::string portName = port.second->getName();
734  std::string portDeclaration = portTypeString + " " + portSizeString + " " + portName + ";\n";
735  moduleDefinition += std::string(SET_INDENT) + portDeclaration;
736  }
737 
738  // Declaring wires
739  moduleDefinition += std::string(SET_INDENT) + "wire a1_carry, a2_carry, a3_carry;\n";
740  moduleDefinition += std::string(SET_INDENT) + "wire [size/4-1:0] a0_out, a1_out, a2_out, a3_out;\n";
741  moduleDefinition += std::string(SET_INDENT) + "wire [size-1:0] f0;\n";
742  moduleDefinition += std::string(SET_INDENT) + "wire [size/2-1:0] h0, h1;\n";
743  moduleDefinition += std::string(SET_INDENT) + "wire [size/4-1:0] q0, q1, q2, q3;\n";
744  moduleDefinition += std::string(SET_INDENT) + "wire [size-1:0] out_add_full, out_add_half, out_add_quart;\n\n";
745 
746  // Configure the outputs of the frac adders
747  moduleDefinition += std::string(SET_INDENT) + "assign a0_out = in_a[size-1:size/4*3] + in_b[size-1:size/4*3];\n";
748  moduleDefinition += std::string(SET_INDENT) + "assign {a1_carry, a1_out} = in_a[size/4*3-1:size/2] + in_b[size/4*3-1:size/2];\n";
749  moduleDefinition += std::string(SET_INDENT) + "assign {a2_carry, a2_out} = in_a[size/2-1:size/4] + in_b[size/2-1:size/4];\n";
750  moduleDefinition += std::string(SET_INDENT) + "assign {a3_carry, a3_out} = in_a[size/4-1:0] + in_b[size/4-1:0];\n\n";
751 
752  // Packaging the outputs from frac adders
753  moduleDefinition += std::string(SET_INDENT) + "assign f0 = {(a0_out + a1_carry), (a1_out + a2_carry), (a2_out + a3_carry), a3_out};\n";
754  moduleDefinition += std::string(SET_INDENT) + "assign h0 = {(a0_out + a1_carry), a1_out};\n";
755  moduleDefinition += std::string(SET_INDENT) + "assign h1 = {(a2_out + a3_carry), a3_out};\n";
756  moduleDefinition += std::string(SET_INDENT) + "assign q0 = a0_out;\n";
757  moduleDefinition += std::string(SET_INDENT) + "assign q1 = a1_out;\n";
758  moduleDefinition += std::string(SET_INDENT) + "assign q2 = a2_out;\n";
759  moduleDefinition += std::string(SET_INDENT) + "assign q3 = a3_out;\n\n";
760 
761  moduleDefinition += std::string(SET_INDENT) + "assign out_add_full = f0;\n";
762  moduleDefinition += std::string(SET_INDENT) + "assign out_add_half = {h0, h1};\n";
763  moduleDefinition += std::string(SET_INDENT) + "assign out_add_quart = {q0, q1, q2, q3};\n\n";
764 
765  // Output select
766  moduleDefinition += std::string(SET_INDENT) + "always @* begin\n";
767  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "case (a_sel%3)\n";
768  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "2'b00: begin\n";
769  moduleDefinition += std::string(SET_QUAD_INDENT) + "out = out_add_full;\n";
770  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
771  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "2'b01: begin\n";
772  moduleDefinition += std::string(SET_QUAD_INDENT) + "out = out_add_half;\n";
773  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
774  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "2'b10: begin\n";
775  moduleDefinition += std::string(SET_QUAD_INDENT) + "out = out_add_quart;\n";
776  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
777  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "default: begin\n";
778  moduleDefinition += std::string(SET_QUAD_INDENT) + "out = 1'bx;\n";
779  moduleDefinition += std::string(SET_TRIPLE_INDENT) + "end\n";
780  moduleDefinition += std::string(SET_DOUBLE_INDENT) + "endcase\n";
781  moduleDefinition += std::string(SET_INDENT) + "end";
782 
783  vjson["definition"] = moduleDefinition;
784  return vjson;
785 }
786 
788  const MRRG& mrrg, const OpGraph & og,
789  const Mapping& map,
790  const ConfigCell& ccell,
791  const MRRGNodesFromOpNode& mrrg_nodes_from_op_node,
792  const MRRGNodesFromValNode& mrrg_nodes_from_val_node
793 ) const {
794  (void)ccell;
795  (void)mrrg_nodes_from_val_node;
796 
797  const auto bits_needed = std::lround(ceil(log2(add_modes_ordered.size())));
798  BitConfig bitConfig(mrrg.initiationInterval());
799 
800  // Organize nodes mapping by cycle
801  std::vector<MRRGNodesFromOpNode> opNodesByCycle(mrrg.initiationInterval());
802  for (const auto& op_and_mrrg_nodes : mrrg_nodes_from_op_node) {
803  for (const auto& mrrg_node : op_and_mrrg_nodes.second) {
804  opNodesByCycle[mrrg_node->cycle][op_and_mrrg_nodes.first].insert(mrrg_node);
805  }
806  }
807 
808  int cycle = 0;
809  for (auto & op_and_mrrg_nodes : opNodesByCycle) {
810  if (op_and_mrrg_nodes.empty()) {
811  bitConfig.add({ (size_t)bits_needed, BitSetting::LOW }, cycle);
812  } else if (op_and_mrrg_nodes.size() == 1) {
813  const auto find_result = std::find(begin(add_modes_ordered), end(add_modes_ordered), begin(op_and_mrrg_nodes)->first->opcode);
814  if (find_result == end(add_modes_ordered)) {
815  throw cgrame_error("couldn't find op in supported modes list");
816  } else {
817  bitConfig.add( bitsettings_from_int(std::distance(begin(add_modes_ordered), find_result), bits_needed), cycle);
818  }
819 
820  } else {
821  throw cgrame_error("expect either 0 or 1 op nodes");
822  }
823  ++cycle;
824  }
825 
826  return bitConfig;
827 }
828 
829 MRRG* FracAddUnit::createMRRG(unsigned II = 1)
830 {
831  MRRG* result_ptr = new MRRG(II);
832  auto& result = *result_ptr;
833 
834  for(unsigned i = 0; i < II; i+= getII())
835  {
836  // create nodes
838 
840  MRRG::NodeDescriptor fu = result.insert(MRRGNode::make_function(this, data_size, i, "frac_add_unit", getLatency(), add_modes_ordered)).first;
841 
842  MRRG::NodeDescriptor out = result.insert(MRRGNode::make_routing(this, data_size, i, "out")).first;
843 
844  result.link(in_a, fu);
845  result.link(in_b, fu);
846  (void)out;
847  }
848 
849  for(unsigned i = 0; i < II; i+= getII())
850  {
851  MRRG::NodeDescriptor fu = result.getNode(i, "frac_add_unit");
852  MRRG::NodeDescriptor out_next = result.getNode(MOD_II(i + getLatency()), "out");
853 
854  result.link(fu, out_next);
855  }
856 
857  return result_ptr;
858 }
859 
861 {
862 }
OpCode::ADD_HALF
@ ADD_HALF
BitConfig
Definition: BitSetting.h:58
FracMulUnit::GenericName
virtual std::string GenericName() override
Definition: ModuleFracUnit.cpp:350
FracMulUnit::FracMulUnit
FracMulUnit(std::string name, Location loc, unsigned size, int II, int latency)
Definition: ModuleFracUnit.cpp:338
ConfigCell
Definition: Module.h:825
OpCode::MULS_HALF_LO
@ MULS_HALF_LO
OpCode::MULS_FULL_LO
@ MULS_FULL_LO
FracUnit::supported_modes
std::vector< OpGraphOpCode > supported_modes
Definition: Module.h:452
FracAddUnit::getLatency
int getLatency() const
Definition: Module.h:500
FracMulUnit::~FracMulUnit
virtual ~FracMulUnit()
Definition: ModuleFracUnit.cpp:640
Multiplexer
Zero-cycle latency multiplexer.
Definition: Module.h:592
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
MRRGNodesFromOpNode
std::map< OpGraphOp *, std::set< MRRG::NodeDescriptor > > MRRGNodesFromOpNode
Definition: Module.h:146
FracAddUnit::GenericName
virtual std::string GenericName() override
Definition: ModuleFracUnit.cpp:673
Location
Definition: Module.h:156
Module::data_size
unsigned data_size
Definition: Module.h:338
OpCode::ADD_QUART
@ ADD_QUART
FracMulUnit::createMRRG
virtual MRRG * createMRRG(unsigned II) override
Definition: ModuleFracUnit.cpp:609
FracAddUnit::getII
int getII() const
Definition: Module.h:499
FracAddUnit::~FracAddUnit
virtual ~FracAddUnit()
Definition: ModuleFracUnit.cpp:860
Operands::BINARY_LHS
static constexpr auto & BINARY_LHS
Definition: OpGraph.h:89
FracUnit::~FracUnit
virtual ~FracUnit()
Definition: ModuleFracUnit.cpp:298
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
Module.h
Module::parameterlist
std::map< std::string, unsigned > parameterlist
Definition: Module.h:224
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
FracAddUnit::all_modes
static const std::map< OpGraphOpCode, LLVMMode > all_modes
Definition: Module.h:502
FracUnit::FracUnit
FracUnit(std::string name, Location loc, std::vector< OpGraphOpCode > supported_modes, unsigned size, int II, int latency)
Definition: ModuleFracUnit.cpp:22
OpCode::MULU_QUART_LO
@ MULU_QUART_LO
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
FracAddUnit::createMRRG
virtual MRRG * createMRRG(unsigned II) override
Definition: ModuleFracUnit.cpp:829
OpCode::MULS_QUART_HI
@ MULS_QUART_HI
OpCode::MULU_FULL_LO
@ MULU_FULL_LO
MRRGNodesFromValNode
std::map< OpGraphVal *, std::set< MRRG::NodeDescriptor > > MRRGNodesFromValNode
Definition: Module.h:147
OpCode::MULU_HALF_HI
@ MULU_HALF_HI
BitSetting::LOW
@ LOW
FracAddUnit::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: ModuleFracUnit.cpp:787
Mapping
Definition: Mapping.h:31
MOD_II
#define MOD_II(x)
Definition: Module.h:32
FracMulUnit::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleFracUnit.cpp:355
Operands::BINARY_RHS
static constexpr auto & BINARY_RHS
Definition: OpGraph.h:90
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
FracUnit::GenericName
virtual std::string GenericName() override
Definition: ModuleFracUnit.cpp:17
OpCode::MULU_HALF_LO
@ MULU_HALF_LO
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
FracMulUnit::getII
int getII() const
Definition: Module.h:472
SET_INDENT
const char *const SET_INDENT
Definition: Module.h:37
Module
Definition: Module.h:163
FracMulUnit::mul_modes_ordered
static const std::vector< OpGraphOpCode > mul_modes_ordered
Definition: Module.h:479
PORT_INPUT
@ PORT_INPUT
Definition: Module.h:63
OpCode::MULU_FULL_HI
@ MULU_FULL_HI
Module::portsToPropagate
std::vector< Port > portsToPropagate
Definition: Module.h:229
FracMulUnit::all_modes
static const std::map< OpGraphOpCode, LLVMMode > all_modes
Definition: Module.h:475
FracMulUnit
Definition: Module.h:455
Module::addConfig
void addConfig(ConfigCell *c, std::vector< std::string > ConnectTo)
Definition: Module.cpp:1087
end
auto end(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:138
MRRGNode
Definition: MRRG.h:60
FracAddUnit::CoreIRGenFunctionality
virtual nlohmann::json CoreIRGenFunctionality() override
Definition: ModuleFracUnit.cpp:678
Module::getSize
int getSize() const
Definition: Module.h:246
OpCode::MULS_FULL_HI
@ MULS_FULL_HI
Module::addSubModule
void addSubModule(Module *m)
Definition: Module.cpp:1124
OpCode::ADD_FULL
@ ADD_FULL
FracAddUnit
Definition: Module.h:482
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
OpCode::MULS_QUART_LO
@ MULS_QUART_LO
FracAddUnit::add_modes_ordered
static const std::vector< OpGraphOpCode > add_modes_ordered
Definition: Module.h:506
Module::loc
Location loc
Definition: Module.h:239
MRRG::initiationInterval
int initiationInterval() const
Definition: MRRG.h:346
FracMulUnit::getLatency
int getLatency() const
Definition: Module.h:473
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
OpCode::MULS_HALF_HI
@ MULS_HALF_HI
FracMulUnit::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: ModuleFracUnit.cpp:567
OpCode::MULU_QUART_HI
@ MULU_QUART_HI
OpGraph
Definition: OpGraph.h:215
cgrame_error
Definition: Exception.h:20
FracAddUnit::FracAddUnit
FracAddUnit(std::string name, Location loc, unsigned size, int II, int latency)
Definition: ModuleFracUnit.cpp:661
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