<commit_before>/*
 * Copyright (c) 2021, <NAME> <<EMAIL>>
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#include <unistd.h>

#include "core/ScopeGuard.h"
#include "backplane.h"
#include "controller.h"
#include "emulator.h"
#include "register.h"
#include "registers.h"

namespace Obelix::CPU {

CPU::CPU(std::string const& image)
    : m_queuedKeys()
{
    m_system.defaultSetup();
    m_system.setRunMode(SystemBus::RunMode::Continuous);
    m_system.controller()->setListener(this);
    m_keyboard = std::make_shared<IOChannel>(0x00, "KEY", [this]() {
        byte b = 0xFF;
        {
            while (read(0, &b, 1)) {
                m_queuedKeys.push_back(b);
            }
        }
        if (!m_queuedKeys.empty()) {
            b = m_queuedKeys.front();
            m_queuedKeys.pop_front();
        }
        return b;
    });

    m_terminal = std::make_shared<IOChannel>(0x01, "OUT", [](byte out) {
        write(1, &out, 1);
    });

    m_system.insertIO(m_keyboard);
    m_system.insertIO(m_terminal);

    openImage(image, 0, false);
}

CPU::~CPU()
{
}

ErrorOr<uint16_t, SystemErrorCode> CPU::run(bool trace, word addr)
{
    ScopeGuard sg([this]() { m_trace = false; });
    m_trace = trace;
    if (auto err = m_system.reset(); err.is_error()) {
        auto e = err.error();
        return { e };
    }
    if (auto err = m_system.run(addr); err.is_error()) {
        auto e = err.error();
        return ErrorOr<uint16_t, SystemErrorCode> { e };
    }
    return ErrorOr<uint16_t, SystemErrorCode> { (uint16_t)m_system.component<AddressRegister>(DI)->getValue() };
}

void CPU::componentEvent(Component const* sender, int ev)
{
    switch (ev) {
    case Controller::EV_AFTERINSTRUCTION:
        if (m_trace) {
            auto instr = dynamic_cast<Controller const*>(sender)->instruction();
            std::string args;
            std::string mnemonic = instr;
            auto pos = instr.find_first_of(' ');
            if (pos != std::string::npos) {
                mnemonic = instr.substr(0, pos);
                args = instr.substr(pos);
            }
            printf("%04x %-6.6s%-15.15s    %02x %02x %02x %02x %04x %04x %04x %04x\n",
                dynamic_cast<Controller const*>(sender)->pc(),
                mnemonic.c_str(), args.c_str(),
                m_system.component<Register>(GP_A)->getValue(),
                m_system.component<Register>(GP_B)->getValue(),
                m_system.component<Register>(GP_C)->getValue(),
                m_system.component<Register>(GP_D)->getValue(),
                m_system.component<AddressRegister>(SI)->getValue(),
                m_system.component<AddressRegister>(DI)->getValue(),
                m_system.component<AddressRegister>(SP)->getValue(),
                m_system.component<AddressRegister>(BP)->getValue());
        }
        break;
    default:
        break;
    }
}

void CPU::openImage(FILE* img, word addr, bool writable)
{
    if (fseek(img, 0, SEEK_END)) {
        perror("fseek");
        exit(-1);
    }
    size_t sz;
    if ((sz = ftell(img)) < 0) {
        perror("ftell");
        exit(-1);
    }
    if (fseek(img, 0, SEEK_SET)) {
        perror("fseek");
        exit(-1);
    }

    byte* bytearr = new byte[sz];
    {
        ScopeGuard sg { [bytearr]() { delete[] bytearr; } };
        if (!fread(bytearr, sz, 1, img)) {
            perror("fread");
            exit(-1);
        }<commit_msg>Show stack when --trace is on<commit_after>/*
 * Copyright (c) 2021, <NAME> <<EMAIL>>
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#include <unistd.h>

#include "core/ScopeGuard.h"
#include "backplane.h"
#include "controller.h"
#include "emulator.h"
#include "register.h"
#include "registers.h"

namespace Obelix::CPU {

CPU::CPU(std::string const& image)
    : m_queuedKeys()
{
    m_system.defaultSetup();
    m_system.setRunMode(SystemBus::RunMode::Continuous);
    m_system.controller()->setListener(this);
    m_keyboard = std::make_shared<IOChannel>(0x00, "KEY", [this]() {
        byte b = 0xFF;
        {
            while (read(0, &b, 1)) {
                m_queuedKeys.push_back(b);
            }
        }
        if (!m_queuedKeys.empty()) {
            b = m_queuedKeys.front();
            m_queuedKeys.pop_front();
        }
        return b;
    });

    m_terminal = std::make_shared<IOChannel>(0x01, "OUT", [](byte out) {
        write(1, &out, 1);
    });

    m_system.insertIO(m_keyboard);
    m_system.insertIO(m_terminal);

    openImage(image, 0, false);
}

CPU::~CPU()
{
}

ErrorOr<uint16_t, SystemErrorCode> CPU::run(bool trace, word addr)
{
    ScopeGuard sg([this]() { m_trace = false; });
    m_trace = trace;
    if (auto err = m_system.reset(); err.is_error()) {
        auto e = err.error();
        return { e };
    }
    if (auto err = m_system.run(addr); err.is_error()) {
        auto e = err.error();
        return ErrorOr<uint16_t, SystemErrorCode> { e };
    }
    return ErrorOr<uint16_t, SystemErrorCode> { (uint16_t)m_system.component<AddressRegister>(DI)->getValue() };
}

void CPU::componentEvent(Component const* sender, int ev)
{
    switch (ev) {
    case Controller::EV_AFTERINSTRUCTION:
        if (m_trace) {
            auto instr = dynamic_cast<Controller const*>(sender)->instruction();
            std::string args;
            std::string mnemonic = instr;
            auto pos = instr.find_first_of(' ');
            if (pos != std::string::npos) {
                mnemonic = instr.substr(0, pos);
                args = instr.substr(pos);
            }
            auto sp = m_system.component<AddressRegister>(SP)->getValue();
            auto bp = m_system.component<AddressRegister>(BP)->getValue();
            auto mem = m_system.component<Memory>();
            std::string stack;
            for (auto ix = sp; 0xC000 < ix; ix -= 2) {
                if (ix == bp)
                    stack += " | ";
                stack += format("{04x} ", (((uint16_t)mem->peek(ix - 1).value()) << 8) | mem->peek(ix - 2).value());
            }
            printf("%04x %-6.6s%-15.15s    %02x %02x %02x %02x %04x %04x %04x %04x    %s\n",
                dynamic_cast<Controller const*>(sender)->pc(),
                mnemonic.c_str(), args.c_str(),
                m_system.component<Register>(GP_A)->getValue(),
                m_system.component<Register>(GP_B)->getValue(),
                m_system.component<Register>(GP_C)->getValue(),
                m_system.component<Register>(GP_D)->getValue(),
                m_system.component<AddressRegister>(SI)->getValue(),
                m_system.component<AddressRegister>(DI)->getValue(),
                m_system.component<AddressRegister>(SP)->getValue(),
                m_system.component<AddressRegister>(BP)->getValue(),
                stack.c_str());
        }
        break;
    default:
        break;
    }
}

void CPU::openImage(FILE* img, word addr, bool writable)
{
    if (fseek(img, 0, SEEK_END)) {
        perror("fseek");
        exit(-1);
    }
    size_t sz;
    if ((sz = ftell(img)) < 0) {
        perror("ftell");
        exit(-1);
    }
    if (fseek(img, 0, SEEK_SET)) {
        perror("fseek");
        exit(-1);
    }

    byte* bytearr = new byte[sz];
    {
        ScopeGuard sg { [bytearr]() { delete[] bytearr; } };
        if (!fread(bytearr, sz, 1, img)) {
            perror("fread");
            exit(-1);
        }
{'fraction_non_alphanumeric': 0.16317142470572318, 'fraction_numerical': 0.017588959545393044, 'mean_word_length': 2.215311004784689, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 74, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6160439', 'n_tokens_mistral': 2547, 'n_tokens_neox': 2413, 'n_words': 441}