blob: bb869ab1adf60970d00db16ff50097e187426aaf [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 <array>
#include <gtest/gtest.h>
#include <prjxray/xilinx/architectures.h>
#include <prjxray/xilinx/bitstream_reader.h>
#include <prjxray/xilinx/bitstream_writer.h>
#include <prjxray/bit_ops.h>
using namespace prjxray::xilinx;
constexpr uint32_t kType1NOP = prjxray::bit_field_set<uint32_t>(0, 15, 13, 0x1);
extern const uint32_t MakeType1(const int opcode,
const int address,
const int word_count);
extern const std::vector<uint32_t> MakeType2(const int opcode,
const int address,
const int word_count);
void dump_packets(BitstreamWriter<Spartan6> 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<Spartan6::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<Spartan6::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<Spartan6::ConfRegType>(
0, ConfigurationPacket<Spartan6::ConfRegType>::NOP,
Spartan6::ConfRegType::CRC, word_span));
}
void AddType1(
std::vector<std::unique_ptr<ConfigurationPacket<Spartan6::ConfRegType>>>&
packets) {
static std::vector<uint32_t> words{MakeType1(0x2, 0x3, 2), 0xAA, 0xBB};
absl::Span<uint32_t> word_span(words);
auto packet = ConfigurationPacket<Spartan6::ConfRegType>::InitWithWords(
word_span);
packets.emplace_back(
new ConfigurationPacket<Spartan6::ConfRegType>(*(packet.second)));
}
// Empty
void AddType1E(
std::vector<std::unique_ptr<ConfigurationPacket<Spartan6::ConfRegType>>>&
packets) {
static std::vector<uint32_t> words{MakeType1(0x2, 0x3, 0)};
absl::Span<uint32_t> word_span(words);
auto packet = ConfigurationPacket<Spartan6::ConfRegType>::InitWithWords(
word_span);
packets.emplace_back(
new ConfigurationPacket<Spartan6::ConfRegType>(*(packet.second)));
}
void AddType2(Spartan6::ConfigurationPackage& packets) {
// Type 2 packet with data
{
static std::vector<uint32_t> words;
words = MakeType2(0x02, 0x3, 12);
std::vector<uint32_t> payload{1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12};
words.insert(words.end(), payload.begin(), payload.end());
std::cout << words.size();
absl::Span<uint32_t> word_span(words);
auto packet =
ConfigurationPacket<Spartan6::ConfRegType>::InitWithWords(
word_span);
packets.emplace_back(
new ConfigurationPacket<Spartan6::ConfRegType>(
*(packet.second)));
}
}
// Empty packets should produce just the header
TEST(BitstreamWriterTest, WriteHeader) {
std::vector<std::unique_ptr<ConfigurationPacket<Spartan6::ConfRegType>>>
packets;
BitstreamWriter<Spartan6> writer(packets);
std::vector<uint32_t> words(writer.begin(), writer.end());
// Per UG380 pg 78: Bus Width Auto Detection
std::vector<uint32_t> ref_header{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
0xAA99, 0x5566};
EXPECT_EQ(words, ref_header);
// dump_packets(writer);
}
TEST(BitstreamWriterTest, WriteType0) {
std::vector<std::unique_ptr<ConfigurationPacket<Spartan6::ConfRegType>>>
packets;
AddType0(packets);
BitstreamWriter<Spartan6> writer(packets);
// dump_packets(writer, false);
std::vector<uint32_t> words(writer.begin(), writer.end());
std::vector<uint32_t> ref{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
0xFFFF, 0xFFFF, 0xFFFF, 0xAA99, 0x5566,
// Type 0
0x0000};
EXPECT_EQ(words, ref);
}
TEST(BitstreamWriterTest, WriteType1) {
Spartan6::ConfigurationPackage packets;
AddType1(packets);
BitstreamWriter<Spartan6> writer(packets);
// dump_packets(writer, false);
std::vector<uint32_t> words(writer.begin(), writer.end());
std::vector<uint32_t> ref{// Bus width + sync
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
0xFFFF, 0xFFFF, 0xFFFF, 0xAA99, 0x5566,
// Type 1
0x3062, 0x00AA, 0x00BB};
EXPECT_EQ(words, ref);
}
TEST(BitstreamWriterTest, WriteType2) {
Spartan6::ConfigurationPackage packets;
AddType2(packets);
BitstreamWriter<Spartan6> writer(packets);
// dump_packets(writer, false);
std::vector<uint32_t> words(writer.begin(), writer.end());
std::vector<uint32_t> ref{
// Bus width + sync
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
0xAA99, 0x5566, 0x5060, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005,
0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C};
EXPECT_EQ(words, ref);
}
TEST(BitstreamWriterTest, WriteMulti) {
Spartan6::ConfigurationPackage packets;
AddType1(packets);
AddType1E(packets);
AddType2(packets);
AddType1E(packets);
BitstreamWriter<Spartan6> writer(packets);
// dump_packets(writer, false);
std::vector<uint32_t> words(writer.begin(), writer.end());
std::vector<uint32_t> ref{// Bus width + sync
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
0xFFFF, 0xFFFF, 0xFFFF, 0xAA99, 0x5566,
// Type1
0x3062, 0x00AA, 0x00BB,
// Type1
0x3060,
// Type 1 + type 2 header
0x5060, 0x0001, 0x0002, 0x0003, 0x0004,
0x0005, 0x0006, 0x0007, 0x0008, 0x0009,
0x000A, 0x000B, 0x000C,
// Type 1
0x3060};
EXPECT_EQ(words, ref);
}