1 /***************************************************************************
2 * Copyright (C) 2012-2013 by Ilari Liusvaara *
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. *
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. *
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 ***************************************************************************/
25 #include "disassemble-gb.hpp"
26 #include "core/audioapi.hpp"
27 #include "core/misc.hpp"
28 #include "core/command.hpp"
29 #include "core/controllerframe.hpp"
30 #include "core/dispatch.hpp"
31 #include "core/settings.hpp"
32 #include "core/framebuffer.hpp"
33 #include "core/instance.hpp"
34 #include "core/messages.hpp"
35 #include "interface/callbacks.hpp"
36 #include "interface/cover.hpp"
37 #include "interface/romtype.hpp"
38 #include "library/framebuffer-pixfmt-rgb32.hpp"
39 #include "library/hex.hpp"
40 #include "library/string.hpp"
41 #include "library/portctrl-data.hpp"
42 #include "library/serialization.hpp"
43 #include "library/minmax.hpp"
44 #include "library/framebuffer.hpp"
45 #include "library/lua-base.hpp"
46 #include "library/lua-params.hpp"
47 #include "library/lua-function.hpp"
48 #include "lua/internal.hpp"
50 #include "libgambatte/include/gambatte.h"
52 #define SAMPLES_PER_FRAME 35112
56 settingvar::supervariable
<settingvar::model_bool
<settingvar::yes_no
>> output_native(lsnes_setgrp
,
57 "gambatte-native-sound", "Gambatteā£Sound Output at native rate", false);
58 settingvar::supervariable
<settingvar::model_bool
<settingvar::yes_no
>> gbchawk_timings(lsnes_setgrp
,
59 "gambatte-gbchawk-fuckup", "Gambatteā£Use old GBCHawk timings", false);
61 bool do_reset_flag
= false;
62 core_type
* internal_rom
= NULL
;
65 gambatte::GB
* instance
;
66 bool reallocate_debug
= false;
67 bool sigillcrash
= false;
68 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
69 gambatte::debugbuffer debugbuf
;
73 unsigned frame_overflow
= 0;
74 std::vector
<unsigned char> romdata
;
75 std::vector
<char> init_savestate
;
76 uint32_t cover_fbmem
[480 * 432];
77 uint32_t primary_framebuffer
[160*144];
78 uint32_t accumulator_l
= 0;
79 uint32_t accumulator_r
= 0;
80 unsigned accumulator_s
= 0;
82 bool disable_breakpoints
= false;
83 bool palette_colors_default
[3] = {true, true, true};
84 uint32_t palette_colors
[12];
85 uint32_t last_tsc_increment
= 0;
87 struct interface_device_reg gb_registers
[] = {
88 {"wrambank", []() -> uint64_t { return instance
? instance
->getIoRam().first
[0x170] & 0x07 : 0; },
90 {"cyclecount", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_CYCLECOUNTER
); },
92 {"pc", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_PC
); },
93 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_PC
, v
); }},
94 {"sp", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_SP
); },
95 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_SP
, v
); }},
96 {"hf1", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_HF1
); },
97 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_HF1
, v
); }},
98 {"hf2", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_HF2
); },
99 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_HF2
, v
); }},
100 {"zf", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_ZF
); },
101 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_ZF
, v
); }},
102 {"cf", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_CF
); },
103 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_CF
, v
); }},
104 {"a", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_A
); },
105 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_A
, v
); }},
106 {"b", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_B
); },
107 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_B
, v
); }},
108 {"c", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_C
); },
109 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_C
, v
); }},
110 {"d", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_D
); },
111 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_D
, v
); }},
112 {"e", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_E
); },
113 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_E
, v
); }},
114 {"f", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_F
); },
115 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_F
, v
); }},
116 {"h", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_H
); },
117 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_H
, v
); }},
118 {"l", []() -> uint64_t { return instance
->get_cpureg(gambatte::GB::REG_L
); },
119 [](uint64_t v
) { instance
->set_cpureg(gambatte::GB::REG_L
, v
); }},
124 struct framebuffer::info cover_fbinfo
= {
125 &framebuffer::pixfmt_rgb32
, //Format.
126 (char*)cover_fbmem
, //Memory.
127 480, 432, 1920, //Physical size.
128 480, 432, 1920, //Logical size.
137 return rtc_fixed_val
;
139 return ecore_callbacks
->get_time();
144 class myinput
: public gambatte::InputGetter
147 unsigned operator()()
150 for(unsigned i
= 0; i
< 8; i
++) {
151 if(ecore_callbacks
->get_input(0, 1, i
))
159 uint64_t get_address(unsigned clazz
, unsigned offset
)
162 case 0: return 0x1000000 + offset
; //BUS.
163 case 1: return offset
; //WRAM.
164 case 2: return 0x18000 + offset
; //IOAMHRAM
165 case 3: return 0x80000000 + offset
; //ROM
166 case 4: return 0x20000 + offset
; //SRAM.
168 return 0xFFFFFFFFFFFFFFFF;
171 void gambatte_read_handler(unsigned clazz
, unsigned offset
, uint8_t value
, bool exec
)
173 if(disable_breakpoints
) return;
174 uint64_t _addr
= get_address(clazz
, offset
);
175 if(_addr
!= 0xFFFFFFFFFFFFFFFFULL
) {
177 ecore_callbacks
->memory_execute(_addr
, 0);
179 ecore_callbacks
->memory_read(_addr
, value
);
183 void gambatte_write_handler(unsigned clazz
, unsigned offset
, uint8_t value
)
185 if(disable_breakpoints
) return;
186 uint64_t _addr
= get_address(clazz
, offset
);
187 if(_addr
!= 0xFFFFFFFFFFFFFFFFULL
)
188 ecore_callbacks
->memory_write(_addr
, value
);
191 int get_hl(gambatte::GB
* instance
)
193 return instance
->get_cpureg(gambatte::GB::REG_H
) * 256 +
194 instance
->get_cpureg(gambatte::GB::REG_L
);
197 int get_bc(gambatte::GB
* instance
)
199 return instance
->get_cpureg(gambatte::GB::REG_B
) * 256 +
200 instance
->get_cpureg(gambatte::GB::REG_C
);
203 int get_de(gambatte::GB
* instance
)
205 return instance
->get_cpureg(gambatte::GB::REG_D
) * 256 +
206 instance
->get_cpureg(gambatte::GB::REG_E
);
209 //0 => None or already done.
216 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
217 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //0
218 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, //1
219 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, //2
220 0, 0, 3, 0, 3, 3, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, //3
221 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //4
222 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //5
223 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //6
224 3, 3, 3, 3, 3, 3, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, //7
225 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //8
226 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //9
227 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //A
228 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, //B
229 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, //C
230 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //D
231 0, 0, 4, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, //E
232 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //F.
235 const char* hexch
= "0123456789abcdef";
236 inline void buffer_h8(char*& ptr
, uint8_t v
)
238 *(ptr
++) = hexch
[v
>> 4];
239 *(ptr
++) = hexch
[v
& 15];
242 inline void buffer_h16(char*& ptr
, uint16_t v
)
244 *(ptr
++) = hexch
[v
>> 12];
245 *(ptr
++) = hexch
[(v
>> 8) & 15];
246 *(ptr
++) = hexch
[(v
>> 4) & 15];
247 *(ptr
++) = hexch
[v
& 15];
250 inline void buffer_str(char*& ptr
, const char* str
)
256 void gambatte_trace_handler(uint16_t _pc
)
258 static char buffer
[512];
259 char* buffer_ptr
= buffer
;
264 std::function
<uint8_t()> fetch
= [pc
, &offset
, &buffer_ptr
]() -> uint8_t {
265 unsigned addr
= pc
+ offset
++;
267 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
268 disable_breakpoints
= true;
269 v
= instance
->bus_read(addr
);
270 disable_breakpoints
= false;
272 buffer_h8(buffer_ptr
, v
);
275 buffer_h16(buffer_ptr
, pc
);
276 *(buffer_ptr
++) = ' ';
277 auto d
= disassemble_gb_opcode(pc
, fetch
, addr
, opcode
);
278 while(buffer_ptr
< buffer
+ 12)
279 *(buffer_ptr
++) = ' ';
280 buffer_str(buffer_ptr
, d
.c_str());
281 switch(memclass
[opcode
>> 8]) {
282 case 1: addr
= get_bc(instance
); break;
283 case 2: addr
= get_de(instance
); break;
284 case 3: addr
= get_hl(instance
); break;
285 case 4: addr
= 0xFF00 + instance
->get_cpureg(gambatte::GB::REG_C
); break;
286 case 5: if((opcode
& 7) == 6) addr
= get_hl(instance
); break;
288 while(buffer_ptr
< buffer
+ 28)
289 *(buffer_ptr
++) = ' ';
291 buffer_str(buffer_ptr
, "[");
292 buffer_h16(buffer_ptr
, addr
);
293 buffer_str(buffer_ptr
, "]");
295 buffer_str(buffer_ptr
, " ");
297 buffer_str(buffer_ptr
, "A:");
298 buffer_h8(buffer_ptr
, instance
->get_cpureg(gambatte::GB::REG_A
));
299 buffer_str(buffer_ptr
, " B:");
300 buffer_h8(buffer_ptr
, instance
->get_cpureg(gambatte::GB::REG_B
));
301 buffer_str(buffer_ptr
, " C:");
302 buffer_h8(buffer_ptr
, instance
->get_cpureg(gambatte::GB::REG_C
));
303 buffer_str(buffer_ptr
, " D:");
304 buffer_h8(buffer_ptr
, instance
->get_cpureg(gambatte::GB::REG_D
));
305 buffer_str(buffer_ptr
, " E:");
306 buffer_h8(buffer_ptr
, instance
->get_cpureg(gambatte::GB::REG_E
));
307 buffer_str(buffer_ptr
, " H:");
308 buffer_h8(buffer_ptr
, instance
->get_cpureg(gambatte::GB::REG_H
));
309 buffer_str(buffer_ptr
, " L:");
310 buffer_h8(buffer_ptr
, instance
->get_cpureg(gambatte::GB::REG_L
));
311 buffer_str(buffer_ptr
, " SP:");
312 buffer_h16(buffer_ptr
, instance
->get_cpureg(gambatte::GB::REG_SP
));
313 buffer_str(buffer_ptr
, " F:");
314 *(buffer_ptr
++) = instance
->get_cpureg(gambatte::GB::REG_CF
) ? 'C' : '-';
315 *(buffer_ptr
++) = instance
->get_cpureg(gambatte::GB::REG_ZF
) ? '-' : 'Z';
316 *(buffer_ptr
++) = instance
->get_cpureg(gambatte::GB::REG_HF1
) ? '1' : '-';
317 *(buffer_ptr
++) = instance
->get_cpureg(gambatte::GB::REG_HF2
) ? '2' : '-';
318 *(buffer_ptr
++) = '\0';
319 ecore_callbacks
->memory_trace(0, buffer
, true);
324 static bool done
= false;
328 instance
= new gambatte::GB
;
329 instance
->setInputGetter(&getinput
);
330 instance
->set_walltime_fn(walltime_fn
);
331 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
332 uint8_t* tmp
= new uint8_t[98816];
333 memset(tmp
, 0, 98816);
335 debugbuf
.bus
= tmp
+ 32768;
336 debugbuf
.ioamhram
= tmp
+ 98304;
337 debugbuf
.read
= gambatte_read_handler
;
338 debugbuf
.write
= gambatte_write_handler
;
339 debugbuf
.trace
= gambatte_trace_handler
;
340 debugbuf
.trace_cpu
= false;
341 instance
->set_debug_buffer(debugbuf
);
345 int load_rom_common(core_romimage
* img
, unsigned flags
, uint64_t rtc_sec
, uint64_t rtc_subsec
,
346 core_type
* inttype
, std::map
<std::string
, std::string
>& settings
)
349 const char* markup
= img
[0].markup
;
352 flags2
= atoi(markup
);
356 const unsigned char* data
= img
[0].data
;
357 size_t size
= img
[0].size
;
361 memset(instance
, 0, sizeof(gambatte::GB
));
362 new(instance
) gambatte::GB
;
363 instance
->setInputGetter(&getinput
);
364 instance
->set_walltime_fn(walltime_fn
);
365 memset(primary_framebuffer
, 0, sizeof(primary_framebuffer
));
369 rtc_fixed_val
= rtc_sec
;
370 instance
->load(data
, size
, flags
);
371 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
372 size_t sramsize
= instance
->getSaveRam().second
;
373 size_t romsize
= size
;
374 if(reallocate_debug
|| cur_ramsize
!= sramsize
|| cur_romsize
!= romsize
) {
375 if(debugbuf
.cart
) delete[] debugbuf
.cart
;
376 if(debugbuf
.sram
) delete[] debugbuf
.sram
;
377 debugbuf
.cart
= NULL
;
378 debugbuf
.sram
= NULL
;
379 if(sramsize
) debugbuf
.sram
= new uint8_t[(sramsize
+ 4095) >> 12 << 12];
380 if(romsize
) debugbuf
.cart
= new uint8_t[(romsize
+ 4095) >> 12 << 12];
381 if(sramsize
) memset(debugbuf
.sram
, 0, (sramsize
+ 4095) >> 12 << 12);
382 if(romsize
) memset(debugbuf
.cart
, 0, (romsize
+ 4095) >> 12 << 12);
383 memset(debugbuf
.wram
, 0, 32768);
384 memset(debugbuf
.ioamhram
, 0, 512);
385 debugbuf
.wramcheat
.clear();
386 debugbuf
.sramcheat
.clear();
387 debugbuf
.cartcheat
.clear();
388 debugbuf
.trace_cpu
= false;
389 reallocate_debug
= false;
390 cur_ramsize
= sramsize
;
391 cur_romsize
= romsize
;
393 instance
->set_debug_buffer(debugbuf
);
396 #ifdef GAMBATTE_SUPPORTS_EMU_FLAGS
397 unsigned emuflags
= 0;
398 if(settings
.count("sigillcrash") && settings
["sigillcrash"] == "1")
400 sigillcrash
= (emuflags
& 1);
401 instance
->set_emuflags(emuflags
);
404 romdata
.resize(size
);
405 memcpy(&romdata
[0], data
, size
);
406 internal_rom
= inttype
;
407 do_reset_flag
= false;
409 for(unsigned i
= 0; i
< 12; i
++)
410 if(!palette_colors_default
[i
>> 2])
411 instance
->setDmgPaletteColor(i
>> 2, i
& 3, palette_colors
[i
]);
412 //Save initial savestate.
413 instance
->saveState(init_savestate
);
417 controller_set
gambatte_controllerconfig(std::map
<std::string
, std::string
>& settings
)
419 std::map
<std::string
, std::string
> _settings
= settings
;
421 r
.ports
.push_back(&psystem
);
422 r
.logical_map
.push_back(std::make_pair(0, 1));
426 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
427 uint8_t gambatte_bus_read(uint64_t offset
)
429 disable_breakpoints
= true;
430 uint8_t val
= instance
->bus_read(offset
);
431 disable_breakpoints
= false;
435 void gambatte_bus_write(uint64_t offset
, uint8_t data
)
437 disable_breakpoints
= true;
438 instance
->bus_write(offset
, data
);
439 disable_breakpoints
= false;
443 std::list
<core_vma_info
> get_VMAlist()
445 std::list
<core_vma_info
> vmas
;
451 core_vma_info ioamhram
;
455 auto g
= instance
->getSaveRam();
458 sram
.size
= g
.second
;
459 sram
.backing_ram
= g
.first
;
462 auto g2
= instance
->getWorkRam();
465 wram
.size
= g2
.second
;
466 wram
.backing_ram
= g2
.first
;
469 auto g3
= instance
->getVideoRam();
472 vram
.size
= g3
.second
;
473 vram
.backing_ram
= g3
.first
;
476 auto g4
= instance
->getIoRam();
477 ioamhram
.name
= "IOAMHRAM";
478 ioamhram
.base
= 0x18000;
479 ioamhram
.size
= g4
.second
;
480 ioamhram
.backing_ram
= g4
.first
;
481 ioamhram
.endian
= -1;
484 rom
.base
= 0x80000000;
485 rom
.size
= romdata
.size();
486 rom
.backing_ram
= (void*)&romdata
[0];
491 vmas
.push_back(sram
);
492 vmas
.push_back(wram
);
494 vmas
.push_back(vram
);
495 vmas
.push_back(ioamhram
);
496 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
498 bus
.base
= 0x1000000;
500 bus
.backing_ram
= NULL
;
501 bus
.read
= gambatte_bus_read
;
502 bus
.write
= gambatte_bus_write
;
510 std::set
<std::string
> gambatte_srams()
512 std::set
<std::string
> s
;
515 auto g
= instance
->getSaveRam();
522 std::string
get_cartridge_name()
524 std::ostringstream name
;
525 if(romdata
.size() < 0x200)
527 for(unsigned i
= 0; i
< 16; i
++) {
528 if(romdata
[0x134 + i
])
529 name
<< (char)romdata
[0x134 + i
];
536 void redraw_cover_fbinfo();
538 struct _gambatte_core
: public core_core
, public core_region
541 : core_core({&psystem
}, {
542 {0, "Soft reset", "reset", {}},
543 {1, "Change BG palette", "bgpalette", {
544 {"Color 0","string:[0-9A-Fa-f]{6}"},
545 {"Color 1","string:[0-9A-Fa-f]{6}"},
546 {"Color 2","string:[0-9A-Fa-f]{6}"},
547 {"Color 3","string:[0-9A-Fa-f]{6}"}
548 }},{2, "Change SP1 palette", "sp1palette", {
549 {"Color 0","string:[0-9A-Fa-f]{6}"},
550 {"Color 1","string:[0-9A-Fa-f]{6}"},
551 {"Color 2","string:[0-9A-Fa-f]{6}"},
552 {"Color 3","string:[0-9A-Fa-f]{6}"}
553 }}, {3, "Change SP2 palette", "sp2palette", {
554 {"Color 0","string:[0-9A-Fa-f]{6}"},
555 {"Color 1","string:[0-9A-Fa-f]{6}"},
556 {"Color 2","string:[0-9A-Fa-f]{6}"},
557 {"Color 3","string:[0-9A-Fa-f]{6}"}
560 core_region({{"world", "World", 0, 0, false, {4389, 262144}, {0}}}) {}
562 std::string
c_core_identifier() const { return "libgambatte "+gambatte::GB::version(); }
563 bool c_set_region(core_region
& region
) { return (®ion
== this); }
564 std::pair
<uint32_t, uint32_t> c_video_rate() { return std::make_pair(262144, 4389); }
565 double c_get_PAR() { return 1.0; }
566 std::pair
<uint32_t, uint32_t> c_audio_rate() {
567 if(output_native(*CORE().settings
))
568 return std::make_pair(2097152, 1);
570 return std::make_pair(32768, 1);
572 std::map
<std::string
, std::vector
<char>> c_save_sram() throw(std::bad_alloc
) {
573 std::map
<std::string
, std::vector
<char>> s
;
576 auto g
= instance
->getSaveRam();
577 s
["main"].resize(g
.second
);
578 memcpy(&s
["main"][0], g
.first
, g
.second
);
580 time_t timebase
= instance
->getRtcBase();
581 for(size_t i
= 0; i
< 8; i
++)
582 s
["rtc"][i
] = ((unsigned long long)timebase
>> (8 * i
));
585 void c_load_sram(std::map
<std::string
, std::vector
<char>>& sram
) throw(std::bad_alloc
) {
588 std::vector
<char> x
= sram
.count("main") ? sram
["main"] : std::vector
<char>();
589 std::vector
<char> x2
= sram
.count("rtc") ? sram
["rtc"] : std::vector
<char>();
590 auto g
= instance
->getSaveRam();
592 if(x
.size() != g
.second
)
593 messages
<< "WARNING: SRAM 'main': Loaded " << x
.size()
594 << " bytes, but the SRAM is " << g
.second
<< "." << std::endl
;
595 memcpy(g
.first
, &x
[0], min(x
.size(), g
.second
));
599 for(size_t i
= 0; i
< 8 && i
< x2
.size(); i
++)
600 timebase
|= (unsigned long long)(unsigned char)x2
[i
] << (8 * i
);
601 instance
->setRtcBase(timebase
);
604 void c_serialize(std::vector
<char>& out
) {
606 throw std::runtime_error("Can't save without ROM");
607 instance
->saveState(out
);
608 size_t osize
= out
.size();
609 out
.resize(osize
+ 4 * sizeof(primary_framebuffer
) / sizeof(primary_framebuffer
[0]));
610 for(size_t i
= 0; i
< sizeof(primary_framebuffer
) / sizeof(primary_framebuffer
[0]); i
++)
611 serialization::u32b(&out
[osize
+ 4 * i
], primary_framebuffer
[i
]);
612 out
.push_back(frame_overflow
>> 8);
613 out
.push_back(frame_overflow
);
615 void c_unserialize(const char* in
, size_t insize
) {
617 throw std::runtime_error("Can't load without ROM");
618 size_t foffset
= insize
- 2 - 4 * sizeof(primary_framebuffer
) /
619 sizeof(primary_framebuffer
[0]);
620 std::vector
<char> tmp
;
622 memcpy(&tmp
[0], in
, foffset
);
623 instance
->loadState(tmp
);
624 for(size_t i
= 0; i
< sizeof(primary_framebuffer
) / sizeof(primary_framebuffer
[0]); i
++)
625 primary_framebuffer
[i
] = serialization::u32b(&in
[foffset
+ 4 * i
]);
627 unsigned x1
= (unsigned char)in
[insize
- 2];
628 unsigned x2
= (unsigned char)in
[insize
- 1];
629 frame_overflow
= x1
* 256 + x2
;
630 do_reset_flag
= false;
632 core_region
& c_get_region() { return *this; }
634 void c_unload_cartridge() {}
635 std::pair
<uint32_t, uint32_t> c_get_scale_factors(uint32_t width
, uint32_t height
) {
636 return std::make_pair(max(512 / width
, (uint32_t)1), max(448 / height
, (uint32_t)1));
638 void c_install_handler() { magic_flags
|= 2; }
639 void c_uninstall_handler() {}
644 bool timings_fucked_up
= gbchawk_timings(*core
.settings
);
645 bool native_rate
= output_native(*core
.settings
);
646 int16_t reset
= ecore_callbacks
->get_input(0, 0, 1);
649 messages
<< "GB(C) reset" << std::endl
;
651 do_reset_flag
= false;
653 uint32_t samplebuffer
[SAMPLES_PER_FRAME
+ 2064];
654 int16_t soundbuf
[2 * (SAMPLES_PER_FRAME
+ 2064)];
656 last_tsc_increment
= 0;
658 unsigned samples_emitted
= timings_fucked_up
? 35112 :
659 (SAMPLES_PER_FRAME
- frame_overflow
);
660 long ret
= instance
->runFor(primary_framebuffer
, 160, samplebuffer
, samples_emitted
);
662 for(unsigned i
= 0; i
< samples_emitted
; i
++) {
663 soundbuf
[emitted
++] = (int16_t)(samplebuffer
[i
]);
664 soundbuf
[emitted
++] = (int16_t)(samplebuffer
[i
] >> 16);
667 for(unsigned i
= 0; i
< samples_emitted
; i
++) {
668 uint32_t l
= (int32_t)(int16_t)(samplebuffer
[i
]) + 32768;
669 uint32_t r
= (int32_t)(int16_t)(samplebuffer
[i
] >> 16) + 32768;
673 if((accumulator_s
& 63) == 0) {
674 int16_t l2
= (accumulator_l
>> 6) - 32768;
675 int16_t r2
= (accumulator_r
>> 6) - 32768;
676 soundbuf
[emitted
++] = l2
;
677 soundbuf
[emitted
++] = r2
;
678 accumulator_l
= accumulator_r
= 0;
682 ecore_callbacks
->timer_tick(samples_emitted
, 2097152);
683 frame_overflow
+= samples_emitted
;
684 last_tsc_increment
+= samples_emitted
;
685 if(frame_overflow
>= SAMPLES_PER_FRAME
) {
686 frame_overflow
-= SAMPLES_PER_FRAME
;
689 if(timings_fucked_up
)
692 framebuffer::info inf
;
693 inf
.type
= &framebuffer::pixfmt_rgb32
;
694 inf
.mem
= reinterpret_cast<char*>(primary_framebuffer
);
696 inf
.physheight
= 144;
697 inf
.physstride
= 640;
704 framebuffer::raw
ls(inf
);
705 ecore_callbacks
->output_frame(ls
, 262144, 4389);
706 CORE().audio
->submit_buffer(soundbuf
, emitted
/ 2, true, native_rate
? 2097152 : 32768);
708 void c_runtosave() {}
709 bool c_get_pflag() { return pflag
; }
710 void c_set_pflag(bool _pflag
) { pflag
= _pflag
; }
711 framebuffer::raw
& c_draw_cover() {
712 static framebuffer::raw
x(cover_fbinfo
);
713 redraw_cover_fbinfo();
716 std::string
c_get_core_shortname() const { return "gambatte"+gambatte::GB::version(); }
717 void c_pre_emulate_frame(portctrl::frame
& cf
) {
718 cf
.axis3(0, 0, 1, do_reset_flag
? 1 : 0);
720 void c_execute_action(unsigned id
, const std::vector
<interface_action_paramval
>& p
)
724 case 0: //Soft reset.
725 do_reset_flag
= true;
727 case 1: //Change DMG BG palette.
728 case 2: //Change DMG SP1 palette.
729 case 3: //Change DMG SP2 palette.
730 a
= strtoul(p
[0].s
.c_str(), NULL
, 16);
731 b
= strtoul(p
[1].s
.c_str(), NULL
, 16);
732 c
= strtoul(p
[2].s
.c_str(), NULL
, 16);
733 d
= strtoul(p
[3].s
.c_str(), NULL
, 16);
734 palette_colors
[4 * (id
- 1) + 0] = a
;
735 palette_colors
[4 * (id
- 1) + 1] = b
;
736 palette_colors
[4 * (id
- 1) + 2] = c
;
737 palette_colors
[4 * (id
- 1) + 3] = d
;
738 palette_colors_default
[id
- 1] = false;
740 instance
->setDmgPaletteColor(id
- 1, 0, a
);
741 instance
->setDmgPaletteColor(id
- 1, 1, b
);
742 instance
->setDmgPaletteColor(id
- 1, 2, c
);
743 instance
->setDmgPaletteColor(id
- 1, 3, d
);
747 const interface_device_reg
* c_get_registers() { return gb_registers
; }
748 unsigned c_action_flags(unsigned id
) { return (id
< 4) ? 1 : 0; }
749 int c_reset_action(bool hard
) { return hard
? -1 : 0; }
750 std::pair
<uint64_t, uint64_t> c_get_bus_map()
752 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
753 return std::make_pair(0x1000000, 0x10000);
755 return std::make_pair(0, 0);
758 std::list
<core_vma_info
> c_vma_list() { return get_VMAlist(); }
759 std::set
<std::string
> c_srams() { return gambatte_srams(); }
760 void c_set_debug_flags(uint64_t addr
, unsigned int sflags
, unsigned int cflags
)
762 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
763 if(addr
== 0 && sflags
& 8) debugbuf
.trace_cpu
= true;
764 if(addr
== 0 && cflags
& 8) debugbuf
.trace_cpu
= false;
765 if(addr
>= 0 && addr
< 32768) {
766 debugbuf
.wram
[addr
] |= (sflags
& 7);
767 debugbuf
.wram
[addr
] &= ~(cflags
& 7);
768 } else if(addr
>= 0x20000 && addr
< 0x20000 + instance
->getSaveRam().second
) {
769 debugbuf
.sram
[addr
- 0x20000] |= (sflags
& 7);
770 debugbuf
.sram
[addr
- 0x20000] &= ~(cflags
& 7);
771 } else if(addr
>= 0x18000 && addr
< 0x18200) {
772 debugbuf
.ioamhram
[addr
- 0x18000] |= (sflags
& 7);
773 debugbuf
.ioamhram
[addr
- 0x18000] &= ~(cflags
& 7);
774 } else if(addr
>= 0x80000000 && addr
< 0x80000000 + romdata
.size()) {
775 debugbuf
.cart
[addr
- 0x80000000] |= (sflags
& 7);
776 debugbuf
.cart
[addr
- 0x80000000] &= ~(cflags
& 7);
777 } else if(addr
>= 0x1000000 && addr
< 0x1010000) {
778 debugbuf
.bus
[addr
- 0x1000000] |= (sflags
& 7);
779 debugbuf
.bus
[addr
- 0x1000000] &= ~(cflags
& 7);
780 } else if(addr
== 0xFFFFFFFFFFFFFFFFULL
) {
781 //Set/Clear every known debug.
782 for(unsigned i
= 0; i
< 32768; i
++) {
783 debugbuf
.wram
[i
] |= ((sflags
& 7) << 4);
784 debugbuf
.wram
[i
] &= ~((cflags
& 7) << 4);
786 for(unsigned i
= 0; i
< 65536; i
++) {
787 debugbuf
.bus
[i
] |= ((sflags
& 7) << 4);
788 debugbuf
.bus
[i
] &= ~((cflags
& 7) << 4);
790 for(unsigned i
= 0; i
< 512; i
++) {
791 debugbuf
.ioamhram
[i
] |= ((sflags
& 7) << 4);
792 debugbuf
.ioamhram
[i
] &= ~((cflags
& 7) << 4);
794 for(unsigned i
= 0; i
< instance
->getSaveRam().second
; i
++) {
795 debugbuf
.sram
[i
] |= ((sflags
& 7) << 4);
796 debugbuf
.sram
[i
] &= ~((cflags
& 7) << 4);
798 for(unsigned i
= 0; i
< romdata
.size(); i
++) {
799 debugbuf
.cart
[i
] |= ((sflags
& 7) << 4);
800 debugbuf
.cart
[i
] &= ~((cflags
& 7) << 4);
805 void c_set_cheat(uint64_t addr
, uint64_t value
, bool set
)
807 #ifdef GAMBATTE_SUPPORTS_ADV_DEBUG
808 if(addr
>= 0 && addr
< 32768) {
810 debugbuf
.wram
[addr
] |= 8;
811 debugbuf
.wramcheat
[addr
] = value
;
813 debugbuf
.wram
[addr
] &= ~8;
814 debugbuf
.wramcheat
.erase(addr
);
816 } else if(addr
>= 0x20000 && addr
< 0x20000 + instance
->getSaveRam().second
) {
817 auto addr2
= addr
- 0x20000;
819 debugbuf
.sram
[addr2
] |= 8;
820 debugbuf
.sramcheat
[addr2
] = value
;
822 debugbuf
.sram
[addr2
] &= ~8;
823 debugbuf
.sramcheat
.erase(addr2
);
825 } else if(addr
>= 0x80000000 && addr
< 0x80000000 + romdata
.size()) {
826 auto addr2
= addr
- 0x80000000;
828 debugbuf
.cart
[addr2
] |= 8;
829 debugbuf
.cartcheat
[addr2
] = value
;
831 debugbuf
.cart
[addr2
] &= ~8;
832 debugbuf
.cartcheat
.erase(addr2
);
839 //Next load will reset trace.
840 reallocate_debug
= true;
841 palette_colors_default
[0] = true;
842 palette_colors_default
[1] = true;
843 palette_colors_default
[2] = true;
845 std::vector
<std::string
> c_get_trace_cpus()
847 std::vector
<std::string
> r
;
851 void c_reset_to_load()
853 instance
->loadState(init_savestate
);
854 memset(primary_framebuffer
, 0, sizeof(primary_framebuffer
));
855 frame_overflow
= 0; //frame_overflow is always 0 at the beginning.
856 do_reset_flag
= false;
860 std::vector
<core_setting_value_param
> boolean_values
= {{"0", "False", 0}, {"1", "True", 1}};
861 core_setting_group gambatte_settings
= {
862 #ifdef GAMBATTE_SUPPORTS_EMU_FLAGS
863 {"sigillcrash", "Crash on SIGILL", "0", boolean_values
},
867 struct _type_dmg
: public core_type
, public core_sysregion
874 .sysname
= "Gameboy",
876 .regions
= {&gambatte_core
},
877 .images
= {{"rom", "Cartridge ROM", 1, 0, 0, "gb;dmg"}},
878 .settings
= gambatte_settings
,
879 .core
= &gambatte_core
,
881 core_sysregion("gdmg", *this, gambatte_core
) {}
883 int t_load_rom(core_romimage
* img
, std::map
<std::string
, std::string
>& settings
,
884 uint64_t secs
, uint64_t subsecs
)
886 return load_rom_common(img
, gambatte::GB::FORCE_DMG
, secs
, subsecs
, this, settings
);
888 controller_set
t_controllerconfig(std::map
<std::string
, std::string
>& settings
)
890 return gambatte_controllerconfig(settings
);
894 struct _type_gbc
: public core_type
, public core_sysregion
899 .hname
= "Game Boy Color",
901 .sysname
= "Gameboy",
903 .regions
= {&gambatte_core
},
904 .images
= {{"rom", "Cartridge ROM", 1, 0, 0, "gbc;cgb"}},
905 .settings
= gambatte_settings
,
906 .core
= &gambatte_core
,
908 core_sysregion("ggbc", *this, gambatte_core
) {}
910 int t_load_rom(core_romimage
* img
, std::map
<std::string
, std::string
>& settings
,
911 uint64_t secs
, uint64_t subsecs
)
913 return load_rom_common(img
, 0, secs
, subsecs
, this, settings
);
915 controller_set
t_controllerconfig(std::map
<std::string
, std::string
>& settings
)
917 return gambatte_controllerconfig(settings
);
921 struct _type_gbca
: public core_type
, public core_sysregion
926 .hname
= "Game Boy Color (GBA)",
928 .sysname
= "Gameboy",
930 .regions
= {&gambatte_core
},
931 .images
= {{"rom", "Cartridge ROM", 1, 0, 0, ""}},
932 .settings
= gambatte_settings
,
933 .core
= &gambatte_core
,
935 core_sysregion("ggbca", *this, gambatte_core
) {}
937 int t_load_rom(core_romimage
* img
, std::map
<std::string
, std::string
>& settings
,
938 uint64_t secs
, uint64_t subsecs
)
940 return load_rom_common(img
, gambatte::GB::GBA_CGB
, secs
, subsecs
, this, settings
);
942 controller_set
t_controllerconfig(std::map
<std::string
, std::string
>& settings
)
944 return gambatte_controllerconfig(settings
);
948 void redraw_cover_fbinfo()
950 for(size_t i
= 0; i
< sizeof(cover_fbmem
) / sizeof(cover_fbmem
[0]); i
++)
951 cover_fbmem
[i
] = 0x00000000;
952 std::string ident
= gambatte_core
.get_core_identifier();
953 cover_render_string(cover_fbmem
, 0, 0, ident
, 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
954 cover_render_string(cover_fbmem
, 0, 16, "Internal ROM name: " + get_cartridge_name(),
955 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
957 for(auto i
: cover_information()) {
958 cover_render_string(cover_fbmem
, 0, y
, i
, 0xFFFFFF, 0x000000, 480, 432, 1920, 4);
962 cover_render_string(cover_fbmem
, 0, y
, "Crash on SIGILL enabled", 0xFFFFFF, 0x000000, 480,
968 std::vector
<char> cmp_save
;
970 command::fnptr
<> cmp_save1(lsnes_cmds
, "set-cmp-save", "", "\n", []() throw(std::bad_alloc
,
971 std::runtime_error
) {
974 instance
->saveState(cmp_save
);
977 command::fnptr
<> cmp_save2(lsnes_cmds
, "do-cmp-save", "", "\n", []() throw(std::bad_alloc
,
978 std::runtime_error
) {
982 instance
->saveState(x
, cmp_save
);
985 int last_frame_cycles(lua::state
& L
, lua::parameters
& P
)
987 L
.pushnumber(last_tsc_increment
);
991 lua::functions
debug_fns_snes(lua_func_misc
, "gambatte", {
992 {"last_frame_cycles", last_frame_cycles
},
998 register_sysregion_mapping("gdmg", "GB");
999 register_sysregion_mapping("ggbc", "GBC");
1000 register_sysregion_mapping("ggbca", "GBC");