Skip to content

Commit 6595b26

Browse files
authored
Merge pull request #2649 from verilog-to-routing/3d_noc
3D NoC
2 parents f43e070 + 8228d52 commit 6595b26

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+49845
-774
lines changed

libs/libarchfpga/src/physical_types.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -829,10 +829,11 @@ struct t_physical_pin {
829829

830830
/**
831831
* @brief Describes The location of a physical tile
832-
* @param layer_num The die number of the physical tile. If the FPGA only has one die, or the physical tile is located
833-
* on the base die, layer_num is equal to zero. If it is one the die above base die, it is one, etc.
834832
* @param x The x location of the physical tile on the given die
835833
* @param y The y location of the physical tile on the given die
834+
* @param layer_num The die number of the physical tile. If the FPGA only has one die, or the physical tile is located
835+
* on the base die, layer_num is equal to zero. If the physical tile is location on the die immediately
836+
* above the base die, the layer_num is 1 and so on.
836837
*/
837838
struct t_physical_tile_loc {
838839
int x = OPEN;
@@ -1982,10 +1983,12 @@ struct t_router {
19821983

19831984
/** A value representing the approximate horizontal position on the FPGA device where the router
19841985
* tile is located*/
1985-
double device_x_position = -1;
1986+
float device_x_position = -1;
19861987
/** A value representing the approximate vertical position on the FPGA device where the router
19871988
* tile is located*/
1988-
double device_y_position = -1;
1989+
float device_y_position = -1;
1990+
/** A value representing the exact layer in the FPGA device where the router tile is located.*/
1991+
int device_layer_position = -1;
19891992

19901993
/** A list of router ids that are connected to the current router*/
19911994
std::vector<int> connection_list;

libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp

Lines changed: 81 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@ static void process_mesh_topology(pugi::xml_node mesh_topology_tag,
6868
static void generate_noc_mesh(pugi::xml_node mesh_topology_tag,
6969
const pugiutil::loc_data& loc_data,
7070
t_noc_inf* noc_ref,
71-
double mesh_region_start_x, double mesh_region_end_x,
72-
double mesh_region_start_y, double mesh_region_end_y,
71+
float mesh_region_start_x, float mesh_region_end_x,
72+
float mesh_region_start_y, float mesh_region_end_y,
73+
int mesh_region_start_layer, int mesh_region_end_layer,
7374
int mesh_size);
7475

7576
/**
@@ -227,17 +228,19 @@ static void process_mesh_topology(pugi::xml_node mesh_topology_tag,
227228
constexpr int ATTRIBUTE_CONVERSION_FAILURE = -1;
228229

229230
// a list of attributes that should be found for the mesh tag
230-
std::vector<std::string> expected_router_attributes = {"startx", "endx", "starty", "endy", "size"};
231+
std::vector<std::string> expected_router_attributes = {"startx", "endx", "starty", "endy", "startlayer", "endlayer", "size"};
231232

232233
// verify that only the acceptable attributes were supplied
233234
pugiutil::expect_only_attributes(mesh_topology_tag, expected_router_attributes, loc_data);
234235

235236
// go through the attributes and store their values
236-
double mesh_region_start_x = pugiutil::get_attribute(mesh_topology_tag, "startx", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE);
237-
double mesh_region_end_x = pugiutil::get_attribute(mesh_topology_tag, "endx", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE);
238-
double mesh_region_start_y = pugiutil::get_attribute(mesh_topology_tag, "starty", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE);
239-
double mesh_region_end_y = pugiutil::get_attribute(mesh_topology_tag, "endy", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE);
237+
float mesh_region_start_x = pugiutil::get_attribute(mesh_topology_tag, "startx", loc_data, pugiutil::REQUIRED).as_float(ATTRIBUTE_CONVERSION_FAILURE);
238+
float mesh_region_end_x = pugiutil::get_attribute(mesh_topology_tag, "endx", loc_data, pugiutil::REQUIRED).as_float(ATTRIBUTE_CONVERSION_FAILURE);
239+
float mesh_region_start_y = pugiutil::get_attribute(mesh_topology_tag, "starty", loc_data, pugiutil::REQUIRED).as_float(ATTRIBUTE_CONVERSION_FAILURE);
240+
float mesh_region_end_y = pugiutil::get_attribute(mesh_topology_tag, "endy", loc_data, pugiutil::REQUIRED).as_float(ATTRIBUTE_CONVERSION_FAILURE);
240241

242+
int mesh_region_start_layer = pugiutil::get_attribute(mesh_topology_tag, "startlayer", loc_data, pugiutil::OPTIONAL).as_int(ATTRIBUTE_CONVERSION_FAILURE);
243+
int mesh_region_end_layer = pugiutil::get_attribute(mesh_topology_tag, "endlayer", loc_data, pugiutil::OPTIONAL).as_int(ATTRIBUTE_CONVERSION_FAILURE);
241244
int mesh_size = pugiutil::get_attribute(mesh_topology_tag, "size", loc_data, pugiutil::REQUIRED).as_int(ATTRIBUTE_CONVERSION_FAILURE);
242245

243246
// verify that the attributes provided were legal
@@ -246,16 +249,29 @@ static void process_mesh_topology(pugi::xml_node mesh_topology_tag,
246249
"The parameters for the mesh topology have to be positive values.");
247250
}
248251

252+
if (mesh_region_start_layer == ATTRIBUTE_CONVERSION_FAILURE || mesh_region_end_layer == ATTRIBUTE_CONVERSION_FAILURE) {
253+
VTR_LOGF_WARN(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag),
254+
"Optional 'startlayer' and 'endlayer' attributes were not set for the <mesh> tag. "
255+
"The default value of zero is used for both of them.\n");
256+
mesh_region_start_layer = 0;
257+
mesh_region_end_layer = 0;
258+
}
259+
249260
// now create the mesh topology for the noc
250261
// create routers, make connections and determine positions
251-
generate_noc_mesh(mesh_topology_tag, loc_data, noc_ref, mesh_region_start_x, mesh_region_end_x, mesh_region_start_y, mesh_region_end_y, mesh_size);
262+
generate_noc_mesh(mesh_topology_tag, loc_data, noc_ref,
263+
mesh_region_start_x, mesh_region_end_x,
264+
mesh_region_start_y, mesh_region_end_y,
265+
mesh_region_start_layer, mesh_region_end_layer,
266+
mesh_size);
252267
}
253268

254269
static void generate_noc_mesh(pugi::xml_node mesh_topology_tag,
255270
const pugiutil::loc_data& loc_data,
256271
t_noc_inf* noc_ref,
257-
double mesh_region_start_x, double mesh_region_end_x,
258-
double mesh_region_start_y, double mesh_region_end_y,
272+
float mesh_region_start_x, float mesh_region_end_x,
273+
float mesh_region_start_y, float mesh_region_end_y,
274+
int mesh_region_start_layer, int mesh_region_end_layer,
259275
int mesh_size) {
260276
// check that the mesh size of the router is not 0
261277
if (mesh_size == 0) {
@@ -285,62 +301,74 @@ static void generate_noc_mesh(pugi::xml_node mesh_topology_tag,
285301
*
286302
* THe reasoning for this is to reduce the number of calculated router positions.
287303
*/
288-
double vertical_router_separation = (mesh_region_end_y - mesh_region_start_y) / (mesh_size - 1);
289-
double horizontal_router_separation = (mesh_region_end_x - mesh_region_start_x) / (mesh_size - 1);
290-
291-
t_router temp_router;
304+
float vertical_router_separation = (mesh_region_end_y - mesh_region_start_y) / (mesh_size - 1);
305+
float horizontal_router_separation = (mesh_region_end_x - mesh_region_start_x) / (mesh_size - 1);
292306

293307
// improper region check
294-
if ((vertical_router_separation <= 0) || (horizontal_router_separation <= 0)) {
308+
if (vertical_router_separation <= 0 || horizontal_router_separation <= 0 ||
309+
mesh_region_end_layer < mesh_region_start_layer) {
295310
archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag),
296311
"The NoC region is invalid.");
297312
}
298313

299314
// create routers and their connections
300315
// start with router id 0 (bottom left of the chip) to the maximum router id (top right of the chip)
301-
for (int j = 0; j < mesh_size; j++) {
302-
for (int i = 0; i < mesh_size; i++) {
303-
// assign router id
304-
temp_router.id = (mesh_size * j) + i;
305-
306-
// calculate router position
307-
/* The first and last router of each column or row will be located on the mesh region boundary,
308-
* the remaining routers will be placed within the region and seperated from other routers
309-
* using the distance calculated previously.
310-
*/
311-
temp_router.device_x_position = (i * horizontal_router_separation) + mesh_region_start_x;
312-
temp_router.device_y_position = (j * vertical_router_separation) + mesh_region_start_y;
313-
314-
// assign connections
315-
// check if there is a router to the left
316-
if ((i - 1) >= 0) {
317-
// add the left router as a connection
318-
temp_router.connection_list.push_back((mesh_size * j) + i - 1);
319-
}
316+
for (int l = mesh_region_start_layer; l <= mesh_region_end_layer; l++) {
317+
for (int j = 0; j < mesh_size; j++) {
318+
for (int i = 0; i < mesh_size; i++) {
319+
t_router temp_router;
320+
321+
// assign router id
322+
temp_router.id = (mesh_size * mesh_size * (l - mesh_region_start_layer)) + (mesh_size * j) + i;
323+
324+
// calculate router position
325+
/* The first and last router of each column or row will be located on the mesh region boundary,
326+
* the remaining routers will be placed within the region and seperated from other routers
327+
* using the distance calculated previously.
328+
*/
329+
temp_router.device_x_position = (i * horizontal_router_separation) + mesh_region_start_x;
330+
temp_router.device_y_position = (j * vertical_router_separation) + mesh_region_start_y;
331+
temp_router.device_layer_position = l;
332+
333+
// assign connections
334+
335+
// check if there is a router to the left
336+
if (i >= 1) {
337+
// add the left router as a connection
338+
temp_router.connection_list.push_back(temp_router.id - 1);
339+
}
320340

321-
// check if there is a router to the top
322-
if ((j + 1) <= (mesh_size - 1)) {
323-
// add the top router as a connection
324-
temp_router.connection_list.push_back((mesh_size * (j + 1)) + i);
325-
}
341+
// check if there is a router to the top
342+
if (j <= mesh_size - 2) {
343+
// add the top router as a connection
344+
temp_router.connection_list.push_back(temp_router.id + mesh_size);
345+
}
326346

327-
// check if there is a router to the right
328-
if ((i + 1) <= (mesh_size - 1)) {
329-
// add the router located to the right
330-
temp_router.connection_list.push_back((mesh_size * j) + i + 1);
331-
}
347+
// check if there is a router to the right
348+
if (i <= mesh_size - 2) {
349+
// add the router located to the right
350+
temp_router.connection_list.push_back(temp_router.id + 1);
351+
}
332352

333-
// check of there is a router below
334-
if ((j - 1) >= (0)) {
335-
// add the bottom router as a connection
336-
temp_router.connection_list.push_back((mesh_size * (j - 1)) + i);
337-
}
353+
// check if there is a router below
354+
if (j >= 1) {
355+
// add the bottom router as a connection
356+
temp_router.connection_list.push_back(temp_router.id - mesh_size);
357+
}
338358

339-
// add the router to the list
340-
noc_ref->router_list.push_back(temp_router);
359+
// check if there is a router on the layer above
360+
if (l < mesh_region_end_layer) {
361+
temp_router.connection_list.push_back(temp_router.id + (mesh_size * mesh_size));
362+
}
341363

342-
// clear the current router information for the next router
343-
temp_router.connection_list.clear();
364+
// check if there is a router on the layer below
365+
if (l > mesh_region_start_layer) {
366+
temp_router.connection_list.push_back(temp_router.id - (mesh_size * mesh_size));
367+
}
368+
369+
// add the router to the list
370+
noc_ref->router_list.push_back(temp_router);
371+
}
344372
}
345373
}
346374
}

libs/libarchfpga/test/test_read_xml_arch_file.cpp

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -148,19 +148,21 @@ TEST_CASE("Verifying mesh topology creation", "[NoC Arch Tests]") {
148148
t_noc_inf test_noc;
149149

150150
// mesh parameters
151-
double mesh_start_x = 10;
152-
double mesh_start_y = 10;
153-
double mesh_end_x = 5;
154-
double mesh_end_y = 56;
155-
double mesh_size = 0;
151+
float mesh_start_x = 10;
152+
float mesh_start_y = 10;
153+
float mesh_end_x = 5;
154+
float mesh_end_y = 56;
155+
float mesh_size = 0;
156+
int mesh_start_layer = 0;
157+
int mesh_end_layer = 0;
156158

157159
SECTION("Check the error where a mesh size was illegal.") {
158-
REQUIRE_THROWS_WITH(generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size), "The NoC mesh size cannot be 0.");
160+
REQUIRE_THROWS_WITH(generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_start_layer, mesh_end_layer, mesh_size), "The NoC mesh size cannot be 0.");
159161
}
160162
SECTION("Check the error where a mesh region size was invalid.") {
161163
mesh_size = 3;
162164

163-
REQUIRE_THROWS_WITH(generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size), "The NoC region is invalid.");
165+
REQUIRE_THROWS_WITH(generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_start_layer, mesh_end_layer, mesh_size), "The NoC region is invalid.");
164166
}
165167
SECTION("Check the mesh creation for integer precision coordinates.") {
166168
// define test parameters
@@ -173,8 +175,8 @@ TEST_CASE("Verifying mesh topology creation", "[NoC Arch Tests]") {
173175
mesh_end_y = 4;
174176

175177
// create the golden results
176-
double golden_results_x[9];
177-
double golden_results_y[9];
178+
float golden_results_x[9];
179+
float golden_results_y[9];
178180

179181
// first row of the mesh
180182
golden_results_x[0] = 0;
@@ -200,7 +202,7 @@ TEST_CASE("Verifying mesh topology creation", "[NoC Arch Tests]") {
200202
golden_results_x[8] = 4;
201203
golden_results_y[8] = 4;
202204

203-
generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size);
205+
generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_start_layer, mesh_end_layer, mesh_size);
204206

205207
// go through all the expected routers
206208
for (int expected_router_id = 0; expected_router_id < (mesh_size * mesh_size); expected_router_id++) {
@@ -224,9 +226,9 @@ TEST_CASE("Verifying mesh topology creation", "[NoC Arch Tests]") {
224226
mesh_end_x = 10.8;
225227
mesh_end_y = 6.4;
226228

227-
// create the golden golden results
228-
double golden_results_x[9];
229-
double golden_results_y[9];
229+
// create the golden results
230+
float golden_results_x[9];
231+
float golden_results_y[9];
230232

231233
// first row of the mesh
232234
golden_results_x[0] = 3.5;
@@ -252,7 +254,7 @@ TEST_CASE("Verifying mesh topology creation", "[NoC Arch Tests]") {
252254
golden_results_x[8] = 10.8;
253255
golden_results_y[8] = 6.4;
254256

255-
generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size);
257+
generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_start_layer, mesh_end_layer, mesh_size);
256258

257259
// go through all the expected routers
258260
for (int expected_router_id = 0; expected_router_id < (mesh_size * mesh_size); expected_router_id++) {

libs/libvtrutil/src/vtr_util.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,25 @@ std::string join(Container container, std::string_view delim);
4848
template<typename T>
4949
std::string join(std::initializer_list<T> list, std::string_view delim);
5050

51+
/**
52+
* @brief Checks if exactly `k` conditions are true.
53+
*
54+
* @tparam Conditions A variadic template parameter pack representing the types of the conditions,
55+
* which should all be convertible to `bool`.
56+
* @param k The exact number of conditions that should evaluate to true.
57+
* @param conditions A variable number of boolean expressions or conditions to evaluate.
58+
* @return `true` if exactly `k` of the provided conditions are true; otherwise `false`.
59+
*
60+
* @example
61+
* @code
62+
* bool result = exactly_k_conditions(2, true, false, true); // Returns true
63+
* result = exactly_k_conditions(1, true, false, false); // Returns true
64+
* result = exactly_k_conditions(3, true, true, false); // Returns false
65+
* @endcode
66+
*/
67+
template<typename... Conditions>
68+
bool exactly_k_conditions(int k, Conditions... conditions);
69+
5170
template<typename Container>
5271
void uniquify(Container container);
5372

@@ -116,6 +135,18 @@ void uniquify(Container container) {
116135
container.end());
117136
}
118137

138+
template<typename... Conditions>
139+
bool exactly_k_conditions(int k, Conditions... conditions) {
140+
bool conditionArray[] = {conditions...};
141+
int count = 0;
142+
for (bool condition : conditionArray) {
143+
if (condition) {
144+
count++;
145+
}
146+
}
147+
return count == k;
148+
}
149+
119150
int get_pid();
120151

121152
} // namespace vtr

0 commit comments

Comments
 (0)