Mark the core methods that should be idempotent as const
[lsnes.git] / src / interface / c-interface.cpp
blobcd58c1e04b60cc50db978b8796b2e8ad440c7563
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"
19 template<> int ccore_call_param_map<lsnes_core_enumerate_cores>::id = LSNES_CORE_ENUMERATE_CORES;
20 template<> int ccore_call_param_map<lsnes_core_get_core_info>::id = LSNES_CORE_GET_CORE_INFO;
21 template<> int ccore_call_param_map<lsnes_core_get_type_info>::id = LSNES_CORE_GET_TYPE_INFO;
22 template<> int ccore_call_param_map<lsnes_core_get_region_info>::id = LSNES_CORE_GET_REGION_INFO;
23 template<> int ccore_call_param_map<lsnes_core_get_sysregion_info>::id = LSNES_CORE_GET_SYSREGION_INFO;
24 template<> int ccore_call_param_map<lsnes_core_get_av_state>::id = LSNES_CORE_GET_AV_STATE;
25 template<> int ccore_call_param_map<lsnes_core_emulate>::id = LSNES_CORE_EMULATE;
26 template<> int ccore_call_param_map<lsnes_core_savestate>::id = LSNES_CORE_SAVESTATE;
27 template<> int ccore_call_param_map<lsnes_core_loadstate>::id = LSNES_CORE_LOADSTATE;
28 template<> int ccore_call_param_map<lsnes_core_get_controllerconfig>::id = LSNES_CORE_GET_CONTROLLERCONFIG;
29 template<> int ccore_call_param_map<lsnes_core_load_rom>::id = LSNES_CORE_LOAD_ROM;
30 template<> int ccore_call_param_map<lsnes_core_get_region>::id = LSNES_CORE_GET_REGION;
31 template<> int ccore_call_param_map<lsnes_core_set_region>::id = LSNES_CORE_SET_REGION;
32 template<> int ccore_call_param_map<lsnes_core_deinitialize>::id = LSNES_CORE_DEINITIALIZE;
33 template<> int ccore_call_param_map<lsnes_core_get_pflag>::id = LSNES_CORE_GET_PFLAG;
34 template<> int ccore_call_param_map<lsnes_core_set_pflag>::id = LSNES_CORE_SET_PFLAG;
35 template<> int ccore_call_param_map<lsnes_core_get_action_flags>::id = LSNES_CORE_GET_ACTION_FLAGS;
36 template<> int ccore_call_param_map<lsnes_core_execute_action>::id = LSNES_CORE_EXECUTE_ACTION;
37 template<> int ccore_call_param_map<lsnes_core_get_bus_mapping>::id = LSNES_CORE_GET_BUS_MAPPING;
38 template<> int ccore_call_param_map<lsnes_core_enumerate_sram>::id = LSNES_CORE_ENUMERATE_SRAM;
39 template<> int ccore_call_param_map<lsnes_core_save_sram>::id = LSNES_CORE_SAVE_SRAM;
40 template<> int ccore_call_param_map<lsnes_core_load_sram>::id = LSNES_CORE_LOAD_SRAM;
41 template<> int ccore_call_param_map<lsnes_core_get_reset_action>::id = LSNES_CORE_GET_RESET_ACTION;
42 template<> int ccore_call_param_map<lsnes_core_compute_scale>::id = LSNES_CORE_COMPUTE_SCALE;
43 template<> int ccore_call_param_map<lsnes_core_runtosave>::id = LSNES_CORE_RUNTOSAVE;
44 template<> int ccore_call_param_map<lsnes_core_poweron>::id = LSNES_CORE_POWERON;
45 template<> int ccore_call_param_map<lsnes_core_unload_cartridge>::id = LSNES_CORE_UNLOAD_CARTRIDGE;
46 template<> int ccore_call_param_map<lsnes_core_debug_reset>::id = LSNES_CORE_DEBUG_RESET;
47 template<> int ccore_call_param_map<lsnes_core_set_debug_flags>::id = LSNES_CORE_SET_DEBUG_FLAGS;
48 template<> int ccore_call_param_map<lsnes_core_set_cheat>::id = LSNES_CORE_SET_CHEAT;
49 template<> int ccore_call_param_map<lsnes_core_draw_cover>::id = LSNES_CORE_DRAW_COVER;
50 template<> int ccore_call_param_map<lsnes_core_pre_emulate>::id = LSNES_CORE_PRE_EMULATE;
51 template<> int ccore_call_param_map<lsnes_core_get_device_regs>::id = LSNES_CORE_GET_DEVICE_REGS;
52 template<> int ccore_call_param_map<lsnes_core_get_vma_list>::id = LSNES_CORE_GET_VMA_LIST;
54 template<> const char* ccore_call_param_map<lsnes_core_enumerate_cores>::name = "LSNES_CORE_ENUMERATE_CORES";
55 template<> const char* ccore_call_param_map<lsnes_core_get_core_info>::name = "LSNES_CORE_GET_CORE_INFO";
56 template<> const char* ccore_call_param_map<lsnes_core_get_type_info>::name = "LSNES_CORE_GET_TYPE_INFO";
57 template<> const char* ccore_call_param_map<lsnes_core_get_region_info>::name = "LSNES_CORE_GET_REGION_INFO";
58 template<> const char* ccore_call_param_map<lsnes_core_get_sysregion_info>::name = "LSNES_CORE_GET_SYSREGION_INFO";
59 template<> const char* ccore_call_param_map<lsnes_core_get_av_state>::name = "LSNES_CORE_GET_AV_STATE";
60 template<> const char* ccore_call_param_map<lsnes_core_emulate>::name = "LSNES_CORE_EMULATE";
61 template<> const char* ccore_call_param_map<lsnes_core_savestate>::name = "LSNES_CORE_SAVESTATE";
62 template<> const char* ccore_call_param_map<lsnes_core_loadstate>::name = "LSNES_CORE_LOADSTATE";
63 template<> const char* ccore_call_param_map<lsnes_core_get_controllerconfig>::name =
64 "LSNES_CORE_GET_CONTROLLERCONFIG";
65 template<> const char* ccore_call_param_map<lsnes_core_load_rom>::name = "LSNES_CORE_LOAD_ROM";
66 template<> const char* ccore_call_param_map<lsnes_core_get_region>::name = "LSNES_CORE_GET_REGION";
67 template<> const char* ccore_call_param_map<lsnes_core_set_region>::name = "LSNES_CORE_SET_REGION";
68 template<> const char* ccore_call_param_map<lsnes_core_deinitialize>::name = "LSNES_CORE_DEINITIALIZE";
69 template<> const char* ccore_call_param_map<lsnes_core_get_pflag>::name = "LSNES_CORE_GET_PFLAG";
70 template<> const char* ccore_call_param_map<lsnes_core_set_pflag>::name = "LSNES_CORE_SET_PFLAG";
71 template<> const char* ccore_call_param_map<lsnes_core_get_action_flags>::name = "LSNES_CORE_GET_ACTION_FLAGS";
72 template<> const char* ccore_call_param_map<lsnes_core_execute_action>::name = "LSNES_CORE_EXECUTE_ACTION";
73 template<> const char* ccore_call_param_map<lsnes_core_get_bus_mapping>::name = "LSNES_CORE_GET_BUS_MAPPING";
74 template<> const char* ccore_call_param_map<lsnes_core_enumerate_sram>::name = "LSNES_CORE_ENUMERATE_SRAM";
75 template<> const char* ccore_call_param_map<lsnes_core_save_sram>::name = "LSNES_CORE_SAVE_SRAM";
76 template<> const char* ccore_call_param_map<lsnes_core_load_sram>::name = "LSNES_CORE_LOAD_SRAM";
77 template<> const char* ccore_call_param_map<lsnes_core_get_reset_action>::name = "LSNES_CORE_GET_RESET_ACTION";
78 template<> const char* ccore_call_param_map<lsnes_core_compute_scale>::name = "LSNES_CORE_COMPUTE_SCALE";
79 template<> const char* ccore_call_param_map<lsnes_core_runtosave>::name = "LSNES_CORE_RUNTOSAVE";
80 template<> const char* ccore_call_param_map<lsnes_core_poweron>::name = "LSNES_CORE_POWERON";
81 template<> const char* ccore_call_param_map<lsnes_core_unload_cartridge>::name = "LSNES_CORE_UNLOAD_CARTRIDGE";
82 template<> const char* ccore_call_param_map<lsnes_core_debug_reset>::name = "LSNES_CORE_DEBUG_RESET";
83 template<> const char* ccore_call_param_map<lsnes_core_set_debug_flags>::name = "LSNES_CORE_SET_DEBUG_FLAGS";
84 template<> const char* ccore_call_param_map<lsnes_core_set_cheat>::name = "LSNES_CORE_SET_CHEAT";
85 template<> const char* ccore_call_param_map<lsnes_core_draw_cover>::name = "LSNES_CORE_DRAW_COVER";
86 template<> const char* ccore_call_param_map<lsnes_core_pre_emulate>::name = "LSNES_CORE_PRE_EMULATE";
87 template<> const char* ccore_call_param_map<lsnes_core_get_device_regs>::name = "LSNES_CORE_GET_DEVICE_REGS";
88 template<> const char* ccore_call_param_map<lsnes_core_get_vma_list>::name = "LSNES_CORE_GET_VMA_LIST";
90 namespace
92 struct c_core_core;
93 c_core_core* current_core = NULL;
95 char* strduplicate(const char* x)
97 if(!x) return NULL;
98 char* out = (char*)malloc(strlen(x) + 1);
99 if(!out)
100 throw std::bad_alloc();
101 strcpy(out, x);
102 return out;
105 std::list<lsnes_core_func_t>& corequeue()
107 static std::list<lsnes_core_func_t> x;
108 return x;
111 void default_error_function(const char* callname, const char* err)
113 messages << "Warning: " << callname << " failed: " << err << std::endl;
116 framebuffer::info translate_info(lsnes_core_framebuffer_info* _fb)
118 framebuffer::info fbinfo;
119 switch(_fb->type) {
120 case LSNES_CORE_PIXFMT_RGB15: fbinfo.type = &framebuffer::pixfmt_rgb15; break;
121 case LSNES_CORE_PIXFMT_BGR15: fbinfo.type = &framebuffer::pixfmt_bgr15; break;
122 case LSNES_CORE_PIXFMT_RGB16: fbinfo.type = &framebuffer::pixfmt_rgb16; break;
123 case LSNES_CORE_PIXFMT_BGR16: fbinfo.type = &framebuffer::pixfmt_bgr16; break;
124 case LSNES_CORE_PIXFMT_RGB24: fbinfo.type = &framebuffer::pixfmt_rgb24; break;
125 case LSNES_CORE_PIXFMT_BGR24: fbinfo.type = &framebuffer::pixfmt_bgr24; break;
126 case LSNES_CORE_PIXFMT_RGB32: fbinfo.type = &framebuffer::pixfmt_rgb32; break;
127 case LSNES_CORE_PIXFMT_LRGB: fbinfo.type = &framebuffer::pixfmt_lrgb; break;
129 fbinfo.mem = (char*)_fb->mem;
130 fbinfo.physwidth = _fb->physwidth;
131 fbinfo.physheight = _fb->physheight;
132 fbinfo.physstride = _fb->physstride;
133 fbinfo.width = _fb->width;
134 fbinfo.height = _fb->height;
135 fbinfo.stride = _fb->stride;
136 fbinfo.offset_x = _fb->offset_x;
137 fbinfo.offset_y = _fb->offset_y;
138 return fbinfo;
141 struct entrypoint_fn
143 entrypoint_fn(lsnes_core_func_t _fn) : fn(_fn) {}
144 template<typename T> bool operator()(unsigned item, T& args,
145 std::function<void(const char* callname, const char* err)> onerror)
147 const char* err = NULL;
148 int r = fn(ccore_call_param_map<T>::id, item, &args, &err);
149 if(r < 0)
150 onerror(ccore_call_param_map<T>::name, err);
151 return (r >= 0);
153 template<typename T> bool operator()(unsigned item, T& args)
155 return (*this)(item, args, default_error_function);
157 private:
158 lsnes_core_func_t fn;
161 struct c_lib_init
163 public:
164 c_lib_init(entrypoint_fn _entrypoint)
165 : entrypoint(_entrypoint)
167 count = 0;
169 void initialize()
171 count++;
173 void deinitialize()
175 if(count) count--;
176 if(!count) {
177 lsnes_core_deinitialize s;
178 entrypoint(0, s);
181 entrypoint_fn get_entrypoint()
183 return entrypoint;
185 private:
186 int count;
187 entrypoint_fn entrypoint;
190 struct c_core_core_params
192 std::vector<interface_action> actions;
193 std::vector<std::string> trace_cpus;
194 std::vector<portctrl::type*> ports;
195 const char* shortname;
196 const char* fullname;
197 unsigned flags;
198 unsigned id;
199 std::map<unsigned, core_region*> regions;
200 c_lib_init* library;
203 struct c_core_core : public core_core
205 c_core_core(c_core_core_params& p)
206 : core_core(p.ports, p.actions), entrypoint(p.library->get_entrypoint()), plugin(p.library)
208 fullname = p.fullname;
209 shortname = p.shortname;
210 id = p.id;
211 internal_pflag = false;
212 caps1 = p.flags;
213 regions = p.regions;
214 actions = p.actions;
215 trace_cpus = p.trace_cpus;
216 for(size_t i = 0; i < p.ports.size(); i++)
217 ports[i] = p.ports[i];
219 ~c_core_core() throw();
220 std::string c_core_identifier() const
222 return fullname;
224 bool get_av_state(lsnes_core_get_av_state& s)
226 return entrypoint(id, s);
228 std::pair<uint32_t, uint32_t> c_video_rate()
230 lsnes_core_get_av_state s;
231 if(!entrypoint(id, s))
232 return std::make_pair(60, 1);
233 return std::make_pair(s.fps_n, s.fps_d);
235 double c_get_PAR()
237 lsnes_core_get_av_state s;
238 return entrypoint(id, s) ? s.par : 1.0;
240 std::pair<uint32_t, uint32_t> c_audio_rate()
242 lsnes_core_get_av_state s;
243 return entrypoint(id, s) ? std::make_pair(s.rate_n, s.rate_d) : std::make_pair(48000U, 1U);
245 void c_power()
247 lsnes_core_poweron s;
248 if(caps1 & LSNES_CORE_CAP1_POWERON) entrypoint(id, s);
250 void c_unload_cartridge()
252 lsnes_core_unload_cartridge s;
253 if(caps1 & LSNES_CORE_CAP1_UNLOAD) entrypoint(id, s);
255 void c_runtosave()
257 lsnes_core_runtosave s;
258 if(caps1 & LSNES_CORE_CAP1_RUNTOSAVE) entrypoint(id, s);
260 void c_emulate()
262 current_core = this;
263 lsnes_core_emulate s;
264 entrypoint(id, s);
265 current_core = NULL;
267 bool c_get_pflag()
269 lsnes_core_get_pflag s;
270 if(!(caps1 & LSNES_CORE_CAP1_PFLAG) || !entrypoint(id, s))
271 return internal_pflag;
272 return (s.pflag != 0);
274 void c_set_pflag(bool pflag)
276 lsnes_core_set_pflag s;
277 s.pflag = pflag ? 1 : 0;
278 if(!(caps1 & LSNES_CORE_CAP1_PFLAG) || !entrypoint(id, s))
279 internal_pflag = pflag;
281 std::string c_get_core_shortname() const
283 return shortname;
285 void c_debug_reset()
287 lsnes_core_debug_reset s;
288 if(caps1 & (LSNES_CORE_CAP1_DEBUG | LSNES_CORE_CAP1_TRACE | LSNES_CORE_CAP1_CHEAT))
289 entrypoint(id, s);
291 std::pair<unsigned, unsigned> c_lightgun_scale()
293 lsnes_core_get_av_state s;
294 if(!(caps1 & LSNES_CORE_CAP1_LIGHTGUN) || !entrypoint(id, s))
295 return std::make_pair(0, 0);
296 return std::make_pair(s.lightgun_width, s.lightgun_height);
298 std::pair<uint64_t, uint64_t> c_get_bus_map()
300 lsnes_core_get_bus_mapping s;
301 if(!(caps1 & LSNES_CORE_CAP1_BUSMAP) || !entrypoint(id, s))
302 return std::make_pair(0, 0);
303 return std::make_pair(s.base, s.size);
305 int c_reset_action(bool hard)
307 lsnes_core_get_reset_action s;
308 if(!(caps1 & LSNES_CORE_CAP1_RESET) || !entrypoint(id, s))
309 return -1;
310 return hard ? s.hardreset : s.softreset;
312 std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height)
314 lsnes_core_compute_scale s;
315 uint32_t hscale, vscale;
316 if(width >= 360) hscale = 1;
317 else hscale = 360 / width + 1;
318 if(height >= 320) vscale = 1;
319 else vscale = 320 / height + 1;
320 if(caps1 & LSNES_CORE_CAP1_SCALE) {
321 s.width = width;
322 s.height = height;
323 if(entrypoint(id, s)) {
324 hscale = s.hfactor;
325 vscale = s.vfactor;
328 return std::make_pair(hscale, vscale);
330 void c_pre_emulate_frame(portctrl::frame& cf)
332 lsnes_core_pre_emulate s;
333 if(caps1 & LSNES_CORE_CAP1_PREEMULATE) {
334 s.context = &cf;
335 s.set_input = [](void* context, unsigned port, unsigned controller, unsigned index,
336 short value) -> void {
337 portctrl::frame& cf = *(portctrl::frame*)context;
338 cf.axis3(port, controller, index, value);
340 entrypoint(id, s);
343 std::set<std::string> c_srams()
345 lsnes_core_enumerate_sram s;
346 std::set<std::string> ret;
347 if(caps1 & LSNES_CORE_CAP1_SRAM) {
348 if(entrypoint(id, s)) {
349 const char** sr = s.srams;
350 while(*sr) {
351 ret.insert(*sr);
352 sr++;
356 return ret;
358 void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc)
360 lsnes_core_load_sram s;
361 if(caps1 & LSNES_CORE_CAP1_SRAM) {
362 std::vector<lsnes_core_sram> srams;
363 std::vector<lsnes_core_sram*> sramsp;
364 std::vector<char> names;
365 srams.resize(sram.size() + 1);
366 srams[sram.size()].name = NULL;
367 size_t idx = 0;
368 size_t nlength = 0;
369 for(auto& i : sram)
370 nlength += i.first.length() + 1;
371 names.resize(nlength);
372 size_t nidx = 0;
373 for(auto& i : sram) {
374 size_t ntmp = nidx;
375 std::copy(i.first.begin(), i.first.end(), names.begin() + nidx);
376 nidx += i.first.length();
377 names[nidx++] = '\0';
378 srams[idx].size = i.second.size();
379 srams[idx].data = &i.second[0];
380 srams[idx].name = &names[ntmp];
381 idx++;
383 s.srams = &srams[0];
384 entrypoint(id, s);
387 std::map<std::string, std::vector<char>> c_save_sram() throw(std::bad_alloc)
389 lsnes_core_save_sram s;
390 std::map<std::string, std::vector<char>> ret;
391 if(caps1 & LSNES_CORE_CAP1_SRAM) {
392 if(entrypoint(id, s)) {
393 lsnes_core_sram* p = s.srams;
394 while(p->name) {
395 ret[p->name].resize(p->size);
396 memcpy(&ret[p->name][0], p->data, p->size);
397 p++;
401 return ret;
403 void c_unserialize(const char* in, size_t insize)
405 lsnes_core_loadstate s;
406 s.data = in;
407 s.size = insize;
408 entrypoint(id, s, [](const char* name, const char* err) {
409 throw std::runtime_error("Loadstate failed: " + std::string(err));
412 void c_serialize(std::vector<char>& out)
414 lsnes_core_savestate s;
415 entrypoint(id, s, [](const char* name, const char* err) {
416 throw std::runtime_error("Savestate failed: " + std::string(err));
418 out.resize(s.size);
419 memcpy(&out[0], s.data, s.size);
421 unsigned c_action_flags(unsigned _id)
423 lsnes_core_get_action_flags s;
424 if(caps1 & LSNES_CORE_CAP1_ACTION) {
425 s.action = _id;
426 return entrypoint(id, s) ? s.flags : 0;
428 return 0;
430 std::vector<std::string> c_get_trace_cpus()
432 return trace_cpus;
434 bool c_set_region(core_region& region)
436 lsnes_core_set_region s;
437 if(caps1 & LSNES_CORE_CAP1_MULTIREGION) {
438 bool hit = false;
439 for(auto i : regions)
440 if(i.second == &region) {
441 s.region = i.first;
442 hit = true;
444 if(!hit)
445 return false; //Bad region.
446 return entrypoint(id, s);
447 } else {
448 return (regions.count(0) && regions[0] == &region);
451 core_region& c_get_region()
453 lsnes_core_get_region s;
454 if(caps1 & LSNES_CORE_CAP1_MULTIREGION) {
455 if(!entrypoint(id, s)) {
456 if(regions.empty())
457 throw std::runtime_error("No valid regions");
458 return *(regions.begin()->second);
459 } else {
460 if(regions.count(s.region))
461 return *regions[s.region];
462 messages << "Internal error: Core gave invalid region number."
463 << std::endl;
464 if(regions.empty())
465 throw std::runtime_error("No valid regions");
466 return *(regions.begin()->second);
468 } else {
469 if(regions.count(0))
470 return *regions[0];
471 else {
472 messages << "Internal error: Not multi-region core and region 0 not present."
473 << std::endl;
474 if(regions.empty())
475 throw std::runtime_error("No valid regions");
476 return *(regions.begin()->second);
480 const struct interface_device_reg* c_get_registers()
482 static std::vector<interface_device_reg> regs;
483 static std::vector<char> namebuf;
484 static interface_device_reg reg_null = {NULL};
485 lsnes_core_get_device_regs s;
486 if(caps1 & LSNES_CORE_CAP1_REGISTERS) {
487 if(!entrypoint(id, s)) {
488 return &reg_null;
489 } else {
490 size_t count = 0;
491 size_t namelen = 0;
492 auto tregs = s.regs;
493 while(tregs->name) {
494 namelen += strlen(tregs->name) + 1;
495 count++;
496 tregs++;
498 tregs = s.regs;
499 if(regs.size() < count + 1)
500 regs.resize(count + 1);
501 if(namelen > namebuf.size())
502 namebuf.resize(namelen);
503 size_t idx = 0;
504 size_t nameptr = 0;
505 while(tregs->name) {
506 strcpy(&namebuf[nameptr], tregs->name);
507 regs[idx].name = &namebuf[nameptr];
508 regs[idx].read = tregs->read;
509 regs[idx].write = tregs->write;
510 regs[idx].boolean = tregs->boolean;
511 nameptr += strlen(tregs->name) + 1;
512 tregs++;
513 idx++;
515 regs[idx].name = NULL; //The sentinel.
517 } else {
518 return &reg_null;
520 return &regs[0];
522 void c_install_handler()
524 plugin->initialize();
526 void c_uninstall_handler()
528 plugin->deinitialize();
530 void c_set_debug_flags(uint64_t addr, unsigned flags_set, unsigned flags_clear)
532 lsnes_core_set_debug_flags s;
533 s.addr = addr;
534 s.set = flags_set;
535 s.clear = flags_clear;
536 if(caps1 & LSNES_CORE_CAP1_DEBUG)
537 entrypoint(id, s);
538 else
539 messages << "Debugging functions not supported by core" << std::endl;
541 void c_set_cheat(uint64_t addr, uint64_t value, bool set)
543 lsnes_core_set_cheat s;
544 s.addr = addr;
545 s.value = value;
546 s.set = set;
547 if(caps1 & LSNES_CORE_CAP1_CHEAT)
548 entrypoint(id, s);
549 else
550 messages << "Cheat functions not supported by core" << std::endl;
552 void c_execute_action(unsigned aid, const std::vector<interface_action_paramval>& p)
554 if(!(caps1 & LSNES_CORE_CAP1_ACTION)) {
555 messages << "Core does not support actions." << std::endl;
556 return;
558 interface_action* act = NULL;
559 for(auto& i : actions) {
560 if(i.id == aid) {
561 act = &i;
562 break;
565 if(!act) {
566 messages << "Unknown action id #" << aid << std::endl;
567 return;
569 size_t j = 0;
570 std::vector<lsnes_core_execute_action_param> parameters;
571 std::list<std::vector<char>> strtmp;
572 for(auto& b : act->params) {
573 std::string m = b.model;
574 if(m == "bool") {
575 //Boolean.
576 lsnes_core_execute_action_param tp;
577 tp.boolean = p[j++].b;
578 parameters.push_back(tp);
579 } else if(regex_match("int:.*", m)) {
580 //Integer.
581 lsnes_core_execute_action_param tp;
582 tp.integer = p[j++].i;
583 parameters.push_back(tp);
584 } else if(regex_match("string(:.*)?", m) || regex_match("enum:.*", m)) {
585 //String.
586 strtmp.push_back(std::vector<char>());
587 auto& i = strtmp.back();
588 i.resize(p[j].s.length() + 1);
589 std::copy(p[j].s.begin(), p[j].s.end(), i.begin());
590 lsnes_core_execute_action_param tp;
591 tp.string.base = &i[0];
592 tp.string.length = p[j++].s.length();
593 parameters.push_back(tp);
594 } else if(m == "toggle") {
595 //Skip.
596 } else {
597 messages << "Unknown model '" << m << "' in action id #" << aid << std::endl;
598 return;
601 lsnes_core_execute_action s;
602 s.action = aid;
603 s.params = &parameters[0];
604 entrypoint(id, s);
606 framebuffer::raw& c_draw_cover()
608 lsnes_core_draw_cover r;
609 if(caps1 & LSNES_CORE_CAP1_COVER) {
610 if(!entrypoint(id, r))
611 goto failed;
612 framebuffer::info fbinfo = translate_info(r.coverpage);
613 size_t needed = fbinfo.physwidth * fbinfo.physheight * fbinfo.type->get_bpp();
614 if(covermem.size() < needed) covermem.resize(needed);
615 memcpy(&covermem[0], fbinfo.mem, needed);
616 fbinfo.mem = &covermem[0];
617 cover = framebuffer::raw(fbinfo);
618 return cover;
620 failed:
621 if(covermem.size() < 1024) covermem.resize(1024);
622 framebuffer::info fbi;
623 fbi.type = &framebuffer::pixfmt_rgb16;
624 fbi.mem = &covermem[0];
625 fbi.physwidth = 512;
626 fbi.physheight = 448;
627 fbi.physstride = 0;
628 fbi.width = 512;
629 fbi.height = 448;
630 fbi.stride = 0;
631 fbi.offset_x = 0;
632 fbi.offset_y = 0;
633 cover = framebuffer::raw(fbi);
634 return cover;
636 std::list<core_vma_info> c_vma_list()
638 lsnes_core_get_vma_list r;
639 if(caps1 & LSNES_CORE_CAP1_MEMWATCH) {
640 if(!entrypoint(id, r))
641 goto failed;
642 std::list<core_vma_info> vmalist;
643 for(lsnes_core_get_vma_list_vma** vmas = r.vmas; *vmas; vmas++) {
644 lsnes_core_get_vma_list_vma* vma = *vmas;
645 core_vma_info _vma;
646 _vma.name = vma->name;
647 _vma.base = vma->base;
648 _vma.size = vma->size;
649 _vma.endian = vma->endian;
650 _vma.readonly = ((vma->flags & LSNES_CORE_VMA_READONLY) != 0);
651 _vma.special = ((vma->flags & LSNES_CORE_VMA_SPECIAL) != 0);
652 _vma.volatile_flag = ((vma->flags & LSNES_CORE_VMA_VOLATILE) != 0);
653 _vma.backing_ram = vma->direct_map;
654 _vma.read = vma->read;
655 _vma.write = vma->write;
656 vmalist.push_back(_vma);
658 return vmalist;
660 failed:
661 return std::list<core_vma_info>();
663 std::map<unsigned, portctrl::type*> get_ports()
665 return ports;
667 void set_internal_pflag()
669 internal_pflag = true;
671 private:
672 std::string fullname;
673 std::string shortname;
674 unsigned id;
675 bool internal_pflag;
676 unsigned caps1;
677 std::vector<std::string> trace_cpus;
678 std::map<unsigned, portctrl::type*> ports;
679 std::map<unsigned, core_region*> regions;
680 std::vector<interface_action> actions;
681 framebuffer::raw cover;
682 std::vector<char> covermem;
683 entrypoint_fn entrypoint;
684 c_lib_init* plugin;
687 c_core_core::~c_core_core() throw()
691 struct c_core_type : public core_type
693 c_core_type(c_lib_init& lib, core_type_params& p, std::map<unsigned, portctrl::type*> _ports,
694 unsigned _rcount, unsigned _id)
695 : core_type(p), ports(_ports), entrypoint(lib.get_entrypoint()), rcount(_rcount), id(_id)
698 ~c_core_type() throw()
701 int t_load_rom(core_romimage* images, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
702 uint64_t rtc_subsec)
704 lsnes_core_load_rom r;
705 std::vector<char> tmpmem;
706 std::vector<lsnes_core_system_setting> tmpmem2;
707 r.rtc_sec = rtc_sec;
708 r.rtc_subsec = rtc_subsec;
709 copy_settings(tmpmem, tmpmem2, settings);
710 r.settings = &tmpmem2[0];
712 std::vector<lsnes_core_load_rom_image> imgs;
713 imgs.resize(rcount);
714 for(unsigned i = 0; i < rcount; i++) {
715 imgs[i].data = (const char*)images[i].data;
716 imgs[i].size = images[i].size;
717 imgs[i].markup = images[i].markup;
719 r.images = &imgs[0];
720 unsigned _id = id;
721 entrypoint(_id, r, [_id](const char* name, const char* err) {
722 (stringfmt() << "LSNES_CORE_LOAD_ROM(" << _id << ") failed: " << err).throwex();
724 return 0;
726 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
728 lsnes_core_get_controllerconfig r;
729 std::vector<char> tmpmem;
730 std::vector<lsnes_core_system_setting> tmpmem2;
731 copy_settings(tmpmem, tmpmem2, settings);
732 r.settings = &tmpmem2[0];
733 unsigned _id = id;
734 entrypoint(_id, r, [_id](const char* name, const char* err) {
735 (stringfmt() << "LSNES_CORE_GET_CONTROLLERCONFIG(" << _id << ") failed: "
736 << err).throwex();
738 controller_set cset;
739 for(unsigned* pt = r.controller_types; *pt != 0xFFFFFFFFU; pt++) {
740 unsigned _pt = *pt;
741 if(!ports.count(_pt))
742 throw std::runtime_error("Illegal port type selected by core");
743 portctrl::type* pt2 = ports[_pt];
744 cset.ports.push_back(pt2);
746 for(lsnes_core_get_controllerconfig_logical_entry* le = r.logical_map;
747 le->port | le->controller; le++) {
748 cset.logical_map.push_back(std::make_pair(le->port, le->controller));
750 return cset;
752 private:
753 void copy_settings(std::vector<char>& tmpmem, std::vector<lsnes_core_system_setting>& tmpmem2,
754 std::map<std::string, std::string>& settings)
756 size_t asize = 0;
757 for(auto i : settings)
758 asize += i.first.length() + i.second.length() + 2;
759 tmpmem.resize(asize);
760 asize = 0;
761 for(auto i : settings) {
762 lsnes_core_system_setting s;
763 std::copy(i.first.begin(), i.first.end(), tmpmem.begin() + asize);
764 s.name = &tmpmem[asize];
765 asize += i.first.length();
766 tmpmem[asize++] = 0;
767 std::copy(i.second.begin(), i.second.end(), tmpmem.begin() + asize);
768 s.value = &tmpmem[asize];
769 asize += i.second.length();
770 tmpmem[asize++] = 0;
771 tmpmem2.push_back(s);
773 lsnes_core_system_setting s;
774 s.name = NULL;
775 s.value = NULL;
776 tmpmem2.push_back(s);
778 std::map<unsigned, portctrl::type*> ports;
779 entrypoint_fn entrypoint;
780 unsigned rcount;
781 unsigned id;
784 std::vector<char> msgbuf;
786 void callback_message(const char* msg, size_t length)
788 std::string _msg(msg, msg + length);
789 messages << _msg << std::endl;
792 short callback_get_input(unsigned port, unsigned index, unsigned control)
794 short v = ecore_callbacks->get_input(port, index, control);
795 if(current_core && (port || index || v))
796 current_core->set_internal_pflag();
797 return v;
800 void callback_notify_action_update()
802 ecore_callbacks->action_state_updated();
805 void callback_timer_tick(uint32_t increment, uint32_t per_second)
807 ecore_callbacks->timer_tick(increment, per_second);
810 const char* callback_get_firmware_path()
812 std::string fwp = ecore_callbacks->get_firmware_path();
813 msgbuf.resize(fwp.length() + 1);
814 std::copy(fwp.begin(), fwp.end(), msgbuf.begin());
815 msgbuf[fwp.length()] = 0;
816 return &msgbuf[0];
819 const char* callback_get_base_path()
821 std::string fwp = ecore_callbacks->get_base_path();
822 msgbuf.resize(fwp.length() + 1);
823 std::copy(fwp.begin(), fwp.end(), msgbuf.begin());
824 msgbuf[fwp.length()] = 0;
825 return &msgbuf[0];
828 time_t callback_get_time()
830 return ecore_callbacks->get_time();
833 time_t callback_get_randomseed()
835 return ecore_callbacks->get_randomseed();
838 void callback_memory_read(uint64_t addr, uint64_t value)
840 ecore_callbacks->memory_read(addr, value);
843 void callback_memory_write(uint64_t addr, uint64_t value)
845 ecore_callbacks->memory_write(addr, value);
848 void callback_memory_execute(uint64_t addr, uint64_t cpunum)
850 ecore_callbacks->memory_execute(addr, cpunum);
853 void callback_memory_trace(uint64_t proc, const char* str, int insn)
855 ecore_callbacks->memory_trace(proc, str, insn);
858 void callback_submit_sound(const int16_t* samples, size_t count, int stereo, double rate)
860 CORE().audio->submit_buffer((int16_t*)samples, count, stereo, rate);
863 void callback_notify_latch(const char** params)
865 std::list<std::string> ps;
866 if(params)
867 for(const char** p = params; *p; p++)
868 ps.push_back(*p);
869 ecore_callbacks->notify_latch(ps);
872 void callback_submit_frame(struct lsnes_core_framebuffer_info* _fb, uint32_t fps_n, uint32_t fps_d)
874 framebuffer::info fbinfo = translate_info(_fb);
875 framebuffer::raw fb(fbinfo);
876 ecore_callbacks->output_frame(fb, fps_n, fps_d);
879 struct fpcfn
881 std::function<unsigned char()> fn;
882 static unsigned char call(void* ctx)
884 return reinterpret_cast<fpcfn*>(ctx)->fn();
888 class ccore_disasm : public disassembler
890 public:
891 ccore_disasm(struct lsnes_core_disassembler* disasm)
892 : disassembler(disasm->name)
894 fn = disasm->fn;
896 ~ccore_disasm()
899 std::string disassemble(uint64_t base, std::function<unsigned char()> fetchpc)
901 fpcfn y;
902 y.fn = fetchpc;
903 const char* out = fn(base, fpcfn::call, &y);
904 return out;
906 private:
907 const char* (*fn)(uint64_t base, unsigned char(*fetch)(void* ctx), void* ctx);
910 void* callback_add_disasm(struct lsnes_core_disassembler* disasm)
912 return new ccore_disasm(disasm);
915 void callback_remove_disasm(void* handle)
917 delete reinterpret_cast<ccore_disasm*>(handle);
920 struct utf8_strlen_iter
922 utf8_strlen_iter() { str_len = 0; }
923 utf8_strlen_iter& operator++() { str_len++; return *this; }
924 uint32_t& operator*() { return dummy; }
925 size_t str_len;
926 uint32_t dummy;
929 template<typename T>
930 void callback_render_text2(struct lsnes_core_fontrender_req& req, const std::string& str)
932 auto size = main_font.get_metrics(str);
933 auto layout = main_font.dolayout(str);
934 size_t memreq = size.first * size.second * sizeof(T);
935 if(!memreq) memreq = 1;
936 if(size.first && memreq / size.first / sizeof(T) < size.second)
937 throw std::bad_alloc(); //Not enough memory.
938 req.bitmap = req.alloc(req.cb_ctx, memreq);
939 if(!req.bitmap)
940 throw std::bad_alloc(); //Not enough memory.
941 T fg = (T)req.fg_color;
942 T bg = (T)req.bg_color;
943 T* bmp = (T*)req.bitmap;
945 for(auto i : layout) {
946 auto& g = *i.dglyph;
947 T* _bmp = bmp + (i.y * size.first + i.x);
948 size_t w = g.wide ? 16 : 8;
949 size_t skip = size.first - w;
950 for(size_t _y = 0; _y < 16; _y++) {
951 uint32_t d = g.data[_y >> (g.wide ? 1 : 2)];
952 if(g.wide)
953 d >>= 16 - ((_y & 1) << 4);
954 else
955 d >>= 24 - ((_y & 3) << 3);
956 for(size_t _x = 0; _x < w; _x++, _bmp++) {
957 uint32_t b = w - _x - 1;
958 *_bmp = ((d >> b) & 1) ? fg : bg;
960 _bmp = _bmp + skip;
963 req.width = size.first;
964 req.height = size.second;
967 void callback_render_text1(struct lsnes_core_fontrender_req& req, const std::string& str)
969 switch(req.bytes_pp) {
970 case 1:
971 callback_render_text2<uint8_t>(req, str);
972 return;
973 case 2:
974 callback_render_text2<uint16_t>(req, str);
975 return;
976 case 3:
977 callback_render_text2<ss_uint24_t>(req, str);
978 return;
979 case 4:
980 callback_render_text2<uint32_t>(req, str);
981 return;
982 default:
983 throw std::runtime_error("Invalid req.bytes_pp");
987 int callback_render_text(struct lsnes_core_fontrender_req* req)
989 req->bitmap = NULL;
990 //If indeterminate length, make it determinate.
991 if(req->text_len < 0)
992 req->text_len = strlen(req->text);
993 const char* text_start = req->text;
994 const char* text_end = req->text + req->text_len;
995 try {
996 std::string str(text_start, text_end);
997 callback_render_text1(*req, str);
998 return 0;
999 } catch(...) {
1000 return -1;
1004 core_sysregion* create_sysregion(entrypoint_fn& entrypoint, std::map<unsigned, core_region*>& regions,
1005 std::map<unsigned, c_core_type*>& types, unsigned sysreg)
1007 struct lsnes_core_get_sysregion_info r;
1008 entrypoint(sysreg, r, [sysreg](const char* name, const char* err) {
1009 (stringfmt() << "LSNES_CORE_GET_SYSREGION_INFO(" << sysreg << ") failed: " << err).throwex();
1011 register_sysregion_mapping(r.name, r.for_system);
1012 if(!types.count(r.type))
1013 throw std::runtime_error("create_sysregion: Unknown type");
1014 if(!regions.count(r.region))
1015 throw std::runtime_error("create_sysregion: Unknown region");
1016 return new core_sysregion(r.name, *types[r.type], *regions[r.region]);
1019 core_region* create_region(entrypoint_fn& entrypoint, unsigned region)
1021 struct lsnes_core_get_region_info r;
1022 entrypoint(region, r, [region](const char* name, const char* err) {
1023 (stringfmt() << "LSNES_CORE_GET_REGION_INFO(" << region << ") failed: " << err).throwex();
1025 core_region_params p;
1026 p.iname = r.iname;
1027 p.hname = r.hname;
1028 p.priority = r.priority;
1029 p.handle = region;
1030 p.multi = r.multi;
1031 p.framemagic[0] = r.fps_n;
1032 p.framemagic[1] = r.fps_d;
1033 for(size_t i = 0; r.compatible_runs[i] != 0xFFFFFFFFU; i++)
1034 p.compatible_runs.push_back(r.compatible_runs[i]);
1035 return new core_region(p);
1038 c_core_core* create_core(c_lib_init& lib, entrypoint_fn& entrypoint,
1039 std::map<unsigned, core_region*>& regions, unsigned core)
1041 c_core_core_params p;
1042 struct lsnes_core_get_core_info r;
1043 entrypoint(core, r, [core](const char* name, const char* err) {
1044 (stringfmt() << "LSNES_CORE_GET_CORE_INFO(" << core << ") failed: " << err).throwex();
1046 //Read ports.
1047 JSON::node root(r.json);
1048 JSON::pointer rootptr(r.root_ptr);
1049 size_t count = root[rootptr].index_count();
1050 for(size_t i = 0; i < count; i++) {
1051 JSON::pointer j = rootptr.index(i);
1052 p.ports.push_back(new portctrl::type_generic(root, j.as_string8()));
1054 //Read actions.
1055 if(r.cap_flags1 & LSNES_CORE_CAP1_ACTION) {
1056 for(lsnes_core_get_core_info_action* i = r.actions; i->iname; i++) {
1057 interface_action a;
1058 a.id = i->id;
1059 a._symbol = i->iname;
1060 a._title = i->hname;
1061 if(!i->parameters)
1062 goto no_parameters;
1063 for(lsnes_core_get_core_info_aparam* k = i->parameters; k->name; k++) {
1064 interface_action_param b;
1065 b.name = strduplicate(k->name);
1066 b.model = strduplicate(k->model);
1067 a.params.push_back(b);
1069 no_parameters:
1070 p.actions.push_back(a);
1073 //Read trace CPUs.
1074 if(r.cap_flags1 & LSNES_CORE_CAP1_TRACE) {
1075 for(const char** i = r.trace_cpu_list; *i; i++) {
1076 p.trace_cpus.push_back(*i);
1079 for(auto & j : regions)
1080 p.regions[j.first] = j.second;
1081 p.shortname = r.shortname;
1082 p.fullname = r.fullname;
1083 p.flags = r.cap_flags1;
1084 p.id = core;
1085 p.library = &lib;
1086 return new c_core_core(p);
1089 c_core_type* create_type(c_lib_init& lib, entrypoint_fn& entrypoint, std::map<unsigned, c_core_core*>& cores,
1090 std::map<unsigned, core_region*>& regions, unsigned type)
1092 std::vector<core_romimage_info_params> rlist;
1093 std::vector<core_setting_param> plist;
1094 core_type_params p;
1095 struct lsnes_core_get_type_info r;
1096 entrypoint(type, r, [type](const char* name, const char* err) {
1097 (stringfmt() << "LSNES_CORE_GET_TYPE_INFO(" << type << ") failed: " << err).throwex();
1099 if(r.settings) {
1100 for(lsnes_core_get_type_info_param* param = r.settings; param->iname; param++) {
1101 core_setting_param _pr;
1102 _pr.iname = strduplicate(param->iname);
1103 _pr.hname = strduplicate(param->hname);
1104 _pr.dflt = strduplicate(param->dflt);
1105 _pr.regex = strduplicate(param->regex);
1106 if(!param->values)
1107 goto no_values;
1108 for(lsnes_core_get_type_info_paramval* pval = param->values; pval->iname; pval++) {
1109 core_setting_value_param pv;
1110 pv.iname = strduplicate(pval->iname);
1111 pv.hname = strduplicate(pval->hname);
1112 pv.index = pval->index;
1113 _pr.values.push_back(pv);
1115 no_values:
1116 plist.push_back(_pr);
1119 unsigned rcount = 0;
1120 if(r.images) {
1121 for(lsnes_core_get_type_info_romimage* rimg = r.images; rimg->iname; rimg++) {
1122 core_romimage_info_params rp;
1123 rp.iname = rimg->iname;
1124 rp.hname = rimg->hname;
1125 rp.mandatory = rimg->mandatory;
1126 rp.pass_mode = rimg->pass_mode;
1127 rp.headersize = rimg->headersize;
1128 rp.extensions = rimg->extensions;
1129 rlist.push_back(rp);
1130 rcount++;
1133 unsigned _core = r.core;
1134 p.id = type;
1135 p.iname = r.iname;
1136 p.hname = r.hname;
1137 p.sysname = r.sysname;
1138 p.bios = r.bios;
1139 p.settings = plist;
1140 p.images = rlist;
1141 if(!cores.count(_core))
1142 throw std::runtime_error("create_type: Unknown core");
1143 p.core = cores[_core];
1144 for(unsigned* reg = r.regions; *reg != 0xFFFFFFFFU; reg++) {
1145 if(!regions.count(*reg))
1146 throw std::runtime_error("create_type: Unknown region");
1147 p.regions.push_back(regions[*reg]);
1149 return new c_core_type(lib, p, cores[_core]->get_ports(), rcount, type);
1152 std::map<const void*, std::list<core_sysregion*>> bylib_sysregion;
1153 std::map<const void*, std::list<core_region*>> bylib_region;
1154 std::map<const void*, std::list<core_type*>> bylib_type;
1155 std::map<const void*, std::list<core_core*>> bylib_core;
1156 std::map<const void*, c_lib_init*> bylib_init;
1158 void initialize_core2(entrypoint_fn fn, std::map<unsigned, core_sysregion*>& sysregs,
1159 std::map<unsigned, core_region*>& regions, std::map<unsigned, c_core_type*>& types,
1160 std::map<unsigned, c_core_core*>& cores, const void* mod_id)
1162 c_lib_init& lib = *new c_lib_init(fn);
1163 for(auto& i : regions)
1164 i.second = create_region(fn, i.first);
1165 for(auto& i : cores)
1166 i.second = create_core(lib, fn, regions, i.first);
1167 for(auto& i : types)
1168 i.second = create_type(lib, fn, cores, regions, i.first);
1169 for(auto& i : sysregs)
1170 i.second = create_sysregion(fn, regions, types, i.first);
1171 //Mark the libs.
1172 if(mod_id) {
1173 for(auto& i : sysregs) bylib_sysregion[mod_id].push_back(i.second);
1174 for(auto& i : regions) bylib_region[mod_id].push_back(i.second);
1175 for(auto& i : types) bylib_type[mod_id].push_back(i.second);
1176 for(auto& i : cores) bylib_core[mod_id].push_back(i.second);
1177 bylib_init[mod_id] = &lib;
1179 //We don't call install_handler, because that is done automatically.
1182 void initialize_core(lsnes_core_func_t fn, const void* mod_id)
1184 //Enumerate what the thing supports.
1185 entrypoint_fn entrypoint(fn);
1186 lsnes_core_enumerate_cores r;
1187 r.emu_flags1 = 2;
1188 r.message = callback_message;
1189 r.get_input = callback_get_input;
1190 r.notify_action_update = callback_notify_action_update;
1191 r.timer_tick = callback_timer_tick;
1192 r.get_firmware_path = callback_get_firmware_path;
1193 r.get_base_path = callback_get_base_path;
1194 r.get_time = callback_get_time;
1195 r.get_randomseed = callback_get_randomseed;
1196 r.memory_read = callback_memory_read;
1197 r.memory_write = callback_memory_write;
1198 r.memory_execute = callback_memory_execute;
1199 r.memory_trace = callback_memory_trace;
1200 r.submit_sound = callback_submit_sound;
1201 r.notify_latch = callback_notify_latch;
1202 r.submit_frame = callback_submit_frame;
1203 r.add_disasm = callback_add_disasm;
1204 r.remove_disasm = callback_remove_disasm;
1205 r.render_text = callback_render_text;
1206 entrypoint(0, r, [](const char* name, const char* err) {
1207 (stringfmt() << "LSNES_CORE_ENUMERATE_CORES(0) failed: " << err).throwex();
1209 //Collect sysregions, types and cores.
1210 std::map<unsigned, core_region*> regions;
1211 std::map<unsigned, core_sysregion*> sysregs;
1212 std::map<unsigned, c_core_type*> types;
1213 std::map<unsigned, c_core_core*> cores;
1214 for(size_t i = 0; r.sysregions[i] != 0xFFFFFFFFU; i++) {
1215 unsigned sysreg = r.sysregions[i];
1216 sysregs.insert(std::make_pair(sysreg, nullptr));
1217 struct lsnes_core_get_sysregion_info r2;
1218 entrypoint(sysreg, r2, [sysreg](const char* name, const char* err) {
1219 (stringfmt() << "LSNES_CORE_GET_SYSREGION_INFO(" << sysreg << ") failed: "
1220 << err).throwex();
1222 unsigned type = r2.type;
1223 types.insert(std::make_pair(type, nullptr));
1224 struct lsnes_core_get_type_info r3;
1225 entrypoint(type, r3, [type](const char* name, const char* err) {
1226 (stringfmt() << "LSNES_CORE_GET_TYPE_INFO(" << type << ") failed: "
1227 << err).throwex();
1229 cores.insert(std::make_pair(r3.core, nullptr));
1230 for(size_t j = 0; r3.regions[j] != 0xFFFFFFFFU; j++) {
1231 regions.insert(std::make_pair(r3.regions[j], nullptr));
1234 //Do the rest.
1235 initialize_core2(entrypoint, sysregs, regions, types, cores, mod_id);
1238 template<typename T> void cleanup_list(std::map<const void*, std::list<T*>>& list, const void* handle)
1240 if(!list.count(handle))
1241 return;
1242 for(auto i : list[handle])
1243 delete i;
1244 list.erase(handle);
1247 template<typename T> void cleanup_entry(std::map<const void*, T*>& list, const void* handle)
1249 if(!list.count(handle))
1250 return;
1251 delete list[handle];
1252 list.erase(handle);
1257 void lsnes_register_builtin_core(lsnes_core_func_t fn)
1259 corequeue().push_back(fn);
1262 void try_init_c_module(const loadlib::module& module)
1264 try {
1265 lsnes_core_func_t fn = module.fn<int, unsigned, unsigned, void*,
1266 const char**>("lsnes_core_entrypoint");
1267 initialize_core(fn, &module);
1268 } catch(std::exception& e) {
1269 messages << "Can't initialize core: " << e.what() << std::endl;
1273 void try_uninit_c_module(const loadlib::module& module)
1275 if(bylib_core.count(&module))
1276 for(auto i : bylib_core[&module])
1277 i->uninstall_handler();
1278 cleanup_list(bylib_sysregion, &module);
1279 cleanup_list(bylib_region, &module);
1280 cleanup_list(bylib_type, &module);
1281 cleanup_list(bylib_core, &module);
1282 cleanup_entry(bylib_init, &module);
1285 bool core_uses_module(core_core* core, const loadlib::module& module)
1287 if(!bylib_core.count(&module))
1288 return false;
1289 for(auto i : bylib_core[&module])
1290 if(i == core)
1291 return true;
1292 return false;
1295 void initialize_all_builtin_c_cores()
1297 while(!corequeue().empty()) {
1298 lsnes_core_func_t fn = corequeue().front();
1299 corequeue().pop_front();
1300 try {
1301 initialize_core(fn, NULL);
1302 } catch(std::exception& e) {
1303 messages << "Can't initialize core: " << e.what() << std::endl;