CGRA-ME
AdresArch.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 
19 #include <CGRA/Exception.h>
22 #include <climits>
23 
24 #define has_input_from_N(conn) (conn & 0b00000001)
25 #define has_input_from_E(conn) (conn & 0b00000010)
26 #define has_input_from_S(conn) (conn & 0b00000100)
27 #define has_input_from_W(conn) (conn & 0b00001000)
28 #define has_input_from_NW(conn) (conn & 0b00010000)
29 #define has_input_from_NE(conn) (conn & 0b00100000)
30 #define has_input_from_SE(conn) (conn & 0b01000000)
31 #define has_input_from_SW(conn) (conn & 0b10000000)
32 
33 // Lookup how many ones in a 4-bit data
34 const unsigned char ones_in_4b[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
35 #define get_ones_in_8b(v) (ones_in_4b[v & 0x0f] + ones_in_4b[v >> 4])
36 
37 // Macros determining whether a PE is in corner or on side
38 #define is_corner_pe(r, c, rows, cols) (\
39  (r == 0 && c == 0) ||\
40  (r == 0 && c == cols-1) ||\
41  (r == rows-1 && c == 0) ||\
42  (r == rows-1 && c == cols-1)\
43 )
44 #define is_side_pe(r, c, rows, cols) (\
45  (r == 0) ||\
46  (c == 0) ||\
47  (r == rows-1) ||\
48  (c == cols-1)\
49 )
50 #define is_top_leftmost_pe(r, c, rows, cols) (r == 0 && c == 0)
51 #define is_top_rightmost_pe(r, c, rows, cols) (r == 0 && c == cols-1)
52 #define is_bot_leftmost_pe(r, c, rows, cols) (r == rows-1 && c == 0)
53 #define is_bot_rightmost_pe(r, c, rows, cols) (r == rows-1 && c == cols-1)
54 #define is_top_pe(r, c, rows, cols) (r == 0)
55 #define is_bot_pe(r, c, rows, cols) (r == rows-1)
56 #define is_leftmost_pe(r, c, rows, cols) (c == 0)
57 #define is_rightmost_pe(r, c, rows, cols) (c == cols-1)
58 
59 // Masks used to cover invalid connections
60 #define mask_top_leftmost_pe(conn) (conn & 0b01000110)
61 #define mask_top_rightmost_pe(conn) (conn & 0b10001100)
62 #define mask_bot_leftmost_pe(conn) (conn & 0b00100011)
63 #define mask_bot_rightmost_pe(conn) (conn & 0b00011001)
64 #define mask_top_pe(conn) (conn & 0b11001110)
65 #define mask_bot_pe(conn) (conn & 0b00111011)
66 #define mask_leftmost_pe(conn) (conn & 0b01100111)
67 #define mask_rightmost_pe(conn) (conn & 0b10011101)
68 
69 
70 // Gets number of inputs from other PEs for the PE at row `r` and column `c`
71 // given the connectivity `conn`, total numbers of rows: `rows`, and columns: `cols`
72 unsigned char get_inter_pe_input_counts(unsigned char conn, int r, int c, int rows, int cols, bool toroid)
73 {
74  int count = 0;
75  if (toroid)
76  {
77  if (is_corner_pe(r, c, rows, cols)) count += 2;
78  else if (is_side_pe(r, c, rows, cols)) count++;
79  }
80  count += get_ones_in_8b(conn);
81  // Minus side and corner invalid connections
82  if (is_corner_pe(r, c, rows, cols)) { // order of the condition is important
83  if (r == 0 && c == 0) {
84  // Top left corner does not have input from N NW NE W SW
85  count -= has_input_from_N(conn)?1:0;
86  count -= has_input_from_NW(conn)?1:0;
87  count -= has_input_from_NE(conn)?1:0;
88  count -= has_input_from_W(conn)?1:0;
89  count -= has_input_from_SW(conn)?1:0;
90  } else if (r == 0 && c == (cols - 1)) {
91  // Top right corner does not have input from N NW NE E SE
92  count -= has_input_from_N(conn)?1:0;
93  count -= has_input_from_NW(conn)?1:0;
94  count -= has_input_from_NE(conn)?1:0;
95  count -= has_input_from_E(conn)?1:0;
96  count -= has_input_from_SE(conn)?1:0;
97  } else if (r == (rows - 1) && c == 0) {
98  // Bottom left corner does not have input from S SW SE W NW
99  count -= has_input_from_S(conn)?1:0;
100  count -= has_input_from_SW(conn)?1:0;
101  count -= has_input_from_SE(conn)?1:0;
102  count -= has_input_from_W(conn)?1:0;
103  count -= has_input_from_NW(conn)?1:0;
104  } else if (r == (rows - 1) && c == (cols - 1)) {
105  // Bottom right corner does not have input from S SW SE E NE
106  count -= has_input_from_S(conn)?1:0;
107  count -= has_input_from_SW(conn)?1:0;
108  count -= has_input_from_SE(conn)?1:0;
109  count -= has_input_from_E(conn)?1:0;
110  count -= has_input_from_NE(conn)?1:0;
111  }
112  return count;
113  } else if (is_side_pe(r, c, rows, cols)) {
114  if (r == 0) {
115  // Top row does not have input from N NW NE
116  count -= has_input_from_N(conn)?1:0;
117  count -= has_input_from_NW(conn)?1:0;
118  count -= has_input_from_NE(conn)?1:0;
119  } else if (c == 0) {
120  // Leftmost column does not have input from W NW SW
121  count -= has_input_from_W(conn)?1:0;
122  count -= has_input_from_NW(conn)?1:0;
123  count -= has_input_from_SW(conn)?1:0;
124  } else if (r == (rows - 1)) {
125  // Bottom row does not have input from S SW SE
126  count -= has_input_from_S(conn)?1:0;
127  count -= has_input_from_SW(conn)?1:0;
128  count -= has_input_from_SE(conn)?1:0;
129  } else if (c == (cols - 1)) {
130  // Rightmost column does not have input from E NE SE
131  count -= has_input_from_E(conn)?1:0;
132  count -= has_input_from_SE(conn)?1:0;
133  count -= has_input_from_NE(conn)?1:0;
134  }
135  return count;
136  } else {
137  return count;
138  }
139 }
140 
141 std::unique_ptr<CGRA> UserArchs::createAdresArch(const ConfigStore& args)
142 {
143  const int cols = args.getInt("cols");
144  const int rows = args.getInt("rows");
145  const int toroid = args.getInt("toroid");
146  const int hetero_fu_type = args.getInt("fu_type");
147  const int fu_latency = args.getInt("fu_latency");
148  const int fu_II = args.getInt("fu_II");
149  const int rf_cols = args.getInt("rf_cols");
150  const int rf_rows = args.getInt("rf_rows");
151  const int num_const_addresses = args.getInt("num_const_addresses");
152  const bool use_op_div = args.getBool("op_div");
153  const bool extra_mem = args.getBool("extra_mem");
154  const int pe_conn = args.getInt("pe_conn");
155  const int II = args.getInt("II");
156  const bool pred = args.getBool("pred");
157  const bool reg_bypass = args.getBool("reg_bypass");
158  const std::string pred_scheme = args.getString("pred_scheme");
159 
160  /* Verify if rows and cols are greater than 2 */
161  if (rows < 2 || cols < 2)
162  throw cgrame_error("ADRES Arch only accepts rows/cols >= 2");
163 
164  /* Verify if rf_rows and rf_cols are of valid values */
165  if (((rows - 1) % rf_rows) != 0) // top row excluded
166  throw cgrame_error("rows-1 must be divisible by rf_rows");
167 
168  if ((cols % rf_cols) != 0)
169  throw cgrame_error("cols must be divisible by rf_rows");
170 
171  const unsigned RF_SIZE = rf_rows * rf_cols;
172  auto cgra_storage = std::make_unique<CGRA>();
173  Module* result = &cgra_storage->getTopLevelModule();
174 
175  result->isElastic = false;
176 
182  double moduleW = 1.0/(2*cols+1);
183  double moduleH = 1.0/(2*rows+1);
184  if (II > 1) {
185  result->addSubModule(new ContextCell("context_cell", II)); // ContextCell stores num of used contexts (II)
186  }
187  /* IO Ports */
188  for (unsigned int i = 0; i < cols; i++)
189  {
190  Location loc = {i + 1 , 0};
191  result->addSubModule(new IO("io_top_" + std::to_string(i), loc, 32, II), (i+1)*moduleW, moduleH/2, moduleW, moduleH/2);
192  if (II > 1) {
193  result->addSubModule(new ContextCounter("context_counter_io" + std::to_string(i), II));
194  result->addConnection("context_cell.Context_Used", "context_counter_io" + std::to_string(i) + ".Context_Used", false);
195  result->addConnection("context_counter_io" + std::to_string(i) + ".Context", "io_top_" + std::to_string(i) + ".Context", false);
196  }
197  }
198 
199  /* Memory Ports */
200  for (unsigned int i = 0; i < rows; i++)
201  {
202  Location loc = {cols + 1, i + 1};
203  result->addSubModule(new MemPort("mem_" + std::to_string(i), loc, cols, 32, num_const_addresses, pred, II), 0, (i+1)*moduleH, moduleW, moduleH);
204  if (extra_mem) {
205  result->addSubModule(new MemPort("mem_right_" + std::to_string(i), loc, cols, 32, num_const_addresses, pred, II), 0, (i+1)*moduleH, moduleW, moduleH);
206  }
207  if (II > 1) {
208  result->addSubModule(new ContextCounter("context_counter_mem" + std::to_string(i), II));
209  result->addConnection("context_cell.Context_Used", "context_counter_mem" + std::to_string(i) + ".Context_Used", false);
210  result->addConnection("context_counter_mem" + std::to_string(i) + ".Context", "mem_" + std::to_string(i) + ".Context", false);
211  if (extra_mem) {
212  result->addSubModule(new ContextCounter("context_counter_mem_right" + std::to_string(i), II));
213  result->addConnection("context_cell.Context_Used", "context_counter_mem_right" + std::to_string(i) + ".Context_Used", false);
214  result->addConnection("context_counter_mem_right" + std::to_string(i) + ".Context", "mem_right_" + std::to_string(i) + ".Context", false);
215  }
216  }
217  }
218 
219  /* Adres Processing Elements */
220  for (unsigned int c = 0; c < cols; c++)
221  {
222  for (unsigned int r = 0; r < rows; r++)
223  {
224  // select fu_type based on position: 'vliw' for top row, 'cga' for everything else
225  std::string fu_type = "cga";
226  if ((r == 0 || hetero_fu_type == 0) ||
227  (hetero_fu_type == 1 && ((r % 2) == 0)) ||
228  (hetero_fu_type == 2 && ((c % 2) == 0))) {
229  fu_type = "vliw";
230  }
231  Location loc = {c+1, r+1};
232  // PE needs inputs for 3~4 adjacent PEs, 1 mem port, and 1 regfile
233  unsigned char count = get_inter_pe_input_counts(pe_conn, r, c, rows, cols, toroid);
234  result->addSubModule(
235  new AdresPE(
236  "pe_c" + std::to_string(c) + "_r" + std::to_string(r),
237  count + ((r == 0)?2:1) + extra_mem, // +2 inputs for first row due to IO
238  fu_type,
239  fu_II,
240  fu_latency,
241  II,
242  loc,
243  use_op_div,
244  pred,
245  reg_bypass,
246  extra_mem
247  ), (2*c+2)*moduleW, (2*r+2)*moduleH, moduleW, moduleH);
248  if (II > 1) {
249  result->addSubModule(new ContextCounter("context_counter_pe_c" + std::to_string(c) + "_r" + std::to_string(r), II));
250  result->addConnection("context_cell.Context_Used", "context_counter_pe_c" + std::to_string(c) + "_r" + std::to_string(r) + ".Context_Used", false);
251  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);
252  }
253  }
254  }
255 
256  /* IO-PE connections */
257  for (unsigned int c = 0; c < cols; c++)
258  {
259  std::string io_n = "io_top_" + std::to_string(c);
260  std::string blk_n = "pe_c" + std::to_string(c) + "_r0";
261  result->addConnection(io_n + ".out", blk_n + ".in0"); //io->blk
262  result->addConnection(blk_n + ".out", io_n + ".in"); //blk->io
263  }
264 
265  /* Mem-PE connections */
266  for (unsigned int r = 0; r < rows; r++)
267  {
268  std::string mem_n = "mem_" + std::to_string(r);
269  std::string mem_right_n = "mem_right_" + std::to_string(r);
270 
271  for (unsigned int c = 0; c < cols; c++)
272  {
273  std::string blk_n = "pe_c" + std::to_string(c) + "_r" + std::to_string(r);
274  result->addConnection(blk_n + ".out", mem_n + ".in" + std::to_string(c)); // to io
275  result->addConnection(mem_n + ".out", blk_n + ((r == 0)?".in1":".in0")); // to block
276  if (extra_mem) {
277  result->addConnection(blk_n + ".out", mem_right_n + ".in" + std::to_string(c)); // to io
278  result->addConnection(mem_right_n + ".out", blk_n + ((r == 0)?".in2":".in1")); // to block
279  }
280  }
281  }
282 
283  // Connect VLIW FUs (top row) to one shared register file
284  Location drf_loc = {1, UINT_MAX};
285  result->addSubModule(new RegisterFile("drf", drf_loc, reg_bypass? cols * 2 : cols, 2*cols, 3, 32, II), 0.3, moduleH, 0.5, moduleH);
286  if (II > 1) {
287  result->addSubModule(new ContextCounter("context_counter_drf", II));
288  result->addConnection("context_cell.Context_Used", "context_counter_drf.Context_Used", false);
289  result->addConnection("context_counter_drf.Context", "drf.Context", false);
290  }
291  for (unsigned int c = 0; c < cols; c++)
292  {
293  std::string blk = "pe_c" + std::to_string(c) + "_r0";
294 
295  result->addConnection(blk + ".fu_to_rf", "drf.in" + std::to_string(c));
296  if (reg_bypass)
297  result->addConnection(blk + ".bypass_to_rf", "drf.in" + std::to_string(cols + c));
298  result->addConnection("drf.out" + std::to_string(c*2), blk + ".rf_to_muxa");
299  result->addConnection("drf.out" + std::to_string(c*2+1), blk + ".rf_to_muxout");
300  }
301 
302  // Instantiate External Register Files (CGA FUs only; excludes top row VLIW FUs)
303  for (unsigned int c = 0; c < cols; c += rf_cols)
304  {
305  for (unsigned int r = 1; r < rows; r += rf_rows)
306  {
307  Location rf_loc = {c + 1, r + 1};
308  // the name represents the minimal indices of the corner(top left) of RF
309  std::string rf = "rf_c" + std::to_string(c) + "_r" + std::to_string(r);
310  std::string blk = "pe_c" + std::to_string(c) + "_r" + std::to_string(r);
311  result->addSubModule(new RegisterFile(rf, rf_loc, RF_SIZE + reg_bypass, 2, RF_SIZE, 32, II), (2*c+1)*moduleW, (2*r+1)*moduleH, moduleW, moduleH);
312  result->addConnection(rf + ".out0", blk + ".rf_to_muxa");
313  result->addConnection(rf + ".out1", blk + ".rf_to_muxout");
314  if (II > 1) {
315  result->addSubModule(new ContextCounter("context_counter_" + rf, II));
316  result->addConnection("context_cell.Context_Used", "context_counter_" + rf + ".Context_Used", false);
317  result->addConnection("context_counter_" + rf + ".Context", rf + ".Context", false);
318  }
319  std::string rfcc = "RfC" + std::to_string(c) + "R" + std::to_string(r);
320  }
321  }
322  // Connect external RFs to PEs
323  for (unsigned int c = 0; c < cols; c++)
324  {
325  for (unsigned int r = 1; r < rows; r++)
326  {
327  int c_mod = c % rf_cols;
328  int r_mod = (r - 1) % rf_rows;
329  int c_rf = c - c_mod;
330  int r_rf = r - r_mod;
331  int rf_in_i = 2 * r_mod + c_mod;
332  std::string rf_in = std::to_string(rf_in_i);
333  std::string rf = "rf_c" + std::to_string(c_rf) + "_r" + std::to_string(r_rf);
334  std::string blk = "pe_c" + std::to_string(c) + "_r" + std::to_string(r);
335  result->addConnection(blk + ".fu_to_rf", rf + ".in" + rf_in);
336  if (reg_bypass) {
337  result->addConnection(blk + ".bypass_to_rf", rf + ".in1");
338  }
339  }
340  }
341 
342  // Connect PEs to PEs
343  for (unsigned int c = 0; c < cols; c++)
344  {
345  for (unsigned int r = 0; r < rows; r++)
346  {
347  std::string blk_n_c_r = "pe_c" + std::to_string(c) + "_r" + std::to_string(r);
348  std::string adj_blk_N = "pe_c" + std::to_string(c) + "_r" + std::to_string(r-1) + ".out";
349  std::string adj_blk_E = "pe_c" + std::to_string(c+1) + "_r" + std::to_string(r) + ".out";
350  std::string adj_blk_S = "pe_c" + std::to_string(c) + "_r" + std::to_string(r+1) + ".out";
351  std::string adj_blk_W = "pe_c" + std::to_string(c-1) + "_r" + std::to_string(r) + ".out";
352  std::string adj_blk_NW = "pe_c" + std::to_string(c-1) + "_r" + std::to_string(r-1) + ".out";
353  std::string adj_blk_NE = "pe_c" + std::to_string(c+1) + "_r" + std::to_string(r-1) + ".out";
354  std::string adj_blk_SE = "pe_c" + std::to_string(c+1) + "_r" + std::to_string(r+1) + ".out";
355  std::string adj_blk_SW = "pe_c" + std::to_string(c-1) + "_r" + std::to_string(r+1) + ".out";
356 
357  // Determine the valid set of connections for this PE
358  unsigned char true_conn = pe_conn;
359  if (is_corner_pe(r, c, rows, cols)) {
360  if (is_top_leftmost_pe(r, c, rows, cols)) {
361  true_conn = mask_top_leftmost_pe(pe_conn);
362  } else if (is_top_rightmost_pe(r, c, rows, cols)) {
363  true_conn = mask_top_rightmost_pe(pe_conn);
364  } else if (is_bot_leftmost_pe(r, c, rows, cols)) {
365  true_conn = mask_bot_leftmost_pe(pe_conn);
366  } else if (is_bot_rightmost_pe(r, c, rows, cols)) {
367  true_conn = mask_bot_rightmost_pe(pe_conn);
368  }
369  } else if (is_side_pe(r, c, rows, cols)) {
370  if (is_top_pe(r, c, rows, cols)) {
371  true_conn = mask_top_pe(pe_conn);
372  } else if (is_bot_pe(r, c, rows, cols)) {
373  true_conn = mask_bot_pe(pe_conn);
374  } else if (is_leftmost_pe(r, c, rows, cols)) {
375  true_conn = mask_leftmost_pe(pe_conn);
376  } else if (is_rightmost_pe(r, c, rows, cols)) {
377  true_conn = mask_rightmost_pe(pe_conn);
378  }
379  }
380 
381  // Add connections based on `true_conn`
382  int index = ((r == 0)?2:1) + extra_mem; // port starting index (since mem/io can occupy port0 & port1)
383  std::string in_port;
384  if (has_input_from_N(true_conn)) {
385  in_port = ".in" + std::to_string(index);
386  result->addConnection(adj_blk_N, blk_n_c_r + in_port);
387  index++;
388  }
389  if (has_input_from_E(true_conn)) {
390  in_port = ".in" + std::to_string(index);
391  result->addConnection(adj_blk_E, blk_n_c_r + in_port);
392  index++;
393  }
394  if (has_input_from_S(true_conn)) {
395  in_port = ".in" + std::to_string(index);
396  result->addConnection(adj_blk_S, blk_n_c_r + in_port);
397  index++;
398  }
399  if (has_input_from_W(true_conn)) {
400  in_port = ".in" + std::to_string(index);
401  result->addConnection(adj_blk_W, blk_n_c_r + in_port);
402  index++;
403  }
404  if (has_input_from_NW(true_conn)) {
405  in_port = ".in" + std::to_string(index);
406  result->addConnection(adj_blk_NW, blk_n_c_r + in_port);
407  index++;
408  }
409  if (has_input_from_NE(true_conn)) {
410  in_port = ".in" + std::to_string(index);
411  result->addConnection(adj_blk_NE, blk_n_c_r + in_port);
412  index++;
413  }
414  if (has_input_from_SE(true_conn)) {
415  in_port = ".in" + std::to_string(index);
416  result->addConnection(adj_blk_SE, blk_n_c_r + in_port);
417  index++;
418  }
419  if (has_input_from_SW(true_conn)) {
420  in_port = ".in" + std::to_string(index);
421  result->addConnection(adj_blk_SW, blk_n_c_r + in_port);
422  index++;
423  }
424  if (toroid) {
425  if (is_top_pe(r, c, rows, cols)) {
426  std::string src_pe = "pe_c" + std::to_string(c) + "_r" + std::to_string(rows-1) + ".out";
427  in_port = ".in" + std::to_string(index);
428  result->addConnection(src_pe, blk_n_c_r + in_port);
429  index++;
430  }
431  if (is_bot_pe(r, c, rows, cols)) {
432  std::string src_pe = "pe_c" + std::to_string(c) + "_r" + std::to_string(0) + ".out";
433  in_port = ".in" + std::to_string(index);
434  result->addConnection(src_pe, blk_n_c_r + in_port);
435  index++;
436  }
437  if (is_leftmost_pe(r, c, rows, cols)) {
438  std::string src_pe = "pe_c" + std::to_string(cols-1) + "_r" + std::to_string(r) + ".out";
439  in_port = ".in" + std::to_string(index);
440  result->addConnection(src_pe, blk_n_c_r + in_port);
441  index++;
442  }
443  if (is_rightmost_pe(r, c, rows, cols)) {
444  std::string src_pe = "pe_c" + std::to_string(0) + "_r" + std::to_string(r) + ".out";
445  in_port = ".in" + std::to_string(index);
446  result->addConnection(src_pe, blk_n_c_r + in_port);
447  index++;
448  }
449  }
450  }
451  }
452  if (!pred) return cgra_storage;
453 
454  /****************** PRED NETWORK BEGINS **************/
455  /* The predication network is the same as the normal */
456  /* 32-bit architecture however it is a 1-bit wide n- */
457  /* etwork. */
458  /*****************************************************/
459 
460  if (pred_scheme.find("event") != std::string::npos){
461  result->addSubModule(new EventTransitionTable("EventTransitionTable", fu_II));
462  result->addSubModule(new Multiplexer("event_mux", {0,0}, cols, 1));
463  result->addConfig(new ConfigCell("eventMuxConfig"), {"event_mux.select"});
464  result->addConnection("event_mux.out", "EventTransitionTable.current_event");
465  for (int i = 0; i < cols; i++ ){
466  result->addConnection("pe_c" + std::to_string(i) + "_r0.out_pred",
467  "event_mux.in"+ std::to_string(i));
468  }
469  } else if (pred_scheme.find("partial") != std::string::npos){
470 
471  } else {
472  throw cgrame_error("Cannot recognize the predication scheme");
473  }
474  int size = 1;
475  /* IO Ports */
476  for (unsigned int i = 0; i < cols; i++)
477  {
478  Location loc = {i + 1 , 0};
479  result->addSubModule(new IO("io_top_pred_" + std::to_string(i), loc, size, II), (i+1)*moduleW, moduleH/2, moduleW, moduleH/2);
480  if (II > 1)
481  result->addConnection("context_counter_io" + std::to_string(i) + ".Context", "io_top_pred_" + std::to_string(i) + ".Context", false);
482  }
483  for (unsigned int c = 0; c < cols; c++)
484  {
485  std::string io_n = "io_top_pred_" + std::to_string(c);
486  std::string blk_n = "pe_c" + std::to_string(c) + "_r0";
487  result->addConnection(io_n + ".out", blk_n + ".in_pred" + std::to_string(extra_mem?2:1)); //io->blk
488  result->addConnection(blk_n + ".out_pred", io_n + ".in"); //blk->io
489  }
490  /* Mem-PE connections */
491  for (unsigned int r = 0; r < rows; r++)
492  {
493  std::string mem_n = "mem_" + std::to_string(r);
494  std::string mem_right_n = "mem_right_" + std::to_string(r);
495 
496  for (unsigned int c = 0; c < cols; c++)
497  {
498  std::string blk_n = "pe_c" + std::to_string(c) + "_r" + std::to_string(r);
499  result->addConnection(blk_n + ".out_pred", mem_n + ".pred" + std::to_string(c)); // to io
500  if (extra_mem) {
501  result->addConnection(blk_n + ".out_pred", mem_right_n + ".pred" + std::to_string(c)); // to io
502  }
503  }
504  }
505 
506  Location pred_drf_loc = {1, UINT_MAX};
507  // predicate architecture
508  // Connect VLIW FUs (top row) to one shared register file
509  result->addSubModule(new RegisterFile("drf_pred", pred_drf_loc, reg_bypass? cols * 2 : cols, 2*cols, 3, size, II), 0.3, moduleH, 0.5, moduleH);
510  if (II > 1) {
511  result->addConnection("context_counter_drf.Context", "drf_pred.Context", false);
512  }
513  for (unsigned int c = 0; c < cols; c++)
514  {
515  std::string blk = "pe_c" + std::to_string(c) + "_r0";
516 
517  result->addConnection(blk + ".fu_to_rf_pred", "drf_pred.in" + std::to_string(c));
518  if (reg_bypass)
519  result->addConnection(blk + ".bypass_to_rf_pred", "drf_pred.in" + std::to_string(cols + c));
520  result->addConnection("drf_pred.out" + std::to_string(c*2), blk + ".rf_to_muxa_pred");
521  result->addConnection("drf_pred.out" + std::to_string(c*2+1), blk + ".rf_to_muxout_pred");
522  }
523 
524  // Instantiate External Register Files (CGA FUs only; excludes top row VLIW FUs)
525  for (unsigned int c = 0; c < cols; c += rf_cols)
526  {
527  for (unsigned int r = 1; r < rows; r += rf_rows)
528  {
529  Location loc = {c + 1, r + 1};
530  // the name represents the minimal indices of the corner(top left) of RF
531  std::string rf_org = "rf_c" + std::to_string(c) + "_r" + std::to_string(r);
532  std::string rf = "rf_pred_c" + std::to_string(c) + "_r" + std::to_string(r);
533  std::string blk = "pe_c" + std::to_string(c) + "_r" + std::to_string(r);
534  result->addSubModule(new RegisterFile(rf, loc, RF_SIZE + reg_bypass, 2, RF_SIZE, size, II), (2*c+1)*moduleW, (2*r+1)*moduleH, moduleW, moduleH);
535  result->addConnection(rf + ".out0", blk + ".rf_to_muxa_pred");
536  result->addConnection(rf + ".out1", blk + ".rf_to_muxout_pred");
537  if (II > 1)
538  result->addConnection("context_counter_" + rf_org + ".Context", rf + ".Context", false);
539 
540  std::string rfcc = "RfC" + std::to_string(c) + "R" + std::to_string(r);
541  }
542  }
543  // Connect external RFs to PEs
544  for (unsigned int c = 0; c < cols; c++)
545  {
546  for (unsigned int r = 1; r < rows; r++)
547  {
548  int c_mod = c % rf_cols;
549  int r_mod = (r - 1) % rf_rows;
550  int c_rf = c - c_mod;
551  int r_rf = r - r_mod;
552  int rf_in_i = 2 * r_mod + c_mod;
553  std::string rf_in = std::to_string(rf_in_i);
554  std::string rf = "rf_pred_c" + std::to_string(c_rf) + "_r" + std::to_string(r_rf);
555  std::string blk = "pe_c" + std::to_string(c) + "_r" + std::to_string(r);
556  result->addConnection(blk + ".fu_to_rf_pred", rf + ".in" + rf_in);
557  if (reg_bypass) {
558  result->addConnection(blk + ".bypass_to_rf_pred", rf + ".in1");
559  }
560  }
561  }
562 
563  // Connect PEs to PEs
564  for (unsigned int c = 0; c < cols; c++)
565  {
566  for (unsigned int r = 0; r < rows; r++)
567  {
568  std::string blk_n_c_r = "pe_c" + std::to_string(c) + "_r" + std::to_string(r);
569  std::string adj_blk_N = "pe_c" + std::to_string(c) + "_r" + std::to_string(r-1) + ".out_pred";
570  std::string adj_blk_E = "pe_c" + std::to_string(c+1) + "_r" + std::to_string(r) + ".out_pred";
571  std::string adj_blk_S = "pe_c" + std::to_string(c) + "_r" + std::to_string(r+1) + ".out_pred";
572  std::string adj_blk_W = "pe_c" + std::to_string(c-1) + "_r" + std::to_string(r) + ".out_pred";
573  std::string adj_blk_NW = "pe_c" + std::to_string(c-1) + "_r" + std::to_string(r-1) + ".out_pred";
574  std::string adj_blk_NE = "pe_c" + std::to_string(c+1) + "_r" + std::to_string(r-1) + ".out_pred";
575  std::string adj_blk_SE = "pe_c" + std::to_string(c+1) + "_r" + std::to_string(r+1) + ".out_pred";
576  std::string adj_blk_SW = "pe_c" + std::to_string(c-1) + "_r" + std::to_string(r+1) + ".out_pred";
577 
578  // Determine the valid set of connections for this PE
579  unsigned char true_conn = pe_conn;
580  if (is_corner_pe(r, c, rows, cols)) {
581  if (is_top_leftmost_pe(r, c, rows, cols)) {
582  true_conn = mask_top_leftmost_pe(pe_conn);
583  } else if (is_top_rightmost_pe(r, c, rows, cols)) {
584  true_conn = mask_top_rightmost_pe(pe_conn);
585  } else if (is_bot_leftmost_pe(r, c, rows, cols)) {
586  true_conn = mask_bot_leftmost_pe(pe_conn);
587  } else if (is_bot_rightmost_pe(r, c, rows, cols)) {
588  true_conn = mask_bot_rightmost_pe(pe_conn);
589  }
590  } else if (is_side_pe(r, c, rows, cols)) {
591  if (is_top_pe(r, c, rows, cols)) {
592  true_conn = mask_top_pe(pe_conn);
593  } else if (is_bot_pe(r, c, rows, cols)) {
594  true_conn = mask_bot_pe(pe_conn);
595  } else if (is_leftmost_pe(r, c, rows, cols)) {
596  true_conn = mask_leftmost_pe(pe_conn);
597  } else if (is_rightmost_pe(r, c, rows, cols)) {
598  true_conn = mask_rightmost_pe(pe_conn);
599  }
600  }
601 
602  // Add connections based on `true_conn`
603  int index = ((r == 0)?2:1) + extra_mem; // port starting index (since mem/io can occupy port0 & port1)
604  std::string in_port;
605  if (has_input_from_N(true_conn)) {
606  in_port = ".in_pred" + std::to_string(index);
607  result->addConnection(adj_blk_N, blk_n_c_r + in_port);
608  index++;
609  }
610  if (has_input_from_E(true_conn)) {
611  in_port = ".in_pred" + std::to_string(index);
612  result->addConnection(adj_blk_E, blk_n_c_r + in_port);
613  index++;
614  }
615  if (has_input_from_S(true_conn)) {
616  in_port = ".in_pred" + std::to_string(index);
617  result->addConnection(adj_blk_S, blk_n_c_r + in_port);
618  index++;
619  }
620  if (has_input_from_W(true_conn)) {
621  in_port = ".in_pred" + std::to_string(index);
622  result->addConnection(adj_blk_W, blk_n_c_r + in_port);
623  index++;
624  }
625  if (has_input_from_NW(true_conn)) {
626  in_port = ".in_pred" + std::to_string(index);
627  result->addConnection(adj_blk_NW, blk_n_c_r + in_port);
628  index++;
629  }
630  if (has_input_from_NE(true_conn)) {
631  in_port = ".in_pred" + std::to_string(index);
632  result->addConnection(adj_blk_NE, blk_n_c_r + in_port);
633  index++;
634  }
635  if (has_input_from_SE(true_conn)) {
636  in_port = ".in_pred" + std::to_string(index);
637  result->addConnection(adj_blk_SE, blk_n_c_r + in_port);
638  index++;
639  }
640  if (has_input_from_SW(true_conn)) {
641  in_port = ".in_pred" + std::to_string(index);
642  result->addConnection(adj_blk_SW, blk_n_c_r + in_port);
643  index++;
644  }
645  if (toroid) {
646  if (is_top_pe(r, c, rows, cols)) {
647  std::string src_pe = "pe_c" + std::to_string(c) + "_r" + std::to_string(rows-1) + ".out_pred";
648  in_port = ".in_pred" + std::to_string(index);
649  result->addConnection(src_pe, blk_n_c_r + in_port);
650  index++;
651  }
652  if (is_bot_pe(r, c, rows, cols)) {
653  std::string src_pe = "pe_c" + std::to_string(c) + "_r" + std::to_string(0) + ".out_pred";
654  in_port = ".in_pred" + std::to_string(index);
655  result->addConnection(src_pe, blk_n_c_r + in_port);
656  index++;
657  }
658  if (is_leftmost_pe(r, c, rows, cols)) {
659  std::string src_pe = "pe_c" + std::to_string(cols-1) + "_r" + std::to_string(r) + ".out_pred";
660  in_port = ".in_pred" + std::to_string(index);
661  result->addConnection(src_pe, blk_n_c_r + in_port);
662  index++;
663  }
664  if (is_rightmost_pe(r, c, rows, cols)) {
665  std::string src_pe = "pe_c" + std::to_string(0) + "_r" + std::to_string(r) + ".out_pred";
666  in_port = ".in_pred" + std::to_string(index);
667  result->addConnection(src_pe, blk_n_c_r + in_port);
668  index++;
669  }
670  }
671  }
672  }
673  return cgra_storage;
674 }
has_input_from_S
#define has_input_from_S(conn)
Definition: AdresArch.cpp:26
ConfigCell
Definition: Module.h:825
has_input_from_NW
#define has_input_from_NW(conn)
Definition: AdresArch.cpp:28
mask_bot_rightmost_pe
#define mask_bot_rightmost_pe(conn)
Definition: AdresArch.cpp:63
is_bot_rightmost_pe
#define is_bot_rightmost_pe(r, c, rows, cols)
Definition: AdresArch.cpp:53
Multiplexer
Zero-cycle latency multiplexer.
Definition: Module.h:592
get_ones_in_8b
#define get_ones_in_8b(v)
Definition: AdresArch.cpp:35
Location
Definition: Module.h:156
mask_top_leftmost_pe
#define mask_top_leftmost_pe(conn)
Definition: AdresArch.cpp:60
is_leftmost_pe
#define is_leftmost_pe(r, c, rows, cols)
Definition: AdresArch.cpp:56
Module::addConnection
void addConnection(std::string src, std::string dst, bool isInMRRG=true)
Definition: Module.cpp:1241
MemPort
Definition: ModuleComposites.h:16
is_bot_leftmost_pe
#define is_bot_leftmost_pe(r, c, rows, cols)
Definition: AdresArch.cpp:52
ContextCell
Definition: Module.h:863
UserArchs.h
ConfigStore
Definition: ConfigStore.h:76
has_input_from_NE
#define has_input_from_NE(conn)
Definition: AdresArch.cpp:29
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
mask_top_pe
#define mask_top_pe(conn)
Definition: AdresArch.cpp:64
Exception.h
is_side_pe
#define is_side_pe(r, c, rows, cols)
Definition: AdresArch.cpp:44
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
has_input_from_N
#define has_input_from_N(conn)
Definition: AdresArch.cpp:24
Module
Definition: Module.h:163
has_input_from_W
#define has_input_from_W(conn)
Definition: AdresArch.cpp:27
is_top_leftmost_pe
#define is_top_leftmost_pe(r, c, rows, cols)
Definition: AdresArch.cpp:50
is_top_rightmost_pe
#define is_top_rightmost_pe(r, c, rows, cols)
Definition: AdresArch.cpp:51
is_corner_pe
#define is_corner_pe(r, c, rows, cols)
Definition: AdresArch.cpp:38
is_rightmost_pe
#define is_rightmost_pe(r, c, rows, cols)
Definition: AdresArch.cpp:57
mask_rightmost_pe
#define mask_rightmost_pe(conn)
Definition: AdresArch.cpp:67
mask_bot_pe
#define mask_bot_pe(conn)
Definition: AdresArch.cpp:65
Module::addConfig
void addConfig(ConfigCell *c, std::vector< std::string > ConnectTo)
Definition: Module.cpp:1087
ContextCounter
Definition: Module.h:878
mask_leftmost_pe
#define mask_leftmost_pe(conn)
Definition: AdresArch.cpp:66
UserArchs::createAdresArch
static std::unique_ptr< CGRA > createAdresArch(const ConfigStore &args)
Definition: AdresArch.cpp:141
mask_bot_leftmost_pe
#define mask_bot_leftmost_pe(conn)
Definition: AdresArch.cpp:62
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
has_input_from_SW
#define has_input_from_SW(conn)
Definition: AdresArch.cpp:31
get_inter_pe_input_counts
unsigned char get_inter_pe_input_counts(unsigned char conn, int r, int c, int rows, int cols, bool toroid)
Definition: AdresArch.cpp:72
is_bot_pe
#define is_bot_pe(r, c, rows, cols)
Definition: AdresArch.cpp:55
is_top_pe
#define is_top_pe(r, c, rows, cols)
Definition: AdresArch.cpp:54
has_input_from_E
#define has_input_from_E(conn)
Definition: AdresArch.cpp:25
Module::isElastic
bool isElastic
Definition: Module.h:236
has_input_from_SE
#define has_input_from_SE(conn)
Definition: AdresArch.cpp:30
RegisterFile
Multiplexed registers.
Definition: Module.h:707
ones_in_4b
const unsigned char ones_in_4b[]
Definition: AdresArch.cpp:34
mask_top_rightmost_pe
#define mask_top_rightmost_pe(conn)
Definition: AdresArch.cpp:61
EventTransitionTable
Definition: Module.h:847
ConfigStore::getInt
long long getInt(const std::string &key) const
Definition: ConfigStore.h:146
cgrame_error
Definition: Exception.h:20
ConfigStore::getBool
bool getBool(const std::string &key) const
Definition: ConfigStore.h:166
AdresPE
Definition: UserModules.h:20