Skip to content

Commit 47ec730

Browse files
Add interposer tag parsing
This commit adds parsing logic for defining interposer-based architectures.
1 parent 7f476db commit 47ec730

File tree

7 files changed

+187
-24
lines changed

7 files changed

+187
-24
lines changed

doc/src/arch/reference.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,32 @@ Grid Layout Example
581581
582582
Example FPGA grid
583583
584+
585+
.. arch:tag:: <interposer_cut dim=x|y loc="int"/>
586+
587+
:req_param dim: Dimension or axis of the cut. 'X' or 'x' means a horizontal cut while 'Y' or 'y' means a vertical cut.
588+
:req_param loc: Location of the cut. Currently only absolute positions are supported.
589+
590+
.. note:: Interposers are experimental and are currently not supported by VPR and using the related tags will not actually result in any changes to the flow.
591+
Defines an interposer cut for modelling 2.5D interposer-based architectures. An interposer cut will cut all connections at location 'loc' along the axis 'dim' Leaving the two sides completely unconnected.
592+
To reconnect the two sides, this tag can have multiple <interdie_wire> tags as children to specify the connection between the two sides.
593+
594+
.. arch:tag:: <interdie_wire sg_name="string" sg_link="string" offset_start="int" offset_end="int" offset_increment="int" num="int"/>
595+
596+
:req_param sg_name: Name of the scatter-gather pattern to be used for the interdie connection.
597+
:req_param sg_link: Name of the scatter-gather link to be used for the interdie connection.
598+
:req_param offset_start: Starting point of scatter-gather instantiations.
599+
:req_param offset_end: Ending point of scatter-gather instantiations
600+
:req_param offset_increment: Increment/distance between scatter-gather instantiations.
601+
:req_param num: Number of scatter-gather instantiations per switchblock location.
602+
603+
Defines the interdie wiring between the two sides of the cut. Connectivity is defined using scatter-gather patterns. Starting at 'offset_start' from location of the cut and moving by 'offset_increment' until we reach the location of 'offset_end' away from the cut, 'num' scatter-gather patterns defined by 'sg_name' and 'sg_link' will be instantiated.
604+
Note that these offset points always define the starting point of the scatter-gather pattern's sg_link.
605+
606+
.. figure:: scatter_gather_images/interposer_diagram.png
607+
608+
An example of how specifying interposers in VTR works. Connections between the two sides of a cut are first severed. The two sides are then reconnected using scatter_gather patterns. Note that there are 'num' of each pattern at each switchblock locations.
609+
584610
.. _arch_device_info:
585611
586612
FPGA Device Information
97.3 KB
Loading
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#pragma once
2+
3+
/**
4+
* @file interposer_types.h
5+
* @brief This file contains types used for parsing interposer-related tags such as <interposer_cut> and <interdie_wire>
6+
* and converting that information into the device architecture-related data structures.
7+
*
8+
*/
9+
10+
#include <unordered_map>
11+
#include <vector>
12+
#include <string>
13+
14+
/**
15+
* @brief Enum for direction of an interposer cut. X means horizontal cut and Y means vertical cut.
16+
*
17+
*/
18+
enum class e_interposer_cut_dim {
19+
X,
20+
Y
21+
};
22+
23+
// Lookup table for converting between a character and an e_interposer_cut_dim
24+
inline const std::unordered_map<char, e_interposer_cut_dim> CHAR_INTERPOSER_DIM_MAP = {
25+
{'X', e_interposer_cut_dim::X},
26+
{'x', e_interposer_cut_dim::X},
27+
{'Y', e_interposer_cut_dim::Y},
28+
{'y', e_interposer_cut_dim::Y}};
29+
30+
/**
31+
* @brief Struct containing information of interdire wires i.e. connections between the dies on an interposer
32+
*
33+
*/
34+
struct t_interdie_wire_inf {
35+
std::string sg_name; ///< Name of the scatter-gather pattern to be used for the interdie connection
36+
std::string sg_link; ///< Name of the scatter-gather link to be used for the interdie connection
37+
int offset_start; ///< Starting point of scatter-gather instantiations
38+
int offset_end; ///< Ending point of scatter-gather instantiations
39+
int offset_increment; ///< Increment/distance between scatter-gather instantiations
40+
int num; ///< Number of scatter-gather instantiations per switchblock location
41+
};
42+
43+
/**
44+
* @brief Struct containing information of an interposer cut
45+
*
46+
*/
47+
struct t_interposer_cut_inf {
48+
e_interposer_cut_dim dim; ///< Dimension or axis of interposer cut
49+
int loc; ///< Location of the cut on the grid
50+
std::vector<t_interdie_wire_inf> interdie_wires; ///< Connectivity specification between the two sides of the cut
51+
};

libs/libarchfpga/src/physical_types.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <limits>
3737
#include <unordered_set>
3838

39+
#include "interposer_types.h"
3940
#include "vtr_ndmatrix.h"
4041
#include "vtr_bimap.h"
4142
#include "vtr_string_interning.h"
@@ -361,13 +362,14 @@ struct t_grid_loc_def {
361362
// that come from a common definition.
362363
};
363364

364-
enum GridDefType {
365+
enum class GridDefType {
365366
AUTO,
366367
FIXED
367368
};
368369

369370
struct t_layer_def {
370-
std::vector<t_grid_loc_def> loc_defs; //The list of block location definitions for this layer specification
371+
std::vector<t_grid_loc_def> loc_defs; ///< List of block location definitions for this layer specification
372+
std::vector<t_interposer_cut_inf> interposer_cuts; ///< List of interposer cuts in this layer
371373
};
372374

373375
struct t_grid_def {

libs/libarchfpga/src/read_xml_arch_file.cpp

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,19 @@
3535
* the two files are swapped on command line.
3636
*
3737
*/
38-
3938
#include <cstring>
4039
#include <map>
41-
#include <set>
4240
#include <string>
4341
#include <sstream>
4442
#include <algorithm>
43+
#include <unordered_set>
4544

4645
#include "logic_types.h"
4746
#include "physical_types.h"
4847
#include "pugixml.hpp"
4948
#include "pugixml_util.hpp"
5049

50+
#include "read_xml_arch_file_interposer.h"
5151
#include "read_xml_arch_file_vib.h"
5252
#include "vtr_assert.h"
5353
#include "vtr_log.h"
@@ -71,6 +71,8 @@
7171
#include "read_xml_arch_file_noc_tag.h"
7272
#include "read_xml_arch_file_sg.h"
7373

74+
#include "interposer_types.h"
75+
7476
using namespace std::string_literals;
7577
using pugiutil::ReqOpt;
7678

@@ -2579,7 +2581,7 @@ static t_grid_def process_grid_layout(vtr::string_internment& strings,
25792581
num_of_avail_layer = get_number_of_layers(layout_type_tag, loc_data);
25802582
bool has_layer = layout_type_tag.child("layer");
25812583

2582-
//Determine the grid specification type
2584+
// Determine the grid specification type
25832585
if (layout_type_tag.name() == std::string("auto_layout")) {
25842586
expect_only_attributes(layout_type_tag, {"aspect_ratio"}, loc_data);
25852587

@@ -2597,7 +2599,7 @@ static t_grid_def process_grid_layout(vtr::string_internment& strings,
25972599
std::string name = get_attribute(layout_type_tag, "name", loc_data).value();
25982600

25992601
if (name == "auto") {
2600-
//We name <auto_layout> as 'auto', so don't allow a user to specify it
2602+
// We name <auto_layout> as 'auto', so don't allow a user to specify it
26012603
archfpga_throw(loc_data.filename_c_str(), loc_data.line(layout_type_tag),
26022604
vtr::string_fmt("The name '%s' is reserved for auto-sized layouts; please choose another name", name.c_str()).c_str());
26032605
}
@@ -2612,27 +2614,26 @@ static t_grid_def process_grid_layout(vtr::string_internment& strings,
26122614

26132615
grid_def.layers.resize(num_of_avail_layer);
26142616
arch->layer_global_routing.resize(num_of_avail_layer);
2615-
//No layer tag is specified (only one die is specified in the arch file)
2616-
//Need to process layout_type_tag children to get block types locations in the grid
2617+
// No layer tag is specified (only one die is specified in the arch file)
2618+
// Need to process layout_type_tag children to get block types locations in the grid
26172619
if (has_layer) {
2618-
std::set<int> seen_die_numbers; //Check that die numbers in the specific layout tag are unique
2619-
//One or more than one layer tag is specified
2620-
auto layer_tag_specified = layout_type_tag.children("layer");
2621-
for (auto layer_child : layer_tag_specified) {
2622-
int die_number;
2623-
bool has_global_routing;
2624-
//More than one layer tag is specified, meaning that multi-die FPGA is specified in the arch file
2625-
//Need to process each <layer> tag children to get block types locations for each grid
2626-
die_number = get_attribute(layer_child, "die", loc_data).as_int(0);
2627-
has_global_routing = get_attribute(layer_child, "has_prog_routing", loc_data, ReqOpt::OPTIONAL).as_bool(true);
2620+
std::unordered_set<int> seen_die_numbers; //Check that die numbers in the specific layout tag are unique
2621+
for (pugi::xml_node layer_child : layout_type_tag.children("layer")) {
2622+
2623+
// More than one layer tag is specified, meaning that multi-die FPGA is specified in the arch file
2624+
// Need to process each <layer> tag children to get block types locations for each grid
2625+
int die_number = get_attribute(layer_child, "die", loc_data).as_int(0);
2626+
bool has_global_routing = get_attribute(layer_child, "has_prog_routing", loc_data, ReqOpt::OPTIONAL).as_bool(true);
26282627
arch->layer_global_routing.at(die_number) = has_global_routing;
26292628
VTR_ASSERT(die_number >= 0 && die_number < num_of_avail_layer);
2630-
auto insert_res = seen_die_numbers.insert(die_number);
2631-
VTR_ASSERT_MSG(insert_res.second, "Two different layers with a same die number may have been specified in the Architecture file");
2629+
2630+
// If the die number is not actually inserted in the seen_die_numbers set, it means that it's a duplicate
2631+
auto [_, did_insert_in_set] = seen_die_numbers.insert(die_number);
2632+
VTR_ASSERT_MSG(did_insert_in_set, "Two different layers with a same die number may have been specified in the Architecture file");
26322633
process_block_type_locs(grid_def, die_number, strings, layer_child, loc_data);
26332634
}
26342635
} else {
2635-
//if only one die is available, then global routing resources must exist in that die
2636+
// If only one die is available, then global routing resources must exist in that die
26362637
int die_number = 0;
26372638
arch->layer_global_routing.at(die_number) = true;
26382639
process_block_type_locs(grid_def, die_number, strings, layout_type_tag, loc_data);
@@ -2646,9 +2647,29 @@ static void process_block_type_locs(t_grid_def& grid_def,
26462647
pugi::xml_node layout_block_type_tag,
26472648
const pugiutil::loc_data& loc_data) {
26482649
//Process all the block location specifications
2649-
for (auto loc_spec_tag : layout_block_type_tag.children()) {
2650-
auto loc_type = loc_spec_tag.name();
2651-
auto type_name = get_attribute(loc_spec_tag, "type", loc_data).value();
2650+
for (pugi::xml_node loc_spec_tag : layout_block_type_tag.children()) {
2651+
const char* loc_type = loc_spec_tag.name();
2652+
2653+
// There are multiple attributes that are shared by every other tag that interposer
2654+
// tags do not have. For this reason we check if loc_spec_tag is an interposer tag
2655+
// and switch code paths if it is.
2656+
if (loc_type == std::string("interposer_cut")) {
2657+
if (grid_def.grid_type == GridDefType::AUTO) {
2658+
archfpga_throw(loc_data.filename_c_str(), loc_data.line(loc_spec_tag), "Interposers are not currently supported for auto sized devices.");
2659+
}
2660+
2661+
t_interposer_cut_inf interposer_cut = parse_interposer_cut_tag(loc_spec_tag, loc_data);
2662+
2663+
if ((interposer_cut.dim == e_interposer_cut_dim::X && interposer_cut.loc >= grid_def.height) || (interposer_cut.dim == e_interposer_cut_dim::Y && interposer_cut.loc >= grid_def.width)) {
2664+
archfpga_throw(loc_data.filename_c_str(), loc_data.line(loc_spec_tag), "Interposer cut dimensions are outside of device bounds");
2665+
}
2666+
2667+
grid_def.layers.at(die_number).interposer_cuts.push_back(interposer_cut);
2668+
continue;
2669+
}
2670+
2671+
// Continue parsing for non-interposer tags
2672+
const char* type_name = get_attribute(loc_spec_tag, "type", loc_data).value();
26522673
int priority = get_attribute(loc_spec_tag, "priority", loc_data).as_int();
26532674
t_metadata_dict meta = process_meta_data(strings, loc_spec_tag, loc_data);
26542675

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#include "read_xml_arch_file_interposer.h"
2+
#include <vector>
3+
#include "interposer_types.h"
4+
#include "read_xml_util.h"
5+
#include "pugixml_util.hpp"
6+
#include "arch_error.h"
7+
8+
t_interposer_cut_inf parse_interposer_cut_tag(pugi::xml_node interposer_cut_tag, const pugiutil::loc_data& loc_data) {
9+
t_interposer_cut_inf interposer;
10+
11+
pugiutil::expect_only_attributes(interposer_cut_tag, {"dim", "loc"}, loc_data);
12+
13+
std::string interposer_dim = pugiutil::get_attribute(interposer_cut_tag, "dim", loc_data).as_string();
14+
if (interposer_dim.size() != 1 || !CHAR_INTERPOSER_DIM_MAP.contains(interposer_dim[0])) {
15+
archfpga_throw(loc_data.filename_c_str(), loc_data.line(interposer_cut_tag), "Interposer tag dimension must be a single character of either X, x, Y or y.");
16+
}
17+
18+
interposer.dim = CHAR_INTERPOSER_DIM_MAP.at(interposer_dim[0]);
19+
20+
interposer.loc = pugiutil::get_attribute(interposer_cut_tag, "loc", loc_data).as_int();
21+
if (interposer.loc < 0) {
22+
archfpga_throw(loc_data.filename_c_str(), loc_data.line(interposer_cut_tag), "Interposer location must be positive.");
23+
}
24+
25+
pugiutil::expect_only_children(interposer_cut_tag, {"interdie_wire"}, loc_data);
26+
27+
for (pugi::xml_node interdie_wire_tag : interposer_cut_tag.children()) {
28+
const std::vector<std::string> interdie_wire_attributes = {{"sg", "sg_link", "offset_start", "offset_end", "offset_increment", "num"}};
29+
pugiutil::expect_only_attributes(interdie_wire_tag, interdie_wire_attributes, loc_data);
30+
31+
t_interdie_wire_inf interdie_wire;
32+
33+
interdie_wire.sg_name = pugiutil::get_attribute(interdie_wire_tag, "sg_name", loc_data).as_string();
34+
interdie_wire.sg_link = pugiutil::get_attribute(interdie_wire_tag, "sg_link", loc_data).as_string();
35+
interdie_wire.offset_start = pugiutil::get_attribute(interdie_wire_tag, "offset_start", loc_data).as_int();
36+
interdie_wire.offset_end = pugiutil::get_attribute(interdie_wire_tag, "offset_end", loc_data).as_int();
37+
interdie_wire.offset_increment = pugiutil::get_attribute(interdie_wire_tag, "offset_increment", loc_data).as_int();
38+
interdie_wire.num = pugiutil::get_attribute(interdie_wire_tag, "num", loc_data).as_int();
39+
40+
interposer.interdie_wires.push_back(interdie_wire);
41+
}
42+
43+
return interposer;
44+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#pragma once
2+
3+
/**
4+
* @file read_xml_arch_file_interposer.h
5+
* @brief This file contains functions related to parsing and processing interposer tags in the architecture file
6+
*
7+
*/
8+
9+
#include "interposer_types.h"
10+
#include "read_xml_util.h"
11+
12+
/**
13+
* @brief Parse an <interposer_cut> tag and its children
14+
*
15+
* @param interposer_cut_tag xml_node pointing to the <interposer_cut> tag
16+
* @param loc_data Points to the location in the architecture file where the parser is reading. Used for priting error messages.
17+
* @return t_interposer_cut_inf with parsed information of the <interposer_cut> tag
18+
*/
19+
t_interposer_cut_inf parse_interposer_cut_tag(pugi::xml_node interposer_cut_tag, const pugiutil::loc_data& loc_data);

0 commit comments

Comments
 (0)