mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-13 07:30:21 +00:00
Completed a first parse at the GCR parser, proving how incredibly slow my drive is.
This commit is contained in:
parent
9d6dcb80a7
commit
8992feb8cd
@ -9,6 +9,7 @@
|
|||||||
#include "Disk.hpp"
|
#include "Disk.hpp"
|
||||||
#include "../../Storage/Disk/DiskDrive.hpp"
|
#include "../../Storage/Disk/DiskDrive.hpp"
|
||||||
#include "../../Storage/Disk/Encodings/CommodoreGCR.hpp"
|
#include "../../Storage/Disk/Encodings/CommodoreGCR.hpp"
|
||||||
|
#include "Utilities.hpp"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -18,7 +19,11 @@ using namespace StaticAnalyser::Commodore;
|
|||||||
|
|
||||||
class CommodoreGCRParser: public Storage::Disk::Drive {
|
class CommodoreGCRParser: public Storage::Disk::Drive {
|
||||||
public:
|
public:
|
||||||
CommodoreGCRParser() : Storage::Disk::Drive(4000000, 4, 300), shift_register_(0) {}
|
CommodoreGCRParser() : Storage::Disk::Drive(4000000, 4, 300), shift_register_(0), track_(1)
|
||||||
|
{
|
||||||
|
// Make sure this drive really is at track '1'.
|
||||||
|
while(!get_is_track_zero()) step(-1);
|
||||||
|
}
|
||||||
|
|
||||||
struct Sector
|
struct Sector
|
||||||
{
|
{
|
||||||
@ -30,7 +35,24 @@ class CommodoreGCRParser: public Storage::Disk::Drive {
|
|||||||
|
|
||||||
std::unique_ptr<Sector> get_sector(uint8_t track, uint8_t sector)
|
std::unique_ptr<Sector> get_sector(uint8_t track, uint8_t sector)
|
||||||
{
|
{
|
||||||
return nullptr;
|
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);
|
||||||
|
|
||||||
|
unsigned int zone = 3;
|
||||||
|
if(track >= 18) zone = 2;
|
||||||
|
else if(track >= 25) zone = 1;
|
||||||
|
else if(track >= 31) zone = 0;
|
||||||
|
set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(zone));
|
||||||
|
}
|
||||||
|
|
||||||
|
return get_sector(sector);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Sector> get_sector(uint8_t sector)
|
std::unique_ptr<Sector> get_sector(uint8_t sector)
|
||||||
@ -94,6 +116,7 @@ class CommodoreGCRParser: public Storage::Disk::Drive {
|
|||||||
unsigned int shift_register_;
|
unsigned int shift_register_;
|
||||||
int index_count_;
|
int index_count_;
|
||||||
int bit_count_;
|
int bit_count_;
|
||||||
|
uint8_t track_;
|
||||||
|
|
||||||
void process_input_bit(int value, unsigned int cycles_since_index_hole)
|
void process_input_bit(int value, unsigned int cycles_since_index_hole)
|
||||||
{
|
{
|
||||||
@ -155,29 +178,78 @@ std::list<File> StaticAnalyser::Commodore::GetFiles(const std::shared_ptr<Storag
|
|||||||
// find any sector whatsoever to establish the current track
|
// find any sector whatsoever to establish the current track
|
||||||
std::unique_ptr<CommodoreGCRParser::Sector> sector;
|
std::unique_ptr<CommodoreGCRParser::Sector> sector;
|
||||||
|
|
||||||
// attempt to grab a sector from track 0
|
// assemble directory
|
||||||
while(!parser.get_is_track_zero()) parser.step(-1);
|
|
||||||
parser.set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(0));
|
|
||||||
sector = parser.get_next_sector();
|
|
||||||
if(!sector) return files;
|
|
||||||
|
|
||||||
// step out to track 18 (== 36)
|
|
||||||
for(int c = 0; c < 36; c++) parser.step(1);
|
|
||||||
|
|
||||||
// assemble disk contents, starting with sector 1
|
|
||||||
parser.set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(1));
|
|
||||||
std::vector<uint8_t> directory;
|
std::vector<uint8_t> directory;
|
||||||
sector = parser.get_sector(1);
|
uint8_t next_track = 18;
|
||||||
while(sector)
|
uint8_t next_sector = 1;
|
||||||
|
while(1)
|
||||||
{
|
{
|
||||||
|
sector = parser.get_sector(next_track, next_sector);
|
||||||
|
if(!sector) break;
|
||||||
directory.insert(directory.end(), sector->data.begin(), sector->data.end());
|
directory.insert(directory.end(), sector->data.begin(), sector->data.end());
|
||||||
uint8_t next_track = sector->data[0];
|
next_track = sector->data[0];
|
||||||
uint8_t next_sector = sector->data[1];
|
next_sector = sector->data[1];
|
||||||
|
|
||||||
if(!next_track) break;
|
if(!next_track) break;
|
||||||
sector = parser.get_sector(next_sector);
|
}
|
||||||
|
|
||||||
// TODO: track changes. Allegedly not possible, but definitely happening.
|
// parse directory
|
||||||
|
size_t header_pointer = (size_t)-32;
|
||||||
|
while(header_pointer+32+31 < directory.size())
|
||||||
|
{
|
||||||
|
header_pointer += 32;
|
||||||
|
|
||||||
|
File new_file;
|
||||||
|
switch(directory[header_pointer + 2] & 7)
|
||||||
|
{
|
||||||
|
case 0: // DEL files
|
||||||
|
default: continue; // Unknown file types
|
||||||
|
|
||||||
|
case 1: new_file.type = File::DataSequence; break;
|
||||||
|
case 2: new_file.type = File::RelocatableProgram; break; // TODO: need a "don't know about relocatable" program?
|
||||||
|
case 3: new_file.type = File::User; break;
|
||||||
|
// case 4: new_file.type = File::Relative; break; // Can't handle REL files yet
|
||||||
|
}
|
||||||
|
|
||||||
|
next_track = directory[header_pointer + 3];
|
||||||
|
next_sector = directory[header_pointer + 4];
|
||||||
|
|
||||||
|
new_file.raw_name.reserve(16);
|
||||||
|
for(size_t c = 0; c < 16; c++)
|
||||||
|
{
|
||||||
|
new_file.raw_name.push_back(directory[header_pointer + 5 + c]);
|
||||||
|
}
|
||||||
|
new_file.name = petscii_from_bytes(&new_file.raw_name[0], 16, false);
|
||||||
|
|
||||||
|
size_t number_of_sectors = (size_t)directory[header_pointer + 0x1e] + ((size_t)directory[header_pointer + 0x1f] << 8);
|
||||||
|
new_file.data.reserve((number_of_sectors - 1) * 254 + 252);
|
||||||
|
|
||||||
|
bool is_first_sector = true;
|
||||||
|
while(next_track)
|
||||||
|
{
|
||||||
|
sector = parser.get_sector(next_track, next_sector);
|
||||||
|
if(!sector) break;
|
||||||
|
|
||||||
|
next_track = sector->data[0];
|
||||||
|
next_sector = sector->data[1];
|
||||||
|
if(is_first_sector)
|
||||||
|
{
|
||||||
|
new_file.starting_address = (uint16_t)sector->data[2] | (uint16_t)(sector->data[3] << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(next_track)
|
||||||
|
{
|
||||||
|
new_file.data.insert(new_file.data.end(), sector->data.begin() + (is_first_sector ? 4 : 2), sector->data.end());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_file.data.insert(new_file.data.end(), sector->data.begin() + 2, sector->data.begin() + next_sector);
|
||||||
|
}
|
||||||
|
|
||||||
|
is_first_sector = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!next_track) files.push_back(new_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
|
@ -16,14 +16,20 @@ namespace StaticAnalyser {
|
|||||||
namespace Commodore {
|
namespace Commodore {
|
||||||
|
|
||||||
struct File {
|
struct File {
|
||||||
|
File() : is_closed(false), is_locked(false) {}
|
||||||
|
|
||||||
std::wstring name;
|
std::wstring name;
|
||||||
std::vector<uint8_t> raw_name;
|
std::vector<uint8_t> raw_name;
|
||||||
uint16_t starting_address;
|
uint16_t starting_address;
|
||||||
uint16_t ending_address;
|
uint16_t ending_address;
|
||||||
|
bool is_locked;
|
||||||
|
bool is_closed;
|
||||||
enum {
|
enum {
|
||||||
RelocatableProgram,
|
RelocatableProgram,
|
||||||
NonRelocatableProgram,
|
NonRelocatableProgram,
|
||||||
DataSequence,
|
DataSequence,
|
||||||
|
User,
|
||||||
|
Relative
|
||||||
} type;
|
} type;
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user