#include "globals.h" #include "decoders/decoders.h" #include "encoders/encoders.h" #include "victor9k.h" #include "crc.h" #include "sector.h" #include "readerwriter.h" #include "image.h" #include "fmt/format.h" #include "arch/victor9k/victor9k.pb.h" #include "lib/encoders/encoders.pb.h" #include "lib/layout.h" #include #include "bytes.h" static bool lastBit; static void write_zero_bits( std::vector& bits, unsigned& cursor, unsigned count) { while (count--) { if (cursor < bits.size()) lastBit = bits[cursor++] = 0; } } static void write_one_bits( std::vector& bits, unsigned& cursor, unsigned count) { while (count--) { if (cursor < bits.size()) lastBit = bits[cursor++] = 1; } } static void write_bits( std::vector& bits, unsigned& cursor, const std::vector& src) { for (bool bit : src) { if (cursor < bits.size()) lastBit = bits[cursor++] = bit; } } static void write_bits( std::vector& bits, unsigned& cursor, uint64_t data, int width) { cursor += width; lastBit = data & 1; for (int i = 0; i < width; i++) { unsigned pos = cursor - i - 1; if (pos < bits.size()) bits[pos] = data & 1; data >>= 1; } } static void write_bits( std::vector& bits, unsigned& cursor, const Bytes& bytes) { ByteReader br(bytes); BitReader bitr(br); while (!bitr.eof()) { if (cursor < bits.size()) bits[cursor++] = bitr.get(); } } static int encode_data_gcr(uint8_t data) { switch (data & 0x0f) { #define GCR_ENTRY(gcr, data) \ case data: \ return gcr; #include "data_gcr.h" #undef GCR_ENTRY } return -1; } static void write_byte(std::vector& bits, unsigned& cursor, uint8_t b) { write_bits(bits, cursor, encode_data_gcr(b >> 4), 5); write_bits(bits, cursor, encode_data_gcr(b), 5); } static void write_bytes( std::vector& bits, unsigned& cursor, const Bytes& bytes) { for (uint8_t b : bytes) write_byte(bits, cursor, b); } static void write_gap(std::vector& bits, unsigned& cursor, int length) { for (int i = 0; i < length / 10; i++) write_byte(bits, cursor, '0'); } static void write_sector(std::vector& bits, unsigned& cursor, const Victor9kEncoderProto::TrackdataProto& trackdata, const Sector& sector) { write_one_bits(bits, cursor, trackdata.pre_header_sync_bits()); write_bits(bits, cursor, VICTOR9K_SECTOR_RECORD, 10); uint8_t encodedTrack = sector.logicalTrack | (sector.logicalSide << 7); uint8_t encodedSector = sector.logicalSector; write_bytes(bits, cursor, Bytes{ encodedTrack, encodedSector, (uint8_t)(encodedTrack + encodedSector), }); write_gap(bits, cursor, trackdata.post_header_gap_bits()); write_one_bits(bits, cursor, trackdata.pre_data_sync_bits()); write_bits(bits, cursor, VICTOR9K_DATA_RECORD, 10); write_bytes(bits, cursor, sector.data); Bytes checksum(2); checksum.writer().write_le16(sumBytes(sector.data)); write_bytes(bits, cursor, checksum); write_gap(bits, cursor, trackdata.post_data_gap_bits()); } class Victor9kEncoder : public Encoder { public: Victor9kEncoder(const EncoderProto& config): Encoder(config), _config(config.victor9k()) { } private: void getTrackFormat(Victor9kEncoderProto::TrackdataProto& trackdata, unsigned track, unsigned head) { trackdata.Clear(); for (const auto& f : _config.trackdata()) { if (f.has_min_track() && (track < f.min_track())) continue; if (f.has_max_track() && (track > f.max_track())) continue; if (f.has_head() && (head != f.head())) continue; trackdata.MergeFrom(f); } } public: std::unique_ptr encode(std::shared_ptr& trackInfo, const std::vector>& sectors, const Image& image) override { Victor9kEncoderProto::TrackdataProto trackdata; getTrackFormat( trackdata, trackInfo->logicalTrack, trackInfo->logicalSide); unsigned bitsPerRevolution = (trackdata.rotational_period_ms() * 1e3) / trackdata.clock_period_us(); std::vector bits(bitsPerRevolution); nanoseconds_t clockPeriod = calculatePhysicalClockPeriod(trackdata.clock_period_us() * 1e3, trackdata.rotational_period_ms() * 1e6); unsigned cursor = 0; fillBitmapTo(bits, cursor, trackdata.post_index_gap_us() * 1e3 / clockPeriod, {true, false}); lastBit = false; for (const auto& sector : sectors) write_sector(bits, cursor, trackdata, *sector); if (cursor >= bits.size()) error("track data overrun by {} bits", cursor - bits.size()); fillBitmapTo(bits, cursor, bits.size(), {true, false}); std::unique_ptr fluxmap(new Fluxmap); fluxmap->appendBits(bits, clockPeriod); return fluxmap; } private: const Victor9kEncoderProto& _config; }; std::unique_ptr createVictor9kEncoder(const EncoderProto& config) { return std::unique_ptr(new Victor9kEncoder(config)); } // vim: sw=4 ts=4 et