| /* |
| * 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 <array> |
| |
| #include <gtest/gtest.h> |
| #include <prjxray/xilinx/bitstream_reader.h> |
| #include <prjxray/xilinx/bitstream_writer.h> |
| #include <prjxray/xilinx/configuration_packet.h> |
| #include <prjxray/xilinx/configuration_register.h> |
| |
| #include <prjxray/bit_ops.h> |
| |
| using namespace prjxray::xilinx; |
| |
| constexpr uint32_t kType1NOP = prjxray::bit_field_set<uint32_t>(0, 31, 29, 0x1); |
| |
| constexpr uint32_t MakeType1(const int opcode, |
| const int address, |
| const int word_count) { |
| return prjxray::bit_field_set<uint32_t>( |
| prjxray::bit_field_set<uint32_t>( |
| prjxray::bit_field_set<uint32_t>( |
| prjxray::bit_field_set<uint32_t>(0x0, 31, 29, 0x1), 28, 27, |
| opcode), |
| 26, 13, address), |
| 10, 0, word_count); |
| } |
| |
| constexpr uint32_t MakeType2(const int opcode, const int word_count) { |
| return prjxray::bit_field_set<uint32_t>( |
| prjxray::bit_field_set<uint32_t>( |
| prjxray::bit_field_set<uint32_t>(0x0, 31, 29, 0x2), 28, 27, |
| opcode), |
| 26, 0, word_count); |
| } |
| |
| void dump_packets(BitstreamWriter<Series7> writer, bool nl = true) { |
| int i = 0; |
| // for (uint32_t x : itr) { |
| for (auto itr = writer.begin(); itr != writer.end(); ++itr) { |
| if (nl) { |
| printf("% 3d: 0x0%08X\n", i, *itr); |
| } else { |
| printf("0x0%08X, ", *itr); |
| } |
| fflush(stdout); |
| ++i; |
| } |
| if (!nl) { |
| printf("\n"); |
| } |
| } |
| |
| // Special all 0's |
| void AddType0( |
| std::vector<std::unique_ptr<ConfigurationPacket<Series7::ConfRegType>>>& |
| packets) { |
| // InitWithWords doesn't like type 0 |
| /* |
| static std::vector<uint32_t> words{0x00000000}; |
| absl::Span<uint32_t> word_span(words); |
| auto packet = |
| ConfigurationPacket<Series7::ConfRegType>::InitWithWords(word_span); |
| packets.push_back(*(packet.second)); |
| */ |
| static std::vector<uint32_t> words{}; |
| absl::Span<uint32_t> word_span(words); |
| // CRC is config value 0 |
| packets.emplace_back(new ConfigurationPacket<Series7::ConfRegType>( |
| 0, ConfigurationPacket<Series7::ConfRegType>::NOP, |
| Series7::ConfRegType::CRC, word_span)); |
| } |
| |
| void AddType1( |
| std::vector<std::unique_ptr<ConfigurationPacket<Series7::ConfRegType>>>& |
| packets) { |
| static std::vector<uint32_t> words{MakeType1(0x2, 0x3, 2), 0xAA, 0xBB}; |
| absl::Span<uint32_t> word_span(words); |
| auto packet = |
| ConfigurationPacket<Series7::ConfRegType>::InitWithWords(word_span); |
| packets.emplace_back( |
| new ConfigurationPacket<Series7::ConfRegType>(*(packet.second))); |
| } |
| |
| // Empty |
| void AddType1E( |
| std::vector<std::unique_ptr<ConfigurationPacket<Series7::ConfRegType>>>& |
| packets) { |
| static std::vector<uint32_t> words{MakeType1(0x2, 0x3, 0)}; |
| absl::Span<uint32_t> word_span(words); |
| auto packet = |
| ConfigurationPacket<Series7::ConfRegType>::InitWithWords(word_span); |
| packets.emplace_back( |
| new ConfigurationPacket<Series7::ConfRegType>(*(packet.second))); |
| } |
| |
| void AddType2( |
| std::vector<std::unique_ptr<ConfigurationPacket<Series7::ConfRegType>>>& |
| packets) { |
| // Type 1 packet with address |
| // Without this InitWithWords will fail on type 2 |
| ConfigurationPacket<Series7::ConfRegType>* packet1; |
| { |
| static std::vector<uint32_t> words{MakeType1(0x2, 0x3, 0)}; |
| absl::Span<uint32_t> word_span(words); |
| auto packet1_pair = |
| ConfigurationPacket<Series7::ConfRegType>::InitWithWords( |
| word_span); |
| packets.emplace_back( |
| new ConfigurationPacket<Series7::ConfRegType>( |
| *(packet1_pair.second))); |
| packet1 = packets[0].get(); |
| } |
| // Type 2 packet with data |
| { |
| static std::vector<uint32_t> words{ |
| MakeType2(0x01, 12), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; |
| absl::Span<uint32_t> word_span(words); |
| auto packet = |
| ConfigurationPacket<Series7::ConfRegType>::InitWithWords( |
| word_span, packet1); |
| packets.emplace_back( |
| new ConfigurationPacket<Series7::ConfRegType>( |
| *(packet.second))); |
| } |
| } |
| |
| // Empty packets should produce just the header |
| TEST(BitstreamWriterTest, WriteHeader) { |
| std::vector<std::unique_ptr<ConfigurationPacket<Series7::ConfRegType>>> |
| packets; |
| |
| BitstreamWriter<Series7> writer(packets); |
| std::vector<uint32_t> words(writer.begin(), writer.end()); |
| |
| // Per UG470 pg 80: Bus Width Auto Detection |
| std::vector<uint32_t> ref_header{ |
| 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, |
| 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000000BB, 0x11220044, |
| 0xFFFFFFFF, 0xFFFFFFFF, 0xAA995566}; |
| EXPECT_EQ(words, ref_header); |
| |
| // dump_packets(writer); |
| } |
| |
| TEST(BitstreamWriterTest, WriteType0) { |
| std::vector<std::unique_ptr<ConfigurationPacket<Series7::ConfRegType>>> |
| packets; |
| AddType0(packets); |
| BitstreamWriter<Series7> writer(packets); |
| // dump_packets(writer, false); |
| std::vector<uint32_t> words(writer.begin(), writer.end()); |
| std::vector<uint32_t> ref{ |
| // Bus width + sync |
| 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, |
| 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0000000BB, 0x011220044, |
| 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0AA995566, |
| // Type 0 |
| 0x00000000}; |
| EXPECT_EQ(words, ref); |
| } |
| TEST(BitstreamWriterTest, WriteType1) { |
| std::vector<std::unique_ptr<ConfigurationPacket<Series7::ConfRegType>>> |
| packets; |
| AddType1(packets); |
| BitstreamWriter<Series7> writer(packets); |
| // dump_packets(writer, false); |
| std::vector<uint32_t> words(writer.begin(), writer.end()); |
| std::vector<uint32_t> ref{ |
| // Bus width + sync |
| 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, |
| 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0000000BB, 0x011220044, |
| 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0AA995566, |
| // Type 1 |
| 0x030006002, 0x0000000AA, 0x0000000BB}; |
| EXPECT_EQ(words, ref); |
| } |
| |
| TEST(BitstreamWriterTest, WriteType2) { |
| std::vector<std::unique_ptr<ConfigurationPacket<Series7::ConfRegType>>> |
| packets; |
| AddType2(packets); |
| BitstreamWriter<Series7> writer(packets); |
| // dump_packets(writer, false); |
| std::vector<uint32_t> words(writer.begin(), writer.end()); |
| std::vector<uint32_t> ref{ |
| // Bus width + sync |
| 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, |
| 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0000000BB, 0x011220044, |
| 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0AA995566, |
| // Type 1 + type 2 header |
| 0x030006000, 0x04800000C, 0x000000001, 0x000000002, 0x000000003, |
| 0x000000004, 0x000000005, 0x000000006, 0x000000007, 0x000000008, |
| 0x000000009, 0x00000000A, 0x00000000B, 0x00000000C}; |
| EXPECT_EQ(words, ref); |
| } |
| |
| TEST(BitstreamWriterTest, WriteMulti) { |
| std::vector<std::unique_ptr<ConfigurationPacket<Series7::ConfRegType>>> |
| packets; |
| AddType1(packets); |
| AddType1E(packets); |
| AddType2(packets); |
| AddType1E(packets); |
| BitstreamWriter<Series7> writer(packets); |
| // dump_packets(writer, false); |
| std::vector<uint32_t> words(writer.begin(), writer.end()); |
| std::vector<uint32_t> ref{ |
| // Bus width + sync |
| 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, |
| 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0000000BB, 0x011220044, |
| 0x0FFFFFFFF, 0x0FFFFFFFF, 0x0AA995566, |
| // Type1 |
| 0x030006002, 0x0000000AA, 0x0000000BB, |
| // Type1 |
| 0x030006000, |
| // Type 1 + type 2 header |
| 0x030006000, 0x04800000C, 0x000000001, 0x000000002, 0x000000003, |
| 0x000000004, 0x000000005, 0x000000006, 0x000000007, 0x000000008, |
| 0x000000009, 0x00000000A, 0x00000000B, 0x00000000C, |
| // Type 1 |
| 0x030006000}; |
| EXPECT_EQ(words, ref); |
| } |