blob: 12917786b4301430af049493ccb83fe22bf0554c [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 <cstdint>
#include <iostream>
#include <vector>
#include <absl/types/span.h>
#include <gtest/gtest.h>
#include <prjxray/memory_mapped_file.h>
#include <prjxray/xilinx/architectures.h>
#include <prjxray/xilinx/bitstream_reader.h>
#include <prjxray/xilinx/configuration.h>
#include <prjxray/xilinx/configuration_packet.h>
#include <prjxray/xilinx/configuration_register.h>
#include <prjxray/xilinx/frames.h>
#include <yaml-cpp/yaml.h>
using namespace prjxray::xilinx;
TEST(ConfigurationTest, ConstructFromPacketsWithSingleFrame) {
std::vector<Series7::FrameAddress> test_part_addresses;
test_part_addresses.push_back(0x4567);
test_part_addresses.push_back(0x4568);
xc7series::Part test_part(0x1234, test_part_addresses);
std::vector<uint32_t> idcode{0x1234};
std::vector<uint32_t> cmd{0x0001};
std::vector<uint32_t> frame_address{0x4567};
std::vector<uint32_t> frame(101, 0xAA);
std::vector<ConfigurationPacket<Series7::ConfRegType>> packets{
{
static_cast<unsigned int>(0x1),
ConfigurationPacket<Series7::ConfRegType>::Opcode::Write,
Series7::ConfRegType::IDCODE,
absl::MakeSpan(idcode),
},
{
static_cast<unsigned int>(0x1),
ConfigurationPacket<Series7::ConfRegType>::Opcode::Write,
Series7::ConfRegType::FAR,
absl::MakeSpan(frame_address),
},
{
static_cast<unsigned int>(0x1),
ConfigurationPacket<Series7::ConfRegType>::Opcode::Write,
Series7::ConfRegType::CMD,
absl::MakeSpan(cmd),
},
{
static_cast<unsigned int>(0x1),
ConfigurationPacket<Series7::ConfRegType>::Opcode::Write,
Series7::ConfRegType::FDRI,
absl::MakeSpan(frame),
},
};
auto test_config =
Configuration<Series7>::InitWithPackets(test_part, packets);
ASSERT_TRUE(test_config);
EXPECT_EQ(test_config->part().idcode(), static_cast<uint32_t>(0x1234));
EXPECT_EQ(test_config->frames().size(), static_cast<size_t>(1));
EXPECT_EQ(test_config->frames().at(0x4567), frame);
}
TEST(ConfigurationTest, ConstructFromPacketsWithAutoincrement) {
std::vector<xc7series::FrameAddress> test_part_addresses;
for (int ii = 0x4560; ii < 0x4570; ++ii) {
test_part_addresses.push_back(ii);
}
for (int ii = 0x4580; ii < 0x4590; ++ii) {
test_part_addresses.push_back(ii);
}
xc7series::Part test_part(0x1234, test_part_addresses);
std::vector<uint32_t> idcode{0x1234};
std::vector<uint32_t> cmd{0x0001};
std::vector<uint32_t> frame_address{0x456F};
std::vector<uint32_t> frame(202, 0xAA);
std::fill_n(frame.begin() + 101, 101, 0xBB);
std::vector<ConfigurationPacket<Series7::ConfRegType>> packets{
{
static_cast<unsigned int>(0x1),
ConfigurationPacket<Series7::ConfRegType>::Opcode::Write,
Series7::ConfRegType::IDCODE,
absl::MakeSpan(idcode),
},
{
static_cast<unsigned int>(0x1),
ConfigurationPacket<Series7::ConfRegType>::Opcode::Write,
Series7::ConfRegType::FAR,
absl::MakeSpan(frame_address),
},
{
static_cast<unsigned int>(0x1),
ConfigurationPacket<Series7::ConfRegType>::Opcode::Write,
Series7::ConfRegType::CMD,
absl::MakeSpan(cmd),
},
{
static_cast<unsigned int>(0x1),
ConfigurationPacket<Series7::ConfRegType>::Opcode::Write,
Series7::ConfRegType::FDRI,
absl::MakeSpan(frame),
},
};
auto test_config =
Configuration<Series7>::InitWithPackets(test_part, packets);
ASSERT_TRUE(test_config);
absl::Span<uint32_t> frame_span(frame);
EXPECT_EQ(test_config->part().idcode(), static_cast<uint32_t>(0x1234));
EXPECT_EQ(test_config->frames().size(), static_cast<size_t>(2));
EXPECT_EQ(test_config->frames().at(0x456F),
std::vector<uint32_t>(101, 0xAA));
EXPECT_EQ(test_config->frames().at(0x4580),
std::vector<uint32_t>(101, 0xBB));
}
TEST(ConfigurationTest,
DebugAndPerFrameCrcBitstreamsProduceEqualConfigurations) {
auto part = xc7series::Part::FromFile("configuration_test.yaml");
ASSERT_TRUE(part);
auto debug_bitstream = prjxray::MemoryMappedFile::InitWithFile(
"configuration_test.debug.bit");
ASSERT_TRUE(debug_bitstream);
auto debug_reader = BitstreamReader<Series7>::InitWithBytes(
debug_bitstream->as_bytes());
ASSERT_TRUE(debug_reader);
auto debug_configuration =
Configuration<Series7>::InitWithPackets(*part, *debug_reader);
ASSERT_TRUE(debug_configuration);
auto perframecrc_bitstream = prjxray::MemoryMappedFile::InitWithFile(
"configuration_test.perframecrc.bit");
ASSERT_TRUE(perframecrc_bitstream);
auto perframecrc_reader = BitstreamReader<Series7>::InitWithBytes(
perframecrc_bitstream->as_bytes());
ASSERT_TRUE(perframecrc_reader);
auto perframecrc_configuration =
Configuration<Series7>::InitWithPackets(*part, *perframecrc_reader);
ASSERT_TRUE(perframecrc_configuration);
for (auto debug_frame : debug_configuration->frames()) {
auto perframecrc_frame =
perframecrc_configuration->frames().find(debug_frame.first);
if (perframecrc_frame ==
perframecrc_configuration->frames().end()) {
ADD_FAILURE() << debug_frame.first
<< ": missing in perframecrc bitstream";
continue;
}
for (int ii = 0; ii < 101; ++ii) {
EXPECT_EQ(perframecrc_frame->second[ii],
debug_frame.second[ii])
<< debug_frame.first << ": word " << ii;
}
}
for (auto perframecrc_frame : perframecrc_configuration->frames()) {
auto debug_frame =
debug_configuration->frames().find(perframecrc_frame.first);
if (debug_frame == debug_configuration->frames().end()) {
ADD_FAILURE() << perframecrc_frame.first
<< ": unexpectedly present in "
"perframecrc bitstream";
}
}
}
TEST(ConfigurationTest, DebugAndNormalBitstreamsProduceEqualConfigurations) {
auto part = xc7series::Part::FromFile("configuration_test.yaml");
ASSERT_TRUE(part);
auto debug_bitstream = prjxray::MemoryMappedFile::InitWithFile(
"configuration_test.debug.bit");
ASSERT_TRUE(debug_bitstream);
auto debug_reader = BitstreamReader<Series7>::InitWithBytes(
debug_bitstream->as_bytes());
ASSERT_TRUE(debug_reader);
auto debug_configuration =
Configuration<Series7>::InitWithPackets(*part, *debug_reader);
ASSERT_TRUE(debug_configuration);
auto normal_bitstream =
prjxray::MemoryMappedFile::InitWithFile("configuration_test.bit");
ASSERT_TRUE(normal_bitstream);
auto normal_reader = BitstreamReader<Series7>::InitWithBytes(
normal_bitstream->as_bytes());
ASSERT_TRUE(normal_reader);
auto normal_configuration =
Configuration<Series7>::InitWithPackets(*part, *normal_reader);
ASSERT_TRUE(normal_configuration);
for (auto debug_frame : debug_configuration->frames()) {
auto normal_frame =
normal_configuration->frames().find(debug_frame.first);
if (normal_frame == normal_configuration->frames().end()) {
ADD_FAILURE() << debug_frame.first
<< ": missing in normal bitstream";
continue;
}
for (int ii = 0; ii < 101; ++ii) {
EXPECT_EQ(normal_frame->second[ii],
debug_frame.second[ii])
<< debug_frame.first << ": word " << ii;
}
}
for (auto normal_frame : normal_configuration->frames()) {
auto debug_frame =
debug_configuration->frames().find(normal_frame.first);
if (debug_frame == debug_configuration->frames().end()) {
ADD_FAILURE()
<< normal_frame.first
<< ": unexpectedly present in normal bitstream";
}
}
}
TEST(ConfigurationTest, CheckForPaddingFrames) {
std::vector<xc7series::FrameAddress> test_part_addresses = {
xc7series::FrameAddress(xc7series::BlockType::CLB_IO_CLK, false, 0,
0, 0),
xc7series::FrameAddress(xc7series::BlockType::CLB_IO_CLK, true, 0,
0, 0),
xc7series::FrameAddress(xc7series::BlockType::CLB_IO_CLK, true, 1,
0, 0),
xc7series::FrameAddress(xc7series::BlockType::BLOCK_RAM, false, 0,
0, 0),
xc7series::FrameAddress(xc7series::BlockType::BLOCK_RAM, false, 1,
0, 0)};
auto test_part = absl::optional<xc7series::Part>(
xc7series::Part(0x1234, test_part_addresses));
Frames<Series7> frames;
frames.getFrames().emplace(std::make_pair(
test_part_addresses.at(0), std::vector<uint32_t>(101, 0xAA)));
frames.getFrames().emplace(std::make_pair(
test_part_addresses.at(1), std::vector<uint32_t>(101, 0xBB)));
frames.getFrames().emplace(std::make_pair(
test_part_addresses.at(2), std::vector<uint32_t>(101, 0xCC)));
frames.getFrames().emplace(std::make_pair(
test_part_addresses.at(3), std::vector<uint32_t>(101, 0xDD)));
frames.getFrames().emplace(std::make_pair(
test_part_addresses.at(4), std::vector<uint32_t>(101, 0xEE)));
ASSERT_EQ(frames.getFrames().size(), 5);
Configuration<Series7>::PacketData packet_data =
Configuration<Series7>::createType2ConfigurationPacketData(
frames.getFrames(), test_part);
// createType2ConfigurationPacketData should detect 4
// row/half/block_type switches thus add 4*2 padding frames moreover 2
// extra padding frames are added at the end of the creation of the data
// overall this gives us: 5(real frames) + 4*2 + 2 = 15 frames, which is
// 15 * 101 = 1515 words
EXPECT_EQ(packet_data.size(), 15 * 101);
std::vector<uint32_t> idcode{0x1234};
std::vector<uint32_t> cmd{0x0001};
std::vector<uint32_t> frame_address{0x0};
std::vector<ConfigurationPacket<Series7::ConfRegType>> packets{
{
static_cast<unsigned int>(0x1),
ConfigurationPacket<Series7::ConfRegType>::Opcode::Write,
Series7::ConfRegType::IDCODE,
absl::MakeSpan(idcode),
},
{
static_cast<unsigned int>(0x1),
ConfigurationPacket<Series7::ConfRegType>::Opcode::Write,
Series7::ConfRegType::FAR,
absl::MakeSpan(frame_address),
},
{
static_cast<unsigned int>(0x1),
ConfigurationPacket<Series7::ConfRegType>::Opcode::Write,
Series7::ConfRegType::CMD,
absl::MakeSpan(cmd),
},
{
static_cast<unsigned int>(0x1),
ConfigurationPacket<Series7::ConfRegType>::Opcode::Write,
Series7::ConfRegType::FDRI,
absl::MakeSpan(packet_data),
},
};
auto test_config =
Configuration<Series7>::InitWithPackets(*test_part, packets);
ASSERT_EQ(test_config->frames().size(), 5);
for (auto& frame : test_config->frames()) {
EXPECT_EQ(frame.second, frames.getFrames().at(frame.first));
}
}