1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-26 08:29:33 +00:00

Improves M50470 entry-point detection, adds test output.

This commit is contained in:
Thomas Harte 2021-01-26 21:29:17 -05:00
parent 56111c75ae
commit dcc2fe0990
4 changed files with 83 additions and 37 deletions

View File

@ -31,7 +31,6 @@ template <
> class Disassembler {
public:
using ProgramCounterType = typename MinIntTypeValue<max_address>::type;
static_assert(!std::is_same_v<ProgramCounterType, void>);
/*!
Adds the result of disassembling @c memory which is @c length @c MemoryWords long from @c start_address
@ -48,10 +47,20 @@ template <
const auto next_entry_point = pending_entry_points_.front();
pending_entry_points_.pop_front();
parser.parse(*this, memory - location, next_entry_point, length + location);
if(next_entry_point >= location) {
parser.parse(*this, memory - location, next_entry_point % max_address, length + location);
}
}
}
const std::map<ProgramCounterType, InstructionType> &instructions() const {
return instructions_;
}
const std::set<ProgramCounterType> &entry_points() const {
return entry_points_;
}
void announce_overflow(ProgramCounterType) {}
void announce_instruction(ProgramCounterType address, InstructionType instruction) {
instructions_[address] = instruction;

View File

@ -169,31 +169,37 @@ inline constexpr const char *addressing_mode_name(AddressingMode addressing_mode
would appear in an assembler. E.g. '$5a' for that zero page address, or '$5a, x' for zero-page indexed from $5a. This function
may access up to three bytes from @c operation onwards.
*/
inline std::string address(AddressingMode addressing_mode, const uint8_t *operation) {
inline std::string address(AddressingMode addressing_mode, const uint8_t *operation, uint16_t program_counter) {
std::stringstream output;
output << std::hex << std::setfill('0') << std::setw(2);
output << std::hex;
#define NUM(x) std::setfill('0') << std::setw(2) << int(x)
#define NUM4(x) std::setfill('0') << std::setw(4) << int(x)
switch(addressing_mode) {
default: return "???";
case AddressingMode::Implied: return "";
case AddressingMode::Accumulator: return "A";
case AddressingMode::Immediate: output << "#$" << int(operation[1]); break;
case AddressingMode::Absolute: output << "$" << int(operation[2]) << int(operation[1]); break;
case AddressingMode::AbsoluteX: output << "$" << int(operation[2]) << int(operation[1]) << ", x"; break;
case AddressingMode::AbsoluteY: output << "$" << int(operation[2]) << int(operation[1]) << ", y"; break;
case AddressingMode::ZeroPage: output << "$" << int(operation[1]); break;
case AddressingMode::ZeroPageX: output << "$" << int(operation[1]) << ", x"; break;
case AddressingMode::ZeroPageY: output << "$" << int(operation[1]) << ", y"; break;
case AddressingMode::XIndirect: output << "(($" << int(operation[1]) << ", x))"; break;
case AddressingMode::IndirectY: output << "(($" << int(operation[1]) << "), y)"; break;
case AddressingMode::Relative: output << "+#$" << int(int8_t(operation[1])); break;
case AddressingMode::AbsoluteIndirect: output << "($" << int(operation[2]) << int(operation[1]) << ")"; break;
case AddressingMode::ZeroPageIndirect: output << "($" << int(operation[1]) << ")"; break;
case AddressingMode::SpecialPage: output << "$1f" << int(operation[1]); break;
case AddressingMode::ImmediateZeroPage: output << "#$" << int(operation[1]) << ", $" << int(int8_t(operation[2])); break;
case AddressingMode::AccumulatorRelative: output << "A, +#$" << int(int8_t(operation[1])); break;
case AddressingMode::ZeroPageRelative: output << "$" << int(operation[1]) << ", +#$" << int(int8_t(operation[2])); break;
case AddressingMode::Accumulator: return "A ";
case AddressingMode::Immediate: output << "#$" << NUM(operation[1]); break;
case AddressingMode::Absolute: output << "$" << NUM(operation[2]) << NUM(operation[1]); break;
case AddressingMode::AbsoluteX: output << "$" << NUM(operation[2]) << NUM(operation[1]) << ", x"; break;
case AddressingMode::AbsoluteY: output << "$" << NUM(operation[2]) << NUM(operation[1]) << ", y"; break;
case AddressingMode::ZeroPage: output << "$" << NUM(operation[1]); break;
case AddressingMode::ZeroPageX: output << "$" << NUM(operation[1]) << ", x"; break;
case AddressingMode::ZeroPageY: output << "$" << NUM(operation[1]) << ", y"; break;
case AddressingMode::XIndirect: output << "(($" << NUM(operation[1]) << ", x))"; break;
case AddressingMode::IndirectY: output << "(($" << NUM(operation[1]) << "), y)"; break;
case AddressingMode::Relative: output << "#$" << NUM4(2 + program_counter + int8_t(operation[1])); break;
case AddressingMode::AbsoluteIndirect: output << "($" << NUM(operation[2]) << NUM(operation[1]) << ") "; break;
case AddressingMode::ZeroPageIndirect: output << "($" << NUM(operation[1]) << ")"; break;
case AddressingMode::SpecialPage: output << "$1f" << NUM(operation[1]); break;
case AddressingMode::ImmediateZeroPage: output << "#$" << NUM(operation[1]) << ", $" << NUM(operation[2]); break;
case AddressingMode::AccumulatorRelative: output << "A, $" << NUM4(2 + program_counter + int8_t(operation[1])); break;
case AddressingMode::ZeroPageRelative:
output << "$" << NUM(operation[1]) << ", $" << NUM4(2 + program_counter + int8_t(operation[2]));
break;
}
#undef NUM4
#undef NUM
return output.str();
}

View File

@ -48,35 +48,50 @@ template<typename Target, bool include_entries_and_accesses> struct Parser {
case Operation::RTS: case Operation::RTI: case Operation::BRK:
return;
// Terminating operations with implied additional entry point.
// Terminating operations, possibly with implied additional entry point.
case Operation::JMP:
target.add_entry(storage[start + 1] | (storage[start + 2] << 8));
if(next.second.addressing_mode == AddressingMode::Absolute) {
target.add_entry(uint16_t(storage[start + 1] | (storage[start + 2] << 8)));
}
return;
case Operation::BRA:
target.add_entry(start + 2 + int8_t(storage[start + 1]));
target.add_entry(uint16_t(start + 2 + int8_t(storage[start + 1])));
return;
// Instructions that suggest another entry point but don't terminate parsing.
// case Operation::BBS: case Operation::BBC: // TODO: BBS, BBC
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]));
target.add_entry(uint16_t(start + 2 + int8_t(storage[start + 1])));
break;
case Operation::JSR:
target.add_entry(storage[start + 1] | (storage[start + 2] << 8));
switch(next.second.addressing_mode) {
default: break;
case AddressingMode::Absolute:
target.add_entry(uint16_t(storage[start + 1] | (storage[start + 2] << 8)));
break;
case AddressingMode::SpecialPage:
target.add_entry(uint16_t(storage[start + 1] | 0x1f00));
break;
}
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;
case Operation::BBS0: case Operation::BBS1: case Operation::BBS2: case Operation::BBS3:
case Operation::BBS4: case Operation::BBS5: case Operation::BBS6: case Operation::BBS7:
case Operation::BBC0: case Operation::BBC1: case Operation::BBC2: case Operation::BBC3:
case Operation::BBC4: case Operation::BBC5: case Operation::BBC6: case Operation::BBC7:
switch(next.second.addressing_mode) {
default: break;
case AddressingMode::AccumulatorRelative:
target.add_entry(uint16_t(start + 2 + int8_t(storage[start + 1])));
break;
case AddressingMode::ZeroPageRelative:
target.add_entry(uint16_t(start + 3 + int8_t(storage[start + 2])));
break;
}
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;
default: break;
}
@ -84,9 +99,9 @@ template<typename Target, bool include_entries_and_accesses> struct Parser {
// 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));
target.add_access(uint16_t(storage[start + 1] | (storage[start + 2] << 8)), access_type(next.second.operation));
break;
case AddressingMode::ZeroPage:
case AddressingMode::ZeroPage: case AddressingMode::ZeroPageRelative:
target.add_access(storage[start + 1], access_type(next.second.operation));
break;
case AddressingMode::ImmediateZeroPage:

View File

@ -222,8 +222,24 @@ uint8_t GLU::read_microcontroller_address(uint16_t address) {
void GLU::set_microcontroller_rom(const std::vector<uint8_t> &rom) {
executor_.set_rom(rom);
// TEST invocation.
InstructionSet::Disassembler<InstructionSet::M50740::Parser, 0x1fff, InstructionSet::M50740::Instruction, uint8_t, uint16_t> disassembler;
disassembler.disassemble(rom.data(), 0x1000, uint16_t(rom.size()), 0x1000);
const auto instructions = disassembler.instructions();
const auto entry_points = disassembler.entry_points();
for(const auto &pair : instructions) {
std::cout << std::hex << pair.first << "\t\t";
if(entry_points.find(pair.first) != entry_points.end()) {
std::cout << "L" << pair.first << "\t";
} else {
std::cout << "\t\t";
}
std::cout << operation_name(pair.second.operation) << " ";
std::cout << address(pair.second.addressing_mode, &rom[pair.first - 0x1000], pair.first);
std::cout << std::endl;
}
}
void GLU::run_for(Cycles cycles) {