Use urandom / rtlgenrandom
[lsnes.git] / src / interface / c-interface.cpp
blob5aabee2c9048eb6a515ee194f49524ff6d0870c0
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/controller-parse.hpp"
7 #include "library/framebuffer.hpp"
8 #include "library/framebuffer-pixfmt-rgb15.hpp"
9 #include "library/framebuffer-pixfmt-rgb16.hpp"
10 #include "library/framebuffer-pixfmt-rgb24.hpp"
11 #include "library/framebuffer-pixfmt-rgb32.hpp"
12 #include "library/framebuffer-pixfmt-lrgb.hpp"
13 #include "core/audioapi.hpp"
14 #include "core/window.hpp"
16 template<> int ccore_call_param_map<lsnes_core_enumerate_cores>::id = LSNES_CORE_ENUMERATE_CORES;
17 template<> int ccore_call_param_map<lsnes_core_get_core_info>::id = LSNES_CORE_GET_CORE_INFO;
18 template<> int ccore_call_param_map<lsnes_core_get_type_info>::id = LSNES_CORE_GET_TYPE_INFO;
19 template<> int ccore_call_param_map<lsnes_core_get_region_info>::id = LSNES_CORE_GET_REGION_INFO;
20 template<> int ccore_call_param_map<lsnes_core_get_sysregion_info>::id = LSNES_CORE_GET_SYSREGION_INFO;
21 template<> int ccore_call_param_map<lsnes_core_get_av_state>::id = LSNES_CORE_GET_AV_STATE;
22 template<> int ccore_call_param_map<lsnes_core_emulate>::id = LSNES_CORE_EMULATE;
23 template<> int ccore_call_param_map<lsnes_core_savestate>::id = LSNES_CORE_SAVESTATE;
24 template<> int ccore_call_param_map<lsnes_core_loadstate>::id = LSNES_CORE_LOADSTATE;
25 template<> int ccore_call_param_map<lsnes_core_get_controllerconfig>::id = LSNES_CORE_GET_CONTROLLERCONFIG;
26 template<> int ccore_call_param_map<lsnes_core_load_rom>::id = LSNES_CORE_LOAD_ROM;
27 template<> int ccore_call_param_map<lsnes_core_get_region>::id = LSNES_CORE_GET_REGION;
28 template<> int ccore_call_param_map<lsnes_core_set_region>::id = LSNES_CORE_SET_REGION;
29 template<> int ccore_call_param_map<lsnes_core_deinitialize>::id = LSNES_CORE_DEINITIALIZE;
30 template<> int ccore_call_param_map<lsnes_core_get_pflag>::id = LSNES_CORE_GET_PFLAG;
31 template<> int ccore_call_param_map<lsnes_core_set_pflag>::id = LSNES_CORE_SET_PFLAG;
32 template<> int ccore_call_param_map<lsnes_core_get_action_flags>::id = LSNES_CORE_GET_ACTION_FLAGS;
33 template<> int ccore_call_param_map<lsnes_core_execute_action>::id = LSNES_CORE_EXECUTE_ACTION;
34 template<> int ccore_call_param_map<lsnes_core_get_bus_mapping>::id = LSNES_CORE_GET_BUS_MAPPING;
35 template<> int ccore_call_param_map<lsnes_core_enumerate_sram>::id = LSNES_CORE_ENUMERATE_SRAM;
36 template<> int ccore_call_param_map<lsnes_core_save_sram>::id = LSNES_CORE_SAVE_SRAM;
37 template<> int ccore_call_param_map<lsnes_core_load_sram>::id = LSNES_CORE_LOAD_SRAM;
38 template<> int ccore_call_param_map<lsnes_core_get_reset_action>::id = LSNES_CORE_GET_RESET_ACTION;
39 template<> int ccore_call_param_map<lsnes_core_compute_scale>::id = LSNES_CORE_COMPUTE_SCALE;
40 template<> int ccore_call_param_map<lsnes_core_runtosave>::id = LSNES_CORE_RUNTOSAVE;
41 template<> int ccore_call_param_map<lsnes_core_poweron>::id = LSNES_CORE_POWERON;
42 template<> int ccore_call_param_map<lsnes_core_unload_cartridge>::id = LSNES_CORE_UNLOAD_CARTRIDGE;
43 template<> int ccore_call_param_map<lsnes_core_debug_reset>::id = LSNES_CORE_DEBUG_RESET;
44 template<> int ccore_call_param_map<lsnes_core_set_debug_flags>::id = LSNES_CORE_SET_DEBUG_FLAGS;
45 template<> int ccore_call_param_map<lsnes_core_set_cheat>::id = LSNES_CORE_SET_CHEAT;
46 template<> int ccore_call_param_map<lsnes_core_draw_cover>::id = LSNES_CORE_DRAW_COVER;
47 template<> int ccore_call_param_map<lsnes_core_pre_emulate>::id = LSNES_CORE_PRE_EMULATE;
48 template<> int ccore_call_param_map<lsnes_core_get_device_regs>::id = LSNES_CORE_GET_DEVICE_REGS;
49 template<> int ccore_call_param_map<lsnes_core_get_vma_list>::id = LSNES_CORE_GET_VMA_LIST;
51 template<> const char* ccore_call_param_map<lsnes_core_enumerate_cores>::name = "LSNES_CORE_ENUMERATE_CORES";
52 template<> const char* ccore_call_param_map<lsnes_core_get_core_info>::name = "LSNES_CORE_GET_CORE_INFO";
53 template<> const char* ccore_call_param_map<lsnes_core_get_type_info>::name = "LSNES_CORE_GET_TYPE_INFO";
54 template<> const char* ccore_call_param_map<lsnes_core_get_region_info>::name = "LSNES_CORE_GET_REGION_INFO";
55 template<> const char* ccore_call_param_map<lsnes_core_get_sysregion_info>::name = "LSNES_CORE_GET_SYSREGION_INFO";
56 template<> const char* ccore_call_param_map<lsnes_core_get_av_state>::name = "LSNES_CORE_GET_AV_STATE";
57 template<> const char* ccore_call_param_map<lsnes_core_emulate>::name = "LSNES_CORE_EMULATE";
58 template<> const char* ccore_call_param_map<lsnes_core_savestate>::name = "LSNES_CORE_SAVESTATE";
59 template<> const char* ccore_call_param_map<lsnes_core_loadstate>::name = "LSNES_CORE_LOADSTATE";
60 template<> const char* ccore_call_param_map<lsnes_core_get_controllerconfig>::name =
61 "LSNES_CORE_GET_CONTROLLERCONFIG";
62 template<> const char* ccore_call_param_map<lsnes_core_load_rom>::name = "LSNES_CORE_LOAD_ROM";
63 template<> const char* ccore_call_param_map<lsnes_core_get_region>::name = "LSNES_CORE_GET_REGION";
64 template<> const char* ccore_call_param_map<lsnes_core_set_region>::name = "LSNES_CORE_SET_REGION";
65 template<> const char* ccore_call_param_map<lsnes_core_deinitialize>::name = "LSNES_CORE_DEINITIALIZE";
66 template<> const char* ccore_call_param_map<lsnes_core_get_pflag>::name = "LSNES_CORE_GET_PFLAG";
67 template<> const char* ccore_call_param_map<lsnes_core_set_pflag>::name = "LSNES_CORE_SET_PFLAG";
68 template<> const char* ccore_call_param_map<lsnes_core_get_action_flags>::name = "LSNES_CORE_GET_ACTION_FLAGS";
69 template<> const char* ccore_call_param_map<lsnes_core_execute_action>::name = "LSNES_CORE_EXECUTE_ACTION";
70 template<> const char* ccore_call_param_map<lsnes_core_get_bus_mapping>::name = "LSNES_CORE_GET_BUS_MAPPING";
71 template<> const char* ccore_call_param_map<lsnes_core_enumerate_sram>::name = "LSNES_CORE_ENUMERATE_SRAM";
72 template<> const char* ccore_call_param_map<lsnes_core_save_sram>::name = "LSNES_CORE_SAVE_SRAM";
73 template<> const char* ccore_call_param_map<lsnes_core_load_sram>::name = "LSNES_CORE_LOAD_SRAM";
74 template<> const char* ccore_call_param_map<lsnes_core_get_reset_action>::name = "LSNES_CORE_GET_RESET_ACTION";
75 template<> const char* ccore_call_param_map<lsnes_core_compute_scale>::name = "LSNES_CORE_COMPUTE_SCALE";
76 template<> const char* ccore_call_param_map<lsnes_core_runtosave>::name = "LSNES_CORE_RUNTOSAVE";
77 template<> const char* ccore_call_param_map<lsnes_core_poweron>::name = "LSNES_CORE_POWERON";
78 template<> const char* ccore_call_param_map<lsnes_core_unload_cartridge>::name = "LSNES_CORE_UNLOAD_CARTRIDGE";
79 template<> const char* ccore_call_param_map<lsnes_core_debug_reset>::name = "LSNES_CORE_DEBUG_RESET";
80 template<> const char* ccore_call_param_map<lsnes_core_set_debug_flags>::name = "LSNES_CORE_SET_DEBUG_FLAGS";
81 template<> const char* ccore_call_param_map<lsnes_core_set_cheat>::name = "LSNES_CORE_SET_CHEAT";
82 template<> const char* ccore_call_param_map<lsnes_core_draw_cover>::name = "LSNES_CORE_DRAW_COVER";
83 template<> const char* ccore_call_param_map<lsnes_core_pre_emulate>::name = "LSNES_CORE_PRE_EMULATE";
84 template<> const char* ccore_call_param_map<lsnes_core_get_device_regs>::name = "LSNES_CORE_GET_DEVICE_REGS";
85 template<> const char* ccore_call_param_map<lsnes_core_get_vma_list>::name = "LSNES_CORE_GET_VMA_LIST";
87 namespace
89 struct c_core_core;
90 c_core_core* current_core = NULL;
92 char* strduplicate(const char* x)
94 if(!x) return NULL;
95 char* out = (char*)malloc(strlen(x) + 1);
96 if(!out)
97 throw std::bad_alloc();
98 strcpy(out, x);
99 return out;
102 std::list<lsnes_core_func_t>& corequeue()
104 static std::list<lsnes_core_func_t> x;
105 return x;
108 void default_error_function(const char* callname, const char* err)
110 messages << "Warning: " << callname << " failed: " << err << std::endl;
113 framebuffer::info translate_info(lsnes_core_framebuffer_info* _fb)
115 framebuffer::info fbinfo;
116 switch(_fb->type) {
117 case LSNES_CORE_PIXFMT_RGB15: fbinfo.type = &framebuffer::pixfmt_rgb15; break;
118 case LSNES_CORE_PIXFMT_BGR15: fbinfo.type = &framebuffer::pixfmt_bgr15; break;
119 case LSNES_CORE_PIXFMT_RGB16: fbinfo.type = &framebuffer::pixfmt_rgb16; break;
120 case LSNES_CORE_PIXFMT_BGR16: fbinfo.type = &framebuffer::pixfmt_bgr16; break;
121 case LSNES_CORE_PIXFMT_RGB24: fbinfo.type = &framebuffer::pixfmt_rgb24; break;
122 case LSNES_CORE_PIXFMT_BGR24: fbinfo.type = &framebuffer::pixfmt_bgr24; break;
123 case LSNES_CORE_PIXFMT_RGB32: fbinfo.type = &framebuffer::pixfmt_rgb32; break;
124 case LSNES_CORE_PIXFMT_LRGB: fbinfo.type = &framebuffer::pixfmt_lrgb; break;
126 fbinfo.mem = (char*)_fb->mem;
127 fbinfo.physwidth = _fb->physwidth;
128 fbinfo.physheight = _fb->physheight;
129 fbinfo.physstride = _fb->physstride;
130 fbinfo.width = _fb->width;
131 fbinfo.height = _fb->height;
132 fbinfo.stride = _fb->stride;
133 fbinfo.offset_x = _fb->offset_x;
134 fbinfo.offset_y = _fb->offset_y;
135 return fbinfo;
138 struct entrypoint_fn
140 entrypoint_fn(lsnes_core_func_t _fn) : fn(_fn) {}
141 template<typename T> bool operator()(unsigned item, T& args,
142 std::function<void(const char* callname, const char* err)> onerror)
144 const char* err = NULL;
145 int r = fn(ccore_call_param_map<T>::id, item, &args, &err);
146 if(r < 0)
147 onerror(ccore_call_param_map<T>::name, err);
148 return (r >= 0);
150 template<typename T> bool operator()(unsigned item, T& args)
152 return (*this)(item, args, default_error_function);
154 private:
155 lsnes_core_func_t fn;
158 struct c_lib_init
160 public:
161 c_lib_init(entrypoint_fn _entrypoint)
162 : entrypoint(_entrypoint)
164 count = 0;
166 void initialize()
168 count++;
170 void deinitialize()
172 if(count) count--;
173 if(!count) {
174 lsnes_core_deinitialize s;
175 entrypoint(0, s);
178 entrypoint_fn get_entrypoint()
180 return entrypoint;
182 private:
183 int count;
184 entrypoint_fn entrypoint;
187 struct c_core_core_params
189 std::vector<interface_action> actions;
190 std::vector<std::string> trace_cpus;
191 std::vector<port_type*> ports;
192 const char* shortname;
193 const char* fullname;
194 unsigned flags;
195 unsigned id;
196 std::map<unsigned, core_region*> regions;
197 c_lib_init* library;
200 struct c_core_core : public core_core
202 c_core_core(c_core_core_params& p)
203 : core_core(p.ports, p.actions), entrypoint(p.library->get_entrypoint()), plugin(p.library)
205 fullname = p.fullname;
206 shortname = p.shortname;
207 id = p.id;
208 internal_pflag = false;
209 caps1 = p.flags;
210 regions = p.regions;
211 actions = p.actions;
212 trace_cpus = p.trace_cpus;
213 for(size_t i = 0; i < p.ports.size(); i++)
214 ports[i] = p.ports[i];
216 ~c_core_core() throw();
217 std::string c_core_identifier()
219 return fullname;
221 bool get_av_state(lsnes_core_get_av_state& s)
223 return entrypoint(id, s);
225 std::pair<uint32_t, uint32_t> c_video_rate()
227 lsnes_core_get_av_state s;
228 if(!entrypoint(id, s))
229 return std::make_pair(60, 1);
230 return std::make_pair(s.fps_n, s.fps_d);
232 double c_get_PAR()
234 lsnes_core_get_av_state s;
235 return entrypoint(id, s) ? s.par : 1.0;
237 std::pair<uint32_t, uint32_t> c_audio_rate()
239 lsnes_core_get_av_state s;
240 return entrypoint(id, s) ? std::make_pair(s.rate_n, s.rate_d) : std::make_pair(48000U, 1U);
242 void c_power()
244 lsnes_core_poweron s;
245 if(caps1 & LSNES_CORE_CAP1_POWERON) entrypoint(id, s);
247 void c_unload_cartridge()
249 lsnes_core_unload_cartridge s;
250 if(caps1 & LSNES_CORE_CAP1_UNLOAD) entrypoint(id, s);
252 void c_runtosave()
254 lsnes_core_runtosave s;
255 if(caps1 & LSNES_CORE_CAP1_RUNTOSAVE) entrypoint(id, s);
257 void c_emulate()
259 current_core = this;
260 lsnes_core_emulate s;
261 entrypoint(id, s);
262 current_core = NULL;
264 bool c_get_pflag()
266 lsnes_core_get_pflag s;
267 if(!(caps1 & LSNES_CORE_CAP1_PFLAG) || !entrypoint(id, s))
268 return internal_pflag;
269 return (s.pflag != 0);
271 void c_set_pflag(bool pflag)
273 lsnes_core_set_pflag s;
274 s.pflag = pflag ? 1 : 0;
275 if(!(caps1 & LSNES_CORE_CAP1_PFLAG) || !entrypoint(id, s))
276 internal_pflag = pflag;
278 std::string c_get_core_shortname()
280 return shortname;
282 void c_debug_reset()
284 lsnes_core_debug_reset s;
285 if(caps1 & (LSNES_CORE_CAP1_DEBUG | LSNES_CORE_CAP1_TRACE | LSNES_CORE_CAP1_CHEAT))
286 entrypoint(id, s);
288 std::pair<unsigned, unsigned> c_lightgun_scale()
290 lsnes_core_get_av_state s;
291 if(!(caps1 & LSNES_CORE_CAP1_LIGHTGUN) || !entrypoint(id, s))
292 return std::make_pair(0, 0);
293 return std::make_pair(s.lightgun_width, s.lightgun_height);
295 std::pair<uint64_t, uint64_t> c_get_bus_map()
297 lsnes_core_get_bus_mapping s;
298 if(!(caps1 & LSNES_CORE_CAP1_BUSMAP) || !entrypoint(id, s))
299 return std::make_pair(0, 0);
300 return std::make_pair(s.base, s.size);
302 int c_reset_action(bool hard)
304 lsnes_core_get_reset_action s;
305 if(!(caps1 & LSNES_CORE_CAP1_RESET) || !entrypoint(id, s))
306 return -1;
307 return hard ? s.hardreset : s.softreset;
309 std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height)
311 lsnes_core_compute_scale s;
312 uint32_t hscale, vscale;
313 if(width >= 360) hscale = 1;
314 else hscale = 360 / width + 1;
315 if(height >= 320) vscale = 1;
316 else vscale = 320 / height + 1;
317 if(caps1 & LSNES_CORE_CAP1_SCALE) {
318 s.width = width;
319 s.height = height;
320 if(entrypoint(id, s)) {
321 hscale = s.hfactor;
322 vscale = s.vfactor;
325 return std::make_pair(hscale, vscale);
327 void c_pre_emulate_frame(controller_frame& cf)
329 lsnes_core_pre_emulate s;
330 if(caps1 & LSNES_CORE_CAP1_PREEMULATE) {
331 s.context = &cf;
332 s.set_input = [](void* context, unsigned port, unsigned controller, unsigned index,
333 short value) -> void {
334 controller_frame& cf = *(controller_frame*)context;
335 cf.axis3(port, controller, index, value);
337 entrypoint(id, s);
340 std::set<std::string> c_srams()
342 lsnes_core_enumerate_sram s;
343 std::set<std::string> ret;
344 if(caps1 & LSNES_CORE_CAP1_SRAM) {
345 if(entrypoint(id, s)) {
346 const char** sr = s.srams;
347 while(*sr) {
348 ret.insert(*sr);
349 sr++;
353 return ret;
355 void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc)
357 lsnes_core_load_sram s;
358 if(caps1 & LSNES_CORE_CAP1_SRAM) {
359 std::vector<lsnes_core_sram> srams;
360 std::vector<lsnes_core_sram*> sramsp;
361 std::vector<char> names;
362 srams.resize(sram.size() + 1);
363 srams[sram.size()].name = NULL;
364 size_t idx = 0;
365 size_t nlength = 0;
366 for(auto& i : sram)
367 nlength += i.first.length() + 1;
368 names.resize(nlength);
369 size_t nidx = 0;
370 for(auto& i : sram) {
371 size_t ntmp = nidx;
372 std::copy(i.first.begin(), i.first.end(), names.begin() + nidx);
373 nidx += i.first.length();
374 names[nidx++] = '\0';
375 srams[idx].size = i.second.size();
376 srams[idx].data = &i.second[0];
377 srams[idx].name = &names[ntmp];
378 idx++;
380 s.srams = &srams[0];
381 entrypoint(id, s);
384 std::map<std::string, std::vector<char>> c_save_sram() throw(std::bad_alloc)
386 lsnes_core_save_sram s;
387 std::map<std::string, std::vector<char>> ret;
388 if(caps1 & LSNES_CORE_CAP1_SRAM) {
389 if(entrypoint(id, s)) {
390 lsnes_core_sram* p = s.srams;
391 while(p->name) {
392 ret[p->name].resize(p->size);
393 memcpy(&ret[p->name][0], p->data, p->size);
394 p++;
398 return ret;
400 void c_unserialize(const char* in, size_t insize)
402 lsnes_core_loadstate s;
403 s.data = in;
404 s.size = insize;
405 entrypoint(id, s, [](const char* name, const char* err) {
406 throw std::runtime_error("Loadstate failed: " + std::string(err));
409 void c_serialize(std::vector<char>& out)
411 lsnes_core_savestate s;
412 entrypoint(id, s, [](const char* name, const char* err) {
413 throw std::runtime_error("Savestate failed: " + std::string(err));
415 out.resize(s.size);
416 memcpy(&out[0], s.data, s.size);
418 unsigned c_action_flags(unsigned _id)
420 lsnes_core_get_action_flags s;
421 if(caps1 & LSNES_CORE_CAP1_ACTION) {
422 s.action = _id;
423 return entrypoint(id, s) ? s.flags : 0;
425 return 0;
427 std::vector<std::string> c_get_trace_cpus()
429 return trace_cpus;
431 bool c_set_region(core_region& region)
433 lsnes_core_set_region s;
434 if(caps1 & LSNES_CORE_CAP1_MULTIREGION) {
435 bool hit = false;
436 for(auto i : regions)
437 if(i.second == &region) {
438 s.region = i.first;
439 hit = true;
441 if(!hit)
442 return false; //Bad region.
443 return entrypoint(id, s);
444 } else {
445 return (regions.count(0) && regions[0] == &region);
448 core_region& c_get_region()
450 lsnes_core_get_region s;
451 if(caps1 & LSNES_CORE_CAP1_MULTIREGION) {
452 if(!entrypoint(id, s)) {
453 if(regions.empty())
454 throw std::runtime_error("No valid regions");
455 return *(regions.begin()->second);
456 } else {
457 if(regions.count(s.region))
458 return *regions[s.region];
459 messages << "Internal error: Core gave invalid region number."
460 << std::endl;
461 if(regions.empty())
462 throw std::runtime_error("No valid regions");
463 return *(regions.begin()->second);
465 } else {
466 if(regions.count(0))
467 return *regions[0];
468 else {
469 messages << "Internal error: Not multi-region core and region 0 not present."
470 << std::endl;
471 if(regions.empty())
472 throw std::runtime_error("No valid regions");
473 return *(regions.begin()->second);
477 const struct interface_device_reg* c_get_registers()
479 static std::vector<interface_device_reg> regs;
480 static std::vector<char> namebuf;
481 static interface_device_reg reg_null = {NULL};
482 lsnes_core_get_device_regs s;
483 if(caps1 & LSNES_CORE_CAP1_REGISTERS) {
484 if(!entrypoint(id, s)) {
485 return &reg_null;
486 } else {
487 size_t count = 0;
488 size_t namelen = 0;
489 auto tregs = s.regs;
490 while(tregs->name) {
491 namelen += strlen(tregs->name) + 1;
492 count++;
493 tregs++;
495 tregs = s.regs;
496 if(regs.size() < count + 1)
497 regs.resize(count + 1);
498 if(namelen > namebuf.size())
499 namebuf.resize(namelen);
500 size_t idx = 0;
501 size_t nameptr = 0;
502 while(tregs->name) {
503 strcpy(&namebuf[nameptr], tregs->name);
504 regs[idx].name = &namebuf[nameptr];
505 regs[idx].read = tregs->read;
506 regs[idx].write = tregs->write;
507 regs[idx].boolean = tregs->boolean;
508 nameptr += strlen(tregs->name) + 1;
509 tregs++;
510 idx++;
512 regs[idx].name = NULL; //The sentinel.
514 } else {
515 return &reg_null;
517 return &regs[0];
519 void c_install_handler()
521 plugin->initialize();
523 void c_uninstall_handler()
525 plugin->deinitialize();
527 void c_set_debug_flags(uint64_t addr, unsigned flags_set, unsigned flags_clear)
529 lsnes_core_set_debug_flags s;
530 s.addr = addr;
531 s.set = flags_set;
532 s.clear = flags_clear;
533 if(caps1 & LSNES_CORE_CAP1_DEBUG)
534 entrypoint(id, s);
535 else
536 messages << "Debugging functions not supported by core" << std::endl;
538 void c_set_cheat(uint64_t addr, uint64_t value, bool set)
540 lsnes_core_set_cheat s;
541 s.addr = addr;
542 s.value = value;
543 s.set = set;
544 if(caps1 & LSNES_CORE_CAP1_CHEAT)
545 entrypoint(id, s);
546 else
547 messages << "Cheat functions not supported by core" << std::endl;
549 void c_execute_action(unsigned aid, const std::vector<interface_action_paramval>& p)
551 if(!(caps1 & LSNES_CORE_CAP1_ACTION)) {
552 messages << "Core does not support actions." << std::endl;
553 return;
555 interface_action* act = NULL;
556 for(auto& i : actions) {
557 if(i.id == aid) {
558 act = &i;
559 break;
562 if(!act) {
563 messages << "Unknown action id #" << aid << std::endl;
564 return;
566 size_t j = 0;
567 std::vector<lsnes_core_execute_action_param> parameters;
568 std::list<std::vector<char>> strtmp;
569 for(auto& b : act->params) {
570 std::string m = b.model;
571 if(m == "bool") {
572 //Boolean.
573 lsnes_core_execute_action_param tp;
574 tp.boolean = p[j++].b;
575 parameters.push_back(tp);
576 } else if(regex_match("int:.*", m)) {
577 //Integer.
578 lsnes_core_execute_action_param tp;
579 tp.integer = p[j++].i;
580 parameters.push_back(tp);
581 } else if(regex_match("string(:.*)?", m) || regex_match("enum:.*", m)) {
582 //String.
583 strtmp.push_back(std::vector<char>());
584 auto& i = strtmp.back();
585 i.resize(p[j].s.length() + 1);
586 std::copy(p[j].s.begin(), p[j].s.end(), i.begin());
587 lsnes_core_execute_action_param tp;
588 tp.string.base = &i[0];
589 tp.string.length = p[j++].s.length();
590 parameters.push_back(tp);
591 } else if(m == "toggle") {
592 //Skip.
593 } else {
594 messages << "Unknown model '" << m << "' in action id #" << aid << std::endl;
595 return;
598 lsnes_core_execute_action s;
599 s.action = aid;
600 s.params = &parameters[0];
601 entrypoint(id, s);
603 framebuffer::raw& c_draw_cover()
605 lsnes_core_draw_cover r;
606 if(caps1 & LSNES_CORE_CAP1_COVER) {
607 if(!entrypoint(id, r))
608 goto failed;
609 framebuffer::info fbinfo = translate_info(r.coverpage);
610 size_t needed = fbinfo.physwidth * fbinfo.physheight * fbinfo.type->get_bpp();
611 if(covermem.size() < needed) covermem.resize(needed);
612 memcpy(&covermem[0], fbinfo.mem, needed);
613 fbinfo.mem = &covermem[0];
614 cover = framebuffer::raw(fbinfo);
615 return cover;
617 failed:
618 if(covermem.size() < 1024) covermem.resize(1024);
619 framebuffer::info fbi;
620 fbi.type = &framebuffer::pixfmt_rgb16;
621 fbi.mem = &covermem[0];
622 fbi.physwidth = 512;
623 fbi.physheight = 448;
624 fbi.physstride = 0;
625 fbi.width = 512;
626 fbi.height = 448;
627 fbi.stride = 0;
628 fbi.offset_x = 0;
629 fbi.offset_y = 0;
630 cover = framebuffer::raw(fbi);
631 return cover;
633 std::list<core_vma_info> c_vma_list()
635 lsnes_core_get_vma_list r;
636 if(caps1 & LSNES_CORE_CAP1_MEMWATCH) {
637 if(!entrypoint(id, r))
638 goto failed;
639 std::list<core_vma_info> vmalist;
640 for(lsnes_core_get_vma_list_vma** vmas = r.vmas; *vmas; vmas++) {
641 lsnes_core_get_vma_list_vma* vma = *vmas;
642 core_vma_info _vma;
643 _vma.name = vma->name;
644 _vma.base = vma->base;
645 _vma.size = vma->size;
646 _vma.endian = vma->endian;
647 _vma.readonly = ((vma->flags & LSNES_CORE_VMA_READONLY) != 0);
648 _vma.special = ((vma->flags & LSNES_CORE_VMA_SPECIAL) != 0);
649 _vma.volatile_flag = ((vma->flags & LSNES_CORE_VMA_VOLATILE) != 0);
650 _vma.backing_ram = vma->direct_map;
651 _vma.read = vma->read;
652 _vma.write = vma->write;
653 vmalist.push_back(_vma);
655 return vmalist;
657 failed:
658 return std::list<core_vma_info>();
660 std::map<unsigned, port_type*> get_ports()
662 return ports;
664 void set_internal_pflag()
666 internal_pflag = true;
668 private:
669 std::string fullname;
670 std::string shortname;
671 unsigned id;
672 bool internal_pflag;
673 unsigned caps1;
674 std::vector<std::string> trace_cpus;
675 std::map<unsigned, port_type*> ports;
676 std::map<unsigned, core_region*> regions;
677 std::vector<interface_action> actions;
678 framebuffer::raw cover;
679 std::vector<char> covermem;
680 entrypoint_fn entrypoint;
681 c_lib_init* plugin;
684 c_core_core::~c_core_core() throw()
688 struct c_core_type : public core_type
690 c_core_type(c_lib_init& lib, core_type_params& p, std::map<unsigned, port_type*> _ports,
691 unsigned _rcount, unsigned _id)
692 : core_type(p), ports(_ports), entrypoint(lib.get_entrypoint()), rcount(_rcount), id(_id)
695 ~c_core_type() throw()
698 int t_load_rom(core_romimage* images, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
699 uint64_t rtc_subsec)
701 lsnes_core_load_rom r;
702 std::vector<char> tmpmem;
703 std::vector<lsnes_core_system_setting> tmpmem2;
704 r.rtc_sec = rtc_sec;
705 r.rtc_subsec = rtc_subsec;
706 copy_settings(tmpmem, tmpmem2, settings);
707 r.settings = &tmpmem2[0];
709 std::vector<lsnes_core_load_rom_image> imgs;
710 imgs.resize(rcount);
711 for(unsigned i = 0; i < rcount; i++) {
712 imgs[i].data = (const char*)images[i].data;
713 imgs[i].size = images[i].size;
714 imgs[i].markup = images[i].markup;
716 r.images = &imgs[0];
717 unsigned _id = id;
718 entrypoint(_id, r, [_id](const char* name, const char* err) {
719 (stringfmt() << "LSNES_CORE_LOAD_ROM(" << _id << ") failed: " << err).throwex();
721 return 0;
723 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
725 lsnes_core_get_controllerconfig r;
726 std::vector<char> tmpmem;
727 std::vector<lsnes_core_system_setting> tmpmem2;
728 copy_settings(tmpmem, tmpmem2, settings);
729 r.settings = &tmpmem2[0];
730 unsigned _id = id;
731 entrypoint(_id, r, [_id](const char* name, const char* err) {
732 (stringfmt() << "LSNES_CORE_GET_CONTROLLERCONFIG(" << _id << ") failed: "
733 << err).throwex();
735 controller_set cset;
736 for(unsigned* pt = r.controller_types; *pt != 0xFFFFFFFFU; pt++) {
737 unsigned _pt = *pt;
738 if(!ports.count(_pt))
739 throw std::runtime_error("Illegal port type selected by core");
740 port_type* pt2 = ports[_pt];
741 cset.ports.push_back(pt2);
743 for(lsnes_core_get_controllerconfig_logical_entry* le = r.logical_map;
744 le->port | le->controller; le++) {
745 cset.logical_map.push_back(std::make_pair(le->port, le->controller));
747 return cset;
749 private:
750 void copy_settings(std::vector<char>& tmpmem, std::vector<lsnes_core_system_setting>& tmpmem2,
751 std::map<std::string, std::string>& settings)
753 size_t asize = 0;
754 for(auto i : settings)
755 asize += i.first.length() + i.second.length() + 2;
756 tmpmem.resize(asize);
757 asize = 0;
758 for(auto i : settings) {
759 lsnes_core_system_setting s;
760 std::copy(i.first.begin(), i.first.end(), tmpmem.begin() + asize);
761 s.name = &tmpmem[asize];
762 asize += i.first.length();
763 tmpmem[asize++] = 0;
764 std::copy(i.second.begin(), i.second.end(), tmpmem.begin() + asize);
765 s.value = &tmpmem[asize];
766 asize += i.second.length();
767 tmpmem[asize++] = 0;
768 tmpmem2.push_back(s);
770 lsnes_core_system_setting s;
771 s.name = NULL;
772 s.value = NULL;
773 tmpmem2.push_back(s);
775 std::map<unsigned, port_type*> ports;
776 entrypoint_fn entrypoint;
777 unsigned rcount;
778 unsigned id;
781 std::vector<char> msgbuf;
783 void callback_message(const char* msg, size_t length)
785 std::string _msg(msg, msg + length);
786 messages << _msg << std::endl;
789 short callback_get_input(unsigned port, unsigned index, unsigned control)
791 short v = ecore_callbacks->get_input(port, index, control);
792 if(current_core && (port || index || v))
793 current_core->set_internal_pflag();
794 return v;
797 void callback_notify_action_update()
799 ecore_callbacks->action_state_updated();
802 void callback_timer_tick(uint32_t increment, uint32_t per_second)
804 ecore_callbacks->timer_tick(increment, per_second);
807 const char* callback_get_firmware_path()
809 std::string fwp = ecore_callbacks->get_firmware_path();
810 msgbuf.resize(fwp.length() + 1);
811 std::copy(fwp.begin(), fwp.end(), msgbuf.begin());
812 msgbuf[fwp.length()] = 0;
813 return &msgbuf[0];
816 const char* callback_get_base_path()
818 std::string fwp = ecore_callbacks->get_base_path();
819 msgbuf.resize(fwp.length() + 1);
820 std::copy(fwp.begin(), fwp.end(), msgbuf.begin());
821 msgbuf[fwp.length()] = 0;
822 return &msgbuf[0];
825 time_t callback_get_time()
827 return ecore_callbacks->get_time();
830 time_t callback_get_randomseed()
832 return ecore_callbacks->get_randomseed();
835 void callback_memory_read(uint64_t addr, uint64_t value)
837 ecore_callbacks->memory_read(addr, value);
840 void callback_memory_write(uint64_t addr, uint64_t value)
842 ecore_callbacks->memory_write(addr, value);
845 void callback_memory_execute(uint64_t addr, uint64_t cpunum)
847 ecore_callbacks->memory_execute(addr, cpunum);
850 void callback_memory_trace(uint64_t proc, const char* str, int insn)
852 ecore_callbacks->memory_trace(proc, str, insn);
855 void callback_submit_sound(const int16_t* samples, size_t count, int stereo, double rate)
857 audioapi_submit_buffer((int16_t*)samples, count, stereo, rate);
860 void callback_notify_latch(const char** params)
862 std::list<std::string> ps;
863 if(params)
864 for(const char** p = params; *p; p++)
865 ps.push_back(*p);
866 ecore_callbacks->notify_latch(ps);
869 void callback_submit_frame(struct lsnes_core_framebuffer_info* _fb, uint32_t fps_n, uint32_t fps_d)
871 framebuffer::info fbinfo = translate_info(_fb);
872 framebuffer::raw fb(fbinfo);
873 ecore_callbacks->output_frame(fb, fps_n, fps_d);
876 struct fpcfn
878 std::function<unsigned char()> fn;
879 static unsigned char call(void* ctx)
881 return reinterpret_cast<fpcfn*>(ctx)->fn();
885 class ccore_disasm : public disassembler
887 public:
888 ccore_disasm(struct lsnes_core_disassembler* disasm)
889 : disassembler(disasm->name)
891 fn = disasm->fn;
893 ~ccore_disasm()
896 std::string disassemble(uint64_t base, std::function<unsigned char()> fetchpc)
898 fpcfn y;
899 y.fn = fetchpc;
900 const char* out = fn(base, fpcfn::call, &y);
901 return out;
903 private:
904 const char* (*fn)(uint64_t base, unsigned char(*fetch)(void* ctx), void* ctx);
907 void* callback_add_disasm(struct lsnes_core_disassembler* disasm)
909 return new ccore_disasm(disasm);
912 void callback_remove_disasm(void* handle)
914 delete reinterpret_cast<ccore_disasm*>(handle);
917 core_sysregion* create_sysregion(entrypoint_fn& entrypoint, std::map<unsigned, core_region*>& regions,
918 std::map<unsigned, c_core_type*>& types, unsigned sysreg)
920 struct lsnes_core_get_sysregion_info r;
921 entrypoint(sysreg, r, [sysreg](const char* name, const char* err) {
922 (stringfmt() << "LSNES_CORE_GET_SYSREGION_INFO(" << sysreg << ") failed: " << err).throwex();
924 register_sysregion_mapping(r.name, r.for_system);
925 if(!types.count(r.type))
926 throw std::runtime_error("create_sysregion: Unknown type");
927 if(!regions.count(r.region))
928 throw std::runtime_error("create_sysregion: Unknown region");
929 return new core_sysregion(r.name, *types[r.type], *regions[r.region]);
932 core_region* create_region(entrypoint_fn& entrypoint, unsigned region)
934 struct lsnes_core_get_region_info r;
935 entrypoint(region, r, [region](const char* name, const char* err) {
936 (stringfmt() << "LSNES_CORE_GET_REGION_INFO(" << region << ") failed: " << err).throwex();
938 core_region_params p;
939 p.iname = r.iname;
940 p.hname = r.hname;
941 p.priority = r.priority;
942 p.handle = region;
943 p.multi = r.multi;
944 p.framemagic[0] = r.fps_n;
945 p.framemagic[1] = r.fps_d;
946 for(size_t i = 0; r.compatible_runs[i] != 0xFFFFFFFFU; i++)
947 p.compatible_runs.push_back(r.compatible_runs[i]);
948 return new core_region(p);
951 c_core_core* create_core(c_lib_init& lib, entrypoint_fn& entrypoint,
952 std::map<unsigned, core_region*>& regions, unsigned core)
954 c_core_core_params p;
955 struct lsnes_core_get_core_info r;
956 entrypoint(core, r, [core](const char* name, const char* err) {
957 (stringfmt() << "LSNES_CORE_GET_CORE_INFO(" << core << ") failed: " << err).throwex();
959 //Read ports.
960 JSON::node root(r.json);
961 JSON::pointer rootptr(r.root_ptr);
962 size_t count = root[rootptr].index_count();
963 for(size_t i = 0; i < count; i++) {
964 JSON::pointer j = rootptr.index(i);
965 p.ports.push_back(new port_type_generic(root, j.as_string8()));
967 //Read actions.
968 if(r.cap_flags1 & LSNES_CORE_CAP1_ACTION) {
969 for(lsnes_core_get_core_info_action* i = r.actions; i->iname; i++) {
970 interface_action a;
971 a.id = i->id;
972 a._symbol = i->iname;
973 a._title = i->hname;
974 if(!i->parameters)
975 goto no_parameters;
976 for(lsnes_core_get_core_info_aparam* k = i->parameters; k->name; k++) {
977 interface_action_param b;
978 b.name = strduplicate(k->name);
979 b.model = strduplicate(k->model);
980 a.params.push_back(b);
982 no_parameters:
983 p.actions.push_back(a);
986 //Read trace CPUs.
987 if(r.cap_flags1 & LSNES_CORE_CAP1_TRACE) {
988 for(const char** i = r.trace_cpu_list; *i; i++) {
989 p.trace_cpus.push_back(*i);
992 for(auto & j : regions)
993 p.regions[j.first] = j.second;
994 p.shortname = r.shortname;
995 p.fullname = r.fullname;
996 p.flags = r.cap_flags1;
997 p.id = core;
998 p.library = &lib;
999 return new c_core_core(p);
1002 c_core_type* create_type(c_lib_init& lib, entrypoint_fn& entrypoint, std::map<unsigned, c_core_core*>& cores,
1003 std::map<unsigned, core_region*>& regions, unsigned type)
1005 std::vector<core_romimage_info_params> rlist;
1006 std::vector<core_setting_param> plist;
1007 core_type_params p;
1008 struct lsnes_core_get_type_info r;
1009 entrypoint(type, r, [type](const char* name, const char* err) {
1010 (stringfmt() << "LSNES_CORE_GET_TYPE_INFO(" << type << ") failed: " << err).throwex();
1012 if(r.settings) {
1013 for(lsnes_core_get_type_info_param* param = r.settings; param->iname; param++) {
1014 core_setting_param _pr;
1015 _pr.iname = strduplicate(param->iname);
1016 _pr.hname = strduplicate(param->hname);
1017 _pr.dflt = strduplicate(param->dflt);
1018 _pr.regex = strduplicate(param->regex);
1019 if(!param->values)
1020 goto no_values;
1021 for(lsnes_core_get_type_info_paramval* pval = param->values; pval->iname; pval++) {
1022 core_setting_value_param pv;
1023 pv.iname = strduplicate(pval->iname);
1024 pv.hname = strduplicate(pval->hname);
1025 pv.index = pval->index;
1026 _pr.values.push_back(pv);
1028 no_values:
1029 plist.push_back(_pr);
1032 unsigned rcount = 0;
1033 if(r.images) {
1034 for(lsnes_core_get_type_info_romimage* rimg = r.images; rimg->iname; rimg++) {
1035 core_romimage_info_params rp;
1036 rp.iname = rimg->iname;
1037 rp.hname = rimg->hname;
1038 rp.mandatory = rimg->mandatory;
1039 rp.pass_mode = rimg->pass_mode;
1040 rp.headersize = rimg->headersize;
1041 rp.extensions = rimg->extensions;
1042 rlist.push_back(rp);
1043 rcount++;
1046 unsigned _core = r.core;
1047 p.id = type;
1048 p.iname = r.iname;
1049 p.hname = r.hname;
1050 p.sysname = r.sysname;
1051 p.bios = r.bios;
1052 p.settings = plist;
1053 p.images = rlist;
1054 if(!cores.count(_core))
1055 throw std::runtime_error("create_type: Unknown core");
1056 p.core = cores[_core];
1057 for(unsigned* reg = r.regions; *reg != 0xFFFFFFFFU; reg++) {
1058 if(!regions.count(*reg))
1059 throw std::runtime_error("create_type: Unknown region");
1060 p.regions.push_back(regions[*reg]);
1062 return new c_core_type(lib, p, cores[_core]->get_ports(), rcount, type);
1065 void initialize_core2(entrypoint_fn fn, std::map<unsigned, core_sysregion*>& sysregs,
1066 std::map<unsigned, core_region*>& regions, std::map<unsigned, c_core_type*>& types,
1067 std::map<unsigned, c_core_core*>& cores)
1069 c_lib_init& lib = *new c_lib_init(fn);
1070 for(auto& i : regions)
1071 i.second = create_region(fn, i.first);
1072 for(auto& i : cores)
1073 i.second = create_core(lib, fn, regions, i.first);
1074 for(auto& i : types)
1075 i.second = create_type(lib, fn, cores, regions, i.first);
1076 for(auto& i : sysregs)
1077 i.second = create_sysregion(fn, regions, types, i.first);
1078 //We don't call install_handler, because that is done automatically.
1081 void initialize_core(lsnes_core_func_t fn)
1083 //Enumerate what the thing supports.
1084 entrypoint_fn entrypoint(fn);
1085 lsnes_core_enumerate_cores r;
1086 r.emu_flags1 = 1;
1087 r.message = callback_message;
1088 r.get_input = callback_get_input;
1089 r.notify_action_update = callback_notify_action_update;
1090 r.timer_tick = callback_timer_tick;
1091 r.get_firmware_path = callback_get_firmware_path;
1092 r.get_base_path = callback_get_base_path;
1093 r.get_time = callback_get_time;
1094 r.get_randomseed = callback_get_randomseed;
1095 r.memory_read = callback_memory_read;
1096 r.memory_write = callback_memory_write;
1097 r.memory_execute = callback_memory_execute;
1098 r.memory_trace = callback_memory_trace;
1099 r.submit_sound = callback_submit_sound;
1100 r.notify_latch = callback_notify_latch;
1101 r.submit_frame = callback_submit_frame;
1102 r.add_disasm = callback_add_disasm;
1103 r.remove_disasm = callback_remove_disasm;
1104 entrypoint(0, r, [](const char* name, const char* err) {
1105 (stringfmt() << "LSNES_CORE_ENUMERATE_CORES(0) failed: " << err).throwex();
1107 //Collect sysregions, types and cores.
1108 std::map<unsigned, core_region*> regions;
1109 std::map<unsigned, core_sysregion*> sysregs;
1110 std::map<unsigned, c_core_type*> types;
1111 std::map<unsigned, c_core_core*> cores;
1112 for(size_t i = 0; r.sysregions[i] != 0xFFFFFFFFU; i++) {
1113 unsigned sysreg = r.sysregions[i];
1114 sysregs.insert(std::make_pair(sysreg, nullptr));
1115 struct lsnes_core_get_sysregion_info r2;
1116 entrypoint(sysreg, r2, [sysreg](const char* name, const char* err) {
1117 (stringfmt() << "LSNES_CORE_GET_SYSREGION_INFO(" << sysreg << ") failed: "
1118 << err).throwex();
1120 unsigned type = r2.type;
1121 types.insert(std::make_pair(type, nullptr));
1122 struct lsnes_core_get_type_info r3;
1123 entrypoint(type, r3, [type](const char* name, const char* err) {
1124 (stringfmt() << "LSNES_CORE_GET_TYPE_INFO(" << type << ") failed: "
1125 << err).throwex();
1127 cores.insert(std::make_pair(r3.core, nullptr));
1128 for(size_t j = 0; r3.regions[j] != 0xFFFFFFFFU; j++) {
1129 regions.insert(std::make_pair(r3.regions[j], nullptr));
1132 //Do the rest.
1133 initialize_core2(entrypoint, sysregs, regions, types, cores);
1137 void lsnes_register_builtin_core(lsnes_core_func_t fn)
1139 corequeue().push_back(fn);
1142 void try_init_c_module(const loadlib::module& module)
1144 try {
1145 lsnes_core_func_t fn = module.fn<int, unsigned, unsigned, void*,
1146 const char**>("lsnes_core_entrypoint");
1147 initialize_core(fn);
1148 } catch(std::exception& e) {
1149 messages << "Can't initialize core: " << e.what() << std::endl;
1153 void initialize_all_builtin_c_cores()
1155 while(!corequeue().empty()) {
1156 lsnes_core_func_t fn = corequeue().front();
1157 corequeue().pop_front();
1158 try {
1159 initialize_core(fn);
1160 } catch(std::exception& e) {
1161 messages << "Can't initialize core: " << e.what() << std::endl;