lib: xc7series: move register details to reusable enum

Both ConfigurationPacket and Configuration need to reference registers.
Use a common scoped enum to reduce change of errors.  Leverage stream
operator to simplify outputing register names.

Signed-off-by: Rick Altherr <kc8apf@kc8apf.net>
Signed-off-by: Tim 'mithro' Ansell <mithro@mithis.com>
This commit is contained in:
Rick Altherr 2017-12-05 10:51:47 -08:00 committed by Tim 'mithro' Ansell
parent 0a005ab5a1
commit 47e02d4cfd
10 changed files with 251 additions and 44 deletions

View File

@ -2,8 +2,10 @@ add_library(libprjxray
database.cc
memory_mapped_file.cc
segbits_file_reader.cc
xilinx/xc7series/configuration_packet.cc
xilinx/xc7series/bitstream_reader.cc
xilinx/xc7series/configuration_frame_address.cc
xilinx/xc7series/configuration_packet.cc
xilinx/xc7series/configuration_register.cc
)
target_include_directories(libprjxray PUBLIC "include")
target_link_libraries(libprjxray absl::optional absl::strings absl::span)

View File

@ -0,0 +1,19 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_BLOCK_TYPE_H_
#define PRJXRAY_LIB_XILINX_XC7SERIES_BLOCK_TYPE_H_
namespace prjxray {
namespace xilinx {
namespace xc7series {
enum class BlockType : unsigned int {
CLB_IO_CLK = 0b000,
BLOCK_RAM = 0b001,
CFG_CLB = 0b010,
/* reserved = 0b011, */
};
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_BLOCK_TYPE_H_

View File

@ -0,0 +1,33 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_FRAME_ADDRESS_H_
#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_FRAME_ADDRESS_H_
#include <cstdint>
#include <prjxray/xilinx/xc7series/block_type.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
class ConfigurationFrameAddress {
public:
ConfigurationFrameAddress(uint32_t address)
: address_(address) {};
operator uint32_t() const { return address_; }
BlockType block_type() const;
bool is_bottom_half_rows() const;
uint8_t row_address() const;
uint16_t column_address() const;
uint8_t minor_address() const;
private:
uint32_t address_;
};
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_FRAME_ADDRESS_H_

View File

@ -5,6 +5,7 @@
#include <absl/types/optional.h>
#include <absl/types/span.h>
#include <prjxray/xilinx/xc7series/configuration_register.h>
namespace prjxray {
namespace xilinx {
@ -23,7 +24,7 @@ class ConfigurationPacket {
/* reserved = 3 */
};
ConfigurationPacket(Opcode opcode, uint32_t address,
ConfigurationPacket(Opcode opcode, ConfigurationRegister address,
const absl::Span<uint32_t> &data)
: opcode_(opcode), address_(address), data_(std::move(data)) {}
@ -39,12 +40,12 @@ class ConfigurationPacket {
const ConfigurationPacket *previous_packet = nullptr);
const Opcode opcode() const { return opcode_; }
const uint32_t address() const { return address_; }
const ConfigurationRegister address() const { return address_; }
const absl::Span<uint32_t> &data() const { return data_; }
private:
Opcode opcode_;
uint32_t address_;
ConfigurationRegister address_;
absl::Span<uint32_t> data_;
};

View File

@ -0,0 +1,39 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_REGISTER_H_
#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_REGISTER_H_
#include <ostream>
namespace prjxray {
namespace xilinx {
namespace xc7series {
enum class ConfigurationRegister : unsigned int {
CRC = 0b00000,
FAR = 0b00001,
FDRI = 0b00010,
FDRO = 0b00011,
CMD = 0b00100,
CTL0 = 0b00101,
MASK = 0b00110,
STAT = 0b00111,
LOUT = 0b01000,
COR0 = 0b01001,
MFWR = 0b01010,
CBC = 0b01011,
IDCODE = 0b01100,
AXSS = 0b01101,
COR1 = 0b01110,
WBSTAR = 0b10000,
TIMER = 0b10001,
BOOTSTS = 0b10110,
CTL1 = 0b11000,
BSPI = 0b11111,
};
std::ostream& operator<<(std::ostream &o, const ConfigurationRegister &value);
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_REGISTER_H_

View File

@ -3,19 +3,19 @@
#include <gtest/gtest.h>
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
#include <prjxray/xilinx/xc7series/configuration_packet.h>
#include <prjxray/xilinx/xc7series/configuration_register.h>
using prjxray::xilinx::xc7series::BitstreamReader;
using prjxray::xilinx::xc7series::ConfigurationPacket;
namespace xc7series = prjxray::xilinx::xc7series;
TEST(BitstreamReaderTest, InitWithEmptyBytesReturnsNull) {
absl::Span<uint8_t> bitstream;
auto reader = BitstreamReader::InitWithBytes(bitstream);
auto reader = xc7series::BitstreamReader::InitWithBytes(bitstream);
EXPECT_FALSE(reader);
}
TEST(BitstreamReaderTest, InitWithOnlySyncReturnsObject) {
std::vector<uint8_t> bitstream{0xAA, 0x99, 0x55, 0x66};
auto reader = BitstreamReader::InitWithBytes(bitstream);
auto reader = xc7series::BitstreamReader::InitWithBytes(bitstream);
EXPECT_TRUE(reader);
}
@ -25,7 +25,7 @@ TEST(BitstreamReaderTest,
0xFF, 0xFE,
0xAA, 0x99, 0x55, 0x66
};
auto reader = BitstreamReader::InitWithBytes(bitstream);
auto reader = xc7series::BitstreamReader::InitWithBytes(bitstream);
EXPECT_TRUE(reader);
}
@ -35,7 +35,7 @@ TEST(BitstreamReaderTest,
0xFF, 0xFE, 0xFD, 0xFC,
0xAA, 0x99, 0x55, 0x66
};
auto reader = BitstreamReader::InitWithBytes(bitstream);
auto reader = xc7series::BitstreamReader::InitWithBytes(bitstream);
EXPECT_TRUE(reader);
}
@ -44,12 +44,13 @@ TEST(BitstreamReaderTest, ParsesType1Packet) {
0xAA, 0x99, 0x55, 0x66, // sync
0b001'00'000, 0b00000000, 0b000'00'000, 0b00000000, // NOP
};
auto reader = BitstreamReader::InitWithBytes(bitstream);
auto reader = xc7series::BitstreamReader::InitWithBytes(bitstream);
ASSERT_TRUE(reader);
ASSERT_NE(reader->begin(), reader->end());
auto first_packet = reader->begin();
EXPECT_EQ(first_packet->opcode(), ConfigurationPacket::Opcode::NOP);
EXPECT_EQ(first_packet->opcode(),
xc7series::ConfigurationPacket::Opcode::NOP);
EXPECT_EQ(++first_packet, reader->end());
}
@ -59,7 +60,7 @@ TEST(BitstreamReaderTest, ParseType2PacketWithoutType1Fails) {
0xAA, 0x99, 0x55, 0x66, // sync
0b010'00'000, 0b00000000, 0b000'00'000, 0b00000000, // NOP
};
auto reader = BitstreamReader::InitWithBytes(bitstream);
auto reader = xc7series::BitstreamReader::InitWithBytes(bitstream);
ASSERT_TRUE(reader);
EXPECT_EQ(reader->begin(), reader->end());
}
@ -78,19 +79,23 @@ TEST(BitstreamReaderTest, ParsesType2AfterType1Packet) {
std::vector<uint32_t> data_words{
0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10};
auto reader = BitstreamReader::InitWithBytes(bitstream);
auto reader = xc7series::BitstreamReader::InitWithBytes(bitstream);
ASSERT_TRUE(reader);
ASSERT_NE(reader->begin(), reader->end());
auto first_packet = reader->begin();
EXPECT_EQ(first_packet->opcode(), ConfigurationPacket::Opcode::Read);
EXPECT_EQ(first_packet->address(), static_cast<uint32_t>(0x3));
EXPECT_EQ(first_packet->opcode(),
xc7series::ConfigurationPacket::Opcode::Read);
EXPECT_EQ(first_packet->address(),
xc7series::ConfigurationRegister::FDRO);
EXPECT_EQ(first_packet->data(), absl::Span<uint32_t>());
auto second_packet = ++first_packet;
ASSERT_NE(second_packet, reader->end());
EXPECT_EQ(second_packet->opcode(), ConfigurationPacket::Opcode::Read);
EXPECT_EQ(second_packet->address(), static_cast<uint32_t>(0x3));
EXPECT_EQ(second_packet->opcode(),
xc7series::ConfigurationPacket::Opcode::Read);
EXPECT_EQ(second_packet->address(),
xc7series::ConfigurationRegister::FDRO);
EXPECT_EQ(first_packet->data(), absl::Span<uint32_t>(data_words));
EXPECT_EQ(++first_packet, reader->end());

View File

@ -0,0 +1,31 @@
#include <prjxray/xilinx/xc7series/configuration_frame_address.h>
#include <prjxray/bit_ops.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
BlockType ConfigurationFrameAddress::block_type() const {
return static_cast<BlockType>(bit_field_get(address_, 25, 23));
}
bool ConfigurationFrameAddress::is_bottom_half_rows() const {
return bit_field_get(address_, 22, 22);
}
uint8_t ConfigurationFrameAddress::row_address() const {
return bit_field_get(address_, 21, 17);
}
uint16_t ConfigurationFrameAddress::column_address() const {
return bit_field_get(address_, 16, 7);
}
uint8_t ConfigurationFrameAddress::minor_address() const {
return bit_field_get(address_, 6, 0);
}
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray

View File

@ -1,5 +1,6 @@
#include <prjxray/xilinx/xc7series/configuration_packet.h>
#include <iomanip>
#include <ostream>
#include <prjxray/bit_ops.h>
@ -19,7 +20,9 @@ ConfigurationPacket::InitWithWords(absl::Span<uint32_t> words,
case 0b001: {
Opcode opcode = static_cast<Opcode>(
bit_field_get(words[0], 28, 27));
uint32_t address = bit_field_get(words[0], 26, 13);
ConfigurationRegister address =
static_cast<ConfigurationRegister>(
bit_field_get(words[0], 26, 13));
uint32_t data_word_count = bit_field_get(words[0], 10, 0);
// If the full packet has not been received, return as though
@ -61,13 +64,21 @@ std::ostream& operator<<(std::ostream& o, const ConfigurationPacket &packet) {
case ConfigurationPacket::Opcode::NOP:
return o << "[NOP]" << std::endl;
case ConfigurationPacket::Opcode::Read:
return o << "[Read Address=" << packet.address()
<< " Length=" << packet.data().size() <<
"]" << std::endl;
return o << "[Read Address="
<< std::setw(2)
<< static_cast<int>(packet.address())
<< " Length="
<< std::setw(10) << packet.data().size()
<< " Reg=\"" << packet.address() << "\""
<< "]" << std::endl;
case ConfigurationPacket::Opcode::Write:
return o << "[Write Address=" << packet.address()
<< " Length=" << packet.data().size() <<
"]" << std::endl;
return o << "[Write Address="
<< std::setw(2)
<< static_cast<int>(packet.address())
<< " Length="
<< std::setw(10) << packet.data().size()
<< " Reg=\"" << packet.address() << "\""
<< "]" << std::endl;
default:
return o << "[Invalid Opcode]" << std::endl;
}

View File

@ -6,7 +6,7 @@
#include <gtest/gtest.h>
#include <prjxray/bit_ops.h>
using prjxray::xilinx::xc7series::ConfigurationPacket;
namespace xc7series = prjxray::xilinx::xc7series;
constexpr uint32_t kType1NOP = prjxray::bit_field_set<uint32_t>(0, 31, 29, 0x1);
@ -31,7 +31,7 @@ constexpr uint32_t MakeType2(const int opcode, const int word_count) {
TEST(ConfigPacket, InitWithZeroBytes) {
auto packet = ConfigurationPacket::InitWithWords({});
auto packet = xc7series::ConfigurationPacket::InitWithWords({});
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
EXPECT_FALSE(packet.second);
@ -40,56 +40,65 @@ TEST(ConfigPacket, InitWithZeroBytes) {
TEST(ConfigPacket, InitWithType1Nop) {
std::vector<uint32_t> words{kType1NOP};
absl::Span<uint32_t> word_span(words);
auto packet = ConfigurationPacket::InitWithWords(word_span);
auto packet = xc7series::ConfigurationPacket::InitWithWords(word_span);
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
ASSERT_TRUE(packet.second);
EXPECT_EQ(packet.second->opcode(), ConfigurationPacket::Opcode::NOP);
EXPECT_EQ(packet.second->address(), static_cast<uint32_t>(0));
EXPECT_EQ(packet.second->opcode(),
xc7series::ConfigurationPacket::Opcode::NOP);
EXPECT_EQ(packet.second->address(),
xc7series::ConfigurationRegister::CRC);
EXPECT_EQ(packet.second->data(), absl::Span<uint32_t>());
}
TEST(ConfigPacket, InitWithType1Read) {
std::vector<uint32_t> words{MakeType1(0x1, 0x1234, 2), 0xAA, 0xBB};
std::vector<uint32_t> words{MakeType1(0x1, 0x2, 2), 0xAA, 0xBB};
absl::Span<uint32_t> word_span(words);
auto packet = ConfigurationPacket::InitWithWords(word_span);
auto packet = xc7series::ConfigurationPacket::InitWithWords(word_span);
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
ASSERT_TRUE(packet.second);
EXPECT_EQ(packet.second->opcode(), ConfigurationPacket::Opcode::Read);
EXPECT_EQ(packet.second->address(), static_cast<uint32_t>(0x1234));
EXPECT_EQ(packet.second->opcode(),
xc7series::ConfigurationPacket::Opcode::Read);
EXPECT_EQ(packet.second->address(),
xc7series::ConfigurationRegister::FDRI);
EXPECT_EQ(packet.second->data(), word_span.subspan(1));
}
TEST(ConfigPacket, InitWithType1Write) {
std::vector<uint32_t> words{MakeType1(0x2, 0x1234, 2), 0xAA, 0xBB};
std::vector<uint32_t> words{MakeType1(0x2, 0x3, 2), 0xAA, 0xBB};
absl::Span<uint32_t> word_span(words);
auto packet = ConfigurationPacket::InitWithWords(word_span);
auto packet = xc7series::ConfigurationPacket::InitWithWords(word_span);
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
ASSERT_TRUE(packet.second);
EXPECT_EQ(packet.second->opcode(), ConfigurationPacket::Opcode::Write);
EXPECT_EQ(packet.second->address(), static_cast<uint32_t>(0x1234));
EXPECT_EQ(packet.second->opcode(),
xc7series::ConfigurationPacket::Opcode::Write);
EXPECT_EQ(packet.second->address(),
xc7series::ConfigurationRegister::FDRO);
EXPECT_EQ(packet.second->data(), word_span.subspan(1));
}
TEST(ConfigPacket, InitWithType2WithoutPreviousPacketFails) {
std::vector<uint32_t> words{MakeType2(0x01, 12)};
absl::Span<uint32_t> word_span(words);
auto packet = ConfigurationPacket::InitWithWords(word_span);
auto packet = xc7series::ConfigurationPacket::InitWithWords(word_span);
EXPECT_EQ(packet.first, words);
EXPECT_FALSE(packet.second);
}
TEST(ConfigPacket, InitWithType2WithPreviousPacket) {
ConfigurationPacket previous_packet(
ConfigurationPacket::Opcode::Read, 0x1234,
xc7series::ConfigurationPacket previous_packet(
xc7series::ConfigurationPacket::Opcode::Read,
xc7series::ConfigurationRegister::MFWR,
absl::Span<uint32_t>());
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::InitWithWords(
auto packet = xc7series::ConfigurationPacket::InitWithWords(
word_span, &previous_packet);
EXPECT_EQ(packet.first, absl::Span<uint32_t>());
ASSERT_TRUE(packet.second);
EXPECT_EQ(packet.second->opcode(), ConfigurationPacket::Opcode::Read);
EXPECT_EQ(packet.second->address(), static_cast<uint32_t>(0x1234));
EXPECT_EQ(packet.second->opcode(),
xc7series::ConfigurationPacket::Opcode::Read);
EXPECT_EQ(packet.second->address(),
xc7series::ConfigurationRegister::MFWR);
EXPECT_EQ(packet.second->data(), word_span.subspan(1));
}

View File

@ -0,0 +1,57 @@
#include <prjxray/xilinx/xc7series/configuration_register.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
std::ostream& operator<<(std::ostream &o, const ConfigurationRegister &value) {
switch (value) {
case ConfigurationRegister::CRC:
return o << "CRC";
case ConfigurationRegister::FAR:
return o << "Frame Address";
case ConfigurationRegister::FDRI:
return o << "Frame Data Input";
case ConfigurationRegister::FDRO:
return o << "Frame Data Output";
case ConfigurationRegister::CMD:
return o << "Command";
case ConfigurationRegister::CTL0:
return o << "Control 0";
case ConfigurationRegister::MASK:
return o << "Mask for CTL0 and CTL1";
case ConfigurationRegister::STAT:
return o << "Status";
case ConfigurationRegister::LOUT:
return o << "Legacy Output";
case ConfigurationRegister::COR0:
return o << "Configuration Option 0";
case ConfigurationRegister::MFWR:
return o << "Multiple Frame Write";
case ConfigurationRegister::CBC:
return o << "Initial CBC Value";
case ConfigurationRegister::IDCODE:
return o << "Device ID";
case ConfigurationRegister::AXSS:
return o << "User Access";
case ConfigurationRegister::COR1:
return o << "Configuration Option 1";
case ConfigurationRegister::WBSTAR:
return o << "Warm Boot Start Address";
case ConfigurationRegister::TIMER:
return o << "Watchdog Timer";
case ConfigurationRegister::BOOTSTS:
return o << "Boot History Status";
case ConfigurationRegister::CTL1:
return o << "Control 1";
case ConfigurationRegister::BSPI:
return o << "BPI/SPI Configuration Options";
default:
return o << "Unknown";
}
};
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray