CGRA-ME
ElasticRIKEN.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/Exception.h>
14 #include <vector>
15 
16 // Checking for connections
17 #define has_input_from_N(conn) (conn & 0b00000001)
18 #define has_input_from_E(conn) (conn & 0b00000010)
19 #define has_input_from_S(conn) (conn & 0b00000100)
20 #define has_input_from_W(conn) (conn & 0b00001000)
21 #define has_input_from_NW(conn) (conn & 0b00010000)
22 #define has_input_from_NE(conn) (conn & 0b00100000)
23 #define has_input_from_SE(conn) (conn & 0b01000000)
24 #define has_input_from_SW(conn) (conn & 0b10000000)
25 
26 // Identifying PE position
27 #define is_top_pe(r, c, rows, cols) (r == 0)
28 #define is_bot_pe(r, c, rows, cols) (r == rows-1)
29 #define is_leftmost_pe(r, c, rows, cols) (c == 0)
30 #define is_rightmost_pe(r, c, rows, cols) (c == cols-1)
31 
32 // Masks
33 #define mask_top_pe(conn) ((conn & 0b11001111) | 0b00000001) // Remove NE, NW connections, add N connection
34 #define mask_bot_pe(conn) ((conn & 0b00111111) | 0b00000100) // Remove SE, SW connections, add S connection
35 #define mask_leftmost_pe(conn) ((conn & 0b01101111) | 0b00001000) // Remove NW, SW connections, add W connection
36 #define mask_rightmost_pe(conn) ((conn & 0b10011111) | 0b00000010) // Remove NE, SE connections, add E connection
37 
39 { // bitshifts val left by 2 bits, with wraparound
40  // val is assumed to only have the right-most 4 bits populated
41  return (((val << 2) & 0x0f) | (val >> 2));
42 }
43 
44 // This function sets the inter-PE connectivity for all of the PEs
45 // I.E. it sets the bitmasks indicating if PEs connect to the NORTH, SOUTH, etc.
46 void RIKENelasticFillPEConnArray(std::vector < std::vector < std::vector<int> > > &pcv, int pe_conn_orig, int rows, int cols)
47 {
48 
49  // Variable Declaration
50  int lefthalf;
51  int righthalf;
52  int pe_conn_out;
53 
54  // 1. Fill all inputs
55  for(int r = 0; r < rows; r++)
56  {
57  for(int c = 0; c < cols; c++)
58  {
59  pcv[0][r][c] = pe_conn_orig;
60  }
61  }
62 
63  // 2. Fill all outputs
64  // Isolate first 4 and last 4 bits in pe_conn
65  lefthalf = (pe_conn_orig >> 4) & 0x0f;
66  righthalf = pe_conn_orig & 0x0f;
67 
68  // Calculate outputs of left and right half
69  lefthalf = RIKENelasticleftshift2(lefthalf);
70  righthalf = RIKENelasticleftshift2(righthalf);
71 
72  // Put them back together to get pe_conn_out
73  pe_conn_out = (lefthalf << 4) | righthalf;
74 
75  // Fill vector
76  for(int r = 0; r < rows; r++)
77  {
78  for(int c = 0; c < cols; c++)
79  {
80  pcv[1][r][c] = pe_conn_out;
81  }
82  }
83 
84  // 3. Consider HyCUBE-specific edge cases (corners are handled in the process)
85  for(int r = 0; r < rows; r++)
86  {
87  for(int c = 0; c < cols; c++)
88  {
89  // Case 1: Top Row PE's
90  if(is_top_pe(r, c, rows, cols))
91  {
92  // Change inputs
93  pcv[0][r][c] = mask_top_pe(pcv[0][r][c]);
94  // Change outputs
95  pcv[1][r][c] = mask_top_pe(pcv[1][r][c]);
96  }
97 
98  // Case 2: Bottom Row PE's
99  if(is_bot_pe(r, c, rows, cols))
100  {
101  // Change inputs
102  pcv[0][r][c] = mask_bot_pe(pcv[0][r][c]);
103  // Change outputs
104  pcv[1][r][c] = mask_bot_pe(pcv[1][r][c]);
105  }
106 
107  // Case 3: Left Column PE's
108  if(is_leftmost_pe(r, c, rows, cols))
109  {
110  // Change inputs
111  pcv[0][r][c] = mask_leftmost_pe(pcv[0][r][c]);
112  // Change outputs
113  pcv[1][r][c] = mask_leftmost_pe(pcv[1][r][c]);
114  }
115 
116  // Case 4: Right Column PE's
117  if(is_rightmost_pe(r, c, rows, cols))
118  {
119  // Change inputs
120  pcv[0][r][c] = mask_rightmost_pe(pcv[0][r][c]);
121  // Change outputs
122  pcv[1][r][c] = mask_rightmost_pe(pcv[1][r][c]);
123  }
124  }
125  }
126 }
127 
128 
129 std::unique_ptr<CGRA> UserArchs::createElasticRIKENArch(const ConfigStore& args)
130 {
131  // Declare all variables
132  const unsigned int cols = args.getInt("cols");
133  const unsigned int rows = args.getInt("rows");
134  const int contexts = args.getInt("II");
135  const int fu_II = args.getInt("fu_II");
136  const int pe_conn = args.getInt("pe_conn");
137  const int fu_latency = args.getInt("fu_latency");
138  const int eb_depth = args.getInt("eb_depth");
139  const bool eb_enable = args.getBool("eb_enable");
140  const int type = args.getInt("type");
141  //const bool pred = args.getBool("pred");
142  //std::string pred_type = args.getString("pred_type");
143 
144  /*if (pred_type.compare("full") != 0 && pred_type.compare("partial") != 0) {
145  throw cgrame_error("Predication type should be full or partial");
146  }*/
147 
151  double moduleW = 1.0/(cols+2);
152  double moduleH = 1.0/(rows+2);
153 
154  // Set bit width to 32
155  const int SIZE = 32;
156 
157  // Variables for use when making connections between tiles
158  std::string north = std::to_string(0);
159  std::string east = std::to_string(1);
160  std::string west = std::to_string(3);
161  std::string south = std::to_string(2);
162  std::string northWest = std::to_string(4);
163  std::string northEast = std::to_string(5);
164  std::string southEast = std::to_string(6);
165  std::string southWest = std::to_string(7);
166 
167  // Determine all input and output connections from each PE
168 
169  // Vectors describe the incoming and outgoing connections from each PE
170  // Organization: pe_conn_vec[in(0)/out(1)] [rows] [cols] ie pe_conn_vec[0][1][2] stores the incoming connections for the PE at row 1, column 2
171  std::vector < std::vector < std::vector<int> > > pe_conn_vec(2, std::vector< std::vector<int> >(rows, std::vector<int>(cols)));
172 
173  // Populate pe_conn_array
174  RIKENelasticFillPEConnArray(pe_conn_vec, pe_conn, rows, cols);
175 
176  auto cgra_storage = std::make_unique<CGRA>();
177  Module* result = &cgra_storage->getTopLevelModule();
178  result->isElastic = true;
179  bool isElastic = result->isElastic;
180 
181  // Instantiate all PEs in the array
182  for (unsigned int c = 0; c < cols; c++)
183  {
184  for(unsigned int r = 0; r < rows; r++)
185  {
186  Location loc = {c + 1, r + 1};
187 
188  result->addSubModule(new RIKEN_PE_Elastic("pe_c" + std::to_string(c) + "_r" + std::to_string(r), pe_conn_vec[0][r][c], pe_conn_vec[1][r][c], fu_II, fu_latency, loc, type, eb_depth, eb_enable, contexts), (c+1.0)*moduleW, (r+1.0)*moduleH, moduleW, moduleH);
189  }
190  }
191 
192  // IOs on the top and bottom of the array
193  for (unsigned int c = 0; c < cols; c++)
194  {
195  Location loc_bot = {c + 1, rows + 1};
196  Location loc_top = {c + 1, 0};
197  result->addSubModule(new IO("io_top_" + std::to_string(c), loc_top, SIZE, contexts, isElastic), c/(cols+2.0), 0, moduleW, moduleH);
198  result->addSubModule(new IO("io_bottom_" + std::to_string(c), loc_bot, SIZE, contexts, isElastic), c*moduleW, (rows+1.0)*moduleH, moduleW, moduleH);
199  }
200 
201  // IOs on the left and right of the array
202  for (unsigned int r = 0; r < rows; r++)
203  {
204  Location loc_l = {0, r + 1};
205  Location loc_r = {cols + 1, r + 1};
206  result->addSubModule(new IO("io_left_" + std::to_string(r), loc_l, SIZE, contexts, isElastic), (cols+1.0)*moduleW, (r+1.0)*moduleH, moduleW, moduleH);
207  result->addSubModule(new IO("io_right_" + std::to_string(r), loc_r, SIZE, contexts, isElastic), (cols+1.0)*moduleW, (r+1.0)*moduleH, moduleW, moduleH);
208  }
209 
210  // Inter-PE connections based on the connectivity vectors
211  for(unsigned int c = 0; c < cols; c++)
212  {
213  for(unsigned int r = 0; r < rows; r++)
214  {
215  std::string currC = std::to_string(c);
216  std::string currR = std::to_string(r);
217 
218  std::string blk_n_c_r = "pe_c" + currC + "_r" + currR;
219 
220  // Use pe_conn to determine whether a connection should be made
221  if(has_input_from_N(pe_conn_vec[0][r][c]))
222  {
223  //Special Case: Top row PE's connect to I/O's
224  if(r == 0)
225  {
226  result->connectPorts("io_top_" + currC + ".out",
227  blk_n_c_r + ".in" + north, isElastic);
228 
229  result->connectPorts(blk_n_c_r + ".out" + north,
230  "io_top_" + currC + ".in", isElastic);
231  }else
232  {
233  result->connectPorts("pe_c" + currC + "_r" + std::to_string(r-1) + ".out" + south,
234  blk_n_c_r + ".in" + north, isElastic);
235  }
236  }
237 
238  if(has_input_from_E(pe_conn_vec[0][r][c]))
239  {
240  // Special Case: Right-most PE's connect to I/O's
241  if(c == cols - 1)
242  {
243  result->connectPorts("io_right_" + currR + ".out",
244  blk_n_c_r + ".in" + east, isElastic);
245 
246  result->connectPorts(blk_n_c_r + ".out" + east,
247  "io_right_" + currR + ".in", isElastic);
248  }else
249  {
250  result->connectPorts("pe_c" + std::to_string(c+1) + "_r" + currR + ".out" + west,
251  blk_n_c_r + ".in" + east, isElastic);
252  }
253  }
254 
255  if(has_input_from_S(pe_conn_vec[0][r][c]))
256  {
257  // Special Case: Bottom-most PE's connect to I/O's
258  if(r == rows - 1)
259  {
260  result->connectPorts("io_bottom_" + currC + ".out",
261  blk_n_c_r + ".in" + south, isElastic);
262 
263  result->connectPorts(blk_n_c_r + ".out" + south,
264  "io_bottom_" + currC + ".in", isElastic);
265  }else
266  {
267  result->connectPorts("pe_c" + currC + "_r" + std::to_string(r+1) + ".out" + north,
268  blk_n_c_r + ".in" + south, isElastic);
269  }
270  }
271 
272  if(has_input_from_W(pe_conn_vec[0][r][c]))
273  {
274  // Special Case: Left-most PE's connect to I/O's
275  if(c == 0)
276  {
277  result->connectPorts("io_left_" + currR + ".out",
278  blk_n_c_r + ".in" + west, isElastic);
279 
280  result->connectPorts(blk_n_c_r + ".out" + west,
281  "io_left_" + currR + ".in", isElastic);
282  }else
283  {
284  result->connectPorts("pe_c" + std::to_string(c-1) + "_r" + currR + ".out" + east,
285  blk_n_c_r + ".in" + west, isElastic);
286 
287  }
288  }
289 
290  if(has_input_from_NW(pe_conn_vec[0][r][c]))
291  {
292  result->connectPorts("pe_c" + std::to_string(c-1) + "_r" + std::to_string(r-1) + ".out" + southEast,
293  blk_n_c_r + ".in" + northWest, isElastic);
294  }
295 
296  if(has_input_from_NE(pe_conn_vec[0][r][c]))
297  {
298  result->connectPorts("pe_c" + std::to_string(c+1) + "_r" + std::to_string(r-1) + ".out" + southWest,
299  blk_n_c_r + ".in" + northEast, isElastic);
300  }
301 
302  if(has_input_from_SE(pe_conn_vec[0][r][c]))
303  {
304  result->connectPorts("pe_c" + std::to_string(c+1) + "_r" + std::to_string(r+1) + ".out" + northWest,
305  blk_n_c_r + ".in" + southEast, isElastic);
306  }
307 
308  if(has_input_from_SW(pe_conn_vec[0][r][c]))
309  {
310  result->connectPorts("pe_c" + std::to_string(c-1) + "_r" + std::to_string(r+1) + ".out" + northEast,
311  blk_n_c_r + ".in" + southWest, isElastic);
312  }
313  }
314  }
315 
316  return cgra_storage;
317 }
is_bot_pe
#define is_bot_pe(r, c, rows, cols)
Definition: ElasticRIKEN.cpp:28
Location
Definition: Module.h:156
RIKEN_PE_Elastic
Definition: UserModules.h:30
has_input_from_NE
#define has_input_from_NE(conn)
Definition: ElasticRIKEN.cpp:22
UserArchs.h
ConfigStore
Definition: ConfigStore.h:76
mask_top_pe
#define mask_top_pe(conn)
Definition: ElasticRIKEN.cpp:33
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
Exception.h
has_input_from_S
#define has_input_from_S(conn)
Definition: ElasticRIKEN.cpp:19
has_input_from_NW
#define has_input_from_NW(conn)
Definition: ElasticRIKEN.cpp:21
has_input_from_SE
#define has_input_from_SE(conn)
Definition: ElasticRIKEN.cpp:23
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: ElasticRIKEN.cpp:17
RIKENelasticFillPEConnArray
void RIKENelasticFillPEConnArray(std::vector< std::vector< std::vector< int > > > &pcv, int pe_conn_orig, int rows, int cols)
Definition: ElasticRIKEN.cpp:46
Module
Definition: Module.h:163
is_leftmost_pe
#define is_leftmost_pe(r, c, rows, cols)
Definition: ElasticRIKEN.cpp:29
has_input_from_W
#define has_input_from_W(conn)
Definition: ElasticRIKEN.cpp:20
is_rightmost_pe
#define is_rightmost_pe(r, c, rows, cols)
Definition: ElasticRIKEN.cpp:30
Module::addSubModule
void addSubModule(Module *m)
Definition: Module.cpp:1124
mask_rightmost_pe
#define mask_rightmost_pe(conn)
Definition: ElasticRIKEN.cpp:36
Module::isElastic
bool isElastic
Definition: Module.h:236
has_input_from_E
#define has_input_from_E(conn)
Definition: ElasticRIKEN.cpp:18
has_input_from_SW
#define has_input_from_SW(conn)
Definition: ElasticRIKEN.cpp:24
is_top_pe
#define is_top_pe(r, c, rows, cols)
Definition: ElasticRIKEN.cpp:27
UserArchs::createElasticRIKENArch
static std::unique_ptr< CGRA > createElasticRIKENArch(const ConfigStore &args)
Definition: ElasticRIKEN.cpp:129
Module::connectPorts
void connectPorts(std::string src, std::string dst, bool isElastic)
Definition: Module.cpp:1232
ConfigStore::getInt
long long getInt(const std::string &key) const
Definition: ConfigStore.h:146
mask_bot_pe
#define mask_bot_pe(conn)
Definition: ElasticRIKEN.cpp:34
ConfigStore::getBool
bool getBool(const std::string &key) const
Definition: ConfigStore.h:166
mask_leftmost_pe
#define mask_leftmost_pe(conn)
Definition: ElasticRIKEN.cpp:35
RIKENelasticleftshift2
int RIKENelasticleftshift2(int val)
Definition: ElasticRIKEN.cpp:38