mirror of https://github.com/openXC7/prjxray.git
lib: move Xilinx 7series classes into a separate namespace
Class names were getting unwieldy. Use a namespace to group all the 7series classes and allow for shorter class names. Signed-off-by: Rick Altherr <kc8apf@kc8apf.net> Signed-off-by: Tim 'mithro' Ansell <mithro@mithis.com>
This commit is contained in:
parent
fa162e0b54
commit
0a005ab5a1
|
|
@ -2,8 +2,8 @@ add_library(libprjxray
|
||||||
database.cc
|
database.cc
|
||||||
memory_mapped_file.cc
|
memory_mapped_file.cc
|
||||||
segbits_file_reader.cc
|
segbits_file_reader.cc
|
||||||
xilinx_7series_configuration_packet.cc
|
xilinx/xc7series/configuration_packet.cc
|
||||||
xilinx_7series_bitstream_reader.cc
|
xilinx/xc7series/bitstream_reader.cc
|
||||||
)
|
)
|
||||||
target_include_directories(libprjxray PUBLIC "include")
|
target_include_directories(libprjxray PUBLIC "include")
|
||||||
target_link_libraries(libprjxray absl::optional absl::strings absl::span)
|
target_link_libraries(libprjxray absl::optional absl::strings absl::span)
|
||||||
|
|
@ -31,17 +31,17 @@ if (PRJXRAY_BUILD_TESTING)
|
||||||
COMMAND segbits_file_reader_test
|
COMMAND segbits_file_reader_test
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test_data)
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test_data)
|
||||||
|
|
||||||
add_executable(xilinx_7series_bitstream_reader_test
|
add_executable(xilinx_xc7series_bitstream_reader_test
|
||||||
xilinx_7series_bitstream_reader_test.cc)
|
xilinx/xc7series/bitstream_reader_test.cc)
|
||||||
target_link_libraries(xilinx_7series_bitstream_reader_test
|
target_link_libraries(xilinx_xc7series_bitstream_reader_test
|
||||||
libprjxray gtest_main)
|
libprjxray gtest_main)
|
||||||
add_test(NAME xilinx_7series_bitstream_reader_test
|
add_test(NAME xilinx_xc7series_bitstream_reader_test
|
||||||
COMMAND xilinx_7series_bitstream_reader_test)
|
COMMAND xilinx_xc7series_bitstream_reader_test)
|
||||||
|
|
||||||
add_executable(xilinx_7series_configuration_packet_test
|
add_executable(xilinx_xc7series_configuration_packet_test
|
||||||
xilinx_7series_configuration_packet_test.cc)
|
xilinx/xc7series/configuration_packet_test.cc)
|
||||||
target_link_libraries(xilinx_7series_configuration_packet_test
|
target_link_libraries(xilinx_xc7series_configuration_packet_test
|
||||||
libprjxray gtest_main)
|
libprjxray gtest_main)
|
||||||
add_test(NAME xilinx_7series_configuration_packet_test
|
add_test(NAME xilinx_xc7series_configuration_packet_test
|
||||||
COMMAND xilinx_7series_configuration_packet_test)
|
COMMAND xilinx_xc7series_configuration_packet_test)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef PRJXRAY_LIB_XILINX_7SERIES_BITSTREAM_READER
|
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_BITSTREAM_READER_H
|
||||||
#define PRJXRAY_LIB_XILINX_7SERIES_BITSTREAM_READER
|
#define PRJXRAY_LIB_XILINX_XC7SERIES_BITSTREAM_READER_H
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
@ -9,13 +9,15 @@
|
||||||
#include <absl/types/span.h>
|
#include <absl/types/span.h>
|
||||||
|
|
||||||
#include <prjxray/big_endian_span.h>
|
#include <prjxray/big_endian_span.h>
|
||||||
#include <prjxray/xilinx_7series_configuration_packet.h>
|
#include <prjxray/xilinx/xc7series/configuration_packet.h>
|
||||||
|
|
||||||
namespace prjxray {
|
namespace prjxray {
|
||||||
|
namespace xilinx {
|
||||||
|
namespace xc7series {
|
||||||
|
|
||||||
class Xilinx7SeriesBitstreamReader {
|
class BitstreamReader {
|
||||||
public:
|
public:
|
||||||
using value_type = Xilinx7SeriesConfigurationPacket;
|
using value_type = ConfigurationPacket;
|
||||||
|
|
||||||
class iterator
|
class iterator
|
||||||
: public std::iterator<std::input_iterator_tag, value_type> {
|
: public std::iterator<std::input_iterator_tag, value_type> {
|
||||||
|
|
@ -32,23 +34,22 @@ class Xilinx7SeriesBitstreamReader {
|
||||||
explicit iterator(absl::Span<uint32_t> words);
|
explicit iterator(absl::Span<uint32_t> words);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend Xilinx7SeriesBitstreamReader;
|
friend BitstreamReader;
|
||||||
|
|
||||||
Xilinx7SeriesConfigurationPacket::ParseResult parse_result_;
|
ConfigurationPacket::ParseResult parse_result_;
|
||||||
absl::Span<uint32_t> words_;
|
absl::Span<uint32_t> words_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Construct a reader from a collection of 32-bit, big-endian words.
|
// Construct a reader from a collection of 32-bit, big-endian words.
|
||||||
// Assumes that any sync word has already been removed.
|
// Assumes that any sync word has already been removed.
|
||||||
Xilinx7SeriesBitstreamReader(std::vector<uint32_t> &&words);
|
BitstreamReader(std::vector<uint32_t> &&words);
|
||||||
|
|
||||||
// Construct a `Xilinx7SeriesBitstreamReader` from a Container of bytes.
|
// Construct a `BitstreamReader` from a Container of bytes.
|
||||||
// Any bytes preceding an initial sync word are ignored.
|
// Any bytes preceding an initial sync word are ignored.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static absl::optional<Xilinx7SeriesBitstreamReader> InitWithBytes(
|
static absl::optional<BitstreamReader> InitWithBytes(T &bitstream);
|
||||||
T &bitstream);
|
|
||||||
|
|
||||||
// Returns an iterator that yields `Xilinx7SeriesConfigurationPackets`
|
// Returns an iterator that yields `ConfigurationPackets`
|
||||||
// as read from the bitstream.
|
// as read from the bitstream.
|
||||||
iterator begin();
|
iterator begin();
|
||||||
iterator end();
|
iterator end();
|
||||||
|
|
@ -59,29 +60,31 @@ class Xilinx7SeriesBitstreamReader {
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
absl::optional<Xilinx7SeriesBitstreamReader>
|
absl::optional<BitstreamReader> BitstreamReader::InitWithBytes(T &bitstream) {
|
||||||
Xilinx7SeriesBitstreamReader::InitWithBytes(T &bitstream) {
|
|
||||||
// If this is really a Xilinx 7-Series bitstream, there will be a sync
|
// If this is really a Xilinx 7-Series bitstream, there will be a sync
|
||||||
// word somewhere toward the beginning.
|
// word somewhere toward the beginning.
|
||||||
auto sync_pos = std::search(bitstream.begin(), bitstream.end(),
|
auto sync_pos = std::search(bitstream.begin(), bitstream.end(),
|
||||||
kSyncWord.begin(), kSyncWord.end());
|
kSyncWord.begin(), kSyncWord.end());
|
||||||
if (sync_pos == bitstream.end()) {
|
if (sync_pos == bitstream.end()) {
|
||||||
return absl::optional<Xilinx7SeriesBitstreamReader>();
|
return absl::optional<BitstreamReader>();
|
||||||
}
|
}
|
||||||
sync_pos += kSyncWord.size();
|
sync_pos += kSyncWord.size();
|
||||||
|
|
||||||
// Wrap the provided container in a span that strips off the preamble.
|
// Wrap the provided container in a span that strips off the preamble.
|
||||||
absl::Span<typename T::value_type> bitstream_span(bitstream);
|
absl::Span<typename T::value_type> bitstream_span(bitstream);
|
||||||
auto config_packets = bitstream_span.subspan(sync_pos - bitstream.begin());
|
auto config_packets = bitstream_span.subspan(
|
||||||
|
sync_pos - bitstream.begin());
|
||||||
|
|
||||||
// Convert the bytes into 32-bit, big-endian words.
|
// Convert the bytes into 32-bit, big-endian words.
|
||||||
auto big_endian_reader = make_big_endian_span<uint32_t>(config_packets);
|
auto big_endian_reader = make_big_endian_span<uint32_t>(config_packets);
|
||||||
std::vector<uint32_t> words{big_endian_reader.begin(),
|
std::vector<uint32_t> words{big_endian_reader.begin(),
|
||||||
big_endian_reader.end()};
|
big_endian_reader.end()};
|
||||||
|
|
||||||
return Xilinx7SeriesBitstreamReader(std::move(words));
|
return BitstreamReader(std::move(words));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace xc7series
|
||||||
|
} // namespace xilinx
|
||||||
} // namespace prjxray
|
} // namespace prjxray
|
||||||
|
|
||||||
#endif // PRJXRAY_LIB_XILINX_7SERIES_BITSTREAM_READER
|
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_BITSTREAM_READER_H
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef PRJXRAY_LIB_XILINX_7SERIES_CONFIGURATION_PACKET_H
|
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKET_H
|
||||||
#define PRJXRAY_LIB_XILINX_7SERIES_CONFIGURATION_PACKET_H
|
#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKET_H
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
@ -7,11 +7,13 @@
|
||||||
#include <absl/types/span.h>
|
#include <absl/types/span.h>
|
||||||
|
|
||||||
namespace prjxray {
|
namespace prjxray {
|
||||||
|
namespace xilinx {
|
||||||
|
namespace xc7series {
|
||||||
|
|
||||||
class Xilinx7SeriesConfigurationPacket {
|
class ConfigurationPacket {
|
||||||
public:
|
public:
|
||||||
typedef std::pair<absl::Span<uint32_t>,
|
typedef std::pair<absl::Span<uint32_t>,
|
||||||
absl::optional<Xilinx7SeriesConfigurationPacket>>
|
absl::optional<ConfigurationPacket>>
|
||||||
ParseResult;
|
ParseResult;
|
||||||
|
|
||||||
enum Opcode {
|
enum Opcode {
|
||||||
|
|
@ -21,8 +23,8 @@ class Xilinx7SeriesConfigurationPacket {
|
||||||
/* reserved = 3 */
|
/* reserved = 3 */
|
||||||
};
|
};
|
||||||
|
|
||||||
Xilinx7SeriesConfigurationPacket(Opcode opcode, uint32_t address,
|
ConfigurationPacket(Opcode opcode, uint32_t address,
|
||||||
const absl::Span<uint32_t> &data)
|
const absl::Span<uint32_t> &data)
|
||||||
: opcode_(opcode), address_(address), data_(std::move(data)) {}
|
: opcode_(opcode), address_(address), data_(std::move(data)) {}
|
||||||
|
|
||||||
// Attempt to read a configuration packet from a sequence of
|
// Attempt to read a configuration packet from a sequence of
|
||||||
|
|
@ -33,8 +35,8 @@ class Xilinx7SeriesConfigurationPacket {
|
||||||
// packet is produced. If no valid header is found, an empty span is
|
// packet is produced. If no valid header is found, an empty span is
|
||||||
// returned.
|
// returned.
|
||||||
static ParseResult InitWithWords(
|
static ParseResult InitWithWords(
|
||||||
absl::Span<uint32_t> words,
|
absl::Span<uint32_t> words,
|
||||||
const Xilinx7SeriesConfigurationPacket *previous_packet = nullptr);
|
const ConfigurationPacket *previous_packet = nullptr);
|
||||||
|
|
||||||
const Opcode opcode() const { return opcode_; }
|
const Opcode opcode() const { return opcode_; }
|
||||||
const uint32_t address() const { return address_; }
|
const uint32_t address() const { return address_; }
|
||||||
|
|
@ -46,9 +48,10 @@ class Xilinx7SeriesConfigurationPacket {
|
||||||
absl::Span<uint32_t> data_;
|
absl::Span<uint32_t> data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o,
|
std::ostream& operator<<(std::ostream& o, const ConfigurationPacket &packet);
|
||||||
const Xilinx7SeriesConfigurationPacket &packet);
|
|
||||||
|
|
||||||
|
} // namespace xc7series
|
||||||
|
} // namespace xilinx
|
||||||
} // namespace prjxray
|
} // namespace prjxray
|
||||||
|
|
||||||
#endif // PRJXRAY_LIB_XILINX_7SERIES_CONFIGURATION_PACKET_H
|
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKET_H
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
|
||||||
|
|
||||||
|
namespace prjxray {
|
||||||
|
namespace xilinx {
|
||||||
|
namespace xc7series {
|
||||||
|
|
||||||
|
std::array<uint8_t, 4> BitstreamReader::kSyncWord{0xAA, 0x99, 0x55, 0x66};
|
||||||
|
|
||||||
|
BitstreamReader::BitstreamReader(std::vector<uint32_t> &&words)
|
||||||
|
: words_(std::move(words)) {}
|
||||||
|
|
||||||
|
BitstreamReader::iterator BitstreamReader::begin() {
|
||||||
|
return iterator(absl::MakeSpan(words_));
|
||||||
|
}
|
||||||
|
|
||||||
|
BitstreamReader::iterator BitstreamReader::end() {
|
||||||
|
return iterator({});
|
||||||
|
}
|
||||||
|
|
||||||
|
BitstreamReader::iterator::iterator(absl::Span<uint32_t> words) {
|
||||||
|
parse_result_.first = words;
|
||||||
|
parse_result_.second = {};
|
||||||
|
++(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
BitstreamReader::iterator&
|
||||||
|
BitstreamReader::iterator::operator++() {
|
||||||
|
do {
|
||||||
|
auto new_result = ConfigurationPacket::InitWithWords(
|
||||||
|
parse_result_.first,
|
||||||
|
parse_result_.second.has_value() ?
|
||||||
|
parse_result_.second.operator->() :
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
// If the a valid header is being found but there are
|
||||||
|
// insufficient words to yield a packet, consider it the end.
|
||||||
|
if (new_result.first == parse_result_.first) {
|
||||||
|
words_ = absl::Span<uint32_t>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
words_ = parse_result_.first;
|
||||||
|
parse_result_ = new_result;
|
||||||
|
} while (!parse_result_.first.empty() &&
|
||||||
|
!parse_result_.second);
|
||||||
|
|
||||||
|
if (!parse_result_.second) {
|
||||||
|
words_ = absl::Span<uint32_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BitstreamReader::iterator::operator==(const iterator &other) const {
|
||||||
|
return words_ == other.words_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BitstreamReader::iterator::operator!=(const iterator &other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
const BitstreamReader::value_type&
|
||||||
|
BitstreamReader::iterator::operator*() const {
|
||||||
|
return *(parse_result_.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
const BitstreamReader::value_type*
|
||||||
|
BitstreamReader::iterator::operator->() const {
|
||||||
|
return parse_result_.second.operator->();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xc7series
|
||||||
|
} // namespace xilinx
|
||||||
|
} // namespace prjxray
|
||||||
|
|
@ -1,71 +1,71 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <prjxray/xilinx_7series_bitstream_reader.h>
|
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
|
||||||
#include <prjxray/xilinx_7series_configuration_packet.h>
|
#include <prjxray/xilinx/xc7series/configuration_packet.h>
|
||||||
|
|
||||||
using prjxray::Xilinx7SeriesBitstreamReader;
|
using prjxray::xilinx::xc7series::BitstreamReader;
|
||||||
using prjxray::Xilinx7SeriesConfigurationPacket;
|
using prjxray::xilinx::xc7series::ConfigurationPacket;
|
||||||
|
|
||||||
TEST(Xilinx7SeriesBitstreamReaderTest, InitWithEmptyBytesReturnsNull) {
|
TEST(BitstreamReaderTest, InitWithEmptyBytesReturnsNull) {
|
||||||
absl::Span<uint8_t> bitstream;
|
absl::Span<uint8_t> bitstream;
|
||||||
auto reader = Xilinx7SeriesBitstreamReader::InitWithBytes(bitstream);
|
auto reader = BitstreamReader::InitWithBytes(bitstream);
|
||||||
EXPECT_FALSE(reader);
|
EXPECT_FALSE(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Xilinx7SeriesBitstreamReaderTest, InitWithOnlySyncReturnsObject) {
|
TEST(BitstreamReaderTest, InitWithOnlySyncReturnsObject) {
|
||||||
std::vector<uint8_t> bitstream{0xAA, 0x99, 0x55, 0x66};
|
std::vector<uint8_t> bitstream{0xAA, 0x99, 0x55, 0x66};
|
||||||
auto reader = Xilinx7SeriesBitstreamReader::InitWithBytes(bitstream);
|
auto reader = BitstreamReader::InitWithBytes(bitstream);
|
||||||
EXPECT_TRUE(reader);
|
EXPECT_TRUE(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Xilinx7SeriesBitstreamReaderTest,
|
TEST(BitstreamReaderTest,
|
||||||
InitWithSyncAfterNonWordSizedPaddingReturnsObject) {
|
InitWithSyncAfterNonWordSizedPaddingReturnsObject) {
|
||||||
std::vector<uint8_t> bitstream{
|
std::vector<uint8_t> bitstream{
|
||||||
0xFF, 0xFE,
|
0xFF, 0xFE,
|
||||||
0xAA, 0x99, 0x55, 0x66
|
0xAA, 0x99, 0x55, 0x66
|
||||||
};
|
};
|
||||||
auto reader = Xilinx7SeriesBitstreamReader::InitWithBytes(bitstream);
|
auto reader = BitstreamReader::InitWithBytes(bitstream);
|
||||||
EXPECT_TRUE(reader);
|
EXPECT_TRUE(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Xilinx7SeriesBitstreamReaderTest,
|
TEST(BitstreamReaderTest,
|
||||||
InitWithSyncAfterWordSizedPaddingReturnsObject) {
|
InitWithSyncAfterWordSizedPaddingReturnsObject) {
|
||||||
std::vector<uint8_t> bitstream{
|
std::vector<uint8_t> bitstream{
|
||||||
0xFF, 0xFE, 0xFD, 0xFC,
|
0xFF, 0xFE, 0xFD, 0xFC,
|
||||||
0xAA, 0x99, 0x55, 0x66
|
0xAA, 0x99, 0x55, 0x66
|
||||||
};
|
};
|
||||||
auto reader = Xilinx7SeriesBitstreamReader::InitWithBytes(bitstream);
|
auto reader = BitstreamReader::InitWithBytes(bitstream);
|
||||||
EXPECT_TRUE(reader);
|
EXPECT_TRUE(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Xilinx7SeriesBitstreamReaderTest, ParsesType1Packet) {
|
TEST(BitstreamReaderTest, ParsesType1Packet) {
|
||||||
std::vector<uint8_t> bitstream{
|
std::vector<uint8_t> bitstream{
|
||||||
0xAA, 0x99, 0x55, 0x66, // sync
|
0xAA, 0x99, 0x55, 0x66, // sync
|
||||||
0b001'00'000, 0b00000000, 0b000'00'000, 0b00000000, // NOP
|
0b001'00'000, 0b00000000, 0b000'00'000, 0b00000000, // NOP
|
||||||
};
|
};
|
||||||
auto reader = Xilinx7SeriesBitstreamReader::InitWithBytes(bitstream);
|
auto reader = BitstreamReader::InitWithBytes(bitstream);
|
||||||
ASSERT_TRUE(reader);
|
ASSERT_TRUE(reader);
|
||||||
ASSERT_NE(reader->begin(), reader->end());
|
ASSERT_NE(reader->begin(), reader->end());
|
||||||
|
|
||||||
auto first_packet = reader->begin();
|
auto first_packet = reader->begin();
|
||||||
EXPECT_EQ(first_packet->opcode(), Xilinx7SeriesConfigurationPacket::Opcode::NOP);
|
EXPECT_EQ(first_packet->opcode(), ConfigurationPacket::Opcode::NOP);
|
||||||
|
|
||||||
EXPECT_EQ(++first_packet, reader->end());
|
EXPECT_EQ(++first_packet, reader->end());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Xilinx7SeriesBitstreamReaderTest, ParseType2PacketWithoutType1Fails) {
|
TEST(BitstreamReaderTest, ParseType2PacketWithoutType1Fails) {
|
||||||
std::vector<uint8_t> bitstream{
|
std::vector<uint8_t> bitstream{
|
||||||
0xAA, 0x99, 0x55, 0x66, // sync
|
0xAA, 0x99, 0x55, 0x66, // sync
|
||||||
0b010'00'000, 0b00000000, 0b000'00'000, 0b00000000, // NOP
|
0b010'00'000, 0b00000000, 0b000'00'000, 0b00000000, // NOP
|
||||||
};
|
};
|
||||||
auto reader = Xilinx7SeriesBitstreamReader::InitWithBytes(bitstream);
|
auto reader = BitstreamReader::InitWithBytes(bitstream);
|
||||||
ASSERT_TRUE(reader);
|
ASSERT_TRUE(reader);
|
||||||
EXPECT_EQ(reader->begin(), reader->end());
|
EXPECT_EQ(reader->begin(), reader->end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(Xilinx7SeriesBitstreamReaderTest, ParsesType2AfterType1Packet) {
|
TEST(BitstreamReaderTest, ParsesType2AfterType1Packet) {
|
||||||
std::vector<uint8_t> bitstream{
|
std::vector<uint8_t> bitstream{
|
||||||
0xAA, 0x99, 0x55, 0x66, // sync
|
0xAA, 0x99, 0x55, 0x66, // sync
|
||||||
0b001'01'000, 0b00000000, 0b011'00'000, 0b00000000, // Read
|
0b001'01'000, 0b00000000, 0b011'00'000, 0b00000000, // Read
|
||||||
|
|
@ -75,20 +75,21 @@ TEST(Xilinx7SeriesBitstreamReaderTest, ParsesType2AfterType1Packet) {
|
||||||
0x9, 0xA, 0xB, 0xC,
|
0x9, 0xA, 0xB, 0xC,
|
||||||
0xD, 0xE, 0xF, 0x10,
|
0xD, 0xE, 0xF, 0x10,
|
||||||
};
|
};
|
||||||
std::vector<uint32_t> data_words{ 0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10};
|
std::vector<uint32_t> data_words{
|
||||||
|
0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10};
|
||||||
|
|
||||||
auto reader = Xilinx7SeriesBitstreamReader::InitWithBytes(bitstream);
|
auto reader = BitstreamReader::InitWithBytes(bitstream);
|
||||||
ASSERT_TRUE(reader);
|
ASSERT_TRUE(reader);
|
||||||
ASSERT_NE(reader->begin(), reader->end());
|
ASSERT_NE(reader->begin(), reader->end());
|
||||||
|
|
||||||
auto first_packet = reader->begin();
|
auto first_packet = reader->begin();
|
||||||
EXPECT_EQ(first_packet->opcode(), Xilinx7SeriesConfigurationPacket::Opcode::Read);
|
EXPECT_EQ(first_packet->opcode(), ConfigurationPacket::Opcode::Read);
|
||||||
EXPECT_EQ(first_packet->address(), static_cast<uint32_t>(0x3));
|
EXPECT_EQ(first_packet->address(), static_cast<uint32_t>(0x3));
|
||||||
EXPECT_EQ(first_packet->data(), absl::Span<uint32_t>());
|
EXPECT_EQ(first_packet->data(), absl::Span<uint32_t>());
|
||||||
|
|
||||||
auto second_packet = ++first_packet;
|
auto second_packet = ++first_packet;
|
||||||
ASSERT_NE(second_packet, reader->end());
|
ASSERT_NE(second_packet, reader->end());
|
||||||
EXPECT_EQ(second_packet->opcode(), Xilinx7SeriesConfigurationPacket::Opcode::Read);
|
EXPECT_EQ(second_packet->opcode(), ConfigurationPacket::Opcode::Read);
|
||||||
EXPECT_EQ(second_packet->address(), static_cast<uint32_t>(0x3));
|
EXPECT_EQ(second_packet->address(), static_cast<uint32_t>(0x3));
|
||||||
EXPECT_EQ(first_packet->data(), absl::Span<uint32_t>(data_words));
|
EXPECT_EQ(first_packet->data(), absl::Span<uint32_t>(data_words));
|
||||||
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
#include <prjxray/xilinx_7series_configuration_packet.h>
|
#include <prjxray/xilinx/xc7series/configuration_packet.h>
|
||||||
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
#include <prjxray/bit_ops.h>
|
#include <prjxray/bit_ops.h>
|
||||||
|
|
||||||
namespace prjxray {
|
namespace prjxray {
|
||||||
|
namespace xilinx {
|
||||||
|
namespace xc7series {
|
||||||
|
|
||||||
std::pair<absl::Span<uint32_t>, absl::optional<Xilinx7SeriesConfigurationPacket>>
|
std::pair<absl::Span<uint32_t>, absl::optional<ConfigurationPacket>>
|
||||||
Xilinx7SeriesConfigurationPacket::InitWithWords(
|
ConfigurationPacket::InitWithWords(absl::Span<uint32_t> words,
|
||||||
absl::Span<uint32_t> words,
|
const ConfigurationPacket *previous_packet) {
|
||||||
const Xilinx7SeriesConfigurationPacket *previous_packet) {
|
|
||||||
// Need at least one 32-bit word to have a valid packet header.
|
// Need at least one 32-bit word to have a valid packet header.
|
||||||
if (words.size() < 1) return {words, {}};
|
if (words.size() < 1) return {words, {}};
|
||||||
|
|
||||||
|
|
@ -31,7 +32,7 @@ Xilinx7SeriesConfigurationPacket::InitWithWords(
|
||||||
{{opcode, address, words.subspan(1, data_word_count)}}};
|
{{opcode, address, words.subspan(1, data_word_count)}}};
|
||||||
}
|
}
|
||||||
case 0b010: {
|
case 0b010: {
|
||||||
absl::optional<Xilinx7SeriesConfigurationPacket> packet;
|
absl::optional<ConfigurationPacket> packet;
|
||||||
Opcode opcode = static_cast<Opcode>(
|
Opcode opcode = static_cast<Opcode>(
|
||||||
bit_field_get(words[0], 28, 27));
|
bit_field_get(words[0], 28, 27));
|
||||||
uint32_t data_word_count = bit_field_get(words[0], 26, 0);
|
uint32_t data_word_count = bit_field_get(words[0], 26, 0);
|
||||||
|
|
@ -43,7 +44,7 @@ Xilinx7SeriesConfigurationPacket::InitWithWords(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previous_packet) {
|
if (previous_packet) {
|
||||||
packet = Xilinx7SeriesConfigurationPacket(
|
packet = ConfigurationPacket(
|
||||||
opcode, previous_packet->address(),
|
opcode, previous_packet->address(),
|
||||||
words.subspan(1, data_word_count));
|
words.subspan(1, data_word_count));
|
||||||
}
|
}
|
||||||
|
|
@ -55,16 +56,15 @@ Xilinx7SeriesConfigurationPacket::InitWithWords(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o,
|
std::ostream& operator<<(std::ostream& o, const ConfigurationPacket &packet) {
|
||||||
const Xilinx7SeriesConfigurationPacket &packet) {
|
|
||||||
switch (packet.opcode()) {
|
switch (packet.opcode()) {
|
||||||
case Xilinx7SeriesConfigurationPacket::Opcode::NOP:
|
case ConfigurationPacket::Opcode::NOP:
|
||||||
return o << "[NOP]" << std::endl;
|
return o << "[NOP]" << std::endl;
|
||||||
case Xilinx7SeriesConfigurationPacket::Opcode::Read:
|
case ConfigurationPacket::Opcode::Read:
|
||||||
return o << "[Read Address=" << packet.address()
|
return o << "[Read Address=" << packet.address()
|
||||||
<< " Length=" << packet.data().size() <<
|
<< " Length=" << packet.data().size() <<
|
||||||
"]" << std::endl;
|
"]" << std::endl;
|
||||||
case Xilinx7SeriesConfigurationPacket::Opcode::Write:
|
case ConfigurationPacket::Opcode::Write:
|
||||||
return o << "[Write Address=" << packet.address()
|
return o << "[Write Address=" << packet.address()
|
||||||
<< " Length=" << packet.data().size() <<
|
<< " Length=" << packet.data().size() <<
|
||||||
"]" << std::endl;
|
"]" << std::endl;
|
||||||
|
|
@ -73,4 +73,6 @@ std::ostream& operator<<(std::ostream& o,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace xc7series
|
||||||
|
} // namespace xilinx
|
||||||
} // namespace prjxray
|
} // namespace prjxray
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include <prjxray/xilinx_7series_configuration_packet.h>
|
#include <prjxray/xilinx/xc7series/configuration_packet.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
|
@ -6,9 +6,12 @@
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <prjxray/bit_ops.h>
|
#include <prjxray/bit_ops.h>
|
||||||
|
|
||||||
|
using prjxray::xilinx::xc7series::ConfigurationPacket;
|
||||||
|
|
||||||
constexpr uint32_t kType1NOP = prjxray::bit_field_set<uint32_t>(0, 31, 29, 0x1);
|
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) {
|
constexpr uint32_t MakeType1(const int opcode, const int address,
|
||||||
|
const int word_count) {
|
||||||
return prjxray::bit_field_set<uint32_t>(
|
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>(
|
prjxray::bit_field_set<uint32_t>(
|
||||||
|
|
@ -28,7 +31,7 @@ constexpr uint32_t MakeType2(const int opcode, const int word_count) {
|
||||||
|
|
||||||
|
|
||||||
TEST(ConfigPacket, InitWithZeroBytes) {
|
TEST(ConfigPacket, InitWithZeroBytes) {
|
||||||
auto packet = prjxray::Xilinx7SeriesConfigurationPacket::InitWithWords({});
|
auto packet = ConfigurationPacket::InitWithWords({});
|
||||||
|
|
||||||
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
|
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
|
||||||
EXPECT_FALSE(packet.second);
|
EXPECT_FALSE(packet.second);
|
||||||
|
|
@ -37,10 +40,10 @@ TEST(ConfigPacket, InitWithZeroBytes) {
|
||||||
TEST(ConfigPacket, InitWithType1Nop) {
|
TEST(ConfigPacket, InitWithType1Nop) {
|
||||||
std::vector<uint32_t> words{kType1NOP};
|
std::vector<uint32_t> words{kType1NOP};
|
||||||
absl::Span<uint32_t> word_span(words);
|
absl::Span<uint32_t> word_span(words);
|
||||||
auto packet = prjxray::Xilinx7SeriesConfigurationPacket::InitWithWords(word_span);
|
auto packet = ConfigurationPacket::InitWithWords(word_span);
|
||||||
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
|
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
|
||||||
ASSERT_TRUE(packet.second);
|
ASSERT_TRUE(packet.second);
|
||||||
EXPECT_EQ(packet.second->opcode(), prjxray::Xilinx7SeriesConfigurationPacket::Opcode::NOP);
|
EXPECT_EQ(packet.second->opcode(), ConfigurationPacket::Opcode::NOP);
|
||||||
EXPECT_EQ(packet.second->address(), static_cast<uint32_t>(0));
|
EXPECT_EQ(packet.second->address(), static_cast<uint32_t>(0));
|
||||||
EXPECT_EQ(packet.second->data(), absl::Span<uint32_t>());
|
EXPECT_EQ(packet.second->data(), absl::Span<uint32_t>());
|
||||||
}
|
}
|
||||||
|
|
@ -48,10 +51,10 @@ TEST(ConfigPacket, InitWithType1Nop) {
|
||||||
TEST(ConfigPacket, InitWithType1Read) {
|
TEST(ConfigPacket, InitWithType1Read) {
|
||||||
std::vector<uint32_t> words{MakeType1(0x1, 0x1234, 2), 0xAA, 0xBB};
|
std::vector<uint32_t> words{MakeType1(0x1, 0x1234, 2), 0xAA, 0xBB};
|
||||||
absl::Span<uint32_t> word_span(words);
|
absl::Span<uint32_t> word_span(words);
|
||||||
auto packet = prjxray::Xilinx7SeriesConfigurationPacket::InitWithWords(word_span);
|
auto packet = ConfigurationPacket::InitWithWords(word_span);
|
||||||
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
|
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
|
||||||
ASSERT_TRUE(packet.second);
|
ASSERT_TRUE(packet.second);
|
||||||
EXPECT_EQ(packet.second->opcode(), prjxray::Xilinx7SeriesConfigurationPacket::Opcode::Read);
|
EXPECT_EQ(packet.second->opcode(), ConfigurationPacket::Opcode::Read);
|
||||||
EXPECT_EQ(packet.second->address(), static_cast<uint32_t>(0x1234));
|
EXPECT_EQ(packet.second->address(), static_cast<uint32_t>(0x1234));
|
||||||
EXPECT_EQ(packet.second->data(), word_span.subspan(1));
|
EXPECT_EQ(packet.second->data(), word_span.subspan(1));
|
||||||
}
|
}
|
||||||
|
|
@ -59,10 +62,10 @@ TEST(ConfigPacket, InitWithType1Read) {
|
||||||
TEST(ConfigPacket, InitWithType1Write) {
|
TEST(ConfigPacket, InitWithType1Write) {
|
||||||
std::vector<uint32_t> words{MakeType1(0x2, 0x1234, 2), 0xAA, 0xBB};
|
std::vector<uint32_t> words{MakeType1(0x2, 0x1234, 2), 0xAA, 0xBB};
|
||||||
absl::Span<uint32_t> word_span(words);
|
absl::Span<uint32_t> word_span(words);
|
||||||
auto packet = prjxray::Xilinx7SeriesConfigurationPacket::InitWithWords(word_span);
|
auto packet = ConfigurationPacket::InitWithWords(word_span);
|
||||||
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
|
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
|
||||||
ASSERT_TRUE(packet.second);
|
ASSERT_TRUE(packet.second);
|
||||||
EXPECT_EQ(packet.second->opcode(), prjxray::Xilinx7SeriesConfigurationPacket::Opcode::Write);
|
EXPECT_EQ(packet.second->opcode(), ConfigurationPacket::Opcode::Write);
|
||||||
EXPECT_EQ(packet.second->address(), static_cast<uint32_t>(0x1234));
|
EXPECT_EQ(packet.second->address(), static_cast<uint32_t>(0x1234));
|
||||||
EXPECT_EQ(packet.second->data(), word_span.subspan(1));
|
EXPECT_EQ(packet.second->data(), word_span.subspan(1));
|
||||||
}
|
}
|
||||||
|
|
@ -70,22 +73,23 @@ TEST(ConfigPacket, InitWithType1Write) {
|
||||||
TEST(ConfigPacket, InitWithType2WithoutPreviousPacketFails) {
|
TEST(ConfigPacket, InitWithType2WithoutPreviousPacketFails) {
|
||||||
std::vector<uint32_t> words{MakeType2(0x01, 12)};
|
std::vector<uint32_t> words{MakeType2(0x01, 12)};
|
||||||
absl::Span<uint32_t> word_span(words);
|
absl::Span<uint32_t> word_span(words);
|
||||||
auto packet = prjxray::Xilinx7SeriesConfigurationPacket::InitWithWords(word_span);
|
auto packet = ConfigurationPacket::InitWithWords(word_span);
|
||||||
EXPECT_EQ(packet.first, words);
|
EXPECT_EQ(packet.first, words);
|
||||||
EXPECT_FALSE(packet.second);
|
EXPECT_FALSE(packet.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ConfigPacket, InitWithType2WithPreviousPacket) {
|
TEST(ConfigPacket, InitWithType2WithPreviousPacket) {
|
||||||
prjxray::Xilinx7SeriesConfigurationPacket previous_packet(
|
ConfigurationPacket previous_packet(
|
||||||
prjxray::Xilinx7SeriesConfigurationPacket::Read,
|
ConfigurationPacket::Opcode::Read, 0x1234,
|
||||||
0x1234, absl::Span<uint32_t>());
|
absl::Span<uint32_t>());
|
||||||
std::vector<uint32_t> words{MakeType2(0x01, 12), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
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);
|
absl::Span<uint32_t> word_span(words);
|
||||||
auto packet = prjxray::Xilinx7SeriesConfigurationPacket::InitWithWords(
|
auto packet = ConfigurationPacket::InitWithWords(
|
||||||
word_span, &previous_packet);
|
word_span, &previous_packet);
|
||||||
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
|
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
|
||||||
ASSERT_TRUE(packet.second);
|
ASSERT_TRUE(packet.second);
|
||||||
EXPECT_EQ(packet.second->opcode(), prjxray::Xilinx7SeriesConfigurationPacket::Opcode::Read);
|
EXPECT_EQ(packet.second->opcode(), ConfigurationPacket::Opcode::Read);
|
||||||
EXPECT_EQ(packet.second->address(), static_cast<uint32_t>(0x1234));
|
EXPECT_EQ(packet.second->address(), static_cast<uint32_t>(0x1234));
|
||||||
EXPECT_EQ(packet.second->data(), word_span.subspan(1));
|
EXPECT_EQ(packet.second->data(), word_span.subspan(1));
|
||||||
}
|
}
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
#include <prjxray/xilinx_7series_bitstream_reader.h>
|
|
||||||
|
|
||||||
namespace prjxray {
|
|
||||||
|
|
||||||
std::array<uint8_t, 4> Xilinx7SeriesBitstreamReader::kSyncWord{
|
|
||||||
0xAA, 0x99, 0x55, 0x66};
|
|
||||||
|
|
||||||
Xilinx7SeriesBitstreamReader::Xilinx7SeriesBitstreamReader(
|
|
||||||
std::vector<uint32_t> &&words)
|
|
||||||
: words_(std::move(words)) {}
|
|
||||||
|
|
||||||
Xilinx7SeriesBitstreamReader::iterator Xilinx7SeriesBitstreamReader::begin() {
|
|
||||||
return iterator(absl::MakeSpan(words_));
|
|
||||||
}
|
|
||||||
|
|
||||||
Xilinx7SeriesBitstreamReader::iterator Xilinx7SeriesBitstreamReader::end() {
|
|
||||||
return iterator({});
|
|
||||||
}
|
|
||||||
|
|
||||||
Xilinx7SeriesBitstreamReader::iterator::iterator(absl::Span<uint32_t> words) {
|
|
||||||
parse_result_.first = words;
|
|
||||||
parse_result_.second = {};
|
|
||||||
++(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
Xilinx7SeriesBitstreamReader::iterator&
|
|
||||||
Xilinx7SeriesBitstreamReader::iterator::operator++() {
|
|
||||||
do {
|
|
||||||
auto new_result = Xilinx7SeriesConfigurationPacket::InitWithWords(
|
|
||||||
parse_result_.first,
|
|
||||||
parse_result_.second.has_value() ?
|
|
||||||
parse_result_.second.operator->() :
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
// If the a valid header is being found but there are
|
|
||||||
// insufficient words to yield a packet, consider it the end.
|
|
||||||
if (new_result.first == parse_result_.first) {
|
|
||||||
words_ = absl::Span<uint32_t>();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
words_ = parse_result_.first;
|
|
||||||
parse_result_ = new_result;
|
|
||||||
} while (!parse_result_.first.empty() &&
|
|
||||||
!parse_result_.second);
|
|
||||||
|
|
||||||
if (!parse_result_.second) {
|
|
||||||
words_ = absl::Span<uint32_t>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Xilinx7SeriesBitstreamReader::iterator::operator==(const iterator &other) const {
|
|
||||||
return words_ == other.words_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Xilinx7SeriesBitstreamReader::iterator::operator!=(const iterator &other) const {
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Xilinx7SeriesBitstreamReader::value_type&
|
|
||||||
Xilinx7SeriesBitstreamReader::iterator::operator*() const {
|
|
||||||
return *(parse_result_.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Xilinx7SeriesBitstreamReader::value_type*
|
|
||||||
Xilinx7SeriesBitstreamReader::iterator::operator->() const {
|
|
||||||
return parse_result_.second.operator->();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace prjxray
|
|
||||||
|
|
@ -4,7 +4,9 @@
|
||||||
#include <absl/types/span.h>
|
#include <absl/types/span.h>
|
||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
#include <prjxray/memory_mapped_file.h>
|
#include <prjxray/memory_mapped_file.h>
|
||||||
#include <prjxray/xilinx_7series_bitstream_reader.h>
|
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
|
||||||
|
|
||||||
|
namespace xc7series = prjxray::xilinx::xc7series;
|
||||||
|
|
||||||
DEFINE_string(action, "list_config_packets", "");
|
DEFINE_string(action, "list_config_packets", "");
|
||||||
|
|
||||||
|
|
@ -24,8 +26,7 @@ int ListConfigPackets(int argc, char *argv[]) {
|
||||||
auto in_bytes = absl::Span<uint8_t>(
|
auto in_bytes = absl::Span<uint8_t>(
|
||||||
static_cast<uint8_t*>(in_file->data()),
|
static_cast<uint8_t*>(in_file->data()),
|
||||||
in_file->size());
|
in_file->size());
|
||||||
auto reader = prjxray::Xilinx7SeriesBitstreamReader::InitWithBytes(
|
auto reader = xc7series::BitstreamReader::InitWithBytes(in_bytes);
|
||||||
in_bytes);
|
|
||||||
if (!reader) {
|
if (!reader) {
|
||||||
std::cerr << "Input doesn't look like a bitstream"
|
std::cerr << "Input doesn't look like a bitstream"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue