1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-09 20:25:19 +00:00

Checksums appear to be calculated as 32-bit quantities.

This commit is contained in:
Thomas Harte
2021-10-10 12:58:10 -07:00
parent 5e083426c5
commit c4cfcfab8e

View File

@@ -12,6 +12,8 @@
#include "../../Encodings/MFM/Encoder.hpp" #include "../../Encodings/MFM/Encoder.hpp"
#include "../../Track/PCMTrack.hpp" #include "../../Track/PCMTrack.hpp"
#include <type_traits>
using namespace Storage::Disk; using namespace Storage::Disk;
namespace { namespace {
@@ -67,8 +69,9 @@ template <typename IteratorT> void write(IteratorT begin, IteratorT end, std::un
} }
} }
template <typename IteratorT> std::array<uint8_t, 2> checksum(IteratorT begin, IteratorT end) { template <typename IteratorT> auto checksum(IteratorT begin, IteratorT end) {
uint16_t checksum = 0; uint16_t checksum[2]{};
int offset = 0;
while(begin != end) { while(begin != end) {
const uint8_t value = *begin; const uint8_t value = *begin;
++begin; ++begin;
@@ -84,19 +87,27 @@ template <typename IteratorT> std::array<uint8_t, 2> checksum(IteratorT begin, I
((value&0x02) << 1) | ((value&0x02) << 1) |
((value&0x01) << 0) ((value&0x01) << 0)
); );
checksum ^= spread; checksum[offset] ^= spread;
offset ^= 1;
} }
return std::array<uint8_t, 2>{ return std::array<uint8_t, 4>{
uint8_t(checksum >> 8), uint8_t(checksum[0] >> 8),
uint8_t(checksum) uint8_t(checksum[0]),
uint8_t(checksum[1] >> 8),
uint8_t(checksum[1]),
}; };
} }
template <typename IteratorT> void write_checksum(IteratorT begin, IteratorT end, std::unique_ptr<Storage::Encodings::MFM::Encoder> &encoder) { template <typename IteratorT> void write_checksum(IteratorT begin, IteratorT end, std::unique_ptr<Storage::Encodings::MFM::Encoder> &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); const auto raw_checksum = checksum(begin, end);
std::array<uint8_t, 2> encoded_checksum; std::decay_t<decltype(raw_checksum)> encoded_checksum{};
encode_block(raw_checksum.begin(), raw_checksum.end(), encoded_checksum.begin()); encode_block(raw_checksum.begin(), raw_checksum.end(), encoded_checksum.begin());
write(encoded_checksum.begin(), encoded_checksum.end(), encoder); write(encoded_checksum.begin(), encoded_checksum.end(), encoder);
@@ -147,7 +158,7 @@ std::shared_ptr<Track> AmigaADF::get_track_at_position(Track::Address address) {
// Encode and write the header. // Encode and write the header.
const uint8_t header[4] = { const uint8_t header[4] = {
0xff, // Amiga v1.0 format. 0xff, // Amiga v1.0 format.
uint8_t(address.position.as_int()), // Track. uint8_t(address.position.as_int() * 2 + address.head), // Track.
uint8_t(s), // Sector. uint8_t(s), // Sector.
uint8_t(11 - s), // Sectors remaining. uint8_t(11 - s), // Sectors remaining.
}; };
@@ -155,14 +166,14 @@ std::shared_ptr<Track> AmigaADF::get_track_at_position(Track::Address address) {
encode_block(std::begin(header), std::end(header), std::begin(encoded_header)); encode_block(std::begin(header), std::end(header), std::begin(encoded_header));
write(std::begin(encoded_header), std::end(encoded_header), encoder); write(std::begin(encoded_header), std::end(encoded_header), encoder);
// Encode the data.
std::array<uint8_t, 512> encoded_data;
encode_block(&track_data[s * 512], &track_data[(s + 1) * 512], std::begin(encoded_data));
// Write the sector label. // Write the sector label.
const std::array<uint8_t, 16> os_recovery{}; const std::array<uint8_t, 16> os_recovery{};
write(os_recovery.begin(), os_recovery.end(), encoder); write(os_recovery.begin(), os_recovery.end(), encoder);
// Encode the data.
std::array<uint8_t, 512> encoded_data;
encode_block(&track_data[s * 512], &track_data[(s + 1) * 512], std::begin(encoded_data));
// Write checksums. // Write checksums.
write_checksum(std::begin(encoded_header), std::end(encoded_header), encoder); write_checksum(std::begin(encoded_header), std::end(encoded_header), encoder);
write_checksum(std::begin(encoded_data), std::end(encoded_data), encoder); write_checksum(std::begin(encoded_data), std::end(encoded_data), encoder);