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:
@@ -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);
|
||||||
|
Reference in New Issue
Block a user