mirror of https://github.com/openXC7/prjxray.git
Merge pull request #72 from kc8apf/xc7patch_emit_init_final_seq
Replace init/final sequence hacks with less hacky solution
This commit is contained in:
commit
d287de935a
|
|
@ -23,7 +23,7 @@ namespace xc7series {
|
|||
class BitstreamWriter {
|
||||
public:
|
||||
typedef std::array<uint32_t, 6> header_t;
|
||||
typedef std::vector<ConfigurationPacket> packets_t;
|
||||
typedef std::vector<std::unique_ptr<ConfigurationPacket>> packets_t;
|
||||
// Only defined if a packet exists
|
||||
typedef absl::optional<absl::Span<const uint32_t>> op_data_t;
|
||||
typedef absl::Span<const uint32_t>::iterator data_iterator_t;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_COMMAND_H_
|
||||
#define PRJXRAY_LIB_XILINX_XC7SERIES_COMMAND_H_
|
||||
|
||||
namespace prjxray {
|
||||
namespace xilinx {
|
||||
namespace xc7series {
|
||||
|
||||
enum class Command : uint32_t {
|
||||
NOP = 0x0,
|
||||
WCFG = 0x1,
|
||||
MFW = 0x2,
|
||||
LFRM = 0x3,
|
||||
RCFG = 0x4,
|
||||
START = 0x5,
|
||||
RCAP = 0x6,
|
||||
RCRC = 0x7,
|
||||
AGHIGH = 0x8,
|
||||
SWITCH = 0x9,
|
||||
GRESTORE = 0xA,
|
||||
SHUTDOWN = 0xB,
|
||||
GCAPTURE = 0xC,
|
||||
DESYNC = 0xD,
|
||||
IPROG = 0xF,
|
||||
CRCC = 0x10,
|
||||
LTIMER = 0x11,
|
||||
BSPI_READ = 0x12,
|
||||
FALL_EDGE = 0x13,
|
||||
};
|
||||
|
||||
} // namespace xc7series
|
||||
} // namespace xilinx
|
||||
} // namespace prjxray
|
||||
|
||||
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_COMMAND_H_
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_OPTIONS_0_VALUE_H
|
||||
#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_OPTIONS_0_VALUE_H
|
||||
|
||||
#include <prjxray/bit_ops.h>
|
||||
#include <prjxray/xilinx/xc7series/configuration_packet.h>
|
||||
#include <prjxray/xilinx/xc7series/configuration_register.h>
|
||||
|
||||
namespace prjxray {
|
||||
namespace xilinx {
|
||||
namespace xc7series {
|
||||
|
||||
class ConfigurationOptions0Value {
|
||||
public:
|
||||
enum class StartupClockSource : uint32_t {
|
||||
CCLK = 0x0,
|
||||
User = 0x1,
|
||||
JTAG = 0x2,
|
||||
};
|
||||
|
||||
enum class SignalReleaseCycle : uint32_t {
|
||||
Phase1 = 0x0,
|
||||
Phase2 = 0x1,
|
||||
Phase3 = 0x2,
|
||||
Phase4 = 0x3,
|
||||
Phase5 = 0x4,
|
||||
Phase6 = 0x5,
|
||||
TrackDone = 0x6,
|
||||
Keep = 0x7,
|
||||
};
|
||||
|
||||
enum class StallCycle : uint32_t {
|
||||
Phase0 = 0x0,
|
||||
Phase1 = 0x1,
|
||||
Phase2 = 0x2,
|
||||
Phase3 = 0x3,
|
||||
Phase4 = 0x4,
|
||||
Phase5 = 0x5,
|
||||
Phase6 = 0x6,
|
||||
NoWait = 0x7,
|
||||
};
|
||||
|
||||
ConfigurationOptions0Value() : value_(0) {}
|
||||
|
||||
operator uint32_t() const { return value_; }
|
||||
|
||||
ConfigurationOptions0Value& SetUseDonePinAsPowerdownStatus(
|
||||
bool enabled) {
|
||||
value_ = bit_field_set(value_, 27, 27, enabled ? 1 : 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConfigurationOptions0Value& SetAddPipelineStageForDoneIn(bool enabled) {
|
||||
value_ = bit_field_set(value_, 25, 25, enabled ? 1 : 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConfigurationOptions0Value& SetDriveDoneHigh(bool enabled) {
|
||||
value_ = bit_field_set(value_, 24, 24, enabled);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConfigurationOptions0Value& SetReadbackIsSingleShot(bool enabled) {
|
||||
value_ = bit_field_set(value_, 23, 23, enabled);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConfigurationOptions0Value& SetCclkFrequency(uint32_t mhz) {
|
||||
value_ = bit_field_set(value_, 22, 17, mhz);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConfigurationOptions0Value& SetStartupClockSource(
|
||||
StartupClockSource source) {
|
||||
value_ = bit_field_set(value_, 16, 15,
|
||||
static_cast<uint32_t>(source));
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConfigurationOptions0Value& SetReleaseDonePinAtStartupCycle(
|
||||
SignalReleaseCycle cycle) {
|
||||
value_ =
|
||||
bit_field_set(value_, 14, 12, static_cast<uint32_t>(cycle));
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConfigurationOptions0Value& SetStallAtStartupCycleUntilDciMatch(
|
||||
StallCycle cycle) {
|
||||
value_ =
|
||||
bit_field_set(value_, 11, 9, static_cast<uint32_t>(cycle));
|
||||
return *this;
|
||||
};
|
||||
|
||||
ConfigurationOptions0Value& SetStallAtStartupCycleUntilMmcmLock(
|
||||
StallCycle cycle) {
|
||||
value_ =
|
||||
bit_field_set(value_, 8, 6, static_cast<uint32_t>(cycle));
|
||||
return *this;
|
||||
};
|
||||
|
||||
ConfigurationOptions0Value& SetReleaseGtsSignalAtStartupCycle(
|
||||
SignalReleaseCycle cycle) {
|
||||
value_ =
|
||||
bit_field_set(value_, 5, 3, static_cast<uint32_t>(cycle));
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConfigurationOptions0Value& SetReleaseGweSignalAtStartupCycle(
|
||||
SignalReleaseCycle cycle) {
|
||||
value_ =
|
||||
bit_field_set(value_, 2, 0, static_cast<uint32_t>(cycle));
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t value_;
|
||||
}; // namespace xc7series
|
||||
|
||||
} // namespace xc7series
|
||||
} // namespace xilinx
|
||||
} // namespace prjxray
|
||||
|
||||
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_OPTIONS_0_VALUE_H
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H
|
||||
#define PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <absl/types/span.h>
|
||||
#include <prjxray/bit_ops.h>
|
||||
#include <prjxray/xilinx/xc7series/configuration_packet.h>
|
||||
#include <prjxray/xilinx/xc7series/configuration_register.h>
|
||||
|
||||
namespace prjxray {
|
||||
namespace xilinx {
|
||||
namespace xc7series {
|
||||
|
||||
template <int Words>
|
||||
class ConfigurationPacketWithPayload : public ConfigurationPacket {
|
||||
public:
|
||||
ConfigurationPacketWithPayload(
|
||||
Opcode op,
|
||||
ConfigurationRegister reg,
|
||||
const std::array<uint32_t, Words>& payload)
|
||||
: ConfigurationPacket(1, op, reg, absl::Span<uint32_t>(payload_)),
|
||||
payload_(std::move(payload)) {}
|
||||
|
||||
private:
|
||||
std::array<uint32_t, Words> payload_;
|
||||
}; // namespace xc7series
|
||||
|
||||
} // namespace xc7series
|
||||
} // namespace xilinx
|
||||
} // namespace prjxray
|
||||
|
||||
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H
|
||||
|
|
@ -25,6 +25,7 @@ enum class ConfigurationRegister : unsigned int {
|
|||
COR1 = 0x0e,
|
||||
WBSTAR = 0x10,
|
||||
TIMER = 0x11,
|
||||
UNKNOWN = 0x13,
|
||||
BOOTSTS = 0x16,
|
||||
CTL1 = 0x18,
|
||||
BSPI = 0x1F,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H
|
||||
#define PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H
|
||||
|
||||
#include <prjxray/xilinx/xc7series/configuration_packet.h>
|
||||
#include <prjxray/xilinx/xc7series/configuration_register.h>
|
||||
|
||||
namespace prjxray {
|
||||
namespace xilinx {
|
||||
namespace xc7series {
|
||||
|
||||
class NopPacket : public ConfigurationPacket {
|
||||
public:
|
||||
NopPacket()
|
||||
: ConfigurationPacket(1,
|
||||
Opcode::NOP,
|
||||
ConfigurationRegister::CRC,
|
||||
{}) {}
|
||||
};
|
||||
|
||||
} // namespace xc7series
|
||||
} // namespace xilinx
|
||||
} // namespace prjxray
|
||||
|
||||
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H
|
||||
|
|
@ -28,7 +28,7 @@ BitstreamWriter::BitstreamWriter(const packets_t& packets)
|
|||
|
||||
BitstreamWriter::packet_iterator BitstreamWriter::iterator::packet_begin() {
|
||||
// itr_packets = packets.begin();
|
||||
const ConfigurationPacket& packet = *itr_packets_;
|
||||
const ConfigurationPacket& packet = **itr_packets_;
|
||||
|
||||
return BitstreamWriter::packet_iterator(
|
||||
&packet, BitstreamWriter::packet_iterator::STATE_HEADER,
|
||||
|
|
@ -36,7 +36,7 @@ BitstreamWriter::packet_iterator BitstreamWriter::iterator::packet_begin() {
|
|||
}
|
||||
|
||||
BitstreamWriter::packet_iterator BitstreamWriter::iterator::packet_end() {
|
||||
const ConfigurationPacket& packet = *itr_packets_;
|
||||
const ConfigurationPacket& packet = **itr_packets_;
|
||||
|
||||
return BitstreamWriter::packet_iterator(
|
||||
&packet, BitstreamWriter::packet_iterator::STATE_END,
|
||||
|
|
@ -138,7 +138,7 @@ BitstreamWriter::iterator BitstreamWriter::begin() {
|
|||
if (itr_packets != packets_.end()) {
|
||||
// op_packet_itr = packet_begin();
|
||||
// FIXME: de-duplicate this
|
||||
const ConfigurationPacket& packet = *itr_packets;
|
||||
const ConfigurationPacket& packet = **itr_packets;
|
||||
packet_iterator packet_itr =
|
||||
packet_iterator(&packet, packet_iterator::STATE_HEADER,
|
||||
packet.data().begin());
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@ void dump_packets(xc7series::BitstreamWriter writer, bool nl = true) {
|
|||
}
|
||||
|
||||
// Special all 0's
|
||||
void AddType0(std::vector<xc7series::ConfigurationPacket>& packets) {
|
||||
void AddType0(
|
||||
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>>& packets) {
|
||||
// InitWithWords doesn't like type 0
|
||||
/*
|
||||
static std::vector<uint32_t> words{0x00000000};
|
||||
|
|
@ -61,27 +62,32 @@ void AddType0(std::vector<xc7series::ConfigurationPacket>& packets) {
|
|||
static std::vector<uint32_t> words{};
|
||||
absl::Span<uint32_t> word_span(words);
|
||||
// CRC is config value 0
|
||||
packets.push_back(xc7series::ConfigurationPacket(
|
||||
packets.emplace_back(new xc7series::ConfigurationPacket(
|
||||
0, xc7series::ConfigurationPacket::NOP,
|
||||
xc7series::ConfigurationRegister::CRC, word_span));
|
||||
}
|
||||
|
||||
void AddType1(std::vector<xc7series::ConfigurationPacket>& packets) {
|
||||
void AddType1(
|
||||
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>>& packets) {
|
||||
static std::vector<uint32_t> words{MakeType1(0x2, 0x3, 2), 0xAA, 0xBB};
|
||||
absl::Span<uint32_t> word_span(words);
|
||||
auto packet = xc7series::ConfigurationPacket::InitWithWords(word_span);
|
||||
packets.push_back(*(packet.second));
|
||||
packets.emplace_back(
|
||||
new xc7series::ConfigurationPacket(*(packet.second)));
|
||||
}
|
||||
|
||||
// Empty
|
||||
void AddType1E(std::vector<xc7series::ConfigurationPacket>& packets) {
|
||||
void AddType1E(
|
||||
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>>& packets) {
|
||||
static std::vector<uint32_t> words{MakeType1(0x2, 0x3, 0)};
|
||||
absl::Span<uint32_t> word_span(words);
|
||||
auto packet = xc7series::ConfigurationPacket::InitWithWords(word_span);
|
||||
packets.push_back(*(packet.second));
|
||||
packets.emplace_back(
|
||||
new xc7series::ConfigurationPacket(*(packet.second)));
|
||||
}
|
||||
|
||||
void AddType2(std::vector<xc7series::ConfigurationPacket>& packets) {
|
||||
void AddType2(
|
||||
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>>& packets) {
|
||||
// Type 1 packet with address
|
||||
// Without this InitWithWords will fail on type 2
|
||||
xc7series::ConfigurationPacket* packet1;
|
||||
|
|
@ -90,8 +96,9 @@ void AddType2(std::vector<xc7series::ConfigurationPacket>& packets) {
|
|||
absl::Span<uint32_t> word_span(words);
|
||||
auto packet1_pair =
|
||||
xc7series::ConfigurationPacket::InitWithWords(word_span);
|
||||
packets.push_back(*(packet1_pair.second));
|
||||
packet1 = &packets[0];
|
||||
packets.emplace_back(
|
||||
new xc7series::ConfigurationPacket(*(packet1_pair.second)));
|
||||
packet1 = packets[0].get();
|
||||
}
|
||||
// Type 2 packet with data
|
||||
{
|
||||
|
|
@ -100,13 +107,14 @@ void AddType2(std::vector<xc7series::ConfigurationPacket>& packets) {
|
|||
absl::Span<uint32_t> word_span(words);
|
||||
auto packet = xc7series::ConfigurationPacket::InitWithWords(
|
||||
word_span, packet1);
|
||||
packets.push_back(*(packet.second));
|
||||
packets.emplace_back(
|
||||
new xc7series::ConfigurationPacket(*(packet.second)));
|
||||
}
|
||||
}
|
||||
|
||||
// Empty packets should produce just the header
|
||||
TEST(BitstreamWriterTest, WriteHeader) {
|
||||
std::vector<xc7series::ConfigurationPacket> packets;
|
||||
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>> packets;
|
||||
|
||||
xc7series::BitstreamWriter writer(packets);
|
||||
std::vector<uint32_t> words(writer.begin(), writer.end());
|
||||
|
|
@ -120,7 +128,7 @@ TEST(BitstreamWriterTest, WriteHeader) {
|
|||
}
|
||||
|
||||
TEST(BitstreamWriterTest, WriteType0) {
|
||||
std::vector<xc7series::ConfigurationPacket> packets;
|
||||
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>> packets;
|
||||
AddType0(packets);
|
||||
xc7series::BitstreamWriter writer(packets);
|
||||
// dump_packets(writer, false);
|
||||
|
|
@ -133,7 +141,7 @@ TEST(BitstreamWriterTest, WriteType0) {
|
|||
EXPECT_EQ(words, ref);
|
||||
}
|
||||
TEST(BitstreamWriterTest, WriteType1) {
|
||||
std::vector<xc7series::ConfigurationPacket> packets;
|
||||
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>> packets;
|
||||
AddType1(packets);
|
||||
xc7series::BitstreamWriter writer(packets);
|
||||
// dump_packets(writer, false);
|
||||
|
|
@ -147,7 +155,7 @@ TEST(BitstreamWriterTest, WriteType1) {
|
|||
}
|
||||
|
||||
TEST(BitstreamWriterTest, WriteType2) {
|
||||
std::vector<xc7series::ConfigurationPacket> packets;
|
||||
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>> packets;
|
||||
AddType2(packets);
|
||||
xc7series::BitstreamWriter writer(packets);
|
||||
// dump_packets(writer, false);
|
||||
|
|
@ -164,7 +172,7 @@ TEST(BitstreamWriterTest, WriteType2) {
|
|||
}
|
||||
|
||||
TEST(BitstreamWriterTest, WriteMulti) {
|
||||
std::vector<xc7series::ConfigurationPacket> packets;
|
||||
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>> packets;
|
||||
AddType1(packets);
|
||||
AddType1E(packets);
|
||||
AddType2(packets);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.PRECIOUS: harness_impl.dcp %_impl.dcp %.bit
|
||||
.PRECIOUS: harness_impl.dcp %_impl.dcp %.bit %_roi_partial.bit
|
||||
|
||||
# Top-level target for generating a programmable bitstream. Given a .fasm
|
||||
# file, calling make with the .fasm extension replaced with _hand_crafted.bit
|
||||
|
|
@ -6,49 +6,14 @@
|
|||
# ready for programming to a board. For example,
|
||||
# 'make inv_hand_crafted.bit' will generate a bitstream that includes the
|
||||
# design from roi_noninv.fasm.
|
||||
%_hand_crafted.bit: init_sequence.bit %_no_headers.bin final_sequence.bin
|
||||
cat $^ > $@
|
||||
|
||||
%_no_headers.bin: %_patched.bin
|
||||
# WARNING: these values need to be tweaked if anything about the
|
||||
# Vivado-generated design changes.
|
||||
xxd -p -s 0x18 $< | xxd -r -p - $@
|
||||
|
||||
%_patched.bin: %_roi_partial.frm harness.bit
|
||||
%_hand_crafted.bit: %_roi_partial.frm harness.bit
|
||||
${XRAY_TOOLS_DIR}/xc7patch \
|
||||
--part_file ${XRAY_PART_YAML} \
|
||||
--part_name "${XRAY_PART}" \
|
||||
--part_file "${XRAY_PART_YAML}" \
|
||||
--bitstream_file harness.bit \
|
||||
--frm_file $< \
|
||||
--output_file $@
|
||||
|
||||
# xc7patch currently only generates the actual frame writes which is
|
||||
# insufficient to program a device. Grab the initialization and finalization
|
||||
# sequences from the harness bitstream so they can be tacked on to the
|
||||
# xc7patch-generated bitstream to create a programmable bitstream.
|
||||
#
|
||||
# The offsets used below were determined by manually inspecting
|
||||
# harness.bit with a hex editor. init_sequence.bit is the beginning of
|
||||
# the file until just before the actual frame data is sent via a write to FDRI.
|
||||
# final_sequence.bin is from just after the frame data write to the end of the
|
||||
# file. Note that final_sequence.bin normally includes at least one CRC check.
|
||||
# The sed command replaces any CRC checks with a Reset CRC command which is the
|
||||
# same behavior as setting BITSTREAM.GENERAL.CRC to Disabled. These offset
|
||||
# should not change unless you alter the bitstream format used (i.e. setting
|
||||
# BITSTREAM.GENERAL.DEBUGBITSTREAM or BITSTREAM.GENERAL.PERFRAMECRC to YES).
|
||||
init_sequence.bit: harness.bit
|
||||
# WARNING: these values need to be tweaked if anything about the
|
||||
# Vivado-generated design changes.
|
||||
xxd -p -l 0x147 $< | xxd -r -p - $@
|
||||
|
||||
final_sequence.bin: harness.bit
|
||||
# WARNING: these values need to be tweaked if anything about the
|
||||
# Vivado-generated design changes.
|
||||
xxd -p -s 0x216abf $< | \
|
||||
tr -d '\n' | \
|
||||
sed -e 's/30000001.\{8\}/3000800100000007/g' | \
|
||||
fold -w 40 | \
|
||||
xxd -r -p - $@
|
||||
|
||||
# Generate a suitable harness by using Vivado's partial reconfiguration
|
||||
# feature. inv.v is used as a sample reconfiguration design as one is
|
||||
# required to generate a partial reconfiguration design.
|
||||
|
|
|
|||
|
|
@ -30,28 +30,11 @@ echo "Out .bit: $bit_out"
|
|||
${XRAY_DIR}/tools/fasm2frame.py $fasm_in roi_partial.frm
|
||||
|
||||
${XRAY_TOOLS_DIR}/xc7patch \
|
||||
--part_name ${XRAY_PART} \
|
||||
--part_file ${XRAY_PART_YAML} \
|
||||
--bitstream_file $bit_in \
|
||||
--frm_file roi_partial.frm \
|
||||
--output_file patched.bin
|
||||
|
||||
# WARNING: these values need to be tweaked if anything about the
|
||||
# Vivado-generated design changes.
|
||||
xxd -p -l 0x147 $bit_in | xxd -r -p - init_sequence.bit
|
||||
|
||||
# WARNING: these values need to be tweaked if anything about the
|
||||
# Vivado-generated design changes.
|
||||
xxd -p -s 0x18 patched.bin | xxd -r -p - no_headers.bin
|
||||
|
||||
# WARNING: these values need to be tweaked if anything about the
|
||||
# Vivado-generated design changes.
|
||||
xxd -p -s 0x216abf $bit_in | \
|
||||
tr -d '\n' | \
|
||||
sed -e 's/30000001.\{8\}/3000800100000007/g' | \
|
||||
fold -w 40 | \
|
||||
xxd -r -p - final_sequence.bin
|
||||
|
||||
cat init_sequence.bit no_headers.bin final_sequence.bin >$bit_out
|
||||
--output_file $bit_out
|
||||
|
||||
#openocd -f $XRAY_DIR/utils/openocd/board-digilent-basys3.cfg -c "init; pld load 0 $bit_out; exit"
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ target_link_libraries(gen_part_base_yaml
|
|||
add_executable(xc7patch xc7patch.cc)
|
||||
target_link_libraries(xc7patch
|
||||
absl::strings
|
||||
absl::time
|
||||
gflags
|
||||
libprjxray
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,14 +5,23 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <absl/strings/str_cat.h>
|
||||
#include <absl/strings/str_split.h>
|
||||
#include <absl/time/clock.h>
|
||||
#include <absl/time/time.h>
|
||||
#include <gflags/gflags.h>
|
||||
#include <prjxray/memory_mapped_file.h>
|
||||
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
|
||||
#include <prjxray/xilinx/xc7series/bitstream_writer.h>
|
||||
#include <prjxray/xilinx/xc7series/command.h>
|
||||
#include <prjxray/xilinx/xc7series/configuration.h>
|
||||
#include <prjxray/xilinx/xc7series/configuration_options_0_value.h>
|
||||
#include <prjxray/xilinx/xc7series/configuration_packet_with_payload.h>
|
||||
#include <prjxray/xilinx/xc7series/ecc.h>
|
||||
#include <prjxray/xilinx/xc7series/nop_packet.h>
|
||||
#include <prjxray/xilinx/xc7series/part.h>
|
||||
|
||||
DEFINE_string(part_name, "", "");
|
||||
DEFINE_string(part_file, "", "Definition file for target 7-series part");
|
||||
DEFINE_string(bitstream_file,
|
||||
"",
|
||||
|
|
@ -111,54 +120,16 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
uint32_t ecc = 0;
|
||||
for (size_t ii = 0; ii < frame_data.size(); ++ii) {
|
||||
uint32_t word = frame_data[ii];
|
||||
uint32_t offset = ii * 32;
|
||||
if (ii > 0x25) {
|
||||
offset += 0x1360;
|
||||
} else if (ii > 0x6) {
|
||||
offset += 0x1340;
|
||||
} else {
|
||||
offset += 0x1320;
|
||||
}
|
||||
|
||||
// Mask out where the ECC should be.
|
||||
if (ii == 0x32) {
|
||||
word &= 0xFFFFE000;
|
||||
}
|
||||
|
||||
for (int jj = 0; jj < 32; ++jj) {
|
||||
if ((word & 1) == 1) {
|
||||
ecc ^= offset + jj;
|
||||
}
|
||||
word >>= 1;
|
||||
}
|
||||
ecc = xc7series::icap_ecc(ii, frame_data[ii], ecc);
|
||||
}
|
||||
|
||||
uint32_t v = ecc & 0xFFF;
|
||||
v ^= v >> 8;
|
||||
v ^= v >> 4;
|
||||
v ^= v >> 2;
|
||||
v ^= v >> 1;
|
||||
ecc ^= (v & 1) << 12;
|
||||
|
||||
// Replace the old ECC with the new.
|
||||
frame_data[0x32] &= 0xFFFFE000;
|
||||
frame_data[0x32] |= (ecc & 0x1FFF);
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (auto& frame : frames) {
|
||||
std::cout << "0x" << std::hex
|
||||
<< static_cast<uint32_t>(frame.first) << " ";
|
||||
|
||||
for (auto& word : frame.second) {
|
||||
std::cout << "0x" << std::hex << word << ",";
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
#endif
|
||||
std::vector<xc7series::ConfigurationPacket> out_packets;
|
||||
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>>
|
||||
out_packets;
|
||||
|
||||
// Generate a single type 2 packet that writes everything at once.
|
||||
std::vector<uint32_t> packet_data;
|
||||
|
|
@ -177,18 +148,167 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
packet_data.insert(packet_data.end(), 202, 0);
|
||||
|
||||
out_packets.push_back(xc7series::ConfigurationPacket(
|
||||
// Initialization sequence
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::TIMER, {0x0}));
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::WBSTAR, {0x0}));
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::NOP)}));
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::RCRC)}));
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::UNKNOWN, {0x0}));
|
||||
|
||||
// Configuration Options 0
|
||||
out_packets.emplace_back(new xc7series::ConfigurationPacketWithPayload<
|
||||
1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::COR0,
|
||||
{xc7series::ConfigurationOptions0Value()
|
||||
.SetAddPipelineStageForDoneIn(true)
|
||||
.SetReleaseDonePinAtStartupCycle(
|
||||
xc7series::ConfigurationOptions0Value::SignalReleaseCycle::
|
||||
Phase4)
|
||||
.SetStallAtStartupCycleUntilDciMatch(
|
||||
xc7series::ConfigurationOptions0Value::StallCycle::NoWait)
|
||||
.SetStallAtStartupCycleUntilMmcmLock(
|
||||
xc7series::ConfigurationOptions0Value::StallCycle::NoWait)
|
||||
.SetReleaseGtsSignalAtStartupCycle(
|
||||
xc7series::ConfigurationOptions0Value::SignalReleaseCycle::
|
||||
Phase5)
|
||||
.SetReleaseGweSignalAtStartupCycle(
|
||||
xc7series::ConfigurationOptions0Value::SignalReleaseCycle::
|
||||
Phase6)}));
|
||||
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::COR1, {0x0}));
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::IDCODE, {part->idcode()}));
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::SWITCH)}));
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::MASK, {0x401}));
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::CTL0, {0x501}));
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::MASK, {0x0}));
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::CTL1, {0x0}));
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::FAR, {0x0}));
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::WCFG)}));
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
|
||||
// Frame data write
|
||||
out_packets.emplace_back(new xc7series::ConfigurationPacket(
|
||||
1, xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::FDRI, {}));
|
||||
out_packets.push_back(xc7series::ConfigurationPacket(
|
||||
out_packets.emplace_back(new xc7series::ConfigurationPacket(
|
||||
2, xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::FDRI, packet_data));
|
||||
|
||||
#if 0
|
||||
for (auto& packet : out_packets) {
|
||||
std::cout << packet << std::endl;
|
||||
// Finalization sequence
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::RCRC)}));
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::GRESTORE)}));
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::LFRM)}));
|
||||
for (int ii = 0; ii < 100; ++ii) {
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
}
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::START)}));
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::FAR, {0x3be0000}));
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::MASK, {0x501}));
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::CTL0, {0x501}));
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::RCRC)}));
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
out_packets.emplace_back(
|
||||
new xc7series::ConfigurationPacketWithPayload<1>(
|
||||
xc7series::ConfigurationPacket::Opcode::Write,
|
||||
xc7series::ConfigurationRegister::CMD,
|
||||
{static_cast<uint32_t>(xc7series::Command::DESYNC)}));
|
||||
for (int ii = 0; ii < 400; ++ii) {
|
||||
out_packets.emplace_back(new xc7series::NopPacket());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Write bitstream.
|
||||
xc7series::BitstreamWriter out_bitstream_writer(out_packets);
|
||||
|
|
@ -199,6 +319,61 @@ int main(int argc, char* argv[]) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Xilinx BIT header.
|
||||
// Sync header
|
||||
std::vector<uint8_t> bit_header{0x0, 0x9, 0x0f, 0xf0, 0x0f,
|
||||
0xf0, 0x0f, 0xf0, 0x0f, 0xf0,
|
||||
0x00, 0x00, 0x01, 'a'};
|
||||
auto build_source = absl::StrCat(FLAGS_frm_file, ";Generator=xc7patch");
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>((build_source.size() + 1) >> 8));
|
||||
bit_header.push_back(static_cast<uint8_t>(build_source.size() + 1));
|
||||
bit_header.insert(bit_header.end(), build_source.begin(),
|
||||
build_source.end());
|
||||
bit_header.push_back(0x0);
|
||||
|
||||
// Source file.
|
||||
bit_header.push_back('b');
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>((FLAGS_part_name.size() + 1) >> 8));
|
||||
bit_header.push_back(static_cast<uint8_t>(FLAGS_part_name.size() + 1));
|
||||
bit_header.insert(bit_header.end(), FLAGS_part_name.begin(),
|
||||
FLAGS_part_name.end());
|
||||
bit_header.push_back(0x0);
|
||||
|
||||
// Build timestamp.
|
||||
auto build_time = absl::Now();
|
||||
auto build_date_string =
|
||||
absl::FormatTime("%E4Y/%m/%d", build_time, absl::UTCTimeZone());
|
||||
auto build_time_string =
|
||||
absl::FormatTime("%H:%M:%S", build_time, absl::UTCTimeZone());
|
||||
|
||||
bit_header.push_back('c');
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>((build_date_string.size() + 1) >> 8));
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>(build_date_string.size() + 1));
|
||||
bit_header.insert(bit_header.end(), build_date_string.begin(),
|
||||
build_date_string.end());
|
||||
bit_header.push_back(0x0);
|
||||
|
||||
bit_header.push_back('d');
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>((build_time_string.size() + 1) >> 8));
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>(build_time_string.size() + 1));
|
||||
bit_header.insert(bit_header.end(), build_time_string.begin(),
|
||||
build_time_string.end());
|
||||
bit_header.push_back(0x0);
|
||||
|
||||
bit_header.insert(bit_header.end(), {'e', 0x0, 0x0, 0x0, 0x0});
|
||||
out_file.write(reinterpret_cast<const char*>(bit_header.data()),
|
||||
bit_header.size());
|
||||
|
||||
auto end_of_header_pos = out_file.tellp();
|
||||
auto header_data_length_pos =
|
||||
end_of_header_pos - static_cast<std::ofstream::off_type>(4);
|
||||
|
||||
for (uint32_t word : out_bitstream_writer) {
|
||||
out_file.put((word >> 24) & 0xFF);
|
||||
out_file.put((word >> 16) & 0xFF);
|
||||
|
|
@ -206,5 +381,13 @@ int main(int argc, char* argv[]) {
|
|||
out_file.put((word)&0xFF);
|
||||
}
|
||||
|
||||
uint32_t length_of_data = out_file.tellp() - end_of_header_pos;
|
||||
|
||||
out_file.seekp(header_data_length_pos);
|
||||
out_file.put((length_of_data >> 24) & 0xFF);
|
||||
out_file.put((length_of_data >> 16) & 0xFF);
|
||||
out_file.put((length_of_data >> 8) & 0xFF);
|
||||
out_file.put((length_of_data)&0xFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue