1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-19 08:31:11 +00:00
CLK/InstructionSets/M50740/Parser.hpp

111 lines
3.5 KiB
C++
Raw Normal View History

2021-01-17 00:54:40 +00:00
//
// Parser.hpp
// Clock Signal
//
// Created by Thomas Harte on 16/01/21.
2021-01-17 00:54:40 +00:00
// Copyright © 2021 Thomas Harte. All rights reserved.
//
#ifndef InstructionSets_M50740_Parser_hpp
#define InstructionSets_M50740_Parser_hpp
#include <cstdint>
#include "Decoder.hpp"
2021-01-17 01:04:01 +00:00
#include "../AccessType.hpp"
2021-01-17 00:54:40 +00:00
namespace InstructionSet {
namespace M50740 {
2021-01-17 01:04:01 +00:00
template<typename Target, bool include_entries_and_accesses> struct Parser {
2021-01-17 00:54:40 +00:00
void parse(Target &target, const uint8_t *storage, uint16_t start, uint16_t closing_bound) {
Decoder decoder;
while(start <= closing_bound) {
const auto next = decoder.decode(&storage[start], 1 + closing_bound - start);
2021-01-17 00:54:40 +00:00
if(next.first <= 0) {
// If there weren't enough bytes left before the closing bound to complete
// an instruction, but implicitly there were some bytes left, announce overflow
// and terminate.
target.announce_overflow(start);
return;
} else {
// Pass on the instruction.
target.announce_instruction(start, next.second);
2021-01-17 01:04:01 +00:00
if constexpr(!include_entries_and_accesses) {
// Do a simplified test: is this a terminating operation?
switch(next.second.operation) {
case Operation::RTS: case Operation::RTI: case Operation::BRK:
case Operation::JMP: case Operation::BRA:
2021-01-17 01:04:01 +00:00
return;
2021-01-17 00:54:40 +00:00
2021-01-17 01:04:01 +00:00
default: break;
}
} else {
// Check for end of stream and potential new entry points.
switch(next.second.operation) {
// Terminating instructions.
case Operation::RTS: case Operation::RTI: case Operation::BRK:
return;
2021-01-17 00:54:40 +00:00
2021-01-17 01:04:01 +00:00
// Terminating operations with implied additional entry point.
case Operation::JMP:
target.add_entry(storage[start + 1] | (storage[start + 2] << 8));
return;
case Operation::BRA:
target.add_entry(start + 2 + int8_t(storage[start + 1]));
return;
2021-01-17 00:54:40 +00:00
2021-01-17 01:04:01 +00:00
// Instructions that suggest another entry point but don't terminate parsing.
// case Operation::BBS: case Operation::BBC: // TODO: BBS, BBC
2021-01-17 01:04:01 +00:00
case Operation::BCC: case Operation::BCS:
case Operation::BVC: case Operation::BVS:
case Operation::BMI: case Operation::BPL:
case Operation::BNE: case Operation::BEQ:
target.add_entry(start + 2 + int8_t(storage[start + 1]));
break;
case Operation::JSR:
target.add_entry(storage[start + 1] | (storage[start + 2] << 8));
break;
// // TODO: addressing like the below for the relevant BBC and BBS.
// case AddressingMode::Bit0AccumulatorRelative:
// target.add_access(start + 2 + int8_t(storage[start + 1]), access_type(next.second.operation));
// break;
// // TODO: this is a potential addressing mode for JSR.
// case AddressingMode::SpecialPage:
// target.add_access(storage[start + 1] | 0x1f00, access_type(next.second.operation));
// break;
2021-01-17 01:04:01 +00:00
default: break;
}
2021-01-17 00:54:40 +00:00
2021-01-17 01:04:01 +00:00
// Provide any fixed address accesses.
switch(next.second.addressing_mode) {
case AddressingMode::Absolute:
target.add_access(storage[start + 1] | (storage[start + 2] << 8), access_type(next.second.operation));
break;
case AddressingMode::ZeroPage:
target.add_access(storage[start + 1], access_type(next.second.operation));
break;
case AddressingMode::ImmediateZeroPage:
target.add_access(storage[start + 2], access_type(next.second.operation));
break;
2021-01-17 00:54:40 +00:00
2021-01-17 01:04:01 +00:00
default: break;
}
2021-01-17 00:54:40 +00:00
}
// Advance.
start += next.first;
}
}
}
};
}
}
#endif /* InstructionSets_M50740_Parser_hpp */