diff --git a/StaticAnalyser/Acorn/Disk.cpp b/StaticAnalyser/Acorn/Disk.cpp index 8ddaf8ac3..0bbfdf2ea 100644 --- a/StaticAnalyser/Acorn/Disk.cpp +++ b/StaticAnalyser/Acorn/Disk.cpp @@ -7,11 +7,145 @@ // #include "Disk.hpp" +#include "../../Storage/Disk/DiskDrive.hpp" +#include "../../Storage/Disk/Encodings/MFM.hpp" using namespace StaticAnalyser::Acorn; +class FMParser: public Storage::Disk::Drive { + public: + FMParser() : Storage::Disk::Drive(4000000, 1, 300), shift_register_(0), track_(0) + { + // Make sure this drive really is at track '1'. + while(!get_is_track_zero()) step(-1); + + Storage::Time bit_length; + bit_length.length = 1; + bit_length.clock_rate = 250000; // i.e. 250 kbps + set_expected_bit_length(bit_length); + } + + /*! + Attempts to read the sector located at @c track and @c sector. + + @returns a sector if one was found; @c nullptr otherwise. + */ + std::shared_ptr get_sector(uint8_t track, uint8_t sector) + { + int difference = (int)track - (int)track_; + track_ = track; + + if(difference) + { + int direction = difference < 0 ? -1 : 1; + difference *= 2 * direction; + + for(int c = 0; c < difference; c++) step(direction); + } + + return get_sector(sector); + } + + private: + unsigned int shift_register_; + int index_count_; + uint8_t track_; + int bit_count_; + std::shared_ptr sector_cache_[65536]; + + void process_input_bit(int value, unsigned int cycles_since_index_hole) + { + shift_register_ = ((shift_register_ << 1) | (unsigned int)value) & 0xffff; + bit_count_++; + } + + void process_index_hole() + { + index_count_++; + } + + uint8_t get_next_byte() + { + bit_count_ = 0; + while(bit_count_ < 16) run_for_cycles(1); + return (uint8_t)( + ((shift_register_&0x0001) >> 0) | + ((shift_register_&0x0004) >> 1) | + ((shift_register_&0x0010) >> 2) | + ((shift_register_&0x0040) >> 3) | + ((shift_register_&0x0100) >> 4) | + ((shift_register_&0x0400) >> 5) | + ((shift_register_&0x1000) >> 6) | + ((shift_register_&0x4000) >> 7)); + } + + std::shared_ptr get_next_sector() + { + std::shared_ptr sector(new Storage::Encodings::MFM::Sector); + index_count_ = 0; + + while(index_count_ < 2) + { + // look for an ID address mark + while(1) + { + run_for_cycles(1); + if(shift_register_ == Storage::Encodings::MFM::FMIDAddressMark) break; + if(index_count_ >= 2) return nullptr; + } + + sector->track = get_next_byte(); + sector->side = get_next_byte(); + sector->sector = get_next_byte(); + uint8_t size = get_next_byte(); + + // look for data mark + while(1) + { + run_for_cycles(1); + if(shift_register_ == Storage::Encodings::MFM::FMDataAddressMark) break; + if(shift_register_ == Storage::Encodings::MFM::FMIDAddressMark) return nullptr; + if(index_count_ >= 2) return nullptr; + } + + size_t data_size = (size_t)(128 << size); + sector->data.reserve(data_size); + for(size_t c = 0; c < data_size; c++) + { + sector->data.push_back(get_next_byte()); + } + + return sector; + } + + return sector; + } + + std::shared_ptr get_sector(uint8_t sector) + { +// uint16_t sector_address = (uint16_t)((track_ << 8) | sector); +// if(sector_cache_[sector_address]) return sector_cache_[sector_address]; + + std::shared_ptr first_sector = get_next_sector(); + if(!first_sector) return first_sector; + if(first_sector->sector == sector) return first_sector; + + while(1) + { + std::shared_ptr next_sector = get_next_sector(); + if(next_sector->sector == first_sector->sector) return nullptr; + if(next_sector->sector == sector) return next_sector; + } + } +}; + std::list StaticAnalyser::Acorn::GetDFSFiles(const std::shared_ptr &disk) { std::list files; + FMParser parser; + parser.set_disk(disk); + + parser.get_sector(0, 0); + return files; } diff --git a/Storage/Disk/DiskDrive.hpp b/Storage/Disk/DiskDrive.hpp index 017e34464..8c9938d54 100644 --- a/Storage/Disk/DiskDrive.hpp +++ b/Storage/Disk/DiskDrive.hpp @@ -36,7 +36,7 @@ class Drive: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop { Drive(unsigned int clock_rate, unsigned int clock_rate_multiplier, unsigned int revolutions_per_minute); /*! - Communicates to the PLL the expected length of a bit. + Communicates to the PLL the expected length of a bit as a fraction of a second. */ void set_expected_bit_length(Time bit_length); diff --git a/Storage/Disk/Encodings/MFM.cpp b/Storage/Disk/Encodings/MFM.cpp index 6b7bd7102..8d04e897f 100644 --- a/Storage/Disk/Encodings/MFM.cpp +++ b/Storage/Disk/Encodings/MFM.cpp @@ -90,25 +90,10 @@ template class FMShifter: public Shifter { )); } - void add_index_address_mark() { - // data 0xfc, with clock 0xd7 => 1111 1100 with clock 1101 0111 => 1111 0111 0111 1010 - static_cast(this)->output_short(0xf77a); - } - - void add_ID_address_mark() { - // data 0xfe, with clock 0xc7 => 1111 1110 with clock 1100 0111 => 1111 0101 0111 1110 - static_cast(this)->output_short(0xf57e); - } - - void add_data_address_mark() { - // data 0xfb, with clock 0xc7 => 1111 1011 with clock 1100 0111 => 1111 0101 0110 1111 - static_cast(this)->output_short(0xf56f); - } - - void add_deleted_data_address_mark() { - // data 0xf8, with clock 0xc7 => 1111 1000 with clock 1100 0111 => 1111 0101 0110 1010 - static_cast(this)->output_short(0xf56a); - } + void add_index_address_mark() { static_cast(this)->output_short(FMIndexAddressMark); } + void add_ID_address_mark() { static_cast(this)->output_short(FMIDAddressMark); } + void add_data_address_mark() { static_cast(this)->output_short(FMDataAddressMark); } + void add_deleted_data_address_mark() { static_cast(this)->output_short(FMDeletedDataAddressMark); } }; static uint8_t logarithmic_size_for_size(size_t size) diff --git a/Storage/Disk/Encodings/MFM.hpp b/Storage/Disk/Encodings/MFM.hpp index 543896559..04662e431 100644 --- a/Storage/Disk/Encodings/MFM.hpp +++ b/Storage/Disk/Encodings/MFM.hpp @@ -17,6 +17,12 @@ namespace Storage { namespace Encodings { namespace MFM { +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 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 + + struct Sector { uint8_t track, side, sector; std::vector data;