mirror of https://github.com/openXC7/prjxray.git
232 lines
7.5 KiB
C++
232 lines
7.5 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 <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);
|
|
}
|