blob: 40a81bb41b58777f2d18daa71d2cc246a9799a54 [file] [log] [blame]
#ifndef VPR_CONTEXT_H
#define VPR_CONTEXT_H
#include <unordered_map>
#include <memory>
#include <vector>
#include "vpr_types.h"
#include "vtr_ndmatrix.h"
#include "vtr_vector.h"
#include "atom_netlist.h"
#include "clustered_netlist.h"
#include "rr_node.h"
#include "tatum/TimingGraph.hpp"
#include "tatum/TimingConstraints.hpp"
#include "power.h"
#include "power_components.h"
#include "device_grid.h"
#include "clock_network_builders.h"
#include "clock_connection_builders.h"
#include "route_traceback.h"
#include "router_lookahead.h"
#include "place_macro.h"
#include "compressed_grid.h"
//A Context is collection of state relating to a particular part of VPR
//
//This is a base class who's only purpose is to disable copying of contexts.
//This ensures that attempting to use a context by value (instead of by reference)
//will result in a compilation error.
//
//No data or member functions should be defined in this class!
struct Context {
//Contexts are non-copyable
Context() = default;
Context(Context&) = delete;
Context& operator=(Context&) = delete;
virtual ~Context() = default;
};
//State relating to the atom-level netlist
//
//This should contain only data structures related to user specified netlist
//being implemented by VPR onto the target device.
struct AtomContext : public Context {
/********************************************************************
* Atom Netlist
********************************************************************/
/* Atom netlist */
AtomNetlist nlist;
/* Mappings to/from the Atom Netlist to physically described .blif models*/
AtomLookup lookup;
};
//State relating to timing
//
//This should contain only data structures related to timing analysis,
//or related timing analysis algorithmic state.
struct TimingContext : public Context {
/********************************************************************
* Timing
********************************************************************/
//The current timing graph.
//This represents the timing dependencies between pins of the atom netlist
std::shared_ptr<tatum::TimingGraph> graph;
//The current timing constraints, as loaded from an SDC file (or set by default).
//These specify how timing analysis is performed (e.g. target clock periods)
std::shared_ptr<tatum::TimingConstraints> constraints;
struct timing_analysis_profile_info {
double timing_analysis_wallclock_time() const {
return sta_wallclock_time + slack_wallclock_time;
}
double old_timing_analysis_wallclock_time() const {
return old_sta_wallclock_time + old_delay_annotation_wallclock_time;
}
size_t num_full_updates() const {
return num_full_setup_updates + num_full_hold_updates + num_full_setup_hold_updates;
}
double sta_wallclock_time = 0.;
double slack_wallclock_time = 0.;
size_t num_full_setup_updates = 0;
size_t num_full_hold_updates = 0;
size_t num_full_setup_hold_updates = 0;
double old_sta_wallclock_time = 0.;
double old_delay_annotation_wallclock_time = 0.;
size_t num_old_sta_full_updates = 0;
};
timing_analysis_profile_info stats;
};
namespace std {
template<>
struct hash<std::tuple<int, int, short>> {
std::size_t operator()(const std::tuple<int, int, short>& ok) const noexcept {
std::size_t seed = std::hash<int>{}(std::get<0>(ok));
vtr::hash_combine(seed, std::get<1>(ok));
vtr::hash_combine(seed, std::get<2>(ok));
return seed;
}
};
} // namespace std
//State relating the device
//
//This should contain only data structures describing the targeted device.
struct DeviceContext : public Context {
/*********************************************************************
* Physical FPGA architecture
*********************************************************************/
/* x and y dimensions of the FPGA itself */
DeviceGrid grid; /* FPGA complex block grid [0 .. grid.width()-1][0 .. grid.height()-1] */
/* Special pointers to identify special blocks on an FPGA: I/Os, unused, and default */
std::set<t_physical_tile_type_ptr> input_types;
std::set<t_physical_tile_type_ptr> output_types;
t_physical_tile_type_ptr EMPTY_TYPE;
/* block_types are blocks that can be moved by the placer
* such as: I/Os, CLBs, memories, multipliers, etc
* Different types of physical block are contained in type descriptors
*/
std::vector<t_physical_tile_type> physical_tile_types;
std::vector<t_logical_block_type> logical_block_types;
/*******************************************************************
* Routing related
********************************************************************/
/* chan_width is for x|y-directed channels; i.e. between rows */
t_chan_width chan_width;
/* Structures to define the routing architecture of the FPGA. */
std::vector<t_rr_node> rr_nodes; /* autogenerated in build_rr_graph */
std::vector<t_rr_indexed_data> rr_indexed_data; /* [0 .. num_rr_indexed_data-1] */
//Fly-weighted Resistance/Capacitance data for RR Nodes
std::vector<t_rr_rc_data> rr_rc_data;
//Sets of non-configurably connected nodes
std::vector<std::vector<int>> rr_non_config_node_sets;
//Reverse look-up from RR node to non-configurably connected node set (index into rr_nonconf_node_sets)
std::unordered_map<int, int> rr_node_to_non_config_node_set;
//The indicies of rr nodes of a given type at a specific x,y grid location
t_rr_node_indices rr_node_indices; //[0..NUM_RR_TYPES-1][0..grid.width()-1][0..grid.width()-1][0..size-1]
std::vector<t_rr_switch_inf> rr_switch_inf; /* autogenerated in build_rr_graph based on switch fan-in. [0..(num_rr_switches-1)] */
int num_arch_switches;
t_arch_switch_inf* arch_switch_inf; /* [0..(num_arch_switches-1)] */
// Clock Networks
std::vector<std::unique_ptr<ClockNetwork>> clock_networks;
std::vector<std::unique_ptr<ClockConnection>> clock_connections;
/** Attributes for each rr_node.
* key: rr_node index
* value: map of <attribute_name, attribute_value>
*/
std::unordered_map<int, t_metadata_dict> rr_node_metadata;
/* Attributes for each rr_edge *
* key: <source rr_node_index, sink rr_node_index, iswitch> *
* iswitch: Index of the switch type used to go from this rr_node to *
* the next one in the routing. OPEN if there is no next node *
* (i.e. this node is the last one (a SINK) in a branch of the *
* net's routing). *
* value: map of <attribute_name, attribute_value> */
std::unordered_map<std::tuple<int, int, short>,
t_metadata_dict>
rr_edge_metadata;
/*
* switch_fanin_remap is only used for printing out switch fanin stats (the -switch_stats option)
* array index: [0..(num_arch_switches-1)];
* map key: num of all possible fanin of that type of switch on chip
* map value: remapped switch index (index in rr_switch_inf)
*/
std::vector<std::map<int, int>> switch_fanin_remap;
/*******************************************************************
* Architecture
********************************************************************/
const t_arch* arch;
/*******************************************************************
* Clock Network
********************************************************************/
t_clock_arch* clock_arch;
// Name of rrgraph file read (if any).
// Used to determine when reading rrgraph if file is already loaded.
std::string read_rr_graph_filename;
};
//State relating to power analysis
//
//This should contain only data structures related to power analysis,
//or related power analysis algorithmic state.
struct PowerContext : public Context {
/*******************************************************************
* Power
********************************************************************/
t_solution_inf solution_inf;
t_power_output* output;
t_power_commonly_used* commonly_used;
t_power_tech* tech;
t_power_arch* arch;
vtr::vector<ClusterNetId, t_net_power> clb_net_power;
/* Atom net power info */
std::unordered_map<AtomNetId, t_net_power> atom_net_power;
t_power_components by_component;
};
//State relating to clustering
//
//This should contain only data structures that describe the current
//clustering/packing, or related clusterer/packer algorithmic state.
struct ClusteringContext : public Context {
/********************************************************************
* CLB Netlist
********************************************************************/
/* New netlist class derived from Netlist */
ClusteredNetlist clb_nlist;
};
//State relating to placement
//
//This should contain only data structures that describe the current placement,
//or related placer algorithm state.
struct PlacementContext : public Context {
//Clustered block placement locations
vtr::vector_map<ClusterBlockId, t_block_loc> block_locs;
//Clustered block associated with each grid location (i.e. inverse of block_locs)
vtr::Matrix<t_grid_blocks> grid_blocks; //[0..device_ctx.grid.width()-1][0..device_ctx.grid.width()-1]
// The pl_macros array stores all the placement macros (usually carry chains).
std::vector<t_pl_macro> pl_macros;
//Compressed grid space for each block type
//Used to efficiently find logically 'adjacent' blocks of the same block type even though
//the may be physically far apart
t_compressed_block_grids compressed_block_grids;
//SHA256 digest of the .place file (used for unique identification and consistency checking)
std::string placement_id;
};
//State relating to routing
//
//This should contain only data structures that describe the current routing implementation,
//or related router algorithmic state.
struct RoutingContext : public Context {
/* [0..num_nets-1] of linked list start pointers. Defines the routing. */
vtr::vector<ClusterNetId, t_traceback> trace;
vtr::vector<ClusterNetId, std::unordered_set<int>> trace_nodes;
vtr::vector<ClusterNetId, std::vector<int>> net_rr_terminals; /* [0..num_nets-1][0..num_pins-1] */
vtr::vector<ClusterBlockId, std::vector<int>> rr_blk_source; /* [0..num_blocks-1][0..num_class-1] */
std::vector<t_rr_node_route_inf> rr_node_route_inf; /* [0..device_ctx.num_rr_nodes-1] */
//Information about current routing status of each net
vtr::vector<ClusterNetId, t_net_routing_status> net_status; //[0..cluster_ctx.clb_nlist.nets().size()-1]
//Limits area within which each net must be routed.
vtr::vector<ClusterNetId, t_bb> route_bb; /* [0..cluster_ctx.clb_nlist.nets().size()-1]*/
t_clb_opins_used clb_opins_used_locally; //[0..cluster_ctx.clb_nlist.blocks().size()-1][0..num_class-1]
//SHA256 digest of the .route file (used for unique identification and consistency checking)
std::string routing_id;
// Cache of router lookahead object.
//
// Cache key: (lookahead type, read lookahead (if any), segment definitions).
vtr::Cache<std::tuple<e_router_lookahead, std::string, std::vector<t_segment_inf>>,
RouterLookahead>
cached_router_lookahead_;
};
//This object encapsulates VPR's state. There is typically a single instance which is
//accessed via the global variable g_vpr_ctx (see globals.h/.cpp).
//
//It is divided up into separate sub-contexts of logically related data structures.
//
//Each sub-context can be accessed via member functions which return a reference to the sub-context:
// * The default the member function (e.g. device()) return an const (immutable) reference providing
// read-only access to the context. This should be the preferred form, as the compiler will detect
// unintentional state changes.
// * The 'mutable' member function (e.g. mutable_device()) will return a non-const (mutable) reference
// allowing modification of the context. This should only be used on an as-needed basis.
//
//Typical usage in VPR would be to call the appropriate accessor to get a reference to the context of
//interest, and then operate on it.
//
//
//For example if we were performing an action which required access to the current placement, we would do:
//
// void my_analysis_algorithm() {
// //Get read-only access to the placement
// auto& place_ctx = g_vpr_ctx.placement();
//
// //Do something that depends on (but does not change)
// //the current placement...
//
// }
//
//If we needed to modify the placement (e.g. we were implementing another placement algorithm) we would do:
//
// void my_placement_algorithm() {
// //Get read-write access to the placement
// auto& place_ctx = g_vpr_ctx.mutable_placement();
//
// //Do something that modifies the placement
// //...
// }
//
//Note that the returned contexts are not copyable, so they must be taken by reference.
class VprContext : public Context {
public:
const AtomContext& atom() const { return atom_; }
AtomContext& mutable_atom() { return atom_; }
const DeviceContext& device() const { return device_; }
DeviceContext& mutable_device() { return device_; }
const TimingContext& timing() const { return timing_; }
TimingContext& mutable_timing() { return timing_; }
const PowerContext& power() const { return power_; }
PowerContext& mutable_power() { return power_; }
const ClusteringContext& clustering() const { return clustering_; }
ClusteringContext& mutable_clustering() { return clustering_; }
const PlacementContext& placement() const { return placement_; }
PlacementContext& mutable_placement() { return placement_; }
const RoutingContext& routing() const { return routing_; }
RoutingContext& mutable_routing() { return routing_; }
private:
DeviceContext device_;
AtomContext atom_;
TimingContext timing_;
PowerContext power_;
ClusteringContext clustering_;
PlacementContext placement_;
RoutingContext routing_;
};
#endif