SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
Core/mbc.c
1 #include <stdbool.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "gb.h"
5
6 const GB_cartridge_t GB_cart_defs[256] = {
7 // From http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header#0147_-_Cartridge_Type
8 /* MBC RAM BAT. RTC RUMB. */
9 { GB_NO_MBC, false, false, false, false}, // 00h ROM ONLY
10 { GB_MBC1 , false, false, false, false}, // 01h MBC1
11 { GB_MBC1 , true , false, false, false}, // 02h MBC1+RAM
12 { GB_MBC1 , true , true , false, false}, // 03h MBC1+RAM+BATTERY
13 [5] =
14 { GB_MBC2 , true , false, false, false}, // 05h MBC2
15 { GB_MBC2 , true , true , false, false}, // 06h MBC2+BATTERY
16 [8] =
17 { GB_NO_MBC, true , false, false, false}, // 08h ROM+RAM
18 { GB_NO_MBC, true , true , false, false}, // 09h ROM+RAM+BATTERY
19 [0xB] =
20 { GB_MMM01 , false, false, false, false}, // 0Bh MMM01
21 { GB_MMM01 , true , false, false, false}, // 0Ch MMM01+RAM
22 { GB_MMM01 , true , true , false, false}, // 0Dh MMM01+RAM+BATTERY
23 [0xF] =
24 { GB_MBC3 , false, true, true , false}, // 0Fh MBC3+TIMER+BATTERY
25 { GB_MBC3 , true , true, true , false}, // 10h MBC3+TIMER+RAM+BATTERY
26 { GB_MBC3 , false, false, false, false}, // 11h MBC3
27 { GB_MBC3 , true , false, false, false}, // 12h MBC3+RAM
28 { GB_MBC3 , true , true , false, false}, // 13h MBC3+RAM+BATTERY
29 [0x19] =
30 { GB_MBC5 , false, false, false, false}, // 19h MBC5
31 { GB_MBC5 , true , false, false, false}, // 1Ah MBC5+RAM
32 { GB_MBC5 , true , true , false, false}, // 1Bh MBC5+RAM+BATTERY
33 { GB_MBC5 , false, false, false, true }, // 1Ch MBC5+RUMBLE
34 { GB_MBC5 , true , false, false, true }, // 1Dh MBC5+RUMBLE+RAM
35 { GB_MBC5 , true , true , false, true }, // 1Eh MBC5+RUMBLE+RAM+BATTERY
36 [0x22] =
37 { GB_MBC7 , true, true, false, false}, // 22h MBC7+ACCEL+EEPROM
38 [0xFC] =
39 { GB_CAMERA, true , true , false, false}, // FCh POCKET CAMERA
40 { GB_NO_MBC, false, false, false, false}, // FDh BANDAI TAMA5 (Todo: Not supported)
41 { GB_HUC3 , true , true , true, false}, // FEh HuC3
42 { GB_HUC1 , true , true , false, false}, // FFh HuC1+RAM+BATTERY
43 };
44
45 void GB_update_mbc_mappings(GB_gameboy_t *gb)
46 {
47 switch (gb->cartridge_type->mbc_type) {
48 case GB_NO_MBC: return;
49 case GB_MBC1:
50 switch (gb->mbc1_wiring) {
51 case GB_STANDARD_MBC1_WIRING:
52 gb->mbc_rom_bank = gb->mbc1.bank_low | (gb->mbc1.bank_high << 5);
53 if (gb->mbc1.mode == 0) {
54 gb->mbc_ram_bank = 0;
55 gb->mbc_rom0_bank = 0;
56 }
57 else {
58 gb->mbc_ram_bank = gb->mbc1.bank_high;
59 gb->mbc_rom0_bank = gb->mbc1.bank_high << 5;
60 }
61 if ((gb->mbc_rom_bank & 0x1F) == 0) {
62 gb->mbc_rom_bank++;
63 }
64 break;
65 case GB_MBC1M_WIRING:
66 gb->mbc_rom_bank = (gb->mbc1.bank_low & 0xF) | (gb->mbc1.bank_high << 4);
67 if (gb->mbc1.mode == 0) {
68 gb->mbc_ram_bank = 0;
69 gb->mbc_rom0_bank = 0;
70 }
71 else {
72 gb->mbc_rom0_bank = gb->mbc1.bank_high << 4;
73 gb->mbc_ram_bank = 0;
74 }
75 if ((gb->mbc1.bank_low & 0x1F) == 0) {
76 gb->mbc_rom_bank++;
77 }
78 break;
79 nodefault;
80 }
81 break;
82 case GB_MBC2:
83 gb->mbc_rom_bank = gb->mbc2.rom_bank;
84 if ((gb->mbc_rom_bank & 0xF) == 0) {
85 gb->mbc_rom_bank = 1;
86 }
87 break;
88 case GB_MBC3:
89 gb->mbc_rom_bank = gb->mbc3.rom_bank;
90 gb->mbc_ram_bank = gb->mbc3.ram_bank;
91 if (!gb->is_mbc30) {
92 gb->mbc_rom_bank &= 0x7F;
93 }
94 if (gb->mbc_rom_bank == 0) {
95 gb->mbc_rom_bank = 1;
96 }
97 break;
98 case GB_MBC5:
99 case GB_CAMERA:
100 gb->mbc_rom_bank = gb->mbc5.rom_bank_low | (gb->mbc5.rom_bank_high << 8);
101 gb->mbc_ram_bank = gb->mbc5.ram_bank;
102 break;
103 case GB_MBC7:
104 gb->mbc_rom_bank = gb->mbc7.rom_bank;
105 break;
106 case GB_MMM01:
107 if (gb->mmm01.locked) {
108 if (gb->mmm01.multiplex_mode) {
109 gb->mbc_rom0_bank = (gb->mmm01.rom_bank_low & (gb->mmm01.rom_bank_mask << 1)) |
110 ((gb->mmm01.mbc1_mode? 0 : gb->mmm01.ram_bank_low) << 5) |
111 (gb->mmm01.rom_bank_high << 7);
112 gb->mbc_rom_bank = gb->mmm01.rom_bank_low |
113 (gb->mmm01.ram_bank_low << 5) |
114 (gb->mmm01.rom_bank_high << 7);
115 gb->mbc_ram_bank = gb->mmm01.rom_bank_mid | (gb->mmm01.ram_bank_high << 2);
116 }
117 else {
118 gb->mbc_rom0_bank = (gb->mmm01.rom_bank_low & (gb->mmm01.rom_bank_mask << 1)) |
119 (gb->mmm01.rom_bank_mid << 5) |
120 (gb->mmm01.rom_bank_high << 7);
121 gb->mbc_rom_bank = gb->mmm01.rom_bank_low |
122 (gb->mmm01.rom_bank_mid << 5) |
123 (gb->mmm01.rom_bank_high << 7);
124 if (gb->mmm01.mbc1_mode) {
125 gb->mbc_ram_bank = gb->mmm01.ram_bank_low | (gb->mmm01.ram_bank_high << 2);
126 }
127 else {
128 gb->mbc_ram_bank = gb->mmm01.ram_bank_low | (gb->mmm01.ram_bank_high << 2);
129 }
130 }
131 if (gb->mbc_rom_bank == gb->mbc_rom0_bank) {
132 gb->mbc_rom_bank++;
133 }
134 }
135 else {
136 gb->mbc_rom_bank = -1;
137 gb->mbc_rom0_bank = -2;
138 }
139 break;
140 case GB_HUC1:
141 gb->mbc_rom_bank = gb->huc1.bank_low;
142 gb->mbc_ram_bank = gb->huc1.bank_high;
143 break;
144 case GB_HUC3:
145 gb->mbc_rom_bank = gb->huc3.rom_bank;
146 gb->mbc_ram_bank = gb->huc3.ram_bank;
147 break;
148 case GB_TPP1:
149 gb->mbc_rom_bank = gb->tpp1.rom_bank;
150 gb->mbc_ram_bank = gb->tpp1.ram_bank;
151 gb->mbc_ram_enable = (gb->tpp1.mode == 2) || (gb->tpp1.mode == 3);
152 break;
153 nodefault;
154 }
155 }
156
157 void GB_configure_cart(GB_gameboy_t *gb)
158 {
159 memset(GB_GET_SECTION(gb, mbc), 0, GB_SECTION_SIZE(mbc));
160 gb->cartridge_type = &GB_cart_defs[gb->rom[0x147]];
161 if (gb->cartridge_type->mbc_type == GB_MMM01) {
162 uint8_t *temp = malloc(0x8000);
163 memcpy(temp, gb->rom, 0x8000);
164 memmove(gb->rom, gb->rom + 0x8000, gb->rom_size - 0x8000);
165 memcpy(gb->rom + gb->rom_size - 0x8000, temp, 0x8000);
166 free(temp);
167 }
168 else {
169 const GB_cartridge_t *maybe_mmm01_type = &GB_cart_defs[gb->rom[gb->rom_size - 0x8000 + 0x147]];
170 if (memcmp(gb->rom + 0x104, gb->rom + gb->rom_size - 0x8000 + 0x104, 0x30) == 0) {
171 if (maybe_mmm01_type->mbc_type == GB_MMM01) {
172 gb->cartridge_type = maybe_mmm01_type;
173 }
174 else if(gb->rom[gb->rom_size - 0x8000 + 0x147] == 0x11) {
175 GB_log(gb, "ROM header reports MBC3, but it appears to be an MMM01 ROM. Assuming cartridge uses MMM01.");
176 gb->cartridge_type = &GB_cart_defs[0xB];
177 }
178 }
179 }
180
181 if (gb->rom[0x147] == 0xBC &&
182 gb->rom[0x149] == 0xC1 &&
183 gb->rom[0x14A] == 0x65) {
184 static const GB_cartridge_t tpp1 = {GB_TPP1, true, true, true, true};
185 gb->cartridge_type = &tpp1;
186 gb->tpp1.rom_bank = 1;
187 }
188
189 if (gb->cartridge_type->mbc_type != GB_MMM01) {
190 if (gb->rom[0x147] == 0 && gb->rom_size > 0x8000) {
191 GB_log(gb, "ROM header reports no MBC, but file size is over 32Kb. Assuming cartridge uses MBC3.\n");
192 gb->cartridge_type = &GB_cart_defs[0x11];
193 }
194 else if (gb->rom[0x147] != 0 && memcmp(gb->cartridge_type, &GB_cart_defs[0], sizeof(GB_cart_defs[0])) == 0) {
195 GB_log(gb, "Cartridge type %02x is not yet supported.\n", gb->rom[0x147]);
196 }
197 }
198
199 if (!gb->cartridge_type->has_ram &&
200 gb->cartridge_type->mbc_type != GB_NO_MBC &&
201 gb->cartridge_type->mbc_type != GB_TPP1 &&
202 gb->rom[0x149]) {
203 GB_log(gb, "ROM header reports no RAM, but also reports a non-zero RAM size. Assuming cartridge has RAM.\n");
204 gb->cartridge_type++;
205 }
206
207 size_t old_mbc_ram_size = gb->mbc_ram_size;
208 gb->mbc_ram_size = 0;
209
210 if (gb->cartridge_type->has_ram) {
211 if (gb->cartridge_type->mbc_type == GB_MBC2) {
212 gb->mbc_ram_size = 0x200;
213 }
214 else if (gb->cartridge_type->mbc_type == GB_MBC7) {
215 gb->mbc_ram_size = 0x100;
216 }
217 else if (gb->cartridge_type->mbc_type == GB_TPP1) {
218 if (gb->rom[0x152] >= 1 && gb->rom[0x152] <= 9) {
219 gb->mbc_ram_size = 0x2000 << (gb->rom[0x152] - 1);
220 }
221 }
222 else {
223 static const unsigned ram_sizes[256] = {0, 0x800, 0x2000, 0x8000, 0x20000, 0x10000};
224 if (gb->cartridge_type->mbc_type == GB_MMM01) {
225 gb->mbc_ram_size = ram_sizes[gb->rom[gb->rom_size - 0x8000 + 0x149]];
226 }
227 else {
228 gb->mbc_ram_size = ram_sizes[gb->rom[0x149]];
229 }
230 }
231
232 if (gb->mbc_ram_size && gb->mbc_ram_size < 0x2000 &&
233 gb->cartridge_type->mbc_type != GB_MBC2 &&
234 gb->cartridge_type->mbc_type != GB_MBC7) {
235 GB_log(gb, "This ROM requests a RAM size smaller than a bank, it may misbehave if this was not done intentionally.\n");
236 }
237
238 if (gb->mbc_ram && old_mbc_ram_size != gb->mbc_ram_size) {
239 free(gb->mbc_ram);
240 gb->mbc_ram = NULL;
241 }
242
243 if (gb->mbc_ram_size && !gb->mbc_ram) {
244 gb->mbc_ram = malloc(gb->mbc_ram_size);
245 /* Todo: Some games assume unintialized MBC RAM is 0xFF. It this true for all cartridge types? */
246 memset(gb->mbc_ram, 0xFF, gb->mbc_ram_size);
247 }
248 }
249
250 /* MBC1 has at least 3 types of wiring (We currently support two (Standard and 4bit-MBC1M) of these).
251 See http://forums.nesdev.com/viewtopic.php?f=20&t=14099 */
252
253 /* Attempt to "guess" wiring */
254 if (gb->cartridge_type->mbc_type == GB_MBC1) {
255 if (gb->rom_size >= 0x44000 && memcmp(gb->rom + 0x104, gb->rom + 0x40104, 0x30) == 0) {
256 gb->mbc1_wiring = GB_MBC1M_WIRING;
257 }
258 }
259
260 /* Detect MBC30 */
261 if (gb->cartridge_type->mbc_type == GB_MBC3) {
262 if (gb->rom_size > 0x200000 || gb->mbc_ram_size > 0x8000) {
263 gb->is_mbc30 = true;
264 }
265 }
266
267 GB_reset_mbc(gb);
268 }
269
270 void GB_reset_mbc(GB_gameboy_t *gb)
271 {
272 gb->mbc_rom0_bank = 0;
273 if (gb->cartridge_type->mbc_type == GB_MMM01) {
274 gb->mbc_rom_bank = -1;
275 gb->mbc_rom0_bank = -2;
276 gb->mmm01.ram_bank_mask = -1;
277 }
278 else if (gb->cartridge_type->mbc_type == GB_MBC5 ||
279 gb->cartridge_type->mbc_type == GB_CAMERA) {
280 gb->mbc5.rom_bank_low = 1;
281 gb->mbc_rom_bank = 1;
282 }
283 else if (gb->cartridge_type->mbc_type == GB_MBC7) {
284 gb->mbc7.x_latch = gb->mbc7.y_latch = 0x8000;
285 gb->mbc7.latch_ready = true;
286 gb->mbc7.read_bits = -1;
287 gb->mbc7.eeprom_do = true;
288 }
289 else {
290 gb->mbc_rom_bank = 1;
291 }
292 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.