<commit_before>#include "Debugger.h"
#include "Cpu.h"
#include "CpuHelpers.h"
#include "CpuOpCodes.h"
#include "MemoryBus.h"
#include "Platform.h"
#include <array>
#include <iostream>
#include <vector>

namespace {
    std::vector<std::string> Tokenize(const std::string& s) {
        std::vector<std::string> result;
        const char* whitespace = " \t";
        size_t startIndex = 0;
        while ((startIndex = s.find_first_not_of(whitespace, startIndex)) != std::string::npos) {
            size_t endIndex = s.find_first_of(whitespace, startIndex + 1);

            if (endIndex == std::string::npos) {
                result.emplace_back(s.substr(startIndex));
                break;
            } else {
                result.emplace_back(s.substr(startIndex, endIndex - startIndex));
                startIndex = endIndex;
            }
        }
        return result;
    }

    struct Instruction {
        const CpuOp& cpuOp;
        int page;
        std::array<uint8_t, 2> operands;
    };

    Instruction ReadInstruction(uint16_t opAddr, const MemoryBus& memoryBus) {
        int cpuOpPage = 0;
        uint8_t opCodeByte = memoryBus.Read(opAddr++);
        if (IsOpCodePage1(opCodeByte)) {
            cpuOpPage = 1;
            opCodeByte = memoryBus.Read(opAddr++);
        } else if (IsOpCodePage2(opCodeByte)) {
            cpuOpPage = 2;
            opCodeByte = memoryBus.Read(opAddr++);
        }

        const auto& cpuOp = LookupCpuOpRuntime(cpuOpPage, opCodeByte);
        const int numOperands = cpuOp.size - 1 - (cpuOpPage == 0 ? 0 : 1);

        Instruction result = {cpuOp, cpuOpPage};
        for (int i = 0; i < numOperands; ++i) {
            result.operands[i] = memoryBus.Read(opAddr++);
        }
        return result;
    }

    std::string DisassembleOp(const CpuRegisters& reg, const MemoryBus& memoryBus) {
        uint16_t opAddr = reg.PC;
        auto instruction = ReadInstruction(opAddr, memoryBus);
        const auto& cpuOp = instruction.cpuOp;

        std::string hexInstruction;
        // Output instruction in hex
        for (uint16_t i = 0; i < cpuOp.size; ++i)
            hexInstruction += FormattedString<>("%02x", memoryBus.Read(opAddr + i));

        std::string disasmInstruction, comment;

        if (cpuOp.addrMode == AddressingMode::Direct) {
            //@TODO: compute EA = DP : (operand[0]) and show it in comments
            uint16_t EA = CombineToU16(reg.DP, instruction.operands[0]);
            uint8_t value = memoryBus.Read(EA);

            disasmInstruction = FormattedString<>("%s $%02x", cpuOp.name, instruction.operands[0]);

            comment = FormattedString<>("DP:(PC) = $%02x = $%02x (%d)", EA, value, value);
        } else {
            disasmInstruction = cpuOp.name;
        }

        std::string result =
            FormattedString<>("%-10s %-10s %s", hexInstruction.c_str(), disasmInstruction.c_str(),
                              comment.size() > 0 ? ("# " + comment).c_str() : "");
        return result;
    };

} // namespace

void Debugger::Init(MemoryBus& memoryBus, Cpu& cpu) {
    m_memoryBus = &memoryBus;
    m_cpu = &cpu;

    Platform::SetConsoleCtrlHandler([this] {
        m_breakIntoDebugger = true;
        return true;
    });
}

void Debugger::Run() {
    m_lastCommand = "step"; // Reasonable default

    // Break on start
    m_breakIntoDebugger = true;<commit_msg>Disassemble Inherent (mostly), Immediate, and Extended instructions<commit_after>#include "Debugger.h"
#include "Cpu.h"
#include "CpuHelpers.h"
#include "CpuOpCodes.h"
#include "MemoryBus.h"
#include "Platform.h"
#include <array>
#include <iostream>
#include <vector>

namespace {
    std::vector<std::string> Tokenize(const std::string& s) {
        std::vector<std::string> result;
        const char* whitespace = " \t";
        size_t startIndex = 0;
        while ((startIndex = s.find_first_not_of(whitespace, startIndex)) != std::string::npos) {
            size_t endIndex = s.find_first_of(whitespace, startIndex + 1);

            if (endIndex == std::string::npos) {
                result.emplace_back(s.substr(startIndex));
                break;
            } else {
                result.emplace_back(s.substr(startIndex, endIndex - startIndex));
                startIndex = endIndex;
            }
        }
        return result;
    }

    struct Instruction {
        const CpuOp& cpuOp;
        int page;
        std::array<uint8_t, 2> operands;
    };

    Instruction ReadInstruction(uint16_t opAddr, const MemoryBus& memoryBus) {
        int cpuOpPage = 0;
        uint8_t opCodeByte = memoryBus.Read(opAddr++);
        if (IsOpCodePage1(opCodeByte)) {
            cpuOpPage = 1;
            opCodeByte = memoryBus.Read(opAddr++);
        } else if (IsOpCodePage2(opCodeByte)) {
            cpuOpPage = 2;
            opCodeByte = memoryBus.Read(opAddr++);
        }

        const auto& cpuOp = LookupCpuOpRuntime(cpuOpPage, opCodeByte);
        const int numOperands = cpuOp.size - 1 - (cpuOpPage == 0 ? 0 : 1);

        Instruction result = {cpuOp, cpuOpPage};
        for (int i = 0; i < numOperands; ++i) {
            result.operands[i] = memoryBus.Read(opAddr++);
        }
        return result;
    }

    std::string DisassembleOp(const CpuRegisters& reg, const MemoryBus& memoryBus) {
        uint16_t opAddr = reg.PC;
        auto instruction = ReadInstruction(opAddr, memoryBus);
        const auto& cpuOp = instruction.cpuOp;

        std::string hexInstruction;
        // Output instruction in hex
        for (uint16_t i = 0; i < cpuOp.size; ++i)
            hexInstruction += FormattedString<>("%02x", memoryBus.Read(opAddr + i));

        std::string disasmInstruction, comment;

        switch (cpuOp.addrMode) {
        case AddressingMode::Inherent: {
            //@TODO: Some inherent instructions do take operands, like TFR
            disasmInstruction = cpuOp.name;
        } break;

        case AddressingMode::Immediate: {
            uint8_t value = instruction.operands[0];
            disasmInstruction = FormattedString<>("%s #$%02x", cpuOp.name, value);
            comment = FormattedString<>("(%d)", value);
        } break;

        case AddressingMode::Extended: {
            auto msb = instruction.operands[0];
            auto lsb = instruction.operands[1];
            uint16_t EA = CombineToU16(msb, lsb);
            uint8_t value = memoryBus.Read(EA);
            disasmInstruction = FormattedString<>("%s $%04x", cpuOp.name, EA);
            comment = FormattedString<>("$%02x (%d)", value, value);
        } break;

        case AddressingMode::Direct: {
            uint16_t EA = CombineToU16(reg.DP, instruction.operands[0]);
            uint8_t value = memoryBus.Read(EA);
            disasmInstruction = FormattedString<>("%s $%02x", cpuOp.name, instruction.operands[0]);
            comment = FormattedString<>("DP:(PC) = $%02x = $%02x (%d)", EA, value, value);
        } break;

        case AddressingMode::Indexed:  //@TODO
        case AddressingMode::Relative: //@TODO
            disasmInstruction = cpuOp.name;
            break;

        case AddressingMode::Illegal:
        case AddressingMode::Variant:
            assert(false);
            break;
        }

        std::string result =
            FormattedString<>("%-10s %-10s %s", hexInstruction.c_str(), disasmInstruction.c_str(),
                              comment.size() > 0 ? ("# " + comment).c_str() : "");
        return result;
    };

} // namespace

void Debugger::Init(MemoryBus& memoryBus, Cpu& cpu) {
    m_memoryBus = &memoryBus;
    m_cpu = &cpu;

    Platform::SetConsoleCtrlHandler([this] {
        m_breakIntoDebugger = true;
        return true;
    });
}

void Debugger::Run() {
    m_lastCommand = "step"; // Reasonable default

    // Break on start
    m_breakIntoDebugger = true;
{'fraction_non_alphanumeric': 0.1283326954968746, 'fraction_numerical': 0.012756729174639622, 'mean_word_length': 2.3010526315789472, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1951408', 'n_tokens_mistral': 2493, 'n_tokens_neox': 2404, 'n_words': 525}