1#include "../../../include/mmu.hpp"
2#include "../../../include/cartridge.hpp"
3#include "../../../include/ppu.hpp"
4#include "../../../include/timer.hpp"
5#include "../../../include/interrupt_controller.hpp"
10 dummy_ic = std::make_unique<InterruptController>();
11 dummy_cartridge = std::make_unique<Cartridge>();
12 dummy_timer = std::make_unique<Timer>(*dummy_ic);
13 dummy_ppu = std::make_unique<PPU>(*dummy_ic);
15 cartridge = dummy_cartridge.get();
17 timer = dummy_timer.get();
18 ppu = dummy_ppu.get();
76u8 MMU::read(
const u16 address)
const {
80 if (address <= 0x7FFF) {
81 return cartridge->read(address);
84 if (address <= 0x9FFF) {
85 return ppu->read(address);
88 if (address <= 0xBFFF) {
89 return cartridge->read(address);
92 if (address <= 0xDFFF) {
93 return wram[address - 0xC000];
96 if (address <= 0xFDFF) {
97 return wram[address - 0xE000];
100 if (address <= 0xFE9F) {
101 return ppu->read(address);
104 if (address <= 0xFEFF) {
108 if (address == 0xFF00)
return get_joypad_state();
109 if (address >= 0xFF04 && address <= 0xFF07)
return timer->read(address);
110 if (address == 0xFF0F)
return ic->read(address);
111 if (address >= 0xFF40 && address <= 0xFF4B)
return ppu->read(address);
112 if (address >= 0xFF00 && address <= 0xFF7F)
return io_regs[address - 0xFF00];
115 if (address <= 0xFFFE)
return hram[address - 0xFF80];
118 if (address == 0xFFFF)
return ic->read(address);
123void MMU::write(
const u16 address, u8 value) {
127 if (address <= 0x7FFF) {
128 cartridge->write(address, value);
132 if (address <= 0x9FFF) {
133 ppu->write(address, value);
137 if (address <= 0xBFFF) {
138 cartridge->write(address, value);
142 if (address <= 0xDFFF) {
143 wram[address - 0xC000] = value;
147 if (address <= 0xFDFF) {
148 wram[address - 0xE000] = value;
152 if (address <= 0xFE9F) {
153 ppu->write(address, value);
157 if (address <= 0xFEFF) {
161 if (address == 0xFF00) { joypad_select = value & 0x30;
return; }
162 if (address >= 0xFF04 && address <= 0xFF07) { timer->write(address, value);
return; }
163 if (address == 0xFF0F) { ic->write(address, value);
return; }
164 if (address == 0xFF46) { perform_dma(value); ppu->write(address, value);
return; }
165 if (address >= 0xFF40 && address <= 0xFF4B) { ppu->write(address, value);
return; }
166 if (address >= 0xFF00 && address <= 0xFF7F) { io_regs[address - 0xFF00] = value;
return; }
169 if (address <= 0xFFFE) { hram[address - 0xFF80] = value;
return; }
172 if (address == 0xFFFF) { ic->write(address, value);
return; }
175u8 MMU::get_current_rom_bank()
const {
176 return cartridge->get_current_rom_bank();
179void MMU::step_timer(
int cycles) {
183bool MMU::map_rom(
const std::vector<u8>& rom_data) {
184 return cartridge->load_rom(rom_data);
187void MMU::perform_dma(u8 value) {
188 u16 source_address = value << 8;
189 for (u16 i = 0; i < 0xA0; i++) {
190 write(0xFE00 + i, read(source_address + i));
194u8 MMU::get_joypad_state()
const {
196 if (!(joypad_select & 0x10)) state &= direction_buttons;
197 if (!(joypad_select & 0x20)) state &= action_buttons;
198 return 0xC0 | joypad_select | state;
201void MMU::set_joypad_state(u8 action, u8 direction) {
202 u8 old_state = get_joypad_state();
203 action_buttons = action;
204 direction_buttons = direction;
205 u8 new_state = get_joypad_state();
207 if ((old_state & ~new_state) & 0x0F) {
208 ic->request_interrupt(InterruptType::Joypad);
212std::vector<u8> MMU::dump_memory()
const {
213 std::vector<u8> dump(0x10000, 0);
216 std::copy(wram.begin(), wram.end(), dump.begin() + 0xC000);
217 std::copy(hram.begin(), hram.end(), dump.begin() + 0xFF80);
218 std::copy(io_regs.begin(), io_regs.end(), dump.begin() + 0xFF00);
221 for (u16 addr = 0x8000; addr <= 0x9FFF; ++addr) {
222 dump[addr] = read(addr);
224 for (u16 addr = 0xA000; addr <= 0xBFFF; ++addr) {
225 dump[addr] = read(addr);
227 for (u16 addr = 0xFE00; addr <= 0xFE9F; ++addr) {
228 dump[addr] = read(addr);
230 for (u16 addr = 0xFF40; addr <= 0xFF4B; ++addr) {
231 dump[addr] = read(addr);
235 dump[0x00] = cartridge->get_current_rom_bank();
236 dump[0x01] = joypad_select;
237 dump[0x02] = action_buttons;
238 dump[0x03] = direction_buttons;
239 dump[0x04] = ic->get_if();
240 dump[0x05] = ic->get_ie();
245bool MMU::load_memory(
const std::vector<u8>& dump) {
246 if (dump.size() != 0x10000) {
250 std::copy(dump.begin() + 0xC000, dump.begin() + 0xE000, wram.begin());
251 std::copy(dump.begin() + 0xFF80, dump.begin() + 0xFFFF, hram.begin());
252 std::copy(dump.begin() + 0xFF00, dump.begin() + 0xFF80, io_regs.begin());
254 cartridge->set_current_rom_bank(dump[0x00]);
255 joypad_select = dump[0x01];
256 action_buttons = dump[0x02];
257 direction_buttons = dump[0x03];
258 ic->set_if(dump[0x04]);
259 ic->set_ie(dump[0x05]);
262 for (u16 addr = 0x8000; addr <= 0x9FFF; ++addr) {
263 write(addr, dump[addr]);
265 for (u16 addr = 0xA000; addr <= 0xBFFF; ++addr) {
266 write(addr, dump[addr]);
268 for (u16 addr = 0xFE00; addr <= 0xFE9F; ++addr) {
269 write(addr, dump[addr]);
271 for (u16 addr = 0xFF40; addr <= 0xFF4B; ++addr) {
272 write(addr, dump[addr]);
278MMU::~MMU() =
default;
285 joypad_select = 0x30;
286 action_buttons = 0x0F;
287 direction_buttons = 0x0F;
291 if (cartridge) cartridge->reset();
292 if (timer) timer->reset();
294 if (ppu) ppu->reset();