diff --git a/Storage/Disk/DiskImage/Formats/AmigaADF.cpp b/Storage/Disk/DiskImage/Formats/AmigaADF.cpp index 5e738b6c9..47a1c999d 100644 --- a/Storage/Disk/DiskImage/Formats/AmigaADF.cpp +++ b/Storage/Disk/DiskImage/Formats/AmigaADF.cpp @@ -12,6 +12,8 @@ #include "../../Encodings/MFM/Encoder.hpp" #include "../../Track/PCMTrack.hpp" +#include + using namespace Storage::Disk; namespace { @@ -67,8 +69,9 @@ template void write(IteratorT begin, IteratorT end, std::un } } -template std::array checksum(IteratorT begin, IteratorT end) { - uint16_t checksum = 0; +template auto checksum(IteratorT begin, IteratorT end) { + uint16_t checksum[2]{}; + int offset = 0; while(begin != end) { const uint8_t value = *begin; ++begin; @@ -84,19 +87,27 @@ template std::array checksum(IteratorT begin, I ((value&0x02) << 1) | ((value&0x01) << 0) ); - checksum ^= spread; + checksum[offset] ^= spread; + offset ^= 1; } - return std::array{ - uint8_t(checksum >> 8), - uint8_t(checksum) + return std::array{ + uint8_t(checksum[0] >> 8), + uint8_t(checksum[0]), + uint8_t(checksum[1] >> 8), + uint8_t(checksum[1]), }; } template void write_checksum(IteratorT begin, IteratorT end, std::unique_ptr &encoder) { + // Believe it or not, this appears to be the actual checksum algorithm on the Amiga: + // + // (1) calculate the XOR checksum of the MFM-encoded data, read as 32-bit words; + // (2) throw away the clock bits; + // (3) Take the resulting 32-bit value and perform an odd-even MFM encoding on those. const auto raw_checksum = checksum(begin, end); - std::array encoded_checksum; + std::decay_t encoded_checksum{}; encode_block(raw_checksum.begin(), raw_checksum.end(), encoded_checksum.begin()); write(encoded_checksum.begin(), encoded_checksum.end(), encoder); @@ -146,23 +157,23 @@ std::shared_ptr AmigaADF::get_track_at_position(Track::Address address) { // Encode and write the header. const uint8_t header[4] = { - 0xff, // Amiga v1.0 format. - uint8_t(address.position.as_int()), // Track. - uint8_t(s), // Sector. - uint8_t(11 - s), // Sectors remaining. + 0xff, // Amiga v1.0 format. + uint8_t(address.position.as_int() * 2 + address.head), // Track. + uint8_t(s), // Sector. + uint8_t(11 - s), // Sectors remaining. }; std::array encoded_header; encode_block(std::begin(header), std::end(header), std::begin(encoded_header)); write(std::begin(encoded_header), std::end(encoded_header), encoder); - // Encode the data. - std::array encoded_data; - encode_block(&track_data[s * 512], &track_data[(s + 1) * 512], std::begin(encoded_data)); - // Write the sector label. const std::array os_recovery{}; write(os_recovery.begin(), os_recovery.end(), encoder); + // Encode the data. + std::array encoded_data; + encode_block(&track_data[s * 512], &track_data[(s + 1) * 512], std::begin(encoded_data)); + // Write checksums. write_checksum(std::begin(encoded_header), std::end(encoded_header), encoder); write_checksum(std::begin(encoded_data), std::end(encoded_data), encoder);