Gambatte: Expose CPU registers
[lsnes.git] / src / emulation / gambatte / core.cpp
blobe12a65c19cf55f694686823efbd95dfc31481064
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 "core/audioapi.hpp"
25 #include "core/misc.hpp"
26 #include "core/command.hpp"
27 #include "core/controllerframe.hpp"
28 #include "core/dispatch.hpp"
29 #include "core/settings.hpp"
30 #include "core/framebuffer.hpp"
31 #include "core/window.hpp"
32 #include "interface/callbacks.hpp"
33 #include "interface/cover.hpp"
34 #include "interface/romtype.hpp"
35 #include "library/pixfmt-rgb32.hpp"
36 #include "library/string.hpp"
37 #include "library/controller-data.hpp"
38 #include "library/serialization.hpp"
39 #include "library/minmax.hpp"
40 #include "library/framebuffer.hpp"
41 #define HAVE_CSTDINT
42 #include "libgambatte/include/gambatte.h"
44 #define SAMPLES_PER_FRAME 35112
46 namespace
48 setting_var<setting_var_model_bool<setting_yes_no>> output_native(lsnes_vset, "gambatte-native-sound",
49 "Gambatteā€£Sound Output at native rate", false);
51 bool do_reset_flag = false;
52 core_type* internal_rom = NULL;
53 bool rtc_fixed;
54 time_t rtc_fixed_val;
55 gambatte::GB* instance;
56 unsigned frame_overflow = 0;
57 std::vector<unsigned char> romdata;
58 uint32_t cover_fbmem[480 * 432];
59 uint32_t primary_framebuffer[160*144];
60 uint32_t accumulator_l = 0;
61 uint32_t accumulator_r = 0;
62 unsigned accumulator_s = 0;
63 bool pflag = false;
66 struct interface_device_reg gb_registers[] = {
67 {"wrambank", []() -> uint64_t { return instance ? instance->getIoRam().first[0x170] & 0x07 : 0; },
68 [](uint64_t v) {}},
69 {"cyclecount", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_CYCLECOUNTER); },
70 [](uint64_t v) {}},
71 {"pc", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_PC); },
72 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_PC, v); }},
73 {"sp", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_SP); },
74 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_SP, v); }},
75 {"hf1", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_HF1); },
76 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_HF1, v); }},
77 {"hf2", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_HF2); },
78 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_HF2, v); }},
79 {"zf", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_ZF); },
80 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_ZF, v); }},
81 {"cf", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_CF); },
82 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_CF, v); }},
83 {"a", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_A); },
84 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_A, v); }},
85 {"b", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_B); },
86 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_B, v); }},
87 {"c", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_C); },
88 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_C, v); }},
89 {"d", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_D); },
90 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_D, v); }},
91 {"e", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_E); },
92 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_E, v); }},
93 {"f", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_F); },
94 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_F, v); }},
95 {"h", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_H); },
96 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_H, v); }},
97 {"l", []() -> uint64_t { return instance->get_cpureg(gambatte::GB::REG_L); },
98 [](uint64_t v) { instance->set_cpureg(gambatte::GB::REG_L, v); }},
99 {NULL, NULL, NULL}
102 //Framebuffer.
103 struct framebuffer_info cover_fbinfo = {
104 &_pixel_format_rgb32, //Format.
105 (char*)cover_fbmem, //Memory.
106 480, 432, 1920, //Physical size.
107 480, 432, 1920, //Logical size.
108 0, 0 //Offset.
111 #include "ports.inc"
113 time_t walltime_fn()
115 if(rtc_fixed)
116 return rtc_fixed_val;
117 if(ecore_callbacks)
118 return ecore_callbacks->get_time();
119 else
120 return time(0);
123 class myinput : public gambatte::InputGetter
125 public:
126 unsigned operator()()
128 unsigned v = 0;
129 for(unsigned i = 0; i < 8; i++) {
130 if(ecore_callbacks->get_input(0, 1, i))
131 v |= (1 << i);
133 pflag = true;
134 return v;
136 } getinput;
138 void basic_init()
140 static bool done = false;
141 if(done)
142 return;
143 done = true;
144 instance = new gambatte::GB;
145 instance->setInputGetter(&getinput);
146 instance->set_walltime_fn(walltime_fn);
149 int load_rom_common(core_romimage* img, unsigned flags, uint64_t rtc_sec, uint64_t rtc_subsec,
150 core_type* inttype)
152 basic_init();
153 const char* markup = img[0].markup;
154 int flags2 = 0;
155 if(markup) {
156 flags2 = atoi(markup);
157 flags2 &= 4;
159 flags |= flags2;
160 const unsigned char* data = img[0].data;
161 size_t size = img[0].size;
163 //Reset it really.
164 instance->~GB();
165 memset(instance, 0, sizeof(gambatte::GB));
166 new(instance) gambatte::GB;
167 instance->setInputGetter(&getinput);
168 instance->set_walltime_fn(walltime_fn);
169 memset(primary_framebuffer, 0, sizeof(primary_framebuffer));
170 frame_overflow = 0;
172 rtc_fixed = true;
173 rtc_fixed_val = rtc_sec;
174 instance->load(data, size, flags);
175 rtc_fixed = false;
176 romdata.resize(size);
177 memcpy(&romdata[0], data, size);
178 internal_rom = inttype;
179 do_reset_flag = false;
180 return 1;
183 controller_set gambatte_controllerconfig(std::map<std::string, std::string>& settings)
185 std::map<std::string, std::string> _settings = settings;
186 controller_set r;
187 r.ports.push_back(&psystem);
188 r.logical_map.push_back(std::make_pair(0, 1));
189 return r;
192 std::list<core_vma_info> get_VMAlist()
194 std::list<core_vma_info> vmas;
195 if(!internal_rom)
196 return vmas;
197 core_vma_info sram;
198 core_vma_info wram;
199 core_vma_info vram;
200 core_vma_info ioamhram;
201 core_vma_info rom;
203 auto g = instance->getSaveRam();
204 sram.name = "SRAM";
205 sram.base = 0x20000;
206 sram.size = g.second;
207 sram.backing_ram = g.first;
208 sram.endian = -1;
210 auto g2 = instance->getWorkRam();
211 wram.name = "WRAM";
212 wram.base = 0;
213 wram.size = g2.second;
214 wram.backing_ram = g2.first;
215 wram.endian = -1;
217 auto g3 = instance->getVideoRam();
218 vram.name = "VRAM";
219 vram.base = 0x10000;
220 vram.size = g3.second;
221 vram.backing_ram = g3.first;
222 vram.endian = -1;
224 auto g4 = instance->getIoRam();
225 ioamhram.name = "IOAMHRAM";
226 ioamhram.base = 0x18000;
227 ioamhram.size = g4.second;
228 ioamhram.backing_ram = g4.first;
229 ioamhram.endian = -1;
231 rom.name = "ROM";
232 rom.base = 0x80000000;
233 rom.size = romdata.size();
234 rom.backing_ram = (void*)&romdata[0];
235 rom.endian = -1;
236 rom.readonly = true;
238 if(sram.size)
239 vmas.push_back(sram);
240 vmas.push_back(wram);
241 vmas.push_back(rom);
242 vmas.push_back(vram);
243 vmas.push_back(ioamhram);
244 return vmas;
247 std::set<std::string> gambatte_srams()
249 std::set<std::string> s;
250 if(!internal_rom)
251 return s;
252 auto g = instance->getSaveRam();
253 if(g.second)
254 s.insert("main");
255 s.insert("rtc");
256 return s;
259 std::string get_cartridge_name()
261 std::ostringstream name;
262 if(romdata.size() < 0x200)
263 return ""; //Bad.
264 for(unsigned i = 0; i < 16; i++) {
265 if(romdata[0x134 + i])
266 name << (char)romdata[0x134 + i];
267 else
268 break;
270 return name.str();
273 void redraw_cover_fbinfo();
275 struct _gambatte_core : public core_core, public core_region
277 _gambatte_core()
278 : core_core({&psystem}, {
279 {0, "Soft reset", "reset", {}},
280 {1, "Change BG palette", "bgpalette", {
281 {"Color 0","string:[0-9A-Fa-f]{6}"},
282 {"Color 1","string:[0-9A-Fa-f]{6}"},
283 {"Color 2","string:[0-9A-Fa-f]{6}"},
284 {"Color 3","string:[0-9A-Fa-f]{6}"}
285 }},{2, "Change SP1 palette", "sp1palette", {
286 {"Color 0","string:[0-9A-Fa-f]{6}"},
287 {"Color 1","string:[0-9A-Fa-f]{6}"},
288 {"Color 2","string:[0-9A-Fa-f]{6}"},
289 {"Color 3","string:[0-9A-Fa-f]{6}"}
290 }}, {3, "Change SP2 palette", "sp2palette", {
291 {"Color 0","string:[0-9A-Fa-f]{6}"},
292 {"Color 1","string:[0-9A-Fa-f]{6}"},
293 {"Color 2","string:[0-9A-Fa-f]{6}"},
294 {"Color 3","string:[0-9A-Fa-f]{6}"}
297 core_region({{"world", "World", 0, 0, false, {4389, 262144}, {0}}}) {}
299 std::string c_core_identifier() { return "libgambatte "+gambatte::GB::version(); }
300 bool c_set_region(core_region& region) { return (&region == this); }
301 std::pair<uint32_t, uint32_t> c_video_rate() { return std::make_pair(262144, 4389); }
302 double c_get_PAR() { return 1.0; }
303 std::pair<uint32_t, uint32_t> c_audio_rate() {
304 if(output_native)
305 return std::make_pair(2097152, 1);
306 else
307 return std::make_pair(32768, 1);
309 std::map<std::string, std::vector<char>> c_save_sram() throw(std::bad_alloc) {
310 std::map<std::string, std::vector<char>> s;
311 if(!internal_rom)
312 return s;
313 auto g = instance->getSaveRam();
314 s["main"].resize(g.second);
315 memcpy(&s["main"][0], g.first, g.second);
316 s["rtc"].resize(8);
317 time_t timebase = instance->getRtcBase();
318 for(size_t i = 0; i < 8; i++)
319 s["rtc"][i] = ((unsigned long long)timebase >> (8 * i));
320 return s;
322 void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc) {
323 if(!internal_rom)
324 return;
325 std::vector<char> x = sram.count("main") ? sram["main"] : std::vector<char>();
326 std::vector<char> x2 = sram.count("rtc") ? sram["rtc"] : std::vector<char>();
327 auto g = instance->getSaveRam();
328 if(x.size()) {
329 if(x.size() != g.second)
330 messages << "WARNING: SRAM 'main': Loaded " << x.size()
331 << " bytes, but the SRAM is " << g.second << "." << std::endl;
332 memcpy(g.first, &x[0], min(x.size(), g.second));
334 if(x2.size()) {
335 time_t timebase = 0;
336 for(size_t i = 0; i < 8 && i < x2.size(); i++)
337 timebase |= (unsigned long long)(unsigned char)x2[i] << (8 * i);
338 instance->setRtcBase(timebase);
341 void c_serialize(std::vector<char>& out) {
342 if(!internal_rom)
343 throw std::runtime_error("Can't save without ROM");
344 instance->saveState(out);
345 size_t osize = out.size();
346 out.resize(osize + 4 * sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]));
347 for(size_t i = 0; i < sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]); i++)
348 write32ube(&out[osize + 4 * i], primary_framebuffer[i]);
349 out.push_back(frame_overflow >> 8);
350 out.push_back(frame_overflow);
352 void c_unserialize(const char* in, size_t insize) {
353 if(!internal_rom)
354 throw std::runtime_error("Can't load without ROM");
355 size_t foffset = insize - 2 - 4 * sizeof(primary_framebuffer) /
356 sizeof(primary_framebuffer[0]);
357 std::vector<char> tmp;
358 tmp.resize(foffset);
359 memcpy(&tmp[0], in, foffset);
360 instance->loadState(tmp);
361 for(size_t i = 0; i < sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]); i++)
362 primary_framebuffer[i] = read32ube(&in[foffset + 4 * i]);
364 unsigned x1 = (unsigned char)in[insize - 2];
365 unsigned x2 = (unsigned char)in[insize - 1];
366 frame_overflow = x1 * 256 + x2;
367 do_reset_flag = false;
369 core_region& c_get_region() { return *this; }
370 void c_power() {}
371 void c_unload_cartridge() {}
372 std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
373 return std::make_pair(max(512 / width, (uint32_t)1), max(448 / height, (uint32_t)1));
375 void c_install_handler() { magic_flags |= 2; }
376 void c_uninstall_handler() {}
377 void c_emulate() {
378 if(!internal_rom)
379 return;
380 bool native_rate = output_native;
381 int16_t reset = ecore_callbacks->get_input(0, 0, 1);
382 if(reset) {
383 instance->reset();
384 messages << "GB(C) reset" << std::endl;
386 do_reset_flag = false;
388 uint32_t samplebuffer[SAMPLES_PER_FRAME + 2064];
389 int16_t soundbuf[2 * (SAMPLES_PER_FRAME + 2064)];
390 size_t emitted = 0;
391 while(true) {
392 unsigned samples_emitted = SAMPLES_PER_FRAME - frame_overflow;
393 long ret = instance->runFor(primary_framebuffer, 160, samplebuffer, samples_emitted);
394 if(native_rate)
395 for(unsigned i = 0; i < samples_emitted; i++) {
396 soundbuf[emitted++] = (int16_t)(samplebuffer[i]);
397 soundbuf[emitted++] = (int16_t)(samplebuffer[i] >> 16);
399 else
400 for(unsigned i = 0; i < samples_emitted; i++) {
401 uint32_t l = (int32_t)(int16_t)(samplebuffer[i]) + 32768;
402 uint32_t r = (int32_t)(int16_t)(samplebuffer[i] >> 16) + 32768;
403 accumulator_l += l;
404 accumulator_r += r;
405 accumulator_s++;
406 if((accumulator_s & 63) == 0) {
407 int16_t l2 = (accumulator_l >> 6) - 32768;
408 int16_t r2 = (accumulator_r >> 6) - 32768;
409 soundbuf[emitted++] = l2;
410 soundbuf[emitted++] = r2;
411 accumulator_l = accumulator_r = 0;
412 accumulator_s = 0;
415 ecore_callbacks->timer_tick(samples_emitted, 2097152);
416 frame_overflow += samples_emitted;
417 if(frame_overflow >= SAMPLES_PER_FRAME) {
418 frame_overflow -= SAMPLES_PER_FRAME;
419 break;
422 framebuffer_info inf;
423 inf.type = &_pixel_format_rgb32;
424 inf.mem = const_cast<char*>(reinterpret_cast<const char*>(primary_framebuffer));
425 inf.physwidth = 160;
426 inf.physheight = 144;
427 inf.physstride = 640;
428 inf.width = 160;
429 inf.height = 144;
430 inf.stride = 640;
431 inf.offset_x = 0;
432 inf.offset_y = 0;
434 framebuffer_raw ls(inf);
435 ecore_callbacks->output_frame(ls, 262144, 4389);
436 audioapi_submit_buffer(soundbuf, emitted / 2, true, native_rate ? 2097152 : 32768);
438 void c_runtosave() {}
439 bool c_get_pflag() { return pflag; }
440 void c_set_pflag(bool _pflag) { pflag = _pflag; }
441 framebuffer_raw& c_draw_cover() {
442 static framebuffer_raw x(cover_fbinfo);
443 redraw_cover_fbinfo();
444 return x;
446 std::string c_get_core_shortname() { return "gambatte"+gambatte::GB::version(); }
447 void c_pre_emulate_frame(controller_frame& cf) {
448 cf.axis3(0, 0, 1, do_reset_flag ? 1 : 0);
450 void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p)
452 uint32_t a, b, c, d;
453 switch(id) {
454 case 0: //Soft reset.
455 do_reset_flag = true;
456 break;
457 case 1: //Change DMG BG palette.
458 case 2: //Change DMG SP1 palette.
459 case 3: //Change DMG SP2 palette.
460 a = strtoul(p[0].s.c_str(), NULL, 16);
461 b = strtoul(p[1].s.c_str(), NULL, 16);
462 c = strtoul(p[2].s.c_str(), NULL, 16);
463 d = strtoul(p[3].s.c_str(), NULL, 16);
464 if(instance) {
465 instance->setDmgPaletteColor(id - 1, 0, a);
466 instance->setDmgPaletteColor(id - 1, 1, b);
467 instance->setDmgPaletteColor(id - 1, 2, c);
468 instance->setDmgPaletteColor(id - 1, 3, d);
472 const interface_device_reg* c_get_registers() { return gb_registers; }
473 unsigned c_action_flags(unsigned id) { return (id < 4) ? 1 : 0; }
474 int c_reset_action(bool hard) { return hard ? -1 : 0; }
475 std::pair<uint64_t, uint64_t> c_get_bus_map()
477 return std::make_pair(0, 0);
479 std::list<core_vma_info> c_vma_list() { return get_VMAlist(); }
480 std::set<std::string> c_srams() { return gambatte_srams(); }
481 } gambatte_core;
483 struct _type_dmg : public core_type, public core_sysregion
485 _type_dmg()
486 : core_type({{
487 .iname = "dmg",
488 .hname = "Game Boy",
489 .id = 1,
490 .sysname = "Gameboy",
491 .bios = NULL,
492 .regions = {&gambatte_core},
493 .images = {{"rom", "Cartridge ROM", 1, 0, 0, "gb;dmg"}},
494 .settings = {},
495 .core = &gambatte_core,
496 }}),
497 core_sysregion("gdmg", *this, gambatte_core) {}
499 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
500 uint64_t secs, uint64_t subsecs)
502 return load_rom_common(img, gambatte::GB::FORCE_DMG, secs, subsecs, this);
504 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
506 return gambatte_controllerconfig(settings);
508 } type_dmg;
510 struct _type_gbc : public core_type, public core_sysregion
512 _type_gbc()
513 : core_type({{
514 .iname = "gbc",
515 .hname = "Game Boy Color",
516 .id = 0,
517 .sysname = "Gameboy",
518 .bios = NULL,
519 .regions = {&gambatte_core},
520 .images = {{"rom", "Cartridge ROM", 1, 0, 0, "gbc;cgb"}},
521 .settings = {},
522 .core = &gambatte_core,
523 }}),
524 core_sysregion("ggbc", *this, gambatte_core) {}
526 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
527 uint64_t secs, uint64_t subsecs)
529 return load_rom_common(img, 0, secs, subsecs, this);
531 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
533 return gambatte_controllerconfig(settings);
535 } type_gbc;
537 struct _type_gbca : public core_type, public core_sysregion
539 _type_gbca()
540 : core_type({{
541 .iname = "gbc_gba",
542 .hname = "Game Boy Color (GBA)",
543 .id = 2,
544 .sysname = "Gameboy",
545 .bios = NULL,
546 .regions = {&gambatte_core},
547 .images = {{"rom", "Cartridge ROM", 1, 0, 0, ""}},
548 .settings = {},
549 .core = &gambatte_core,
550 }}),
551 core_sysregion("ggbca", *this, gambatte_core) {}
553 int t_load_rom(core_romimage* img, std::map<std::string, std::string>& settings,
554 uint64_t secs, uint64_t subsecs)
556 return load_rom_common(img, gambatte::GB::GBA_CGB, secs, subsecs, this);
558 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
560 return gambatte_controllerconfig(settings);
562 } type_gbca;
564 void redraw_cover_fbinfo()
566 for(size_t i = 0; i < sizeof(cover_fbmem) / sizeof(cover_fbmem[0]); i++)
567 cover_fbmem[i] = 0x00000000;
568 std::string ident = gambatte_core.get_core_identifier();
569 cover_render_string(cover_fbmem, 0, 0, ident, 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
570 cover_render_string(cover_fbmem, 0, 16, "Internal ROM name: " + get_cartridge_name(),
571 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
572 unsigned y = 32;
573 for(auto i : cover_information()) {
574 cover_render_string(cover_fbmem, 0, y, i, 0xFFFFFF, 0x000000, 480, 432, 1920, 4);
575 y += 16;
579 std::vector<char> cmp_save;
581 function_ptr_command<> cmp_save1(lsnes_cmd, "set-cmp-save", "", "\n", []() throw(std::bad_alloc,
582 std::runtime_error) {
583 if(!internal_rom)
584 return;
585 instance->saveState(cmp_save);
588 function_ptr_command<> cmp_save2(lsnes_cmd, "do-cmp-save", "", "\n", []() throw(std::bad_alloc,
589 std::runtime_error) {
590 std::vector<char> x;
591 if(!internal_rom)
592 return;
593 instance->saveState(x, cmp_save);
596 struct oninit {
597 oninit()
599 register_sysregion_mapping("gdmg", "GB");
600 register_sysregion_mapping("ggbc", "GBC");
601 register_sysregion_mapping("ggbca", "GBC");
603 } _oninit;