mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-15 14:27:29 +00:00
Started working towards capturing everything there is to know about a file. CRC calculation appears to be flawed somehow at the moment.
This commit is contained in:
@@ -11,36 +11,33 @@
|
|||||||
using namespace StaticAnalyser::Acorn;
|
using namespace StaticAnalyser::Acorn;
|
||||||
|
|
||||||
struct TapeParser {
|
struct TapeParser {
|
||||||
float wave_lengths[4];
|
|
||||||
int wave_length_pointer;
|
|
||||||
|
|
||||||
TapeParser() : wave_length_pointer(0) {}
|
TapeParser(const std::shared_ptr<Storage::Tape::Tape> &tape) : _wave_length_pointer(0), _tape(tape) {}
|
||||||
|
|
||||||
int GetNextBit(const std::shared_ptr<Storage::Tape::Tape> &tape)
|
int get_next_bit()
|
||||||
{
|
{
|
||||||
while(!tape->is_at_end())
|
while(!_tape->is_at_end())
|
||||||
{
|
{
|
||||||
// skip any gaps
|
// skip any gaps
|
||||||
Storage::Tape::Tape::Pulse next_pulse = tape->get_next_pulse();
|
Storage::Tape::Tape::Pulse next_pulse = _tape->get_next_pulse();
|
||||||
while(next_pulse.type == Storage::Tape::Tape::Pulse::Zero)
|
while(next_pulse.type == Storage::Tape::Tape::Pulse::Zero)
|
||||||
{
|
{
|
||||||
next_pulse = tape->get_next_pulse();
|
next_pulse = _tape->get_next_pulse();
|
||||||
}
|
}
|
||||||
|
|
||||||
wave_lengths[wave_length_pointer] = next_pulse.length.get_float();
|
_wave_lengths[_wave_length_pointer] = next_pulse.length.get_float();
|
||||||
wave_length_pointer++;
|
_wave_length_pointer++;
|
||||||
|
|
||||||
// if first wave is too short or too long, drop it
|
// if first wave is too short or too long, drop it
|
||||||
if(wave_lengths[0] < 1.0f / 4800.0f || wave_lengths[0] >= 5.0f / 4800.0f)
|
if(_wave_lengths[0] < 1.0f / 4800.0f || _wave_lengths[0] >= 5.0f / 4800.0f)
|
||||||
{
|
{
|
||||||
rotate(1);
|
rotate(1);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if first two waves add up to a correct-length cycle, pop them and this is a 0
|
// if first two waves add up to a correct-length cycle, pop them and this is a 0
|
||||||
if(wave_length_pointer >= 2)
|
if(_wave_length_pointer >= 2)
|
||||||
{
|
{
|
||||||
float length = wave_lengths[0] + wave_lengths[1];
|
float length = _wave_lengths[0] + _wave_lengths[1];
|
||||||
if(length >= 3.0f / 4800.0f && length < 5.0f / 4800.0f)
|
if(length >= 3.0f / 4800.0f && length < 5.0f / 4800.0f)
|
||||||
{
|
{
|
||||||
rotate(2);
|
rotate(2);
|
||||||
@@ -49,70 +46,165 @@ struct TapeParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if all four waves add up to a correct-length cycle, pop them and this is a 1
|
// if all four waves add up to a correct-length cycle, pop them and this is a 1
|
||||||
if(wave_length_pointer >= 4)
|
if(_wave_length_pointer == 4)
|
||||||
{
|
{
|
||||||
float length = wave_lengths[0] + wave_lengths[1] + wave_lengths[2] + wave_lengths[3];
|
float length = _wave_lengths[0] + _wave_lengths[1] + _wave_lengths[2] + _wave_lengths[3];
|
||||||
if(length >= 3.0f / 4800.0f && length < 5.0f / 4800.0f)
|
if(length >= 3.0f / 4800.0f && length < 5.0f / 4800.0f)
|
||||||
{
|
{
|
||||||
rotate(4);
|
rotate(4);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rotate(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetNextByte(const std::shared_ptr<Storage::Tape::Tape> &tape)
|
int get_next_byte()
|
||||||
{
|
{
|
||||||
int value = 0;
|
int value = 0;
|
||||||
int c = 8;
|
int c = 8;
|
||||||
if(GetNextBit(tape)) return -1;
|
if(get_next_bit())
|
||||||
|
{
|
||||||
|
_error_flag = true;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
while(c--)
|
while(c--)
|
||||||
{
|
{
|
||||||
value = (value >> 1) | (GetNextBit(tape) << 7);
|
value = (value >> 1) | (get_next_bit() << 7);
|
||||||
}
|
}
|
||||||
if(!GetNextBit(tape)) return -1;
|
if(!get_next_bit())
|
||||||
|
{
|
||||||
|
_error_flag = true;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
add_to_crc((uint8_t)value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_next_short()
|
||||||
|
{
|
||||||
|
int result = get_next_byte();
|
||||||
|
result |= get_next_byte() << 8;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_next_word()
|
||||||
|
{
|
||||||
|
int result = get_next_short();
|
||||||
|
result |= get_next_short() << 8;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_error_flag()
|
||||||
|
{
|
||||||
|
_error_flag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_error_flag()
|
||||||
|
{
|
||||||
|
return _error_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_crc()
|
||||||
|
{
|
||||||
|
_crc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_to_crc(uint8_t value)
|
||||||
|
{
|
||||||
|
_crc ^= (uint16_t)value << 8;
|
||||||
|
for(int c = 0; c < 8; c++)
|
||||||
|
{
|
||||||
|
uint16_t exclusive_or = (_crc&0x8000) ? 0x1021 : 0x0000;
|
||||||
|
_crc = (uint16_t)(_crc << 1) ^ exclusive_or;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t get_crc()
|
||||||
|
{
|
||||||
|
return _crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_at_end()
|
||||||
|
{
|
||||||
|
return _tape->is_at_end();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void rotate(int places)
|
void rotate(int places)
|
||||||
{
|
{
|
||||||
wave_length_pointer -= places;
|
_wave_length_pointer -= places;
|
||||||
if(places < 4) memmove(wave_lengths, &wave_lengths[places], (size_t)(4 - places) * sizeof(float));
|
if(places < 4) memmove(_wave_lengths, &_wave_lengths[places], (size_t)(4 - places) * sizeof(float));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t _crc;
|
||||||
|
bool _error_flag;
|
||||||
|
|
||||||
|
float _wave_lengths[4];
|
||||||
|
int _wave_length_pointer;
|
||||||
|
std::shared_ptr<Storage::Tape::Tape> _tape;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<File> StaticAnalyser::Acorn::GetNextFile(const std::shared_ptr<Storage::Tape::Tape> &tape)
|
static std::unique_ptr<File::Chunk> GetNextChunk(TapeParser &parser)
|
||||||
{
|
{
|
||||||
|
std::unique_ptr<File::Chunk> new_chunk(new File::Chunk);
|
||||||
int shift_register = 0;
|
int shift_register = 0;
|
||||||
TapeParser parser;
|
|
||||||
|
|
||||||
#define shift() \
|
#define shift() \
|
||||||
shift_register = (shift_register >> 1) | (parser.GetNextBit(tape) << 9)
|
shift_register = (shift_register >> 1) | (parser.get_next_bit() << 9)
|
||||||
|
|
||||||
// find next area of high tone
|
// find next area of high tone
|
||||||
while(!tape->is_at_end() && (shift_register != 0x3ff))
|
while(!parser.is_at_end() && (shift_register != 0x3ff))
|
||||||
{
|
{
|
||||||
shift();
|
shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
// find next 0x2a (swallowing stop bit)
|
// find next 0x2a (swallowing stop bit)
|
||||||
while(!tape->is_at_end() && (shift_register != 0x254))
|
while(!parser.is_at_end() && (shift_register != 0x254))
|
||||||
{
|
{
|
||||||
shift();
|
shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parser.reset_crc();
|
||||||
|
parser.reset_error_flag();
|
||||||
|
|
||||||
// read out name
|
// read out name
|
||||||
char name[10];
|
char name[10];
|
||||||
int name_ptr = 0;
|
int name_ptr = 0;
|
||||||
while(!tape->is_at_end() && name_ptr < 10)
|
while(!parser.is_at_end() && name_ptr < 10)
|
||||||
{
|
{
|
||||||
name[name_ptr] = (char)parser.GetNextByte(tape);
|
name[name_ptr] = (char)parser.get_next_byte();
|
||||||
if(!name[name_ptr]) break;
|
if(!name[name_ptr]) break;
|
||||||
name_ptr++;
|
name_ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addresses
|
||||||
|
new_chunk->load_address = (uint32_t)parser.get_next_word();
|
||||||
|
new_chunk->execution_address = (uint32_t)parser.get_next_word();
|
||||||
|
new_chunk->block_number = (uint16_t)parser.get_next_short();
|
||||||
|
new_chunk->block_length = (uint16_t)parser.get_next_short();
|
||||||
|
new_chunk->block_flag = (uint8_t)parser.get_next_byte();
|
||||||
|
new_chunk->next_address = (uint32_t)parser.get_next_word();
|
||||||
|
|
||||||
|
uint16_t calculated_crc = parser.get_crc();
|
||||||
|
uint16_t stored_crc = (uint16_t)parser.get_next_short();
|
||||||
|
|
||||||
|
printf("%04x v %04x", calculated_crc, stored_crc);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<File> StaticAnalyser::Acorn::GetNextFile(const std::shared_ptr<Storage::Tape::Tape> &tape)
|
||||||
|
{
|
||||||
|
TapeParser parser(tape);
|
||||||
|
|
||||||
|
GetNextChunk(parser);
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
#ifndef StaticAnalyser_Acorn_Tape_hpp
|
#ifndef StaticAnalyser_Acorn_Tape_hpp
|
||||||
#define StaticAnalyser_Acorn_Tape_hpp
|
#define StaticAnalyser_Acorn_Tape_hpp
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -20,10 +21,25 @@ namespace Acorn {
|
|||||||
|
|
||||||
struct File {
|
struct File {
|
||||||
std::string name;
|
std::string name;
|
||||||
uint16_t load_address;
|
uint32_t load_address;
|
||||||
uint16_t execution_address;
|
uint32_t execution_address;
|
||||||
bool is_protected;
|
bool is_protected;
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
struct Chunk {
|
||||||
|
uint32_t load_address;
|
||||||
|
uint32_t execution_address;
|
||||||
|
uint16_t block_number;
|
||||||
|
uint16_t block_length;
|
||||||
|
uint8_t block_flag;
|
||||||
|
uint32_t next_address;
|
||||||
|
|
||||||
|
bool header_crc_matched;
|
||||||
|
bool data_crc_matched;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::list<Chunk> chunks;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<File> GetNextFile(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
std::unique_ptr<File> GetNextFile(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
||||||
|
Reference in New Issue
Block a user