Skip to content

Mdudek/fpga interchange rr graph gen improvements #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: acom/fpga-interchange-improve-arch-reading-luts
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions libs/EXTERNAL/libinterchange/interchange/DeviceResources.capnp
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,8 @@ annotation wireRef(*) :WireRef;
using WireIdx = UInt32;

struct WireTypeRef {
type @0 :Ref.ReferenceType = parent;
type @0 :Ref.ReferenceType = rootValue;
field @1 :Text = "wireTypes";
depth @2 :Int32 = 1;
}
annotation wireTypeRef(*) :WireTypeRef;
using WireTypeIdx = UInt32;
Expand All @@ -81,19 +80,16 @@ using TileTypeSiteTypeIdx = UInt32;
using TileTypeSubTileIdx = UInt16;

struct PIPTimingRef {
type @0 :Ref.ReferenceType = parent;
field @1 :Text = "pipTimingList";
depth @2 :Int32 = 1;
type @0 :Ref.ReferenceType = rootValue;
field @1 :Text = "pipTimings";

}
annotation pipTimingRef(*) :PIPTimingRef;
using PipTimingIdx = UInt32;

struct NodeTimingRef {
type @0 :Ref.ReferenceType = parent;
field @1 :Text = "nodeTimingList";
depth @2 :Int32 = 1;

type @0 :Ref.ReferenceType = rootValue;
field @1 :Text = "nodeTimings";
}
annotation nodeTimingRef(*) :NodeTimingRef;
using NodeTimingIdx = UInt32;
Expand Down Expand Up @@ -632,7 +628,7 @@ struct Device {
}

struct PinDelay {
pin @0 : BELPinIdx $belPinRef();
pin @0 : BELPinIdx;
union {
noClock @1 : Void;
clockEdge @2 : ClockEdge;
Expand Down
78 changes: 78 additions & 0 deletions libs/libarchfpga/src/fpga_interchange_arch_utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include "fpga_interchange_arch_utils.h"

/****************** Utility functions ******************/

/**
* @brief The FPGA interchange timing model includes three different corners (min, typ and max) for each of the two
* speed_models (slow and fast).
*
* Timing data can be found on PIPs, nodes, site pins and bel pins.
* This function retrieves the timing value based on the wanted speed model and the wanted corner.
*
* Corner model is considered valid if at least one configuration is set.
* In that case this value shall be returned.
*
* More information on the FPGA Interchange timing model can be found here:
* - https://github.com/chipsalliance/fpga-interchange-schema/blob/main/interchange/DeviceResources.capnp
*/

float get_corner_value(DeviceResources::Device::CornerModel::Reader model, const char* speed_model, const char* value) {
bool slow_model = std::string(speed_model) == std::string("slow");
bool fast_model = std::string(speed_model) == std::string("fast");

bool min_corner = std::string(value) == std::string("min");
bool typ_corner = std::string(value) == std::string("typ");
bool max_corner = std::string(value) == std::string("max");

if (!slow_model && !fast_model) {
archfpga_throw("", __LINE__, "Wrong speed model `%s`. Expected `slow` or `fast`\n", speed_model);
}

if (!min_corner && !typ_corner && !max_corner) {
archfpga_throw("", __LINE__, "Wrong corner model `%s`. Expected `min`, `typ` or `max`\n", value);
}

bool has_fast = model.getFast().hasFast();
bool has_slow = model.getSlow().hasSlow();

if ((slow_model || (fast_model && !has_fast)) && has_slow) {
auto half = model.getSlow().getSlow();
if (min_corner && half.getMin().isMin()) {
return half.getMin().getMin();
} else if (typ_corner && half.getTyp().isTyp()) {
return half.getTyp().getTyp();
} else if (max_corner && half.getMax().isMax()) {
return half.getMax().getMax();
} else {
if (half.getMin().isMin()) {
return half.getMin().getMin();
} else if (half.getTyp().isTyp()) {
return half.getTyp().getTyp();
} else if (half.getMax().isMax()) {
return half.getMax().getMax();
} else {
archfpga_throw("", __LINE__, "Invalid speed model %s. No value found!\n", speed_model);
}
}
} else if ((fast_model || slow_model) && has_fast) {
auto half = model.getFast().getFast();
if (min_corner && half.getMin().isMin()) {
return half.getMin().getMin();
} else if (typ_corner && half.getTyp().isTyp()) {
return half.getTyp().getTyp();
} else if (max_corner && half.getMax().isMax()) {
return half.getMax().getMax();
} else {
if (half.getMin().isMin()) {
return half.getMin().getMin();
} else if (half.getTyp().isTyp()) {
return half.getTyp().getTyp();
} else if (half.getMax().isMax()) {
return half.getMax().getMax();
} else {
archfpga_throw("", __LINE__, "Invalid speed model %s. No value found!\n", speed_model);
}
}
}
return 0.;
}
41 changes: 41 additions & 0 deletions libs/libarchfpga/src/fpga_interchange_arch_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#ifndef FPGAINTERCHANGE_ARCH_UTILS_FILE_H
#define FPGAINTERCHANGE_ARCH_UTILS_FILE_H

#include "arch_types.h"
#include "arch_error.h"
#include "vtr_error.h"

#include "DeviceResources.capnp.h"
#include "LogicalNetlist.capnp.h"
#include "capnp/serialize.h"
#include "capnp/serialize-packed.h"
#include <fcntl.h>
#include <unistd.h>

#ifdef __cplusplus
extern "C" {
#endif

/****************** Utility functions ******************/

/**
* @brief The FPGA interchange timing model includes three different corners (min, typ and max) for each of the two
* speed_models (slow and fast).
*
* Timing data can be found on PIPs, nodes, site pins and bel pins.
* This function retrieves the timing value based on the wanted speed model and the wanted corner.
*
* Corner model is considered valid if at least one configuration is set.
* In that case this value shall be returned.
*
* More information on the FPGA Interchange timing model can be found here:
* - https://github.com/chipsalliance/fpga-interchange-schema/blob/main/interchange/DeviceResources.capnp
*/

float get_corner_value(DeviceResources::Device::CornerModel::Reader model, const char* speed_model, const char* value);

#ifdef __cplusplus
}
#endif

#endif
135 changes: 29 additions & 106 deletions libs/libarchfpga/src/read_fpga_interchange_arch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "arch_types.h"

#include "read_fpga_interchange_arch.h"
#include "fpga_interchange_arch_utils.h"

/*
* FPGA Interchange Device frontend
Expand Down Expand Up @@ -78,82 +79,6 @@ struct t_ic_data {

/****************** Utility functions ******************/

/**
* @brief The FPGA interchange timing model includes three different corners (min, typ and max) for each of the two
* speed_models (slow and fast).
*
* Timing data can be found on PIPs, nodes, site pins and bel pins.
* This function retrieves the timing value based on the wanted speed model and the wanted corner.
*
* More information on the FPGA Interchange timing model can be found here:
* - https://github.com/chipsalliance/fpga-interchange-schema/blob/main/interchange/DeviceResources.capnp
*/
static float get_corner_value(Device::CornerModel::Reader model, const char* speed_model, const char* value) {
bool slow_model = std::string(speed_model) == std::string("slow");
bool fast_model = std::string(speed_model) == std::string("fast");

bool min_corner = std::string(value) == std::string("min");
bool typ_corner = std::string(value) == std::string("typ");
bool max_corner = std::string(value) == std::string("max");

if (!slow_model && !fast_model) {
archfpga_throw("", __LINE__,
"Wrong speed model `%s`. Expected `slow` or `fast`\n", speed_model);
}

if (!min_corner && !typ_corner && !max_corner) {
archfpga_throw("", __LINE__,
"Wrong corner model `%s`. Expected `min`, `typ` or `max`\n", value);
}

bool has_fast = model.getFast().hasFast();
bool has_slow = model.getSlow().hasSlow();

if (slow_model && has_slow) {
auto half = model.getSlow().getSlow();
if (min_corner && half.getMin().isMin()) {
return half.getMin().getMin();
} else if (typ_corner && half.getTyp().isTyp()) {
return half.getTyp().getTyp();
} else if (max_corner && half.getMax().isMax()) {
return half.getMax().getMax();
} else {
if (half.getMin().isMin()) {
return half.getMin().getMin();
} else if (half.getTyp().isTyp()) {
return half.getTyp().getTyp();
} else if (half.getMax().isMax()) {
return half.getMax().getMax();
} else {
archfpga_throw("", __LINE__,
"Invalid speed model %s. No value found!\n", speed_model);
}
}
} else if (fast_model && has_fast) {
auto half = model.getFast().getFast();
if (min_corner && half.getMin().isMin()) {
return half.getMin().getMin();
} else if (typ_corner && half.getTyp().isTyp()) {
return half.getTyp().getTyp();
} else if (max_corner && half.getMax().isMax()) {
return half.getMax().getMax();
} else {
if (half.getMin().isMin()) {
return half.getMin().getMin();
} else if (half.getTyp().isTyp()) {
return half.getTyp().getTyp();
} else if (half.getMax().isMax()) {
return half.getMax().getMax();
} else {
archfpga_throw("", __LINE__,
"Invalid speed model %s. No value found!\n", speed_model);
}
}
}

return 0.;
}

/** @brief Returns the port corresponding to the given model in the architecture */
static t_model_ports* get_model_port(t_arch* arch, std::string model, std::string port, bool fail = true) {
for (t_model* m : {arch->models, arch->model_library}) {
Expand Down Expand Up @@ -328,7 +253,6 @@ struct ArchReader {

// Bel Cell mappings
std::unordered_map<uint32_t, std::set<t_bel_cell_mapping>> bel_cell_mappings_;
std::unordered_map<std::string, int> segment_name_to_segment_idx;

// Utils

Expand Down Expand Up @@ -2226,6 +2150,29 @@ struct ArchReader {
}
}

void add_segment_with_default_values(t_segment_inf& seg, std::string name) {
// Use default values as we will populate rr_graph with correct values
// This segments are just declaration of future use
seg.name = name;
seg.length = 1;
seg.frequency = 1;
seg.Rmetal = 1e-12;
seg.Cmetal = 1e-12;
seg.parallel_axis = BOTH_AXIS;

// TODO: Only bi-directional segments are created, but it the interchange format
// has directionality information on PIPs, which may be used to infer the
// segments' directonality.
seg.directionality = BI_DIRECTIONAL;
seg.arch_wire_switch = 1;
seg.arch_opin_switch = 1;
seg.cb.resize(1);
seg.cb[0] = true;
seg.sb.resize(2);
seg.sb[0] = true;
seg.sb[1] = true;
}

void process_segments() {
// Segment names will be taken from wires connected to pips
// They are good representation for nodes
Expand All @@ -2238,38 +2185,14 @@ struct ArchReader {
}
}

// FIXME: have only one segment type for the time being, so that
// the RR graph generation is correct.
// This can be removed once the RR graph reader from the interchange
// device is ready and functional.
size_t num_seg = 1; //wire_names.size();
int num_seg = wire_names.size() + 1;

arch_->Segments.resize(num_seg);
size_t index = 0;

size_t index = 1;
add_segment_with_default_values(arch_->Segments[0], std::string("__generic__"));
for (auto i : wire_names) {
if (index >= num_seg) break;

// Use default values as we will populate rr_graph with correct values
// This segments are just declaration of future use
arch_->Segments[index].name = str(i);
arch_->Segments[index].length = 1;
arch_->Segments[index].frequency = 1;
arch_->Segments[index].Rmetal = 1e-12;
arch_->Segments[index].Cmetal = 1e-12;
arch_->Segments[index].parallel_axis = BOTH_AXIS;

// TODO: Only bi-directional segments are created, but it the interchange format
// has directionality information on PIPs, which may be used to infer the
// segments' directonality.
arch_->Segments[index].directionality = BI_DIRECTIONAL;
arch_->Segments[index].arch_wire_switch = 1;
arch_->Segments[index].arch_opin_switch = 1;
arch_->Segments[index].cb.resize(1);
arch_->Segments[index].cb[0] = true;
arch_->Segments[index].sb.resize(2);
arch_->Segments[index].sb[0] = true;
arch_->Segments[index].sb[1] = true;
segment_name_to_segment_idx[str(i)] = index;
add_segment_with_default_values(arch_->Segments[index], str(i));
++index;
}
}
Expand Down
1 change: 1 addition & 0 deletions vpr/src/base/SetupVPR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ static void SetupRouterOpts(const t_options& Options, t_router_opts* RouterOpts)

RouterOpts->max_logged_overused_rr_nodes = Options.max_logged_overused_rr_nodes;
RouterOpts->generate_rr_node_overuse_report = Options.generate_rr_node_overuse_report;
RouterOpts->FPGAInterchange = (Options.arch_format == e_arch_format::FPGAInterchange);
}

static void SetupAnnealSched(const t_options& Options,
Expand Down
3 changes: 3 additions & 0 deletions vpr/src/base/vpr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1278,6 +1278,9 @@ struct t_router_opts {
e_rr_node_reorder_algorithm reorder_rr_graph_nodes_algorithm = DONT_REORDER;
int reorder_rr_graph_nodes_threshold = 0;
int reorder_rr_graph_nodes_seed = 1;

// Options related to FPGA Interchange
bool FPGAInterchange;
};

struct t_analysis_opts {
Expand Down
16 changes: 14 additions & 2 deletions vpr/src/route/rr_graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "build_switchblocks.h"
#include "rr_graph_writer.h"
#include "rr_graph_reader.h"
#include "rr_graph_fpga_interchange.h"
#include "router_lookahead_map.h"
#include "rr_graph_clock.h"
#include "edge_groups.h"
Expand Down Expand Up @@ -314,8 +315,8 @@ void create_rr_graph(const t_graph_type graph_type,
int* Warnings) {
const auto& device_ctx = g_vpr_ctx.device();

if (!det_routing_arch->read_rr_graph_filename.empty()) {
if (device_ctx.read_rr_graph_filename != det_routing_arch->read_rr_graph_filename) {
if (!det_routing_arch->read_rr_graph_filename.empty() || router_opts.FPGAInterchange) {
if (device_ctx.read_rr_graph_filename != det_routing_arch->read_rr_graph_filename && !router_opts.FPGAInterchange) {
free_rr_graph();

load_rr_file(graph_type,
Expand All @@ -328,6 +329,17 @@ void create_rr_graph(const t_graph_type graph_type,
router_opts.do_check_rr_graph);

reorder_rr_graph_nodes(router_opts);
} else if (!device_ctx.read_rr_graph_filename.size() && router_opts.FPGAInterchange) {
free_rr_graph();

VTR_LOG("Custom RR_graph generator\n");
build_rr_graph_fpga_interchange(graph_type,
grid,
segment_inf,
router_opts.base_cost_type,
&det_routing_arch->wire_to_rr_ipin_switch,
router_opts.do_check_rr_graph);
reorder_rr_graph_nodes(router_opts);
}
} else {
if (channel_widths_unchanged(device_ctx.chan_width, nodes_per_chan) && !device_ctx.rr_nodes.empty()) {
Expand Down
Loading