1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-02 16:38:51 +00:00

Made steps towards proper CRC generation. Am currently comparing against Oric disk images, as — amongst other things — they include precomputed CRCs.

This commit is contained in:
Thomas Harte 2016-12-28 18:29:37 -05:00
parent 99993a1b24
commit a568172758
7 changed files with 99 additions and 65 deletions

View File

@ -193,13 +193,14 @@ void WD1770::process_input_bit(int value, unsigned int cycles_since_index_hole)
{ {
switch(shift_register_ & 0xffff) switch(shift_register_ & 0xffff)
{ {
case Storage::Encodings::MFM::MFMIndexAddressMark: case Storage::Encodings::MFM::MFMIndexSync:
bits_since_token_ = 0; bits_since_token_ = 0;
is_awaiting_marker_value_ = true; is_awaiting_marker_value_ = true;
return; return;
case Storage::Encodings::MFM::MFMAddressMark: case Storage::Encodings::MFM::MFMSync:
bits_since_token_ = 0; bits_since_token_ = 0;
is_awaiting_marker_value_ = true; is_awaiting_marker_value_ = true;
crc_generator_.set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
return; return;
default: default:
break; break;
@ -250,6 +251,7 @@ void WD1770::process_input_bit(int value, unsigned int cycles_since_index_hole)
} }
} }
crc_generator_.add(latest_token_.byte_value);
posit_event(Event::Token); posit_event(Event::Token);
return; return;
} }
@ -542,7 +544,17 @@ void WD1770::posit_event(Event new_event_type)
(has_motor_on_line() || !(command_&0x02) || ((command_&0x08) >> 3) == header_[1])) (has_motor_on_line() || !(command_&0x02) || ((command_&0x08) >> 3) == header_[1]))
{ {
printf("Found %d/%d\n", header_[0], header_[2]); printf("Found %d/%d\n", header_[0], header_[2]);
// TODO: test CRC if(crc_generator_.get_value())
{
update_status([] (Status &status) {
status.crc_error = true;
});
goto type2_get_header;
}
update_status([] (Status &status) {
status.crc_error = false;
});
goto type2_read_or_write_data; goto type2_read_or_write_data;
} }
distance_into_section_ = 0; distance_into_section_ = 0;
@ -564,7 +576,6 @@ void WD1770::posit_event(Event new_event_type)
}); });
distance_into_section_ = 0; distance_into_section_ = 0;
is_reading_data_ = true; is_reading_data_ = true;
crc_generator_.reset();
goto type2_read_byte; goto type2_read_byte;
} }
goto type2_read_data; goto type2_read_data;
@ -573,7 +584,6 @@ void WD1770::posit_event(Event new_event_type)
WAIT_FOR_EVENT(Event::Token); WAIT_FOR_EVENT(Event::Token);
if(latest_token_.type != Token::Byte) goto type2_read_byte; if(latest_token_.type != Token::Byte) goto type2_read_byte;
data_ = latest_token_.byte_value; data_ = latest_token_.byte_value;
crc_generator_.add(data_);
update_status([] (Status &status) { update_status([] (Status &status) {
status.lost_data |= status.data_request; status.lost_data |= status.data_request;
status.data_request = true; status.data_request = true;
@ -593,10 +603,12 @@ void WD1770::posit_event(Event new_event_type)
distance_into_section_++; distance_into_section_++;
if(distance_into_section_ == 2) if(distance_into_section_ == 2)
{ {
uint16_t crc = crc_generator_.get_value(); if(crc_generator_.get_value())
if((crc >> 8) != header_[0] || (crc&0xff) != header_[1])
{ {
printf("CRC error: %04x v %02x%02x\n", crc, header_[0], header_[1]); update_status([this] (Status &status) {
status.crc_error = true;
});
goto wait_for_command;
} }
if(command_ & 0x10) if(command_ & 0x10)
@ -638,17 +650,18 @@ void WD1770::posit_event(Event new_event_type)
if(is_double_density_) if(is_double_density_)
{ {
write_raw_short(Storage::Encodings::MFM::MFMAddressMark); crc_generator_.set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
write_byte((command_&0x01) ? Storage::Encodings::MFM::MFMDeletedDataAddressByte : Storage::Encodings::MFM::MFMDataAddressByte); write_byte((command_&0x01) ? Storage::Encodings::MFM::MFMDeletedDataAddressByte : Storage::Encodings::MFM::MFMDataAddressByte);
} }
else else
{ {
crc_generator_.reset();
crc_generator_.add((command_&0x01) ? Storage::Encodings::MFM::MFMDeletedDataAddressByte : Storage::Encodings::MFM::MFMDataAddressByte);
write_raw_short((command_&0x01) ? Storage::Encodings::MFM::FMDeletedDataAddressMark : Storage::Encodings::MFM::FMDataAddressMark); write_raw_short((command_&0x01) ? Storage::Encodings::MFM::FMDeletedDataAddressMark : Storage::Encodings::MFM::FMDataAddressMark);
} }
WAIT_FOR_EVENT(Event::DataWritten); WAIT_FOR_EVENT(Event::DataWritten);
distance_into_section_ = 0; distance_into_section_ = 0;
crc_generator_.reset();
type2_write_loop: type2_write_loop:
/* /*
@ -752,6 +765,7 @@ void WD1770::write_bit(int bit)
void WD1770::write_byte(uint8_t byte) void WD1770::write_byte(uint8_t byte)
{ {
for(int c = 0; c < 8; c++) write_bit((byte << c)&0x80); for(int c = 0; c < 8; c++) write_bit((byte << c)&0x80);
crc_generator_.add(byte);
} }
void WD1770::write_raw_short(uint16_t value) void WD1770::write_raw_short(uint16_t value)

View File

@ -38,47 +38,60 @@ void Microdisc::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive)
void Microdisc::set_control_register(uint8_t control) void Microdisc::set_control_register(uint8_t control)
{ {
printf("control: %d%d%d%d%d%d%d%d\n", // printf("control: %d%d%d%d%d%d%d%d\n",
(control >> 7)&1, // (control >> 7)&1,
(control >> 6)&1, // (control >> 6)&1,
(control >> 5)&1, // (control >> 5)&1,
(control >> 4)&1, // (control >> 4)&1,
(control >> 3)&1, // (control >> 3)&1,
(control >> 2)&1, // (control >> 2)&1,
(control >> 1)&1, // (control >> 1)&1,
(control >> 0)&1); // (control >> 0)&1);
uint8_t changes = last_control_ ^ control;
last_control_ = control;
// b2: data separator clock rate select (1 = double) [TODO] // b2: data separator clock rate select (1 = double) [TODO]
// b65: drive select // b65: drive select
selected_drive_ = (control >> 5)&3; if((changes >> 5)&3)
set_drive(drives_[selected_drive_]); {
selected_drive_ = (control >> 5)&3;
set_drive(drives_[selected_drive_]);
}
// b4: side select // b4: side select
unsigned int head = (control & 0x10) ? 1 : 0; if(changes & 0x10)
for(int c = 0; c < 4; c++)
{ {
if(drives_[c]) drives_[c]->set_head(head); unsigned int head = (control & 0x10) ? 1 : 0;
for(int c = 0; c < 4; c++)
{
if(drives_[c]) drives_[c]->set_head(head);
}
} }
// b3: double density select (0 = double) // b3: double density select (0 = double)
set_is_double_density(!(control & 0x08)); if(changes & 0x08)
{
set_is_double_density(!(control & 0x08));
}
// b0: IRQ enable // b0: IRQ enable
bool had_irq = get_interrupt_request_line(); if(changes & 0x01)
irq_enable_ = !!(control & 0x01);
bool has_irq = get_interrupt_request_line();
if(has_irq != had_irq && delegate_)
{ {
delegate_->wd1770_did_change_output(this); bool had_irq = get_interrupt_request_line();
irq_enable_ = !!(control & 0x01);
bool has_irq = get_interrupt_request_line();
if(has_irq != had_irq && delegate_)
{
delegate_->wd1770_did_change_output(this);
}
} }
// b7: EPROM select (0 = select) // b7: EPROM select (0 = select)
// b1: ROM disable (0 = disable) // b1: ROM disable (0 = disable)
int new_paging_flags = ((control & 0x02) ? 0 : BASICDisable) | ((control & 0x80) ? MicrodscDisable : 0); if(changes & 0x82)
if(new_paging_flags != paging_flags_)
{ {
paging_flags_ = new_paging_flags; paging_flags_ = ((control & 0x02) ? 0 : BASICDisable) | ((control & 0x80) ? MicrodscDisable : 0);
if(delegate_) delegate_->microdisc_did_change_paging_flags(this); if(delegate_) delegate_->microdisc_did_change_paging_flags(this);
} }
} }

View File

@ -47,6 +47,7 @@ class Microdisc: public WD::WD1770 {
int paging_flags_; int paging_flags_;
int head_load_request_counter_; int head_load_request_counter_;
Delegate *delegate_; Delegate *delegate_;
uint8_t last_control_;
}; };
} }

View File

@ -29,6 +29,7 @@ class CRC16 {
} }
} }
inline uint16_t get_value() const { return value_; } inline uint16_t get_value() const { return value_; }
inline void set_value(uint16_t value) { value_ = value; }
private: private:
uint16_t reset_value_, polynomial_; uint16_t reset_value_, polynomial_;

View File

@ -22,7 +22,8 @@
- (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:(NumberTheory::CRC16 &)generator
{ {
generator.reset(); generator.reset();
for(size_t c = 0; c < length; c++) generator.add(data[c]); for(size_t c = 0; c < length; c++)
generator.add(data[c]);
return generator.get_value(); return generator.get_value();
} }

View File

@ -18,6 +18,7 @@ class MFMEncoder: public Encoder {
MFMEncoder(std::vector<uint8_t> &target) : Encoder(target) {} MFMEncoder(std::vector<uint8_t> &target) : Encoder(target) {}
void add_byte(uint8_t input) { void add_byte(uint8_t input) {
crc_generator_.add(input);
uint16_t spread_value = uint16_t spread_value =
(uint16_t)( (uint16_t)(
((input & 0x01) << 0) | ((input & 0x01) << 0) |
@ -29,33 +30,42 @@ class MFMEncoder: public Encoder {
((input & 0x40) << 6) | ((input & 0x40) << 6) |
((input & 0x80) << 7) ((input & 0x80) << 7)
); );
uint16_t or_bits = (uint16_t)((spread_value << 1) | (spread_value >> 1) | (output_ << 15)); uint16_t or_bits = (uint16_t)((spread_value << 1) | (spread_value >> 1) | (last_output_ << 15));
output_ = spread_value | ((~or_bits) & 0xaaaa); uint16_t output = spread_value | ((~or_bits) & 0xaaaa);
output_short(output_); output_short(output);
} }
void add_index_address_mark() { void add_index_address_mark() {
output_short(output_ = MFMIndexAddressMark); for(int c = 0; c < 3; c++) output_short(MFMIndexSync);
add_byte(MFMIndexAddressByte); add_byte(MFMIndexAddressByte);
} }
void add_ID_address_mark() { void add_ID_address_mark() {
output_short(output_ = MFMAddressMark); output_sync();
add_byte(MFMIDAddressByte); add_byte(MFMIDAddressByte);
} }
void add_data_address_mark() { void add_data_address_mark() {
output_short(output_ = MFMAddressMark); output_sync();
add_byte(MFMDataAddressByte); add_byte(MFMDataAddressByte);
} }
void add_deleted_data_address_mark() { void add_deleted_data_address_mark() {
output_short(output_ = MFMAddressMark); output_sync();
add_byte(MFMDeletedDataAddressByte); add_byte(MFMDeletedDataAddressByte);
} }
private: private:
uint16_t output_; uint16_t last_output_;
void output_short(uint16_t value) {
last_output_ = value;
Encoder::output_short(value);
}
void output_sync() {
for(int c = 0; c < 3; c++) output_short(MFMSync);
crc_generator_.set_value(MFMPostSyncCRCValue);
}
}; };
class FMEncoder: public Encoder { class FMEncoder: public Encoder {
@ -64,6 +74,7 @@ class FMEncoder: public Encoder {
FMEncoder(std::vector<uint8_t> &target) : Encoder(target) {} FMEncoder(std::vector<uint8_t> &target) : Encoder(target) {}
void add_byte(uint8_t input) { void add_byte(uint8_t input) {
crc_generator_.add(input);
output_short( output_short(
(uint16_t)( (uint16_t)(
((input & 0x01) << 0) | ((input & 0x01) << 0) |
@ -109,7 +120,6 @@ template<class T> std::shared_ptr<Storage::Disk::Track>
Storage::Disk::PCMSegment segment; Storage::Disk::PCMSegment segment;
segment.data.reserve(expected_track_bytes); segment.data.reserve(expected_track_bytes);
T shifter(segment.data); T shifter(segment.data);
NumberTheory::CRC16 crc_generator(0x1021, 0xffff);
// output the index mark // output the index mark
shifter.add_index_address_mark(); shifter.add_index_address_mark();
@ -130,16 +140,7 @@ template<class T> std::shared_ptr<Storage::Disk::Track>
shifter.add_byte(sector.sector); shifter.add_byte(sector.sector);
uint8_t size = logarithmic_size_for_size(sector.data.size()); uint8_t size = logarithmic_size_for_size(sector.data.size());
shifter.add_byte(size); shifter.add_byte(size);
shifter.add_crc();
// header CRC
crc_generator.reset();
crc_generator.add(sector.track);
crc_generator.add(sector.side);
crc_generator.add(sector.sector);
crc_generator.add(size);
uint16_t crc_value = crc_generator.get_value();
shifter.add_byte(crc_value >> 8);
shifter.add_byte(crc_value & 0xff);
// gap // gap
for(int c = 0; c < post_address_mark_bytes; c++) shifter.add_byte(0x4e); for(int c = 0; c < post_address_mark_bytes; c++) shifter.add_byte(0x4e);
@ -147,17 +148,11 @@ template<class T> std::shared_ptr<Storage::Disk::Track>
// data // data
shifter.add_data_address_mark(); shifter.add_data_address_mark();
crc_generator.reset();
for(size_t c = 0; c < sector.data.size(); c++) for(size_t c = 0; c < sector.data.size(); c++)
{ {
shifter.add_byte(sector.data[c]); shifter.add_byte(sector.data[c]);
crc_generator.add(sector.data[c]);
} }
shifter.add_crc();
// data CRC
crc_value = crc_generator.get_value();
shifter.add_byte(crc_value >> 8);
shifter.add_byte(crc_value & 0xff);
// gap // gap
for(int c = 0; c < post_data_bytes; c++) shifter.add_byte(0x00); for(int c = 0; c < post_data_bytes; c++) shifter.add_byte(0x00);
@ -171,6 +166,7 @@ template<class T> std::shared_ptr<Storage::Disk::Track>
} }
Encoder::Encoder(std::vector<uint8_t> &target) : Encoder::Encoder(std::vector<uint8_t> &target) :
crc_generator_(0x1021, 0xffff),
target_(target) target_(target)
{} {}
@ -180,6 +176,11 @@ void Encoder::output_short(uint16_t value)
target_.push_back(value & 0xff); target_.push_back(value & 0xff);
} }
void Encoder::add_crc()
{
output_short(crc_generator_.get_value());
}
std::shared_ptr<Storage::Disk::Track> Storage::Encodings::MFM::GetFMTrackWithSectors(const std::vector<Sector> &sectors) std::shared_ptr<Storage::Disk::Track> Storage::Encodings::MFM::GetFMTrackWithSectors(const std::vector<Sector> &sectors)
{ {
return GetTrackWithSectors<FMEncoder>( return GetTrackWithSectors<FMEncoder>(
@ -298,7 +299,7 @@ std::shared_ptr<Storage::Encodings::MFM::Sector> Parser::get_next_sector()
run_for_cycles(1); run_for_cycles(1);
if(is_mfm_) if(is_mfm_)
{ {
if(shift_register_ == Storage::Encodings::MFM::MFMAddressMark) while(shift_register_ == Storage::Encodings::MFM::MFMSync)
{ {
uint8_t mark = get_next_byte(); uint8_t mark = get_next_byte();
if(mark == Storage::Encodings::MFM::MFMIDAddressByte) break; if(mark == Storage::Encodings::MFM::MFMIDAddressByte) break;
@ -326,7 +327,7 @@ std::shared_ptr<Storage::Encodings::MFM::Sector> Parser::get_next_sector()
run_for_cycles(1); run_for_cycles(1);
if(is_mfm_) if(is_mfm_)
{ {
if(shift_register_ == Storage::Encodings::MFM::MFMAddressMark) while(shift_register_ == Storage::Encodings::MFM::MFMSync)
{ {
uint8_t mark = get_next_byte(); uint8_t mark = get_next_byte();
if(mark == Storage::Encodings::MFM::MFMDataAddressByte) break; if(mark == Storage::Encodings::MFM::MFMDataAddressByte) break;

View File

@ -24,12 +24,13 @@ const uint16_t FMIDAddressMark = 0xf57e; // data 0xfe, with clock 0xc7 => 1111
const uint16_t FMDataAddressMark = 0xf56f; // data 0xfb, with clock 0xc7 => 1111 1011 with clock 1100 0111 => 1111 0101 0110 1111 const uint16_t FMDataAddressMark = 0xf56f; // data 0xfb, with clock 0xc7 => 1111 1011 with clock 1100 0111 => 1111 0101 0110 1111
const uint16_t FMDeletedDataAddressMark = 0xf56a; // data 0xf8, with clock 0xc7 => 1111 1000 with clock 1100 0111 => 1111 0101 0110 1010 const uint16_t FMDeletedDataAddressMark = 0xf56a; // data 0xf8, with clock 0xc7 => 1111 1000 with clock 1100 0111 => 1111 0101 0110 1010
const uint16_t MFMIndexAddressMark = 0x5224; const uint16_t MFMIndexSync = 0x5224;
const uint16_t MFMAddressMark = 0x4489; const uint16_t MFMSync = 0x4489;
const uint8_t MFMIndexAddressByte = 0xfc; const uint8_t MFMIndexAddressByte = 0xfc;
const uint8_t MFMIDAddressByte = 0xfe; const uint8_t MFMIDAddressByte = 0xfe;
const uint8_t MFMDataAddressByte = 0xfb; const uint8_t MFMDataAddressByte = 0xfb;
const uint8_t MFMDeletedDataAddressByte = 0xf8; const uint8_t MFMDeletedDataAddressByte = 0xf8;
const uint16_t MFMPostSyncCRCValue = 0xcdb4;
struct Sector { struct Sector {
uint8_t track, side, sector; uint8_t track, side, sector;
@ -47,9 +48,11 @@ class Encoder {
virtual void add_ID_address_mark() = 0; virtual void add_ID_address_mark() = 0;
virtual void add_data_address_mark() = 0; virtual void add_data_address_mark() = 0;
virtual void add_deleted_data_address_mark() = 0; virtual void add_deleted_data_address_mark() = 0;
void add_crc();
protected: protected:
void output_short(uint16_t value); virtual void output_short(uint16_t value);
NumberTheory::CRC16 crc_generator_;
private: private:
std::vector<uint8_t> &target_; std::vector<uint8_t> &target_;