Gambatte: Some Trace/Disassemble fixes
[lsnes.git] / src / emulation / gambatte / core.cpp
blob438d85bfcdc88738ab6439975adf8575eeb306d2
1 /***************************************************************************
2 * Copyright (C) 2012-2013 by Ilari Liusvaara *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License version 2 as *
6 * published by the Free Software Foundation. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11 * GNU General Public License version 2 for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License *
14 * version 2 along with this program; if not, write to the *
15 * Free Software Foundation, Inc., *
16 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
17 ***************************************************************************/
18 #include "lsnes.hpp"
19 #include <sstream>
20 #include <iostream>
21 #include <map>
22 #include <string>
23 #include <vector>
24 #include "disassemble-gb.hpp"
25 #include "core/audioapi.hpp"
26 #include "core/misc.hpp"
27 #include "core/command.hpp"
28 #include "core/controllerframe.hpp"
29 #include "core/dispatch.hpp"
30 #include "core/settings.hpp"
31 #include "core/framebuffer.hpp"
32 #include "core/window.hpp"
33 #include "interface/callbacks.hpp"
34 #include "interface/cover.hpp"
35 #include "interface/romtype.hpp"
36 #include "library/framebuffer-pixfmt-rgb32.hpp"
37 #include "library/hex.hpp"
38 #include "library/string.hpp"
39 #include "library/controller-data.hpp"
40 #include "library/serialization.hpp"
41 #include "library/minmax.hpp"
42 #include "library/framebuffer.hpp"
43 #define HAVE_CSTDINT
44 #include "libgambatte/include/gambatte.h"
46 #define SAMPLES_PER_FRAME 35112
48 namespace
50 settingvar::variable<settingvar::model_bool<settingvar::yes_no>> output_native(lsnes_vset,
51 "gambatte-native-sound", "Gambatteā€£Sound Output at native rate", false);
53 bool do_reset_flag = false;
54 core_type* internal_rom = NULL;
55 bool rtc_fixed;
56 time_t rtc_fixed_val;
57 gambatte::GB* instance;
58 bool reallocate_debug = false;
59 bool sigillcrash = false;
60 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
61 gambatte::debugbuffer debugbuf;
62 size_t cur_romsize;
63 size_t cur_ramsize;
64 #endif
65 unsigned frame_overflow = 0;
66 std::vector<unsigned char> romdata;
67 uint32_t cover_fbmem[480 * 432];
68 uint32_t primary_framebuffer[160*144];
69 uint32_t accumulator_l = 0;
70 uint32_t accumulator_r = 0;
71 unsigned accumulator_s = 0;
72 bool pflag = false;
73 bool disable_breakpoints = false;
74 bool palette_colors_default[3] = {true, true, true};
75 uint32_t palette_colors[12];
77 struct interface_device_reg gb_registers[] = {
78 {"wrambank", []() -> uint64_t { return instance ? instance->getIoRam().first[0x170] & 0x07 : 0; },
79 [](uint64_t v) {}},
80 {"cyclecount", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_CYCLECOUNTER); },
81 [](uint64_t v) {}},
82 {"pc", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_PC); },
83 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_PC, v); }},
84 {"sp", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_SP); },
85 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_SP, v); }},
86 {"hf1", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_HF1); },
87 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_HF1, v); }},
88 {"hf2", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_HF2); },
89 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_HF2, v); }},
90 {"zf", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_ZF); },
91 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_ZF, v); }},
92 {"cf", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_CF); },
93 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_CF, v); }},
94 {"a", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_A); },
95 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_A, v); }},
96 {"b", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_B); },
97 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_B, v); }},
98 {"c", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_C); },
99 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_C, v); }},
100 {"d", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_D); },
101 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_D, v); }},
102 {"e", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_E); },
103 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_E, v); }},
104 {"f", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_F); },
105 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_F, v); }},
106 {"h", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_H); },
107 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_H, v); }},
108 {"l", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_L); },
109 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_L, v); }},
110 {NULL, NULL, NULL}
113 //Framebuffer.
114 struct framebuffer::info cover_fbinfo = {
115 &framebuffer::pixfmt_rgb32, //Format.
116 (char*)cover_fbmem, //Memory.
117 480, 432, 1920, //Physical size.
118 480, 432, 1920, //Logical size.
119 0, 0 //Offset.
122 #include "ports.inc"
124 time_t walltime_fn()
126 if(rtc_fixed)
127 return rtc_fixed_val;
128 if(ecore_callbacks)
129 return ecore_callbacks->get_time();
130 else
131 return time(0);
134 class myinput : public gambatte::InputGetter
136 public:
137 unsigned operator()()
139 unsigned v = 0;
140 for(unsigned i = 0; i < 8; i++) {
141 if(ecore_callbacks->get_input(0, 1, i))
142 v |= (1 << i);
144 pflag = true;
145 return v;
147 } getinput;
149 uint64_t get_address(unsigned clazz, unsigned offset)
151 switch(clazz) {
152 case 0: return 0x1000000 + offset; //BUS.
153 case 1: return offset; //WRAM.
154 case 2: return 0x18000 + offset; //IOAMHRAM
155 case 3: return 0x80000000 + offset; //ROM
156 case 4: return 0x20000 + offset; //SRAM.
158 return 0xFFFFFFFFFFFFFFFF;
161 void gambatte_read_handler(unsigned clazz, unsigned offset, uint8_t value, bool exec)
163 if(disable_breakpoints) return;
164 uint64_t _addr = get_address(clazz, offset);
165 if(_addr != 0xFFFFFFFFFFFFFFFFULL) {
166 if(exec)
167 ecore_callbacks->memory_execute(_addr, 0);
168 else
169 ecore_callbacks->memory_read(_addr, value);
173 void gambatte_write_handler(unsigned clazz, unsigned offset, uint8_t value)
175 if(disable_breakpoints) return;
176 uint64_t _addr = get_address(clazz, offset);
177 if(_addr != 0xFFFFFFFFFFFFFFFFULL)
178 ecore_callbacks->memory_write(_addr, value);
181 int get_hl(gambatte::GB* instance)
183 return instance->get_cpureg(gambatte::GB::REG_H) * 256 +
184 instance->get_cpureg(gambatte::GB::REG_L);
187 int get_bc(gambatte::GB* instance)
189 return instance->get_cpureg(gambatte::GB::REG_B) * 256 +
190 instance->get_cpureg(gambatte::GB::REG_C);
193 int get_de(gambatte::GB* instance)
195 return instance->get_cpureg(gambatte::GB::REG_D) * 256 +
196 instance->get_cpureg(gambatte::GB::REG_E);
199 //0 => None or already done.
200 //1 => BC
201 //2 => DE
202 //3 => HL
203 //4 => 0xFF00 + C.
204 //5 => Bitops
205 int memclass[] = {
206 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
207 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //0
208 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, //1
209 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, //2
210 0, 0, 3, 0, 3, 3, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, //3
211 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //4
212 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //5
213 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //6
214 3, 3, 3, 3, 3, 3, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, //7
215 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //8
216 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //9
217 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //A
218 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //B
219 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, //C
220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //D
221 0, 0, 4, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, //E
222 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //F.
225 const char* hexch = "0123456789abcdef";
226 inline void buffer_h8(char*& ptr, uint8_t v)
228 *(ptr++) = hexch[v >> 4];
229 *(ptr++) = hexch[v & 15];
232 inline void buffer_h16(char*& ptr, uint16_t v)
234 *(ptr++) = hexch[v >> 12];
235 *(ptr++) = hexch[(v >> 8) & 15];
236 *(ptr++) = hexch[(v >> 4) & 15];
237 *(ptr++) = hexch[v & 15];
240 inline void buffer_str(char*& ptr, const char* str)
242 while(*str)
243 *(ptr++) = *(str++);
246 void gambatte_trace_handler(uint16_t _pc)
248 static char buffer[512];
249 char* buffer_ptr = buffer;
250 int addr = -1;
251 uint16_t opcode;
252 uint32_t pc = _pc;
253 uint16_t offset = 0;
254 std::function<uint8_t()> fetch = [pc, &offset, &buffer_ptr]() -> uint8_t {
255 unsigned addr = pc + offset++;
256 uint8_t v;
257 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
258 disable_breakpoints = true;
259 v = instance->bus_read(addr);
260 disable_breakpoints = true;
261 #endif
262 buffer_h8(buffer_ptr, v);
263 return v;
265 buffer_h16(buffer_ptr, pc);
266 *(buffer_ptr++) = ' ';
267 auto d = disassemble_gb_opcode(pc, fetch, addr, opcode);
268 while(buffer_ptr < buffer + 12)
269 *(buffer_ptr++) = ' ';
270 buffer_str(buffer_ptr, d.c_str());
271 switch(memclass[opcode >> 8]) {
272 case 1: addr = get_bc(instance); break;
273 case 2: addr = get_de(instance); break;
274 case 3: addr = get_hl(instance); break;
275 case 4: addr = 0xFF00 + instance->get_cpureg(gambatte::GB::REG_C); break;
276 case 5: if((opcode & 7) == 6) addr = get_hl(instance); break;
278 while(buffer_ptr < buffer + 28)
279 *(buffer_ptr++) = ' ';
280 if(addr >= 0) {
281 buffer_str(buffer_ptr, "[");
282 buffer_h16(buffer_ptr, addr);
283 buffer_str(buffer_ptr, "]");
284 } else
285 buffer_str(buffer_ptr, " ");
287 buffer_str(buffer_ptr, "A:");
288 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_A));
289 buffer_str(buffer_ptr, " B:");
290 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_B));
291 buffer_str(buffer_ptr, " C:");
292 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_C));
293 buffer_str(buffer_ptr, " D:");
294 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_D));
295 buffer_str(buffer_ptr, " E:");
296 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_E));
297 buffer_str(buffer_ptr, " H:");
298 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_H));
299 buffer_str(buffer_ptr, " L:");
300 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_L));
301 buffer_str(buffer_ptr, " SP:");
302 buffer_h16(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_SP));
303 buffer_str(buffer_ptr, " F:");
304 *(buffer_ptr++) = instance->get_cpureg(gambatte::GB::REG_CF) ? 'C' : '-';
305 *(buffer_ptr++) = instance->get_cpureg(gambatte::GB::REG_ZF) ? '-' : 'Z';
306 *(buffer_ptr++) = instance->get_cpureg(gambatte::GB::REG_HF1) ? '1' : '-';
307 *(buffer_ptr++) = instance->get_cpureg(gambatte::GB::REG_HF2) ? '2' : '-';
308 *(buffer_ptr++) = '\0';
309 ecore_callbacks->memory_trace(0, buffer);
312 void basic_init()
314 static bool done = false;
315 if(done)
316 return;
317 done = true;
318 instance = new gambatte::GB;
319 instance->setInputGetter(&getinput);
320 instance->set_walltime_fn(walltime_fn);
321 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
322 uint8_t* tmp = new uint8_t[98816];
323 memset(tmp, 0, 98816);
324 debugbuf.wram = tmp;
325 debugbuf.bus = tmp + 32768;
326 debugbuf.ioamhram = tmp + 98304;
327 debugbuf.read = gambatte_read_handler;
328 debugbuf.write = gambatte_write_handler;
329 debugbuf.trace = gambatte_trace_handler;
330 debugbuf.trace_cpu = false;
331 instance->set_debug_buffer(debugbuf);
332 #endif
335 int load_rom_common(core_romimage* img, unsigned flags, uint64_t rtc_sec, uint64_t rtc_subsec,
336 core_type* inttype, std::map<std::string, std::string>& settings)
338 basic_init();
339 const char* markup = img[0].markup;
340 int flags2 = 0;
341 if(markup) {
342 flags2 = atoi(markup);
343 flags2 &= 4;
345 flags |= flags2;
346 const unsigned char* data = img[0].data;
347 size_t size = img[0].size;
349 //Reset it really.
350 instance->~GB();
351 memset(instance, 0, sizeof(gambatte::GB));
352 new(instance) gambatte::GB;
353 instance->setInputGetter(&getinput);
354 instance->set_walltime_fn(walltime_fn);
355 memset(primary_framebuffer, 0, sizeof(primary_framebuffer));
356 frame_overflow = 0;
358 rtc_fixed = true;
359 rtc_fixed_val = rtc_sec;
360 instance->load(data, size, flags);
361 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
362 size_t sramsize = instance->getSaveRam().second;
363 size_t romsize = size;
364 if(reallocate_debug || cur_ramsize != sramsize || cur_romsize != romsize) {
365 if(debugbuf.cart) delete[] debugbuf.cart;
366 if(debugbuf.sram) delete[] debugbuf.sram;
367 debugbuf.cart = NULL;
368 debugbuf.sram = NULL;
369 if(sramsize) debugbuf.sram = new uint8_t[(sramsize + 4095) >> 12 << 12];
370 if(romsize) debugbuf.cart = new uint8_t[(romsize + 4095) >> 12 << 12];
371 if(sramsize) memset(debugbuf.sram, 0, (sramsize + 4095) >> 12 << 12);
372 if(romsize) memset(debugbuf.cart, 0, (romsize + 4095) >> 12 << 12);
373 memset(debugbuf.wram, 0, 32768);
374 memset(debugbuf.ioamhram, 0, 512);
375 debugbuf.wramcheat.clear();
376 debugbuf.sramcheat.clear();
377 debugbuf.cartcheat.clear();
378 debugbuf.trace_cpu = false;
379 reallocate_debug = false;
380 cur_ramsize = sramsize;
381 cur_romsize = romsize;
383 instance->set_debug_buffer(debugbuf);
384 #endif
385 sigillcrash = false;
386 #ifdef GAMBATTE_SUPPORTS_EMU_FLAGS
387 unsigned emuflags = 0;
388 if(settings.count("sigillcrash") && settings["sigillcrash"] == "1")
389 emuflags |= 1;
390 sigillcrash = (emuflags & 1);
391 instance->set_emuflags(emuflags);
392 #endif
393 rtc_fixed = false;
394 romdata.resize(size);
395 memcpy(&romdata[0], data, size);
396 internal_rom = inttype;
397 do_reset_flag = false;
399 for(unsigned i = 0; i < 12; i++)
400 if(!palette_colors_default[i >> 2])
401 instance->setDmgPaletteColor(i >> 2, i & 3, palette_colors[i]);
403 return 1;
406 controller_set gambatte_controllerconfig(std::map<std::string, std::string>& settings)
408 std::map<std::string, std::string> _settings = settings;
409 controller_set r;
410 r.ports.push_back(&psystem);
411 r.logical_map.push_back(std::make_pair(0, 1));
412 return r;
415 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
416 uint8_t gambatte_bus_iospace_rw(uint64_t offset, uint8_t data, bool write)
418 uint8_t val = 0;
419 disable_breakpoints = true;
420 if(write)
421 instance->bus_write(offset, data);
422 else
423 val = instance->bus_read(offset);
424 disable_breakpoints = false;
425 return val;
427 #endif
429 std::list<core_vma_info> get_VMAlist()
431 std::list<core_vma_info> vmas;
432 if(!internal_rom)
433 return vmas;
434 core_vma_info sram;
435 core_vma_info wram;
436 core_vma_info vram;
437 core_vma_info ioamhram;
438 core_vma_info rom;
439 core_vma_info bus;
441 auto g = instance->getSaveRam();
442 sram.name = "SRAM";
443 sram.base = 0x20000;
444 sram.size = g.second;
445 sram.backing_ram = g.first;
446 sram.endian = -1;
448 auto g2 = instance->getWorkRam();
449 wram.name = "WRAM";
450 wram.base = 0;
451 wram.size = g2.second;
452 wram.backing_ram = g2.first;
453 wram.endian = -1;
455 auto g3 = instance->getVideoRam();
456 vram.name = "VRAM";
457 vram.base = 0x10000;
458 vram.size = g3.second;
459 vram.backing_ram = g3.first;
460 vram.endian = -1;
462 auto g4 = instance->getIoRam();
463 ioamhram.name = "IOAMHRAM";
464 ioamhram.base = 0x18000;
465 ioamhram.size = g4.second;
466 ioamhram.backing_ram = g4.first;
467 ioamhram.endian = -1;
469 rom.name = "ROM";
470 rom.base = 0x80000000;
471 rom.size = romdata.size();
472 rom.backing_ram = (void*)&romdata[0];
473 rom.endian = -1;
474 rom.readonly = true;
476 if(sram.size)
477 vmas.push_back(sram);
478 vmas.push_back(wram);
479 vmas.push_back(rom);
480 vmas.push_back(vram);
481 vmas.push_back(ioamhram);
482 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
483 bus.name = "BUS";
484 bus.base = 0x1000000;
485 bus.size = 0x10000;
486 bus.iospace_rw = gambatte_bus_iospace_rw;
487 bus.endian = -1;
488 vmas.push_back(bus);
489 #endif
490 return vmas;
493 std::set<std::string> gambatte_srams()
495 std::set<std::string> s;
496 if(!internal_rom)
497 return s;
498 auto g = instance->getSaveRam();
499 if(g.second)
500 s.insert("main");
501 s.insert("rtc");
502 return s;
505 std::string get_cartridge_name()
507 std::ostringstream name;
508 if(romdata.size() < 0x200)
509 return ""; //Bad.
510 for(unsigned i = 0; i < 16; i++) {
511 if(romdata[0x134 + i])
512 name << (char)romdata[0x134 + i];
513 else
514 break;
516 return name.str();
519 void redraw_cover_fbinfo();
521 struct _gambatte_core : public core_core, public core_region
523 _gambatte_core()
524 : core_core({&psystem}, {
525 {0, "Soft reset", "reset", {}},
526 {1, "Change BG palette", "bgpalette", {
527 {"Color 0","string:[0-9A-Fa-f]{6}"},
528 {"Color 1","string:[0-9A-Fa-f]{6}"},
529 {"Color 2","string:[0-9A-Fa-f]{6}"},
530 {"Color 3","string:[0-9A-Fa-f]{6}"}
531 }},{2, "Change SP1 palette", "sp1palette", {
532 {"Color 0","string:[0-9A-Fa-f]{6}"},
533 {"Color 1","string:[0-9A-Fa-f]{6}"},
534 {"Color 2","string:[0-9A-Fa-f]{6}"},
535 {"Color 3","string:[0-9A-Fa-f]{6}"}
536 }}, {3, "Change SP2 palette", "sp2palette", {
537 {"Color 0","string:[0-9A-Fa-f]{6}"},
538 {"Color 1","string:[0-9A-Fa-f]{6}"},
539 {"Color 2","string:[0-9A-Fa-f]{6}"},
540 {"Color 3","string:[0-9A-Fa-f]{6}"}
543 core_region({{"world", "World", 0, 0, false, {4389, 262144}, {0}}}) {}
545 std::string c_core_identifier() { return "libgambatte "+gambatte::GB::version(); }
546 bool c_set_region(core_region& region) { return (&region == this); }
547 std::pair<uint32_t, uint32_t> c_video_rate() { return std::make_pair(262144, 4389); }
548 double c_get_PAR() { return 1.0; }
549 std::pair<uint32_t, uint32_t> c_audio_rate() {
550 if(output_native)
551 return std::make_pair(2097152, 1);
552 else
553 return std::make_pair(32768, 1);
555 std::map<std::string, std::vector<char>> c_save_sram() throw(std::bad_alloc) {
556 std::map<std::string, std::vector<char>> s;
557 if(!internal_rom)
558 return s;
559 auto g = instance->getSaveRam();
560 s["main"].resize(g.second);
561 memcpy(&s["main"][0], g.first, g.second);
562 s["rtc"].resize(8);
563 time_t timebase = instance->getRtcBase();
564 for(size_t i = 0; i < 8; i++)
565 s["rtc"][i] = ((unsigned long long)timebase >> (8 * i));
566 return s;
568 void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc) {
569 if(!internal_rom)
570 return;
571 std::vector<char> x = sram.count("main") ? sram["main"] : std::vector<char>();
572 std::vector<char> x2 = sram.count("rtc") ? sram["rtc"] : std::vector<char>();
573 auto g = instance->getSaveRam();
574 if(x.size()) {
575 if(x.size() != g.second)
576 messages << "WARNING: SRAM 'main': Loaded " << x.size()
577 << " bytes, but the SRAM is " << g.second << "." << std::endl;
578 memcpy(g.first, &x[0], min(x.size(), g.second));
580 if(x2.size()) {
581 time_t timebase = 0;
582 for(size_t i = 0; i < 8 && i < x2.size(); i++)
583 timebase |= (unsigned long long)(unsigned char)x2[i] << (8 * i);
584 instance->setRtcBase(timebase);
587 void c_serialize(std::vector<char>& out) {
588 if(!internal_rom)
589 throw std::runtime_error("Can't save without ROM");
590 instance->saveState(out);
591 size_t osize = out.size();
592 out.resize(osize + 4 * sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]));
593 for(size_t i = 0; i < sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]); i++)
594 serialization::u32b(&out[osize + 4 * i], primary_framebuffer[i]);
595 out.push_back(frame_overflow >> 8);
596 out.push_back(frame_overflow);
598 void c_unserialize(const char* in, size_t insize) {
599 if(!internal_rom)
600 throw std::runtime_error("Can't load without ROM");
601 size_t foffset = insize - 2 - 4 * sizeof(primary_framebuffer) /
602 sizeof(primary_framebuffer[0]);
603 std::vector<char> tmp;
604 tmp.resize(foffset);
605 memcpy(&tmp[0], in, foffset);
606 instance->loadState(tmp);
607 for(size_t i = 0; i < sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]); i++)
608 primary_framebuffer[i] = serialization::u32b(&in[foffset + 4 * i]);
610 unsigned x1 = (unsigned char)in[insize - 2];
611 unsigned x2 = (unsigned char)in[insize - 1];
612 frame_overflow = x1 * 256 + x2;
613 do_reset_flag = false;
615 core_region& c_get_region() { return *this; }
616 void c_power() {}
617 void c_unload_cartridge() {}
618 std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
619 return std::make_pair(max(512 / width, (uint32_t)1), max(448 / height, (uint32_t)1));
621 void c_install_handler() { magic_flags |= 2; }
622 void c_uninstall_handler() {}
623 void c_emulate() {
624 if(!internal_rom)
625 return;
626 bool native_rate = output_native;
627 int16_t reset = ecore_callbacks->get_input(0, 0, 1);
628 if(reset) {
629 instance->reset();
630 messages << "GB(C) reset" << std::endl;
632 do_reset_flag = false;
634 uint32_t samplebuffer[SAMPLES_PER_FRAME + 2064];
635 int16_t soundbuf[2 * (SAMPLES_PER_FRAME + 2064)];
636 size_t emitted = 0;
637 while(true) {
638 unsigned samples_emitted = SAMPLES_PER_FRAME - frame_overflow;
639 long ret = instance->runFor(primary_framebuffer, 160, samplebuffer, samples_emitted);
640 if(native_rate)
641 for(unsigned i = 0; i < samples_emitted; i++) {
642 soundbuf[emitted++] = (int16_t)(samplebuffer[i]);
643 soundbuf[emitted++] = (int16_t)(samplebuffer[i] >> 16);
645 else
646 for(unsigned i = 0; i < samples_emitted; i++) {
647 uint32_t l = (int32_t)(int16_t)(samplebuffer[i]) + 32768;
648 uint32_t r = (int32_t)(int16_t)(samplebuffer[i] >> 16) + 32768;
649 accumulator_l += l;
650 accumulator_r += r;
651 accumulator_s++;
652 if((accumulator_s & 63) == 0) {
653 int16_t l2 = (accumulator_l >> 6) - 32768;
654 int16_t r2 = (accumulator_r >> 6) - 32768;
655 soundbuf[emitted++] = l2;
656 soundbuf[emitted++] = r2;
657 accumulator_l = accumulator_r = 0;
658 accumulator_s = 0;
661 ecore_callbacks->timer_tick(samples_emitted, 2097152);
662 frame_overflow += samples_emitted;
663 if(frame_overflow >= SAMPLES_PER_FRAME) {
664 frame_overflow -= SAMPLES_PER_FRAME;
665 break;
668 framebuffer::info inf;
669 inf.type = &framebuffer::pixfmt_rgb32;
670 inf.mem = const_cast<char*>(reinterpret_cast<const char*>(primary_framebuffer));
671 inf.physwidth = 160;
672 inf.physheight = 144;
673 inf.physstride = 640;
674 inf.width = 160;
675 inf.height = 144;
676 inf.stride = 640;
677 inf.offset_x = 0;
678 inf.offset_y = 0;
680 framebuffer::raw ls(inf);
681 ecore_callbacks->output_frame(ls, 262144, 4389);
682 audioapi_submit_buffer(soundbuf, emitted / 2, true, native_rate ? 2097152 : 32768);
684 void c_runtosave() {}
685 bool c_get_pflag() { return pflag; }
686 void c_set_pflag(bool _pflag) { pflag = _pflag; }
687 framebuffer::raw& c_draw_cover() {
688 static framebuffer::raw x(cover_fbinfo);
689 redraw_cover_fbinfo();
690 return x;
692 std::string c_get_core_shortname() { return "gambatte"+gambatte::GB::version(); }
693 void c_pre_emulate_frame(controller_frame& cf) {
694 cf.axis3(0, 0, 1, do_reset_flag ? 1 : 0);
696 void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p)
698 uint32_t a, b, c, d;
699 switch(id) {
700 case 0: //Soft reset.
701 do_reset_flag = true;
702 break;
703 case 1: //Change DMG BG palette.
704 case 2: //Change DMG SP1 palette.
705 case 3: //Change DMG SP2 palette.
706 a = strtoul(p[0].s.c_str(), NULL, 16);
707 b = strtoul(p[1].s.c_str(), NULL, 16);
708 c = strtoul(p[2].s.c_str(), NULL, 16);
709 d = strtoul(p[3].s.c_str(), NULL, 16);
710 palette_colors[4 * (id - 1) + 0] = a;
711 palette_colors[4 * (id - 1) + 1] = b;
712 palette_colors[4 * (id - 1) + 2] = c;
713 palette_colors[4 * (id - 1) + 3] = d;
714 palette_colors_default[id - 1] = false;
715 if(instance) {
716 instance->setDmgPaletteColor(id - 1, 0, a);
717 instance->setDmgPaletteColor(id - 1, 1, b);
718 instance->setDmgPaletteColor(id - 1, 2, c);
719 instance->setDmgPaletteColor(id - 1, 3, d);
723 const interface_device_reg* c_get_registers() { return gb_registers; }
724 unsigned c_action_flags(unsigned id) { return (id < 4) ? 1 : 0; }
725 int c_reset_action(bool hard) { return hard ? -1 : 0; }
726 std::pair<uint64_t, uint64_t> c_get_bus_map()
728 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
729 return std::make_pair(0x1000000, 0x10000);
730 #else
731 return std::make_pair(0, 0);
732 #endif
734 std::list<core_vma_info> c_vma_list() { return get_VMAlist(); }
735 std::set<std::string> c_srams() { return gambatte_srams(); }
736 void c_set_debug_flags(uint64_t addr, unsigned int sflags, unsigned int cflags)
738 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
739 if(addr == 0 && sflags & 8) debugbuf.trace_cpu = true;
740 if(addr == 0 && cflags & 8) debugbuf.trace_cpu = false;
741 if(addr >= 0 && addr < 32768) {
742 debugbuf.wram[addr] |= (sflags & 7);
743 debugbuf.wram[addr] &= ~(cflags & 7);
744 } else if(addr >= 0x20000 && addr < 0x20000 + instance->getSaveRam().second) {
745 debugbuf.sram[addr - 0x20000] |= (sflags & 7);
746 debugbuf.sram[addr - 0x20000] &= ~(cflags & 7);
747 } else if(addr >= 0x18000 && addr < 0x18200) {
748 debugbuf.ioamhram[addr - 0x18000] |= (sflags & 7);
749 debugbuf.ioamhram[addr - 0x18000] &= ~(cflags & 7);
750 } else if(addr >= 0x80000000 && addr < 0x80000000 + romdata.size()) {
751 debugbuf.cart[addr - 0x80000000] |= (sflags & 7);
752 debugbuf.cart[addr - 0x80000000] &= ~(cflags & 7);
753 } else if(addr >= 0x1000000 && addr < 0x1010000) {
754 debugbuf.bus[addr - 0x1000000] |= (sflags & 7);
755 debugbuf.bus[addr - 0x1000000] &= ~(cflags & 7);
756 } else if(addr == 0xFFFFFFFFFFFFFFFFULL) {
757 //Set/Clear every known debug.
758 for(unsigned i = 0; i < 32768; i++) {
759 debugbuf.wram[i] |= ((sflags & 7) << 4);
760 debugbuf.wram[i] &= ~((cflags & 7) << 4);
762 for(unsigned i = 0; i < 65536; i++) {
763 debugbuf.bus[i] |= ((sflags & 7) << 4);
764 debugbuf.bus[i] &= ~((cflags & 7) << 4);
766 for(unsigned i = 0; i < 512; i++) {
767 debugbuf.ioamhram[i] |= ((sflags & 7) << 4);
768 debugbuf.ioamhram[i] &= ~((cflags & 7) << 4);
770 for(unsigned i = 0; i < instance->getSaveRam().second; i++) {
771 debugbuf.sram[i] |= ((sflags & 7) << 4);
772 debugbuf.sram[i] &= ~((cflags & 7) << 4);
774 for(unsigned i = 0; i < romdata.size(); i++) {
775 debugbuf.cart[i] |= ((sflags & 7) << 4);
776 debugbuf.cart[i] &= ~((cflags & 7) << 4);
779 #endif
781 void c_set_cheat(uint64_t addr, uint64_t value, bool set)
783 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
784 if(addr >= 0 && addr < 32768) {
785 if(set) {
786 debugbuf.wram[addr] |= 8;
787 debugbuf.wramcheat[addr] = value;
788 } else {
789 debugbuf.wram[addr] &= ~8;
790 debugbuf.wramcheat.erase(addr);
792 } else if(addr >= 0x20000 && addr < 0x20000 + instance->getSaveRam().second) {
793 auto addr2 = addr - 0x20000;
794 if(set) {
795 debugbuf.sram[addr2] |= 8;
796 debugbuf.sramcheat[addr2] = value;
797 } else {
798 debugbuf.sram[addr2] &= ~8;
799 debugbuf.sramcheat.erase(addr2);
801 } else if(addr >= 0x80000000 && addr < 0x80000000 + romdata.size()) {
802 auto addr2 = addr - 0x80000000;
803 if(set) {
804 debugbuf.cart[addr2] |= 8;
805 debugbuf.cartcheat[addr2] = value;
806 } else {
807 debugbuf.cart[addr2] &= ~8;
808 debugbuf.cartcheat.erase(addr2);
811 #endif
813 void c_debug_reset()
815 //Next load will reset trace.
816 reallocate_debug = true;
817 palette_colors_default[0] = true;
818 palette_colors_default[1] = true;
819 palette_colors_default[2] = true;
821 std::vector<std::string> c_get_trace_cpus()
823 std::vector<std::string> r;
824 r.push_back("cpu");
825 return r;
827 } gambatte_core;
829 std::vector<core_setting_value_param> boolean_values = {{"0", "False", 0}, {"1", "True", 1}};
830 core_setting_group gambatte_settings = {
831 #ifdef GAMBATTE_SUPPORTS_EMU_FLAGS
832 {"sigillcrash", "Crash on SIGILL", "0", boolean_values},
833 #endif
836 struct _type_dmg : public core_type, public core_sysregion
838 _type_dmg()
839 : core_type({{
840 .iname = "dmg",
841 .hname = "Game Boy",
842 .id = 1,
843 .sysname = "Gameboy",
844 .bios = NULL,
845 .regions = {&gambatte_core},
846 .images = {{"rom", "Cartridge ROM", 1, 0, 0, "gb;dmg"}},
847 .settings = gambatte_settings,
848 .core = &gambatte_core,
849 }}),
850 core_sysregion("gdmg", *this, gambatte_core) {}
852 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
853 uint64_t secs, uint64_t subsecs)
855 return load_rom_common(img, gambatte::GB::FORCE_DMG, secs, subsecs, this, settings);
857 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
859 return gambatte_controllerconfig(settings);
861 } type_dmg;
863 struct _type_gbc : public core_type, public core_sysregion
865 _type_gbc()
866 : core_type({{
867 .iname = "gbc",
868 .hname = "Game Boy Color",
869 .id = 0,
870 .sysname = "Gameboy",
871 .bios = NULL,
872 .regions = {&gambatte_core},
873 .images = {{"rom", "Cartridge ROM", 1, 0, 0, "gbc;cgb"}},
874 .settings = gambatte_settings,
875 .core = &gambatte_core,
876 }}),
877 core_sysregion("ggbc", *this, gambatte_core) {}
879 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
880 uint64_t secs, uint64_t subsecs)
882 return load_rom_common(img, 0, secs, subsecs, this, settings);
884 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
886 return gambatte_controllerconfig(settings);
888 } type_gbc;
890 struct _type_gbca : public core_type, public core_sysregion
892 _type_gbca()
893 : core_type({{
894 .iname = "gbc_gba",
895 .hname = "Game Boy Color (GBA)",
896 .id = 2,
897 .sysname = "Gameboy",
898 .bios = NULL,
899 .regions = {&gambatte_core},
900 .images = {{"rom", "Cartridge ROM", 1, 0, 0, ""}},
901 .settings = gambatte_settings,
902 .core = &gambatte_core,
903 }}),
904 core_sysregion("ggbca", *this, gambatte_core) {}
906 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
907 uint64_t secs, uint64_t subsecs)
909 return load_rom_common(img, gambatte::GB::GBA_CGB, secs, subsecs, this, settings);
911 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
913 return gambatte_controllerconfig(settings);
915 } type_gbca;
917 void redraw_cover_fbinfo()
919 for(size_t i = 0; i < sizeof(cover_fbmem) / sizeof(cover_fbmem[0]); i++)
920 cover_fbmem[i] = 0x00000000;
921 std::string ident = gambatte_core.get_core_identifier();
922 cover_render_string(cover_fbmem, 0, 0, ident, 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
923 cover_render_string(cover_fbmem, 0, 16, "Internal ROM name: " + get_cartridge_name(),
924 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
925 unsigned y = 32;
926 for(auto i : cover_information()) {
927 cover_render_string(cover_fbmem, 0, y, i, 0xFFFFFF, 0x000000, 480, 432, 1920, 4);
928 y += 16;
930 if(sigillcrash) {
931 cover_render_string(cover_fbmem, 0, y, "Crash on SIGILL enabled", 0xFFFFFF, 0x000000, 480,
932 432, 1920, 4);
933 y += 16;
937 std::vector<char> cmp_save;
939 command::fnptr<> cmp_save1(lsnes_cmd, "set-cmp-save", "", "\n", []() throw(std::bad_alloc,
940 std::runtime_error) {
941 if(!internal_rom)
942 return;
943 instance->saveState(cmp_save);
946 command::fnptr<> cmp_save2(lsnes_cmd, "do-cmp-save", "", "\n", []() throw(std::bad_alloc,
947 std::runtime_error) {
948 std::vector<char> x;
949 if(!internal_rom)
950 return;
951 instance->saveState(x, cmp_save);
954 struct oninit {
955 oninit()
957 register_sysregion_mapping("gdmg", "GB");
958 register_sysregion_mapping("ggbc", "GBC");
959 register_sysregion_mapping("ggbca", "GBC");
961 } _oninit;