1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-22 12:33:29 +00:00

Generalised CRC generation and created specific subclasses for the CCITT CRC16 and CRC32.

This commit is contained in:
Thomas Harte 2018-05-23 22:21:57 -04:00
parent d3c5e4267f
commit 853261364e
10 changed files with 89 additions and 40 deletions

View File

@ -11,45 +11,84 @@
#include <cstdint>
namespace NumberTheory {
namespace CRC {
/*! Provides a class capable of accumulating a CRC16 from source data. */
class CRC16 {
/*! Provides a class capable of generating a CRC from source data. */
template <typename T, T reset_value, T xor_output, bool reflect_input, bool reflect_output> class Generator {
public:
/*!
Instantiates a CRC16 that will compute the CRC16 specified by the supplied
@c polynomial and @c reset_value.
*/
CRC16(uint16_t polynomial, uint16_t reset_value) :
reset_value_(reset_value), value_(reset_value) {
Generator(T polynomial): value_(reset_value) {
const T top_bit = T(~(T(~0) >> 1));
for(int c = 0; c < 256; c++) {
uint16_t shift_value = static_cast<uint16_t>(c << 8);
T shift_value = static_cast<T>(c << multibyte_shift);
for(int b = 0; b < 8; b++) {
uint16_t exclusive_or = (shift_value&0x8000) ? polynomial : 0x0000;
shift_value = static_cast<uint16_t>(shift_value << 1) ^ exclusive_or;
T exclusive_or = (shift_value&top_bit) ? polynomial : 0;
shift_value = static_cast<T>(shift_value << 1) ^ exclusive_or;
}
xor_table[c] = static_cast<uint16_t>(shift_value);
xor_table[c] = shift_value;
}
}
/// Resets the CRC to the reset value.
inline void reset() { value_ = reset_value_; }
void reset() { value_ = reset_value; }
/// Updates the CRC to include @c byte.
inline void add(uint8_t byte) {
value_ = static_cast<uint16_t>((value_ << 8) ^ xor_table[(value_ >> 8) ^ byte]);
void add(uint8_t byte) {
if(reflect_input) byte = reverse_byte(byte);
value_ = static_cast<T>((value_ << 8) ^ xor_table[(value_ >> multibyte_shift) ^ byte]);
}
/// @returns The current value of the CRC.
inline uint16_t get_value() const { return value_; }
inline T get_value() const {
T result = value_^xor_output;
if(reflect_output) {
T reflected_output = 0;
for(std::size_t c = 0; c < sizeof(T); ++c) {
reflected_output = T(reflected_output << 8) | T(reverse_byte(result & 0xff));
result >>= 8;
}
return reflected_output;
}
return result;
}
/// Sets the current value of the CRC.
inline void set_value(uint16_t value) { value_ = value; }
inline void set_value(T value) { value_ = value; }
private:
const uint16_t reset_value_;
uint16_t xor_table[256];
uint16_t value_;
static constexpr int multibyte_shift = (sizeof(T) * 8) - 8;
T xor_table[256];
T value_;
constexpr uint8_t reverse_byte(uint8_t byte) const {
return
((byte & 0x80) ? 0x01 : 0x00) |
((byte & 0x40) ? 0x02 : 0x00) |
((byte & 0x20) ? 0x04 : 0x00) |
((byte & 0x10) ? 0x08 : 0x00) |
((byte & 0x08) ? 0x10 : 0x00) |
((byte & 0x04) ? 0x20 : 0x00) |
((byte & 0x02) ? 0x40 : 0x00) |
((byte & 0x01) ? 0x80 : 0x00);
}
};
/*!
Provides a generator of 16-bit CCITT CRCs, which amongst other uses are
those used by the FM and MFM disk encodings.
*/
struct CCITT: public Generator<uint16_t, 0xffff, 0x0000, false, false> {
CCITT() : Generator(0x1021) {}
};
/*!
Provides a generator of "standard 32-bit" CRCs.
*/
struct CRC32: public Generator<uint32_t, 0xffffffff, 0xffffffff, true, true> {
CRC32() : Generator(0x04c11db7) {}
};
}

View File

@ -8,18 +8,14 @@
#import <XCTest/XCTest.h>
#include "CRC.hpp"
#include <string>
@interface CRCTests : XCTestCase
@end
@implementation CRCTests
- (NumberTheory::CRC16)mfmCRCGenerator
{
return NumberTheory::CRC16(0x1021, 0xffff);
}
- (uint16_t)crcOfData:(uint8_t *)data length:(size_t)length generator:(NumberTheory::CRC16 &)generator
- (uint16_t)crcOfData:(uint8_t *)data length:(size_t)length generator:(CRC::CCITT &)generator
{
generator.reset();
for(size_t c = 0; c < length; c++)
@ -34,7 +30,7 @@
0xa1, 0xa1, 0xa1, 0xfe, 0x00, 0x00, 0x01, 0x01
};
uint16_t crc = 0xfa0c;
NumberTheory::CRC16 crcGenerator = self.mfmCRCGenerator;
CRC::CCITT crcGenerator;
uint16_t computedCRC = [self crcOfData:IDMark length:sizeof(IDMark) generator:crcGenerator];
XCTAssert(computedCRC == crc, @"Calculated CRC should have been %04x, was %04x", crc, computedCRC);
@ -63,10 +59,26 @@
0x20, 0x20, 0x20, 0x20
};
uint16_t crc = 0x4de7;
NumberTheory::CRC16 crcGenerator = self.mfmCRCGenerator;
CRC::CCITT crcGenerator;
uint16_t computedCRC = [self crcOfData:sectorData length:sizeof(sectorData) generator:crcGenerator];
XCTAssert(computedCRC == crc, @"Calculated CRC should have been %04x, was %04x", crc, computedCRC);
}
- (void)testCCITTCheck {
CRC::CCITT crcGenerator;
for(auto c: std::string("123456789")) {
crcGenerator.add(c);
}
XCTAssertEqual(crcGenerator.get_value(), 0x29b1);
}
- (void)testCRC32Check {
CRC::CRC32 crcGenerator;
for(auto c: std::string("123456789")) {
crcGenerator.add(c);
}
XCTAssertEqual(crcGenerator.get_value(), 0xcbf43926);
}
@end

View File

@ -14,8 +14,7 @@ using namespace Storage::Disk;
MFMController::MFMController(Cycles clock_rate) :
Storage::Disk::Controller(clock_rate),
shifter_(&crc_generator_),
crc_generator_(0x1021, 0xffff) {
shifter_(&crc_generator_) {
}
void MFMController::process_index_hole() {
@ -49,7 +48,7 @@ MFMController::Token MFMController::get_latest_token() {
return latest_token_;
}
NumberTheory::CRC16 &MFMController::get_crc_generator() {
CRC::CCITT &MFMController::get_crc_generator() {
return crc_generator_;
}

View File

@ -72,7 +72,7 @@ class MFMController: public Controller {
Token get_latest_token();
/// @returns The controller's CRC generator. This is automatically fed during reading.
NumberTheory::CRC16 &get_crc_generator();
CRC::CCITT &get_crc_generator();
// Events
enum class Event: int {
@ -163,7 +163,7 @@ class MFMController: public Controller {
int last_bit_;
// CRC generator
NumberTheory::CRC16 crc_generator_;
CRC::CCITT crc_generator_;
};
}

View File

@ -187,7 +187,6 @@ template<class T> std::shared_ptr<Storage::Disk::Track>
}
Encoder::Encoder(std::vector<uint8_t> &target) :
crc_generator_(0x1021, 0xffff),
target_(target) {}
void Encoder::output_short(uint16_t value) {

View File

@ -56,7 +56,7 @@ class Encoder {
void add_crc(bool incorrectly);
protected:
NumberTheory::CRC16 crc_generator_;
CRC::CCITT crc_generator_;
private:
std::vector<uint8_t> &target_;

View File

@ -11,8 +11,8 @@
using namespace Storage::Encodings::MFM;
Shifter::Shifter() : owned_crc_generator_(new NumberTheory::CRC16(0x1021, 0xffff)), crc_generator_(owned_crc_generator_.get()) {}
Shifter::Shifter(NumberTheory::CRC16 *crc_generator) : crc_generator_(crc_generator) {}
Shifter::Shifter() : owned_crc_generator_(new CRC::CCITT()), crc_generator_(owned_crc_generator_.get()) {}
Shifter::Shifter(CRC::CCITT *crc_generator) : crc_generator_(crc_generator) {}
void Shifter::set_is_double_density(bool is_double_density) {
is_double_density_ = is_double_density;

View File

@ -44,7 +44,7 @@ namespace MFM {
class Shifter {
public:
Shifter();
Shifter(NumberTheory::CRC16 *crc_generator);
Shifter(CRC::CCITT *crc_generator);
void set_is_double_density(bool is_double_density);
void set_should_obey_syncs(bool should_obey_syncs);
@ -57,7 +57,7 @@ class Shifter {
Token get_token() const {
return token_;
}
NumberTheory::CRC16 &get_crc_generator() {
CRC::CCITT &get_crc_generator() {
return *crc_generator_;
}
@ -72,8 +72,8 @@ class Shifter {
// input configuration
bool is_double_density_ = false;
std::unique_ptr<NumberTheory::CRC16> owned_crc_generator_;
NumberTheory::CRC16 *crc_generator_;
std::unique_ptr<CRC::CCITT> owned_crc_generator_;
CRC::CCITT *crc_generator_;
};
}

View File

@ -14,7 +14,7 @@ namespace {
const int PLLClockRate = 1920000;
}
Parser::Parser() : crc_(0x1021, 0x0000) {
Parser::Parser() {
shifter_.set_delegate(this);
}

View File

@ -63,7 +63,7 @@ class Parser: public Storage::Tape::Parser<SymbolType>, public Shifter::Delegate
private:
bool did_update_shifter(int new_value, int length);
NumberTheory::CRC16 crc_;
CRC::CCITT crc_;
Shifter shifter_;
};