GameBoy Emulator 1
Game Boy emulator core and tooling
Loading...
Searching...
No Matches
cartridge.cpp
1#include "../../include/cartridge.hpp"
2#include <cstring>
3#include <stdexcept>
4#include <algorithm>
5
6Cartridge::Cartridge() {
7 rom.clear();
8 ram.resize(32768, 0);
9 ram_enabled = true;
10 std::memset(&header, 0, sizeof(header));
11 title = "";
12}
13
14Cartridge::Cartridge(const std::vector<u8>& rom_data) {
15 load_rom(rom_data);
16}
17
18bool Cartridge::load_rom(const std::vector<u8>& rom_data) {
19 if (rom_data.empty()) {
20 return false;
21 }
22
23 rom = rom_data;
24 mbc_type = MBCType::None;
25
26 if (rom.size() >= 0x150) {
27 std::memcpy(&header, &rom[0x100], sizeof(rom_header));
28
29 // Safely copy the title
30 char title_buf[17]{};
31 std::memcpy(title_buf, header.title, 16);
32 title = title_buf;
33
34 // Determine MBC type
35 u8 type = header.type;
36 if (type >= 0x01 && type <= 0x03) {
37 mbc_type = MBCType::MBC1;
38 } else if (type >= 0x0F && type <= 0x13) {
39 mbc_type = MBCType::MBC3;
40 } else if (type >= 0x19 && type <= 0x1E) {
41 mbc_type = MBCType::MBC5;
42 }
43
44 // Calculate RAM size based on header code
45 u32 ram_size_bytes = 0;
46 switch (header.ram_size) {
47 case 1: ram_size_bytes = 2048; break; // 2KB
48 case 2: ram_size_bytes = 8192; break; // 8KB
49 case 3: ram_size_bytes = 32768; break; // 32KB
50 case 4: ram_size_bytes = 131072; break; // 128KB
51 case 5: ram_size_bytes = 65536; break; // 64KB
52 default: ram_size_bytes = 0; break;
53 }
54
55 if (ram_size_bytes > 0) {
56 ram.resize(ram_size_bytes, 0);
57 } else {
58 ram.clear();
59 }
60 } else {
61 std::memset(&header, 0, sizeof(rom_header));
62 title = "Test ROM";
63 ram.clear();
64 }
65
66 current_rom_bank = 1;
67 current_ram_bank = 0;
68 ram_enabled = false;
69 banking_mode = 0;
70 rom_bank_low = 1;
71 rom_bank_high = 0;
72 return true;
73}
74
75u8 Cartridge::read(u16 address) const {
76 if (address <= 0x3FFF) {
77 if (mbc_type == MBCType::MBC1 && banking_mode == 1) {
78 u32 bank = (rom_bank_high << 5);
79 u32 address_in_rom = (bank * 0x4000) + address;
80 if (address_in_rom < rom.size()) return rom[address_in_rom];
81 }
82 if (address < rom.size()) return rom[address];
83 return 0x00;
84 }
85 if (address >= 0x4000 && address <= 0x7FFF) {
86 u32 bank = current_rom_bank;
87 u32 address_in_rom = (address - 0x4000) + (bank * 0x4000);
88 if (address_in_rom < rom.size()) return rom[address_in_rom];
89 return 0x00;
90 }
91 if (address >= 0xA000 && address <= 0xBFFF) {
92 if (ram_enabled && !ram.empty()) {
93 u8 ram_bank = 0;
94 if (mbc_type == MBCType::MBC1 && banking_mode == 1) {
95 ram_bank = current_ram_bank;
96 } else if (mbc_type == MBCType::MBC3 || mbc_type == MBCType::MBC5) {
97 ram_bank = current_ram_bank;
98 }
99 u32 ram_address = (ram_bank * 0x2000) + (address - 0xA000);
100 if (ram_address < ram.size()) return ram[ram_address];
101 }
102 return 0xFF;
103 }
104 return 0xFF;
105}
106
107void Cartridge::write(u16 address, u8 value) {
108 // RAM Enable (0x0000 - 0x1FFF)
109 if (address <= 0x1FFF) {
110 if (mbc_type != MBCType::None) {
111 ram_enabled = ((value & 0x0F) == 0x0A);
112 }
113 return;
114 }
115 // ROM Bank Number (0x2000 - 0x3FFF)
116 if (address >= 0x2000 && address <= 0x3FFF) {
117 if (mbc_type == MBCType::MBC1) {
118 rom_bank_low = value & 0x1F;
119 if (rom_bank_low == 0) rom_bank_low = 1;
120 current_rom_bank = (rom_bank_high << 5) | rom_bank_low;
121 } else if (mbc_type == MBCType::MBC3) {
122 current_rom_bank = value & 0x7F;
123 if (current_rom_bank == 0) current_rom_bank = 1;
124 } else if (mbc_type == MBCType::MBC5) {
125 if (address <= 0x2FFF) {
126 rom_bank_low = value;
127 } else {
128 rom_bank_high = value & 0x01;
129 }
130 current_rom_bank = (rom_bank_high << 8) | rom_bank_low;
131 }
132 return;
133 }
134 // RAM Bank Number / ROM Bank Extension (0x4000 - 0x5FFF)
135 if (address >= 0x4000 && address <= 0x5FFF) {
136 if (mbc_type == MBCType::MBC1) {
137 rom_bank_high = value & 0x03;
138 current_ram_bank = value & 0x03;
139 current_rom_bank = (rom_bank_high << 5) | rom_bank_low;
140 } else if (mbc_type == MBCType::MBC3) {
141 current_ram_bank = value & 0x0F;
142 } else if (mbc_type == MBCType::MBC5) {
143 current_ram_bank = value & 0x0F;
144 }
145 return;
146 }
147 // Banking Mode Select (0x6000 - 0x7FFF)
148 if (address >= 0x6000 && address <= 0x7FFF) {
149 if (mbc_type == MBCType::MBC1) {
150 banking_mode = value & 0x01;
151 }
152 return;
153 }
154 // External RAM (0xA000 - 0xBFFF)
155 if (address >= 0xA000 && address <= 0xBFFF) {
156 if (ram_enabled && !ram.empty()) {
157 u8 ram_bank = 0;
158 if (mbc_type == MBCType::MBC1 && banking_mode == 1) {
159 ram_bank = current_ram_bank;
160 } else if (mbc_type == MBCType::MBC3 || mbc_type == MBCType::MBC5) {
161 ram_bank = current_ram_bank;
162 }
163 u32 ram_address = (ram_bank * 0x2000) + (address - 0xA000);
164 if (ram_address < ram.size()) ram[ram_address] = value;
165 }
166 }
167}
168
169void Cartridge::reset() {
170 current_rom_bank = 1;
171 current_ram_bank = 0;
172 ram_enabled = false;
173 banking_mode = 0;
174 rom_bank_low = 1;
175 rom_bank_high = 0;
176 if (!ram.empty()) {
177 std::fill(ram.begin(), ram.end(), 0);
178 }
179}