mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-02 14:31:20 +00:00
Completes Mac GCR decoding and its associated test.
This commit is contained in:
parent
8f28b33342
commit
5a9f3cfc1e
OSBindings/Mac/Clock SignalTests
Storage/Disk/Encodings/AppleGCR
@ -163,17 +163,19 @@
|
||||
uint8_t sector_plus_tags[524];
|
||||
|
||||
// Provide tags plus a sector body that are just the sector number ad infinitum.
|
||||
memset(sector_plus_tags, sector_id, sizeof(sector_plus_tags));
|
||||
for(size_t c = 0; c < sizeof(sector_plus_tags); ++c) {
|
||||
sector_plus_tags[c] = uint8_t(sector_id + (c * 3));
|
||||
}
|
||||
|
||||
// NB: sync lengths below are identical to those for
|
||||
// the Apple II, as I have no idea whatsoever what they
|
||||
// should be.
|
||||
|
||||
segment += Storage::Encodings::AppleGCR::Macintosh::header(
|
||||
format,
|
||||
track_id,
|
||||
format ^ c,
|
||||
track_id - c,
|
||||
sector_id,
|
||||
is_side_two
|
||||
is_side_two ^ (c & 1)
|
||||
);
|
||||
segment += Storage::Encodings::AppleGCR::six_and_two_sync(7);
|
||||
segment += Storage::Encodings::AppleGCR::Macintosh::data(sector_id, sector_plus_tags);
|
||||
@ -183,8 +185,26 @@
|
||||
// Parse the prepared track to look for sectors.
|
||||
const auto decoded_sectors = Storage::Encodings::AppleGCR::sectors_from_segment(segment);
|
||||
|
||||
// Assert that all sectors fed in were found and correctly decoded.
|
||||
// Assert that the proper number of sectors was found.
|
||||
XCTAssertEqual(decoded_sectors.size(), 8);
|
||||
|
||||
// Assert that the sector descriptions and contents are correct.
|
||||
int sector = 0;
|
||||
for(const auto &pair: decoded_sectors) {
|
||||
XCTAssertFalse(pair.second.has_header_checksum_error);
|
||||
XCTAssertFalse(pair.second.has_data_checksum_error);
|
||||
|
||||
XCTAssertEqual(pair.second.address.is_side_two, is_side_two ^ (sector & 1));
|
||||
XCTAssertEqual(pair.second.address.format, format ^ sector);
|
||||
XCTAssertEqual(pair.second.address.track, track_id - sector);
|
||||
XCTAssertEqual(pair.second.address.sector, sector);
|
||||
|
||||
for(size_t c = 0; c < sizeof(pair.second.data.size()); ++c) {
|
||||
XCTAssertEqual(pair.second.data[c], uint8_t(sector + (c * 3)));
|
||||
}
|
||||
|
||||
++sector;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -24,8 +24,8 @@ struct Sector {
|
||||
struct {
|
||||
/// For Apple II-type sectors, provides the volume number.
|
||||
uint_fast8_t volume = 0;
|
||||
/// For Macintosh-type sectors, provides the type from the sector header.
|
||||
uint_fast8_t type = 0;
|
||||
/// For Macintosh-type sectors, provides the format from the sector header.
|
||||
uint_fast8_t format = 0;
|
||||
};
|
||||
uint_fast8_t track = 0;
|
||||
uint_fast8_t sector = 0;
|
||||
|
@ -196,15 +196,67 @@ std::map<std::size_t, Sector> Storage::Encodings::AppleGCR::sectors_from_segment
|
||||
if(out_of_bounds) continue;
|
||||
|
||||
// Test the checksum.
|
||||
if(decoded_header[4] != (decoded_header[0] ^ decoded_header[1] ^ decoded_header[2] ^ decoded_header[3])) continue;
|
||||
if(decoded_header[4] != (decoded_header[0] ^ decoded_header[1] ^ decoded_header[2] ^ decoded_header[3]))
|
||||
sector->has_header_checksum_error = true;
|
||||
|
||||
// Decode the header.
|
||||
sector->address.track = uint8_t(decoded_header[0] | ((decoded_header[2]&0x1f) << 6));
|
||||
sector->address.sector = decoded_header[1];
|
||||
sector->address.type = decoded_header[3];
|
||||
sector->address.format = decoded_header[3];
|
||||
sector->address.is_side_two = decoded_header[2] & 0x20;
|
||||
|
||||
// TODO: sector contents, naturally.
|
||||
// Reverse the GCR encoding of the sector contents to get back to 6-bit data.
|
||||
for(auto &c: sector->data) {
|
||||
c = unmap_six_and_two(c);
|
||||
if(c == 0xff) {
|
||||
out_of_bounds = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(out_of_bounds) continue;
|
||||
|
||||
// The first byte in the sector is a repeat of the sector number; test it
|
||||
// for correctness.
|
||||
if(sector->data[0] != sector->address.sector) continue;
|
||||
|
||||
// Cf. the corresponding section of Encoder.cpp for logic below.
|
||||
int checksum[3] = {0, 0, 0};
|
||||
for(size_t c = 0; c < 175; ++c) {
|
||||
// Calculate the rolling checcksum in order to decode the bytes.
|
||||
checksum[0] = (checksum[0] << 1) | (checksum[0] >> 7);
|
||||
|
||||
// All offsets are +1 below, to skip the initial sector number duplicate.
|
||||
const uint8_t top_bits = sector->data[1 + c*4];
|
||||
|
||||
// Decode first byte.
|
||||
sector->data[0 + c * 3] = uint8_t((sector->data[2 + c*4] + ((top_bits & 0x30) << 2)) ^ checksum[0]);
|
||||
checksum[2] += sector->data[0 + c * 3] + (checksum[0] >> 8);
|
||||
|
||||
// Decode second byte;
|
||||
sector->data[1 + c * 3] = uint8_t((sector->data[3 + c*4] + ((top_bits & 0x0c) << 4)) ^ checksum[2]);
|
||||
checksum[1] += sector->data[1 + c * 3] + (checksum[2] >> 8);
|
||||
|
||||
// Decode third byte, if there is one.
|
||||
if(c != 174) {
|
||||
sector->data[2 + c * 3] = uint8_t((sector->data[4 + c*4] + ((top_bits & 0x03) << 6)) ^ checksum[1]);
|
||||
checksum[0] += sector->data[2 + c * 3] + (checksum[1] >> 8);
|
||||
}
|
||||
|
||||
// Reset carries.
|
||||
checksum[0] &= 0xff;
|
||||
checksum[1] &= 0xff;
|
||||
checksum[2] &= 0xff;
|
||||
}
|
||||
|
||||
// Test the checksum.
|
||||
if(
|
||||
checksum[0] != uint8_t(sector->data[703] + ((sector->data[700] & 0x03) << 6)) ||
|
||||
checksum[1] != uint8_t(sector->data[702] + ((sector->data[700] & 0x0c) << 4)) ||
|
||||
checksum[2] != uint8_t(sector->data[701] + ((sector->data[700] & 0x30) << 2))
|
||||
) sector->has_data_checksum_error = true;
|
||||
|
||||
// Chop to size, and that's that.
|
||||
sector->data.resize(524);
|
||||
|
||||
// Add this sector to the map.
|
||||
sector->encoding = Sector::Encoding::Macintosh;
|
||||
|
Loading…
x
Reference in New Issue
Block a user