Add dedicated method for resetting to poweron state
[lsnes.git] / src / emulation / gambatte / core.cpp
blob328d49de3f4205fa8cc8b3f6a671c115753620b9
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/instance.hpp"
33 #include "core/messages.hpp"
34 #include "interface/callbacks.hpp"
35 #include "interface/cover.hpp"
36 #include "interface/romtype.hpp"
37 #include "library/framebuffer-pixfmt-rgb32.hpp"
38 #include "library/hex.hpp"
39 #include "library/string.hpp"
40 #include "library/portctrl-data.hpp"
41 #include "library/serialization.hpp"
42 #include "library/minmax.hpp"
43 #include "library/framebuffer.hpp"
44 #include "library/lua-base.hpp"
45 #include "library/lua-params.hpp"
46 #include "library/lua-function.hpp"
47 #include "lua/internal.hpp"
48 #define HAVE_CSTDINT
49 #include "libgambatte/include/gambatte.h"
51 #define SAMPLES_PER_FRAME 35112
53 namespace
55 settingvar::supervariable<settingvar::model_bool<settingvar::yes_no>> output_native(lsnes_setgrp,
56 "gambatte-native-sound", "Gambatteā€£Sound Output at native rate", false);
57 settingvar::supervariable<settingvar::model_bool<settingvar::yes_no>> gbchawk_timings(lsnes_setgrp,
58 "gambatte-gbchawk-fuckup", "Gambatteā€£Use old GBCHawk timings", false);
60 bool do_reset_flag = false;
61 core_type* internal_rom = NULL;
62 bool rtc_fixed;
63 time_t rtc_fixed_val;
64 gambatte::GB* instance;
65 bool reallocate_debug = false;
66 bool sigillcrash = false;
67 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
68 gambatte::debugbuffer debugbuf;
69 size_t cur_romsize;
70 size_t cur_ramsize;
71 #endif
72 unsigned frame_overflow = 0;
73 std::vector<unsigned char> romdata;
74 std::vector<char> init_savestate;
75 uint32_t cover_fbmem[480 * 432];
76 uint32_t primary_framebuffer[160*144];
77 uint32_t accumulator_l = 0;
78 uint32_t accumulator_r = 0;
79 unsigned accumulator_s = 0;
80 bool pflag = false;
81 bool disable_breakpoints = false;
82 bool palette_colors_default[3] = {true, true, true};
83 uint32_t palette_colors[12];
84 uint32_t last_tsc_increment = 0;
86 struct interface_device_reg gb_registers[] = {
87 {"wrambank", []() -> uint64_t { return instance ? instance->getIoRam().first[0x170] & 0x07 : 0; },
88 [](uint64_t v) {}},
89 {"cyclecount", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_CYCLECOUNTER); },
90 [](uint64_t v) {}},
91 {"pc", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_PC); },
92 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_PC, v); }},
93 {"sp", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_SP); },
94 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_SP, v); }},
95 {"hf1", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_HF1); },
96 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_HF1, v); }},
97 {"hf2", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_HF2); },
98 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_HF2, v); }},
99 {"zf", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_ZF); },
100 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_ZF, v); }},
101 {"cf", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_CF); },
102 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_CF, v); }},
103 {"a", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_A); },
104 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_A, v); }},
105 {"b", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_B); },
106 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_B, v); }},
107 {"c", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_C); },
108 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_C, v); }},
109 {"d", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_D); },
110 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_D, v); }},
111 {"e", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_E); },
112 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_E, v); }},
113 {"f", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_F); },
114 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_F, v); }},
115 {"h", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_H); },
116 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_H, v); }},
117 {"l", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_L); },
118 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_L, v); }},
119 {NULL, NULL, NULL}
122 //Framebuffer.
123 struct framebuffer::info cover_fbinfo = {
124 &framebuffer::pixfmt_rgb32, //Format.
125 (char*)cover_fbmem, //Memory.
126 480, 432, 1920, //Physical size.
127 480, 432, 1920, //Logical size.
128 0, 0 //Offset.
131 #include "ports.inc"
133 time_t walltime_fn()
135 if(rtc_fixed)
136 return rtc_fixed_val;
137 if(ecore_callbacks)
138 return ecore_callbacks->get_time();
139 else
140 return time(0);
143 class myinput : public gambatte::InputGetter
145 public:
146 unsigned operator()()
148 unsigned v = 0;
149 for(unsigned i = 0; i < 8; i++) {
150 if(ecore_callbacks->get_input(0, 1, i))
151 v |= (1 << i);
153 pflag = true;
154 return v;
156 } getinput;
158 uint64_t get_address(unsigned clazz, unsigned offset)
160 switch(clazz) {
161 case 0: return 0x1000000 + offset; //BUS.
162 case 1: return offset; //WRAM.
163 case 2: return 0x18000 + offset; //IOAMHRAM
164 case 3: return 0x80000000 + offset; //ROM
165 case 4: return 0x20000 + offset; //SRAM.
167 return 0xFFFFFFFFFFFFFFFF;
170 void gambatte_read_handler(unsigned clazz, unsigned offset, uint8_t value, bool exec)
172 if(disable_breakpoints) return;
173 uint64_t _addr = get_address(clazz, offset);
174 if(_addr != 0xFFFFFFFFFFFFFFFFULL) {
175 if(exec)
176 ecore_callbacks->memory_execute(_addr, 0);
177 else
178 ecore_callbacks->memory_read(_addr, value);
182 void gambatte_write_handler(unsigned clazz, unsigned offset, uint8_t value)
184 if(disable_breakpoints) return;
185 uint64_t _addr = get_address(clazz, offset);
186 if(_addr != 0xFFFFFFFFFFFFFFFFULL)
187 ecore_callbacks->memory_write(_addr, value);
190 int get_hl(gambatte::GB* instance)
192 return instance->get_cpureg(gambatte::GB::REG_H) * 256 +
193 instance->get_cpureg(gambatte::GB::REG_L);
196 int get_bc(gambatte::GB* instance)
198 return instance->get_cpureg(gambatte::GB::REG_B) * 256 +
199 instance->get_cpureg(gambatte::GB::REG_C);
202 int get_de(gambatte::GB* instance)
204 return instance->get_cpureg(gambatte::GB::REG_D) * 256 +
205 instance->get_cpureg(gambatte::GB::REG_E);
208 //0 => None or already done.
209 //1 => BC
210 //2 => DE
211 //3 => HL
212 //4 => 0xFF00 + C.
213 //5 => Bitops
214 int memclass[] = {
215 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
216 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //0
217 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, //1
218 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, //2
219 0, 0, 3, 0, 3, 3, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, //3
220 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //4
221 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //5
222 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //6
223 3, 3, 3, 3, 3, 3, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, //7
224 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //8
225 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //9
226 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //A
227 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //B
228 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, //C
229 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //D
230 0, 0, 4, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, //E
231 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //F.
234 const char* hexch = "0123456789abcdef";
235 inline void buffer_h8(char*& ptr, uint8_t v)
237 *(ptr++) = hexch[v >> 4];
238 *(ptr++) = hexch[v & 15];
241 inline void buffer_h16(char*& ptr, uint16_t v)
243 *(ptr++) = hexch[v >> 12];
244 *(ptr++) = hexch[(v >> 8) & 15];
245 *(ptr++) = hexch[(v >> 4) & 15];
246 *(ptr++) = hexch[v & 15];
249 inline void buffer_str(char*& ptr, const char* str)
251 while(*str)
252 *(ptr++) = *(str++);
255 void gambatte_trace_handler(uint16_t _pc)
257 static char buffer[512];
258 char* buffer_ptr = buffer;
259 int addr = -1;
260 uint16_t opcode;
261 uint32_t pc = _pc;
262 uint16_t offset = 0;
263 std::function<uint8_t()> fetch = [pc, &offset, &buffer_ptr]() -> uint8_t {
264 unsigned addr = pc + offset++;
265 uint8_t v;
266 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
267 disable_breakpoints = true;
268 v = instance->bus_read(addr);
269 disable_breakpoints = false;
270 #endif
271 buffer_h8(buffer_ptr, v);
272 return v;
274 buffer_h16(buffer_ptr, pc);
275 *(buffer_ptr++) = ' ';
276 auto d = disassemble_gb_opcode(pc, fetch, addr, opcode);
277 while(buffer_ptr < buffer + 12)
278 *(buffer_ptr++) = ' ';
279 buffer_str(buffer_ptr, d.c_str());
280 switch(memclass[opcode >> 8]) {
281 case 1: addr = get_bc(instance); break;
282 case 2: addr = get_de(instance); break;
283 case 3: addr = get_hl(instance); break;
284 case 4: addr = 0xFF00 + instance->get_cpureg(gambatte::GB::REG_C); break;
285 case 5: if((opcode & 7) == 6) addr = get_hl(instance); break;
287 while(buffer_ptr < buffer + 28)
288 *(buffer_ptr++) = ' ';
289 if(addr >= 0) {
290 buffer_str(buffer_ptr, "[");
291 buffer_h16(buffer_ptr, addr);
292 buffer_str(buffer_ptr, "]");
293 } else
294 buffer_str(buffer_ptr, " ");
296 buffer_str(buffer_ptr, "A:");
297 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_A));
298 buffer_str(buffer_ptr, " B:");
299 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_B));
300 buffer_str(buffer_ptr, " C:");
301 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_C));
302 buffer_str(buffer_ptr, " D:");
303 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_D));
304 buffer_str(buffer_ptr, " E:");
305 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_E));
306 buffer_str(buffer_ptr, " H:");
307 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_H));
308 buffer_str(buffer_ptr, " L:");
309 buffer_h8(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_L));
310 buffer_str(buffer_ptr, " SP:");
311 buffer_h16(buffer_ptr, instance->get_cpureg(gambatte::GB::REG_SP));
312 buffer_str(buffer_ptr, " F:");
313 *(buffer_ptr++) = instance->get_cpureg(gambatte::GB::REG_CF) ? 'C' : '-';
314 *(buffer_ptr++) = instance->get_cpureg(gambatte::GB::REG_ZF) ? '-' : 'Z';
315 *(buffer_ptr++) = instance->get_cpureg(gambatte::GB::REG_HF1) ? '1' : '-';
316 *(buffer_ptr++) = instance->get_cpureg(gambatte::GB::REG_HF2) ? '2' : '-';
317 *(buffer_ptr++) = '\0';
318 ecore_callbacks->memory_trace(0, buffer, true);
321 void basic_init()
323 static bool done = false;
324 if(done)
325 return;
326 done = true;
327 instance = new gambatte::GB;
328 instance->setInputGetter(&getinput);
329 instance->set_walltime_fn(walltime_fn);
330 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
331 uint8_t* tmp = new uint8_t[98816];
332 memset(tmp, 0, 98816);
333 debugbuf.wram = tmp;
334 debugbuf.bus = tmp + 32768;
335 debugbuf.ioamhram = tmp + 98304;
336 debugbuf.read = gambatte_read_handler;
337 debugbuf.write = gambatte_write_handler;
338 debugbuf.trace = gambatte_trace_handler;
339 debugbuf.trace_cpu = false;
340 instance->set_debug_buffer(debugbuf);
341 #endif
344 int load_rom_common(core_romimage* img, unsigned flags, uint64_t rtc_sec, uint64_t rtc_subsec,
345 core_type* inttype, std::map<std::string, std::string>& settings)
347 basic_init();
348 const char* markup = img[0].markup;
349 int flags2 = 0;
350 if(markup) {
351 flags2 = atoi(markup);
352 flags2 &= 4;
354 flags |= flags2;
355 const unsigned char* data = img[0].data;
356 size_t size = img[0].size;
358 //Reset it really.
359 instance->~GB();
360 memset(instance, 0, sizeof(gambatte::GB));
361 new(instance) gambatte::GB;
362 instance->setInputGetter(&getinput);
363 instance->set_walltime_fn(walltime_fn);
364 memset(primary_framebuffer, 0, sizeof(primary_framebuffer));
365 frame_overflow = 0;
367 rtc_fixed = true;
368 rtc_fixed_val = rtc_sec;
369 instance->load(data, size, flags);
370 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
371 size_t sramsize = instance->getSaveRam().second;
372 size_t romsize = size;
373 if(reallocate_debug || cur_ramsize != sramsize || cur_romsize != romsize) {
374 if(debugbuf.cart) delete[] debugbuf.cart;
375 if(debugbuf.sram) delete[] debugbuf.sram;
376 debugbuf.cart = NULL;
377 debugbuf.sram = NULL;
378 if(sramsize) debugbuf.sram = new uint8_t[(sramsize + 4095) >> 12 << 12];
379 if(romsize) debugbuf.cart = new uint8_t[(romsize + 4095) >> 12 << 12];
380 if(sramsize) memset(debugbuf.sram, 0, (sramsize + 4095) >> 12 << 12);
381 if(romsize) memset(debugbuf.cart, 0, (romsize + 4095) >> 12 << 12);
382 memset(debugbuf.wram, 0, 32768);
383 memset(debugbuf.ioamhram, 0, 512);
384 debugbuf.wramcheat.clear();
385 debugbuf.sramcheat.clear();
386 debugbuf.cartcheat.clear();
387 debugbuf.trace_cpu = false;
388 reallocate_debug = false;
389 cur_ramsize = sramsize;
390 cur_romsize = romsize;
392 instance->set_debug_buffer(debugbuf);
393 #endif
394 sigillcrash = false;
395 #ifdef GAMBATTE_SUPPORTS_EMU_FLAGS
396 unsigned emuflags = 0;
397 if(settings.count("sigillcrash") && settings["sigillcrash"] == "1")
398 emuflags |= 1;
399 sigillcrash = (emuflags & 1);
400 instance->set_emuflags(emuflags);
401 #endif
402 rtc_fixed = false;
403 romdata.resize(size);
404 memcpy(&romdata[0], data, size);
405 internal_rom = inttype;
406 do_reset_flag = false;
408 for(unsigned i = 0; i < 12; i++)
409 if(!palette_colors_default[i >> 2])
410 instance->setDmgPaletteColor(i >> 2, i & 3, palette_colors[i]);
411 //Save initial savestate.
412 instance->saveState(init_savestate);
413 return 1;
416 controller_set gambatte_controllerconfig(std::map<std::string, std::string>& settings)
418 std::map<std::string, std::string> _settings = settings;
419 controller_set r;
420 r.ports.push_back(&psystem);
421 r.logical_map.push_back(std::make_pair(0, 1));
422 return r;
425 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
426 uint8_t gambatte_bus_read(uint64_t offset)
428 disable_breakpoints = true;
429 uint8_t val = instance->bus_read(offset);
430 disable_breakpoints = false;
431 return val;
434 void gambatte_bus_write(uint64_t offset, uint8_t data)
436 disable_breakpoints = true;
437 instance->bus_write(offset, data);
438 disable_breakpoints = false;
440 #endif
442 std::list<core_vma_info> get_VMAlist()
444 std::list<core_vma_info> vmas;
445 if(!internal_rom)
446 return vmas;
447 core_vma_info sram;
448 core_vma_info wram;
449 core_vma_info vram;
450 core_vma_info ioamhram;
451 core_vma_info rom;
452 core_vma_info bus;
454 auto g = instance->getSaveRam();
455 sram.name = "SRAM";
456 sram.base = 0x20000;
457 sram.size = g.second;
458 sram.backing_ram = g.first;
459 sram.endian = -1;
461 auto g2 = instance->getWorkRam();
462 wram.name = "WRAM";
463 wram.base = 0;
464 wram.size = g2.second;
465 wram.backing_ram = g2.first;
466 wram.endian = -1;
468 auto g3 = instance->getVideoRam();
469 vram.name = "VRAM";
470 vram.base = 0x10000;
471 vram.size = g3.second;
472 vram.backing_ram = g3.first;
473 vram.endian = -1;
475 auto g4 = instance->getIoRam();
476 ioamhram.name = "IOAMHRAM";
477 ioamhram.base = 0x18000;
478 ioamhram.size = g4.second;
479 ioamhram.backing_ram = g4.first;
480 ioamhram.endian = -1;
482 rom.name = "ROM";
483 rom.base = 0x80000000;
484 rom.size = romdata.size();
485 rom.backing_ram = (void*)&romdata[0];
486 rom.endian = -1;
487 rom.readonly = true;
489 if(sram.size)
490 vmas.push_back(sram);
491 vmas.push_back(wram);
492 vmas.push_back(rom);
493 vmas.push_back(vram);
494 vmas.push_back(ioamhram);
495 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
496 bus.name = "BUS";
497 bus.base = 0x1000000;
498 bus.size = 0x10000;
499 bus.backing_ram = NULL;
500 bus.read = gambatte_bus_read;
501 bus.write = gambatte_bus_write;
502 bus.endian = -1;
503 bus.special = true;
504 vmas.push_back(bus);
505 #endif
506 return vmas;
509 std::set<std::string> gambatte_srams()
511 std::set<std::string> s;
512 if(!internal_rom)
513 return s;
514 auto g = instance->getSaveRam();
515 if(g.second)
516 s.insert("main");
517 s.insert("rtc");
518 return s;
521 std::string get_cartridge_name()
523 std::ostringstream name;
524 if(romdata.size() < 0x200)
525 return ""; //Bad.
526 for(unsigned i = 0; i < 16; i++) {
527 if(romdata[0x134 + i])
528 name << (char)romdata[0x134 + i];
529 else
530 break;
532 return name.str();
535 void redraw_cover_fbinfo();
537 struct _gambatte_core : public core_core, public core_region
539 _gambatte_core()
540 : core_core({&psystem}, {
541 {0, "Soft reset", "reset", {}},
542 {1, "Change BG palette", "bgpalette", {
543 {"Color 0","string:[0-9A-Fa-f]{6}"},
544 {"Color 1","string:[0-9A-Fa-f]{6}"},
545 {"Color 2","string:[0-9A-Fa-f]{6}"},
546 {"Color 3","string:[0-9A-Fa-f]{6}"}
547 }},{2, "Change SP1 palette", "sp1palette", {
548 {"Color 0","string:[0-9A-Fa-f]{6}"},
549 {"Color 1","string:[0-9A-Fa-f]{6}"},
550 {"Color 2","string:[0-9A-Fa-f]{6}"},
551 {"Color 3","string:[0-9A-Fa-f]{6}"}
552 }}, {3, "Change SP2 palette", "sp2palette", {
553 {"Color 0","string:[0-9A-Fa-f]{6}"},
554 {"Color 1","string:[0-9A-Fa-f]{6}"},
555 {"Color 2","string:[0-9A-Fa-f]{6}"},
556 {"Color 3","string:[0-9A-Fa-f]{6}"}
559 core_region({{"world", "World", 0, 0, false, {4389, 262144}, {0}}}) {}
561 std::string c_core_identifier() const { return "libgambatte "+gambatte::GB::version(); }
562 bool c_set_region(core_region& region) { return (&region == this); }
563 std::pair<uint32_t, uint32_t> c_video_rate() { return std::make_pair(262144, 4389); }
564 double c_get_PAR() { return 1.0; }
565 std::pair<uint32_t, uint32_t> c_audio_rate() {
566 if(output_native(*CORE().settings))
567 return std::make_pair(2097152, 1);
568 else
569 return std::make_pair(32768, 1);
571 std::map<std::string, std::vector<char>> c_save_sram() throw(std::bad_alloc) {
572 std::map<std::string, std::vector<char>> s;
573 if(!internal_rom)
574 return s;
575 auto g = instance->getSaveRam();
576 s["main"].resize(g.second);
577 memcpy(&s["main"][0], g.first, g.second);
578 s["rtc"].resize(8);
579 time_t timebase = instance->getRtcBase();
580 for(size_t i = 0; i < 8; i++)
581 s["rtc"][i] = ((unsigned long long)timebase >> (8 * i));
582 return s;
584 void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc) {
585 if(!internal_rom)
586 return;
587 std::vector<char> x = sram.count("main") ? sram["main"] : std::vector<char>();
588 std::vector<char> x2 = sram.count("rtc") ? sram["rtc"] : std::vector<char>();
589 auto g = instance->getSaveRam();
590 if(x.size()) {
591 if(x.size() != g.second)
592 messages << "WARNING: SRAM 'main': Loaded " << x.size()
593 << " bytes, but the SRAM is " << g.second << "." << std::endl;
594 memcpy(g.first, &x[0], min(x.size(), g.second));
596 if(x2.size()) {
597 time_t timebase = 0;
598 for(size_t i = 0; i < 8 && i < x2.size(); i++)
599 timebase |= (unsigned long long)(unsigned char)x2[i] << (8 * i);
600 instance->setRtcBase(timebase);
603 void c_serialize(std::vector<char>& out) {
604 if(!internal_rom)
605 throw std::runtime_error("Can't save without ROM");
606 instance->saveState(out);
607 size_t osize = out.size();
608 out.resize(osize + 4 * sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]));
609 for(size_t i = 0; i < sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]); i++)
610 serialization::u32b(&out[osize + 4 * i], primary_framebuffer[i]);
611 out.push_back(frame_overflow >> 8);
612 out.push_back(frame_overflow);
614 void c_unserialize(const char* in, size_t insize) {
615 if(!internal_rom)
616 throw std::runtime_error("Can't load without ROM");
617 size_t foffset = insize - 2 - 4 * sizeof(primary_framebuffer) /
618 sizeof(primary_framebuffer[0]);
619 std::vector<char> tmp;
620 tmp.resize(foffset);
621 memcpy(&tmp[0], in, foffset);
622 instance->loadState(tmp);
623 for(size_t i = 0; i < sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]); i++)
624 primary_framebuffer[i] = serialization::u32b(&in[foffset + 4 * i]);
626 unsigned x1 = (unsigned char)in[insize - 2];
627 unsigned x2 = (unsigned char)in[insize - 1];
628 frame_overflow = x1 * 256 + x2;
629 do_reset_flag = false;
631 core_region& c_get_region() { return *this; }
632 void c_power() {}
633 void c_unload_cartridge() {}
634 std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
635 return std::make_pair(max(512 / width, (uint32_t)1), max(448 / height, (uint32_t)1));
637 void c_install_handler() { magic_flags |= 2; }
638 void c_uninstall_handler() {}
639 void c_emulate() {
640 if(!internal_rom)
641 return;
642 auto& core = CORE();
643 bool timings_fucked_up = gbchawk_timings(*core.settings);
644 bool native_rate = output_native(*core.settings);
645 int16_t reset = ecore_callbacks->get_input(0, 0, 1);
646 if(reset) {
647 instance->reset();
648 messages << "GB(C) reset" << std::endl;
650 do_reset_flag = false;
652 uint32_t samplebuffer[SAMPLES_PER_FRAME + 2064];
653 int16_t soundbuf[2 * (SAMPLES_PER_FRAME + 2064)];
654 size_t emitted = 0;
655 last_tsc_increment = 0;
656 while(true) {
657 unsigned samples_emitted = timings_fucked_up ? 35112 :
658 (SAMPLES_PER_FRAME - frame_overflow);
659 long ret = instance->runFor(primary_framebuffer, 160, samplebuffer, samples_emitted);
660 if(native_rate)
661 for(unsigned i = 0; i < samples_emitted; i++) {
662 soundbuf[emitted++] = (int16_t)(samplebuffer[i]);
663 soundbuf[emitted++] = (int16_t)(samplebuffer[i] >> 16);
665 else
666 for(unsigned i = 0; i < samples_emitted; i++) {
667 uint32_t l = (int32_t)(int16_t)(samplebuffer[i]) + 32768;
668 uint32_t r = (int32_t)(int16_t)(samplebuffer[i] >> 16) + 32768;
669 accumulator_l += l;
670 accumulator_r += r;
671 accumulator_s++;
672 if((accumulator_s & 63) == 0) {
673 int16_t l2 = (accumulator_l >> 6) - 32768;
674 int16_t r2 = (accumulator_r >> 6) - 32768;
675 soundbuf[emitted++] = l2;
676 soundbuf[emitted++] = r2;
677 accumulator_l = accumulator_r = 0;
678 accumulator_s = 0;
681 ecore_callbacks->timer_tick(samples_emitted, 2097152);
682 frame_overflow += samples_emitted;
683 last_tsc_increment += samples_emitted;
684 if(frame_overflow >= SAMPLES_PER_FRAME) {
685 frame_overflow -= SAMPLES_PER_FRAME;
686 break;
688 if(timings_fucked_up)
689 break;
691 framebuffer::info inf;
692 inf.type = &framebuffer::pixfmt_rgb32;
693 inf.mem = reinterpret_cast<char*>(primary_framebuffer);
694 inf.physwidth = 160;
695 inf.physheight = 144;
696 inf.physstride = 640;
697 inf.width = 160;
698 inf.height = 144;
699 inf.stride = 640;
700 inf.offset_x = 0;
701 inf.offset_y = 0;
703 framebuffer::raw ls(inf);
704 ecore_callbacks->output_frame(ls, 262144, 4389);
705 CORE().audio->submit_buffer(soundbuf, emitted / 2, true, native_rate ? 2097152 : 32768);
707 void c_runtosave() {}
708 bool c_get_pflag() { return pflag; }
709 void c_set_pflag(bool _pflag) { pflag = _pflag; }
710 framebuffer::raw& c_draw_cover() {
711 static framebuffer::raw x(cover_fbinfo);
712 redraw_cover_fbinfo();
713 return x;
715 std::string c_get_core_shortname() const { return "gambatte"+gambatte::GB::version(); }
716 void c_pre_emulate_frame(portctrl::frame& cf) {
717 cf.axis3(0, 0, 1, do_reset_flag ? 1 : 0);
719 void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p)
721 uint32_t a, b, c, d;
722 switch(id) {
723 case 0: //Soft reset.
724 do_reset_flag = true;
725 break;
726 case 1: //Change DMG BG palette.
727 case 2: //Change DMG SP1 palette.
728 case 3: //Change DMG SP2 palette.
729 a = strtoul(p[0].s.c_str(), NULL, 16);
730 b = strtoul(p[1].s.c_str(), NULL, 16);
731 c = strtoul(p[2].s.c_str(), NULL, 16);
732 d = strtoul(p[3].s.c_str(), NULL, 16);
733 palette_colors[4 * (id - 1) + 0] = a;
734 palette_colors[4 * (id - 1) + 1] = b;
735 palette_colors[4 * (id - 1) + 2] = c;
736 palette_colors[4 * (id - 1) + 3] = d;
737 palette_colors_default[id - 1] = false;
738 if(instance) {
739 instance->setDmgPaletteColor(id - 1, 0, a);
740 instance->setDmgPaletteColor(id - 1, 1, b);
741 instance->setDmgPaletteColor(id - 1, 2, c);
742 instance->setDmgPaletteColor(id - 1, 3, d);
746 const interface_device_reg* c_get_registers() { return gb_registers; }
747 unsigned c_action_flags(unsigned id) { return (id < 4) ? 1 : 0; }
748 int c_reset_action(bool hard) { return hard ? -1 : 0; }
749 std::pair<uint64_t, uint64_t> c_get_bus_map()
751 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
752 return std::make_pair(0x1000000, 0x10000);
753 #else
754 return std::make_pair(0, 0);
755 #endif
757 std::list<core_vma_info> c_vma_list() { return get_VMAlist(); }
758 std::set<std::string> c_srams() { return gambatte_srams(); }
759 void c_set_debug_flags(uint64_t addr, unsigned int sflags, unsigned int cflags)
761 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
762 if(addr == 0 && sflags & 8) debugbuf.trace_cpu = true;
763 if(addr == 0 && cflags & 8) debugbuf.trace_cpu = false;
764 if(addr >= 0 && addr < 32768) {
765 debugbuf.wram[addr] |= (sflags & 7);
766 debugbuf.wram[addr] &= ~(cflags & 7);
767 } else if(addr >= 0x20000 && addr < 0x20000 + instance->getSaveRam().second) {
768 debugbuf.sram[addr - 0x20000] |= (sflags & 7);
769 debugbuf.sram[addr - 0x20000] &= ~(cflags & 7);
770 } else if(addr >= 0x18000 && addr < 0x18200) {
771 debugbuf.ioamhram[addr - 0x18000] |= (sflags & 7);
772 debugbuf.ioamhram[addr - 0x18000] &= ~(cflags & 7);
773 } else if(addr >= 0x80000000 && addr < 0x80000000 + romdata.size()) {
774 debugbuf.cart[addr - 0x80000000] |= (sflags & 7);
775 debugbuf.cart[addr - 0x80000000] &= ~(cflags & 7);
776 } else if(addr >= 0x1000000 && addr < 0x1010000) {
777 debugbuf.bus[addr - 0x1000000] |= (sflags & 7);
778 debugbuf.bus[addr - 0x1000000] &= ~(cflags & 7);
779 } else if(addr == 0xFFFFFFFFFFFFFFFFULL) {
780 //Set/Clear every known debug.
781 for(unsigned i = 0; i < 32768; i++) {
782 debugbuf.wram[i] |= ((sflags & 7) << 4);
783 debugbuf.wram[i] &= ~((cflags & 7) << 4);
785 for(unsigned i = 0; i < 65536; i++) {
786 debugbuf.bus[i] |= ((sflags & 7) << 4);
787 debugbuf.bus[i] &= ~((cflags & 7) << 4);
789 for(unsigned i = 0; i < 512; i++) {
790 debugbuf.ioamhram[i] |= ((sflags & 7) << 4);
791 debugbuf.ioamhram[i] &= ~((cflags & 7) << 4);
793 for(unsigned i = 0; i < instance->getSaveRam().second; i++) {
794 debugbuf.sram[i] |= ((sflags & 7) << 4);
795 debugbuf.sram[i] &= ~((cflags & 7) << 4);
797 for(unsigned i = 0; i < romdata.size(); i++) {
798 debugbuf.cart[i] |= ((sflags & 7) << 4);
799 debugbuf.cart[i] &= ~((cflags & 7) << 4);
802 #endif
804 void c_set_cheat(uint64_t addr, uint64_t value, bool set)
806 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
807 if(addr >= 0 && addr < 32768) {
808 if(set) {
809 debugbuf.wram[addr] |= 8;
810 debugbuf.wramcheat[addr] = value;
811 } else {
812 debugbuf.wram[addr] &= ~8;
813 debugbuf.wramcheat.erase(addr);
815 } else if(addr >= 0x20000 && addr < 0x20000 + instance->getSaveRam().second) {
816 auto addr2 = addr - 0x20000;
817 if(set) {
818 debugbuf.sram[addr2] |= 8;
819 debugbuf.sramcheat[addr2] = value;
820 } else {
821 debugbuf.sram[addr2] &= ~8;
822 debugbuf.sramcheat.erase(addr2);
824 } else if(addr >= 0x80000000 && addr < 0x80000000 + romdata.size()) {
825 auto addr2 = addr - 0x80000000;
826 if(set) {
827 debugbuf.cart[addr2] |= 8;
828 debugbuf.cartcheat[addr2] = value;
829 } else {
830 debugbuf.cart[addr2] &= ~8;
831 debugbuf.cartcheat.erase(addr2);
834 #endif
836 void c_debug_reset()
838 //Next load will reset trace.
839 reallocate_debug = true;
840 palette_colors_default[0] = true;
841 palette_colors_default[1] = true;
842 palette_colors_default[2] = true;
844 std::vector<std::string> c_get_trace_cpus()
846 std::vector<std::string> r;
847 r.push_back("cpu");
848 return r;
850 void c_reset_to_load()
852 instance->loadState(init_savestate);
853 memset(primary_framebuffer, 0, sizeof(primary_framebuffer));
854 frame_overflow = 0; //frame_overflow is always 0 at the beginning.
855 do_reset_flag = false;
857 } gambatte_core;
859 std::vector<core_setting_value_param> boolean_values = {{"0", "False", 0}, {"1", "True", 1}};
860 core_setting_group gambatte_settings = {
861 #ifdef GAMBATTE_SUPPORTS_EMU_FLAGS
862 {"sigillcrash", "Crash on SIGILL", "0", boolean_values},
863 #endif
866 struct _type_dmg : public core_type, public core_sysregion
868 _type_dmg()
869 : core_type({{
870 .iname = "dmg",
871 .hname = "Game Boy",
872 .id = 1,
873 .sysname = "Gameboy",
874 .bios = NULL,
875 .regions = {&gambatte_core},
876 .images = {{"rom", "Cartridge ROM", 1, 0, 0, "gb;dmg"}},
877 .settings = gambatte_settings,
878 .core = &gambatte_core,
879 }}),
880 core_sysregion("gdmg", *this, gambatte_core) {}
882 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
883 uint64_t secs, uint64_t subsecs)
885 return load_rom_common(img, gambatte::GB::FORCE_DMG, secs, subsecs, this, settings);
887 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
889 return gambatte_controllerconfig(settings);
891 } type_dmg;
893 struct _type_gbc : public core_type, public core_sysregion
895 _type_gbc()
896 : core_type({{
897 .iname = "gbc",
898 .hname = "Game Boy Color",
899 .id = 0,
900 .sysname = "Gameboy",
901 .bios = NULL,
902 .regions = {&gambatte_core},
903 .images = {{"rom", "Cartridge ROM", 1, 0, 0, "gbc;cgb"}},
904 .settings = gambatte_settings,
905 .core = &gambatte_core,
906 }}),
907 core_sysregion("ggbc", *this, gambatte_core) {}
909 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
910 uint64_t secs, uint64_t subsecs)
912 return load_rom_common(img, 0, secs, subsecs, this, settings);
914 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
916 return gambatte_controllerconfig(settings);
918 } type_gbc;
920 struct _type_gbca : public core_type, public core_sysregion
922 _type_gbca()
923 : core_type({{
924 .iname = "gbc_gba",
925 .hname = "Game Boy Color (GBA)",
926 .id = 2,
927 .sysname = "Gameboy",
928 .bios = NULL,
929 .regions = {&gambatte_core},
930 .images = {{"rom", "Cartridge ROM", 1, 0, 0, ""}},
931 .settings = gambatte_settings,
932 .core = &gambatte_core,
933 }}),
934 core_sysregion("ggbca", *this, gambatte_core) {}
936 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
937 uint64_t secs, uint64_t subsecs)
939 return load_rom_common(img, gambatte::GB::GBA_CGB, secs, subsecs, this, settings);
941 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
943 return gambatte_controllerconfig(settings);
945 } type_gbca;
947 void redraw_cover_fbinfo()
949 for(size_t i = 0; i < sizeof(cover_fbmem) / sizeof(cover_fbmem[0]); i++)
950 cover_fbmem[i] = 0x00000000;
951 std::string ident = gambatte_core.get_core_identifier();
952 cover_render_string(cover_fbmem, 0, 0, ident, 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
953 cover_render_string(cover_fbmem, 0, 16, "Internal ROM name: " + get_cartridge_name(),
954 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
955 unsigned y = 32;
956 for(auto i : cover_information()) {
957 cover_render_string(cover_fbmem, 0, y, i, 0xFFFFFF, 0x000000, 480, 432, 1920, 4);
958 y += 16;
960 if(sigillcrash) {
961 cover_render_string(cover_fbmem, 0, y, "Crash on SIGILL enabled", 0xFFFFFF, 0x000000, 480,
962 432, 1920, 4);
963 y += 16;
967 std::vector<char> cmp_save;
969 command::fnptr<> cmp_save1(lsnes_cmds, "set-cmp-save", "", "\n", []() throw(std::bad_alloc,
970 std::runtime_error) {
971 if(!internal_rom)
972 return;
973 instance->saveState(cmp_save);
976 command::fnptr<> cmp_save2(lsnes_cmds, "do-cmp-save", "", "\n", []() throw(std::bad_alloc,
977 std::runtime_error) {
978 std::vector<char> x;
979 if(!internal_rom)
980 return;
981 instance->saveState(x, cmp_save);
984 int last_frame_cycles(lua::state& L, lua::parameters& P)
986 L.pushnumber(last_tsc_increment);
987 return 1;
990 lua::functions debug_fns_snes(lua_func_misc, "gambatte", {
991 {"last_frame_cycles", last_frame_cycles},
995 struct oninit {
996 oninit()
998 register_sysregion_mapping("gdmg", "GB");
999 register_sysregion_mapping("ggbc", "GBC");
1000 register_sysregion_mapping("ggbca", "GBC");
1002 } _oninit;