| /* |
| * Copyright (C) 2017-2020 The Project X-Ray Authors. |
| * |
| * Use of this source code is governed by a ISC-style |
| * license that can be found in the LICENSE file or at |
| * https://opensource.org/licenses/ISC |
| * |
| * SPDX-License-Identifier: ISC |
| */ |
| #include <prjxray/xilinx/spartan6/part.h> |
| |
| #include <iomanip> |
| #include <iostream> |
| #include <sstream> |
| |
| namespace prjxray { |
| namespace xilinx { |
| namespace spartan6 { |
| |
| absl::optional<Part> Part::FromFile(const std::string& path) { |
| try { |
| YAML::Node yaml = YAML::LoadFile(path); |
| return yaml.as<Part>(); |
| } catch (YAML::Exception& e) { |
| return {}; |
| } |
| } |
| |
| bool Part::IsValidFrameAddress(FrameAddress address) const { |
| if (address.is_bottom_half_rows()) { |
| return bottom_region_.IsValidFrameAddress(address); |
| } else { |
| return top_region_.IsValidFrameAddress(address); |
| } |
| } |
| |
| absl::optional<FrameAddress> Part::GetNextFrameAddress( |
| FrameAddress address) const { |
| // Ask the current global clock region first. |
| absl::optional<FrameAddress> next_address = |
| (address.is_bottom_half_rows() |
| ? bottom_region_.GetNextFrameAddress(address) |
| : top_region_.GetNextFrameAddress(address)); |
| if (next_address) |
| return next_address; |
| |
| // If the current address is in the top region, the bottom region is |
| // next numerically. |
| if (!address.is_bottom_half_rows()) { |
| next_address = FrameAddress(address.block_type(), 0, 0, 0); |
| if (bottom_region_.IsValidFrameAddress(*next_address)) |
| return next_address; |
| } |
| |
| // Block types are next numerically. |
| if (address.block_type() < spartan6::BlockType::BLOCK_RAM) { |
| next_address = |
| FrameAddress(spartan6::BlockType::BLOCK_RAM, 0, 0, 0); |
| if (IsValidFrameAddress(*next_address)) |
| return next_address; |
| } |
| |
| if (address.block_type() < spartan6::BlockType::IOB) { |
| next_address = FrameAddress(spartan6::BlockType::IOB, 0, 0, 0); |
| if (IsValidFrameAddress(*next_address)) |
| return next_address; |
| } |
| |
| return {}; |
| } |
| |
| } // namespace spartan6 |
| } // namespace xilinx |
| } // namespace prjxray |
| |
| namespace spartan6 = prjxray::xilinx::spartan6; |
| |
| namespace YAML { |
| |
| Node convert<spartan6::Part>::encode(const spartan6::Part& rhs) { |
| Node node; |
| node.SetTag("xilinx/spartan6/part"); |
| |
| std::ostringstream idcode_str; |
| idcode_str << "0x" << std::hex << rhs.idcode_; |
| node["idcode"] = idcode_str.str(); |
| node["global_clock_regions"]["top"] = rhs.top_region_; |
| node["global_clock_regions"]["bottom"] = rhs.bottom_region_; |
| return node; |
| } |
| |
| bool convert<spartan6::Part>::decode(const Node& node, spartan6::Part& lhs) { |
| if (!node.Tag().empty() && node.Tag() != "xilinx/spartan6/part") |
| return false; |
| |
| if (!node["global_clock_regions"] && !node["configuration_ranges"]) { |
| return false; |
| } |
| |
| lhs.idcode_ = node["idcode"].as<uint32_t>(); |
| |
| if (node["global_clock_regions"]) { |
| lhs.top_region_ = node["global_clock_regions"]["top"] |
| .as<spartan6::GlobalClockRegion>(); |
| lhs.bottom_region_ = node["global_clock_regions"]["bottom"] |
| .as<spartan6::GlobalClockRegion>(); |
| } else if (node["configuration_ranges"]) { |
| std::vector<spartan6::FrameAddress> addresses; |
| for (auto range : node["configuration_ranges"]) { |
| auto begin = |
| range["begin"].as<spartan6::FrameAddress>(); |
| auto end = range["end"].as<spartan6::FrameAddress>(); |
| for (uint32_t cur = begin; cur < end; ++cur) { |
| addresses.push_back(cur); |
| } |
| } |
| |
| lhs = spartan6::Part(lhs.idcode_, addresses); |
| } |
| |
| return true; |
| }; |
| |
| } // namespace YAML |