CGRA-ME
HyCUBE.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 //HyCUBE.cpp
12 //Implements the HyCUBE architecture using the C++ API in CGRA-ME
13 //Utilizes HyCUBEPE, a processing element specified in the HyCUBE paper
14 
15 #include <CGRA/Exception.h>
18 #include <vector>
19 
20 // Checking for connections
21 #define has_input_from_N(conn) (conn & 0b00000001)
22 #define has_input_from_E(conn) (conn & 0b00000010)
23 #define has_input_from_S(conn) (conn & 0b00000100)
24 #define has_input_from_W(conn) (conn & 0b00001000)
25 #define has_input_from_NW(conn) (conn & 0b00010000)
26 #define has_input_from_NE(conn) (conn & 0b00100000)
27 #define has_input_from_SE(conn) (conn & 0b01000000)
28 #define has_input_from_SW(conn) (conn & 0b10000000)
29 
30 // Identifying PE position
31 #define is_top_pe(r, c, rows, cols) (r == 0)
32 #define is_bot_pe(r, c, rows, cols) (r == rows-1)
33 #define is_leftmost_pe(r, c, rows, cols) (c == 0)
34 #define is_rightmost_pe(r, c, rows, cols) (c == cols-1)
35 
36 // Masks
37 #define mask_top_pe(conn) ((conn & 0b11001111) | 0b00000001) // Remove NE, NW connections, add N connection
38 #define mask_bot_pe(conn) ((conn & 0b00111111) | 0b00000100) // Remove SE, SW connections, add S connection
39 #define mask_leftmost_pe(conn) ((conn & 0b01101111) | 0b00001000) // Remove NW, SW connections, add W connection
40 #define mask_rightmost_pe(conn) ((conn & 0b10011111) | 0b00000010) // Remove NE, SE connections, add E connection
41 // Predication Masks
42 #define mask_top_pred(conn) ((conn & 0b11001111) | 0b00000001) // Remove NE, NW connections, add N connection
43 #define mask_bot_pred(conn) ((conn & 0b00111111) | 0b00000100) // Remove SE, SW connections, add S connection
44 #define mask_leftmost_pred(conn) ((conn & 0b01100111)) // Remove NW, SW connections, remove W connection
45 #define mask_rightmost_pred(conn) ((conn & 0b10011111) | 0b00000010) // Remove NE, SE connections, add E connection
46 #define mask_rightmost_pred_mem(conn) ((conn & 0b10011101)) // Remove NE, SE connections, remove E connection
47 // Event Predication Masks
48 #define mask_top_event_pred(conn) ((conn & 0b11001111) | 0b00000001) // Remove NE, NW connections, add N connection
49 
50 int leftshift2(int val) {
51  // bitshifts val left by 2 bits, with wraparound
52  // val is assumed to only have the right-most 4 bits populated
53  return (((val << 2) & 0x0f) | (val >> 2));
54 }
55 
56 void fillPEConnArray(std::vector < std::vector < std::vector<int> > > &pcv,
57  int pe_conn_orig, int rows, int cols, bool pred, bool extra_mem = false, std::string pred_scheme = "") {
58  // fills the pe_conn_vector with all incoming and outgoing connections, including special cases (architecture-specific)
59  // pcv is a vector whose address is set to pe_conn_vector (editing pcv_ptr also edits pe_conn_vector)
60 
61  // Variable Declaration
62  int lefthalf;
63  int righthalf;
64  int pe_conn_out;
65 
66 
67  // 1. Fill all inputs
68  for (int r = 0; r < rows; r++) {
69  for (int c = 0; c < cols; c++) {
70  pcv[0][r][c] = pe_conn_orig;
71  }
72  }
73 
74  // 2. Fill all outputs
75  // Isolate first 4 and last 4 bits in pe_conn
76  lefthalf = (pe_conn_orig >> 4) & 0x0f;
77  righthalf = pe_conn_orig & 0x0f;
78 
79  // Calculate outputs of left and right half
80  lefthalf = leftshift2(lefthalf);
81  righthalf = leftshift2(righthalf);
82 
83  // Put them back together to get pe_conn_out
84  pe_conn_out = (lefthalf << 4) | righthalf;
85 
86  // Fill vector
87  for (int r = 0; r < rows; r++) {
88  for (int c = 0; c < cols; c++) {
89  pcv[1][r][c] = pe_conn_out;
90  }
91  }
92 
93  // 3. Consider HyCUBE-specific edge cases (corners are handled in the process)
94  for (int r = 0; r < rows; r++) {
95  for (int c = 0; c < cols; c++) {
96  // Case 1: Top Row PE's
97  if (is_top_pe(r, c, rows, cols)) {
98  if (pred) {
99  if (pred_scheme.find("event") != std::string::npos) {
100  // Change outputs
101  pcv[1][r][c] = mask_top_event_pred(pcv[1][r][c]);
102  } else {
103  // Change outputs
104  pcv[1][r][c] = mask_top_pred(pcv[1][r][c]);
105  }
106  // Change inputs
107  pcv[0][r][c] = mask_top_pred(pcv[0][r][c]);
108  } else {
109  // Change inputs
110  pcv[0][r][c] = mask_top_pe(pcv[0][r][c]);
111  // Change outputs
112  pcv[1][r][c] = mask_top_pe(pcv[1][r][c]);
113  }
114  }
115 
116  // Case 2: Bottom Row PE's
117  if (is_bot_pe(r, c, rows, cols)) {
118  if (pred) {
119  // Change inputs
120  pcv[0][r][c] = mask_bot_pred(pcv[0][r][c]);
121  // Change outputs
122  pcv[1][r][c] = mask_bot_pred(pcv[1][r][c]);
123  } else {
124  // Change inputs
125  pcv[0][r][c] = mask_bot_pe(pcv[0][r][c]);
126  // Change outputs
127  pcv[1][r][c] = mask_bot_pe(pcv[1][r][c]);
128  }
129  }
130 
131  // Case 3: Left Column PE's
132  if (is_leftmost_pe(r, c, rows, cols)) {
133  if (pred) {
134  // Change inputs
135  pcv[0][r][c] = mask_leftmost_pred(pcv[0][r][c]);
136  // Change outputs
137  pcv[1][r][c] = mask_leftmost_pe(pcv[1][r][c]);
138  } else {
139  // Change inputs
140  pcv[0][r][c] = mask_leftmost_pe(pcv[0][r][c]);
141  // Change outputs
142  pcv[1][r][c] = mask_leftmost_pe(pcv[1][r][c]);
143  }
144  }
145 
146  // Case 4: Right Column PE's
147  if (is_rightmost_pe(r, c, rows, cols)) {
148  if (pred) {
149  // Change inputs
150  if (extra_mem) {
151  pcv[0][r][c] = mask_rightmost_pred_mem(pcv[0][r][c]);
152  } else {
153  pcv[0][r][c] = mask_rightmost_pred(pcv[0][r][c]);
154  }
155  // Change outputs
156  pcv[1][r][c] = mask_rightmost_pred(pcv[1][r][c]);
157  } else {
158  // Change inputs
159  pcv[0][r][c] = mask_rightmost_pe(pcv[0][r][c]);
160  // Change outputs
161  pcv[1][r][c] = mask_rightmost_pe(pcv[1][r][c]);
162  }
163  }
164  }
165  }
166 }
167 
168 std::unique_ptr<CGRA> UserArchs::createHyCUBEArch(const ConfigStore& args) {
169  // Declare all variables
170  const unsigned int cols = args.getInt("cols");
171  const unsigned int rows = args.getInt("rows");
172  const int fu_II = args.getInt("fu_II");
173  const int pe_conn = args.getInt("pe_conn");
174  const int fu_latency = args.getInt("fu_latency");
175  const int num_const_addresses = args.getInt("num_const_addresses");
176  const bool pred = args.getBool("pred");
177  const int II = args.getInt("II");
178  const bool extra_mem = args.getBool("extra_mem");
179  const std::string pred_scheme = args.getString("pred_scheme");
180 
186  double moduleW = 1.0/(cols+2);
187  double moduleH = 1.0/(rows+2);
188 
189  // Determine bit width for predication
190  const int SIZE = [&]() {
191  return 32;
192  }();
193 
194  // Variables for use when making connections between tiles
195  std::string north = std::to_string(0);
196  std::string east = std::to_string(1);
197  std::string west = std::to_string(3);
198  std::string south = std::to_string(2);
199  std::string northWest = std::to_string(4);
200  std::string northEast = std::to_string(5);
201  std::string southEast = std::to_string(6);
202  std::string southWest = std::to_string(7);
203 
204  // Determine all input and output connections
205 
206  // Vector describes the incoming and outgoing connection PE's (including to external units such as memory)
207  // Organization: pe_conn_vec[in(0)/out(1)] [rows] [cols] ie pe_conn_vec[0][1][2]
208  // stores the incoming connections for the PE at row 1, column 2
209 
210  std::vector < std::vector < std::vector<int> > >
211  pe_conn_vec(2, std::vector< std::vector<int> >(rows, std::vector<int>(cols)));
212 
213  std::vector < std::vector < std::vector<int> > >
214  pred_conn_vec(2, std::vector< std::vector<int> >(rows, std::vector<int>(cols)));
215  // Populate pe_conn_array
216  fillPEConnArray(pe_conn_vec, pe_conn, rows, cols, false);
217 
218  fillPEConnArray(pred_conn_vec, pe_conn, rows, cols, pred, extra_mem, pred_scheme);
219  auto cgra_storage = std::make_unique<CGRA>();
220  Module* result = &cgra_storage->getTopLevelModule();
221  if (II > 1) {
222  result->addSubModule(new ContextCell("context_cell", II)); // ContextCell stores num of used contexts (II)
223  }
224  // 1. Add all elements within the Architecture
225  // HyCUBE Processing Elements
226  for (unsigned int c = 0; c < cols; c++) {
227  for (unsigned int r = 0; r < rows; r++) {
228  Location loc = {c + 1, r + 1};
229  auto PE = new HyCUBEPE(
230  "pe_c" + std::to_string(c) + "_r" + std::to_string(r),
231  pred,
232  pe_conn_vec[0][r][c],
233  pe_conn_vec[1][r][c],
234  pred_conn_vec[0][r][c],
235  pred_conn_vec[1][r][c],
236  fu_II,
237  II,
238  fu_latency,
239  loc,
240  pred_scheme);
241  result->addSubModule(PE, (c+1.0)*moduleW, (r+1.0)*moduleH, moduleW, moduleH);
242  if (II > 1) {
243  result->addSubModule(new ContextCounter("context_counter_pe_c" + std::to_string(c) + "_r" + std::to_string(r), II));
244  result->addConnection("context_cell.Context_Used", "context_counter_pe_c" + std::to_string(c) + "_r" + std::to_string(r) + ".Context_Used", false);
245  result->addConnection("context_counter_pe_c" + std::to_string(c) + "_r" + std::to_string(r) + ".Context", "pe_c" + std::to_string(c) + "_r" + std::to_string(r) + ".Context", false);
246  }
247  }
248 
249  }
250 
251  // Memory Ports
252  for (unsigned int r = 0; r < rows; r++) {
253  Location loc = {0, r + 1};
254  auto mem_port = new MemPort("mem_" + std::to_string(r), loc, rows, SIZE, num_const_addresses, pred, II);
255  result->addSubModule(mem_port, 0, (r+1.0)*moduleH, moduleW, moduleH);
256  if (II > 1) {
257  result->addSubModule(new ContextCounter("context_counter_mem_" + std::to_string(r), II));
258  result->addConnection("context_cell.Context_Used", "context_counter_mem_" + std::to_string(r) + ".Context_Used", false);
259  result->addConnection("context_counter_mem_" + std::to_string(r) + ".Context", "mem_" + std::to_string(r) + ".Context", false);
260  }
261  }
262 
263  // I/O's
264  for (unsigned int c = 0; c < cols; c++) {
265  Location loc_bot = {c + 1, rows + 1};
266  Location loc_top = {c + 1, 0};
267  auto io_top = new IO("io_top_" + std::to_string(c), loc_top, SIZE, II);
268  auto io_bottom = new IO("io_bottom_" + std::to_string(c), loc_bot, SIZE, II);
269  result->addSubModule(io_top, c/(cols+2.0), 0, moduleW, moduleH);
270  result->addSubModule(io_bottom, c*moduleW, (rows+1.0)*moduleH, moduleW, moduleH);
271  if (II > 1) {
272  result->addSubModule(new ContextCounter("context_counter_io_top_" + std::to_string(c), II));
273  result->addSubModule(new ContextCounter("context_counter_io_bottom_" + std::to_string(c), II));
274  result->addConnection("context_cell.Context_Used", "context_counter_io_top_" + std::to_string(c) + ".Context_Used", false);
275  result->addConnection("context_cell.Context_Used", "context_counter_io_bottom_" + std::to_string(c) + ".Context_Used", false);
276  result->addConnection("context_counter_io_top_" + std::to_string(c) + ".Context", "io_top_" + std::to_string(c) + ".Context", false);
277  result->addConnection("context_counter_io_bottom_" + std::to_string(c) + ".Context", "io_bottom_" + std::to_string(c) + ".Context", false);
278  }
279  }
280 
281  for (unsigned int r = 0; r < rows; r++) {
282  Location loc = {cols + 1, r + 1};
283  if (extra_mem) {
284  auto mem_port = new MemPort("mem_right_" + std::to_string(r), loc, rows, SIZE, num_const_addresses, pred, II);
285  result->addSubModule(mem_port, 0, (r+1.0)*moduleH, moduleW, moduleH);
286  if (II > 1) {
287  result->addSubModule(new ContextCounter("context_counter_mem_right_" + std::to_string(r), II));
288  result->addConnection("context_cell.Context_Used", "context_counter_mem_right_" + std::to_string(r) + ".Context_Used", false);
289  result->addConnection("context_counter_mem_right_" + std::to_string(r) + ".Context", "mem_right_" + std::to_string(r) + ".Context", false);
290  }
291  } else {
292  auto io_right = new IO("io_right_" + std::to_string(r), loc, SIZE, II);
293  result->addSubModule(io_right, (cols+1.0)*moduleW, (r+1.0)*moduleH, moduleW, moduleH);
294  if (II > 1) {
295  result->addSubModule(new ContextCounter("context_counter_io_right_" + std::to_string(r), II));
296  result->addConnection("context_cell.Context_Used", "context_counter_io_right_" + std::to_string(r) + ".Context_Used", false);
297  result->addConnection("context_counter_io_right_" + std::to_string(r) + ".Context", "io_right_" + std::to_string(r) + ".Context", false);
298  }
299  }
300  }
301 
302  // 2. Add Connections
303  // Inter-PE Connections (NEWS)
304  for (unsigned int c = 0; c < cols; c++) {
305  for (unsigned int r = 0; r < rows; r++) {
306  std::string currC = std::to_string(c);
307  std::string currR = std::to_string(r);
308 
309  std::string blk_n_c_r = "pe_c" + currC + "_r" + currR;
310 
311  // Use pe_conn to determine whether a connection should be made
312  if (has_input_from_N(pe_conn_vec[0][r][c])) {
313  // Special Case: Top Row PE's connect to I/O's
314  if (r == 0) {
315  result->addConnection("io_top_" + currC + ".out",
316  blk_n_c_r + ".in" + north);
317 
318  result->addConnection(blk_n_c_r + ".out" + north,
319  "io_top_" + currC + ".in");
320  } else {
321  result->addConnection("pe_c" + currC + "_r" + std::to_string(r-1) + ".out" + south,
322  blk_n_c_r + ".in" + north);
323  }
324  }
325 
326  if (has_input_from_E(pe_conn_vec[0][r][c])) {
327  // Special Case: Right-most PE's connect to I/O's
328  if (c == cols - 1) {
329  if (extra_mem) {
330  result->addConnection("mem_right_" + currR + ".out",
331  blk_n_c_r + ".in" + east);
332 
333  std::string _blk_prefix = "pe_c" + currC + "_r";
334  for (int _r = 0; _r < rows; _r++) {
335  std::string _currR = std::to_string(_r);
336  std::string _blk_n_c_r = _blk_prefix + _currR;
337  result->addConnection(_blk_n_c_r + ".out" + east,
338  "mem_right_" + currR + ".in" + _currR);
339  }
340  } else {
341  result->addConnection("io_right_" + currR + ".out",
342  blk_n_c_r + ".in" + east);
343 
344  result->addConnection(blk_n_c_r + ".out" + east,
345  "io_right_" + currR + ".in");
346  }
347  } else {
348  result->addConnection("pe_c" + std::to_string(c+1) + "_r" + currR + ".out" + west,
349  blk_n_c_r + ".in" + east);
350  }
351  }
352 
353  if (has_input_from_S(pe_conn_vec[0][r][c])) {
354  // Special Case: Bottom-most PE's connect to I/O's
355  if (r == rows - 1) {
356  result->addConnection("io_bottom_" + currC + ".out",
357  blk_n_c_r + ".in" + south);
358 
359  result->addConnection(blk_n_c_r + ".out" + south,
360  "io_bottom_" + currC + ".in");
361  } else {
362  result->addConnection("pe_c" + currC + "_r" + std::to_string(r+1) + ".out" + north,
363  blk_n_c_r + ".in" + south);
364  }
365  }
366 
367  if (has_input_from_W(pe_conn_vec[0][r][c])) {
368  // Special Case: Left-most PE's connect to Memory Ports
369  if (c == 0) {
370  result->addConnection("mem_" + currR + ".out",
371  blk_n_c_r + ".in" + west);
372 
373  std::string _blk_prefix = "pe_c" + currC + "_r";
374  for (int _r = 0; _r < rows; _r++) {
375  std::string _currR = std::to_string(_r);
376  std::string _blk_n_c_r = _blk_prefix + _currR;
377  result->addConnection(_blk_n_c_r + ".out" + west,
378  "mem_" + currR + ".in" + _currR);
379  }
380  } else {
381  result->addConnection("pe_c" + std::to_string(c-1) + "_r" + currR + ".out" + east,
382  blk_n_c_r + ".in" + west);
383  }
384  }
385 
386  if (has_input_from_NW(pe_conn_vec[0][r][c])) {
387  result->addConnection("pe_c" + std::to_string(c-1) + "_r" + std::to_string(r-1) + ".out" + southEast,
388  blk_n_c_r + ".in" + northWest);
389  }
390 
391  if (has_input_from_NE(pe_conn_vec[0][r][c])) {
392  result->addConnection("pe_c" + std::to_string(c+1) + "_r" + std::to_string(r-1) + ".out" + southWest,
393  blk_n_c_r + ".in" + northEast);
394  }
395 
396  if (has_input_from_SE(pe_conn_vec[0][r][c])) {
397  result->addConnection("pe_c" + std::to_string(c+1) + "_r" + std::to_string(r+1) + ".out" + northWest,
398  blk_n_c_r + ".in" + southEast);
399  }
400 
401  if (has_input_from_SW(pe_conn_vec[0][r][c])) {
402  result->addConnection("pe_c" + std::to_string(c-1) + "_r" + std::to_string(r+1) + ".out" + northEast,
403  blk_n_c_r + ".in" + southWest);
404  }
405  }
406  }
407 
408  if (!pred) return cgra_storage;
409 
410  /****************** PRED NETWORK BEGINS **************/
411  /* The predication network is the same as the normal */
412  /* 32-bit architecture however it is a 1-bit wide n- */
413  /* etwork. */
414  /*****************************************************/
415 
416  if (pred_scheme.find("event") != std::string::npos) {
417  result->addSubModule(new EventTransitionTable("EventTransitionTable", fu_II));
418  result->addSubModule(new Multiplexer("event_mux", {0, 0}, cols, 1));
419  result->addConfig(new ConfigCell("eventMuxConfig"), {"event_mux.select"});
420  result->addConnection("event_mux.out", "EventTransitionTable.current_event");
421  for (int i = 0; i < cols; i++) {
422  result->addConnection("pe_c" + std::to_string(i) + "_r0.out_pred" + north,
423  "event_mux.in"+ std::to_string(i));
424  }
425  } else if (pred_scheme.find("partial") != std::string::npos) {
426  } else {
427  throw cgrame_error("Cannot recognize the predication scheme");
428  }
429  // If predication is set to true connect the predicate network.
430  // I/O's
431 
432  // I/O's
433  for (unsigned int c = 0; c < cols; c++) {
434  Location loc_bot = {c + 1, rows + 1};
435  Location loc_top = {c + 1, 0};
436  auto io_top = new IO("io_top_pred_" + std::to_string(c), loc_top, 1, II);
437  auto io_bottom = new IO("io_bottom_pred_" + std::to_string(c), loc_bot, 1, II);
438  result->addSubModule(io_top, c/(cols+2.0), 0, moduleW, moduleH);
439  result->addSubModule(io_bottom, c*moduleW, (rows+1.0)*moduleH, moduleW, moduleH);
440  if (II > 1) {
441  result->addConnection("context_counter_io_top_" + std::to_string(c) + ".Context", "io_top_pred_" + std::to_string(c) + ".Context", false);
442  result->addConnection("context_counter_io_bottom_" + std::to_string(c) + ".Context", "io_bottom_pred_" + std::to_string(c) + ".Context", false);
443  }
444  }
445 
446  for (unsigned int r = 0; r < rows; r++) {
447  Location loc = {cols + 1, r + 1};
448  if (!extra_mem) {
449  auto io_right = new IO("io_right_pred_" + std::to_string(r), loc, 1, II);
450  result->addSubModule(io_right, (cols+1.0)*moduleW, (r+1.0)*moduleH, moduleW, moduleH);
451  if (II > 1) {
452  result->addConnection("context_counter_io_right_" + std::to_string(r) + ".Context", "io_right_pred_" + std::to_string(r) + ".Context", false);
453  }
454  }
455  }
456 
457  // 1. Add Connections
458  // Inter-PE Connections (NEWS)
459  for (unsigned int c = 0; c < cols; c++) {
460  for (unsigned int r = 0; r < rows; r++) {
461  std::string currC = std::to_string(c);
462  std::string currR = std::to_string(r);
463  std::string blk_n_c_r = "pe_c" + currC + "_r" + currR;
464 
465  // Use pe_conn to determine whether a connection should be made
466  if (has_input_from_N(pred_conn_vec[0][r][c])) {
467  // Special Case: Top Row PE's connect to I/O's
468  if (r == 0) {
469  result->addConnection("io_top_pred_" + currC + ".out",
470  blk_n_c_r + ".in_pred" + north);
471 
472  result->addConnection(blk_n_c_r + ".out_pred" + north,
473  "io_top_pred_" + currC + ".in");
474  } else {
475  result->addConnection("pe_c" + currC + "_r" + std::to_string(r - 1) + ".out_pred" + south,
476  blk_n_c_r + ".in_pred" + north);
477  }
478  }
479 
480  if (has_input_from_E(pred_conn_vec[1][r][c])) {
481  if (c == cols - 1) {
482  if (extra_mem) {
483  std::string _blk_prefix = "pe_c" + currC + "_r";
484  for (int _r = 0; _r < rows; _r++) {
485  std::string _currR = std::to_string(_r);
486  std::string _blk_n_c_r = _blk_prefix + _currR;
487  result->addConnection(_blk_n_c_r + ".out_pred" + east,
488  "mem_right_" + currR + ".pred" + _currR);
489  }
490  } else {
491  result->addConnection("io_right_pred_" + currR + ".out",
492  blk_n_c_r + ".in_pred" + east);
493 
494  result->addConnection(blk_n_c_r + ".out_pred" + east,
495  "io_right_pred_" + currR + ".in");
496  }
497  } else {
498  result->addConnection("pe_c" + std::to_string(c + 1) + "_r" + currR + ".out_pred" + west,
499  blk_n_c_r + ".in_pred" + east);
500  }
501  }
502 
503  if (has_input_from_S(pred_conn_vec[0][r][c])) {
504  if (r == rows - 1) {
505  result->addConnection("io_bottom_pred_" + currC + ".out",
506  blk_n_c_r + ".in_pred" + south);
507 
508  result->addConnection(blk_n_c_r + ".out_pred" + south,
509  "io_bottom_pred_" + currC + ".in");
510  } else {
511  result->addConnection("pe_c" + currC + "_r" + std::to_string(r + 1) + ".out_pred" + north,
512  blk_n_c_r + ".in_pred" + south);
513  }
514  }
515 
516  if (has_input_from_W(pred_conn_vec[1][r][c])) {
517  // Special Case: Left-most PE's connect to Memory Ports
518  if (c == 0) {
519  std::string _blk_prefix = "pe_c" + currC + "_r";
520  for (int _r = 0; _r < rows; _r++) {
521  std::string _currR = std::to_string(_r);
522  std::string _blk_n_c_r = _blk_prefix + _currR;
523  result->addConnection(_blk_n_c_r + ".out_pred" + west,
524  "mem_" + currR + ".pred" + _currR);
525  }
526  } else {
527  result->addConnection("pe_c" + std::to_string(c - 1) + "_r" + currR + ".out_pred" + east,
528  blk_n_c_r + ".in_pred" + west);
529  }
530  }
531 
532  if (has_input_from_NW(pred_conn_vec[0][r][c])) {
533  result->addConnection(
534  "pe_c" + std::to_string(c - 1) + "_r" + std::to_string(r - 1) + ".out_pred" + southEast,
535  blk_n_c_r + ".in_pred" + northWest);
536  }
537 
538  if (has_input_from_NE(pred_conn_vec[0][r][c])) {
539  result->addConnection(
540  "pe_c" + std::to_string(c + 1) + "_r" + std::to_string(r - 1) + ".out_pred" + southWest,
541  blk_n_c_r + ".in_pred" + northEast);
542  }
543 
544  if (has_input_from_SE(pred_conn_vec[0][r][c])) {
545  result->addConnection(
546  "pe_c" + std::to_string(c + 1) + "_r" + std::to_string(r + 1) + ".out_pred" + northWest,
547  blk_n_c_r + ".in_pred" + southEast);
548  }
549 
550  if (has_input_from_SW(pred_conn_vec[0][r][c])) {
551  result->addConnection(
552  "pe_c" + std::to_string(c - 1) + "_r" + std::to_string(r + 1) + ".out_pred" + northEast,
553  blk_n_c_r + ".in_pred" + southWest);
554  }
555  }
556  }
557  return cgra_storage;
558 }
ConfigCell
Definition: Module.h:825
mask_leftmost_pred
#define mask_leftmost_pred(conn)
Definition: HyCUBE.cpp:44
has_input_from_N
#define has_input_from_N(conn)
Definition: HyCUBE.cpp:21
has_input_from_E
#define has_input_from_E(conn)
Definition: HyCUBE.cpp:22
is_leftmost_pe
#define is_leftmost_pe(r, c, rows, cols)
Definition: HyCUBE.cpp:33
Multiplexer
Zero-cycle latency multiplexer.
Definition: Module.h:592
mask_rightmost_pred
#define mask_rightmost_pred(conn)
Definition: HyCUBE.cpp:45
has_input_from_S
#define has_input_from_S(conn)
Definition: HyCUBE.cpp:23
Location
Definition: Module.h:156
has_input_from_SW
#define has_input_from_SW(conn)
Definition: HyCUBE.cpp:28
fillPEConnArray
void fillPEConnArray(std::vector< std::vector< std::vector< int > > > &pcv, int pe_conn_orig, int rows, int cols, bool pred, bool extra_mem=false, std::string pred_scheme="")
Definition: HyCUBE.cpp:56
mask_rightmost_pred_mem
#define mask_rightmost_pred_mem(conn)
Definition: HyCUBE.cpp:46
Module::addConnection
void addConnection(std::string src, std::string dst, bool isInMRRG=true)
Definition: Module.cpp:1241
MemPort
Definition: ModuleComposites.h:16
ContextCell
Definition: Module.h:863
UserArchs.h
ConfigStore
Definition: ConfigStore.h:76
is_bot_pe
#define is_bot_pe(r, c, rows, cols)
Definition: HyCUBE.cpp:32
mask_leftmost_pe
#define mask_leftmost_pe(conn)
Definition: HyCUBE.cpp:39
has_input_from_NW
#define has_input_from_NW(conn)
Definition: HyCUBE.cpp:25
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
mask_top_pe
#define mask_top_pe(conn)
Definition: HyCUBE.cpp:37
has_input_from_SE
#define has_input_from_SE(conn)
Definition: HyCUBE.cpp:27
leftshift2
int leftshift2(int val)
Definition: HyCUBE.cpp:50
Exception.h
is_rightmost_pe
#define is_rightmost_pe(r, c, rows, cols)
Definition: HyCUBE.cpp:34
has_input_from_NE
#define has_input_from_NE(conn)
Definition: HyCUBE.cpp:26
IO
Supports the input and output ops. Will add an external port at the top-level of generated verilog.
Definition: Module.h:762
UserModules.h
UserArchs::createHyCUBEArch
static std::unique_ptr< CGRA > createHyCUBEArch(const ConfigStore &args)
Definition: HyCUBE.cpp:168
Module
Definition: Module.h:163
mask_rightmost_pe
#define mask_rightmost_pe(conn)
Definition: HyCUBE.cpp:40
Module::addConfig
void addConfig(ConfigCell *c, std::vector< std::string > ConnectTo)
Definition: Module.cpp:1087
ContextCounter
Definition: Module.h:878
HyCUBEPE
Definition: UserModules.h:41
ConfigStore::getString
const std::string & getString(const std::string &key) const
Definition: ConfigStore.h:136
Module::addSubModule
void addSubModule(Module *m)
Definition: Module.cpp:1124
is_top_pe
#define is_top_pe(r, c, rows, cols)
Definition: HyCUBE.cpp:31
mask_top_event_pred
#define mask_top_event_pred(conn)
Definition: HyCUBE.cpp:48
mask_top_pred
#define mask_top_pred(conn)
Definition: HyCUBE.cpp:42
has_input_from_W
#define has_input_from_W(conn)
Definition: HyCUBE.cpp:24
EventTransitionTable
Definition: Module.h:847
mask_bot_pe
#define mask_bot_pe(conn)
Definition: HyCUBE.cpp:38
ConfigStore::getInt
long long getInt(const std::string &key) const
Definition: ConfigStore.h:146
mask_bot_pred
#define mask_bot_pred(conn)
Definition: HyCUBE.cpp:43
cgrame_error
Definition: Exception.h:20
ConfigStore::getBool
bool getBool(const std::string &key) const
Definition: ConfigStore.h:166