Skip to content

Commit

Permalink
Merge pull request #2649 from verilog-to-routing/3d_noc
Browse files Browse the repository at this point in the history
3D NoC
  • Loading branch information
vaughnbetz authored Sep 17, 2024
2 parents f43e070 + 8228d52 commit 6595b26
Show file tree
Hide file tree
Showing 42 changed files with 49,845 additions and 774 deletions.
11 changes: 7 additions & 4 deletions libs/libarchfpga/src/physical_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -829,10 +829,11 @@ struct t_physical_pin {

/**
* @brief Describes The location of a physical tile
* @param layer_num The die number of the physical tile. If the FPGA only has one die, or the physical tile is located
* on the base die, layer_num is equal to zero. If it is one the die above base die, it is one, etc.
* @param x The x location of the physical tile on the given die
* @param y The y location of the physical tile on the given die
* @param layer_num The die number of the physical tile. If the FPGA only has one die, or the physical tile is located
* on the base die, layer_num is equal to zero. If the physical tile is location on the die immediately
* above the base die, the layer_num is 1 and so on.
*/
struct t_physical_tile_loc {
int x = OPEN;
Expand Down Expand Up @@ -1982,10 +1983,12 @@ struct t_router {

/** A value representing the approximate horizontal position on the FPGA device where the router
* tile is located*/
double device_x_position = -1;
float device_x_position = -1;
/** A value representing the approximate vertical position on the FPGA device where the router
* tile is located*/
double device_y_position = -1;
float device_y_position = -1;
/** A value representing the exact layer in the FPGA device where the router tile is located.*/
int device_layer_position = -1;

/** A list of router ids that are connected to the current router*/
std::vector<int> connection_list;
Expand Down
134 changes: 81 additions & 53 deletions libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ static void process_mesh_topology(pugi::xml_node mesh_topology_tag,
static void generate_noc_mesh(pugi::xml_node mesh_topology_tag,
const pugiutil::loc_data& loc_data,
t_noc_inf* noc_ref,
double mesh_region_start_x, double mesh_region_end_x,
double mesh_region_start_y, double mesh_region_end_y,
float mesh_region_start_x, float mesh_region_end_x,
float mesh_region_start_y, float mesh_region_end_y,
int mesh_region_start_layer, int mesh_region_end_layer,
int mesh_size);

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

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

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

// go through the attributes and store their values
double mesh_region_start_x = pugiutil::get_attribute(mesh_topology_tag, "startx", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE);
double mesh_region_end_x = pugiutil::get_attribute(mesh_topology_tag, "endx", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE);
double mesh_region_start_y = pugiutil::get_attribute(mesh_topology_tag, "starty", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE);
double mesh_region_end_y = pugiutil::get_attribute(mesh_topology_tag, "endy", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE);
float mesh_region_start_x = pugiutil::get_attribute(mesh_topology_tag, "startx", loc_data, pugiutil::REQUIRED).as_float(ATTRIBUTE_CONVERSION_FAILURE);
float mesh_region_end_x = pugiutil::get_attribute(mesh_topology_tag, "endx", loc_data, pugiutil::REQUIRED).as_float(ATTRIBUTE_CONVERSION_FAILURE);
float mesh_region_start_y = pugiutil::get_attribute(mesh_topology_tag, "starty", loc_data, pugiutil::REQUIRED).as_float(ATTRIBUTE_CONVERSION_FAILURE);
float mesh_region_end_y = pugiutil::get_attribute(mesh_topology_tag, "endy", loc_data, pugiutil::REQUIRED).as_float(ATTRIBUTE_CONVERSION_FAILURE);

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

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

if (mesh_region_start_layer == ATTRIBUTE_CONVERSION_FAILURE || mesh_region_end_layer == ATTRIBUTE_CONVERSION_FAILURE) {
VTR_LOGF_WARN(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag),
"Optional 'startlayer' and 'endlayer' attributes were not set for the <mesh> tag. "
"The default value of zero is used for both of them.\n");
mesh_region_start_layer = 0;
mesh_region_end_layer = 0;
}

// now create the mesh topology for the noc
// create routers, make connections and determine positions
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);
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_region_start_layer, mesh_region_end_layer,
mesh_size);
}

static void generate_noc_mesh(pugi::xml_node mesh_topology_tag,
const pugiutil::loc_data& loc_data,
t_noc_inf* noc_ref,
double mesh_region_start_x, double mesh_region_end_x,
double mesh_region_start_y, double mesh_region_end_y,
float mesh_region_start_x, float mesh_region_end_x,
float mesh_region_start_y, float mesh_region_end_y,
int mesh_region_start_layer, int mesh_region_end_layer,
int mesh_size) {
// check that the mesh size of the router is not 0
if (mesh_size == 0) {
Expand Down Expand Up @@ -285,62 +301,74 @@ static void generate_noc_mesh(pugi::xml_node mesh_topology_tag,
*
* THe reasoning for this is to reduce the number of calculated router positions.
*/
double vertical_router_separation = (mesh_region_end_y - mesh_region_start_y) / (mesh_size - 1);
double horizontal_router_separation = (mesh_region_end_x - mesh_region_start_x) / (mesh_size - 1);

t_router temp_router;
float vertical_router_separation = (mesh_region_end_y - mesh_region_start_y) / (mesh_size - 1);
float horizontal_router_separation = (mesh_region_end_x - mesh_region_start_x) / (mesh_size - 1);

// improper region check
if ((vertical_router_separation <= 0) || (horizontal_router_separation <= 0)) {
if (vertical_router_separation <= 0 || horizontal_router_separation <= 0 ||
mesh_region_end_layer < mesh_region_start_layer) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag),
"The NoC region is invalid.");
}

// create routers and their connections
// start with router id 0 (bottom left of the chip) to the maximum router id (top right of the chip)
for (int j = 0; j < mesh_size; j++) {
for (int i = 0; i < mesh_size; i++) {
// assign router id
temp_router.id = (mesh_size * j) + i;

// calculate router position
/* The first and last router of each column or row will be located on the mesh region boundary,
* the remaining routers will be placed within the region and seperated from other routers
* using the distance calculated previously.
*/
temp_router.device_x_position = (i * horizontal_router_separation) + mesh_region_start_x;
temp_router.device_y_position = (j * vertical_router_separation) + mesh_region_start_y;

// assign connections
// check if there is a router to the left
if ((i - 1) >= 0) {
// add the left router as a connection
temp_router.connection_list.push_back((mesh_size * j) + i - 1);
}
for (int l = mesh_region_start_layer; l <= mesh_region_end_layer; l++) {
for (int j = 0; j < mesh_size; j++) {
for (int i = 0; i < mesh_size; i++) {
t_router temp_router;

// assign router id
temp_router.id = (mesh_size * mesh_size * (l - mesh_region_start_layer)) + (mesh_size * j) + i;

// calculate router position
/* The first and last router of each column or row will be located on the mesh region boundary,
* the remaining routers will be placed within the region and seperated from other routers
* using the distance calculated previously.
*/
temp_router.device_x_position = (i * horizontal_router_separation) + mesh_region_start_x;
temp_router.device_y_position = (j * vertical_router_separation) + mesh_region_start_y;
temp_router.device_layer_position = l;

// assign connections

// check if there is a router to the left
if (i >= 1) {
// add the left router as a connection
temp_router.connection_list.push_back(temp_router.id - 1);
}

// check if there is a router to the top
if ((j + 1) <= (mesh_size - 1)) {
// add the top router as a connection
temp_router.connection_list.push_back((mesh_size * (j + 1)) + i);
}
// check if there is a router to the top
if (j <= mesh_size - 2) {
// add the top router as a connection
temp_router.connection_list.push_back(temp_router.id + mesh_size);
}

// check if there is a router to the right
if ((i + 1) <= (mesh_size - 1)) {
// add the router located to the right
temp_router.connection_list.push_back((mesh_size * j) + i + 1);
}
// check if there is a router to the right
if (i <= mesh_size - 2) {
// add the router located to the right
temp_router.connection_list.push_back(temp_router.id + 1);
}

// check of there is a router below
if ((j - 1) >= (0)) {
// add the bottom router as a connection
temp_router.connection_list.push_back((mesh_size * (j - 1)) + i);
}
// check if there is a router below
if (j >= 1) {
// add the bottom router as a connection
temp_router.connection_list.push_back(temp_router.id - mesh_size);
}

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

// clear the current router information for the next router
temp_router.connection_list.clear();
// check if there is a router on the layer below
if (l > mesh_region_start_layer) {
temp_router.connection_list.push_back(temp_router.id - (mesh_size * mesh_size));
}

// add the router to the list
noc_ref->router_list.push_back(temp_router);
}
}
}
}
Expand Down
30 changes: 16 additions & 14 deletions libs/libarchfpga/test/test_read_xml_arch_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,19 +148,21 @@ TEST_CASE("Verifying mesh topology creation", "[NoC Arch Tests]") {
t_noc_inf test_noc;

// mesh parameters
double mesh_start_x = 10;
double mesh_start_y = 10;
double mesh_end_x = 5;
double mesh_end_y = 56;
double mesh_size = 0;
float mesh_start_x = 10;
float mesh_start_y = 10;
float mesh_end_x = 5;
float mesh_end_y = 56;
float mesh_size = 0;
int mesh_start_layer = 0;
int mesh_end_layer = 0;

SECTION("Check the error where a mesh size was illegal.") {
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.");
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.");
}
SECTION("Check the error where a mesh region size was invalid.") {
mesh_size = 3;

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.");
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.");
}
SECTION("Check the mesh creation for integer precision coordinates.") {
// define test parameters
Expand All @@ -173,8 +175,8 @@ TEST_CASE("Verifying mesh topology creation", "[NoC Arch Tests]") {
mesh_end_y = 4;

// create the golden results
double golden_results_x[9];
double golden_results_y[9];
float golden_results_x[9];
float golden_results_y[9];

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

generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size);
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);

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

// create the golden golden results
double golden_results_x[9];
double golden_results_y[9];
// create the golden results
float golden_results_x[9];
float golden_results_y[9];

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

generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size);
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);

// go through all the expected routers
for (int expected_router_id = 0; expected_router_id < (mesh_size * mesh_size); expected_router_id++) {
Expand Down
31 changes: 31 additions & 0 deletions libs/libvtrutil/src/vtr_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,25 @@ std::string join(Container container, std::string_view delim);
template<typename T>
std::string join(std::initializer_list<T> list, std::string_view delim);

/**
* @brief Checks if exactly `k` conditions are true.
*
* @tparam Conditions A variadic template parameter pack representing the types of the conditions,
* which should all be convertible to `bool`.
* @param k The exact number of conditions that should evaluate to true.
* @param conditions A variable number of boolean expressions or conditions to evaluate.
* @return `true` if exactly `k` of the provided conditions are true; otherwise `false`.
*
* @example
* @code
* bool result = exactly_k_conditions(2, true, false, true); // Returns true
* result = exactly_k_conditions(1, true, false, false); // Returns true
* result = exactly_k_conditions(3, true, true, false); // Returns false
* @endcode
*/
template<typename... Conditions>
bool exactly_k_conditions(int k, Conditions... conditions);

template<typename Container>
void uniquify(Container container);

Expand Down Expand Up @@ -116,6 +135,18 @@ void uniquify(Container container) {
container.end());
}

template<typename... Conditions>
bool exactly_k_conditions(int k, Conditions... conditions) {
bool conditionArray[] = {conditions...};
int count = 0;
for (bool condition : conditionArray) {
if (condition) {
count++;
}
}
return count == k;
}

int get_pid();

} // namespace vtr
Expand Down
Loading

0 comments on commit 6595b26

Please sign in to comment.