CGRA-ME
HyCUBEPE.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 //HyCUBEPE.cpp
17 
18 // Macro for calculating number of ones
19 static const unsigned char ones_in_4b[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
20 #define get_ones_in_8b(v) (ones_in_4b[v & 0x0f] + ones_in_4b[v >> 4])
21 
22 
23 
24 std::string HyCUBEPE::GenericName()
25 {
26  std::string name;
27 
28  if(predExist)
29  {
30  name = "hycube_pred_in" + std::to_string(pe_conn_in) + "_out" + std::to_string(pe_conn_out) + "_pred_in" + std::to_string(pred_conn_in) + "_pred_out" + std::to_string(pred_conn_out);
31  } else
32  {
33  name = "hycube_in" + std::to_string(pe_conn_in) + "_out" + std::to_string(pe_conn_out);
34  }
35 
36  return name;
37 }
38 
39 
40 HyCUBEPE::HyCUBEPE(std::string name, bool predExist, int pe_conn_in, int pe_conn_out,
41  int pred_conn_in, int pred_conn_out, int fu_II, int II, int latency, Location loc, std::string pred_scheme)
42  : Module(name, loc, 32)
43  , predExist(predExist)
44  , pe_conn_in(pe_conn_in)
45  , pe_conn_out(pe_conn_out)
46  , pred_conn_in(pred_conn_in)
47  , pred_conn_out(pred_conn_out)
48 {
49  // Figure out Word Length
50  int size = getSize();
51 
52  // Figure out number of inputs, and outputs using pe_conn
53  int num_outPorts = get_ones_in_8b(pe_conn_out);
54  int num_inPorts = get_ones_in_8b(pe_conn_in);
55 
56  // TODO: Calculate total number of possible inputs/outputs, based on the length of pe_conn
57  int num_Possible_Ports = 8;
58 
59  // 1. Add all submodules
60  // ALU
61  addSubModule(new FuncUnit("ALU", loc,
62  {
67  OpCode::OR,
73  }, size, fu_II, latency), 0, 0.75, 0.5, 0.25);
74 
75  // Crossbar
76  // NOTE: Crossbar connection indices may not match with HyCUBEPE's input and output indices (ie this.in1 may be assigned to crossbar.in0)
77  int numCrossbarInputs = num_inPorts + 3; // Add 3 for ALU, const and RES register outputs,
78  int numCrossbarOutputs = num_outPorts + 2; // Add 2 for ALU in_a and in_b
79  bool crossbarSelect = predExist & pred_scheme.find("event") == std::string::npos;
80  addSubModule(new Crossbar("crossbar", loc, numCrossbarInputs, numCrossbarOutputs, size, crossbarSelect, II), 0.5, 0.375, 0.4, 0.4);
81 
82  // Registers
83  // RES register (stores output of ALU)
84  addSubModule(new Register("RES", loc, size), 0.5, 0.875, 0.5, 0.125);
85 
86 
87  // Inputs to ALU
88  addSubModule(new Register("rega", loc, size), 0, 0.05, 0.5, 0.125);
89  addSubModule(new Register("regb", loc, size), 0.5, 0.05, 0.5, 0.125);
90  addSubModule(new ConstUnit("const_val", loc, size, II), 0.0, 0.15, 1, 0.125);
91 
92  // Input registers and 2-to-1 Muxes must follow the pe_conn_in convention (only initialize for enabled connections)
93  for (int i = 0; i < num_Possible_Ports; i++) {
94  if (pe_conn_in & (0b00000001 << i)) {
95  // Input registers (use size to include predication)
96  addSubModule(new Register("reg" + std::to_string(i), loc, size), static_cast<double>(i)/num_Possible_Ports, 0.5, 1.0/num_Possible_Ports, 0.125);
97  // Input 2-to-1 muxes
98  addSubModule(new Multiplexer("mux_" + std::to_string(i), loc, 2, size), static_cast<double>(i)/num_Possible_Ports, 0.625, 1.0/num_Possible_Ports, 0.125);
99  }
100  }
101 
102  if (II > 1)
103  addPort("Context", PORT_INPUT, ceil(log2(II)));
104 
105  // 2. Add Configuration files
106  // ALU
107  addConfig(new ConfigCell("ALUconfig", II), {"ALU.select"});
108  addConfig(new ConfigCell("RegAConfig", II), {"regb.enable"});
109  addConfig(new ConfigCell("RegBConfig", II), {"rega.enable"});
110  addConfig(new ConfigCell("RESConfig", II), {"RES.enable"});
111 
112 
113  for(int i = 0; i < num_Possible_Ports; i++)
114  {
115  if (pe_conn_in & (0b00000001<<i))
116  {
117  // Input registers
118  addConfig(new ConfigCell("Reg" + std::to_string(i) + "config", II), {"reg" + std::to_string(i) + ".enable"});
119  // Input 2-to-1 Mux
120  addConfig(new ConfigCell("Mux" + std::to_string(i) + "config", II), {"mux_" + std::to_string(i) + ".select"});
121  }
122  }
123 
124  if (II > 1) {
125  addConnection("this.Context" , "ALUconfig.Context", false);
126  addConnection("this.Context" , "RegAConfig.Context", false);
127  addConnection("this.Context" , "RegBConfig.Context", false);
128  addConnection("this.Context" , "RESConfig.Context", false);
129  for(int i = 0; i < num_Possible_Ports; i++) {
130  if (pe_conn_in & (0b00000001<<i)) {
131  addConnection("this.Context" , "Reg" + std::to_string(i) + "config.Context", false);
132  addConnection("this.Context" , "Mux" + std::to_string(i) + "config.Context", false);
133  }
134  }
135  addConnection("this.Context" , "crossbar.Context", false);
136  addConnection("this.Context" , "const_val.Context", false);
137  }
138 
139  // 3. Ports and Wiring
140  // 3A. Input Ports and Output Ports must follow pe_conn_in and pe_conn_out conventions, respectively
141  for(int i = 0; i < num_Possible_Ports; i++)
142  {
143  if (pe_conn_in & (0b00000001<<i))
144  {
145  // Add input ports
146  addPort("in" + std::to_string(i), PORT_INPUT, size);
147  node_relative_position.insert({"in" + std::to_string(i), {0.1, static_cast<double>(i)/num_Possible_Ports}}); // Add position for visualization
148  }
149 
150  if (pe_conn_out & (0b00000001<<i))
151  {
152  // Add output ports
153  addPort("out" + std::to_string(i), PORT_OUTPUT, size);
154  node_relative_position.insert({"out" + std::to_string(i), {0.9, static_cast<double>(i)/num_Possible_Ports}}); // Add position for visualization
155  }
156  }
157 
158  // 3B. Connections
159  // InPorts to Registers
160  for(int i = 0; i < num_Possible_Ports; i++)
161  {
162  if (pe_conn_in & (0b00000001<<i))
163  { // InPorts to Registers
164  addConnection("this.in" + std::to_string(i), "reg" + std::to_string(i) + ".in");
165 
166  // InPorts and Registers to Muxes
167  addConnection("this.in" + std::to_string(i), "mux_" + std::to_string(i) + ".in0");
168  addConnection("reg" + std::to_string(i) + ".out", "mux_" + std::to_string(i) + ".in1");
169  }
170  }
171 
172  // Muxes to Crossbar
173  int crossbarInputCounter = 0; // Needed because the crossbar and mux indices may not be the same
174 
175  for(int i = 0; i < num_Possible_Ports; i++)
176  {
177  if (pe_conn_in & (0b00000001<<i))
178  {
179  addConnection("mux_" + std::to_string(i) + ".out", "crossbar.in" + std::to_string(crossbarInputCounter));
180  crossbarInputCounter += 1; //TODO: Throw an error if this goes out of bounds
181  }
182  }
183 
184  // ALU to Crossbar
185  addConnection("ALU.out", "crossbar.in" + std::to_string(num_inPorts));
186 
187  // RES to Crossbar
188  addConnection("RES.out", "crossbar.in" + std::to_string(num_inPorts + 1));
189 
190  // Const to Crossbar
191  addConnection("const_val.out", "crossbar.in" + std::to_string(num_inPorts + 2));
192 
193  // Crossbar to outPorts
194  int crossbarOutputCounter = 0; // Needed because the crossbar and mux indices may not be the same
195 
196  for(int i = 0; i < num_Possible_Ports; i++)
197  {
198  if (pe_conn_out & (0b00000001<<i))
199  {
200  addConnection("crossbar.out" + std::to_string(crossbarOutputCounter), "this.out" + std::to_string(i));
201  crossbarOutputCounter += 1; //TODO: Throw an error if this goes out of bounds
202  }
203  }
204 
205  // Crossbar to rega, regb
206  addConnection("crossbar.out" + std::to_string(num_outPorts), "rega.in");
207  addConnection("crossbar.out" + std::to_string(num_outPorts + 1), "regb.in");
208 
209  // ALU inputs
210  addConnection("rega.out", "ALU.in_a");
211  addConnection("regb.out", "ALU.in_b");
212 
213  // ALU to RES
214  addConnection("ALU.out", "RES.in");
215 
216  // If predExist add predication network.
217  if (!predExist) return;
218  /****************** PRED NETWORK BEGINS **************/
219  /* The predication network is the same as the normal */
220  /* 32-bit architecture however it is a 1-bit wide n- */
221  /* etwork. */
222  /*****************************************************/
223 
224  addSubModule(new TruncateInput("trunc_res", loc, 1, size));
225  addSubModule(new TruncateInput("trunc_const", loc, 1, size));
226  // set size =1 for pred network
227  size = 1;
228 
229  // Figure out number of inputs, and outputs using pred_conn
230  int num_pred_outPorts = get_ones_in_8b(pred_conn_out);
231  int num_pred_inPorts = get_ones_in_8b(pred_conn_in);
232  // Add 2 for ALU_pred and RES_pred register outputs,
233  // add 1 for const and 1 for connection coming from ALU
234  int numPredCrossbarInputs = num_pred_inPorts + 2 + 2;
235  // Add 2 for ALU_pred in_a, in_b, add 1 to connect back to phi mux
236  int numPredCrossbarOutputs = num_pred_outPorts + 2 + 1;
237 
238  // 1. Add all submodules
239  // ALU
240  addSubModule(new FuncUnit("ALU_pred", loc,
241  {
242  OpCode::AND,
243  OpCode::OR,
244  OpCode::XOR,
245  }, size, 1, latency), 0, 0.75, 0.5, 0.25);
246 
247  // Crossbar
248  // NOTE: Crossbar connection indices may not match with HyCUBEPE_Phi's input and output indices (ie this.in1 may be assigned to crossbar.in0)
249  addSubModule(new Crossbar("crossbar_pred", loc, numPredCrossbarInputs, numPredCrossbarOutputs, size, false, II), 0.5, 0.375, 0.4, 0.4);
250 
251  // Registers
252  // RES register (stores output of ALU)
253  addSubModule(new Register("RES_pred", loc, size), 0.5, 0.875, 0.5, 0.125);
254 
255  // Inputs to ALU
256  addSubModule(new Register("rega_pred", loc, size), 0, 0.05, 0.5, 0.125);
257  addSubModule(new Register("regb_pred", loc, size), 0.5, 0.05, 0.5, 0.125);
258  // addSubModule(new ConstUnit("const_pred", loc, 1), 0.0, 0.15, 1, 0.125);
259 
260  // Input registers and 2-to-1 Muxes must follow the pred_conn_in convention (only initialize for enabled connections)
261  for (int i = 0; i < num_Possible_Ports; i++) {
262  if (pred_conn_in & (0b00000001 << i)) {
263  // Input registers (use size to include predication)
264  addSubModule(new Register("reg_pred" + std::to_string(i), loc, size), static_cast<double>(i)/num_Possible_Ports, 0.5, 1.0/num_Possible_Ports, 0.125);
265  // Input 2-to-1 muxes
266  addSubModule(new Multiplexer("mux_pred_" + std::to_string(i), loc, 2, size), static_cast<double>(i)/num_Possible_Ports, 0.625, 1.0/num_Possible_Ports, 0.125);
267  }
268  }
269 
270 
271 
272  for(int i = 0; i < num_Possible_Ports; i++)
273  {
274  if (pred_conn_in & (0b00000001<<i))
275  {
276  // Add input ports
277  addPort("in_pred" + std::to_string(i), PORT_INPUT, size);
278  node_relative_position.insert({"in_pred" + std::to_string(i), {0.1, static_cast<double>(i)/num_Possible_Ports}}); // Add position for visualization
279  }
280 
281  if (pred_conn_out & (0b00000001<<i))
282  {
283  // Add output ports
284  addPort("out_pred" + std::to_string(i), PORT_OUTPUT, size);
285  node_relative_position.insert({"out_pred" + std::to_string(i), {0.9, static_cast<double>(i)/num_Possible_Ports}}); // Add position for visualization
286  }
287  }
288 
289  // 2. Add Configuration files
290  // ALU
291  addConfig(new ConfigCell("ALUconfig_pred", II), {"ALU_pred.select"});
292  addConfig(new ConfigCell("RegAConfig_pred", II), {"regb_pred.enable"});
293  addConfig(new ConfigCell("RegBConfig_pred", II), {"rega_pred.enable"});
294  addConfig(new ConfigCell("RESConfig_pred", II), {"RES_pred.enable"});
295 
296  // addConfig(new ConfigCell{"constValPred"}, {"const_pred.in"});
297 
298 
299  for(int i = 0; i < num_Possible_Ports; i++) {
300  if (pred_conn_in & (0b00000001<<i))
301  {
302  // Input registers
303  addConfig(new ConfigCell("Reg_pred" + std::to_string(i) + "config", II), {"reg_pred" + std::to_string(i) + ".enable"});
304  // Input 2-to-1 Mux
305  addConfig(new ConfigCell("Mux_pred" + std::to_string(i) + "config", II), {"mux_pred_" + std::to_string(i) + ".select"});
306  }
307  }
308  if (II > 1) {
309  addConnection("this.Context" , "ALUconfig_pred.Context", false);
310  addConnection("this.Context" , "RegAConfig_pred.Context", false);
311  addConnection("this.Context" , "RegBConfig_pred.Context", false);
312  addConnection("this.Context" , "RESConfig_pred.Context", false);
313  for(int i = 0; i < num_Possible_Ports; i++) {
314  if (pred_conn_in & (0b00000001<<i)) {
315  addConnection("this.Context" , "Reg_pred" + std::to_string(i) + "config.Context", false);
316  addConnection("this.Context" , "Mux_pred" + std::to_string(i) + "config.Context", false);
317  }
318  }
319 
320  addConnection("this.Context" , "crossbar_pred.Context", false);
321  }
322 
323  // 3B. Connections
324  // InPorts to Registers
325  addConnection("ALU.out", "trunc_res.in");
326  addConnection("const_val.out", "trunc_const.in");
327  addConnection("trunc_res.out0", "crossbar_pred.in" + std::to_string(numPredCrossbarInputs - 1));
328 
329  for(int i = 0; i < num_Possible_Ports; i++)
330  {
331  if (pred_conn_in & (0b00000001<<i))
332  { // InPorts to Registers
333  addConnection("this.in_pred" + std::to_string(i), "reg_pred" + std::to_string(i) + ".in");
334 
335  // InPorts and Registers to Muxes
336  addConnection("this.in_pred" + std::to_string(i), "mux_pred_" + std::to_string(i) + ".in0");
337  addConnection("reg_pred" + std::to_string(i) + ".out", "mux_pred_" + std::to_string(i) + ".in1");
338  }
339  }
340 
341  // Muxes to Crossbar
342  crossbarInputCounter = 0; // Needed because the crossbar and mux indices may not be the sameout0
343 
344  for(int i = 0; i < num_Possible_Ports; i++)
345  {
346  if (pred_conn_in & (0b00000001<<i))
347  {
348  addConnection("mux_pred_" + std::to_string(i) + ".out", "crossbar_pred.in" + std::to_string(crossbarInputCounter));
349  crossbarInputCounter += 1; //TODO: Throw an error if this goes out of bounds
350  }
351  }
352 
353 
354  // ALU to Crossbar
355  addConnection("ALU_pred.out", "crossbar_pred.in" + std::to_string(num_pred_inPorts));
356 
357  // RES to Crossbar
358  addConnection("RES_pred.out", "crossbar_pred.in" + std::to_string(num_pred_inPorts + 1));
359 
360  // Const to Crossbar
361  //addConnection("const_pred.out", "crossbar_pred.in" + std::to_string(num_pred_inPorts + 2));
362  addConnection("trunc_const.out0", "crossbar_pred.in" + std::to_string(num_pred_inPorts + 2));
363 
364  //TODO:: FIX THIS
365  crossbarOutputCounter = 0; // Needed because the crossbar and mux indices may not be the same
366 
367  for(int i = 0; i < num_Possible_Ports; i++)
368  {
369  if (pred_conn_out & (0b00000001<<i))
370  {
371  addConnection("crossbar_pred.out" + std::to_string(crossbarOutputCounter), "this.out_pred" + std::to_string(i));
372  crossbarOutputCounter += 1; //TODO: Throw an error if this goes out of bounds
373  }
374  }
375 
376  // Crossbar to rega, regb
377  addConnection("crossbar_pred.out" + std::to_string(num_pred_outPorts), "rega_pred.in");
378  addConnection("crossbar_pred.out" + std::to_string(num_pred_outPorts + 1), "regb_pred.in");
379 
380 
381  // ALU inputs
382  addConnection("rega_pred.out", "ALU_pred.in_a");
383  addConnection("regb_pred.out", "ALU_pred.in_b");
384 
385 
386  // ALU to RES
387  addConnection("ALU_pred.out", "RES_pred.in");
388  if (pred_scheme.find("event") == std::string::npos) {
389  //addConnection("RES_pred.out", "crossbar.pred_in");
390  addConnection("crossbar_pred.out" + std::to_string(numPredCrossbarOutputs -1), "crossbar.pred_in");
391  }
392 }
Module::name
std::string name
Definition: Module.h:341
ConfigCell
Definition: Module.h:825
get_ones_in_8b
#define get_ones_in_8b(v)
Definition: HyCUBEPE.cpp:20
TruncateInput
Zero-cycle latency split input.
Definition: Module.h:621
ones_in_4b
static const unsigned char ones_in_4b[]
Definition: HyCUBEPE.cpp:19
Multiplexer
Zero-cycle latency multiplexer.
Definition: Module.h:592
Location
Definition: Module.h:156
HyCUBEPE::pred_conn_in
int pred_conn_in
Definition: UserModules.h:47
OpCode::ASHR
@ ASHR
OpCode::OR
@ OR
Module::addConnection
void addConnection(std::string src, std::string dst, bool isInMRRG=true)
Definition: Module.cpp:1241
Register
A simple latency element with an enable signal; a data flip-flop.
Definition: Module.h:566
OpCode::ADD
@ ADD
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
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
OpCode::LSHR
@ LSHR
HyCUBEPE::predExist
bool predExist
Definition: UserModules.h:44
HyCUBEPE::GenericName
virtual std::string GenericName()
Definition: HyCUBEPE.cpp:24
OpCode::XOR
@ XOR
HyCUBEPE::pe_conn_in
int pe_conn_in
Definition: UserModules.h:45
UserModules.h
ConstUnit
Definition: Module.h:540
Module
Definition: Module.h:163
PORT_INPUT
@ PORT_INPUT
Definition: Module.h:63
HyCUBEPE::pred_conn_out
int pred_conn_out
Definition: UserModules.h:48
OpCode::SHL
@ SHL
Module::addConfig
void addConfig(ConfigCell *c, std::vector< std::string > ConnectTo)
Definition: Module.cpp:1087
Module::getSize
int getSize() const
Definition: Module.h:246
Module::addSubModule
void addSubModule(Module *m)
Definition: Module.cpp:1124
OpCode::AND
@ AND
OpCode::SUB
@ SUB
Crossbar
Definition: Module.h:720
OpCode::MUL
@ MUL
Module::loc
Location loc
Definition: Module.h:239
OpCode::ICMP
@ ICMP
HyCUBEPE::pe_conn_out
int pe_conn_out
Definition: UserModules.h:46
HyCUBEPE::HyCUBEPE
HyCUBEPE(std::string name, bool predExist, int pe_conn_in, int pe_conn_out, int pred_conn_in, int pre_conn_out, int fu_II, int II, int latency, Location Loc, std::string pred_scheme="")
Definition: HyCUBEPE.cpp:40
FuncUnit
Functional Unit, does one of a set of arithmetic computations.
Definition: Module.h:406
PORT_OUTPUT
@ PORT_OUTPUT
Definition: Module.h:64