mirror of https://github.com/openXC7/prjxray.git
125 lines
3.4 KiB
C++
125 lines
3.4 KiB
C++
/*
|
|
* 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/xc7series/part.h>
|
|
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
|
|
namespace prjxray {
|
|
namespace xilinx {
|
|
namespace xc7series {
|
|
|
|
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(), true, 0, 0, 0);
|
|
if (bottom_region_.IsValidFrameAddress(*next_address))
|
|
return next_address;
|
|
}
|
|
|
|
// Block types are next numerically.
|
|
if (address.block_type() < BlockType::BLOCK_RAM) {
|
|
next_address =
|
|
FrameAddress(BlockType::BLOCK_RAM, false, 0, 0, 0);
|
|
if (IsValidFrameAddress(*next_address))
|
|
return next_address;
|
|
}
|
|
|
|
if (address.block_type() < BlockType::CFG_CLB) {
|
|
next_address = FrameAddress(BlockType::CFG_CLB, false, 0, 0, 0);
|
|
if (IsValidFrameAddress(*next_address))
|
|
return next_address;
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
} // namespace xc7series
|
|
} // namespace xilinx
|
|
} // namespace prjxray
|
|
|
|
namespace xc7series = prjxray::xilinx::xc7series;
|
|
|
|
namespace YAML {
|
|
|
|
Node convert<xc7series::Part>::encode(const xc7series::Part& rhs) {
|
|
Node node;
|
|
node.SetTag("xilinx/xc7series/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<xc7series::Part>::decode(const Node& node, xc7series::Part& lhs) {
|
|
if (!node.Tag().empty() && node.Tag() != "xilinx/xc7series/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<xc7series::GlobalClockRegion>();
|
|
lhs.bottom_region_ = node["global_clock_regions"]["bottom"]
|
|
.as<xc7series::GlobalClockRegion>();
|
|
} else if (node["configuration_ranges"]) {
|
|
std::vector<xc7series::FrameAddress> addresses;
|
|
for (auto range : node["configuration_ranges"]) {
|
|
auto begin =
|
|
range["begin"].as<xc7series::FrameAddress>();
|
|
auto end = range["end"].as<xc7series::FrameAddress>();
|
|
for (uint32_t cur = begin; cur < end; ++cur) {
|
|
addresses.push_back(cur);
|
|
}
|
|
}
|
|
|
|
lhs = xc7series::Part(lhs.idcode_, addresses);
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
} // namespace YAML
|