Gambatte: Clean up unused stuff
[lsnes.git] / src / emulation / gambatte / core.cpp
blob130c4605a471ae84273ed48234112a3259f202f4
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/framebuffer.hpp"
30 #include "core/window.hpp"
31 #include "interface/callbacks.hpp"
32 #include "interface/cover.hpp"
33 #include "interface/romtype.hpp"
34 #include "library/pixfmt-rgb32.hpp"
35 #include "library/string.hpp"
36 #include "library/portfn.hpp"
37 #include "library/serialization.hpp"
38 #include "library/minmax.hpp"
39 #include "library/framebuffer.hpp"
40 #define HAVE_CSTDINT
41 #include "libgambatte/include/gambatte.h"
43 #define SAMPLES_PER_FRAME 35112
45 namespace
47 bool do_reset_flag = false;
48 core_type* internal_rom = NULL;
49 extern core_core_params _gambatte_core;
50 bool rtc_fixed;
51 time_t rtc_fixed_val;
52 gambatte::GB* instance;
53 unsigned frame_overflow = 0;
54 std::vector<unsigned char> romdata;
55 uint32_t cover_fbmem[480 * 432];
56 uint32_t primary_framebuffer[160*144];
57 uint32_t accumulator_l = 0;
58 uint32_t accumulator_r = 0;
59 unsigned accumulator_s = 0;
60 bool pflag = false;
62 //Framebuffer.
63 struct framebuffer_info cover_fbinfo = {
64 &_pixel_format_rgb32, //Format.
65 (char*)cover_fbmem, //Memory.
66 480, 432, 1920, //Physical size.
67 480, 432, 1920, //Logical size.
68 0, 0 //Offset.
71 #include "ports.inc"
72 #include "slots.inc"
73 #include "regions.inc"
75 core_setting_group gambatte_settings;
77 time_t walltime_fn()
79 if(rtc_fixed)
80 return rtc_fixed_val;
81 if(ecore_callbacks)
82 return ecore_callbacks->get_time();
83 else
84 return time(0);
87 class myinput : public gambatte::InputGetter
89 public:
90 unsigned operator()()
92 unsigned v = 0;
93 for(unsigned i = 0; i < 8; i++) {
94 if(ecore_callbacks->get_input(0, 1, i))
95 v |= (1 << i);
97 pflag = true;
98 return v;
100 } getinput;
102 void basic_init()
104 static bool done = false;
105 if(done)
106 return;
107 done = true;
108 instance = new gambatte::GB;
109 instance->setInputGetter(&getinput);
110 instance->set_walltime_fn(walltime_fn);
113 int load_rom_common(core_romimage* img, unsigned flags, uint64_t rtc_sec, uint64_t rtc_subsec,
114 core_type* inttype)
116 basic_init();
117 const char* markup = img[0].markup;
118 int flags2 = 0;
119 if(markup) {
120 flags2 = atoi(markup);
121 flags2 &= 4;
123 flags |= flags2;
124 const unsigned char* data = img[0].data;
125 size_t size = img[0].size;
127 //Reset it really.
128 instance->~GB();
129 memset(instance, 0, sizeof(gambatte::GB));
130 new(instance) gambatte::GB;
131 instance->setInputGetter(&getinput);
132 instance->set_walltime_fn(walltime_fn);
133 memset(primary_framebuffer, 0, sizeof(primary_framebuffer));
134 frame_overflow = 0;
136 rtc_fixed = true;
137 rtc_fixed_val = rtc_sec;
138 instance->load(data, size, flags);
139 rtc_fixed = false;
140 romdata.resize(size);
141 memcpy(&romdata[0], data, size);
142 internal_rom = inttype;
143 do_reset_flag = false;
144 return 1;
147 port_index_triple t(unsigned p, unsigned c, unsigned i, bool nl)
149 port_index_triple x;
150 x.valid = true;
151 x.port = p;
152 x.controller = c;
153 x.control = i;
154 return x;
157 controller_set _controllerconfig(std::map<std::string, std::string>& settings)
159 std::map<std::string, std::string> _settings = settings;
160 controller_set r;
161 r.ports.push_back(&psystem);
162 for(unsigned i = 0; i < 4; i++)
163 r.portindex.indices.push_back(t(0, 0, i, false));
164 for(unsigned i = 0; i < 8; i++)
165 r.portindex.indices.push_back(t(0, 1, i, true));
166 r.portindex.logical_map.push_back(std::make_pair(0, 1));
167 r.portindex.pcid_map.push_back(std::make_pair(0, 1));
168 return r;
171 std::pair<uint64_t, uint64_t> gambatte_bus_map()
173 return std::make_pair(0, 0);
176 std::list<core_vma_info> get_VMAlist()
178 std::list<core_vma_info> vmas;
179 if(!internal_rom)
180 return vmas;
181 core_vma_info sram;
182 core_vma_info wram;
183 core_vma_info vram;
184 core_vma_info ioamhram;
185 core_vma_info rom;
187 auto g = instance->getSaveRam();
188 sram.name = "SRAM";
189 sram.base = 0x20000;
190 sram.size = g.second;
191 sram.backing_ram = g.first;
192 sram.endian = -1;
193 sram.readonly = false;
194 sram.iospace_rw = NULL;
196 auto g2 = instance->getWorkRam();
197 wram.name = "WRAM";
198 wram.base = 0;
199 wram.size = g2.second;
200 wram.backing_ram = g2.first;
201 wram.endian = -1;
202 wram.readonly = false;
203 wram.iospace_rw = NULL;
205 auto g3 = instance->getVideoRam();
206 vram.name = "VRAM";
207 vram.base = 0x10000;
208 vram.size = g3.second;
209 vram.backing_ram = g3.first;
210 vram.endian = -1;
211 vram.readonly = false;
212 vram.iospace_rw = NULL;
214 auto g4 = instance->getIoRam();
215 ioamhram.name = "IOAMHRAM";
216 ioamhram.base = 0x18000;
217 ioamhram.size = g4.second;
218 ioamhram.backing_ram = g4.first;
219 ioamhram.endian = -1;
220 ioamhram.readonly = false;
221 ioamhram.iospace_rw = NULL;
223 rom.name = "ROM";
224 rom.base = 0x80000000;
225 rom.size = romdata.size();
226 rom.backing_ram = (void*)&romdata[0];
227 rom.endian = -1;
228 rom.readonly = true;
229 rom.iospace_rw = NULL;
231 if(sram.size)
232 vmas.push_back(sram);
233 vmas.push_back(wram);
234 vmas.push_back(rom);
235 vmas.push_back(vram);
236 vmas.push_back(ioamhram);
237 return vmas;
240 std::set<std::string> srams()
242 std::set<std::string> s;
243 if(!internal_rom)
244 return s;
245 auto g = instance->getSaveRam();
246 if(g.second)
247 s.insert("main");
248 s.insert("rtc");
249 return s;
252 std::string get_cartridge_name()
254 std::ostringstream name;
255 if(romdata.size() < 0x200)
256 return ""; //Bad.
257 for(unsigned i = 0; i < 16; i++) {
258 if(romdata[0x134 + i])
259 name << (char)romdata[0x134 + i];
260 else
261 break;
263 return name.str();
266 void redraw_cover_fbinfo()
268 for(size_t i = 0; i < sizeof(cover_fbmem) / sizeof(cover_fbmem[0]); i++)
269 cover_fbmem[i] = 0x00000000;
270 std::string ident = _gambatte_core.core_identifier();
271 cover_render_string(cover_fbmem, 0, 0, ident, 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
272 cover_render_string(cover_fbmem, 0, 16, "Internal ROM name: " + get_cartridge_name(),
273 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
274 unsigned y = 32;
275 for(auto i : cover_information()) {
276 cover_render_string(cover_fbmem, 0, y, i, 0xFFFFFF, 0x000000, 480, 432, 1920, 4);
277 y += 16;
281 core_core_params _gambatte_core = {
282 .core_identifier = []() -> std::string { return "libgambatte "+gambatte::GB::version(); },
283 .set_region = [](core_region& region) -> bool { return (&region == &region_world); },
284 .video_rate = []() -> std::pair<uint32_t, uint32_t> { return std::make_pair(262144, 4389); },
285 .audio_rate = []() -> std::pair<uint32_t, uint32_t> { return std::make_pair(32768, 1); },
286 .snes_rate = NULL,
287 .save_sram = []() -> std::map<std::string, std::vector<char>> {
288 std::map<std::string, std::vector<char>> s;
289 if(!internal_rom)
290 return s;
291 auto g = instance->getSaveRam();
292 s["main"].resize(g.second);
293 memcpy(&s["main"][0], g.first, g.second);
294 s["rtc"].resize(8);
295 time_t timebase = instance->getRtcBase();
296 for(size_t i = 0; i < 8; i++)
297 s["rtc"][i] = ((unsigned long long)timebase >> (8 * i));
298 return s;
300 .load_sram = [](std::map<std::string, std::vector<char>>& sram) -> void {
301 if(!internal_rom)
302 return;
303 std::vector<char> x = sram.count("main") ? sram["main"] : std::vector<char>();
304 std::vector<char> x2 = sram.count("rtc") ? sram["rtc"] : std::vector<char>();
305 auto g = instance->getSaveRam();
306 if(x.size()) {
307 if(x.size() != g.second)
308 messages << "WARNING: SRAM 'main': Loaded " << x.size()
309 << " bytes, but the SRAM is " << g.second << "." << std::endl;
310 memcpy(g.first, &x[0], min(x.size(), g.second));
312 if(x2.size()) {
313 time_t timebase = 0;
314 for(size_t i = 0; i < 8 && i < x2.size(); i++)
315 timebase |= (unsigned long long)(unsigned char)x2[i] << (8 * i);
316 instance->setRtcBase(timebase);
319 .serialize = [](std::vector<char>& out) -> void {
320 if(!internal_rom)
321 throw std::runtime_error("Can't save without ROM");
322 instance->saveState(out);
323 size_t osize = out.size();
324 out.resize(osize + 4 * sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]));
325 for(size_t i = 0; i < sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]); i++)
326 write32ube(&out[osize + 4 * i], primary_framebuffer[i]);
327 out.push_back(frame_overflow >> 8);
328 out.push_back(frame_overflow);
330 .unserialize = [](const char* in, size_t insize) -> void {
331 if(!internal_rom)
332 throw std::runtime_error("Can't load without ROM");
333 size_t foffset = insize - 2 - 4 * sizeof(primary_framebuffer) /
334 sizeof(primary_framebuffer[0]);
335 std::vector<char> tmp;
336 tmp.resize(foffset);
337 memcpy(&tmp[0], in, foffset);
338 instance->loadState(tmp);
339 for(size_t i = 0; i < sizeof(primary_framebuffer) / sizeof(primary_framebuffer[0]); i++)
340 primary_framebuffer[i] = read32ube(&in[foffset + 4 * i]);
342 unsigned x1 = (unsigned char)in[insize - 2];
343 unsigned x2 = (unsigned char)in[insize - 1];
344 frame_overflow = x1 * 256 + x2;
345 do_reset_flag = false;
347 .get_region = []() -> core_region& { return region_world; },
348 .power = []() -> void {},
349 .unload_cartridge = []() -> void {},
350 .get_scale_factors = [](uint32_t width, uint32_t height) -> std::pair<uint32_t, uint32_t> {
351 return std::make_pair(max(512 / width, (uint32_t)1), max(448 / height, (uint32_t)1));
353 .install_handler = []() -> void { magic_flags |= 2; },
354 .uninstall_handler = []() -> void {},
355 .emulate = []() -> void {
356 if(!internal_rom)
357 return;
358 int16_t reset = ecore_callbacks->get_input(0, 0, 1);
359 if(reset) {
360 instance->reset();
361 messages << "GB(C) reset" << std::endl;
363 do_reset_flag = false;
365 uint32_t samplebuffer[SAMPLES_PER_FRAME + 2064];
366 while(true) {
367 int16_t soundbuf[(SAMPLES_PER_FRAME + 63) / 32 + 66];
368 size_t emitted = 0;
369 unsigned samples_emitted = SAMPLES_PER_FRAME - frame_overflow;
370 long ret = instance->runFor(primary_framebuffer, 160, samplebuffer, samples_emitted);
371 for(unsigned i = 0; i < samples_emitted; i++) {
372 uint32_t l = (int32_t)(int16_t)(samplebuffer[i]) + 32768;
373 uint32_t r = (int32_t)(int16_t)(samplebuffer[i] >> 16) + 32768;
374 accumulator_l += l;
375 accumulator_r += r;
376 accumulator_s++;
377 if((accumulator_s & 63) == 0) {
378 int16_t l2 = (accumulator_l >> 6) - 32768;
379 int16_t r2 = (accumulator_r >> 6) - 32768;
380 soundbuf[emitted++] = l2;
381 soundbuf[emitted++] = r2;
382 information_dispatch::do_sample(l2, r2);
383 accumulator_l = accumulator_r = 0;
384 accumulator_s = 0;
387 audioapi_submit_buffer(soundbuf, emitted / 2, true, 32768);
388 ecore_callbacks->timer_tick(samples_emitted, 2097152);
389 frame_overflow += samples_emitted;
390 if(frame_overflow >= SAMPLES_PER_FRAME) {
391 frame_overflow -= SAMPLES_PER_FRAME;
392 break;
395 framebuffer_info inf;
396 inf.type = &_pixel_format_rgb32;
397 inf.mem = const_cast<char*>(reinterpret_cast<const char*>(primary_framebuffer));
398 inf.physwidth = 160;
399 inf.physheight = 144;
400 inf.physstride = 640;
401 inf.width = 160;
402 inf.height = 144;
403 inf.stride = 640;
404 inf.offset_x = 0;
405 inf.offset_y = 0;
407 framebuffer_raw ls(inf);
408 ecore_callbacks->output_frame(ls, 262144, 4389);
410 .runtosave = []() -> void {},
411 .get_pflag = []() -> bool { return pflag; },
412 .set_pflag = [](bool _pflag) -> void { pflag = _pflag; },
413 .request_reset = [](long delay, bool hard) -> void { do_reset_flag = true; },
414 .port_types = port_types,
415 .draw_cover = []() -> framebuffer_raw& {
416 static framebuffer_raw x(cover_fbinfo);
417 redraw_cover_fbinfo();
418 return x;
420 .get_core_shortname = []() -> std::string { return "gambatte"+gambatte::GB::version(); },
421 .pre_emulate_frame = [](controller_frame& cf) -> void {
422 cf.axis3(0, 0, 1, do_reset_flag ? 1 : 0);
426 core_core gambatte_core(_gambatte_core);
428 core_type_params _type_dmg = {
429 .iname = "dmg", .hname = "Game Boy", .id = 1, .reset_support = 1,
430 .load_rom = [](core_romimage* img, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
431 uint64_t rtc_subsec) -> int {
432 return load_rom_common(img, gambatte::GB::FORCE_DMG, rtc_sec, rtc_subsec, &type_dmg);
434 .controllerconfig = _controllerconfig, .extensions = "gb;dmg", .bios = NULL, .regions = dmg_regions,
435 .images = dmg_images, .settings = &gambatte_settings, .core = &gambatte_core,
436 .get_bus_map = gambatte_bus_map, .vma_list = get_VMAlist, .srams = srams
438 core_type_params _type_gbc = {
439 .iname = "gbc", .hname = "Game Boy Color", .id = 0, .reset_support = 1,
440 .load_rom = [](core_romimage* img, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
441 uint64_t rtc_subsec) -> int {
442 return load_rom_common(img, 0, rtc_sec, rtc_subsec, &type_gbc);
444 .controllerconfig = _controllerconfig, .extensions = "gbc;cgb", .bios = NULL, .regions = gbc_regions,
445 .images = gbc_images, .settings = &gambatte_settings, .core = &gambatte_core,
446 .get_bus_map = gambatte_bus_map, .vma_list = get_VMAlist, .srams = srams
448 core_type_params _type_gbca = {
449 .iname = "gbc_gba", .hname = "Game Boy Color (GBA)", .id = 2, .reset_support = 1,
450 .load_rom = [](core_romimage* img, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
451 uint64_t rtc_subsec) -> int {
452 return load_rom_common(img, gambatte::GB::GBA_CGB, rtc_sec, rtc_subsec, &type_gbca);
454 .controllerconfig = _controllerconfig, .extensions = "", .bios = NULL, .regions = gbca_regions,
455 .images = gbca_images, .settings = &gambatte_settings, .core = &gambatte_core,
456 .get_bus_map = gambatte_bus_map, .vma_list = get_VMAlist, .srams = srams
459 core_type type_dmg(_type_dmg);
460 core_type type_gbc(_type_gbc);
461 core_type type_gbca(_type_gbca);
463 std::vector<char> cmp_save;
465 function_ptr_command<> cmp_save1(lsnes_cmd, "set-cmp-save", "", "\n", []() throw(std::bad_alloc,
466 std::runtime_error) {
467 if(!internal_rom)
468 return;
469 instance->saveState(cmp_save);
472 function_ptr_command<> cmp_save2(lsnes_cmd, "do-cmp-save", "", "\n", []() throw(std::bad_alloc,
473 std::runtime_error) {
474 std::vector<char> x;
475 if(!internal_rom)
476 return;
477 instance->saveState(x, cmp_save);