diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp new file mode 100644 index 000000000..2e8c80708 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp @@ -0,0 +1,268 @@ +/********************************************************** + * MIT License + * + * Copyright (c) 2018 LNIS - The University of Utah + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ***********************************************************************/ + +/************************************************************************ + * Filename: chan_node_details.cpp + * Created by: Xifan Tang + * Change history: + * +-------------------------------------+ + * | Date | Author | Notes + * +-------------------------------------+ + * | 2019/06/14 | Xifan Tang | Created + * +-------------------------------------+ + ***********************************************************************/ +/************************************************************************ + * This file contains member functions for class ChanNodeDetails + ***********************************************************************/ +#include +#include +#include "chan_node_details.h" + +/************************************************************************ + * Constructors + ***********************************************************************/ +ChanNodeDetails::ChanNodeDetails(const ChanNodeDetails& src) { + /* duplicate */ + size_t chan_width = src.get_chan_width(); + this->reserve(chan_width); + for (size_t itrack = 0; itrack < chan_width; ++itrack) { + track_node_ids_.push_back(src.get_track_node_id(itrack)); + track_direction_.push_back(src.get_track_direction(itrack)); + seg_length_.push_back(src.get_track_segment_length(itrack)); + track_start_.push_back(src.is_track_start(itrack)); + track_end_.push_back(src.is_track_end(itrack)); + } +} + +ChanNodeDetails::ChanNodeDetails() { + this->clear(); +} + +/************************************************************************ + * Accessors + ***********************************************************************/ +size_t ChanNodeDetails::get_chan_width() const { + assert(validate_chan_width()); + return track_node_ids_.size(); +} + +size_t ChanNodeDetails::get_track_node_id(size_t track_id) const { + assert(validate_track_id(track_id)); + return track_node_ids_[track_id]; +} + +e_direction ChanNodeDetails::get_track_direction(size_t track_id) const { + assert(validate_track_id(track_id)); + return track_direction_[track_id]; +} + +size_t ChanNodeDetails::get_track_segment_length(size_t track_id) const { + assert(validate_track_id(track_id)); + return seg_length_[track_id]; +} + +bool ChanNodeDetails::is_track_start(size_t track_id) const { + assert(validate_track_id(track_id)); + return track_start_[track_id]; +} + +bool ChanNodeDetails::is_track_end(size_t track_id) const { + assert(validate_track_id(track_id)); + return track_end_[track_id]; +} + +/* Track_id is the starting point of group (whose is_start should be true) + * This function will try to find the track_ids with the same directionality as track_id and seg_length + * A group size is the number of such nodes between the starting points (include the 1st starting point) + */ +std::vector ChanNodeDetails::get_seg_group(size_t track_id) const { + assert(validate_chan_width()); + assert(validate_track_id(track_id)); + assert(is_track_start(track_id)); + + std::vector group; + /* Make sure a clean start */ + group.clear(); + + /* track_id is the first element */ + group.push_back(track_id); + + for (size_t itrack = track_id; itrack < get_chan_width(); ++itrack) { + if ( (get_track_direction(itrack) == get_track_direction(track_id) ) + && (get_track_segment_length(itrack) == get_track_segment_length(track_id)) ) { + if ( (false == is_track_start(itrack)) + || ( (true == is_track_start(itrack)) && (itrack == track_id)) ) { + group.push_back(itrack); + continue; + } + /* Stop if this another starting point */ + if (true == is_track_start(itrack)) { + break; + } + } + } + return group; +} + +/* Get a list of track_ids with the given list of track indices */ +std::vector ChanNodeDetails::get_seg_group_node_id(std::vector seg_group) const { + std::vector group; + /* Make sure a clean start */ + group.clear(); + + for (size_t id = 0; id < seg_group.size(); ++id) { + assert(validate_track_id(seg_group[id])); + group.push_back(get_track_node_id(seg_group[id])); + } + + return group; +} + +/* Get the number of tracks that starts in this routing channel */ +size_t ChanNodeDetails::get_num_starting_tracks() const { + size_t counter = 0; + for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) { + if (false == is_track_start(itrack)) { + continue; + } + counter++; + } + return counter; +} + +/* Get the number of tracks that ends in this routing channel */ +size_t ChanNodeDetails::get_num_ending_tracks() const { + size_t counter = 0; + for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) { + if (false == is_track_end(itrack)) { + continue; + } + counter++; + } + return counter; +} + +/************************************************************************ + * Mutators + ***********************************************************************/ +/* Reserve the capacitcy of vectors */ +void ChanNodeDetails::reserve(size_t chan_width) { + track_node_ids_.reserve(chan_width); + track_direction_.reserve(chan_width); + seg_length_.reserve(chan_width); + track_start_.reserve(chan_width); + track_end_.reserve(chan_width); +} + +/* Add a track to the channel */ +void ChanNodeDetails::add_track(size_t track_node_id, e_direction track_direction, size_t seg_length, size_t is_start, size_t is_end) { + track_node_ids_.push_back(track_node_id); + track_direction_.push_back(track_direction); + seg_length_.push_back(seg_length); + track_start_.push_back(is_start); + track_end_.push_back(is_end); +} + +/* Set tracks with a given direction to start */ +void ChanNodeDetails::set_tracks_start(e_direction track_direction) { + for (size_t inode = 0; inode < get_chan_width(); ++inode) { + /* Bypass non-match tracks */ + if (track_direction != get_track_direction(inode)) { + } + track_start_[inode] = true; + } +} + +/* Set tracks with a given direction to end */ +void ChanNodeDetails::set_tracks_end(e_direction track_direction) { + for (size_t inode = 0; inode < get_chan_width(); ++inode) { + /* Bypass non-match tracks */ + if (track_direction != get_track_direction(inode)) { + } + track_end_[inode] = true; + } +} + +/* rotate the track_node_id by an offset */ +void ChanNodeDetails::rotate_track_node_id(size_t offset, bool counter_rotate) { + /* Rotate the node_ids by groups + * A group begins from a track_start and ends before another track_start + */ + assert(validate_chan_width()); + for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) { + /* Bypass non-start segment */ + if (false == is_track_start(itrack) ) { + continue; + } + /* Find the group nodes */ + std::vector track_group = get_seg_group(itrack); + /* Build a vector of the node ids of the tracks */ + std::vector track_group_node_id = get_seg_group_node_id(track_group); + /* Rotate or Counter rotate */ + if (true == counter_rotate) { + std::rotate(track_group_node_id.begin(), track_group_node_id.end() - offset, track_group_node_id.end()); + } else { + std::rotate(track_group_node_id.begin(), track_group_node_id.begin() + offset, track_group_node_id.end()); + } + /* Update the node_ids */ + for (size_t inode = 0; inode < track_group.size(); ++inode) { + track_node_ids_[track_group[inode]] = track_group_node_id[inode]; + } + } + return; +} + +void ChanNodeDetails::clear() { + track_node_ids_.clear(); + track_direction_.clear(); + seg_length_.clear(); + track_start_.clear(); + track_end_.clear(); +} + +/************************************************************************ + * Validators + ***********************************************************************/ +bool ChanNodeDetails::validate_chan_width() const { + size_t chan_width = track_node_ids_.size(); + if ( (chan_width == track_direction_.size()) + &&(chan_width == seg_length_.size()) + &&(chan_width == track_start_.size()) + &&(chan_width == track_end_.size()) ) { + return true; + } + return false; +} + +bool ChanNodeDetails::validate_track_id(size_t track_id) const { + if ( (track_id < track_node_ids_.size()) + && (track_id < track_direction_.size()) + && (track_id < seg_length_.size()) + && (track_id < track_start_.size()) + && (track_id < track_end_.size()) ) { + return true; + } + return false; +} + diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h new file mode 100644 index 000000000..8b45ba25f --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h @@ -0,0 +1,105 @@ +/********************************************************** + * MIT License + * + * Copyright (c) 2018 LNIS - The University of Utah + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ***********************************************************************/ + +/************************************************************************ + * Filename: chan_node_details.h + * Created by: Xifan Tang + * Change history: + * +-------------------------------------+ + * | Date | Author | Notes + * +-------------------------------------+ + * | 2019/06/11 | Xifan Tang | Created + * +-------------------------------------+ + ***********************************************************************/ +/************************************************************************ + * This file contains a class to model the details of routing node + * in a channel: + * 1. segment information: length, frequency etc. + * 2. starting point of segment + * 3. ending point of segment + * 4. potentail track_id(ptc_num) of each segment + ***********************************************************************/ + +/* IMPORTANT: + * The following preprocessing flags are added to + * avoid compilation error when this headers are included in more than 1 times + */ +#ifndef CHAN_NODE_DETAILS_H +#define CHAN_NODE_DETAILS_H + +/* + * Notes in include header files in a head file + * Only include the neccessary header files + * that is required by the data types in the function/class declarations! + */ +/* Header files should be included in a sequence */ +/* Standard header files required go first */ +#include +#include "vpr_types.h" + +/************************************************************************ + * ChanNodeDetails records segment length, directionality and starting of routing tracks + * +---------------------------------+ + * | Index | Direction | Start Point | + * +---------------------------------+ + * | 0 | --------> | Yes | + * +---------------------------------+ + ***********************************************************************/ + + +class ChanNodeDetails { + public : /* Constructor */ + ChanNodeDetails(const ChanNodeDetails&); /* Duplication */ + ChanNodeDetails(); /* Initilization */ + public: /* Accessors */ + size_t get_chan_width() const; + size_t get_track_node_id(size_t track_id) const; + e_direction get_track_direction(size_t track_id) const; + size_t get_track_segment_length(size_t track_id) const; + bool is_track_start(size_t track_id) const; + bool is_track_end(size_t track_id) const; + std::vector get_seg_group(size_t track_id) const; + std::vector get_seg_group_node_id(std::vector seg_group) const; + size_t get_num_starting_tracks() const; + size_t get_num_ending_tracks() const; + public: /* Mutators */ + void reserve(size_t chan_width); /* Reserve the capacitcy of vectors */ + void add_track(size_t track_node_id, e_direction track_direction, size_t seg_length, size_t is_start, size_t is_end); + void set_tracks_start(e_direction track_direction); + void set_tracks_end(e_direction track_direction); + void rotate_track_node_id(size_t offset, bool counter_rotate); /* rotate the track_node_id by an offset */ + void clear(); + private: /* validators */ + bool validate_chan_width() const; + bool validate_track_id(size_t track_id) const; + private: /* Internal data */ + std::vector track_node_ids_; /* indices of each track */ + std::vector track_direction_; /* direction of each track */ + std::vector seg_length_; /* Length of each segment */ + std::vector track_start_; /* flag to identify if this is the starting point of the track */ + std::vector track_end_; /* flag to identify if this is the ending point of the track */ +}; + +#endif + diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index 647e8d1f9..d5cbd8bfc 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -55,19 +55,386 @@ #include "fpga_x2p_types.h" #include "rr_graph_tileable_builder.h" +#include "chan_node_details.h" +#include "device_coordinator.h" /************************************************************************ * Local function in the file ***********************************************************************/ +/************************************************************************ + * Generate the number of tracks for each types of routing segments + * w.r.t. the frequency of each of segments and channel width + * Note that if we dertermine the number of tracks per type using + * chan_width * segment_frequency / total_freq may cause + * The total track num may not match the chan_width, + * therefore, we assign tracks one by one until we meet the frequency requirement + * In this way, we can assign the number of tracks with repect to frequency + ***********************************************************************/ +static +std::vector get_num_tracks_per_seg_type(size_t chan_width, + std::vector segment_inf, + bool use_full_seg_groups) { + std::vector result; + std::vector demand; + /* Make sure a clean start */ + result.resize(segment_inf.size()); + demand.resize(segment_inf.size()); + + /* Scale factor so we can divide by any length + * and still use integers */ + /* Get the sum of frequency */ + size_t scale = 1; + size_t freq_sum = 0; + for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) { + scale *= segment_inf[iseg].length; + freq_sum += segment_inf[iseg].frequency; + } + size_t reduce = scale * freq_sum; + + /* Init assignments to 0 and set the demand values */ + /* Get the fraction of each segment type considering the frequency: + * num_track_per_seg = chan_width * (freq_of_seg / sum_freq) + */ + for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) { + result[iseg] = 0; + demand[iseg] = scale * chan_width * segment_inf[iseg].frequency; + if (true == use_full_seg_groups) { + demand[iseg] /= segment_inf[iseg].length; + } + } + + /* check if the sum of num_tracks, matches the chan_width */ + /* Keep assigning tracks until we use them up */ + size_t assigned = 0; + size_t size = 0; + size_t imax = 0; + while (assigned < chan_width) { + /* Find current maximum demand */ + double max = 0; + for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) { + if (demand[iseg] > max) { + imax = iseg; + } + max = std::max(demand[iseg], max); + } + + /* Assign tracks to the type and reduce the types demand */ + size = (use_full_seg_groups ? segment_inf[imax].length : 1); + demand[imax] -= reduce; + result[imax] += size; + assigned += size; + } + + /* Undo last assignment if we were closer to goal without it */ + if ((assigned - chan_width) > (size / 2)) { + result[imax] -= size; + } + + return result; +} + +/************************************************************************ + * Build details of routing tracks in a channel + * The function will + * 1. Assign the segments for each routing channel, + * To be specific, for each routing track, we assign a routing segment. + * The assignment is subject to users' specifications, such as + * a. length of each type of segment + * b. frequency of each type of segment. + * c. routing channel width + * + * 2. The starting point of each segment in the channel will be assigned + * For each segment group with same directionality (tracks have the same length), + * every L track will be a starting point (where L denotes the length of segments) + * In this case, if the number of tracks is not a multiple of L, + * indeed we may have some | Yes | + * +---------------------------------+ + * | 1 | <-------- | Yes | + * +---------------------------------+ + * | 2 | --------> | No | + * +---------------------------------+ + * | 3 | <-------- | No | + * +---------------------------------+ + * | 4 | --------> | No | + * +---------------------------------+ + * | 5 | <-------- | No | + * +---------------------------------+ + * | 7 | --------> | No | + * +---------------------------------+ + * | 8 | <-------- | No | + * +---------------------------------+ + * | 9 | --------> | Yes | + * +---------------------------------+ + * | 10 | <-------- | Yes | + * +---------------------------------+ + * | 11 | --------> | No | + * +---------------------------------+ + * | 12 | <-------- | No | + * +---------------------------------+ + * + * 3. SPECIAL for fringes: TOP|RIGHT|BOTTOM|RIGHT + * if device_side is NUM_SIDES, we assume this channel does not locate on borders + * All segments will start and ends with no exception + * + * 4. IMPORTANT: we should be aware that channel width maybe different + * in X-direction and Y-direction channels!!! + * So we will load segment details for different channels + ***********************************************************************/ +static +ChanNodeDetails build_unidir_chan_node_details(size_t chan_width, size_t max_seg_length, + enum e_side device_side, + std::vector segment_inf) { + ChanNodeDetails chan_node_details; + /* Correct the chan_width: it should be an even number */ + if (0 != chan_width % 2) { + chan_width++; /* increment it to be even */ + } + assert (0 == chan_width % 2); + + /* Reserve channel width */ + chan_node_details.reserve(chan_width); + /* Return if zero width is forced */ + if (0 == chan_width) { + return chan_node_details; + } + + /* Find the number of segments required by each group */ + std::vector num_tracks = get_num_tracks_per_seg_type(chan_width/2, segment_inf, TRUE); + + /* Add node to ChanNodeDetails */ + size_t cur_track = 0; + for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) { + /* segment length will be set to maxium segment length if this is a longwire */ + size_t seg_len = segment_inf[iseg].length; + if (TRUE == segment_inf[iseg].longline) { + seg_len = max_seg_length; + } + for (size_t itrack = 0; itrack < num_tracks[iseg]; ++itrack) { + bool seg_start = false; + /* Every length of wire, we set a starting point */ + if (0 == itrack % seg_len) { + seg_start = true; + } + /* Since this is a unidirectional routing architecture, + * Add a pair of tracks, 1 INC_DIRECTION track and 1 DEC_DIRECTION track + */ + chan_node_details.add_track(cur_track, INC_DIRECTION, seg_len, seg_start, false); + cur_track++; + chan_node_details.add_track(cur_track, DEC_DIRECTION, seg_len, seg_start, false); + cur_track++; + } + } + /* Check if all the tracks have been satisified */ + assert (cur_track == chan_width); + + /* If this is on the border of a device, segments should start */ + switch (device_side) { + case TOP: + case RIGHT: + /* INC_DIRECTION should all end */ + chan_node_details.set_tracks_end(INC_DIRECTION); + /* DEC_DIRECTION should all start */ + chan_node_details.set_tracks_start(DEC_DIRECTION); + break; + case BOTTOM: + case LEFT: + /* INC_DIRECTION should all start */ + chan_node_details.set_tracks_start(INC_DIRECTION); + /* DEC_DIRECTION should all end */ + chan_node_details.set_tracks_end(DEC_DIRECTION); + break; + case NUM_SIDES: + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Invalid device_side!\n", + __FILE__, __LINE__); + exit(1); + } + + return chan_node_details; +} + +/* Deteremine the side of a io grid */ +static +enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size, + const DeviceCoordinator& grid_coordinator) { + /* TOP side IO of FPGA */ + if (device_size.get_y() == grid_coordinator.get_y()) { + return BOTTOM; /* Such I/O has only Bottom side pins */ + } else if (device_size.get_x() == grid_coordinator.get_x()) { /* RIGHT side IO of FPGA */ + return LEFT; /* Such I/O has only Left side pins */ + } else if (0 == grid_coordinator.get_y()) { /* BOTTOM side IO of FPGA */ + return TOP; /* Such I/O has only Top side pins */ + } else if (0 == grid_coordinator.get_x()) { /* LEFT side IO of FPGA */ + return RIGHT; /* Such I/O has only Right side pins */ + } else { + vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])I/O Grid is in the center part of FPGA! Currently unsupported!\n", + __FILE__, __LINE__); + exit(1); + } +} + +/************************************************************************ + * Get a list of pin_index for a grid (either OPIN or IPIN) + * For IO_TYPE, only one side will be used, we consider one side of pins + * For others, we consider all the sides + ***********************************************************************/ +static +std::vector get_grid_side_pins(const t_grid_tile& cur_grid, enum e_pin_type pin_type, enum e_side pin_side, int pin_height) { + std::vector pin_list; + /* Make sure a clear start */ + pin_list.clear(); + + for (int ipin = 0; ipin < cur_grid.type->num_pins; ++ipin) { + if ( (1 == cur_grid.type->pinloc[pin_height][pin_side][ipin]) + && (pin_type == cur_grid.type->pin_class[ipin]) ) { + pin_list.push_back(ipin); + } + } + return pin_list; +} + +/************************************************************************ + * Get the number of pins for a grid (either OPIN or IPIN) + * For IO_TYPE, only one side will be used, we consider one side of pins + * For others, we consider all the sides + ***********************************************************************/ +static +size_t get_grid_num_pins(const t_grid_tile& cur_grid, enum e_pin_type pin_type, enum e_side io_side) { + size_t num_pins = 0; + Side io_side_manager(io_side); + /* For IO_TYPE sides */ + for (size_t side = 0; side < NUM_SIDES; ++side) { + Side side_manager(side); + /* skip unwanted sides */ + if ( (IO_TYPE == cur_grid.type) + && (side != io_side_manager.to_size_t()) ) { + continue; + } + /* Get pin list */ + for (int height = 0; height < cur_grid.type->height; ++height) { + std::vector pin_list = get_grid_side_pins(cur_grid, pin_type, side_manager.get_side(), height); + num_pins += pin_list.size(); + } + } + + return num_pins; +} + /************************************************************************ * Estimate the number of rr_nodes per category: * CHANX, CHANY, IPIN, OPIN, SOURCE, SINK ***********************************************************************/ static -std::vector estimate_num_rr_nodes_per_type() { +std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& device_size, + std::vector> grids, + std::vector chan_width, + std::vector segment_infs) { std::vector num_rr_nodes_per_type; + /* reserve the vector: + * we have the follow type: + * SOURCE = 0, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE, NUM_RR_TYPES + * NUM_RR_TYPES and INTRA_CLUSTER_EDGE will be 0 + */ + num_rr_nodes_per_type.resize(NUM_RR_TYPES); + /* Make sure a clean start */ + for (size_t i = 0; i < NUM_RR_TYPES; ++i) { + num_rr_nodes_per_type[i] = 0; + } + /************************************************************************ + * 1. Search the grid and find the number OPINs and IPINs per grid + * Note that the number of SOURCE nodes are the same as OPINs + * and the number of SINK nodes are the same as IPINs + ***********************************************************************/ + for (size_t ix = 0; ix < grids.size(); ++ix) { + for (size_t iy = 0; iy < grids[ix].size(); ++iy) { + /* Skip EMPTY tiles */ + if (EMPTY_TYPE == grids[ix][iy].type) { + continue; + } + /* Skip height>1 tiles (mostly heterogeneous blocks) */ + if (0 < grids[ix][iy].offset) { + continue; + } + enum e_side io_side = NUM_SIDES; + /* If this is the block on borders, we consider IO side */ + if (IO_TYPE == grid[ix][iy].type) { + DeviceCoordinator io_device_size(device_size.get_x() - 1, device_size.get_y() - 1); + DeviceCoordinator grid_coordinator(ix, iy); + io_side = determine_io_grid_pin_side(device_size, grid_coordinator); + } + /* get the number of OPINs */ + num_rr_nodes_per_type[OPIN] += get_grid_num_pins(grids[ix][iy], DRIVER, io_side); + /* get the number of IPINs */ + num_rr_nodes_per_type[IPIN] += get_grid_num_pins(grids[ix][iy], RECEIVER, io_side); + } + } + /* SOURCE and SINK */ + num_rr_nodes_per_type[SOURCE] = num_rr_nodes_per_type[OPIN]; + num_rr_nodes_per_type[SINK] = num_rr_nodes_per_type[IPIN]; + + /************************************************************************ + * 2. Assign the segments for each routing channel, + * To be specific, for each routing track, we assign a routing segment. + * The assignment is subject to users' specifications, such as + * a. length of each type of segment + * b. frequency of each type of segment. + * c. routing channel width + * + * SPECIAL for fringes: + * All segments will start and ends with no exception + * + * IMPORTANT: we should be aware that channel width maybe different + * in X-direction and Y-direction channels!!! + * So we will load segment details for different channels + ***********************************************************************/ + /* For X-direction Channel */ + /* For LEFT side of FPGA */ + ChanNodeDetails left_chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, LEFT, segment_infs); + for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) { + num_rr_nodes_per_type[CHANX] += left_chanx_details.get_num_starting_tracks(); + } + /* For RIGHT side of FPGA */ + ChanNodeDetails right_chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, RIGHT, segment_infs); + for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) { + num_rr_nodes_per_type[CHANX] += right_chanx_details.get_num_starting_tracks(); + } + /* For core of FPGA */ + ChanNodeDetails core_chanx_details = build_unidir_chan_node_details(chan_width[1], device_size.get_x() - 2, NUM_SIDES, segment_infs); + for (size_t ix = 1; ix < grids.size() - 2; ++ix) { + for (size_t iy = 1; iy < grids[ix].size() - 2; ++iy) { + num_rr_nodes_per_type[CHANX] += core_chanx_details.get_num_starting_tracks(); + } + } + + /* For Y-direction Channel */ + /* For TOP side of FPGA */ + ChanNodeDetails top_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, TOP, segment_infs); + for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) { + num_rr_nodes_per_type[CHANY] += top_chany_details.get_num_starting_tracks(); + } + /* For BOTTOM side of FPGA */ + ChanNodeDetails bottom_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, BOTTOM, segment_infs); + for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) { + num_rr_nodes_per_type[CHANY] += bottom_chany_details.get_num_starting_tracks(); + } + /* For core of FPGA */ + ChanNodeDetails core_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, NUM_SIDES, segment_infs); + for (size_t ix = 1; ix < grids.size() - 2; ++ix) { + for (size_t iy = 1; iy < grids[ix].size() - 2; ++iy) { + num_rr_nodes_per_type[CHANY] += core_chany_details.get_num_starting_tracks(); + } + } return num_rr_nodes_per_type; } @@ -122,9 +489,9 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings, - /*Xifan TANG: Switch Segment Pattern Support*/ - INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns, - INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) { + /*Xifan TANG: Switch Segment Pattern Support*/ + INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns, + INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) { /* Create an empty graph */ t_rr_graph rr_graph; rr_graph.rr_node_indices = NULL; @@ -134,31 +501,27 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, /* Reset warning flag */ *Warnings = RR_GRAPH_NO_WARN; - /************************************************************************ - * 1. Assign the segments for each routing channel, - * To be specific, for each routing track, we assign a routing segment. - * The assignment is subject to users' specifications, such as - * a. length of each type of segment - * b. frequency of each type of segment. - * c. routing channel width - * IMPORTANT: we should be aware that channel width maybe different - * in X-direction and Y-direction channels!!! - * So we will load segment details for different channels - ***********************************************************************/ - /* Check the channel width */ - int nodes_per_chan = chan_width; - assert(chan_width > 0); - t_seg_details *seg_details = NULL; - seg_details = alloc_and_load_seg_details(&nodes_per_chan, - std::max(L_nx, L_ny), - num_seg_types, segment_inf, - TRUE, FALSE, UNI_DIRECTIONAL); + /* Create a matrix of grid */ + DeviceCoordinator device_size(L_nx + 2, L_ny + 2); + std::vector< std::vector > grids; + /* reserve vector capacity to be memory efficient */ + grids.resize(L_nx + 2); + for (int ix = 0; ix < (L_nx + 2); ++ix) { + grids[ix].resize(L_ny + 2); + for (int iy = 0; ix < (L_ny + 2); ++iy) { + grid[ix][iy] = L_grid[ix][iy]; + } + } + /* Create a vector of channel width, we support X-direction and Y-direction has different W */ + std::vector device_chan_width; + device_chan_width.push_back(chan_width); + device_chan_width.push_back(chan_width); - /* Predict the track index of each channel, - * The track index, also called ptc_num of each CHANX and CHANY rr_node - * Will rotate by 2 in a uni-directional tileable routing architecture - * Vectors are built here to record the ptc_num sequence in each channel - */ + /* Create a vector of segment_inf */ + std::vector segment_infs; + for (int iseg = 0; iseg < num_seg_types; ++iseg) { + segment_infs.push_back(segment_inf[iseg]); + } /************************************************************************ * 2. Estimate the number of nodes in the rr_graph @@ -169,8 +532,24 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, * d. SINK, virtual node which is connected to IPINs * e. CHANX and CHANY, routing segments of each channel ***********************************************************************/ - std::vector num_rr_nodes_per_type = estimate_num_rr_nodes_per_type(); + std::vector num_rr_nodes_per_type = estimate_num_rr_nodes_per_type(device_size, grids, device_chan_width, segment_infs); + /************************************************************************ + * 3. Allocate the rr_nodes + ***********************************************************************/ + rr_graph.num_rr_nodes = 0; + for (size_t i = 0; i < num_rr_nodes_per_type.size(); ++i) { + rr_graph.num_rr_nodes += num_rr_nodes_per_type[i]; + } + /* use calloc to initialize everything to be zero */ + rr_graph.rr_node = (t_rr_node*)my_calloc(rr_graph.num_rr_nodes, sizeof(t_rr_node)); + + /************************************************************************ + * 4. Initialize the basic information of rr_nodes: + * coordinators: xlow, ylow, xhigh, yhigh, + * features: capacity, track_ids, ptc_num, direction + * grid_info : pb_graph_pin + ***********************************************************************/ /************************************************************************ * 3. Create the connectivity of OPINs @@ -180,7 +559,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, int **Fc_in = NULL; /* [0..num_types-1][0..num_pins-1] */ boolean Fc_clipped; Fc_clipped = FALSE; - Fc_in = alloc_and_load_actual_fc(L_num_types, types, nodes_per_chan, + Fc_in = alloc_and_load_actual_fc(L_num_types, types, chan_width, FALSE, UNI_DIRECTIONAL, &Fc_clipped, ignore_Fc_0); if (Fc_clipped) { *Warnings |= RR_GRAPH_WARN_FC_CLIPPED; @@ -193,7 +572,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, ***********************************************************************/ int **Fc_out = NULL; /* [0..num_types-1][0..num_pins-1] */ Fc_clipped = FALSE; - Fc_out = alloc_and_load_actual_fc(L_num_types, types, nodes_per_chan, + Fc_out = alloc_and_load_actual_fc(L_num_types, types, chan_width, TRUE, UNI_DIRECTIONAL, &Fc_clipped, ignore_Fc_0); /************************************************************************ @@ -204,6 +583,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, * c. handle direct-connections ***********************************************************************/ /* Alloc node lookups, count nodes, alloc rr nodes */ + /* rr_graph.num_rr_nodes = 0; rr_graph.rr_node_indices = alloc_and_load_rr_node_indices(nodes_per_chan, L_nx, L_ny, &(rr_graph.num_rr_nodes), seg_details); @@ -211,6 +591,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, memset(rr_node, 0, sizeof(t_rr_node) * rr_graph.num_rr_nodes); boolean* L_rr_edge_done = (boolean *) my_malloc(sizeof(boolean) * rr_graph.num_rr_nodes); memset(L_rr_edge_done, 0, sizeof(boolean) * rr_graph.num_rr_nodes); + */ /* handle direct-connections */ t_clb_to_clb_directs* clb_to_clb_directs = NULL; @@ -223,7 +604,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, * a. cost_index * b. RC tree ***********************************************************************/ - rr_graph_externals(timing_inf, segment_inf, num_seg_types, nodes_per_chan, + rr_graph_externals(timing_inf, segment_inf, num_seg_types, chan_width, wire_to_ipin_switch, base_cost_type); return rr_graph; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_rr_graph_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_rr_graph_utils.c index 711b6ddc0..e5312fcb4 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_rr_graph_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_rr_graph_utils.c @@ -403,7 +403,7 @@ void alloc_and_load_rr_graph_route_structs(t_rr_graph* local_rr_graph) { int inode; - local_rr_graph->rr_node_route_inf = (t_rr_node_route_inf *) my_malloc(local_rr_graph->num_rr_nodes * sizeof(t_rr_node_route_inf)); + local_rr_graph->rr_node_route_inf = (t_rr_node_route_inf *) my_calloc(local_rr_graph->num_rr_nodes, sizeof(t_rr_node_route_inf)); for (inode = 0; inode < local_rr_graph->num_rr_nodes; inode++) { local_rr_graph->rr_node_route_inf[inode].prev_node = NO_PREVIOUS; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/router/fpga_x2p_pb_rr_graph.c b/vpr7_x2p/vpr/SRC/fpga_x2p/router/fpga_x2p_pb_rr_graph.c index e0d4457d6..db283690c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/router/fpga_x2p_pb_rr_graph.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/router/fpga_x2p_pb_rr_graph.c @@ -33,6 +33,8 @@ #include "fpga_x2p_pbtypes_utils.h" #include "fpga_x2p_globals.h" +#include "fpga_x2p_pb_rr_graph.h" + /* Count the number of rr_graph nodes that should be allocated * (a) INPUT pins at the top-level pb_graph_node should be a local_rr_node and plus a SOURCE * (b) CLOCK pins at the top-level pb_graph_node should be a local_rr_node and plus a SOURCE @@ -104,6 +106,7 @@ void init_one_rr_node_pack_cost_for_phy_graph_node(INP t_pb_graph_pin* cur_pb_gr /* Override the fan-in and fan-out for a top/primitive pb_graph_node */ +static void override_one_rr_node_for_top_primitive_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_pin, INOUTP t_rr_graph* local_rr_graph, int cur_rr_node_index, @@ -151,6 +154,7 @@ void override_one_rr_node_for_top_primitive_phy_pb_graph_node(INP t_pb_graph_pin } /* initialize a rr_node in a rr_graph of phyical pb_graph_node */ +static void init_one_rr_node_for_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_pin, INOUTP t_rr_graph* local_rr_graph, int cur_rr_node_index, @@ -206,7 +210,9 @@ void init_one_rr_node_for_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_pin local_rr_graph->rr_node[cur_rr_node_index].prev_edge = OPEN; local_rr_graph->rr_node[cur_rr_node_index].capacity = 1; + local_rr_graph->rr_node[cur_rr_node_index].occ = 0; local_rr_graph->rr_node[cur_rr_node_index].type = rr_node_type; + local_rr_graph->rr_node[cur_rr_node_index].cost_index = 0; return; } @@ -270,6 +276,7 @@ void connect_one_rr_node_for_phy_pb_graph_node(INP t_pb_graph_pin* cur_pb_graph_ /* Recursively configure all the rr_nodes in the rr_graph * Initialize the routing cost, fan-in rr_nodes and fan-out rr_nodes, and switches */ +static void rec_init_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* cur_pb_graph_node, INOUTP t_rr_graph* local_rr_graph, int* cur_rr_node_index) { @@ -418,6 +425,7 @@ void rec_init_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* cur_pb_graph_n /* Recursively connect all the rr_nodes in the rr_graph * output_edges, output_switches */ +static void rec_connect_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* cur_pb_graph_node, INOUTP t_rr_graph* local_rr_graph, int* cur_rr_node_index) { @@ -598,6 +606,7 @@ void alloc_and_load_rr_graph_for_phy_pb_graph_node(INP t_pb_graph_node* top_pb_g /* Check the vpack_net_num of a rr_node mapped to a pb_graph_pin and * mark the used vpack_net_num in the list */ +static void mark_vpack_net_used_in_pb_pin(t_pb* cur_op_pb, t_pb_graph_pin* cur_pb_graph_pin, int L_num_vpack_nets, boolean* vpack_net_used_in_pb) { int inode; @@ -621,6 +630,7 @@ void mark_vpack_net_used_in_pb_pin(t_pb* cur_op_pb, t_pb_graph_pin* cur_pb_graph /* Recursively visit all the child pbs and * mark the used vpack_net_num in the list */ +static void mark_vpack_net_used_in_pb(t_pb* cur_op_pb, int L_num_vpack_nets, boolean* vpack_net_used_in_pb) { int mode_index, ipb, jpb; @@ -718,6 +728,7 @@ void alloc_and_load_phy_pb_rr_graph_nets(INP t_pb* cur_op_pb, } /* Find the rr_node in the primitive node of a pb_rr_graph*/ +static void sync_pb_graph_pin_vpack_net_num_to_phy_pb(t_rr_node* cur_op_pb_rr_graph, t_pb_graph_pin* cur_pb_graph_pin, t_rr_graph* local_rr_graph) { @@ -787,6 +798,7 @@ void sync_pb_graph_pin_vpack_net_num_to_phy_pb(t_rr_node* cur_op_pb_rr_graph, return; } +static void rec_sync_wired_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb_graph_node* cur_pb_graph_node, t_rr_node* op_pb_rr_graph, t_rr_graph* local_rr_graph) { @@ -851,6 +863,7 @@ void rec_sync_wired_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb_graph_node* cur_pb_ * synchronize the vpack_net_num of the top-level/primitive pb_graph_pin * to the physical pb rr_node nodes */ +static void rec_sync_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb* cur_op_pb, t_rr_graph* local_rr_graph) { int mode_index, ipb, jpb; @@ -921,6 +934,7 @@ void rec_sync_pb_vpack_net_num_to_phy_pb_rr_graph(t_pb* cur_op_pb, * 3. Find the SOURCE and SINK rr_nodes related to the pb_graph_pin * 4. Configure the net_rr_terminals with the SINK/SOURCE rr_nodes */ +static void alloc_and_load_phy_pb_rr_graph_net_rr_terminals(INP t_pb* cur_op_pb, t_rr_graph* local_rr_graph) { int inet, inode, rr_node_net_name; @@ -1013,10 +1027,11 @@ void alloc_and_load_phy_pb_rr_graph_net_rr_terminals(INP t_pb* cur_op_pb, return; } +static void alloc_pb_rr_graph_rr_indexed_data(t_rr_graph* local_rr_graph) { /* inside a cluster, I do not consider rr_indexed_data cost, set to 1 since other costs are multiplied by it */ alloc_rr_graph_rr_indexed_data(local_rr_graph, 1); - local_rr_graph->rr_indexed_data[0].base_cost = 1; + local_rr_graph->rr_indexed_data[0].base_cost = 1.; return; } @@ -1025,8 +1040,8 @@ void alloc_pb_rr_graph_rr_indexed_data(t_rr_graph* local_rr_graph) { * Add an output edge to the rr_node of the used input * connect it to the rr_node of the used LUT output */ +static void add_rr_node_edge_to_one_wired_lut(t_pb_graph_node* cur_pb_graph_node, - t_pb_type* cur_pb_type, t_rr_node* op_pb_rr_graph, t_rr_graph* local_rr_graph) { int iport, ipin; @@ -1140,6 +1155,7 @@ void add_rr_node_edge_to_one_wired_lut(t_pb_graph_node* cur_pb_graph_node, /* Add rr edges connecting from an input of a LUT to its output * IMPORTANT: this is only applied to LUT which operates in wire mode (a buffer) */ +static void rec_add_unused_rr_graph_wired_lut_rr_edges(INP t_pb_graph_node* cur_op_pb_graph_node, INP t_rr_node* cur_op_pb_rr_graph, INOUTP t_rr_graph* local_rr_graph) { @@ -1162,7 +1178,6 @@ void rec_add_unused_rr_graph_wired_lut_rr_edges(INP t_pb_graph_node* cur_op_pb_g * connect it to the rr_node of the used LUT output */ add_rr_node_edge_to_one_wired_lut(cur_op_pb_graph_node, - cur_pb_type, cur_op_pb_rr_graph, local_rr_graph); } @@ -1194,6 +1209,7 @@ void rec_add_unused_rr_graph_wired_lut_rr_edges(INP t_pb_graph_node* cur_op_pb_g /* Add rr edges connecting from an input of a LUT to its output * IMPORTANT: this is only applied to LUT which operates in wire mode (a buffer) */ +static void rec_add_rr_graph_wired_lut_rr_edges(INP t_pb* cur_op_pb, INOUTP t_rr_graph* local_rr_graph) { int mode_index, ipb, jpb, imode; @@ -1214,7 +1230,6 @@ void rec_add_rr_graph_wired_lut_rr_edges(INP t_pb* cur_op_pb, * connect it to the rr_node of the used LUT output */ add_rr_node_edge_to_one_wired_lut(cur_op_pb->pb_graph_node, - cur_pb_type, cur_op_pb->rr_graph, local_rr_graph); } @@ -1253,6 +1268,7 @@ void rec_add_rr_graph_wired_lut_rr_edges(INP t_pb* cur_op_pb, * For each multiple-source net, I add a new source as the unique source in routing purpose * As so, edges have to be added to the decendents of sources */ +static int add_virtual_sources_to_rr_graph_multi_sources(t_rr_graph* local_rr_graph) { int inet, isrc; int unique_src_node; @@ -1271,6 +1287,8 @@ int add_virtual_sources_to_rr_graph_multi_sources(t_rr_graph* local_rr_graph) { unique_src_node = local_rr_graph->num_rr_nodes - 1; local_rr_graph->rr_node[unique_src_node].type = SOURCE; local_rr_graph->rr_node[unique_src_node].capacity = 1; + local_rr_graph->rr_node[unique_src_node].occ = 0; + local_rr_graph->rr_node[unique_src_node].cost_index = 0; local_rr_graph->rr_node[unique_src_node].fan_in = 0; local_rr_graph->rr_node[unique_src_node].num_drive_rr_nodes = 0; local_rr_graph->rr_node[unique_src_node].drive_rr_nodes = NULL; @@ -1314,6 +1332,9 @@ void alloc_and_load_rr_graph_for_phy_pb(INP t_pb* cur_op_pb, /* Allocate rr_graph*/ cur_phy_pb->rr_graph = (t_rr_graph*) my_calloc(1, sizeof(t_rr_graph)); + /* Allocate and initialize cost index */ + alloc_pb_rr_graph_rr_indexed_data(cur_phy_pb->rr_graph); + /* Create rr_graph */ alloc_and_load_rr_graph_for_phy_pb_graph_node(cur_phy_pb->pb_graph_node, cur_phy_pb->rr_graph); @@ -1332,8 +1353,6 @@ void alloc_and_load_rr_graph_for_phy_pb(INP t_pb* cur_op_pb, /* Allocate trace in rr_graph */ alloc_rr_graph_route_static_structs(cur_phy_pb->rr_graph, nx * ny); /* TODO: nx * ny should be reduced for pb-only routing */ - alloc_pb_rr_graph_rr_indexed_data(cur_phy_pb->rr_graph); - /* Fill the net_rr_terminals with * 1. pin-to-pin mapping in pb_graph_node in cur_op_pb * 2. rr_graph in the cur_op_pb diff --git a/vpr7_x2p/vpr/SRC/power/power.c b/vpr7_x2p/vpr/SRC/power/power.c index 420b7e655..d185ffa9d 100644 --- a/vpr7_x2p/vpr/SRC/power/power.c +++ b/vpr7_x2p/vpr/SRC/power/power.c @@ -201,6 +201,7 @@ static void power_usage_primitive(t_power_usage * power_usage, t_pb * pb, } } +static void power_usage_local_pin_toggle(t_power_usage * power_usage, t_pb * pb, t_pb_graph_pin * pin) { float scale_factor; @@ -222,6 +223,7 @@ void power_usage_local_pin_toggle(t_power_usage * power_usage, t_pb * pb, / g_solution_inf.T_crit; } +static void power_usage_local_pin_buffer_and_wire(t_power_usage * power_usage, t_pb * pb, t_pb_graph_pin * pin) { t_power_usage sub_power_usage; @@ -1027,6 +1029,7 @@ static void power_usage_routing(t_power_usage * power_usage, } } +static void power_alloc_and_init_pb_pin(t_pb_graph_pin * pin) { int port_idx; t_port * port_to_find; @@ -1085,6 +1088,7 @@ void power_alloc_and_init_pb_pin(t_pb_graph_pin * pin) { } } +static void power_init_pb_pins_rec(t_pb_graph_node * pb_node) { int mode; int type; @@ -1131,6 +1135,7 @@ void power_init_pb_pins_rec(t_pb_graph_node * pb_node) { } } +static void power_pb_pins_init() { int type_idx; @@ -1141,6 +1146,7 @@ void power_pb_pins_init() { } } +static void power_routing_init(t_det_routing_arch * routing_arch) { int net_idx; int rr_node_idx; @@ -1367,7 +1373,7 @@ boolean power_uninit(void) { } delete mux_info; } - free(g_power_commonly_used); + delete g_power_commonly_used; if (g_power_output->out) { fclose(g_power_output->out);