|
| 1 | +#include "fpga/xilinx/arch-xc7-configuration-packet.h" |
| 2 | + |
| 3 | +#include <cstdint> |
| 4 | +#include <optional> |
| 5 | + |
| 6 | +#include "absl/types/span.h" |
| 7 | +#include "fpga/xilinx/arch-xc7-defs.h" |
| 8 | +#include "fpga/xilinx/bit-ops.h" |
| 9 | +#include "fpga/xilinx/configuration-packet.h" |
| 10 | + |
| 11 | +namespace fpga { |
| 12 | +namespace xilinx { |
| 13 | +namespace xc7 { |
| 14 | +ConfigurationPacket::ParseResult ConfigurationPacket::InitWithWordsImpl( |
| 15 | + absl::Span<uint32_t> words, const ConfigurationPacket *previous_packet) { |
| 16 | + using ConfigurationRegister = ConfigurationRegister; |
| 17 | + // Need at least one 32-bit word to have a valid packet header. |
| 18 | + if (words.empty()) { |
| 19 | + return {words, {}}; |
| 20 | + } |
| 21 | + const ConfigurationPacketType header_type = |
| 22 | + static_cast<ConfigurationPacketType>(bit_field_get(words[0], 31, 29)); |
| 23 | + switch (header_type) { |
| 24 | + case ConfigurationPacketType::kNONE: |
| 25 | + // Type 0 is emitted at the end of a configuration row |
| 26 | + // when BITSTREAM.GENERAL.DEBUGBITSTREAM is set to YES. |
| 27 | + // These seem to be padding that are interepreted as |
| 28 | + // NOPs. Since Type 0 packets don't exist according to |
| 29 | + // UG470 and they seem to be zero-filled, just consume |
| 30 | + // the bytes without generating a packet. |
| 31 | + return {words.subspan(1), |
| 32 | + {{static_cast<uint32_t>(header_type), |
| 33 | + Opcode::kNOP, |
| 34 | + ConfigurationRegister::kCRC, |
| 35 | + {}}}}; |
| 36 | + case ConfigurationPacketType::kTYPE1: { |
| 37 | + const Opcode opcode = static_cast<Opcode>(bit_field_get(words[0], 28, 27)); |
| 38 | + const ConfigurationRegister address = |
| 39 | + static_cast<ConfigurationRegister>(bit_field_get(words[0], 26, 13)); |
| 40 | + const uint32_t data_word_count = bit_field_get(words[0], 10, 0); |
| 41 | + |
| 42 | + // If the full packet has not been received, return as |
| 43 | + // though no valid packet was found. |
| 44 | + if (data_word_count > words.size() - 1) { |
| 45 | + return {words, {}}; |
| 46 | + } |
| 47 | + |
| 48 | + return {words.subspan(data_word_count + 1), |
| 49 | + {{static_cast<uint32_t>(header_type), opcode, address, |
| 50 | + words.subspan(1, data_word_count)}}}; |
| 51 | + } |
| 52 | + case ConfigurationPacketType::kTYPE2: { |
| 53 | + std::optional<ConfigurationPacket> packet; |
| 54 | + const Opcode opcode = static_cast<Opcode>(bit_field_get(words[0], 28, 27)); |
| 55 | + const uint32_t data_word_count = bit_field_get(words[0], 26, 0); |
| 56 | + |
| 57 | + // If the full packet has not been received, return as |
| 58 | + // though no valid packet was found. |
| 59 | + if (data_word_count > words.size() - 1) { |
| 60 | + return {words, {}}; |
| 61 | + } |
| 62 | + |
| 63 | + if (previous_packet) { |
| 64 | + packet = ConfigurationPacket(static_cast<uint32_t>(header_type), opcode, |
| 65 | + previous_packet->address(), |
| 66 | + words.subspan(1, data_word_count)); |
| 67 | + } |
| 68 | + |
| 69 | + return {words.subspan(data_word_count + 1), packet}; |
| 70 | + } |
| 71 | + default: return {{}, {}}; |
| 72 | + } |
| 73 | +} |
| 74 | +} // namespace xc7 |
| 75 | +} // namespace xilinx |
| 76 | +} // namespace fpga |
0 commit comments