1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-06 01:28:57 +00:00

The parsers no longer own a tape, merely taking one as an argument. So they can be an adjunct.

This commit is contained in:
Thomas Harte 2016-11-06 15:25:18 -05:00
parent bc83a8f2d0
commit 093eb55fc6
3 changed files with 111 additions and 115 deletions

View File

@ -24,30 +24,30 @@ enum class SymbolType {
class Acorn1200BaudTapeParser: public StaticAnalyer::TapeParser<WaveType, SymbolType> {
public:
Acorn1200BaudTapeParser(const std::shared_ptr<Storage::Tape::Tape> &tape) :
TapeParser(tape),
Acorn1200BaudTapeParser() :
TapeParser(),
_crc(0x1021, 0x0000) {}
int get_next_bit()
int get_next_bit(const std::shared_ptr<Storage::Tape::Tape> &tape)
{
SymbolType symbol = get_next_symbol();
SymbolType symbol = get_next_symbol(tape);
return (symbol == SymbolType::One) ? 1 : 0;
}
int get_next_byte()
int get_next_byte(const std::shared_ptr<Storage::Tape::Tape> &tape)
{
int value = 0;
int c = 8;
if(get_next_bit())
if(get_next_bit(tape))
{
set_error_flag();
return -1;
}
while(c--)
{
value = (value >> 1) | (get_next_bit() << 7);
value = (value >> 1) | (get_next_bit(tape) << 7);
}
if(!get_next_bit())
if(!get_next_bit(tape))
{
set_error_flag();
return -1;
@ -56,17 +56,17 @@ class Acorn1200BaudTapeParser: public StaticAnalyer::TapeParser<WaveType, Symbol
return value;
}
int get_next_short()
int get_next_short(const std::shared_ptr<Storage::Tape::Tape> &tape)
{
int result = get_next_byte();
result |= get_next_byte() << 8;
int result = get_next_byte(tape);
result |= get_next_byte(tape) << 8;
return result;
}
int get_next_word()
int get_next_word(const std::shared_ptr<Storage::Tape::Tape> &tape)
{
int result = get_next_short();
result |= get_next_short() << 8;
int result = get_next_short(tape);
result |= get_next_short(tape) << 8;
return result;
}
@ -117,22 +117,22 @@ class Acorn1200BaudTapeParser: public StaticAnalyer::TapeParser<WaveType, Symbol
NumberTheory::CRC16 _crc;
};
static std::unique_ptr<File::Chunk> GetNextChunk(Acorn1200BaudTapeParser &parser)
static std::unique_ptr<File::Chunk> GetNextChunk(const std::shared_ptr<Storage::Tape::Tape> &tape, Acorn1200BaudTapeParser &parser)
{
std::unique_ptr<File::Chunk> new_chunk(new File::Chunk);
int shift_register = 0;
// TODO: move this into the parser
#define shift() shift_register = (shift_register >> 1) | (parser.get_next_bit() << 9)
#define shift() shift_register = (shift_register >> 1) | (parser.get_next_bit(tape) << 9)
// find next area of high tone
while(!parser.is_at_end() && (shift_register != 0x3ff))
while(!tape->is_at_end() && (shift_register != 0x3ff))
{
shift();
}
// find next 0x2a (swallowing stop bit)
while(!parser.is_at_end() && (shift_register != 0x254))
while(!tape->is_at_end() && (shift_register != 0x254))
{
shift();
}
@ -145,9 +145,9 @@ static std::unique_ptr<File::Chunk> GetNextChunk(Acorn1200BaudTapeParser &parser
// read out name
char name[11];
int name_ptr = 0;
while(!parser.is_at_end() && name_ptr < sizeof(name))
while(!tape->is_at_end() && name_ptr < sizeof(name))
{
name[name_ptr] = (char)parser.get_next_byte();
name[name_ptr] = (char)parser.get_next_byte(tape);
if(!name[name_ptr]) break;
name_ptr++;
}
@ -155,15 +155,15 @@ static std::unique_ptr<File::Chunk> GetNextChunk(Acorn1200BaudTapeParser &parser
new_chunk->name = name;
// 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();
new_chunk->load_address = (uint32_t)parser.get_next_word(tape);
new_chunk->execution_address = (uint32_t)parser.get_next_word(tape);
new_chunk->block_number = (uint16_t)parser.get_next_short(tape);
new_chunk->block_length = (uint16_t)parser.get_next_short(tape);
new_chunk->block_flag = (uint8_t)parser.get_next_byte(tape);
new_chunk->next_address = (uint32_t)parser.get_next_word(tape);
uint16_t calculated_header_crc = parser.get_crc();
uint16_t stored_header_crc = (uint16_t)parser.get_next_short();
uint16_t stored_header_crc = (uint16_t)parser.get_next_short(tape);
stored_header_crc = (uint16_t)((stored_header_crc >> 8) | (stored_header_crc << 8));
new_chunk->header_crc_matched = stored_header_crc == calculated_header_crc;
@ -171,13 +171,13 @@ static std::unique_ptr<File::Chunk> GetNextChunk(Acorn1200BaudTapeParser &parser
new_chunk->data.reserve(new_chunk->block_length);
for(int c = 0; c < new_chunk->block_length; c++)
{
new_chunk->data.push_back((uint8_t)parser.get_next_byte());
new_chunk->data.push_back((uint8_t)parser.get_next_byte(tape));
}
if(new_chunk->block_length && !(new_chunk->block_flag&0x40))
{
uint16_t calculated_data_crc = parser.get_crc();
uint16_t stored_data_crc = (uint16_t)parser.get_next_short();
uint16_t stored_data_crc = (uint16_t)parser.get_next_short(tape);
stored_data_crc = (uint16_t)((stored_data_crc >> 8) | (stored_data_crc << 8));
new_chunk->data_crc_matched = stored_data_crc == calculated_data_crc;
}
@ -233,13 +233,13 @@ std::unique_ptr<File> GetNextFile(std::deque<File::Chunk> &chunks)
std::list<File> StaticAnalyser::Acorn::GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape)
{
Acorn1200BaudTapeParser parser(tape);
Acorn1200BaudTapeParser parser;
// populate chunk list
std::deque<File::Chunk> chunk_list;
while(!parser.is_at_end())
while(!tape->is_at_end())
{
std::unique_ptr<File::Chunk> chunk = GetNextChunk(parser);
std::unique_ptr<File::Chunk> chunk = GetNextChunk(tape, parser);
if(chunk)
{
chunk_list.push_back(*chunk);

View File

@ -49,7 +49,7 @@ struct Data {
class CommodoreROMTapeParser: public StaticAnalyer::TapeParser<WaveType, SymbolType> {
public:
CommodoreROMTapeParser(const std::shared_ptr<Storage::Tape::Tape> &tape) :
TapeParser(tape),
TapeParser(),
_wave_period(0.0f),
_previous_was_high(false),
_parity_byte(0) {}
@ -58,11 +58,11 @@ class CommodoreROMTapeParser: public StaticAnalyer::TapeParser<WaveType, SymbolT
Advances to the next block on the tape, treating it as a header, then consumes, parses, and returns it.
Returns @c nullptr if any wave-encoding level errors are encountered.
*/
std::unique_ptr<Header> get_next_header()
std::unique_ptr<Header> get_next_header(const std::shared_ptr<Storage::Tape::Tape> &tape)
{
return duplicate_match<Header>(
get_next_header_body(true),
get_next_header_body(false)
get_next_header_body(tape, true),
get_next_header_body(tape, false)
);
}
@ -70,29 +70,29 @@ class CommodoreROMTapeParser: public StaticAnalyer::TapeParser<WaveType, SymbolT
Advances to the next block on the tape, treating it as data, then consumes, parses, and returns it.
Returns @c nullptr if any wave-encoding level errors are encountered.
*/
std::unique_ptr<Data> get_next_data()
std::unique_ptr<Data> get_next_data(const std::shared_ptr<Storage::Tape::Tape> &tape)
{
return duplicate_match<Data>(
get_next_data_body(true),
get_next_data_body(false)
get_next_data_body(tape, true),
get_next_data_body(tape, false)
);
}
void spin()
{
while(!is_at_end())
{
SymbolType symbol = get_next_symbol();
switch(symbol)
{
case SymbolType::One: printf("1"); break;
case SymbolType::Zero: printf("0"); break;
case SymbolType::Word: printf(" "); break;
case SymbolType::EndOfBlock: printf("\n"); break;
case SymbolType::LeadIn: printf("-"); break;
}
}
}
// void spin()
// {
// while(!is_at_end())
// {
// SymbolType symbol = get_next_symbol();
// switch(symbol)
// {
// case SymbolType::One: printf("1"); break;
// case SymbolType::Zero: printf("0"); break;
// case SymbolType::Word: printf(" "); break;
// case SymbolType::EndOfBlock: printf("\n"); break;
// case SymbolType::LeadIn: printf("-"); break;
// }
// }
// }
private:
/*!
@ -122,20 +122,20 @@ class CommodoreROMTapeParser: public StaticAnalyer::TapeParser<WaveType, SymbolT
return std::move(*copy_to_return);
}
std::unique_ptr<Header> get_next_header_body(bool is_original)
std::unique_ptr<Header> get_next_header_body(const std::shared_ptr<Storage::Tape::Tape> &tape, bool is_original)
{
std::unique_ptr<Header> header(new Header);
reset_error_flag();
// find and proceed beyond lead-in tone
proceed_to_symbol(SymbolType::LeadIn);
proceed_to_symbol(tape, SymbolType::LeadIn);
// look for landing zone
proceed_to_landing_zone(is_original);
proceed_to_landing_zone(tape, is_original);
reset_parity_byte();
// get header type
uint8_t header_type = get_next_byte();
uint8_t header_type = get_next_byte(tape);
switch(header_type)
{
default: header->type = Header::Unknown; break;
@ -150,11 +150,11 @@ class CommodoreROMTapeParser: public StaticAnalyer::TapeParser<WaveType, SymbolT
header->data.reserve(191);
for(size_t c = 0; c < 191; c++)
{
header->data.push_back(get_next_byte());
header->data.push_back(get_next_byte(tape));
}
uint8_t parity_byte = get_parity_byte();
header->parity_was_valid = get_next_byte() == parity_byte;
header->parity_was_valid = get_next_byte(tape) == parity_byte;
// parse if this is not pure data
if(header->type != Header::DataBlock)
@ -174,22 +174,22 @@ class CommodoreROMTapeParser: public StaticAnalyer::TapeParser<WaveType, SymbolT
}
std::unique_ptr<Data> get_next_data_body(bool is_original)
std::unique_ptr<Data> get_next_data_body(const std::shared_ptr<Storage::Tape::Tape> &tape, bool is_original)
{
std::unique_ptr<Data> data(new Data);
reset_error_flag();
// find and proceed beyond lead-in tone to the next landing zone
proceed_to_symbol(SymbolType::LeadIn);
proceed_to_landing_zone(is_original);
proceed_to_symbol(tape, SymbolType::LeadIn);
proceed_to_landing_zone(tape, is_original);
reset_parity_byte();
// accumulate until the next non-word marker is hit
while(!is_at_end())
while(!tape->is_at_end())
{
SymbolType start_symbol = get_next_symbol();
SymbolType start_symbol = get_next_symbol(tape);
if(start_symbol != SymbolType::Word) break;
data->data.push_back(get_next_byte_contents());
data->data.push_back(get_next_byte_contents(tape));
}
// the above has reead the parity byte to the end of the data; if it matched the calculated parity it'll now be zero
@ -205,13 +205,13 @@ class CommodoreROMTapeParser: public StaticAnalyer::TapeParser<WaveType, SymbolT
/*!
Finds and completes the next landing zone.
*/
void proceed_to_landing_zone(bool is_original)
void proceed_to_landing_zone(const std::shared_ptr<Storage::Tape::Tape> &tape, bool is_original)
{
uint8_t landing_zone[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
while(!is_at_end())
while(!tape->is_at_end())
{
memmove(landing_zone, &landing_zone[1], sizeof(uint8_t) * 8);
landing_zone[8] = get_next_byte();
landing_zone[8] = get_next_byte(tape);
bool is_landing_zone = true;
for(int c = 0; c < 9; c++)
@ -230,11 +230,11 @@ class CommodoreROMTapeParser: public StaticAnalyer::TapeParser<WaveType, SymbolT
Swallows symbols until it reaches the first instance of the required symbol, swallows that
and returns.
*/
void proceed_to_symbol(SymbolType required_symbol)
void proceed_to_symbol(const std::shared_ptr<Storage::Tape::Tape> &tape, SymbolType required_symbol)
{
while(!is_at_end())
while(!tape->is_at_end())
{
SymbolType symbol = get_next_symbol();
SymbolType symbol = get_next_symbol(tape);
if(symbol == required_symbol) return;
}
}
@ -242,9 +242,9 @@ class CommodoreROMTapeParser: public StaticAnalyer::TapeParser<WaveType, SymbolT
/*!
Swallows the next byte; sets the error flag if it is not equal to @c value.
*/
void expect_byte(uint8_t value)
void expect_byte(const std::shared_ptr<Storage::Tape::Tape> &tape, uint8_t value)
{
uint8_t next_byte = get_next_byte();
uint8_t next_byte = get_next_byte(tape);
if(next_byte != value) set_error_flag();
}
@ -256,10 +256,10 @@ class CommodoreROMTapeParser: public StaticAnalyer::TapeParser<WaveType, SymbolT
/*!
Proceeds to the next word marker then returns the result of @c get_next_byte_contents.
*/
uint8_t get_next_byte()
uint8_t get_next_byte(const std::shared_ptr<Storage::Tape::Tape> &tape)
{
proceed_to_symbol(SymbolType::Word);
return get_next_byte_contents();
proceed_to_symbol(tape, SymbolType::Word);
return get_next_byte_contents(tape);
}
/*!
@ -267,13 +267,13 @@ class CommodoreROMTapeParser: public StaticAnalyer::TapeParser<WaveType, SymbolT
Returns a byte composed of the first eight of those as bits; sets the error flag if any symbol is not
::One and not ::Zero, or if the ninth bit is not equal to the odd parity of the other eight.
*/
uint8_t get_next_byte_contents()
uint8_t get_next_byte_contents(const std::shared_ptr<Storage::Tape::Tape> &tape)
{
int byte_plus_parity = 0;
int c = 9;
while(c--)
{
SymbolType next_symbol = get_next_symbol();
SymbolType next_symbol = get_next_symbol(tape);
if((next_symbol != SymbolType::One) && (next_symbol != SymbolType::Zero)) set_error_flag();
byte_plus_parity = (byte_plus_parity >> 1) | (((next_symbol == SymbolType::One) ? 1 : 0) << 8);
}
@ -292,10 +292,10 @@ class CommodoreROMTapeParser: public StaticAnalyer::TapeParser<WaveType, SymbolT
/*!
Returns the result of two consecutive @c get_next_byte calls, arranged in little-endian format.
*/
uint16_t get_next_short()
uint16_t get_next_short(const std::shared_ptr<Storage::Tape::Tape> &tape)
{
uint16_t value = get_next_byte();
value |= get_next_byte() << 8;
uint16_t value = get_next_byte(tape);
value |= get_next_byte(tape) << 8;
return value;
}
@ -376,13 +376,13 @@ std::list<File> StaticAnalyser::Commodore::GetFiles(const std::shared_ptr<Storag
CommodoreROMTapeParser parser(tape);
std::list<File> file_list;
std::unique_ptr<Header> header = parser.get_next_header();
std::unique_ptr<Header> header = parser.get_next_header(tape);
while(!parser.is_at_end())
while(!tape->is_at_end())
{
if(!header)
{
header = parser.get_next_header();
header = parser.get_next_header(tape);
continue;
}
@ -398,9 +398,9 @@ std::list<File> StaticAnalyser::Commodore::GetFiles(const std::shared_ptr<Storag
new_file.type = File::DataSequence;
new_file.data.swap(header->data);
while(!parser.is_at_end())
while(!tape->is_at_end())
{
header = parser.get_next_header();
header = parser.get_next_header(tape);
if(!header) continue;
if(header->type != Header::DataBlock) break;
std::copy(header->data.begin(), header->data.end(), std::back_inserter(new_file.data));
@ -413,7 +413,7 @@ std::list<File> StaticAnalyser::Commodore::GetFiles(const std::shared_ptr<Storag
case Header::RelocatableProgram:
case Header::NonRelocatableProgram:
{
std::unique_ptr<Data> data = parser.get_next_data();
std::unique_ptr<Data> data = parser.get_next_data(tape);
if(data)
{
File new_file;
@ -427,12 +427,12 @@ std::list<File> StaticAnalyser::Commodore::GetFiles(const std::shared_ptr<Storag
file_list.push_back(new_file);
}
header = parser.get_next_header();
header = parser.get_next_header(tape);
}
break;
default:
header = parser.get_next_header();
header = parser.get_next_header(tape);
break;
}
}

View File

@ -21,14 +21,32 @@ namespace StaticAnalyer {
template <typename WaveType, typename SymbolType> class TapeParser {
public:
/// Instantiates a new parser with the supplied @c tape.
TapeParser(const std::shared_ptr<Storage::Tape::Tape> &tape) : _tape(tape), _has_next_symbol(false), _error_flag(false) {}
TapeParser() : _has_next_symbol(false), _error_flag(false) {}
/// Resets the error flag.
void reset_error_flag() { _error_flag = false; }
/// @returns @c true if an error has occurred since the error flag was last reset; @c false otherwise.
bool get_error_flag() { return _error_flag; }
/// @returns @c true if the encapsulated tape has reached its end; @c false otherwise.
bool is_at_end() { return _tape->is_at_end(); }
/*!
Asks the parser to continue taking pulses from the tape until either the subclass next declares a symbol
or the tape runs out, returning the most-recently declared symbol.
*/
SymbolType get_next_symbol(const std::shared_ptr<Storage::Tape::Tape> &tape)
{
while(!_has_next_symbol && !tape->is_at_end())
{
process_pulse(tape->get_next_pulse());
}
_has_next_symbol = false;
return _next_symbol;
}
/*!
Should be implemented by subclasses. Consumes @c pulse. Is likely either to call @c push_wave
or to take no action.
*/
virtual void process_pulse(Storage::Tape::Tape::Pulse pulse) = 0;
protected:
@ -67,20 +85,6 @@ template <typename WaveType, typename SymbolType> class TapeParser {
remove_waves(number_of_waves);
}
/*!
Asks the parser to continue taking pulses from the tape until either the subclass next declares a symbol
or the tape runs out, returning the most-recently declared symbol.
*/
SymbolType get_next_symbol()
{
while(!_has_next_symbol && !is_at_end())
{
process_pulse(_tape->get_next_pulse());
}
_has_next_symbol = false;
return _next_symbol;
}
void set_error_flag()
{
_error_flag = true;
@ -89,12 +93,6 @@ template <typename WaveType, typename SymbolType> class TapeParser {
private:
bool _error_flag;
/*!
Should be implemented by subclasses. Consumes @c pulse. Is likely either to call @c push_wave
or to take no action.
*/
virtual void process_pulse(Storage::Tape::Tape::Pulse pulse) = 0;
/*!
Should be implemented by subclasses. Inspects @c waves for a potential new symbol. If one is
found should call @c push_symbol. May wish alternatively to call @c remove_waves to have entries
@ -106,8 +104,6 @@ template <typename WaveType, typename SymbolType> class TapeParser {
std::vector<WaveType> _wave_queue;
SymbolType _next_symbol;
bool _has_next_symbol;
std::shared_ptr<Storage::Tape::Tape> _tape;
};
}