diff --git a/InstructionSets/Disassembler.hpp b/InstructionSets/Disassembler.hpp index a9613d8d0..1b3fece00 100644 --- a/InstructionSets/Disassembler.hpp +++ b/InstructionSets/Disassembler.hpp @@ -31,7 +31,6 @@ template < > class Disassembler { public: using ProgramCounterType = typename MinIntTypeValue::type; - static_assert(!std::is_same_v); /*! 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 &instructions() const { + return instructions_; + } + + const std::set &entry_points() const { + return entry_points_; + } + void announce_overflow(ProgramCounterType) {} void announce_instruction(ProgramCounterType address, InstructionType instruction) { instructions_[address] = instruction; diff --git a/InstructionSets/M50740/Instruction.hpp b/InstructionSets/M50740/Instruction.hpp index 539d9971b..b5c675534 100644 --- a/InstructionSets/M50740/Instruction.hpp +++ b/InstructionSets/M50740/Instruction.hpp @@ -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(); } diff --git a/InstructionSets/M50740/Parser.hpp b/InstructionSets/M50740/Parser.hpp index 84d692464..9c9937921 100644 --- a/InstructionSets/M50740/Parser.hpp +++ b/InstructionSets/M50740/Parser.hpp @@ -48,35 +48,50 @@ template 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 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: diff --git a/Machines/Apple/AppleIIgs/ADB.cpp b/Machines/Apple/AppleIIgs/ADB.cpp index 299084253..b632898c6 100644 --- a/Machines/Apple/AppleIIgs/ADB.cpp +++ b/Machines/Apple/AppleIIgs/ADB.cpp @@ -222,8 +222,24 @@ uint8_t GLU::read_microcontroller_address(uint16_t address) { void GLU::set_microcontroller_rom(const std::vector &rom) { executor_.set_rom(rom); + // TEST invocation. InstructionSet::Disassembler 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) {