mirror of
https://github.com/TomHarte/CLK.git
synced 2024-09-08 03:54:27 +00:00
Merge pull request #92 from TomHarte/MFMCleanup
Adds some documentation and tidies some of the new MFM infrastructure
This commit is contained in:
commit
0689df1349
@ -175,22 +175,22 @@ void WD1770::process_input_bit(int value, unsigned int cycles_since_index_hole)
|
|||||||
case Storage::Encodings::MFM::FMIndexAddressMark:
|
case Storage::Encodings::MFM::FMIndexAddressMark:
|
||||||
token_type = Token::Index;
|
token_type = Token::Index;
|
||||||
crc_generator_.reset();
|
crc_generator_.reset();
|
||||||
crc_generator_.add(Storage::Encodings::MFM::MFMIndexAddressByte);
|
crc_generator_.add(Storage::Encodings::MFM::IndexAddressByte);
|
||||||
break;
|
break;
|
||||||
case Storage::Encodings::MFM::FMIDAddressMark:
|
case Storage::Encodings::MFM::FMIDAddressMark:
|
||||||
token_type = Token::ID;
|
token_type = Token::ID;
|
||||||
crc_generator_.reset();
|
crc_generator_.reset();
|
||||||
crc_generator_.add(Storage::Encodings::MFM::MFMIDAddressByte);
|
crc_generator_.add(Storage::Encodings::MFM::IDAddressByte);
|
||||||
break;
|
break;
|
||||||
case Storage::Encodings::MFM::FMDataAddressMark:
|
case Storage::Encodings::MFM::FMDataAddressMark:
|
||||||
token_type = Token::Data;
|
token_type = Token::Data;
|
||||||
crc_generator_.reset();
|
crc_generator_.reset();
|
||||||
crc_generator_.add(Storage::Encodings::MFM::MFMDataAddressByte);
|
crc_generator_.add(Storage::Encodings::MFM::DataAddressByte);
|
||||||
break;
|
break;
|
||||||
case Storage::Encodings::MFM::FMDeletedDataAddressMark:
|
case Storage::Encodings::MFM::FMDeletedDataAddressMark:
|
||||||
token_type = Token::DeletedData;
|
token_type = Token::DeletedData;
|
||||||
crc_generator_.reset();
|
crc_generator_.reset();
|
||||||
crc_generator_.add(Storage::Encodings::MFM::MFMDeletedDataAddressByte);
|
crc_generator_.add(Storage::Encodings::MFM::DeletedDataAddressByte);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -242,16 +242,16 @@ void WD1770::process_input_bit(int value, unsigned int cycles_since_index_hole)
|
|||||||
is_awaiting_marker_value_ = false;
|
is_awaiting_marker_value_ = false;
|
||||||
switch(latest_token_.byte_value)
|
switch(latest_token_.byte_value)
|
||||||
{
|
{
|
||||||
case Storage::Encodings::MFM::MFMIndexAddressByte:
|
case Storage::Encodings::MFM::IndexAddressByte:
|
||||||
latest_token_.type = Token::Index;
|
latest_token_.type = Token::Index;
|
||||||
break;
|
break;
|
||||||
case Storage::Encodings::MFM::MFMIDAddressByte:
|
case Storage::Encodings::MFM::IDAddressByte:
|
||||||
latest_token_.type = Token::ID;
|
latest_token_.type = Token::ID;
|
||||||
break;
|
break;
|
||||||
case Storage::Encodings::MFM::MFMDataAddressByte:
|
case Storage::Encodings::MFM::DataAddressByte:
|
||||||
latest_token_.type = Token::Data;
|
latest_token_.type = Token::Data;
|
||||||
break;
|
break;
|
||||||
case Storage::Encodings::MFM::MFMDeletedDataAddressByte:
|
case Storage::Encodings::MFM::DeletedDataAddressByte:
|
||||||
latest_token_.type = Token::DeletedData;
|
latest_token_.type = Token::DeletedData;
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
@ -662,12 +662,12 @@ void WD1770::posit_event(Event new_event_type)
|
|||||||
{
|
{
|
||||||
crc_generator_.set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
|
crc_generator_.set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
|
||||||
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMSync);
|
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMSync);
|
||||||
write_byte((command_&0x01) ? Storage::Encodings::MFM::MFMDeletedDataAddressByte : Storage::Encodings::MFM::MFMDataAddressByte);
|
write_byte((command_&0x01) ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
crc_generator_.reset();
|
crc_generator_.reset();
|
||||||
crc_generator_.add((command_&0x01) ? Storage::Encodings::MFM::MFMDeletedDataAddressByte : Storage::Encodings::MFM::MFMDataAddressByte);
|
crc_generator_.add((command_&0x01) ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,13 +115,30 @@ class Disk {
|
|||||||
*/
|
*/
|
||||||
virtual std::shared_ptr<Track> get_uncached_track_at_position(unsigned int head, unsigned int position) = 0;
|
virtual std::shared_ptr<Track> get_uncached_track_at_position(unsigned int head, unsigned int position) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Subclasses that support writing should implement @c store_updated_track_at_position to determine which bytes
|
||||||
|
have to be written from @c track, then obtain @c file_access_mutex and write new data to their file to represent
|
||||||
|
the track underneath @c head at @c position.
|
||||||
|
|
||||||
|
The base class will ensure that calls are made to @c get_uncached_track_at_position only while it holds @c file_access_mutex;
|
||||||
|
that mutex therefore provides serialisation of file access.
|
||||||
|
|
||||||
|
This method will be called asynchronously. Subclasses are responsible for any synchronisation other than that
|
||||||
|
provided automatically via @c file_access_mutex.
|
||||||
|
*/
|
||||||
virtual void store_updated_track_at_position(unsigned int head, unsigned int position, const std::shared_ptr<Track> &track, std::mutex &file_access_mutex);
|
virtual void store_updated_track_at_position(unsigned int head, unsigned int position, const std::shared_ptr<Track> &track, std::mutex &file_access_mutex);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Subclasses that support writing should call @c flush_updates during their destructor if there is anything they
|
||||||
|
do in @c store_updated_track_at_position that would not be valid after their destructor has completed but prior
|
||||||
|
to Disk's constructor running.
|
||||||
|
*/
|
||||||
void flush_updates();
|
void flush_updates();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<int, std::shared_ptr<Track>> cached_tracks_;
|
|
||||||
int get_id_for_track_at_position(unsigned int head, unsigned int position);
|
int get_id_for_track_at_position(unsigned int head, unsigned int position);
|
||||||
|
std::map<int, std::shared_ptr<Track>> cached_tracks_;
|
||||||
|
|
||||||
std::mutex file_access_mutex_;
|
std::mutex file_access_mutex_;
|
||||||
std::unique_ptr<Concurrency::AsyncTaskQueue> update_queue_;
|
std::unique_ptr<Concurrency::AsyncTaskQueue> update_queue_;
|
||||||
};
|
};
|
||||||
|
@ -37,22 +37,22 @@ class MFMEncoder: public Encoder {
|
|||||||
|
|
||||||
void add_index_address_mark() {
|
void add_index_address_mark() {
|
||||||
for(int c = 0; c < 3; c++) output_short(MFMIndexSync);
|
for(int c = 0; c < 3; c++) output_short(MFMIndexSync);
|
||||||
add_byte(MFMIndexAddressByte);
|
add_byte(IndexAddressByte);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_ID_address_mark() {
|
void add_ID_address_mark() {
|
||||||
output_sync();
|
output_sync();
|
||||||
add_byte(MFMIDAddressByte);
|
add_byte(IDAddressByte);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_data_address_mark() {
|
void add_data_address_mark() {
|
||||||
output_sync();
|
output_sync();
|
||||||
add_byte(MFMDataAddressByte);
|
add_byte(DataAddressByte);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_deleted_data_address_mark() {
|
void add_deleted_data_address_mark() {
|
||||||
output_sync();
|
output_sync();
|
||||||
add_byte(MFMDeletedDataAddressByte);
|
add_byte(DeletedDataAddressByte);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -92,28 +92,28 @@ class FMEncoder: public Encoder {
|
|||||||
void add_index_address_mark()
|
void add_index_address_mark()
|
||||||
{
|
{
|
||||||
crc_generator_.reset();
|
crc_generator_.reset();
|
||||||
crc_generator_.add(MFMIndexAddressByte);
|
crc_generator_.add(IndexAddressByte);
|
||||||
output_short(FMIndexAddressMark);
|
output_short(FMIndexAddressMark);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_ID_address_mark()
|
void add_ID_address_mark()
|
||||||
{
|
{
|
||||||
crc_generator_.reset();
|
crc_generator_.reset();
|
||||||
crc_generator_.add(MFMIDAddressByte);
|
crc_generator_.add(IDAddressByte);
|
||||||
output_short(FMIDAddressMark);
|
output_short(FMIDAddressMark);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_data_address_mark()
|
void add_data_address_mark()
|
||||||
{
|
{
|
||||||
crc_generator_.reset();
|
crc_generator_.reset();
|
||||||
crc_generator_.add(MFMDataAddressByte);
|
crc_generator_.add(DataAddressByte);
|
||||||
output_short(FMDataAddressMark);
|
output_short(FMDataAddressMark);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_deleted_data_address_mark()
|
void add_deleted_data_address_mark()
|
||||||
{
|
{
|
||||||
crc_generator_.reset();
|
crc_generator_.reset();
|
||||||
crc_generator_.add(MFMDeletedDataAddressByte);
|
crc_generator_.add(DeletedDataAddressByte);
|
||||||
output_short(FMDeletedDataAddressMark);
|
output_short(FMDeletedDataAddressMark);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -282,7 +282,7 @@ void Parser::seek_to_track(uint8_t track)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Storage::Encodings::MFM::Sector> Parser::get_sector(uint8_t track, uint8_t sector)
|
std::shared_ptr<Sector> Parser::get_sector(uint8_t track, uint8_t sector)
|
||||||
{
|
{
|
||||||
seek_to_track(track);
|
seek_to_track(track);
|
||||||
return get_sector(sector);
|
return get_sector(sector);
|
||||||
@ -408,9 +408,9 @@ std::vector<uint8_t> Parser::get_track()
|
|||||||
{
|
{
|
||||||
switch(byte_value)
|
switch(byte_value)
|
||||||
{
|
{
|
||||||
case MFMIDAddressByte: found_id = true; break;
|
case IDAddressByte: found_id = true; break;
|
||||||
case MFMDataAddressByte:
|
case DataAddressByte:
|
||||||
case MFMDeletedDataAddressByte: found_data = true; break;
|
case DeletedDataAddressByte: found_data = true; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -431,9 +431,9 @@ std::vector<uint8_t> Parser::get_track()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<Storage::Encodings::MFM::Sector> Parser::get_next_sector()
|
std::shared_ptr<Sector> Parser::get_next_sector()
|
||||||
{
|
{
|
||||||
std::shared_ptr<Storage::Encodings::MFM::Sector> sector(new Storage::Encodings::MFM::Sector);
|
std::shared_ptr<Sector> sector(new Sector);
|
||||||
index_count_ = 0;
|
index_count_ = 0;
|
||||||
|
|
||||||
while(index_count_ < 2)
|
while(index_count_ < 2)
|
||||||
@ -445,10 +445,10 @@ 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_)
|
||||||
{
|
{
|
||||||
while(shift_register_ == Storage::Encodings::MFM::MFMSync)
|
while(shift_register_ == MFMSync)
|
||||||
{
|
{
|
||||||
uint8_t mark = get_next_byte();
|
uint8_t mark = get_next_byte();
|
||||||
if(mark == Storage::Encodings::MFM::MFMIDAddressByte)
|
if(mark == IDAddressByte)
|
||||||
{
|
{
|
||||||
crc_generator_.set_value(MFMPostSyncCRCValue);
|
crc_generator_.set_value(MFMPostSyncCRCValue);
|
||||||
id_found = true;
|
id_found = true;
|
||||||
@ -458,7 +458,7 @@ std::shared_ptr<Storage::Encodings::MFM::Sector> Parser::get_next_sector()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(shift_register_ == Storage::Encodings::MFM::FMIDAddressMark)
|
if(shift_register_ == FMIDAddressMark)
|
||||||
{
|
{
|
||||||
crc_generator_.reset();
|
crc_generator_.reset();
|
||||||
id_found = true;
|
id_found = true;
|
||||||
@ -467,7 +467,7 @@ std::shared_ptr<Storage::Encodings::MFM::Sector> Parser::get_next_sector()
|
|||||||
if(index_count_ >= 2) return nullptr;
|
if(index_count_ >= 2) return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
crc_generator_.add(MFMIDAddressByte);
|
crc_generator_.add(IDAddressByte);
|
||||||
sector->track = get_next_byte();
|
sector->track = get_next_byte();
|
||||||
sector->side = get_next_byte();
|
sector->side = get_next_byte();
|
||||||
sector->sector = get_next_byte();
|
sector->sector = get_next_byte();
|
||||||
@ -483,30 +483,30 @@ 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_)
|
||||||
{
|
{
|
||||||
while(shift_register_ == Storage::Encodings::MFM::MFMSync)
|
while(shift_register_ == MFMSync)
|
||||||
{
|
{
|
||||||
uint8_t mark = get_next_byte();
|
uint8_t mark = get_next_byte();
|
||||||
if(mark == Storage::Encodings::MFM::MFMDataAddressByte)
|
if(mark == DataAddressByte)
|
||||||
{
|
{
|
||||||
crc_generator_.set_value(MFMPostSyncCRCValue);
|
crc_generator_.set_value(MFMPostSyncCRCValue);
|
||||||
data_found = true;
|
data_found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(mark == Storage::Encodings::MFM::MFMIDAddressByte) return nullptr;
|
if(mark == IDAddressByte) return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(shift_register_ == Storage::Encodings::MFM::FMDataAddressMark)
|
if(shift_register_ == FMDataAddressMark)
|
||||||
{
|
{
|
||||||
crc_generator_.reset();
|
crc_generator_.reset();
|
||||||
data_found = true;
|
data_found = true;
|
||||||
}
|
}
|
||||||
if(shift_register_ == Storage::Encodings::MFM::FMIDAddressMark) return nullptr;
|
if(shift_register_ == FMIDAddressMark) return nullptr;
|
||||||
}
|
}
|
||||||
if(index_count_ >= 2) return nullptr;
|
if(index_count_ >= 2) return nullptr;
|
||||||
}
|
}
|
||||||
crc_generator_.add(MFMDataAddressByte);
|
crc_generator_.add(DataAddressByte);
|
||||||
|
|
||||||
size_t data_size = (size_t)(128 << size);
|
size_t data_size = (size_t)(128 << size);
|
||||||
sector->data.reserve(data_size);
|
sector->data.reserve(data_size);
|
||||||
@ -524,9 +524,9 @@ std::shared_ptr<Storage::Encodings::MFM::Sector> Parser::get_next_sector()
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Storage::Encodings::MFM::Sector> Parser::get_sector(uint8_t sector)
|
std::shared_ptr<Sector> Parser::get_sector(uint8_t sector)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Storage::Encodings::MFM::Sector> first_sector;
|
std::shared_ptr<Sector> first_sector;
|
||||||
index_count_ = 0;
|
index_count_ = 0;
|
||||||
while(!first_sector && index_count_ < 2) first_sector = get_next_sector();
|
while(!first_sector && index_count_ < 2) first_sector = get_next_sector();
|
||||||
if(!first_sector) return first_sector;
|
if(!first_sector) return first_sector;
|
||||||
@ -534,7 +534,7 @@ std::shared_ptr<Storage::Encodings::MFM::Sector> Parser::get_sector(uint8_t sect
|
|||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Storage::Encodings::MFM::Sector> next_sector = get_next_sector();
|
std::shared_ptr<Sector> next_sector = get_next_sector();
|
||||||
if(!next_sector) continue;
|
if(!next_sector) continue;
|
||||||
if(next_sector->sector == first_sector->sector) return nullptr;
|
if(next_sector->sector == first_sector->sector) return nullptr;
|
||||||
if(next_sector->sector == sector) return next_sector;
|
if(next_sector->sector == sector) return next_sector;
|
||||||
|
@ -19,18 +19,19 @@ namespace Storage {
|
|||||||
namespace Encodings {
|
namespace Encodings {
|
||||||
namespace MFM {
|
namespace MFM {
|
||||||
|
|
||||||
|
const uint8_t IndexAddressByte = 0xfc;
|
||||||
|
const uint8_t IDAddressByte = 0xfe;
|
||||||
|
const uint8_t DataAddressByte = 0xfb;
|
||||||
|
const uint8_t DeletedDataAddressByte = 0xf8;
|
||||||
|
|
||||||
const uint16_t FMIndexAddressMark = 0xf77a; // data 0xfc, with clock 0xd7 => 1111 1100 with clock 1101 0111 => 1111 0111 0111 1010
|
const uint16_t FMIndexAddressMark = 0xf77a; // data 0xfc, with clock 0xd7 => 1111 1100 with clock 1101 0111 => 1111 0111 0111 1010
|
||||||
const uint16_t FMIDAddressMark = 0xf57e; // data 0xfe, with clock 0xc7 => 1111 1110 with clock 1100 0111 => 1111 0101 0111 1110
|
const uint16_t FMIDAddressMark = 0xf57e; // data 0xfe, with clock 0xc7 => 1111 1110 with clock 1100 0111 => 1111 0101 0111 1110
|
||||||
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 MFMIndexSync = 0x5224;
|
const uint16_t MFMIndexSync = 0x5224; // data 0xc2, with a missing clock at 0x0080 => 0101 0010 1010 0100 without 1000 0000
|
||||||
const uint16_t MFMSync = 0x4489;
|
const uint16_t MFMSync = 0x4489; // data 0xa1, with a missing clock at 0x0020 => 0100 0100 1010 1001 without 0010 0000
|
||||||
const uint8_t MFMIndexAddressByte = 0xfc;
|
const uint16_t MFMPostSyncCRCValue = 0xcdb4; // the value the CRC generator should have after encountering three 0xa1s
|
||||||
const uint8_t MFMIDAddressByte = 0xfe;
|
|
||||||
const uint8_t MFMDataAddressByte = 0xfb;
|
|
||||||
const uint8_t MFMDeletedDataAddressByte = 0xf8;
|
|
||||||
const uint16_t MFMPostSyncCRCValue = 0xcdb4;
|
|
||||||
|
|
||||||
struct Sector {
|
struct Sector {
|
||||||
uint8_t track, side, sector;
|
uint8_t track, side, sector;
|
||||||
|
Loading…
Reference in New Issue
Block a user