| #include <algorithm> |
| #include <numeric> |
| |
| #include "vtr_assert.h" |
| #include "vtr_log.h" |
| #include "vpr_error.h" |
| /* |
| * |
| * NetlistIdRemapper class implementation |
| * |
| */ |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| BlockId NetlistIdRemapper<BlockId, PortId, PinId, NetId>::new_block_id(BlockId old_id) const { |
| return block_id_map_[old_id]; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| PortId NetlistIdRemapper<BlockId, PortId, PinId, NetId>::new_port_id(PortId old_id) const { |
| return port_id_map_[old_id]; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| PinId NetlistIdRemapper<BlockId, PortId, PinId, NetId>::new_pin_id(PinId old_id) const { |
| return pin_id_map_[old_id]; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| NetId NetlistIdRemapper<BlockId, PortId, PinId, NetId>::new_net_id(NetId old_id) const { |
| return net_id_map_[old_id]; |
| } |
| |
| /* |
| * |
| * Netlist class implementation |
| * |
| */ |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| Netlist<BlockId, PortId, PinId, NetId>::Netlist(std::string name, std::string id) |
| : netlist_name_(name) |
| , netlist_id_(id) {} |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| Netlist<BlockId, PortId, PinId, NetId>::~Netlist() = default; |
| |
| /* |
| * |
| * Netlist |
| * |
| */ |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| const std::string& Netlist<BlockId, PortId, PinId, NetId>::netlist_name() const { |
| return netlist_name_; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| const std::string& Netlist<BlockId, PortId, PinId, NetId>::netlist_id() const { |
| return netlist_id_; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::is_dirty() const { |
| return dirty_; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::is_compressed() const { |
| return !is_dirty(); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::print_stats() const { |
| VTR_LOG("Blocks %zu capacity/size: %.2f\n", block_ids_.size(), float(block_ids_.capacity()) / block_ids_.size()); |
| VTR_LOG("Ports %zu capacity/size: %.2f\n", port_ids_.size(), float(port_ids_.capacity()) / port_ids_.size()); |
| VTR_LOG("Pins %zu capacity/size: %.2f\n", pin_ids_.size(), float(pin_ids_.capacity()) / pin_ids_.size()); |
| VTR_LOG("Nets %zu capacity/size: %.2f\n", net_ids_.size(), float(net_ids_.capacity()) / net_ids_.size()); |
| VTR_LOG("Strings %zu capacity/size: %.2f\n", string_ids_.size(), float(string_ids_.capacity()) / string_ids_.size()); |
| } |
| |
| /* |
| * |
| * Blocks |
| * |
| */ |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| const std::string& Netlist<BlockId, PortId, PinId, NetId>::block_name(const BlockId blk_id) const { |
| StringId str_id = block_names_[blk_id]; |
| return strings_[str_id]; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::block_is_combinational(const BlockId blk_id) const { |
| VTR_ASSERT_SAFE(valid_block_id(blk_id)); |
| |
| return block_clock_pins(blk_id).size() == 0; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::attr_range Netlist<BlockId, PortId, PinId, NetId>::block_attrs(const BlockId blk_id) const { |
| VTR_ASSERT_SAFE(valid_block_id(blk_id)); |
| |
| return vtr::make_range(block_attrs_[blk_id].begin(), block_attrs_[blk_id].end()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::param_range Netlist<BlockId, PortId, PinId, NetId>::block_params(const BlockId blk_id) const { |
| VTR_ASSERT_SAFE(valid_block_id(blk_id)); |
| |
| return vtr::make_range(block_params_[blk_id].begin(), block_params_[blk_id].end()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::pin_range Netlist<BlockId, PortId, PinId, NetId>::block_pins(const BlockId blk_id) const { |
| VTR_ASSERT_SAFE(valid_block_id(blk_id)); |
| |
| return vtr::make_range(block_pins_[blk_id].begin(), block_pins_[blk_id].end()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::pin_range Netlist<BlockId, PortId, PinId, NetId>::block_input_pins(const BlockId blk_id) const { |
| VTR_ASSERT_SAFE(valid_block_id(blk_id)); |
| |
| auto begin = block_pins_[blk_id].begin(); |
| |
| auto end = block_pins_[blk_id].begin() + block_num_input_pins_[blk_id]; |
| |
| return vtr::make_range(begin, end); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::pin_range Netlist<BlockId, PortId, PinId, NetId>::block_output_pins(const BlockId blk_id) const { |
| VTR_ASSERT_SAFE(valid_block_id(blk_id)); |
| |
| auto begin = block_pins_[blk_id].begin() + block_num_input_pins_[blk_id]; |
| |
| auto end = begin + block_num_output_pins_[blk_id]; |
| |
| return vtr::make_range(begin, end); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::pin_range Netlist<BlockId, PortId, PinId, NetId>::block_clock_pins(const BlockId blk_id) const { |
| VTR_ASSERT_SAFE(valid_block_id(blk_id)); |
| |
| auto begin = block_pins_[blk_id].begin() |
| + block_num_input_pins_[blk_id] |
| + block_num_output_pins_[blk_id]; |
| |
| auto end = begin + block_num_clock_pins_[blk_id]; |
| |
| VTR_ASSERT_SAFE(end == block_pins_[blk_id].end()); |
| |
| return vtr::make_range(begin, end); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::port_range Netlist<BlockId, PortId, PinId, NetId>::block_ports(const BlockId blk_id) const { |
| VTR_ASSERT_SAFE(valid_block_id(blk_id)); |
| |
| return vtr::make_range(block_ports_[blk_id].begin(), block_ports_[blk_id].end()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::port_range Netlist<BlockId, PortId, PinId, NetId>::block_input_ports(const BlockId blk_id) const { |
| VTR_ASSERT_SAFE(valid_block_id(blk_id)); |
| |
| auto begin = block_ports_[blk_id].begin(); |
| |
| auto end = block_ports_[blk_id].begin() + block_num_input_ports_[blk_id]; |
| |
| return vtr::make_range(begin, end); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::port_range Netlist<BlockId, PortId, PinId, NetId>::block_output_ports(const BlockId blk_id) const { |
| VTR_ASSERT_SAFE(valid_block_id(blk_id)); |
| |
| auto begin = block_ports_[blk_id].begin() + block_num_input_ports_[blk_id]; |
| |
| auto end = begin + block_num_output_ports_[blk_id]; |
| |
| return vtr::make_range(begin, end); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::port_range Netlist<BlockId, PortId, PinId, NetId>::block_clock_ports(const BlockId blk_id) const { |
| VTR_ASSERT_SAFE(valid_block_id(blk_id)); |
| |
| auto begin = block_ports_[blk_id].begin() |
| + block_num_input_ports_[blk_id] |
| + block_num_output_ports_[blk_id]; |
| |
| auto end = begin + block_num_clock_ports_[blk_id]; |
| |
| VTR_ASSERT_SAFE(end == block_ports_[blk_id].end()); |
| |
| return vtr::make_range(begin, end); |
| } |
| |
| /* |
| * |
| * Ports |
| * |
| */ |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| const std::string& Netlist<BlockId, PortId, PinId, NetId>::port_name(const PortId port_id) const { |
| VTR_ASSERT_SAFE(valid_port_id(port_id)); |
| |
| StringId str_id = port_names_[port_id]; |
| return strings_[str_id]; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| BlockId Netlist<BlockId, PortId, PinId, NetId>::port_block(const PortId port_id) const { |
| VTR_ASSERT_SAFE(valid_port_id(port_id)); |
| |
| return port_blocks_[port_id]; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::pin_range Netlist<BlockId, PortId, PinId, NetId>::port_pins(const PortId port_id) const { |
| VTR_ASSERT_SAFE(valid_port_id(port_id)); |
| |
| return vtr::make_range(port_pins_[port_id].begin(), port_pins_[port_id].end()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| PinId Netlist<BlockId, PortId, PinId, NetId>::port_pin(const PortId port_id, const BitIndex port_bit) const { |
| //Convenience look-up bypassing port |
| return find_pin(port_id, port_bit); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| NetId Netlist<BlockId, PortId, PinId, NetId>::port_net(const PortId port_id, const BitIndex port_bit) const { |
| //port_pin() will validate that port_bit and port_id are valid so don't |
| //check redundently here |
| |
| //Convenience look-up bypassing port and pin |
| PinId pin_id = port_pin(port_id, port_bit); |
| if (pin_id) { |
| return pin_net(pin_id); |
| } else { |
| return NetId::INVALID(); |
| } |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| BitIndex Netlist<BlockId, PortId, PinId, NetId>::port_width(const PortId port_id) const { |
| VTR_ASSERT_SAFE(valid_port_id(port_id)); |
| |
| return port_widths_[port_id]; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| PortType Netlist<BlockId, PortId, PinId, NetId>::port_type(const PortId port_id) const { |
| VTR_ASSERT_SAFE(valid_port_id(port_id)); |
| |
| return port_types_[port_id]; |
| } |
| |
| /* |
| * |
| * Pins |
| * |
| */ |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| std::string Netlist<BlockId, PortId, PinId, NetId>::pin_name(const PinId pin_id) const { |
| BlockId blk = pin_block(pin_id); |
| PortId port = pin_port(pin_id); |
| |
| return block_name(blk) + "." + port_name(port) + "[" + std::to_string(pin_port_bit(pin_id)) + "]"; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| PinType Netlist<BlockId, PortId, PinId, NetId>::pin_type(const PinId pin_id) const { |
| auto port_id = pin_port(pin_id); |
| |
| PinType type = PinType::OPEN; |
| switch (port_type(port_id)) { |
| case PortType::INPUT: /*fallthrough */; |
| case PortType::CLOCK: |
| type = PinType::SINK; |
| break; |
| case PortType::OUTPUT: |
| type = PinType::DRIVER; |
| break; |
| default: |
| VTR_ASSERT_OPT_MSG(false, "Valid port type"); |
| } |
| return type; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| NetId Netlist<BlockId, PortId, PinId, NetId>::pin_net(const PinId pin_id) const { |
| VTR_ASSERT_SAFE(valid_pin_id(pin_id)); |
| |
| return pin_nets_[pin_id]; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| int Netlist<BlockId, PortId, PinId, NetId>::pin_net_index(const PinId pin_id) const { |
| VTR_ASSERT_SAFE(valid_pin_id(pin_id)); |
| |
| return pin_net_indices_[pin_id]; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| PortId Netlist<BlockId, PortId, PinId, NetId>::pin_port(const PinId pin_id) const { |
| VTR_ASSERT_SAFE(valid_pin_id(pin_id)); |
| |
| return pin_ports_[pin_id]; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| BitIndex Netlist<BlockId, PortId, PinId, NetId>::pin_port_bit(const PinId pin_id) const { |
| VTR_ASSERT_SAFE(valid_pin_id(pin_id)); |
| |
| return pin_port_bits_[pin_id]; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| BlockId Netlist<BlockId, PortId, PinId, NetId>::pin_block(const PinId pin_id) const { |
| //Convenience lookup bypassing the port |
| VTR_ASSERT_SAFE(valid_pin_id(pin_id)); |
| |
| PortId port_id = pin_port(pin_id); |
| return port_block(port_id); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| PortType Netlist<BlockId, PortId, PinId, NetId>::pin_port_type(const PinId pin_id) const { |
| PortId port_id = pin_port(pin_id); |
| |
| return port_type(port_id); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::pin_is_constant(const PinId pin_id) const { |
| VTR_ASSERT_SAFE(valid_pin_id(pin_id)); |
| |
| return pin_is_constant_[pin_id]; |
| } |
| |
| /* |
| * |
| * Nets |
| * |
| */ |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| const std::string& Netlist<BlockId, PortId, PinId, NetId>::net_name(const NetId net_id) const { |
| VTR_ASSERT_SAFE(valid_net_id(net_id)); |
| |
| StringId str_id = net_names_[net_id]; |
| return strings_[str_id]; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::pin_range Netlist<BlockId, PortId, PinId, NetId>::net_pins(const NetId net_id) const { |
| VTR_ASSERT_SAFE(valid_net_id(net_id)); |
| |
| return vtr::make_range(net_pins_[net_id].begin(), net_pins_[net_id].end()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| PinId Netlist<BlockId, PortId, PinId, NetId>::net_pin(const NetId net_id, int net_pin_index) const { |
| VTR_ASSERT_SAFE(valid_net_id(net_id)); |
| VTR_ASSERT_SAFE_MSG(net_pin_index >= 0 && size_t(net_pin_index) < net_pins_[net_id].size(), "Pin index must be in range"); |
| |
| return net_pins_[net_id][net_pin_index]; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| BlockId Netlist<BlockId, PortId, PinId, NetId>::net_pin_block(const NetId net_id, int net_pin_index) const { |
| auto pin_id = net_pin(net_id, net_pin_index); |
| |
| return pin_block(pin_id); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| PinId Netlist<BlockId, PortId, PinId, NetId>::net_driver(const NetId net_id) const { |
| VTR_ASSERT_SAFE(valid_net_id(net_id)); |
| |
| if (net_pins_[net_id].size() > 0) { |
| return net_pins_[net_id][0]; |
| } else { |
| return PinId::INVALID(); |
| } |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| BlockId Netlist<BlockId, PortId, PinId, NetId>::net_driver_block(const NetId net_id) const { |
| auto driver_pin_id = net_driver(net_id); |
| if (driver_pin_id) { |
| return pin_block(driver_pin_id); |
| } |
| return BlockId::INVALID(); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::pin_range Netlist<BlockId, PortId, PinId, NetId>::net_sinks(const NetId net_id) const { |
| VTR_ASSERT_SAFE(valid_net_id(net_id)); |
| |
| return vtr::make_range(++net_pins_[net_id].begin(), net_pins_[net_id].end()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::net_is_constant(const NetId net_id) const { |
| VTR_ASSERT_SAFE(valid_net_id(net_id)); |
| |
| //Look-up the driver |
| auto driver_pin_id = net_driver(net_id); |
| if (driver_pin_id) { |
| //Valid driver, see it is constant |
| return pin_is_constant(driver_pin_id); |
| } |
| |
| //No valid driver so can't be const |
| return false; |
| } |
| |
| /* |
| * |
| * Aggregates |
| * |
| */ |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::block_range Netlist<BlockId, PortId, PinId, NetId>::blocks() const { |
| return vtr::make_range(block_ids_.begin(), block_ids_.end()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::port_range Netlist<BlockId, PortId, PinId, NetId>::ports() const { |
| return vtr::make_range(port_ids_.begin(), port_ids_.end()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::pin_range Netlist<BlockId, PortId, PinId, NetId>::pins() const { |
| return vtr::make_range(pin_ids_.begin(), pin_ids_.end()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::net_range Netlist<BlockId, PortId, PinId, NetId>::nets() const { |
| return vtr::make_range(net_ids_.begin(), net_ids_.end()); |
| } |
| |
| /* |
| * |
| * Lookups |
| * |
| */ |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| BlockId Netlist<BlockId, PortId, PinId, NetId>::find_block(const std::string& name) const { |
| auto str_id = find_string(name); |
| if (!str_id) { |
| return BlockId::INVALID(); |
| } else { |
| return find_block(str_id); |
| } |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| PortId Netlist<BlockId, PortId, PinId, NetId>::find_port(const BlockId blk_id, const std::string& name) const { |
| VTR_ASSERT_SAFE(valid_block_id(blk_id)); |
| |
| //Since we only know the port name, we must search all the ports |
| for (auto port_id : block_ports(blk_id)) { |
| if (port_name(port_id) == name) { |
| return port_id; |
| } |
| } |
| return PortId::INVALID(); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| NetId Netlist<BlockId, PortId, PinId, NetId>::find_net(const std::string& name) const { |
| auto str_id = find_string(name); |
| if (!str_id) { |
| return NetId::INVALID(); |
| } else { |
| return find_net(str_id); |
| } |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| PinId Netlist<BlockId, PortId, PinId, NetId>::find_pin(const PortId port_id, BitIndex port_bit) const { |
| VTR_ASSERT_SAFE(valid_port_id(port_id)); |
| VTR_ASSERT_SAFE(valid_port_bit(port_id, port_bit)); |
| |
| //Pins are stored in ascending order of bit index, |
| //so we can binary search for the specific bit |
| auto port_bit_cmp = [&](const PinId pin_id, BitIndex bit_index) { |
| return pin_port_bit(pin_id) < bit_index; |
| }; |
| |
| auto pins_rng = port_pins(port_id); |
| |
| //Finds the location where the pin with bit index port_bit should be located (if it exists) |
| auto iter = std::lower_bound(pins_rng.begin(), pins_rng.end(), port_bit, port_bit_cmp); |
| |
| if (iter == pins_rng.end() || pin_port_bit(*iter) != port_bit) { |
| //Either the end of the pins (i.e. not found), or |
| //the value does not match (indicating a gap in the indicies, so also not found) |
| return PinId::INVALID(); |
| } else { |
| //Found it |
| VTR_ASSERT_SAFE(pin_port_bit(*iter) == port_bit); |
| return *iter; |
| } |
| } |
| |
| /* |
| * |
| * Validation |
| * |
| */ |
| //Top-level verification method, checks that the sizes |
| //references, and lookups are all consistent. |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::verify() const { |
| bool valid = true; |
| |
| //Verify data structure consistency |
| valid &= verify_sizes(); |
| valid &= verify_refs(); |
| valid &= verify_lookups(); |
| |
| //Verify logical consistency |
| valid &= verify_block_invariants(); |
| |
| return valid; |
| } |
| |
| //Checks that the sizes of internal data structures |
| //are consistent. Should take constant time. |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::verify_sizes() const { |
| bool valid = true; |
| valid &= validate_block_sizes(); |
| valid &= validate_port_sizes(); |
| valid &= validate_pin_sizes(); |
| valid &= validate_net_sizes(); |
| valid &= validate_string_sizes(); |
| return valid; |
| } |
| |
| //Checks that all cross-references are consistent. |
| //Should take linear time. |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::verify_refs() const { |
| bool valid = true; |
| valid &= validate_block_port_refs(); |
| valid &= validate_port_pin_refs(); |
| valid &= validate_block_pin_refs(); |
| valid &= validate_net_pin_refs(); |
| valid &= validate_string_refs(); |
| |
| return valid; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::verify_lookups() const { |
| //Verify that fast look-ups are consistent |
| |
| //Blocks |
| for (auto blk_id : blocks()) { |
| const auto& name = block_name(blk_id); |
| if (find_block(name) != blk_id) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Block lookup by name mismatch"); |
| } |
| } |
| |
| //Ports |
| for (auto port_id : port_ids_) { |
| auto blk_id = port_block(port_id); |
| const auto& name = port_name(port_id); |
| if (find_port(blk_id, name) != port_id) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Port lookup by name mismatch"); |
| } |
| } |
| |
| //Pins |
| for (auto pin_id : pin_ids_) { |
| auto port_id = pin_port(pin_id); |
| auto bit = pin_port_bit(pin_id); |
| if (find_pin(port_id, bit) != pin_id) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Pin lookup by name mismatch"); |
| } |
| } |
| |
| //Nets |
| for (auto net_id : nets()) { |
| const auto& name = net_name(net_id); |
| if (find_net(name) != net_id) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Net lookup by name mismatch"); |
| } |
| } |
| |
| //Strings |
| for (auto str_id : string_ids_) { |
| const auto& name = strings_[str_id]; |
| if (find_string(name) != str_id) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "String lookup by name mismatch"); |
| } |
| } |
| return true; |
| } |
| |
| /* |
| * |
| * Mutators |
| * |
| */ |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| BlockId Netlist<BlockId, PortId, PinId, NetId>::create_block(const std::string name) { |
| //Must have a non-empty name |
| VTR_ASSERT_MSG(!name.empty(), "Non-Empty block name"); |
| |
| //Check if the block has already been created |
| StringId name_id = create_string(name); |
| BlockId blk_id = find_block(name_id); |
| |
| if (blk_id == BlockId::INVALID()) { |
| //Not found, create it |
| |
| //Reserve an id |
| blk_id = BlockId(block_ids_.size()); |
| block_ids_.push_back(blk_id); |
| |
| //Initialize the data |
| block_names_.push_back(name_id); |
| block_attrs_.emplace_back(); |
| block_params_.emplace_back(); |
| |
| //Initialize the look-ups |
| block_name_to_block_id_.insert(name_id, blk_id); |
| |
| block_pins_.emplace_back(); |
| block_num_input_pins_.push_back(0); |
| block_num_output_pins_.push_back(0); |
| block_num_clock_pins_.push_back(0); |
| |
| block_ports_.emplace_back(); |
| block_num_input_ports_.push_back(0); |
| block_num_output_ports_.push_back(0); |
| block_num_clock_ports_.push_back(0); |
| } |
| |
| //Check post-conditions: values |
| VTR_ASSERT(valid_block_id(blk_id)); |
| VTR_ASSERT(block_name(blk_id) == name); |
| VTR_ASSERT_SAFE(find_block(name) == blk_id); |
| |
| return blk_id; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| PortId Netlist<BlockId, PortId, PinId, NetId>::create_port(const BlockId blk_id, const std::string name, BitIndex width, PortType type) { |
| //Check pre-conditions |
| VTR_ASSERT_MSG(valid_block_id(blk_id), "Valid block id"); |
| |
| //See if the port already exists |
| StringId name_id = create_string(name); |
| PortId port_id = find_port(blk_id, name); |
| if (!port_id) { //Not found, create it |
| //Reserve an id |
| port_id = PortId(port_ids_.size()); |
| port_ids_.push_back(port_id); |
| |
| //Initialize the per-port-instance data |
| port_blocks_.push_back(blk_id); |
| port_names_.push_back(name_id); |
| port_widths_.push_back(width); |
| port_types_.push_back(type); |
| |
| //Allocate the pins, initialize to invalid Ids |
| port_pins_.emplace_back(); |
| } |
| |
| //Check post-conditions: values |
| VTR_ASSERT(valid_port_id(port_id)); |
| VTR_ASSERT(port_block(port_id) == blk_id); |
| VTR_ASSERT(port_width(port_id) == width); |
| |
| return port_id; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| PinId Netlist<BlockId, PortId, PinId, NetId>::create_pin(const PortId port_id, BitIndex port_bit, const NetId net_id, const PinType type, bool is_const) { |
| //Check pre-conditions (valid ids) |
| VTR_ASSERT_MSG(valid_port_id(port_id), "Valid port id"); |
| VTR_ASSERT_MSG(valid_port_bit(port_id, port_bit), "Valid port bit"); |
| VTR_ASSERT_MSG(valid_net_id(net_id), "Valid net id"); |
| |
| //See if the pin already exists |
| PinId pin_id = find_pin(port_id, port_bit); |
| if (!pin_id) { |
| //Not found, create it |
| |
| //Reserve an id |
| pin_id = PinId(pin_ids_.size()); |
| pin_ids_.push_back(pin_id); |
| |
| //Initialize the pin data |
| pin_ports_.push_back(port_id); |
| pin_port_bits_.push_back(port_bit); |
| pin_nets_.push_back(net_id); |
| pin_is_constant_.push_back(is_const); |
| |
| //Add the pin to the net |
| int pins_net_index = associate_pin_with_net(pin_id, type, net_id); |
| |
| //Save the net index of the pin |
| pin_net_indices_.push_back(pins_net_index); |
| |
| //Add the pin to the port |
| associate_pin_with_port(pin_id, port_id); |
| |
| //Add the pin to the block |
| associate_pin_with_block(pin_id, port_type(port_id), port_block(port_id)); |
| } |
| |
| //Check post-conditions: values |
| VTR_ASSERT(valid_pin_id(pin_id)); |
| VTR_ASSERT(pin_port(pin_id) == port_id); |
| VTR_ASSERT(pin_port_bit(pin_id) == port_bit); |
| VTR_ASSERT(pin_net(pin_id) == net_id); |
| VTR_ASSERT(pin_is_constant(pin_id) == is_const); |
| VTR_ASSERT_SAFE(find_pin(port_id, port_bit) == pin_id); |
| |
| return pin_id; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| NetId Netlist<BlockId, PortId, PinId, NetId>::create_net(const std::string name) { |
| //Creates an empty net (or returns an existing one) |
| VTR_ASSERT_MSG(!name.empty(), "Valid net name"); |
| |
| //Check if the net has already been created |
| StringId name_id = create_string(name); |
| NetId net_id = find_net(name_id); |
| if (net_id == NetId::INVALID()) { |
| //Not found, create it |
| |
| //Reserve an id |
| net_id = NetId(net_ids_.size()); |
| net_ids_.push_back(net_id); |
| |
| //Initialize the data |
| net_names_.push_back(name_id); |
| |
| //Initialize the look-ups |
| net_name_to_net_id_.insert(name_id, net_id); |
| |
| //Initialize with no driver |
| net_pins_.emplace_back(); |
| net_pins_[net_id].emplace_back(PinId::INVALID()); |
| |
| VTR_ASSERT(net_pins_[net_id].size() == 1); |
| VTR_ASSERT(net_pins_[net_id][0] == PinId::INVALID()); |
| } |
| |
| //Check post-conditions: values |
| VTR_ASSERT(valid_net_id(net_id)); |
| VTR_ASSERT(net_name(net_id) == name); |
| VTR_ASSERT(find_net(name) == net_id); |
| |
| return net_id; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| NetId Netlist<BlockId, PortId, PinId, NetId>::add_net(const std::string name, PinId driver, std::vector<PinId> sinks) { |
| //Creates a net with a full set of pins |
| VTR_ASSERT_MSG(!find_net(name), "Net should not exist"); |
| |
| //Create the empty net |
| NetId net_id = create_net(name); |
| |
| //Set the driver and sinks of the net |
| auto& dest_pins = net_pins_[net_id]; |
| dest_pins[0] = driver; |
| dest_pins.insert(dest_pins.end(), |
| std::make_move_iterator(sinks.begin()), |
| std::make_move_iterator(sinks.end())); |
| |
| //Associate each pin with the net |
| int net_index = 0; |
| pin_nets_[driver] = net_id; |
| pin_net_indices_[driver] = net_index++; |
| for (auto sink : sinks) { |
| pin_nets_[sink] = net_id; |
| pin_net_indices_[sink] = net_index++; |
| } |
| |
| return net_id; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::set_pin_is_constant(const PinId pin_id, const bool value) { |
| VTR_ASSERT(valid_pin_id(pin_id)); |
| |
| pin_is_constant_[pin_id] = value; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::set_pin_net(const PinId pin, PinType type, const NetId net) { |
| VTR_ASSERT(valid_pin_id(pin)); |
| |
| VTR_ASSERT((type == PinType::DRIVER && pin_port_type(pin) == PortType::OUTPUT) |
| || (type == PinType::SINK && (pin_port_type(pin) == PortType::INPUT || pin_port_type(pin) == PortType::CLOCK))); |
| |
| NetId orig_net = pin_net(pin); |
| if (orig_net) { |
| //Clean up the pin reference on the original net |
| remove_net_pin(orig_net, pin); |
| } |
| |
| //Mark the pin's net |
| pin_nets_[pin] = net; |
| |
| //Add the pin to the net |
| int pins_net_index = associate_pin_with_net(pin, type, net); |
| |
| //Save the pin's index within the net |
| pin_net_indices_[pin] = pins_net_index; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::set_block_name(const BlockId blk_id, const std::string new_name) { |
| VTR_ASSERT(valid_block_id(blk_id)); |
| |
| //Names must be unique -- no duplicates allowed |
| BlockId existing_blk_id = find_block(new_name); |
| if (existing_blk_id) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Can not re-name block '%s' to '%s' (a block named '%s' already exists).", |
| block_name(blk_id).c_str(), |
| new_name.c_str(), |
| new_name.c_str()); |
| } |
| |
| //Remove old name-look-up |
| { |
| StringId old_string = find_string(block_name(blk_id)); |
| block_name_to_block_id_[old_string] = BlockId::INVALID(); |
| } |
| |
| //Re-name the block |
| StringId new_string = create_string(new_name); |
| block_names_[blk_id] = new_string; |
| |
| //Update name-look-up |
| block_name_to_block_id_.insert(new_string, blk_id); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::set_block_attr(const BlockId blk_id, const std::string& name, const std::string& value) { |
| VTR_ASSERT(valid_block_id(blk_id)); |
| |
| block_attrs_[blk_id][name] = value; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::set_block_param(const BlockId blk_id, const std::string& name, const std::string& value) { |
| VTR_ASSERT(valid_block_id(blk_id)); |
| |
| block_params_[blk_id][name] = value; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::merge_nets(const NetId driver_net, const NetId sink_net) { |
| VTR_ASSERT(valid_net_id(driver_net)); |
| VTR_ASSERT(valid_net_id(sink_net)); |
| |
| //Sink net must not have a driver pin |
| PinId sink_driver = net_driver(sink_net); |
| if (sink_driver) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Can not merge nets '%s' and '%s' (sink net '%s' should have no driver, but is driven by pin '%s')", |
| net_name(driver_net).c_str(), |
| net_name(sink_net).c_str(), |
| net_name(sink_net).c_str(), |
| pin_name(sink_driver).c_str()); |
| } |
| |
| //We allow the driver net to (potentially) have no driver yet, |
| //so we don't check to ensure it exists |
| |
| // |
| //Merge the nets |
| // |
| |
| //Move the sinks to the driver net |
| for (PinId sink_pin : net_sinks(sink_net)) { |
| //Update pin -> net references, also adds pins to driver_net |
| set_pin_net(sink_pin, pin_type(sink_pin), driver_net); |
| } |
| |
| //Remove the sink net |
| // Note that we drop the sink net's pin references first, |
| // this ensures remove_net() will only clean-up the net |
| // data, and will not modify the (already moved) pins |
| net_pins_[sink_net].clear(); //Drop sink_net's pin references |
| remove_net(sink_net); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::remove_block(const BlockId blk_id) { |
| VTR_ASSERT(valid_block_id(blk_id)); |
| |
| //Remove the ports |
| for (PortId block_port : block_ports(blk_id)) { |
| remove_port(block_port); |
| } |
| |
| //Invalidate look-up |
| StringId name_id = block_names_[blk_id]; |
| block_name_to_block_id_.insert(name_id, BlockId::INVALID()); |
| |
| //Mark as invalid |
| block_ids_[blk_id] = BlockId::INVALID(); |
| |
| //Call derived class' remove() |
| remove_block_impl(blk_id); |
| |
| //Mark netlist dirty |
| dirty_ = true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::remove_port(const PortId port_id) { |
| VTR_ASSERT(valid_port_id(port_id)); |
| |
| //Remove the pins |
| for (auto pin : port_pins(port_id)) { |
| if (valid_pin_id(pin)) { |
| remove_pin(pin); |
| } |
| } |
| |
| //Mark as invalid |
| port_ids_[port_id] = PortId::INVALID(); |
| |
| //Call derived class' remove() |
| remove_port_impl(port_id); |
| |
| //Mark netlist dirty |
| dirty_ = true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::remove_pin(const PinId pin_id) { |
| VTR_ASSERT(valid_pin_id(pin_id)); |
| |
| //Find the associated net |
| NetId net = pin_net(pin_id); |
| |
| //Remove the pin from the associated net/port/block |
| remove_net_pin(net, pin_id); |
| |
| //Mark as invalid |
| pin_ids_[pin_id] = PinId::INVALID(); |
| |
| //Call derived class' remove() |
| remove_pin_impl(pin_id); |
| |
| //Mark netlist dirty |
| dirty_ = true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::remove_net(const NetId net_id) { |
| VTR_ASSERT(valid_net_id(net_id)); |
| |
| //Disassociate the pins from the net |
| for (auto pin_id : net_pins(net_id)) { |
| if (pin_id) { |
| pin_nets_[pin_id] = NetId::INVALID(); |
| pin_net_indices_[pin_id] = INVALID_INDEX; |
| } |
| } |
| //Invalidate look-up |
| StringId name_id = net_names_[net_id]; |
| net_name_to_net_id_.insert(name_id, NetId::INVALID()); |
| |
| //Mark as invalid |
| net_ids_[net_id] = NetId::INVALID(); |
| |
| //Call derived class' remove() |
| remove_net_impl(net_id); |
| |
| //Mark netlist dirty |
| dirty_ = true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::remove_net_pin(const NetId net_id, const PinId pin_id) { |
| //Remove a net-pin connection |
| // |
| //Note that during sweeping either the net or pin could be invalid (i.e. already swept) |
| //so we check before trying to use them |
| |
| if (valid_net_id(net_id)) { |
| //Warning: this is slow! |
| auto iter = std::find(net_pins_[net_id].begin(), net_pins_[net_id].end(), pin_id); //Linear search |
| VTR_ASSERT(iter != net_pins_[net_id].end()); |
| |
| if (net_driver(net_id) == pin_id) { |
| //Mark no driver |
| net_pins_[net_id][0] = PinId::INVALID(); |
| } else { |
| //Remove sink |
| net_pins_[net_id].erase(iter); //Linear remove |
| } |
| |
| //Note: since we fully update the net we don't need to mark the netlist dirty_ |
| } |
| |
| //Disassociate the pin with the net |
| if (valid_pin_id(pin_id)) { |
| pin_nets_[pin_id] = NetId::INVALID(); |
| pin_net_indices_[pin_id] = INVALID_INDEX; |
| |
| //Mark netlist dirty, since we are leaving an invalid net id |
| dirty_ = true; |
| } |
| } |
| |
| /* |
| * |
| * Internal utilities |
| * |
| */ |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::IdRemapper Netlist<BlockId, PortId, PinId, NetId>::remove_and_compress() { |
| remove_unused(); |
| return compress(); |
| } |
| |
| //Compress the various netlist components to remove invalid entries |
| // Note: this invalidates all Ids |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::IdRemapper Netlist<BlockId, PortId, PinId, NetId>::compress() { |
| //Build the mappings from old to new id's, potentially |
| //re-ordering for improved cache locality |
| // |
| //The vectors passed as parameters are initialized as a mapping from old to new index |
| // e.g. block_id_map[old_id] == new_id |
| IdRemapper id_remapper = build_id_maps(); |
| |
| clean_nets(id_remapper.net_id_map_); |
| clean_pins(id_remapper.pin_id_map_); |
| clean_ports(id_remapper.port_id_map_); |
| clean_blocks(id_remapper.block_id_map_); |
| //TODO: clean strings |
| //TODO: iterative cleaning? |
| |
| //Now we re-build all the cross references |
| // Note: net references must be rebuilt (to remove pins) before |
| // the pin references can be rebuilt (to account for index changes |
| // due to pins being removed from the net) |
| rebuild_block_refs(id_remapper.pin_id_map_, id_remapper.port_id_map_); |
| rebuild_port_refs(id_remapper.block_id_map_, id_remapper.pin_id_map_); |
| rebuild_net_refs(id_remapper.pin_id_map_); |
| rebuild_pin_refs(id_remapper.port_id_map_, id_remapper.net_id_map_); |
| |
| //Re-build the lookups |
| rebuild_lookups(); |
| |
| //Resize containers to exact size |
| shrink_to_fit(); |
| |
| //Netlist is now clean |
| dirty_ = false; |
| |
| return id_remapper; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::remove_unused() { |
| //Mark any nets/pins/ports/blocks which are not in use as invalid |
| //so they will be removed |
| |
| bool found_unused; |
| do { |
| found_unused = false; |
| //Nets with no connected pins |
| for (auto net_id : net_ids_) { |
| if (net_id |
| && !net_driver(net_id) |
| && net_sinks(net_id).size() == 0) { |
| remove_net(net_id); |
| found_unused = true; |
| } |
| } |
| |
| //Pins with no connected nets |
| for (auto pin_id : pin_ids_) { |
| if (pin_id && !pin_net(pin_id)) { |
| remove_pin(pin_id); |
| found_unused = true; |
| } |
| } |
| |
| //Empty ports |
| for (auto port_id : port_ids_) { |
| if (port_id && port_pins(port_id).size() == 0) { |
| remove_port(port_id); |
| found_unused = true; |
| } |
| } |
| |
| //Blocks with no pins |
| for (auto blk_id : block_ids_) { |
| if (blk_id && block_pins(blk_id).size() == 0) { |
| remove_block(blk_id); |
| found_unused = true; |
| } |
| } |
| |
| } while (found_unused); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::IdRemapper Netlist<BlockId, PortId, PinId, NetId>::build_id_maps() { |
| IdRemapper id_remapper; |
| id_remapper.block_id_map_ = compress_ids(block_ids_); |
| id_remapper.port_id_map_ = compress_ids(port_ids_); |
| id_remapper.pin_id_map_ = compress_ids(pin_ids_); |
| id_remapper.net_id_map_ = compress_ids(net_ids_); |
| return id_remapper; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::clean_blocks(const vtr::vector_map<BlockId, BlockId>& block_id_map) { |
| //Update all the block values |
| block_ids_ = clean_and_reorder_ids(block_id_map); |
| block_names_ = clean_and_reorder_values(block_names_, block_id_map); |
| |
| block_pins_ = clean_and_reorder_values(block_pins_, block_id_map); |
| block_num_input_pins_ = clean_and_reorder_values(block_num_input_pins_, block_id_map); |
| block_num_output_pins_ = clean_and_reorder_values(block_num_output_pins_, block_id_map); |
| block_num_clock_pins_ = clean_and_reorder_values(block_num_clock_pins_, block_id_map); |
| |
| block_ports_ = clean_and_reorder_values(block_ports_, block_id_map); |
| block_num_input_ports_ = clean_and_reorder_values(block_num_input_ports_, block_id_map); |
| block_num_output_ports_ = clean_and_reorder_values(block_num_output_ports_, block_id_map); |
| block_num_clock_ports_ = clean_and_reorder_values(block_num_clock_ports_, block_id_map); |
| |
| block_attrs_ = clean_and_reorder_values(block_attrs_, block_id_map); |
| block_params_ = clean_and_reorder_values(block_params_, block_id_map); |
| |
| clean_blocks_impl(block_id_map); |
| |
| VTR_ASSERT(validate_block_sizes()); |
| |
| VTR_ASSERT_MSG(are_contiguous(block_ids_), "Ids should be contiguous"); |
| VTR_ASSERT_MSG(all_valid(block_ids_), "All Ids should be valid"); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::clean_ports(const vtr::vector_map<PortId, PortId>& port_id_map) { |
| //Update all the port values |
| port_ids_ = clean_and_reorder_ids(port_id_map); |
| port_names_ = clean_and_reorder_values(port_names_, port_id_map); |
| port_blocks_ = clean_and_reorder_values(port_blocks_, port_id_map); |
| port_widths_ = clean_and_reorder_values(port_widths_, port_id_map); |
| port_types_ = clean_and_reorder_values(port_types_, port_id_map); |
| port_pins_ = clean_and_reorder_values(port_pins_, port_id_map); |
| |
| clean_ports_impl(port_id_map); |
| |
| VTR_ASSERT(validate_port_sizes()); |
| |
| VTR_ASSERT_MSG(are_contiguous(port_ids_), "Ids should be contiguous"); |
| VTR_ASSERT_MSG(all_valid(port_ids_), "All Ids should be valid"); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::clean_pins(const vtr::vector_map<PinId, PinId>& pin_id_map) { |
| //Update all the pin values |
| pin_ids_ = clean_and_reorder_ids(pin_id_map); |
| pin_ports_ = clean_and_reorder_values(pin_ports_, pin_id_map); |
| |
| //It is sufficient to merely clean and re-order the pin_port_bits_, since |
| //the size of a port (and hence the pin's bit index in the port) does not change |
| //during cleaning |
| pin_port_bits_ = clean_and_reorder_values(pin_port_bits_, pin_id_map); |
| pin_nets_ = clean_and_reorder_values(pin_nets_, pin_id_map); |
| |
| //Note that clean and re-order serves only to resize pin_net_indices_, the |
| //actual net references are wrong (since net size may have changed during |
| //cleaning). They will be updated in rebuild_pin_refs() |
| pin_net_indices_ = clean_and_reorder_values(pin_net_indices_, pin_id_map); |
| pin_is_constant_ = clean_and_reorder_values(pin_is_constant_, pin_id_map); |
| |
| clean_pins_impl(pin_id_map); |
| |
| VTR_ASSERT(validate_pin_sizes()); |
| |
| VTR_ASSERT_MSG(are_contiguous(pin_ids_), "Ids should be contiguous"); |
| VTR_ASSERT_MSG(all_valid(pin_ids_), "All Ids should be valid"); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::clean_nets(const vtr::vector_map<NetId, NetId>& net_id_map) { |
| //Update all the net values |
| net_ids_ = clean_and_reorder_ids(net_id_map); |
| net_names_ = clean_and_reorder_values(net_names_, net_id_map); |
| net_pins_ = clean_and_reorder_values(net_pins_, net_id_map); //Note: actual pin refs are updated in rebuild_net_refs() |
| |
| clean_nets_impl(net_id_map); |
| |
| VTR_ASSERT(validate_net_sizes()); |
| |
| VTR_ASSERT_MSG(are_contiguous(net_ids_), "Ids should be contiguous"); |
| VTR_ASSERT_MSG(all_valid(net_ids_), "All Ids should be valid"); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::rebuild_lookups() { |
| //We iterate through the reverse-lookups and update the values (i.e. ids) |
| //to the new id values |
| |
| //Blocks |
| block_name_to_block_id_.clear(); |
| for (auto blk_id : blocks()) { |
| const auto& key = block_names_[blk_id]; |
| block_name_to_block_id_.insert(key, blk_id); |
| } |
| |
| //Nets |
| net_name_to_net_id_.clear(); |
| for (auto net_id : nets()) { |
| const auto& key = net_names_[net_id]; |
| net_name_to_net_id_.insert(key, net_id); |
| } |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::rebuild_block_refs(const vtr::vector_map<PinId, PinId>& pin_id_map, |
| const vtr::vector_map<PortId, PortId>& port_id_map) { |
| //Update the pin id references held by blocks |
| for (auto blk_id : blocks()) { |
| //Before update the references, we need to know how many are valid, |
| //so we can also update the numbers of input/output/clock pins |
| |
| //Note that we take special care to not modify the pin counts until after |
| //they have all been counted (since the block_*_pins() functions depend on |
| //the counts). |
| size_t num_input_pins = count_valid_refs(block_input_pins(blk_id), pin_id_map); |
| size_t num_output_pins = count_valid_refs(block_output_pins(blk_id), pin_id_map); |
| size_t num_clock_pins = count_valid_refs(block_clock_pins(blk_id), pin_id_map); |
| |
| std::vector<PinId>& pin_collection = block_pins_[blk_id]; |
| |
| pin_collection = update_valid_refs(pin_collection, pin_id_map); |
| block_num_input_pins_[blk_id] = num_input_pins; |
| block_num_output_pins_[blk_id] = num_output_pins; |
| block_num_clock_pins_[blk_id] = num_clock_pins; |
| |
| VTR_ASSERT_SAFE_MSG(all_valid(pin_collection), "All Ids should be valid"); |
| VTR_ASSERT(pin_collection.size() == size_t(block_num_input_pins_[blk_id] + block_num_output_pins_[blk_id] + block_num_clock_pins_[blk_id])); |
| |
| //Similarily for ports |
| size_t num_input_ports = count_valid_refs(block_input_ports(blk_id), port_id_map); |
| size_t num_output_ports = count_valid_refs(block_output_ports(blk_id), port_id_map); |
| size_t num_clock_ports = count_valid_refs(block_clock_ports(blk_id), port_id_map); |
| |
| std::vector<PortId>& blk_ports = block_ports_[blk_id]; |
| |
| blk_ports = update_valid_refs(blk_ports, port_id_map); |
| block_num_input_ports_[blk_id] = num_input_ports; |
| block_num_output_ports_[blk_id] = num_output_ports; |
| block_num_clock_ports_[blk_id] = num_clock_ports; |
| |
| VTR_ASSERT_SAFE_MSG(all_valid(blk_ports), "All Ids should be valid"); |
| VTR_ASSERT(blk_ports.size() == size_t(block_num_input_ports_[blk_id] + block_num_output_ports_[blk_id] + block_num_clock_ports_[blk_id])); |
| } |
| |
| rebuild_block_refs_impl(pin_id_map, port_id_map); |
| |
| VTR_ASSERT(validate_block_sizes()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::rebuild_port_refs(const vtr::vector_map<BlockId, BlockId>& block_id_map, |
| const vtr::vector_map<PinId, PinId>& pin_id_map) { |
| //Update block and pin references held by ports |
| port_blocks_ = update_valid_refs(port_blocks_, block_id_map); |
| VTR_ASSERT_SAFE_MSG(all_valid(port_blocks_), "All Ids should be valid"); |
| |
| VTR_ASSERT(port_blocks_.size() == port_ids_.size()); |
| |
| for (auto& pin_collection : port_pins_) { |
| pin_collection = update_valid_refs(pin_collection, pin_id_map); |
| VTR_ASSERT_SAFE_MSG(all_valid(pin_collection), "All Ids should be valid"); |
| } |
| |
| rebuild_port_refs_impl(block_id_map, pin_id_map); |
| |
| VTR_ASSERT(validate_port_sizes()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::rebuild_pin_refs(const vtr::vector_map<PortId, PortId>& port_id_map, |
| const vtr::vector_map<NetId, NetId>& net_id_map) { |
| //Update port and net references held by pins |
| pin_ports_ = update_all_refs(pin_ports_, port_id_map); |
| VTR_ASSERT_SAFE_MSG(all_valid(pin_ports_), "All Ids should be valid"); |
| |
| //NOTE: we do not need to update pin_port_bits_ since a pin's index within it's |
| //port will not change (since the port width's don't change when cleaned) |
| |
| pin_nets_ = update_all_refs(pin_nets_, net_id_map); |
| VTR_ASSERT_SAFE_MSG(all_valid(pin_nets_), "All Ids should be valid"); |
| |
| //We must carefully re-build the pin net indices from scratch, since cleaning |
| //may have changed the index of the pin within the net (e.g. if invalid pins |
| //were removed) |
| // |
| //Note that for this to work correctly, the net references must have already been re-built! |
| for (auto net : nets()) { |
| int i = 0; |
| for (auto pin : net_pins(net)) { |
| pin_net_indices_[pin] = i; |
| ++i; |
| } |
| } |
| |
| rebuild_pin_refs_impl(port_id_map, net_id_map); |
| |
| VTR_ASSERT(validate_pin_sizes()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::rebuild_net_refs(const vtr::vector_map<PinId, PinId>& pin_id_map) { |
| //Update pin references held by nets |
| for (auto& pin_collection : net_pins_) { |
| //We take special care to preserve the driver index, since an INVALID id is used |
| //to indicate an undriven net it should not be dropped during the update |
| pin_collection = update_valid_refs(pin_collection, pin_id_map, {NET_DRIVER_INDEX}); |
| |
| VTR_ASSERT_SAFE_MSG(all_valid(pin_collection), "All sinks should be valid"); |
| } |
| |
| rebuild_net_refs_impl(pin_id_map); |
| |
| VTR_ASSERT(validate_net_sizes()); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::shrink_to_fit() { |
| //Block data |
| block_ids_.shrink_to_fit(); |
| block_names_.shrink_to_fit(); |
| |
| block_pins_.shrink_to_fit(); |
| for (std::vector<PinId>& pin_collection : block_pins_) { |
| pin_collection.shrink_to_fit(); |
| } |
| block_num_input_pins_.shrink_to_fit(); |
| block_num_output_pins_.shrink_to_fit(); |
| block_num_clock_pins_.shrink_to_fit(); |
| |
| block_ports_.shrink_to_fit(); |
| for (auto& blk_ports : block_ports_) { |
| blk_ports.shrink_to_fit(); |
| } |
| block_num_input_ports_.shrink_to_fit(); |
| block_num_output_ports_.shrink_to_fit(); |
| block_num_clock_ports_.shrink_to_fit(); |
| |
| VTR_ASSERT(validate_block_sizes()); |
| |
| //Port data |
| port_ids_.shrink_to_fit(); |
| port_blocks_.shrink_to_fit(); |
| port_widths_.shrink_to_fit(); |
| port_types_.shrink_to_fit(); |
| port_pins_.shrink_to_fit(); |
| for (auto& pin_collection : port_pins_) { |
| pin_collection.shrink_to_fit(); |
| } |
| VTR_ASSERT(validate_port_sizes()); |
| |
| //Pin data |
| pin_ids_.shrink_to_fit(); |
| pin_ports_.shrink_to_fit(); |
| pin_port_bits_.shrink_to_fit(); |
| pin_nets_.shrink_to_fit(); |
| pin_is_constant_.shrink_to_fit(); |
| VTR_ASSERT(validate_pin_sizes()); |
| |
| //Net data |
| net_ids_.shrink_to_fit(); |
| net_names_.shrink_to_fit(); |
| net_pins_.shrink_to_fit(); |
| VTR_ASSERT(validate_net_sizes()); |
| |
| //String data |
| string_ids_.shrink_to_fit(); |
| strings_.shrink_to_fit(); |
| VTR_ASSERT(validate_string_sizes()); |
| } |
| |
| /* |
| * |
| * Sanity Checks |
| * |
| */ |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::valid_block_id(BlockId block_id) const { |
| if (block_id == BlockId::INVALID() |
| || !block_ids_.contains(block_id) |
| || block_ids_[block_id] != block_id) { |
| return false; |
| } |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::valid_port_id(PortId port_id) const { |
| if (port_id == PortId::INVALID() |
| || !port_ids_.contains(port_id) |
| || port_ids_[port_id] != port_id) { |
| return false; |
| } |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::valid_port_bit(PortId port_id, BitIndex port_bit) const { |
| VTR_ASSERT_SAFE(valid_port_id(port_id)); |
| if (port_bit >= port_width(port_id)) { |
| return false; |
| } |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::valid_pin_id(PinId pin_id) const { |
| if (pin_id == PinId::INVALID() |
| || !pin_ids_.contains(pin_id) |
| || pin_ids_[pin_id] != pin_id) { |
| return false; |
| } |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::valid_net_id(NetId net_id) const { |
| if (net_id == NetId::INVALID() |
| || !net_ids_.contains(net_id) |
| || net_ids_[net_id] != net_id) { |
| return false; |
| } |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::valid_string_id(typename Netlist<BlockId, PortId, PinId, NetId>::StringId string_id) const { |
| if (string_id == StringId::INVALID() |
| || !string_ids_.contains(string_id) |
| || string_ids_[string_id] != string_id) { |
| return false; |
| } |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::validate_block_sizes() const { |
| size_t num_blocks = blocks().size(); |
| if (block_names_.size() != num_blocks |
| || block_pins_.size() != num_blocks |
| || block_num_input_pins_.size() != num_blocks |
| || block_num_output_pins_.size() != num_blocks |
| || block_num_clock_pins_.size() != num_blocks |
| || block_ports_.size() != num_blocks |
| || block_num_input_ports_.size() != num_blocks |
| || block_num_output_ports_.size() != num_blocks |
| || block_num_clock_ports_.size() != num_blocks |
| || block_attrs_.size() != num_blocks |
| || block_params_.size() != num_blocks |
| || !validate_block_sizes_impl(num_blocks)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Inconsistent block data sizes"); |
| } |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::validate_port_sizes() const { |
| size_t num_ports = ports().size(); |
| if (port_names_.size() != num_ports |
| || port_blocks_.size() != num_ports |
| || port_pins_.size() != num_ports |
| || !validate_port_sizes_impl(num_ports)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Inconsistent port data sizes"); |
| } |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::validate_pin_sizes() const { |
| size_t num_pins = pins().size(); |
| if (pin_ports_.size() != num_pins |
| || pin_port_bits_.size() != num_pins |
| || pin_nets_.size() != num_pins |
| || pin_net_indices_.size() != num_pins |
| || pin_is_constant_.size() != num_pins |
| || !validate_pin_sizes_impl(num_pins)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Inconsistent pin data sizes"); |
| } |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::validate_net_sizes() const { |
| size_t num_nets = nets().size(); |
| if (net_names_.size() != num_nets |
| || net_pins_.size() != num_nets |
| || !validate_net_sizes_impl(num_nets)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Inconsistent net data sizes"); |
| } |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::validate_string_sizes() const { |
| if (strings_.size() != string_ids_.size()) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Inconsistent string data sizes"); |
| } |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::validate_block_port_refs() const { |
| //Verify that all block <-> port references are consistent |
| |
| //Track how many times we've seen each port from the blocks |
| vtr::vector_map<PortId, unsigned> seen_port_ids(port_ids_.size()); |
| |
| for (auto blk_id : blocks()) { |
| for (auto in_port_id : block_input_ports(blk_id)) { |
| if (blk_id != port_block(in_port_id)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Block-input port cross-reference does not match"); |
| } |
| ++seen_port_ids[in_port_id]; |
| } |
| for (auto out_port_id : block_output_ports(blk_id)) { |
| if (blk_id != port_block(out_port_id)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Block-output port cross-reference does not match"); |
| } |
| ++seen_port_ids[out_port_id]; |
| } |
| for (auto clock_port_id : block_clock_ports(blk_id)) { |
| if (blk_id != port_block(clock_port_id)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Block-clock port cross-reference does not match"); |
| } |
| ++seen_port_ids[clock_port_id]; |
| } |
| } |
| |
| //Check that we have neither orphaned ports (i.e. that aren't referenced by a block) |
| //nor shared ports (i.e. referenced by multiple blocks) |
| auto is_one = [](unsigned val) { |
| return val == 1; |
| }; |
| if (!std::all_of(seen_port_ids.begin(), seen_port_ids.end(), is_one)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Port not referenced by a single block"); |
| } |
| |
| if (std::accumulate(seen_port_ids.begin(), seen_port_ids.end(), 0u) != port_ids_.size()) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Found orphaned port (not referenced by a block)"); |
| } |
| |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::validate_block_pin_refs() const { |
| //Verify that block pin refs are consistent |
| //(e.g. inputs are inputs, outputs are outputs etc.) |
| for (auto blk_id : blocks()) { |
| //Check that only input pins are found when iterating through inputs |
| for (auto pin_id : block_input_pins(blk_id)) { |
| auto port_id = pin_port(pin_id); |
| |
| auto type = port_type(port_id); |
| if (type != PortType::INPUT) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Non-input pin in block input pins"); |
| } |
| } |
| |
| //Check that only output pins are found when iterating through outputs |
| for (auto pin_id : block_output_pins(blk_id)) { |
| auto port_id = pin_port(pin_id); |
| |
| auto type = port_type(port_id); |
| if (type != PortType::OUTPUT) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Non-output pin in block output pins"); |
| } |
| } |
| |
| //Check that only clock pins are found when iterating through clocks |
| for (auto pin_id : block_clock_pins(blk_id)) { |
| auto port_id = pin_port(pin_id); |
| |
| auto type = port_type(port_id); |
| if (type != PortType::CLOCK) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Non-clock pin in block clock pins"); |
| } |
| } |
| } |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::validate_port_pin_refs() const { |
| //Check that port <-> pin references are consistent |
| |
| //Track how many times we've seen each pin from the ports |
| vtr::vector_map<PinId, unsigned> seen_pin_ids(pin_ids_.size()); |
| |
| for (auto port_id : port_ids_) { |
| bool first_bit = true; |
| BitIndex prev_bit_index = 0; |
| for (auto pin_id : port_pins(port_id)) { |
| if (pin_port(pin_id) != port_id) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Port-pin cross-reference does not match"); |
| } |
| if (pin_port_bit(pin_id) >= port_width(port_id)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Out-of-range port bit index"); |
| } |
| ++seen_pin_ids[pin_id]; |
| |
| BitIndex port_bit_index = pin_port_bit(pin_id); |
| |
| //Verify that the port bit index is legal |
| if (!valid_port_bit(port_id, port_bit_index)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Invalid pin bit index in port"); |
| } |
| |
| //Verify that the pins are listed in increasing order of port bit index, |
| //we rely on this property to perform fast binary searches for pins with specific bit |
| //indicies |
| if (first_bit) { |
| prev_bit_index = port_bit_index; |
| first_bit = false; |
| } else if (prev_bit_index >= port_bit_index) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Port pin indicies are not in ascending order"); |
| } |
| } |
| } |
| |
| //Check that we have neither orphaned pins (i.e. that aren't referenced by a port) |
| //nor shared pins (i.e. referenced by multiple ports) |
| auto is_one = [](unsigned val) { |
| return val == 1; |
| }; |
| if (!std::all_of(seen_pin_ids.begin(), seen_pin_ids.end(), is_one)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Pins referenced by zero or multiple ports"); |
| } |
| |
| if (std::accumulate(seen_pin_ids.begin(), seen_pin_ids.end(), 0u) != pin_ids_.size()) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Found orphaned pins (not referenced by a port)"); |
| } |
| |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::validate_net_pin_refs() const { |
| //Check that net <-> pin references are consistent |
| |
| //Track how many times we've seen each pin from the ports |
| vtr::vector_map<PinId, unsigned> seen_pin_ids(pin_ids_.size()); |
| |
| for (auto net_id : nets()) { |
| auto pins_rng = net_pins(net_id); |
| for (auto iter = pins_rng.begin(); iter != pins_rng.end(); ++iter) { |
| int pin_index = std::distance(pins_rng.begin(), iter); |
| auto pin_id = *iter; |
| |
| if (iter == pins_rng.begin()) { |
| //The first net pin is the driver, which may be invalid |
| //if there is no driver. |
| if (pin_id) { |
| VTR_ASSERT(pin_index == NET_DRIVER_INDEX); |
| if (pin_type(pin_id) != PinType::DRIVER) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Driver pin not found at expected index in net"); |
| } |
| } |
| } else { |
| //Any non-driver (i.e. sink) pins must be valid |
| if (!pin_id) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Invalid pin found in net sinks"); |
| } |
| |
| if (pin_type(pin_id) != PinType::SINK) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Invalid pin type found in net sinks"); |
| } |
| } |
| |
| if (pin_id) { |
| //Verify the cross reference if the pin_id is valid (i.e. a sink or a valid driver) |
| if (pin_net(pin_id) != net_id) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Net-pin cross-reference does not match"); |
| } |
| |
| if (pin_net_index(pin_id) != pin_index) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Pin's net index cross-reference does not match actual net index"); |
| } |
| |
| //We only record valid seen pins since we may see multiple undriven nets with invalid IDs |
| ++seen_pin_ids[pin_id]; |
| } |
| } |
| } |
| |
| //Check that we have neither orphaned pins (i.e. that aren't referenced by a port) |
| //nor shared pins (i.e. referenced by multiple ports) |
| auto is_one = [](unsigned val) { |
| return val == 1; |
| }; |
| if (!std::all_of(seen_pin_ids.begin(), seen_pin_ids.end(), is_one)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Found pins referenced by zero or multiple nets"); |
| } |
| |
| if (std::accumulate(seen_pin_ids.begin(), seen_pin_ids.end(), 0u) != pin_ids_.size()) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Found orphaned pins (not referenced by a net)"); |
| } |
| |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::validate_string_refs() const { |
| for (const auto& str_id : block_names_) { |
| if (!valid_string_id(str_id)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Invalid block name string reference"); |
| } |
| } |
| for (const auto& str_id : port_names_) { |
| if (!valid_string_id(str_id)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Invalid port name string reference"); |
| } |
| } |
| for (const auto& str_id : net_names_) { |
| if (!valid_string_id(str_id)) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Invalid net name string reference"); |
| } |
| } |
| return true; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| bool Netlist<BlockId, PortId, PinId, NetId>::verify_block_invariants() const { |
| for (auto blk_id : blocks()) { |
| //Check block type |
| //Find any connected clock |
| NetId clk_net_id; |
| for (auto pin_id : block_clock_pins(blk_id)) { |
| if (pin_id) { |
| clk_net_id = pin_net(pin_id); |
| break; |
| } |
| } |
| |
| if (block_is_combinational(blk_id)) { |
| //Non-sequential types must not have a clock |
| if (clk_net_id) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Block '%s' is a non-sequential type but has a clock '%s'", |
| block_name(blk_id).c_str(), net_name(clk_net_id).c_str()); |
| } |
| |
| } else { |
| //Sequential types must have a clock |
| if (!clk_net_id) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Block '%s' is sequential type but has no clock", |
| block_name(blk_id).c_str()); |
| } |
| } |
| |
| //Check that block pins and ports are consistent (i.e. same number of pins) |
| size_t num_block_pins = block_pins(blk_id).size(); |
| |
| size_t total_block_port_pins = 0; |
| for (auto port_id : block_ports(blk_id)) { |
| total_block_port_pins += port_pins(port_id).size(); |
| } |
| |
| if (num_block_pins != total_block_port_pins) { |
| VPR_FATAL_ERROR(VPR_ERROR_NETLIST, "Block pins and port pins do not match on block '%s'", |
| block_name(blk_id).c_str()); |
| } |
| } |
| |
| return true; |
| } |
| |
| /* |
| * |
| * Internal utilities |
| * |
| */ |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::StringId Netlist<BlockId, PortId, PinId, NetId>::find_string(const std::string& str) const { |
| auto iter = string_to_string_id_.find(str); |
| if (iter != string_to_string_id_.end()) { |
| StringId str_id = iter->second; |
| |
| VTR_ASSERT_SAFE(str_id); |
| VTR_ASSERT_SAFE(strings_[str_id] == str); |
| |
| return str_id; |
| } else { |
| return StringId::INVALID(); |
| } |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| BlockId Netlist<BlockId, PortId, PinId, NetId>::find_block(const typename Netlist<BlockId, PortId, PinId, NetId>::StringId name_id) const { |
| VTR_ASSERT_SAFE(valid_string_id(name_id)); |
| auto iter = block_name_to_block_id_.find(name_id); |
| if (iter != block_name_to_block_id_.end()) { |
| BlockId blk_id = *iter; |
| |
| //Check post-conditions |
| if (blk_id) { |
| VTR_ASSERT_SAFE(valid_block_id(blk_id)); |
| VTR_ASSERT_SAFE(block_names_[blk_id] == name_id); |
| } |
| |
| return blk_id; |
| } else { |
| return BlockId::INVALID(); |
| } |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::associate_pin_with_block(const PinId pin_id, const PortType type, const BlockId blk_id) { |
| //Get an interator pointing to where we want to insert |
| pin_iterator iter; |
| if (type == PortType::INPUT) { |
| iter = block_input_pins(blk_id).end(); |
| ++block_num_input_pins_[blk_id]; |
| } else if (type == PortType::OUTPUT) { |
| iter = block_output_pins(blk_id).end(); |
| ++block_num_output_pins_[blk_id]; |
| } else { |
| VTR_ASSERT(type == PortType::CLOCK); |
| iter = block_clock_pins(blk_id).end(); |
| ++block_num_clock_pins_[blk_id]; |
| } |
| |
| //Insert the element just before iter |
| auto new_iter = block_pins_[blk_id].insert(iter, pin_id); |
| |
| //Inserted value should be the last valid range element |
| if (type == PortType::INPUT) { |
| VTR_ASSERT(new_iter + 1 == block_input_pins(blk_id).end()); |
| VTR_ASSERT(new_iter + 1 == block_output_pins(blk_id).begin()); |
| } else if (type == PortType::OUTPUT) { |
| VTR_ASSERT(new_iter + 1 == block_output_pins(blk_id).end()); |
| VTR_ASSERT(new_iter + 1 == block_clock_pins(blk_id).begin()); |
| } else { |
| VTR_ASSERT(type == PortType::CLOCK); |
| VTR_ASSERT(new_iter + 1 == block_clock_pins(blk_id).end()); |
| VTR_ASSERT(new_iter + 1 == block_pins(blk_id).end()); |
| } |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| int Netlist<BlockId, PortId, PinId, NetId>::associate_pin_with_net(const PinId pin_id, const PinType type, const NetId net_id) { |
| //Add the pin to the net |
| if (type == PinType::DRIVER) { |
| VTR_ASSERT_MSG(net_pins_[net_id].size() > 0, "Must be space for net's pin"); |
| VTR_ASSERT_MSG(net_pins_[net_id][0] == PinId::INVALID(), "Must be no existing net driver"); |
| |
| net_pins_[net_id][0] = pin_id; //Set driver |
| |
| return 0; //Driver always at index 0 |
| } else { |
| VTR_ASSERT(type == PinType::SINK); |
| |
| net_pins_[net_id].emplace_back(pin_id); //Add sink |
| |
| return net_pins_[net_id].size() - 1; //Index of inserted pin |
| } |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::associate_pin_with_port(const PinId pin_id, const PortId port_id) { |
| //A ports pins are stored in ascending order of port bit index, to allow for fast look-ups. |
| //As a result we need to ensure that even if pins are created out-of-order (with respect |
| //to port bit) they are still inserted in the port in sorted order. |
| // |
| //As a result we find the correct position using std::lower_bound and insert there. |
| //Note that in the typical case (when port pins are created in order) this will be |
| //the end of the port's pins and the insertion will be efficient. Only in the (more |
| //unusual) case where the pins are created out-of-order will we need to do a slow |
| //insert in the middle of the vector. |
| auto port_bit_cmp = [&](const PinId pin, BitIndex bit_index) { |
| return pin_port_bit(pin) < bit_index; |
| }; |
| auto iter = std::lower_bound(port_pins_[port_id].begin(), port_pins_[port_id].end(), pin_port_bit(pin_id), port_bit_cmp); |
| port_pins_[port_id].insert(iter, pin_id); |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| void Netlist<BlockId, PortId, PinId, NetId>::associate_port_with_block(const PortId port_id, const PortType type, const BlockId blk_id) { |
| //Associate the port with the blocks inputs/outputs/clocks |
| |
| //Get an interator pointing to where we want to insert |
| port_iterator iter; |
| if (type == PortType::INPUT) { |
| iter = block_input_ports(blk_id).end(); |
| ++block_num_input_ports_[blk_id]; |
| } else if (type == PortType::OUTPUT) { |
| iter = block_output_ports(blk_id).end(); |
| ++block_num_output_ports_[blk_id]; |
| } else { |
| VTR_ASSERT(type == PortType::CLOCK); |
| iter = block_clock_ports(blk_id).end(); |
| ++block_num_clock_ports_[blk_id]; |
| } |
| |
| //Insert the element just before iter |
| auto new_iter = block_ports_[blk_id].insert(iter, port_id); |
| |
| //Inserted value should be the last valid range element |
| if (type == PortType::INPUT) { |
| VTR_ASSERT(new_iter + 1 == block_input_ports(blk_id).end()); |
| VTR_ASSERT(new_iter + 1 == block_output_ports(blk_id).begin()); |
| } else if (type == PortType::OUTPUT) { |
| VTR_ASSERT(new_iter + 1 == block_output_ports(blk_id).end()); |
| VTR_ASSERT(new_iter + 1 == block_clock_ports(blk_id).begin()); |
| } else { |
| VTR_ASSERT(type == PortType::CLOCK); |
| VTR_ASSERT(new_iter + 1 == block_clock_ports(blk_id).end()); |
| VTR_ASSERT(new_iter + 1 == block_ports(blk_id).end()); |
| } |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| typename Netlist<BlockId, PortId, PinId, NetId>::StringId Netlist<BlockId, PortId, PinId, NetId>::create_string(const std::string& str) { |
| StringId str_id = find_string(str); |
| if (!str_id) { |
| //Not found, create |
| |
| //Reserve an id |
| str_id = StringId(string_ids_.size()); |
| string_ids_.push_back(str_id); |
| |
| //Store the reverse look-up |
| auto key = str; |
| string_to_string_id_[key] = str_id; |
| |
| //Initialize the data |
| strings_.emplace_back(str); |
| } |
| |
| //Check post-conditions: sizes |
| VTR_ASSERT(string_to_string_id_.size() == string_ids_.size()); |
| VTR_ASSERT(strings_.size() == string_ids_.size()); |
| |
| //Check post-conditions: values |
| VTR_ASSERT(strings_[str_id] == str); |
| VTR_ASSERT_SAFE(find_string(str) == str_id); |
| |
| return str_id; |
| } |
| |
| template<typename BlockId, typename PortId, typename PinId, typename NetId> |
| NetId Netlist<BlockId, PortId, PinId, NetId>::find_net(const typename Netlist<BlockId, PortId, PinId, NetId>::StringId name_id) const { |
| VTR_ASSERT_SAFE(valid_string_id(name_id)); |
| auto iter = net_name_to_net_id_.find(name_id); |
| if (iter != net_name_to_net_id_.end()) { |
| NetId net_id = *iter; |
| |
| if (net_id) { |
| //Check post-conditions |
| VTR_ASSERT_SAFE(valid_net_id(net_id)); |
| VTR_ASSERT_SAFE(net_names_[net_id] == name_id); |
| } |
| |
| return net_id; |
| } else { |
| return NetId::INVALID(); |
| } |
| } |