-
-
Notifications
You must be signed in to change notification settings - Fork 14
/
mem.cpp
167 lines (146 loc) · 3.75 KB
/
mem.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "mem.h"
#include "rom.h"
#include "lcd.h"
#include "mbc.h"
#include "interrupt.h"
#include "timer.h"
#include "cpu.h"
bool usebootrom = false;
uint8_t *mem = nullptr;
static uint8_t *echo;
static uint32_t DMA_pending;
static uint8_t joypad_select_buttons, joypad_select_directions;
uint8_t btn_directions, btn_faces;
static const s_rominfo *rominfo;
static const uint8_t *rom;
uint8_t mem_get_byte(uint16_t i)
{
if(DMA_pending && i < 0xFF80)
{
uint32_t elapsed = cpu_get_cycles() - DMA_pending;
if(elapsed >= 160) {
DMA_pending = 0;
} else {
return mem[0xFE00+elapsed];
}
}
if(i >= 0x4000 && i < 0x8000)
return rombank[i - 0x4000];
else if (i >= 0xA000 && i < 0xC000)
return mbc_read_ram(i);
else if (i >= 0xE000 && i < 0xFE00)
return echo[i];
else switch(i)
{
case 0xFF00: { /* Joypad */
uint8_t mask = 0;
if(!joypad_select_buttons)
mask = btn_faces;
if(!joypad_select_directions)
mask = btn_directions;
return (0xC0) | (joypad_select_buttons | joypad_select_directions) | (mask);
}
case 0xFF04: return timer_get_div();
case 0xFF0F: return 0xE0 | IF;
case 0xFF41: return lcd_get_stat();
case 0xFF44: return lcd_get_line();
case 0xFF4D: return 0xFF; /* GBC speed switch */
case 0xFFFF: return IE;
}
return mem[i];
}
void mem_write_byte(uint16_t d, uint8_t i)
{
/* ROM */
if (d < 0x8000)
mbc_write_rom(d, i);
/* SRAM */
else if (d >= 0xA000 && d < 0xC000)
mbc_write_ram(d, i);
/* ECHO */
else if (d >= 0xE000 && d < 0xFE00)
echo[d] = i;
else switch(d)
{
case 0xFF00: /* Joypad */
joypad_select_buttons = i&0x20;
joypad_select_directions = i&0x10;
break;
case 0xFF04: timer_reset_div(); break;
case 0xFF07: timer_set_tac(i); break;
case 0xFF0F: IF = i; break;
case 0xFF40: lcd_write_control(i); break;
case 0xFF41: lcd_write_stat(i); break;
case 0xFF42: lcd_write_scroll_y(i); break;
case 0xFF43: lcd_write_scroll_x(i); break;
case 0xFF44: lcd_reset(); break;
case 0xFF45: lcd_set_ly_compare(i); break;
case 0xFF46: { /* OAM DMA */
/* Check if address overlaps with RAM or ROM */
uint16_t addr = i * 0x100;
const uint8_t* src = mem;
if (addr >= 0x4000 && addr < 0x8000) {
src = rombank;
addr -= 0x4000;
}
else if (addr >= 0xA000 && addr < 0xC000) {
src = rambank;
addr -= 0xA000;
}
/* Copy 0xA0 bytes from source to OAM */
memcpy(&mem[0xFE00], &src[addr], 0xA0);
DMA_pending = cpu_get_cycles();
break;
}
case 0xFF47: lcd_write_bg_palette(i); break;
case 0xFF48: lcd_write_spr_palette1(i); break;
case 0xFF49: lcd_write_spr_palette2(i); break;
case 0xFF4A: lcd_set_window_y(i); break;
case 0xFF4B: lcd_set_window_x(i); break;
case 0xFF50: memcpy(&mem[0x0000], &rom[0x0000], 0x100); break; /* Lock bootROM */
case 0xFFFF: IE = i; break;
default: mem[d] = i; break;
}
}
bool mmu_init(const uint8_t* bootrom)
{
mem = (uint8_t *)calloc(1, 0x10000);
if (!mem)
return false;
if (!mbc_init())
return false;
rom = rom_getbytes();
echo = mem + 0xC000 - 0xE000;
if (bootrom) {
memcpy(&mem[0x0000], &bootrom[0x0000], 0x100);
memcpy(&mem[0x0100], &rom[0x0100], 0x4000 - 0x100);
usebootrom = true;
return true;
}
// First ROM bank is always in RAM
memcpy(&mem[0x0000], &rom[0x0000], 0x4000);
// Default values if bootrom is not present
mem[0xFF10] = 0x80;
mem[0xFF11] = 0xBF;
mem[0xFF12] = 0xF3;
mem[0xFF14] = 0xBF;
mem[0xFF16] = 0x3F;
mem[0xFF19] = 0xBF;
mem[0xFF1A] = 0x7F;
mem[0xFF1B] = 0xFF;
mem[0xFF1C] = 0x9F;
mem[0xFF1E] = 0xBF;
mem[0xFF20] = 0xFF;
mem[0xFF23] = 0xBF;
mem[0xFF24] = 0x77;
mem[0xFF25] = 0xF3;
mem[0xFF26] = 0xF1;
mem[0xFF40] = 0x91;
mem[0xFF47] = 0xFC;
mem[0xFF48] = 0xFF;
mem[0xFF49] = 0xFF;
return true;
}