blob: a8215e35f7adf63c0441f3554c2673a50c73ed40 [file] [log] [blame]
/*
* 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