Actually call on_reset callback
[lsnes.git] / src / interface / c-interface.cpp
blob780f587b89280eb6d4f6521eb80c2b1e3914a9b6
1 #include "interface/c-interface.hpp"
2 #include "interface/callbacks.hpp"
3 #include "interface/romtype.hpp"
4 #include "interface/setting.hpp"
5 #include "interface/disassembler.hpp"
6 #include "library/string.hpp"
7 #include "library/portctrl-parse.hpp"
8 #include "library/framebuffer.hpp"
9 #include "library/framebuffer-pixfmt-rgb15.hpp"
10 #include "library/framebuffer-pixfmt-rgb16.hpp"
11 #include "library/framebuffer-pixfmt-rgb24.hpp"
12 #include "library/framebuffer-pixfmt-rgb32.hpp"
13 #include "library/framebuffer-pixfmt-lrgb.hpp"
14 #include "fonts/wrapper.hpp"
15 #include "core/audioapi.hpp"
16 #include "core/instance.hpp"
17 #include "core/messages.hpp"
18 #include <functional>
20 template<> int ccore_call_param_map<lsnes_core_enumerate_cores>::id = LSNES_CORE_ENUMERATE_CORES;
21 template<> int ccore_call_param_map<lsnes_core_get_core_info>::id = LSNES_CORE_GET_CORE_INFO;
22 template<> int ccore_call_param_map<lsnes_core_get_type_info>::id = LSNES_CORE_GET_TYPE_INFO;
23 template<> int ccore_call_param_map<lsnes_core_get_region_info>::id = LSNES_CORE_GET_REGION_INFO;
24 template<> int ccore_call_param_map<lsnes_core_get_sysregion_info>::id = LSNES_CORE_GET_SYSREGION_INFO;
25 template<> int ccore_call_param_map<lsnes_core_get_av_state>::id = LSNES_CORE_GET_AV_STATE;
26 template<> int ccore_call_param_map<lsnes_core_emulate>::id = LSNES_CORE_EMULATE;
27 template<> int ccore_call_param_map<lsnes_core_savestate>::id = LSNES_CORE_SAVESTATE;
28 template<> int ccore_call_param_map<lsnes_core_loadstate>::id = LSNES_CORE_LOADSTATE;
29 template<> int ccore_call_param_map<lsnes_core_get_controllerconfig>::id = LSNES_CORE_GET_CONTROLLERCONFIG;
30 template<> int ccore_call_param_map<lsnes_core_load_rom>::id = LSNES_CORE_LOAD_ROM;
31 template<> int ccore_call_param_map<lsnes_core_get_region>::id = LSNES_CORE_GET_REGION;
32 template<> int ccore_call_param_map<lsnes_core_set_region>::id = LSNES_CORE_SET_REGION;
33 template<> int ccore_call_param_map<lsnes_core_deinitialize>::id = LSNES_CORE_DEINITIALIZE;
34 template<> int ccore_call_param_map<lsnes_core_get_pflag>::id = LSNES_CORE_GET_PFLAG;
35 template<> int ccore_call_param_map<lsnes_core_set_pflag>::id = LSNES_CORE_SET_PFLAG;
36 template<> int ccore_call_param_map<lsnes_core_get_action_flags>::id = LSNES_CORE_GET_ACTION_FLAGS;
37 template<> int ccore_call_param_map<lsnes_core_execute_action>::id = LSNES_CORE_EXECUTE_ACTION;
38 template<> int ccore_call_param_map<lsnes_core_get_bus_mapping>::id = LSNES_CORE_GET_BUS_MAPPING;
39 template<> int ccore_call_param_map<lsnes_core_enumerate_sram>::id = LSNES_CORE_ENUMERATE_SRAM;
40 template<> int ccore_call_param_map<lsnes_core_save_sram>::id = LSNES_CORE_SAVE_SRAM;
41 template<> int ccore_call_param_map<lsnes_core_load_sram>::id = LSNES_CORE_LOAD_SRAM;
42 template<> int ccore_call_param_map<lsnes_core_get_reset_action>::id = LSNES_CORE_GET_RESET_ACTION;
43 template<> int ccore_call_param_map<lsnes_core_compute_scale>::id = LSNES_CORE_COMPUTE_SCALE;
44 template<> int ccore_call_param_map<lsnes_core_runtosave>::id = LSNES_CORE_RUNTOSAVE;
45 template<> int ccore_call_param_map<lsnes_core_poweron>::id = LSNES_CORE_POWERON;
46 template<> int ccore_call_param_map<lsnes_core_unload_cartridge>::id = LSNES_CORE_UNLOAD_CARTRIDGE;
47 template<> int ccore_call_param_map<lsnes_core_debug_reset>::id = LSNES_CORE_DEBUG_RESET;
48 template<> int ccore_call_param_map<lsnes_core_set_debug_flags>::id = LSNES_CORE_SET_DEBUG_FLAGS;
49 template<> int ccore_call_param_map<lsnes_core_set_cheat>::id = LSNES_CORE_SET_CHEAT;
50 template<> int ccore_call_param_map<lsnes_core_draw_cover>::id = LSNES_CORE_DRAW_COVER;
51 template<> int ccore_call_param_map<lsnes_core_pre_emulate>::id = LSNES_CORE_PRE_EMULATE;
52 template<> int ccore_call_param_map<lsnes_core_get_device_regs>::id = LSNES_CORE_GET_DEVICE_REGS;
53 template<> int ccore_call_param_map<lsnes_core_get_vma_list>::id = LSNES_CORE_GET_VMA_LIST;
54 template<> int ccore_call_param_map<lsnes_core_reinit>::id = LSNES_CORE_REINIT;
56 template<> const char* ccore_call_param_map<lsnes_core_enumerate_cores>::name = "LSNES_CORE_ENUMERATE_CORES";
57 template<> const char* ccore_call_param_map<lsnes_core_get_core_info>::name = "LSNES_CORE_GET_CORE_INFO";
58 template<> const char* ccore_call_param_map<lsnes_core_get_type_info>::name = "LSNES_CORE_GET_TYPE_INFO";
59 template<> const char* ccore_call_param_map<lsnes_core_get_region_info>::name = "LSNES_CORE_GET_REGION_INFO";
60 template<> const char* ccore_call_param_map<lsnes_core_get_sysregion_info>::name = "LSNES_CORE_GET_SYSREGION_INFO";
61 template<> const char* ccore_call_param_map<lsnes_core_get_av_state>::name = "LSNES_CORE_GET_AV_STATE";
62 template<> const char* ccore_call_param_map<lsnes_core_emulate>::name = "LSNES_CORE_EMULATE";
63 template<> const char* ccore_call_param_map<lsnes_core_savestate>::name = "LSNES_CORE_SAVESTATE";
64 template<> const char* ccore_call_param_map<lsnes_core_loadstate>::name = "LSNES_CORE_LOADSTATE";
65 template<> const char* ccore_call_param_map<lsnes_core_get_controllerconfig>::name =
66 "LSNES_CORE_GET_CONTROLLERCONFIG";
67 template<> const char* ccore_call_param_map<lsnes_core_load_rom>::name = "LSNES_CORE_LOAD_ROM";
68 template<> const char* ccore_call_param_map<lsnes_core_get_region>::name = "LSNES_CORE_GET_REGION";
69 template<> const char* ccore_call_param_map<lsnes_core_set_region>::name = "LSNES_CORE_SET_REGION";
70 template<> const char* ccore_call_param_map<lsnes_core_deinitialize>::name = "LSNES_CORE_DEINITIALIZE";
71 template<> const char* ccore_call_param_map<lsnes_core_get_pflag>::name = "LSNES_CORE_GET_PFLAG";
72 template<> const char* ccore_call_param_map<lsnes_core_set_pflag>::name = "LSNES_CORE_SET_PFLAG";
73 template<> const char* ccore_call_param_map<lsnes_core_get_action_flags>::name = "LSNES_CORE_GET_ACTION_FLAGS";
74 template<> const char* ccore_call_param_map<lsnes_core_execute_action>::name = "LSNES_CORE_EXECUTE_ACTION";
75 template<> const char* ccore_call_param_map<lsnes_core_get_bus_mapping>::name = "LSNES_CORE_GET_BUS_MAPPING";
76 template<> const char* ccore_call_param_map<lsnes_core_enumerate_sram>::name = "LSNES_CORE_ENUMERATE_SRAM";
77 template<> const char* ccore_call_param_map<lsnes_core_save_sram>::name = "LSNES_CORE_SAVE_SRAM";
78 template<> const char* ccore_call_param_map<lsnes_core_load_sram>::name = "LSNES_CORE_LOAD_SRAM";
79 template<> const char* ccore_call_param_map<lsnes_core_get_reset_action>::name = "LSNES_CORE_GET_RESET_ACTION";
80 template<> const char* ccore_call_param_map<lsnes_core_compute_scale>::name = "LSNES_CORE_COMPUTE_SCALE";
81 template<> const char* ccore_call_param_map<lsnes_core_runtosave>::name = "LSNES_CORE_RUNTOSAVE";
82 template<> const char* ccore_call_param_map<lsnes_core_poweron>::name = "LSNES_CORE_POWERON";
83 template<> const char* ccore_call_param_map<lsnes_core_unload_cartridge>::name = "LSNES_CORE_UNLOAD_CARTRIDGE";
84 template<> const char* ccore_call_param_map<lsnes_core_debug_reset>::name = "LSNES_CORE_DEBUG_RESET";
85 template<> const char* ccore_call_param_map<lsnes_core_set_debug_flags>::name = "LSNES_CORE_SET_DEBUG_FLAGS";
86 template<> const char* ccore_call_param_map<lsnes_core_set_cheat>::name = "LSNES_CORE_SET_CHEAT";
87 template<> const char* ccore_call_param_map<lsnes_core_draw_cover>::name = "LSNES_CORE_DRAW_COVER";
88 template<> const char* ccore_call_param_map<lsnes_core_pre_emulate>::name = "LSNES_CORE_PRE_EMULATE";
89 template<> const char* ccore_call_param_map<lsnes_core_get_device_regs>::name = "LSNES_CORE_GET_DEVICE_REGS";
90 template<> const char* ccore_call_param_map<lsnes_core_get_vma_list>::name = "LSNES_CORE_GET_VMA_LIST";
91 template<> const char* ccore_call_param_map<lsnes_core_reinit>::name = "LSNES_CORE_REINIT";
93 namespace
95 struct c_core_core;
96 c_core_core* current_core = NULL;
98 char* strduplicate(const char* x)
100 if(!x) return NULL;
101 char* out = (char*)malloc(strlen(x) + 1);
102 if(!out)
103 throw std::bad_alloc();
104 strcpy(out, x);
105 return out;
108 std::list<lsnes_core_func_t>& corequeue()
110 static std::list<lsnes_core_func_t> x;
111 return x;
114 void default_error_function(const char* callname, const char* err)
116 messages << "Warning: " << callname << " failed: " << err << std::endl;
119 framebuffer::info translate_info(lsnes_core_framebuffer_info* _fb)
121 framebuffer::info fbinfo;
122 switch(_fb->type) {
123 case LSNES_CORE_PIXFMT_RGB15: fbinfo.type = &framebuffer::pixfmt_rgb15; break;
124 case LSNES_CORE_PIXFMT_BGR15: fbinfo.type = &framebuffer::pixfmt_bgr15; break;
125 case LSNES_CORE_PIXFMT_RGB16: fbinfo.type = &framebuffer::pixfmt_rgb16; break;
126 case LSNES_CORE_PIXFMT_BGR16: fbinfo.type = &framebuffer::pixfmt_bgr16; break;
127 case LSNES_CORE_PIXFMT_RGB24: fbinfo.type = &framebuffer::pixfmt_rgb24; break;
128 case LSNES_CORE_PIXFMT_BGR24: fbinfo.type = &framebuffer::pixfmt_bgr24; break;
129 case LSNES_CORE_PIXFMT_RGB32: fbinfo.type = &framebuffer::pixfmt_rgb32; break;
130 case LSNES_CORE_PIXFMT_LRGB: fbinfo.type = &framebuffer::pixfmt_lrgb; break;
132 fbinfo.mem = (char*)_fb->mem;
133 fbinfo.physwidth = _fb->physwidth;
134 fbinfo.physheight = _fb->physheight;
135 fbinfo.physstride = _fb->physstride;
136 fbinfo.width = _fb->width;
137 fbinfo.height = _fb->height;
138 fbinfo.stride = _fb->stride;
139 fbinfo.offset_x = _fb->offset_x;
140 fbinfo.offset_y = _fb->offset_y;
141 return fbinfo;
144 struct entrypoint_fn
146 entrypoint_fn(lsnes_core_func_t _fn) : fn(_fn) {}
147 template<typename T> bool operator()(unsigned item, T& args,
148 std::function<void(const char* callname, const char* err)> onerror)
150 const char* err = NULL;
151 int r = fn(ccore_call_param_map<T>::id, item, &args, &err);
152 if(r < 0)
153 onerror(ccore_call_param_map<T>::name, err);
154 return (r >= 0);
156 template<typename T> bool operator()(unsigned item, T& args)
158 return (*this)(item, args, default_error_function);
160 private:
161 lsnes_core_func_t fn;
164 struct c_lib_init
166 public:
167 c_lib_init(entrypoint_fn _entrypoint)
168 : entrypoint(_entrypoint)
170 count = 0;
172 void initialize()
174 count++;
176 void deinitialize()
178 if(count) count--;
179 if(!count) {
180 lsnes_core_deinitialize s;
181 entrypoint(0, s);
184 entrypoint_fn get_entrypoint()
186 return entrypoint;
188 private:
189 int count;
190 entrypoint_fn entrypoint;
193 struct c_core_core_params
195 std::vector<interface_action> actions;
196 std::vector<std::string> trace_cpus;
197 std::vector<portctrl::type*> ports;
198 const char* shortname;
199 const char* fullname;
200 unsigned flags;
201 unsigned id;
202 std::map<unsigned, core_region*> regions;
203 c_lib_init* library;
206 struct c_core_core : public core_core
208 c_core_core(c_core_core_params& p)
209 : core_core(p.ports, p.actions), entrypoint(p.library->get_entrypoint()), plugin(p.library)
211 fullname = p.fullname;
212 shortname = p.shortname;
213 id = p.id;
214 internal_pflag = false;
215 caps1 = p.flags;
216 regions = p.regions;
217 actions = p.actions;
218 trace_cpus = p.trace_cpus;
219 for(size_t i = 0; i < p.ports.size(); i++)
220 ports[i] = p.ports[i];
222 ~c_core_core() throw();
223 std::string c_core_identifier() const
225 return fullname;
227 bool get_av_state(lsnes_core_get_av_state& s)
229 return entrypoint(id, s);
231 std::pair<uint32_t, uint32_t> c_video_rate()
233 lsnes_core_get_av_state s;
234 if(!entrypoint(id, s))
235 return std::make_pair(60, 1);
236 return std::make_pair(s.fps_n, s.fps_d);
238 double c_get_PAR()
240 lsnes_core_get_av_state s;
241 return entrypoint(id, s) ? s.par : 1.0;
243 std::pair<uint32_t, uint32_t> c_audio_rate()
245 lsnes_core_get_av_state s;
246 return entrypoint(id, s) ? std::make_pair(s.rate_n, s.rate_d) : std::make_pair(48000U, 1U);
248 void c_power()
250 lsnes_core_poweron s;
251 if(caps1 & LSNES_CORE_CAP1_POWERON) entrypoint(id, s);
253 void c_unload_cartridge()
255 lsnes_core_unload_cartridge s;
256 if(caps1 & LSNES_CORE_CAP1_UNLOAD) entrypoint(id, s);
258 void c_runtosave()
260 lsnes_core_runtosave s;
261 if(caps1 & LSNES_CORE_CAP1_RUNTOSAVE) entrypoint(id, s);
263 void c_emulate()
265 current_core = this;
266 lsnes_core_emulate s;
267 entrypoint(id, s);
268 current_core = NULL;
270 bool c_get_pflag()
272 lsnes_core_get_pflag s;
273 if(!(caps1 & LSNES_CORE_CAP1_PFLAG) || !entrypoint(id, s))
274 return internal_pflag;
275 return (s.pflag != 0);
277 void c_set_pflag(bool pflag)
279 lsnes_core_set_pflag s;
280 s.pflag = pflag ? 1 : 0;
281 if(!(caps1 & LSNES_CORE_CAP1_PFLAG) || !entrypoint(id, s))
282 internal_pflag = pflag;
284 std::string c_get_core_shortname() const
286 return shortname;
288 void c_debug_reset()
290 lsnes_core_debug_reset s;
291 if(caps1 & (LSNES_CORE_CAP1_DEBUG | LSNES_CORE_CAP1_TRACE | LSNES_CORE_CAP1_CHEAT))
292 entrypoint(id, s);
294 std::pair<unsigned, unsigned> c_lightgun_scale()
296 lsnes_core_get_av_state s;
297 if(!(caps1 & LSNES_CORE_CAP1_LIGHTGUN) || !entrypoint(id, s))
298 return std::make_pair(0, 0);
299 return std::make_pair(s.lightgun_width, s.lightgun_height);
301 std::pair<uint64_t, uint64_t> c_get_bus_map()
303 lsnes_core_get_bus_mapping s;
304 if(!(caps1 & LSNES_CORE_CAP1_BUSMAP) || !entrypoint(id, s))
305 return std::make_pair(0, 0);
306 return std::make_pair(s.base, s.size);
308 int c_reset_action(bool hard)
310 lsnes_core_get_reset_action s;
311 if(!(caps1 & LSNES_CORE_CAP1_RESET) || !entrypoint(id, s))
312 return -1;
313 return hard ? s.hardreset : s.softreset;
315 std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height)
317 lsnes_core_compute_scale s;
318 uint32_t hscale, vscale;
319 if(width >= 360) hscale = 1;
320 else hscale = 360 / width + 1;
321 if(height >= 320) vscale = 1;
322 else vscale = 320 / height + 1;
323 if(caps1 & LSNES_CORE_CAP1_SCALE) {
324 s.width = width;
325 s.height = height;
326 if(entrypoint(id, s)) {
327 hscale = s.hfactor;
328 vscale = s.vfactor;
331 return std::make_pair(hscale, vscale);
333 void c_pre_emulate_frame(portctrl::frame& cf)
335 lsnes_core_pre_emulate s;
336 if(caps1 & LSNES_CORE_CAP1_PREEMULATE) {
337 s.context = &cf;
338 s.set_input = [](void* context, unsigned port, unsigned controller, unsigned index,
339 short value) -> void {
340 portctrl::frame& cf = *(portctrl::frame*)context;
341 cf.axis3(port, controller, index, value);
343 entrypoint(id, s);
346 std::set<std::string> c_srams()
348 lsnes_core_enumerate_sram s;
349 std::set<std::string> ret;
350 if(caps1 & LSNES_CORE_CAP1_SRAM) {
351 if(entrypoint(id, s)) {
352 const char** sr = s.srams;
353 while(*sr) {
354 ret.insert(*sr);
355 sr++;
359 return ret;
361 void c_load_sram(std::map<std::string, std::vector<char>>& sram)
363 lsnes_core_load_sram s;
364 if(caps1 & LSNES_CORE_CAP1_SRAM) {
365 std::vector<lsnes_core_sram> srams;
366 std::vector<lsnes_core_sram*> sramsp;
367 std::vector<char> names;
368 srams.resize(sram.size() + 1);
369 srams[sram.size()].name = NULL;
370 size_t idx = 0;
371 size_t nlength = 0;
372 for(auto& i : sram)
373 nlength += i.first.length() + 1;
374 names.resize(nlength);
375 size_t nidx = 0;
376 for(auto& i : sram) {
377 size_t ntmp = nidx;
378 std::copy(i.first.begin(), i.first.end(), names.begin() + nidx);
379 nidx += i.first.length();
380 names[nidx++] = '\0';
381 srams[idx].size = i.second.size();
382 srams[idx].data = &i.second[0];
383 srams[idx].name = &names[ntmp];
384 idx++;
386 s.srams = &srams[0];
387 entrypoint(id, s);
390 std::map<std::string, std::vector<char>> c_save_sram()
392 lsnes_core_save_sram s;
393 std::map<std::string, std::vector<char>> ret;
394 if(caps1 & LSNES_CORE_CAP1_SRAM) {
395 if(entrypoint(id, s)) {
396 lsnes_core_sram* p = s.srams;
397 while(p->name) {
398 ret[p->name].resize(p->size);
399 memcpy(&ret[p->name][0], p->data, p->size);
400 p++;
404 return ret;
406 void c_unserialize(const char* in, size_t insize)
408 lsnes_core_loadstate s;
409 s.data = in;
410 s.size = insize;
411 entrypoint(id, s, [](const char* name, const char* err) {
412 throw std::runtime_error("Loadstate failed: " + std::string(err));
415 void c_serialize(std::vector<char>& out)
417 lsnes_core_savestate s;
418 entrypoint(id, s, [](const char* name, const char* err) {
419 throw std::runtime_error("Savestate failed: " + std::string(err));
421 out.resize(s.size);
422 memcpy(&out[0], s.data, s.size);
424 unsigned c_action_flags(unsigned _id)
426 lsnes_core_get_action_flags s;
427 if(caps1 & LSNES_CORE_CAP1_ACTION) {
428 s.action = _id;
429 return entrypoint(id, s) ? s.flags : 0;
431 return 0;
433 std::vector<std::string> c_get_trace_cpus()
435 return trace_cpus;
437 bool c_set_region(core_region& region)
439 lsnes_core_set_region s;
440 if(caps1 & LSNES_CORE_CAP1_MULTIREGION) {
441 bool hit = false;
442 for(auto i : regions)
443 if(i.second == &region) {
444 s.region = i.first;
445 hit = true;
447 if(!hit)
448 return false; //Bad region.
449 return entrypoint(id, s);
450 } else {
451 return (regions.count(0) && regions[0] == &region);
454 core_region& c_get_region()
456 lsnes_core_get_region s;
457 if(caps1 & LSNES_CORE_CAP1_MULTIREGION) {
458 if(!entrypoint(id, s)) {
459 if(regions.empty())
460 throw std::runtime_error("No valid regions");
461 return *(regions.begin()->second);
462 } else {
463 if(regions.count(s.region))
464 return *regions[s.region];
465 messages << "Internal error: Core gave invalid region number."
466 << std::endl;
467 if(regions.empty())
468 throw std::runtime_error("No valid regions");
469 return *(regions.begin()->second);
471 } else {
472 if(regions.count(0))
473 return *regions[0];
474 else {
475 messages << "Internal error: Not multi-region core and region 0 not present."
476 << std::endl;
477 if(regions.empty())
478 throw std::runtime_error("No valid regions");
479 return *(regions.begin()->second);
483 const struct interface_device_reg* c_get_registers()
485 static std::vector<interface_device_reg> regs;
486 static std::vector<char> namebuf;
487 static interface_device_reg reg_null = {NULL};
488 lsnes_core_get_device_regs s;
489 if(caps1 & LSNES_CORE_CAP1_REGISTERS) {
490 if(!entrypoint(id, s)) {
491 return &reg_null;
492 } else {
493 size_t count = 0;
494 size_t namelen = 0;
495 auto tregs = s.regs;
496 while(tregs->name) {
497 namelen += strlen(tregs->name) + 1;
498 count++;
499 tregs++;
501 tregs = s.regs;
502 if(regs.size() < count + 1)
503 regs.resize(count + 1);
504 if(namelen > namebuf.size())
505 namebuf.resize(namelen);
506 size_t idx = 0;
507 size_t nameptr = 0;
508 while(tregs->name) {
509 strcpy(&namebuf[nameptr], tregs->name);
510 regs[idx].name = &namebuf[nameptr];
511 regs[idx].read = tregs->read;
512 regs[idx].write = tregs->write;
513 regs[idx].boolean = tregs->boolean;
514 nameptr += strlen(tregs->name) + 1;
515 tregs++;
516 idx++;
518 regs[idx].name = NULL; //The sentinel.
520 } else {
521 return &reg_null;
523 return &regs[0];
525 void c_install_handler()
527 plugin->initialize();
529 void c_uninstall_handler()
531 plugin->deinitialize();
533 void c_set_debug_flags(uint64_t addr, unsigned flags_set, unsigned flags_clear)
535 lsnes_core_set_debug_flags s;
536 s.addr = addr;
537 s.set = flags_set;
538 s.clear = flags_clear;
539 if(caps1 & LSNES_CORE_CAP1_DEBUG)
540 entrypoint(id, s);
541 else
542 messages << "Debugging functions not supported by core" << std::endl;
544 void c_set_cheat(uint64_t addr, uint64_t value, bool set)
546 lsnes_core_set_cheat s;
547 s.addr = addr;
548 s.value = value;
549 s.set = set;
550 if(caps1 & LSNES_CORE_CAP1_CHEAT)
551 entrypoint(id, s);
552 else
553 messages << "Cheat functions not supported by core" << std::endl;
555 void c_execute_action(unsigned aid, const std::vector<interface_action_paramval>& p)
557 if(!(caps1 & LSNES_CORE_CAP1_ACTION)) {
558 messages << "Core does not support actions." << std::endl;
559 return;
561 interface_action* act = NULL;
562 for(auto& i : actions) {
563 if(i.id == aid) {
564 act = &i;
565 break;
568 if(!act) {
569 messages << "Unknown action id #" << aid << std::endl;
570 return;
572 size_t j = 0;
573 std::vector<lsnes_core_execute_action_param> parameters;
574 std::list<std::vector<char>> strtmp;
575 for(auto& b : act->params) {
576 std::string m = b.model;
577 if(m == "bool") {
578 //Boolean.
579 lsnes_core_execute_action_param tp;
580 tp.boolean = p[j++].b;
581 parameters.push_back(tp);
582 } else if(regex_match("int:.*", m)) {
583 //Integer.
584 lsnes_core_execute_action_param tp;
585 tp.integer = p[j++].i;
586 parameters.push_back(tp);
587 } else if(regex_match("string(:.*)?", m) || regex_match("enum:.*", m)) {
588 //String.
589 strtmp.push_back(std::vector<char>());
590 auto& i = strtmp.back();
591 i.resize(p[j].s.length() + 1);
592 std::copy(p[j].s.begin(), p[j].s.end(), i.begin());
593 lsnes_core_execute_action_param tp;
594 tp.string.base = &i[0];
595 tp.string.length = p[j++].s.length();
596 parameters.push_back(tp);
597 } else if(m == "toggle") {
598 //Skip.
599 } else {
600 messages << "Unknown model '" << m << "' in action id #" << aid << std::endl;
601 return;
604 lsnes_core_execute_action s;
605 s.action = aid;
606 s.params = &parameters[0];
607 entrypoint(id, s);
609 framebuffer::raw& c_draw_cover()
611 lsnes_core_draw_cover r;
612 if(caps1 & LSNES_CORE_CAP1_COVER) {
613 if(!entrypoint(id, r))
614 goto failed;
615 framebuffer::info fbinfo = translate_info(r.coverpage);
616 size_t needed = fbinfo.physwidth * fbinfo.physheight * fbinfo.type->get_bpp();
617 if(covermem.size() < needed) covermem.resize(needed);
618 memcpy(&covermem[0], fbinfo.mem, needed);
619 fbinfo.mem = &covermem[0];
620 cover = framebuffer::raw(fbinfo);
621 return cover;
623 failed:
624 if(covermem.size() < 1024) covermem.resize(1024);
625 framebuffer::info fbi;
626 fbi.type = &framebuffer::pixfmt_rgb16;
627 fbi.mem = &covermem[0];
628 fbi.physwidth = 512;
629 fbi.physheight = 448;
630 fbi.physstride = 0;
631 fbi.width = 512;
632 fbi.height = 448;
633 fbi.stride = 0;
634 fbi.offset_x = 0;
635 fbi.offset_y = 0;
636 cover = framebuffer::raw(fbi);
637 return cover;
639 std::list<core_vma_info> c_vma_list()
641 lsnes_core_get_vma_list r;
642 if(caps1 & LSNES_CORE_CAP1_MEMWATCH) {
643 if(!entrypoint(id, r))
644 goto failed;
645 std::list<core_vma_info> vmalist;
646 for(lsnes_core_get_vma_list_vma** vmas = r.vmas; *vmas; vmas++) {
647 lsnes_core_get_vma_list_vma* vma = *vmas;
648 core_vma_info _vma;
649 _vma.name = vma->name;
650 _vma.base = vma->base;
651 _vma.size = vma->size;
652 _vma.endian = vma->endian;
653 _vma.readonly = ((vma->flags & LSNES_CORE_VMA_READONLY) != 0);
654 _vma.special = ((vma->flags & LSNES_CORE_VMA_SPECIAL) != 0);
655 _vma.volatile_flag = ((vma->flags & LSNES_CORE_VMA_VOLATILE) != 0);
656 _vma.backing_ram = vma->direct_map;
657 _vma.read = vma->read;
658 _vma.write = vma->write;
659 vmalist.push_back(_vma);
661 return vmalist;
663 failed:
664 return std::list<core_vma_info>();
666 void c_reset_to_load()
668 lsnes_core_reinit r;
669 if(caps1 & LSNES_CORE_CAP1_REINIT) {
670 entrypoint(id, r, [](const char* name, const char* err) {
671 throw std::runtime_error("Resetting state failed: " + std::string(err));
673 return;
675 //Emulate by loadstate.
676 c_unserialize(&init_savestate[0], init_savestate.size());
678 std::map<unsigned, portctrl::type*> get_ports()
680 return ports;
682 void set_internal_pflag()
684 internal_pflag = true;
686 void update_initial_savestate()
688 if((caps1 & LSNES_CORE_CAP1_REINIT) == 0)
689 c_serialize(init_savestate);
691 private:
692 std::string fullname;
693 std::string shortname;
694 unsigned id;
695 bool internal_pflag;
696 unsigned caps1;
697 std::vector<std::string> trace_cpus;
698 std::map<unsigned, portctrl::type*> ports;
699 std::map<unsigned, core_region*> regions;
700 std::vector<interface_action> actions;
701 framebuffer::raw cover;
702 std::vector<char> covermem;
703 std::vector<char> init_savestate;
704 entrypoint_fn entrypoint;
705 c_lib_init* plugin;
708 c_core_core::~c_core_core() throw()
712 struct c_core_type : public core_type
714 c_core_type(c_lib_init& lib, core_type_params& p, std::map<unsigned, portctrl::type*> _ports,
715 unsigned _rcount, unsigned _id)
716 : core_type(p), ports(_ports), entrypoint(lib.get_entrypoint()), rcount(_rcount), id(_id)
719 ~c_core_type() throw()
722 int t_load_rom(core_romimage* images, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
723 uint64_t rtc_subsec)
725 lsnes_core_load_rom r;
726 std::vector<char> tmpmem;
727 std::vector<lsnes_core_system_setting> tmpmem2;
728 r.rtc_sec = rtc_sec;
729 r.rtc_subsec = rtc_subsec;
730 copy_settings(tmpmem, tmpmem2, settings);
731 r.settings = &tmpmem2[0];
733 std::vector<lsnes_core_load_rom_image> imgs;
734 imgs.resize(rcount);
735 for(unsigned i = 0; i < rcount; i++) {
736 imgs[i].data = (const char*)images[i].data;
737 imgs[i].size = images[i].size;
738 imgs[i].markup = images[i].markup;
740 r.images = &imgs[0];
741 unsigned _id = id;
742 entrypoint(_id, r, [_id](const char* name, const char* err) {
743 (stringfmt() << "LSNES_CORE_LOAD_ROM(" << _id << ") failed: " << err).throwex();
745 dynamic_cast<c_core_core*>(get_core())->update_initial_savestate();
746 return 0;
748 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
750 lsnes_core_get_controllerconfig r;
751 std::vector<char> tmpmem;
752 std::vector<lsnes_core_system_setting> tmpmem2;
753 copy_settings(tmpmem, tmpmem2, settings);
754 r.settings = &tmpmem2[0];
755 unsigned _id = id;
756 entrypoint(_id, r, [_id](const char* name, const char* err) {
757 (stringfmt() << "LSNES_CORE_GET_CONTROLLERCONFIG(" << _id << ") failed: "
758 << err).throwex();
760 controller_set cset;
761 for(unsigned* pt = r.controller_types; *pt != 0xFFFFFFFFU; pt++) {
762 unsigned _pt = *pt;
763 if(!ports.count(_pt))
764 throw std::runtime_error("Illegal port type selected by core");
765 portctrl::type* pt2 = ports[_pt];
766 cset.ports.push_back(pt2);
768 for(lsnes_core_get_controllerconfig_logical_entry* le = r.logical_map;
769 le->port | le->controller; le++) {
770 cset.logical_map.push_back(std::make_pair(le->port, le->controller));
772 return cset;
774 private:
775 void copy_settings(std::vector<char>& tmpmem, std::vector<lsnes_core_system_setting>& tmpmem2,
776 std::map<std::string, std::string>& settings)
778 size_t asize = 0;
779 for(auto i : settings)
780 asize += i.first.length() + i.second.length() + 2;
781 tmpmem.resize(asize);
782 asize = 0;
783 for(auto i : settings) {
784 lsnes_core_system_setting s;
785 std::copy(i.first.begin(), i.first.end(), tmpmem.begin() + asize);
786 s.name = &tmpmem[asize];
787 asize += i.first.length();
788 tmpmem[asize++] = 0;
789 std::copy(i.second.begin(), i.second.end(), tmpmem.begin() + asize);
790 s.value = &tmpmem[asize];
791 asize += i.second.length();
792 tmpmem[asize++] = 0;
793 tmpmem2.push_back(s);
795 lsnes_core_system_setting s;
796 s.name = NULL;
797 s.value = NULL;
798 tmpmem2.push_back(s);
800 std::map<unsigned, portctrl::type*> ports;
801 entrypoint_fn entrypoint;
802 unsigned rcount;
803 unsigned id;
806 std::vector<char> msgbuf;
808 void callback_message(const char* msg, size_t length)
810 std::string _msg(msg, msg + length);
811 messages << _msg << std::endl;
814 short callback_get_input(unsigned port, unsigned index, unsigned control)
816 short v = ecore_callbacks->get_input(port, index, control);
817 if(current_core && (port || index || v))
818 current_core->set_internal_pflag();
819 return v;
822 void callback_notify_action_update()
824 ecore_callbacks->action_state_updated();
827 void callback_timer_tick(uint32_t increment, uint32_t per_second)
829 ecore_callbacks->timer_tick(increment, per_second);
832 const char* callback_get_firmware_path()
834 std::string fwp = ecore_callbacks->get_firmware_path();
835 msgbuf.resize(fwp.length() + 1);
836 std::copy(fwp.begin(), fwp.end(), msgbuf.begin());
837 msgbuf[fwp.length()] = 0;
838 return &msgbuf[0];
841 const char* callback_get_base_path()
843 std::string fwp = ecore_callbacks->get_base_path();
844 msgbuf.resize(fwp.length() + 1);
845 std::copy(fwp.begin(), fwp.end(), msgbuf.begin());
846 msgbuf[fwp.length()] = 0;
847 return &msgbuf[0];
850 time_t callback_get_time()
852 return ecore_callbacks->get_time();
855 time_t callback_get_randomseed()
857 return ecore_callbacks->get_randomseed();
860 void callback_memory_read(uint64_t addr, uint64_t value)
862 ecore_callbacks->memory_read(addr, value);
865 void callback_memory_write(uint64_t addr, uint64_t value)
867 ecore_callbacks->memory_write(addr, value);
870 void callback_memory_execute(uint64_t addr, uint64_t cpunum)
872 ecore_callbacks->memory_execute(addr, cpunum);
875 void callback_memory_trace(uint64_t proc, const char* str, int insn)
877 ecore_callbacks->memory_trace(proc, str, insn);
880 void callback_submit_sound(const int16_t* samples, size_t count, int stereo, double rate)
882 CORE().audio->submit_buffer((int16_t*)samples, count, stereo, rate);
885 void callback_notify_latch(const char** params)
887 std::list<std::string> ps;
888 if(params)
889 for(const char** p = params; *p; p++)
890 ps.push_back(*p);
891 ecore_callbacks->notify_latch(ps);
894 void callback_submit_frame(struct lsnes_core_framebuffer_info* _fb, uint32_t fps_n, uint32_t fps_d)
896 framebuffer::info fbinfo = translate_info(_fb);
897 framebuffer::raw fb(fbinfo);
898 ecore_callbacks->output_frame(fb, fps_n, fps_d);
901 struct fpcfn
903 std::function<unsigned char()> fn;
904 static unsigned char call(void* ctx)
906 return reinterpret_cast<fpcfn*>(ctx)->fn();
910 class ccore_disasm : public disassembler
912 public:
913 ccore_disasm(struct lsnes_core_disassembler* disasm)
914 : disassembler(disasm->name)
916 fn = disasm->fn;
918 ~ccore_disasm()
921 std::string disassemble(uint64_t base, std::function<unsigned char()> fetchpc)
923 fpcfn y;
924 y.fn = fetchpc;
925 const char* out = fn(base, fpcfn::call, &y);
926 return out;
928 private:
929 const char* (*fn)(uint64_t base, unsigned char(*fetch)(void* ctx), void* ctx);
932 void* callback_add_disasm(struct lsnes_core_disassembler* disasm)
934 return new ccore_disasm(disasm);
937 void callback_remove_disasm(void* handle)
939 delete reinterpret_cast<ccore_disasm*>(handle);
942 struct utf8_strlen_iter
944 utf8_strlen_iter() { str_len = 0; }
945 utf8_strlen_iter& operator++() { str_len++; return *this; }
946 uint32_t& operator*() { return dummy; }
947 size_t str_len;
948 uint32_t dummy;
951 template<typename T>
952 void callback_render_text2(struct lsnes_core_fontrender_req& req, const std::string& str)
954 auto size = main_font.get_metrics(str, 0, false, false);
955 size_t memreq = size.first * size.second * sizeof(T);
956 if(!memreq) memreq = 1;
957 if(size.first && memreq / size.first / sizeof(T) < size.second)
958 throw std::bad_alloc(); //Not enough memory.
959 req.bitmap = req.alloc(req.cb_ctx, memreq);
960 if(!req.bitmap)
961 throw std::bad_alloc(); //Not enough memory.
962 T fg = (T)req.fg_color;
963 T bg = (T)req.bg_color;
964 T* bmp = (T*)req.bitmap;
966 main_font.for_each_glyph(str, 0, false, false, [size, &fg, &bg, bmp](uint32_t ix, uint32_t iy,
967 const framebuffer::font::glyph& g, bool hdbl, bool vdbl) {
968 T* _bmp = bmp + (iy * size.first + ix);
969 size_t w = g.get_width();
970 size_t skip = size.first - w;
971 for(size_t _y = 0; _y < g.get_height(); _y++) {
972 for(size_t _x = 0; _x < g.get_width(); _x++, _bmp++) {
973 *_bmp = g.read_pixel(_x, _y) ? fg : bg;
975 _bmp = _bmp + skip;
978 req.width = size.first;
979 req.height = size.second;
982 void callback_render_text1(struct lsnes_core_fontrender_req& req, const std::string& str)
984 switch(req.bytes_pp) {
985 case 1:
986 callback_render_text2<uint8_t>(req, str);
987 return;
988 case 2:
989 callback_render_text2<uint16_t>(req, str);
990 return;
991 case 3:
992 callback_render_text2<ss_uint24_t>(req, str);
993 return;
994 case 4:
995 callback_render_text2<uint32_t>(req, str);
996 return;
997 default:
998 throw std::runtime_error("Invalid req.bytes_pp");
1002 int callback_render_text(struct lsnes_core_fontrender_req* req)
1004 req->bitmap = NULL;
1005 //If indeterminate length, make it determinate.
1006 if(req->text_len < 0)
1007 req->text_len = strlen(req->text);
1008 const char* text_start = req->text;
1009 const char* text_end = req->text + req->text_len;
1010 try {
1011 std::string str(text_start, text_end);
1012 callback_render_text1(*req, str);
1013 return 0;
1014 } catch(...) {
1015 return -1;
1019 core_sysregion* create_sysregion(entrypoint_fn& entrypoint, std::map<unsigned, core_region*>& regions,
1020 std::map<unsigned, c_core_type*>& types, unsigned sysreg)
1022 struct lsnes_core_get_sysregion_info r;
1023 entrypoint(sysreg, r, [sysreg](const char* name, const char* err) {
1024 (stringfmt() << "LSNES_CORE_GET_SYSREGION_INFO(" << sysreg << ") failed: " << err).throwex();
1026 register_sysregion_mapping(r.name, r.for_system);
1027 if(!types.count(r.type))
1028 throw std::runtime_error("create_sysregion: Unknown type");
1029 if(!regions.count(r.region))
1030 throw std::runtime_error("create_sysregion: Unknown region");
1031 return new core_sysregion(r.name, *types[r.type], *regions[r.region]);
1034 core_region* create_region(entrypoint_fn& entrypoint, unsigned region)
1036 struct lsnes_core_get_region_info r;
1037 entrypoint(region, r, [region](const char* name, const char* err) {
1038 (stringfmt() << "LSNES_CORE_GET_REGION_INFO(" << region << ") failed: " << err).throwex();
1040 core_region_params p;
1041 p.iname = r.iname;
1042 p.hname = r.hname;
1043 p.priority = r.priority;
1044 p.handle = region;
1045 p.multi = r.multi;
1046 p.framemagic[0] = r.fps_n;
1047 p.framemagic[1] = r.fps_d;
1048 for(size_t i = 0; r.compatible_runs[i] != 0xFFFFFFFFU; i++)
1049 p.compatible_runs.push_back(r.compatible_runs[i]);
1050 return new core_region(p);
1053 c_core_core* create_core(c_lib_init& lib, entrypoint_fn& entrypoint,
1054 std::map<unsigned, core_region*>& regions, unsigned core)
1056 c_core_core_params p;
1057 struct lsnes_core_get_core_info r;
1058 entrypoint(core, r, [core](const char* name, const char* err) {
1059 (stringfmt() << "LSNES_CORE_GET_CORE_INFO(" << core << ") failed: " << err).throwex();
1061 //Read ports.
1062 JSON::node root(r.json);
1063 JSON::pointer rootptr(r.root_ptr);
1064 size_t count = root[rootptr].index_count();
1065 for(size_t i = 0; i < count; i++) {
1066 JSON::pointer j = rootptr.index(i);
1067 p.ports.push_back(new portctrl::type_generic(root, j.as_string8()));
1069 //Read actions.
1070 if(r.cap_flags1 & LSNES_CORE_CAP1_ACTION) {
1071 for(lsnes_core_get_core_info_action* i = r.actions; i->iname; i++) {
1072 interface_action a;
1073 a.id = i->id;
1074 a._symbol = i->iname;
1075 a._title = i->hname;
1076 if(!i->parameters)
1077 goto no_parameters;
1078 for(lsnes_core_get_core_info_aparam* k = i->parameters; k->name; k++) {
1079 interface_action_param b;
1080 b.name = strduplicate(k->name);
1081 b.model = strduplicate(k->model);
1082 a.params.push_back(b);
1084 no_parameters:
1085 p.actions.push_back(a);
1088 //Read trace CPUs.
1089 if(r.cap_flags1 & LSNES_CORE_CAP1_TRACE) {
1090 for(const char** i = r.trace_cpu_list; *i; i++) {
1091 p.trace_cpus.push_back(*i);
1094 for(auto & j : regions)
1095 p.regions[j.first] = j.second;
1096 p.shortname = r.shortname;
1097 p.fullname = r.fullname;
1098 p.flags = r.cap_flags1;
1099 p.id = core;
1100 p.library = &lib;
1101 return new c_core_core(p);
1104 c_core_type* create_type(c_lib_init& lib, entrypoint_fn& entrypoint, std::map<unsigned, c_core_core*>& cores,
1105 std::map<unsigned, core_region*>& regions, unsigned type)
1107 std::vector<core_romimage_info_params> rlist;
1108 std::vector<core_setting_param> plist;
1109 core_type_params p;
1110 struct lsnes_core_get_type_info r;
1111 entrypoint(type, r, [type](const char* name, const char* err) {
1112 (stringfmt() << "LSNES_CORE_GET_TYPE_INFO(" << type << ") failed: " << err).throwex();
1114 if(r.settings) {
1115 for(lsnes_core_get_type_info_param* param = r.settings; param->iname; param++) {
1116 core_setting_param _pr;
1117 _pr.iname = strduplicate(param->iname);
1118 _pr.hname = strduplicate(param->hname);
1119 _pr.dflt = strduplicate(param->dflt);
1120 _pr.regex = strduplicate(param->regex);
1121 if(!param->values)
1122 goto no_values;
1123 for(lsnes_core_get_type_info_paramval* pval = param->values; pval->iname; pval++) {
1124 core_setting_value_param pv;
1125 pv.iname = strduplicate(pval->iname);
1126 pv.hname = strduplicate(pval->hname);
1127 pv.index = pval->index;
1128 _pr.values.push_back(pv);
1130 no_values:
1131 plist.push_back(_pr);
1134 unsigned rcount = 0;
1135 if(r.images) {
1136 for(lsnes_core_get_type_info_romimage* rimg = r.images; rimg->iname; rimg++) {
1137 core_romimage_info_params rp;
1138 rp.iname = rimg->iname;
1139 rp.hname = rimg->hname;
1140 rp.mandatory = rimg->mandatory;
1141 rp.pass_mode = rimg->pass_mode;
1142 rp.headersize = rimg->headersize;
1143 rp.extensions = rimg->extensions;
1144 rlist.push_back(rp);
1145 rcount++;
1148 unsigned _core = r.core;
1149 p.id = type;
1150 p.iname = r.iname;
1151 p.hname = r.hname;
1152 p.sysname = r.sysname;
1153 p.bios = r.bios;
1154 p.settings = plist;
1155 p.images = rlist;
1156 if(!cores.count(_core))
1157 throw std::runtime_error("create_type: Unknown core");
1158 p.core = cores[_core];
1159 for(unsigned* reg = r.regions; *reg != 0xFFFFFFFFU; reg++) {
1160 if(!regions.count(*reg))
1161 throw std::runtime_error("create_type: Unknown region");
1162 p.regions.push_back(regions[*reg]);
1164 return new c_core_type(lib, p, cores[_core]->get_ports(), rcount, type);
1167 std::map<const void*, std::list<core_sysregion*>> bylib_sysregion;
1168 std::map<const void*, std::list<core_region*>> bylib_region;
1169 std::map<const void*, std::list<core_type*>> bylib_type;
1170 std::map<const void*, std::list<core_core*>> bylib_core;
1171 std::map<const void*, c_lib_init*> bylib_init;
1173 void initialize_core2(entrypoint_fn fn, std::map<unsigned, core_sysregion*>& sysregs,
1174 std::map<unsigned, core_region*>& regions, std::map<unsigned, c_core_type*>& types,
1175 std::map<unsigned, c_core_core*>& cores, const void* mod_id)
1177 c_lib_init& lib = *new c_lib_init(fn);
1178 for(auto& i : regions)
1179 i.second = create_region(fn, i.first);
1180 for(auto& i : cores)
1181 i.second = create_core(lib, fn, regions, i.first);
1182 for(auto& i : types)
1183 i.second = create_type(lib, fn, cores, regions, i.first);
1184 for(auto& i : sysregs)
1185 i.second = create_sysregion(fn, regions, types, i.first);
1186 //Mark the libs.
1187 if(mod_id) {
1188 for(auto& i : sysregs) bylib_sysregion[mod_id].push_back(i.second);
1189 for(auto& i : regions) bylib_region[mod_id].push_back(i.second);
1190 for(auto& i : types) bylib_type[mod_id].push_back(i.second);
1191 for(auto& i : cores) bylib_core[mod_id].push_back(i.second);
1192 bylib_init[mod_id] = &lib;
1194 //We don't call install_handler, because that is done automatically.
1197 void initialize_core(lsnes_core_func_t fn, const void* mod_id)
1199 //Enumerate what the thing supports.
1200 entrypoint_fn entrypoint(fn);
1201 lsnes_core_enumerate_cores r;
1202 r.emu_flags1 = 2;
1203 r.message = callback_message;
1204 r.get_input = callback_get_input;
1205 r.notify_action_update = callback_notify_action_update;
1206 r.timer_tick = callback_timer_tick;
1207 r.get_firmware_path = callback_get_firmware_path;
1208 r.get_base_path = callback_get_base_path;
1209 r.get_time = callback_get_time;
1210 r.get_randomseed = callback_get_randomseed;
1211 r.memory_read = callback_memory_read;
1212 r.memory_write = callback_memory_write;
1213 r.memory_execute = callback_memory_execute;
1214 r.memory_trace = callback_memory_trace;
1215 r.submit_sound = callback_submit_sound;
1216 r.notify_latch = callback_notify_latch;
1217 r.submit_frame = callback_submit_frame;
1218 r.add_disasm = callback_add_disasm;
1219 r.remove_disasm = callback_remove_disasm;
1220 r.render_text = callback_render_text;
1221 entrypoint(0, r, [](const char* name, const char* err) {
1222 (stringfmt() << "LSNES_CORE_ENUMERATE_CORES(0) failed: " << err).throwex();
1224 //Collect sysregions, types and cores.
1225 std::map<unsigned, core_region*> regions;
1226 std::map<unsigned, core_sysregion*> sysregs;
1227 std::map<unsigned, c_core_type*> types;
1228 std::map<unsigned, c_core_core*> cores;
1229 for(size_t i = 0; r.sysregions[i] != 0xFFFFFFFFU; i++) {
1230 unsigned sysreg = r.sysregions[i];
1231 sysregs.insert(std::make_pair(sysreg, nullptr));
1232 struct lsnes_core_get_sysregion_info r2;
1233 entrypoint(sysreg, r2, [sysreg](const char* name, const char* err) {
1234 (stringfmt() << "LSNES_CORE_GET_SYSREGION_INFO(" << sysreg << ") failed: "
1235 << err).throwex();
1237 unsigned type = r2.type;
1238 types.insert(std::make_pair(type, nullptr));
1239 struct lsnes_core_get_type_info r3;
1240 entrypoint(type, r3, [type](const char* name, const char* err) {
1241 (stringfmt() << "LSNES_CORE_GET_TYPE_INFO(" << type << ") failed: "
1242 << err).throwex();
1244 cores.insert(std::make_pair(r3.core, nullptr));
1245 for(size_t j = 0; r3.regions[j] != 0xFFFFFFFFU; j++) {
1246 regions.insert(std::make_pair(r3.regions[j], nullptr));
1249 //Do the rest.
1250 initialize_core2(entrypoint, sysregs, regions, types, cores, mod_id);
1253 template<typename T> void cleanup_list(std::map<const void*, std::list<T*>>& list, const void* handle)
1255 if(!list.count(handle))
1256 return;
1257 for(auto i : list[handle])
1258 delete i;
1259 list.erase(handle);
1262 template<typename T> void cleanup_entry(std::map<const void*, T*>& list, const void* handle)
1264 if(!list.count(handle))
1265 return;
1266 delete list[handle];
1267 list.erase(handle);
1272 void lsnes_register_builtin_core(lsnes_core_func_t fn)
1274 corequeue().push_back(fn);
1277 void try_init_c_module(const loadlib::module& module)
1279 try {
1280 lsnes_core_func_t fn = module.fn<int, unsigned, unsigned, void*,
1281 const char**>("lsnes_core_entrypoint");
1282 initialize_core(fn, &module);
1283 } catch(std::exception& e) {
1284 messages << "Can't initialize core: " << e.what() << std::endl;
1288 void try_uninit_c_module(const loadlib::module& module)
1290 if(bylib_core.count(&module))
1291 for(auto i : bylib_core[&module])
1292 i->uninstall_handler();
1293 cleanup_list(bylib_sysregion, &module);
1294 cleanup_list(bylib_region, &module);
1295 cleanup_list(bylib_type, &module);
1296 cleanup_list(bylib_core, &module);
1297 cleanup_entry(bylib_init, &module);
1300 bool core_uses_module(core_core* core, const loadlib::module& module)
1302 if(!bylib_core.count(&module))
1303 return false;
1304 for(auto i : bylib_core[&module])
1305 if(i == core)
1306 return true;
1307 return false;
1310 void initialize_all_builtin_c_cores()
1312 while(!corequeue().empty()) {
1313 lsnes_core_func_t fn = corequeue().front();
1314 corequeue().pop_front();
1315 try {
1316 initialize_core(fn, NULL);
1317 } catch(std::exception& e) {
1318 messages << "Can't initialize core: " << e.what() << std::endl;