mirror of https://github.com/openXC7/prjxray.git
226 lines
6.4 KiB
C++
226 lines
6.4 KiB
C++
/*
|
|
* TODO
|
|
* -Finish type 1/2 support
|
|
* -Review sample bitstream padding. What are they for?
|
|
*/
|
|
#include <prjxray/xilinx/xc7series/bitstream_writer.h>
|
|
|
|
#include <prjxray/bit_ops.h>
|
|
|
|
namespace prjxray {
|
|
namespace xilinx {
|
|
namespace xc7series {
|
|
|
|
// Per UG470 pg 80: Bus Width Auto Detection
|
|
std::array<uint32_t, 6> BitstreamWriter::header_{
|
|
0xFFFFFFFF, 0x000000BB, 0x11220044, 0xFFFFFFFF, 0xFFFFFFFF, 0xAA995566};
|
|
|
|
/**************************************************
|
|
* BitstreamWriter::BitstreamWriter
|
|
*************************************************/
|
|
|
|
BitstreamWriter::BitstreamWriter(const packets_t& packets)
|
|
: packets_(packets) {}
|
|
|
|
/**************************************************
|
|
*
|
|
*************************************************/
|
|
|
|
BitstreamWriter::packet_iterator BitstreamWriter::iterator::packet_begin() {
|
|
// itr_packets = packets.begin();
|
|
const ConfigurationPacket& packet = **itr_packets_;
|
|
|
|
return BitstreamWriter::packet_iterator(
|
|
&packet, BitstreamWriter::packet_iterator::STATE_HEADER,
|
|
packet.data().begin());
|
|
}
|
|
|
|
BitstreamWriter::packet_iterator BitstreamWriter::iterator::packet_end() {
|
|
const ConfigurationPacket& packet = **itr_packets_;
|
|
|
|
return BitstreamWriter::packet_iterator(
|
|
&packet, BitstreamWriter::packet_iterator::STATE_END,
|
|
// Essentially ignored
|
|
packet.data().end());
|
|
}
|
|
|
|
BitstreamWriter::packet_iterator::packet_iterator(
|
|
const ConfigurationPacket* packet,
|
|
state_t state,
|
|
data_iterator_t itr_data)
|
|
: state_(state), itr_data_(itr_data), packet_(packet) {}
|
|
|
|
BitstreamWriter::packet_iterator& BitstreamWriter::packet_iterator::
|
|
operator++() {
|
|
if (state_ == STATE_HEADER) {
|
|
itr_data_ = packet_->data().begin();
|
|
if (itr_data_ == packet_->data().end()) {
|
|
state_ = STATE_END;
|
|
} else {
|
|
state_ = STATE_DATA;
|
|
}
|
|
} else if (state_ == STATE_DATA) {
|
|
/// Advance. data must be valid while not at end
|
|
itr_data_++;
|
|
// Reached this end of this packet?
|
|
if (itr_data_ == packet_->data().end()) {
|
|
state_ = STATE_END;
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool BitstreamWriter::packet_iterator::operator==(
|
|
const packet_iterator& other) const {
|
|
return state_ == other.state_ && itr_data_ == other.itr_data_;
|
|
}
|
|
|
|
bool BitstreamWriter::packet_iterator::operator!=(
|
|
const packet_iterator& other) const {
|
|
return !(*this == other);
|
|
}
|
|
|
|
uint32_t packet2header(const ConfigurationPacket& packet) {
|
|
uint32_t ret = 0;
|
|
|
|
ret = bit_field_set(ret, 31, 29, packet.header_type());
|
|
|
|
switch (packet.header_type()) {
|
|
case 0x0:
|
|
// Bitstreams are 0 padded sometimes, essentially making
|
|
// a type 0 frame Ignore the other fields for now
|
|
break;
|
|
case 0x1: {
|
|
// Table 5-20: Type 1 Packet Header Format
|
|
ret = bit_field_set(ret, 28, 27, packet.opcode());
|
|
ret = bit_field_set(ret, 26, 13, packet.address());
|
|
ret = bit_field_set(ret, 10, 0, packet.data().length());
|
|
break;
|
|
}
|
|
case 0x2: {
|
|
// Table 5-22: Type 2 Packet Header
|
|
// Note address is from previous type 1 header
|
|
ret = bit_field_set(ret, 28, 27, packet.opcode());
|
|
ret = bit_field_set(ret, 26, 0, packet.data().length());
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
const BitstreamWriter::itr_value_type BitstreamWriter::packet_iterator::
|
|
operator*() const {
|
|
if (state_ == STATE_HEADER) {
|
|
return packet2header(*packet_);
|
|
} else if (state_ == STATE_DATA) {
|
|
return *itr_data_;
|
|
}
|
|
return 0; // XXX: assert or something?
|
|
}
|
|
|
|
const BitstreamWriter::itr_value_type BitstreamWriter::packet_iterator::
|
|
operator->() const {
|
|
return *(*this);
|
|
}
|
|
|
|
/**************************************************
|
|
* BitstreamWriter::iterator
|
|
*************************************************/
|
|
|
|
BitstreamWriter::iterator BitstreamWriter::begin() {
|
|
packets_t::const_iterator itr_packets = packets_.begin();
|
|
absl::optional<packet_iterator> op_packet_itr;
|
|
|
|
// May have no packets
|
|
if (itr_packets != packets_.end()) {
|
|
// op_packet_itr = packet_begin();
|
|
// FIXME: de-duplicate this
|
|
const ConfigurationPacket& packet = **itr_packets;
|
|
packet_iterator packet_itr =
|
|
packet_iterator(&packet, packet_iterator::STATE_HEADER,
|
|
packet.data().begin());
|
|
op_packet_itr = packet_itr;
|
|
}
|
|
return iterator(header_.begin(), packets_, itr_packets, op_packet_itr);
|
|
}
|
|
|
|
BitstreamWriter::iterator BitstreamWriter::end() {
|
|
return iterator(header_.end(), packets_, packets_.end(),
|
|
absl::optional<packet_iterator>());
|
|
}
|
|
|
|
BitstreamWriter::iterator::iterator(header_t::iterator itr_header,
|
|
const packets_t& packets,
|
|
packets_t::const_iterator itr_packets,
|
|
absl::optional<packet_iterator> itr_packet)
|
|
: itr_header_(itr_header),
|
|
packets_(packets),
|
|
itr_packets_(itr_packets),
|
|
op_itr_packet_(itr_packet) {}
|
|
|
|
BitstreamWriter::iterator& BitstreamWriter::iterator::operator++() {
|
|
// Still generating header?
|
|
if (itr_header_ != header_.end()) {
|
|
itr_header_++;
|
|
// Finished header?
|
|
// Will advance to initialized itr_packets value
|
|
// XXX: maybe should just overwrite here
|
|
if (itr_header_ == header_.end()) {
|
|
itr_packets_ = packets_.begin();
|
|
if (itr_packets_ != packets_.end()) {
|
|
op_itr_packet_ = packet_begin();
|
|
}
|
|
}
|
|
// Then somewhere in packets
|
|
} else {
|
|
// We are either at end() in which case this operation is
|
|
// invalid Or there is a packet in progress packet in progress?
|
|
// Advance it
|
|
++(*op_itr_packet_);
|
|
// Done with this packet?
|
|
if (*op_itr_packet_ == packet_end()) {
|
|
itr_packets_++;
|
|
if (itr_packets_ == packets_.end()) {
|
|
// we are at the very end
|
|
// invalidate data to be neat
|
|
op_itr_packet_.reset();
|
|
} else {
|
|
op_itr_packet_ = packet_begin();
|
|
}
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool BitstreamWriter::iterator::operator==(const iterator& other) const {
|
|
return itr_header_ == other.itr_header_ &&
|
|
itr_packets_ == other.itr_packets_ &&
|
|
op_itr_packet_ == other.op_itr_packet_;
|
|
}
|
|
|
|
bool BitstreamWriter::iterator::operator!=(const iterator& other) const {
|
|
return !(*this == other);
|
|
}
|
|
|
|
const BitstreamWriter::itr_value_type BitstreamWriter::iterator::operator*()
|
|
const {
|
|
if (itr_header_ != header_.end()) {
|
|
return *itr_header_;
|
|
} else {
|
|
// Iterating over packets, get data from current packet position
|
|
return *(*op_itr_packet_);
|
|
}
|
|
}
|
|
|
|
const BitstreamWriter::itr_value_type BitstreamWriter::iterator::operator->()
|
|
const {
|
|
return *(*this);
|
|
}
|
|
|
|
} // namespace xc7series
|
|
} // namespace xilinx
|
|
} // namespace prjxray
|