You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
2.9 KiB
116 lines
2.9 KiB
/* |
|
* Copyright (C) 2022 Riyyi |
|
* Copyright (C) 2022 Th3FrankXD |
|
* |
|
* SPDX-License-Identifier: MIT |
|
*/ |
|
|
|
#include <cstdint> // uint32_t |
|
#include <string_view> |
|
#include <utility> // std::move |
|
#include <vector> |
|
|
|
#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<uint32_t>(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; |
|
}
|
|
|