| /* | |
| * 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)); | |
| } | |
| } |