1use core::fmt::{Debug, Formatter};
2use serde::{Deserialize, Serialize};
3use crate::internal::memory::oam::ObjectAttributes;
4use crate::memory::Licensee::{NewLicensee, OldLicensee};
5
6#[derive(Copy, Clone)]
7pub struct OAMObject {
8 pub lcd_y: u8,
9 pub lcd_x: u8,
10 pub tile_index: u8,
11 pub attributes: ObjectAttributes,
12}
13
14#[derive(Copy, Clone)]
15pub enum ROMSize {
16 KB32,
17 KB64,
18 KB128,
19 KB256,
20 KB512,
21 MB1,
22 MB2,
23 MB4,
24 MB8,
25}
26
27pub enum Licensee {
28 OldLicensee(u8),
29 NewLicensee(char, char),
30}
31
32impl Licensee {
33 pub fn from_bytes(rom_bytes: &[u8]) -> Self {
34 let licensee_code = rom_bytes[0x14B];
35 if licensee_code == 0x33 {
36 NewLicensee(
37 rom_bytes[0x0144] as char,
38 rom_bytes[0x0145] as char,
39 )
40 } else {
41 OldLicensee(licensee_code)
42 }
43 }
44
45 pub fn is_licensed_by_nintendo(&self) -> bool {
46 match self {
47 OldLicensee(code) => *code == 0x01,
48 NewLicensee(upper, lower) => *upper == '0' && *lower == '1'
49 }
50 }
51
52 pub fn get_name(&self) -> String {
53 let name = match self {
54 OldLicensee(code) => match *code {
55 0x00 => "None",
56 0x01 => "Nintendo",
57 0x08 => "Capcom",
58 0x09 => "Hot-B",
59 0x0A => "Jaleco",
60 0x0B => "Coconuts Japan",
61 0x0C => "Elite Systems",
62 0x13 => "EA (Electronic Arts)",
63 0x18 => "Hudsonsoft",
64 0x19 => "ITC Entertainment",
65 0x1A => "Yanoman",
66 0x1D => "Japan Clary",
67 0x1F => "Virgin Interactive",
68 0x24 => "PCM Complete",
69 0x25 => "San-X",
70 0x28 => "Kotobuki Systems",
71 0x29 => "Seta",
72 0x30 => "Infogrames",
73 0x31 => "Nintendo",
74 0x32 => "Bandai",
75 0x34 => "Konami",
76 0x35 => "HectorSoft",
77 0x38 => "Capcom",
78 0x39 => "Banpresto",
79 0x3C => ".Entertainment i",
80 0x3E => "Gremlin",
81 0x41 => "Ubisoft",
82 0x42 => "Atlus",
83 0x44 => "Malibu",
84 0x46 => "Angel",
85 0x47 => "Spectrum Holoby",
86 0x49 => "Irem",
87 0x4A => "Virgin Interactive",
88 0x4D => "Malibu",
89 0x4F => "U.S. Gold",
90 0x50 => "Absolute",
91 0x51 => "Acclaim",
92 0x52 => "Activision",
93 0x53 => "American Sammy",
94 0x54 => "GameTek",
95 0x55 => "Park Place",
96 0x56 => "LJN",
97 0x57 => "Matchbox",
98 0x59 => "Milton Bradley",
99 0x5A => "Mindscape",
100 0x5B => "Romstar",
101 0x5C => "Naxat Soft",
102 0x5D => "Tradewest",
103 0x60 => "Titus",
104 0x61 => "Virgin Interactive",
105 0x67 => "Ocean Interactive",
106 0x69 => "EA (Electronic Arts)",
107 0x6E => "Elite Systems",
108 0x6F => "Electro Brain",
109 0x70 => "Infogrames",
110 0x71 => "Interplay",
111 0x72 => "Broderbund",
112 0x73 => "Sculptered Soft",
113 0x75 => "The Sales Curve",
114 0x78 => "t.hq",
115 0x79 => "Accolade",
116 0x7A => "Triffix Entertainment",
117 0x7C => "Microprose",
118 0x7F => "Kemco",
119 0x80 => "Misawa Entertainment",
120 0x83 => "Lozc",
121 0x86 => "Tokuma Shoten Intermedia",
122 0x8B => "Bullet-Proof Software",
123 0x8C => "Vic Tokai",
124 0x8E => "Ape",
125 0x8F => "I’Max",
126 0x91 => "Chunsoft Co.",
127 0x92 => "Video System",
128 0x93 => "Tsubaraya Productions Co.",
129 0x95 => "Varie Corporation",
130 0x96 => "Yonezawa/S’Pal",
131 0x97 => "Kaneko",
132 0x99 => "Arc",
133 0x9A => "Nihon Bussan",
134 0x9B => "Tecmo",
135 0x9C => "Imagineer",
136 0x9D => "Banpresto",
137 0x9F => "Nova",
138 0xA1 => "Hori Electric",
139 0xA2 => "Bandai",
140 0xA4 => "Konami",
141 0xA6 => "Kawada",
142 0xA7 => "Takara",
143 0xA9 => "Technos Japan",
144 0xAA => "Broderbund",
145 0xAC => "Toei Animation",
146 0xAD => "Toho",
147 0xAF => "Namco",
148 0xB0 => "acclaim",
149 0xB1 => "ASCII or Nexsoft",
150 0xB2 => "Bandai",
151 0xB4 => "Square Enix",
152 0xB6 => "HAL Laboratory",
153 0xB7 => "SNK",
154 0xB9 => "Pony Canyon",
155 0xBA => "Culture Brain",
156 0xBB => "Sunsoft",
157 0xBD => "Sony Imagesoft",
158 0xBF => "Sammy",
159 0xC0 => "Taito",
160 0xC2 => "Kemco",
161 0xC3 => "Squaresoft",
162 0xC4 => "Tokuma Shoten Intermedia",
163 0xC5 => "Data East",
164 0xC6 => "Tonkinhouse",
165 0xC8 => "Koei",
166 0xC9 => "UFL",
167 0xCA => "Ultra",
168 0xCB => "Vap",
169 0xCC => "Use Corporation",
170 0xCD => "Meldac",
171 0xCE => ".Pony Canyon or",
172 0xCF => "Angel",
173 0xD0 => "Taito",
174 0xD1 => "Sofel",
175 0xD2 => "Quest",
176 0xD3 => "Sigma Enterprises",
177 0xD4 => "ASK Kodansha Co.",
178 0xD6 => "Naxat Soft",
179 0xD7 => "Copya System",
180 0xD9 => "Banpresto",
181 0xDA => "Tomy",
182 0xDB => "LJN",
183 0xDD => "NCS",
184 0xDE => "Human",
185 0xDF => "Altron",
186 0xE0 => "Jaleco",
187 0xE1 => "Towa Chiki",
188 0xE2 => "Yutaka",
189 0xE3 => "Varie",
190 0xE5 => "Epcoh",
191 0xE7 => "Athena",
192 0xE8 => "Asmik ACE Entertainment",
193 0xE9 => "Natsume",
194 0xEA => "King Records",
195 0xEB => "Atlus",
196 0xEC => "Epic/Sony Records",
197 0xEE => "IGS",
198 0xF0 => "A Wave",
199 0xF3 => "Extreme Entertainment",
200 0xFF => "LJN",
201 _ => "Unknown"
202 },
203 NewLicensee(upper, lower) => match (*upper, *lower) {
204 ('0', '0') => "None",
205 ('0', '1') => "Nintendo R&D1",
206 ('0', '8') => "Capcom",
207 ('1', '3') => "Electronic Arts",
208 ('1', '8') => "Hudson Soft",
209 ('1', '9') => "b-ai",
210 ('2', '0') => "kss",
211 ('2', '2') => "pow",
212 ('2', '4') => "PCM Complete",
213 ('2', '5') => "san-x",
214 ('2', '8') => "Kemco Japan",
215 ('2', '9') => "seta",
216 ('3', '0') => "Viacom",
217 ('3', '1') => "Nintendo",
218 ('3', '2') => "Bandai",
219 ('3', '3') => "Ocean/Acclaim",
220 ('3', '4') => "Konami",
221 ('3', '5') => "Hector",
222 ('3', '7') => "Taito",
223 ('3', '8') => "Hudson",
224 ('3', '9') => "Banpresto",
225 ('4', '1') => "Ubi Soft",
226 ('4', '2') => "Atlus",
227 ('4', '4') => "Malibu",
228 ('4', '6') => "angel",
229 ('4', '7') => "Bullet-Proof",
230 ('4', '9') => "irem",
231 ('5', '0') => "Absolute",
232 ('5', '1') => "Acclaim",
233 ('5', '2') => "Activision",
234 ('5', '3') => "American sammy",
235 ('5', '4') => "Konami",
236 ('5', '5') => "Hi tech entertainment",
237 ('5', '6') => "LJN",
238 ('5', '7') => "Matchbox",
239 ('5', '8') => "Mattel",
240 ('5', '9') => "Milton Bradley",
241 ('6', '0') => "Titus",
242 ('6', '1') => "Virgin",
243 ('6', '4') => "LucasArts",
244 ('6', '7') => "Ocean",
245 ('6', '9') => "Electronic Arts",
246 ('7', '0') => "Infogrames",
247 ('7', '1') => "Interplay",
248 ('7', '2') => "Broderbund",
249 ('7', '3') => "sculptured",
250 ('7', '5') => "sci",
251 ('7', '8') => "THQ",
252 ('7', '9') => "Accolade",
253 ('8', '0') => "misawa",
254 ('8', '3') => "lozc",
255 ('8', '6') => "Tokuma Shoten Intermedia",
256 ('8', '7') => "Tsukuda Original",
257 ('9', '1') => "Chunsoft",
258 ('9', '2') => "Video system",
259 ('9', '3') => "Ocean/Acclaim",
260 ('9', '5') => "Varie",
261 ('9', '6') => "Yonezawa/s’pal",
262 ('9', '7') => "Kaneko",
263 ('9', '9') => "Pack in soft",
264 ('9', 'H') => "Bottom Up",
265 ('A', '4') => "Konami (Yu-Gi-Oh!)",
266 _ => "Unknown"
267 }
268 };
269 String::from(name)
270 }
271}
272
273#[derive(Copy, Clone)]
274pub enum CartridgeType {
275 MBC,
276 MBC1,
277 MBC2,
278 MMM01,
279 MBC3,
280 MBC5,
281 MBC6,
282 MBC7,
283 PocketCamera,
284 Bandai,
285 HuC3,
286 HuC1,
287}
288
289impl CartridgeType {
290 pub fn from_byte(byte: u8) -> Self {
291 match byte {
292 0x00 => CartridgeType::MBC,
293 0x01..=0x03 => CartridgeType::MBC1,
294 0x05..=0x06 => CartridgeType::MBC2,
295 0x0B..=0x0D => CartridgeType::MMM01,
296 0x0F..=0x13 => CartridgeType::MBC3,
297 0x19..=0x1E => CartridgeType::MBC5,
298 0x20 => CartridgeType::MBC6,
299 0x22 => CartridgeType::MBC7,
300 0xFC => CartridgeType::PocketCamera,
301 0xFD => CartridgeType::Bandai,
302 0xFE => CartridgeType::HuC3,
303 0xFF => CartridgeType::HuC1,
304 _ => panic!("Unknown cartridge for byte {:#x}", byte)
305 }
306 }
307}
308
309impl Debug for CartridgeType {
310 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
311 match self {
312 CartridgeType::MBC => write!(f, "MBC"),
313 CartridgeType::MBC1 => write!(f, "MBC1"),
314 CartridgeType::MBC2 => write!(f, "MBC2"),
315 CartridgeType::MMM01 => write!(f, "MMM01"),
316 CartridgeType::MBC3 => write!(f, "MBC3"),
317 CartridgeType::MBC5 => write!(f, "MBC5"),
318 CartridgeType::MBC6 => write!(f, "MBC6"),
319 CartridgeType::MBC7 => write!(f, "MBC7"),
320 CartridgeType::PocketCamera => write!(f, "Pocket Camera"),
321 CartridgeType::Bandai => write!(f, "Bandai"),
322 CartridgeType::HuC3 => write!(f, "HuC3"),
323 CartridgeType::HuC1 => write!(f, "HuC1")
324 }
325 }
326}
327
328impl Debug for ROMSize {
329 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
330 match self {
331 ROMSize::KB32 => write!(f, "32 kB"),
332 ROMSize::KB64 => write!(f, "64 kB"),
333 ROMSize::KB128 => write!(f, "128 kB"),
334 ROMSize::KB256 => write!(f, "256 kB"),
335 ROMSize::KB512 => write!(f, "512 kB"),
336 ROMSize::MB1 => write!(f, "1 MB"),
337 ROMSize::MB2 => write!(f, "2 MB"),
338 ROMSize::MB4 => write!(f, "4 MB"),
339 ROMSize::MB8 => write!(f, "8 MB")
340 }
341 }
342}
343
344impl ROMSize {
345 pub fn from_byte(byte: u8) -> ROMSize {
346 match byte {
347 0x00 => ROMSize::KB32,
348 0x01 => ROMSize::KB64,
349 0x02 => ROMSize::KB128,
350 0x03 => ROMSize::KB256,
351 0x04 => ROMSize::KB512,
352 0x05 => ROMSize::MB1,
353 0x06 => ROMSize::MB2,
354 0x07 => ROMSize::MB4,
355 0x08 => ROMSize::MB8,
356 _ => panic!("Byte {} does not correspond to any known ROM size", byte)
357 }
358 }
359
360 pub fn bytes(&self) -> usize {
361 match self {
362 ROMSize::KB32 => 0x8000,
363 ROMSize::KB64 => 0x10000,
364 ROMSize::KB128 => 0x20000,
365 ROMSize::KB256 => 0x40000,
366 ROMSize::KB512 => 0x80000,
367 ROMSize::MB1 => 0x100000,
368 ROMSize::MB2 => 0x200000,
369 ROMSize::MB4 => 0x400000,
370 ROMSize::MB8 => 0x800000
371 }
372 }
373}
374
375#[derive(Copy, Clone)]
376pub enum RAMSize {
377 Unavailable,
378 KB8,
379 KB32,
380 KB64,
381 KB128,
382}
383
384impl Debug for RAMSize {
385 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
386 match self {
387 RAMSize::Unavailable => write!(f, "Unavailable"),
388 RAMSize::KB8 => write!(f, "8 kB"),
389 RAMSize::KB32 => write!(f, "32 kB"),
390 RAMSize::KB64 => write!(f, "64 kB"),
391 RAMSize::KB128 => write!(f, "128 kB"),
392 }
393 }
394}
395
396impl RAMSize {
397 pub fn from_byte(byte: u8) -> RAMSize {
398 match byte {
399 0x00 => RAMSize::Unavailable,
400 0x01 => RAMSize::Unavailable,
401 0x02 => RAMSize::KB8,
402 0x03 => RAMSize::KB32,
403 0x04 => RAMSize::KB128,
404 0x05 => RAMSize::KB64,
405 _ => panic!("Byte {} does not correspond to any known RAM size", byte)
406 }
407 }
408
409 pub fn bytes(&self) -> usize {
410 match self {
411 RAMSize::Unavailable => 0,
412 RAMSize::KB8 => 0x8000,
413 RAMSize::KB32 => 0x8000,
414 RAMSize::KB64 => 0x10000,
415 RAMSize::KB128 => 0x20000,
416 }
417 }
418}
419
420#[derive(Copy, Clone, Serialize, Deserialize)]
421pub enum CGBMode {
422 Monochrome,
423 Color,
424 PGB,
425}
426
427impl CGBMode {
428 pub fn from_byte(byte: u8) -> CGBMode {
429 match byte & 0xBF {
430 0x80 => CGBMode::Color,
431 0x82 => CGBMode::PGB,
432 0x84 => CGBMode::PGB,
433 _ => CGBMode::Monochrome
434 }
435 }
436}
437
438impl Debug for CGBMode {
439 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
440 match self {
441 CGBMode::Monochrome => write!(f, "Monochrome"),
442 CGBMode::Color => write!(f, "Color"),
443 CGBMode::PGB => write!(f, "PGB")
444 }
445 }
446}