| /* |
| * 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 |