/* * Copyright (C) 2022 Riyyi * Copyright (C) 2022 Th3FrankXD * * SPDX-License-Identifier: MIT */ #include // uint32_t #include #include // std::move #include #include "cpu.h" #include "emu.h" #include "loader.h" #include "ruc/format/log.h" #include "ruc/format/print.h" #include "ruc/meta/assert.h" void Emu::init(uint32_t frequency) { m_frequency = frequency; m_timestep = 1.0 / m_frequency * 1000000; } void Emu::update() { double time = m_timer.elapsedNanoseconds() / 1000.0; m_cycle_time += (time - m_previous_time); m_previous_time = time; if (m_cycle_time > m_timestep) { for (auto unit : m_processing_units) { if (m_cycle % (m_frequency / unit.second->frequency()) == 0) { unit.second->update(); } } m_cycle_time -= m_timestep; m_cycle++; } } void Emu::addProcessingUnit(std::string_view name, ProcessingUnit* processing_unit) { m_processing_units.emplace(name, processing_unit); } void Emu::addMemorySpace(std::string_view name, uint32_t start_address, uint32_t end_adress, uint32_t amount_of_banks) { uint32_t bank_length = 1 + end_adress - start_address; MemorySpace memory_space { .memory = BankedMemory(amount_of_banks, std::vector(bank_length)), .active_bank = 0, .start_address = start_address, .end_address = end_adress, }; m_memory_spaces.emplace(name, std::move(memory_space)); } void Emu::removeMemorySpace(std::string_view name) { m_memory_spaces.erase(name); } void Emu::writeMemory(uint32_t address, uint32_t value) { for (auto& memory_space : m_memory_spaces) { auto& memory = memory_space.second; if (address >= memory.start_address && address <= memory.end_address) { // Note: ECHO RAM hack if (address >= 0xc000 && address <= 0xddff) { writeMemory(address + (0xe000 - 0xc000), value); } memory.memory[memory.active_bank][address - memory.start_address] = value; if (address == 0xff50) { print("DISABLING BOOTROM\n"); Loader::the().disableBootrom(); } // Write serial data from linkport I/O, used for blargg's test ROMs if (address == 0xff02 && value == 0x81) { uint32_t data = readMemory(0xff01); print("{:c}", (data >= 58 && data <= 64) ? data + 7 : data); } return; } } ruc::error("writing into address '{:#06x}' which is not in a memory space!", address); VERIFY_NOT_REACHED(); } uint32_t Emu::readMemory(uint32_t address) const { for (const auto& memory_space : m_memory_spaces) { const auto& memory = memory_space.second; if (address >= memory.start_address && address <= memory.end_address) { return memory.memory[memory.active_bank][address - memory.start_address]; } } // When trying to access the cartridge header if (address >= 0x100 && address <= 0x14f) { ruc::error("no cartridge loaded!"); } else { ruc::error("reading from address '{:#06x}' which is not in a memory space!", address); } VERIFY_NOT_REACHED(); return 0; }