-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMMU.cpp
More file actions
149 lines (132 loc) · 4.56 KB
/
MMU.cpp
File metadata and controls
149 lines (132 loc) · 4.56 KB
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
#include "MMU.h"
MMU::MMU () {
memset (Memory, 0, sizeof(Memory));
}
uint8_t MMU::GetByteAt (uint16_t Address) {
if (Address < 0x4000)
return ROM [Address]; // ROM Bank 0
else if (Address < 0x8000)
return ROM [0x4000 * CurrentROMBank + (Address - 0x4000)]; // ROM Bank n
if (Address >= 0xE000 && Address < 0xFE00) // 8KB Internal RAM Echo
Address -= 0x2000;
if (Address >= 0xFE00 && Address < 0xFEA0) { // OAM
if (CurrentPPUMode >= 2) { // Inaccessible
printf ("[WARN] Blocked OAM Read\n");
return 0xFF;
}
}
if (ROMType == 1 || ROMType == 2) {
if (ExternalRAMEnabled) {
if (Address >= 0xA000 && Address < 0xC000) // Read from External RAM
return ExternalRAM [0x2000 * CurrentRAMBank + (Address - 0xA000)];
}
} else if (ROMType == 3) {
if (Address >= 0xA000 && Address < 0xC000) { // Read from External RAM / RTC
if (CurrentRAMBank <= 0x07)
return ExternalRAM [0x2000 * CurrentRAMBank + (Address - 0xA000)];
else { // TODO RTC
return RTCRegister [CurrentRAMBank];
}
}
}
return Memory [Address];
}
void MMU::SetByteAt (uint16_t Address, uint8_t Value) {
switch (Address) {
case 0xFF01: printf ("%c", Value); fflush (stdout); return; // SB
case 0xFF04: Value = 0; return; // DIV Register, Always write 0
case 0xFF46: if (CurrentPPUMode < 2) memcpy (Memory + 0xFE00, Memory + (Value << 8), 0xA0); return; // DMA
default: break;
}
if (Address >= 0xE000 && Address < 0xFE00) // 8KB Internal RAM Echo
Address -= 0x2000;
if (Address >= 0xFE00 && Address < 0xFEA0) { // OAM
if (CurrentPPUMode >= 2) { // Inaccessible
printf ("[WARN] Blocked OAM Write\n");
return;
}
}
if (Address >= 0x8000 && Address < 0xA000) { // VRAM
if (CurrentPPUMode >= 3) { // Inaccessible
printf ("[WARN] Blocked VRAM Write\n");
return;
}
}
if (Address >= 0xFEA0 && Address < 0xFF00) // Unused Memory Area, Ignore write
return;
if (ROMType == 0) {
if (Address < 0x8000) {
printf ("[WARN] Blocked illegal ROM Write\n");
return;
}
} else if (ROMType == 1) {
if (Address <= 0x1FFF) { // Toggle External RAM
ExternalRAMEnabled = (Value == 0x0A); // Active only if gb writes 0x0A
return;
} else if (Address >= 0x2000 && Address < 0x4000) { // Write lower 5 bits of ROM Bank
CurrentROMBank &= 0b11100000;
if (Value == 0) // Writing 0 translates to 1 in DMG
Value = 1;
CurrentROMBank |= Value & 0b00011111;
return;
} else if (Address >= 0x4000 && Address < 0x6000) { // Write upper 2 bits of ROM Bank (bit 7 is left as 0), or just select RAM Bank
if (SelectRAMBank) { // Choose RAM Bank
CurrentRAMBank = Value & 0b11;
} else {
CurrentROMBank &= 0b00011111;
CurrentROMBank |= ((Value & 0b11) << 5);
}
return;
} else if (Address >= 0x6000 && Address < 0x8000) { // Switch mode above
if (Value == 0) {
SelectRAMBank = 0;
CurrentRAMBank = 0;
} else {
SelectRAMBank = 1;
CurrentROMBank &= 0b00011111; // Clear the 2 bits to accommodate the change
}
return;
} else if (Address >= 0xA000 && Address < 0xC000) { // Write to External RAM
if (ExternalRAMEnabled)
ExternalRAM [0x2000 * CurrentRAMBank + (Address - 0xA000)] = Value;
return;
}
} else if (ROMType == 2) {
if (Address < 0x2000) { // Toggle External RAM
ExternalRAMEnabled = (Value == 0x0A); // TODO, Special case: "The least significant bit of the upper address byte must be '0' to enable/disable cart RAM."
return;
} else if (Address < 0x4000) {
CurrentROMBank = Value & 0xF; // TODO, Special case: "The least significant bit of the upper address byte must be '1' to select a ROM bank."
return;
}
} else if (ROMType == 3) {
if (Address < 0x2000) { // Toggle External RAM / RTC
ExternalRAMEnabled = (Value == 0x0A);
return;
} else if (Address >= 0x2000 && Address < 0x4000) { // Choose ROM Bank
if (Value == 0)
Value = 1;
CurrentROMBank = Value;
return;
} else if (Address >= 0x4000 && Address < 0x6000) { // Choose RAM / RTC Bank
CurrentRAMBank = Value;
return;
} else if (Address >= 0xA000 && Address < 0xC000) { // Write to External RAM / RTC
if (CurrentRAMBank <= 0x07) {
ExternalRAM [0x2000 * CurrentRAMBank + (Address - 0xA000)] = Value;
} else
RTCRegister [CurrentRAMBank] = Value;
return;
} else if (Address >= 0x6000 && Address < 0x8000) { // RTC Latch
return;
}
}
Memory [Address] = Value;
}
uint16_t MMU::GetWordAt (uint16_t Address) {
return (GetByteAt (Address + 1) << 8) + GetByteAt (Address);
}
void MMU::SetWordAt (uint16_t Address, uint16_t Value) {
SetByteAt (Address + 1, Value >> 8);
SetByteAt (Address, Value & 0xFF);
}