C interface: Check for value != 0, not for control != 0 for lag check
[lsnes.git] / src / interface / c-interface.cpp
blob5ebb6db95c5791899b950c514928ad8bffbe6b47
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 std::string c_core_identifier()
218 return fullname;
220 bool get_av_state(lsnes_core_get_av_state& s)
222 return entrypoint(id, s);
224 std::pair<uint32_t, uint32_t> c_video_rate()
226 lsnes_core_get_av_state s;
227 if(!entrypoint(id, s))
228 return std::make_pair(60, 1);
229 return std::make_pair(s.fps_n, s.fps_d);
231 double c_get_PAR()
233 lsnes_core_get_av_state s;
234 return entrypoint(id, s) ? s.par : 1.0;
236 std::pair<uint32_t, uint32_t> c_audio_rate()
238 lsnes_core_get_av_state s;
239 return entrypoint(id, s) ? std::make_pair(s.rate_n, s.rate_d) : std::make_pair(48000U, 1U);
241 void c_power()
243 lsnes_core_poweron s;
244 if(caps1 & LSNES_CORE_CAP1_POWERON) entrypoint(id, s);
246 void c_unload_cartridge()
248 lsnes_core_unload_cartridge s;
249 if(caps1 & LSNES_CORE_CAP1_UNLOAD) entrypoint(id, s);
251 void c_runtosave()
253 lsnes_core_runtosave s;
254 if(caps1 & LSNES_CORE_CAP1_RUNTOSAVE) entrypoint(id, s);
256 void c_emulate()
258 current_core = this;
259 lsnes_core_emulate s;
260 entrypoint(id, s);
261 current_core = NULL;
263 bool c_get_pflag()
265 lsnes_core_get_pflag s;
266 if(!(caps1 & LSNES_CORE_CAP1_PFLAG) || !entrypoint(id, s))
267 return internal_pflag;
268 return (s.pflag != 0);
270 void c_set_pflag(bool pflag)
272 lsnes_core_set_pflag s;
273 s.pflag = pflag ? 1 : 0;
274 if(!(caps1 & LSNES_CORE_CAP1_PFLAG) || !entrypoint(id, s))
275 internal_pflag = pflag;
277 std::string c_get_core_shortname()
279 return shortname;
281 void c_debug_reset()
283 lsnes_core_debug_reset s;
284 if(caps1 & (LSNES_CORE_CAP1_DEBUG | LSNES_CORE_CAP1_TRACE | LSNES_CORE_CAP1_CHEAT))
285 entrypoint(id, s);
287 std::pair<unsigned, unsigned> c_lightgun_scale()
289 lsnes_core_get_av_state s;
290 if(!(caps1 & LSNES_CORE_CAP1_LIGHTGUN) || !entrypoint(id, s))
291 return std::make_pair(0, 0);
292 return std::make_pair(s.lightgun_width, s.lightgun_height);
294 std::pair<uint64_t, uint64_t> c_get_bus_map()
296 lsnes_core_get_bus_mapping s;
297 if(!(caps1 & LSNES_CORE_CAP1_BUSMAP) || !entrypoint(id, s))
298 return std::make_pair(0, 0);
299 return std::make_pair(s.base, s.size);
301 int c_reset_action(bool hard)
303 lsnes_core_get_reset_action s;
304 if(!(caps1 & LSNES_CORE_CAP1_RESET) || !entrypoint(id, s))
305 return -1;
306 return hard ? s.hardreset : s.softreset;
308 std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height)
310 lsnes_core_compute_scale s;
311 bool r = -1;
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 const char* err;
413 entrypoint(id, s, [](const char* name, const char* err) {
414 throw std::runtime_error("Savestate failed: " + std::string(err));
416 out.resize(s.size);
417 memcpy(&out[0], s.data, s.size);
419 unsigned c_action_flags(unsigned _id)
421 lsnes_core_get_action_flags s;
422 if(caps1 & LSNES_CORE_CAP1_ACTION) {
423 s.action = _id;
424 return entrypoint(id, s) ? s.flags : 0;
426 return 0;
428 std::vector<std::string> c_get_trace_cpus()
430 return trace_cpus;
432 bool c_set_region(core_region& region)
434 lsnes_core_set_region s;
435 if(caps1 & LSNES_CORE_CAP1_MULTIREGION) {
436 bool hit = false;
437 for(auto i : regions)
438 if(i.second == &region) {
439 s.region = i.first;
440 hit = true;
442 if(!hit)
443 return false; //Bad region.
444 return entrypoint(id, s);
445 } else {
446 return (regions.count(0) && regions[0] == &region);
449 core_region& c_get_region()
451 lsnes_core_get_region s;
452 if(caps1 & LSNES_CORE_CAP1_MULTIREGION) {
453 if(!entrypoint(id, s)) {
454 if(regions.empty())
455 throw std::runtime_error("No valid regions");
456 return *(regions.begin()->second);
457 } else {
458 if(regions.count(s.region))
459 return *regions[s.region];
460 messages << "Internal error: Core gave invalid region number."
461 << std::endl;
462 if(regions.empty())
463 throw std::runtime_error("No valid regions");
464 return *(regions.begin()->second);
466 } else {
467 if(regions.count(0))
468 return *regions[0];
469 else {
470 messages << "Internal error: Not multi-region core and region 0 not present."
471 << std::endl;
472 if(regions.empty())
473 throw std::runtime_error("No valid regions");
474 return *(regions.begin()->second);
478 const struct interface_device_reg* c_get_registers()
480 static std::vector<interface_device_reg> regs;
481 static std::vector<char> namebuf;
482 static interface_device_reg reg_null = {NULL};
483 lsnes_core_get_device_regs s;
484 if(caps1 & LSNES_CORE_CAP1_REGISTERS) {
485 if(!entrypoint(id, s)) {
486 return &reg_null;
487 } else {
488 size_t count = 0;
489 size_t namelen = 0;
490 auto tregs = s.regs;
491 while(tregs->name) {
492 namelen += strlen(tregs->name) + 1;
493 count++;
494 tregs++;
496 tregs = s.regs;
497 if(regs.size() < count + 1)
498 regs.resize(count + 1);
499 if(namelen > namebuf.size())
500 namebuf.resize(namelen);
501 size_t idx = 0;
502 size_t nameptr = 0;
503 while(tregs->name) {
504 strcpy(&namebuf[nameptr], tregs->name);
505 regs[idx].name = &namebuf[nameptr];
506 regs[idx].read = tregs->read;
507 regs[idx].write = tregs->write;
508 regs[idx].boolean = tregs->boolean;
509 nameptr += strlen(tregs->name) + 1;
510 tregs++;
511 idx++;
513 regs[idx].name = NULL; //The sentinel.
515 } else {
516 return &reg_null;
518 return &regs[0];
520 void c_install_handler()
522 plugin->initialize();
524 void c_uninstall_handler()
526 plugin->deinitialize();
528 void c_set_debug_flags(uint64_t addr, unsigned flags_set, unsigned flags_clear)
530 lsnes_core_set_debug_flags s;
531 s.addr = addr;
532 s.set = flags_set;
533 s.clear = flags_clear;
534 if(caps1 & LSNES_CORE_CAP1_DEBUG)
535 entrypoint(id, s);
536 else
537 messages << "Debugging functions not supported by core" << std::endl;
539 void c_set_cheat(uint64_t addr, uint64_t value, bool set)
541 lsnes_core_set_cheat s;
542 s.addr = addr;
543 s.value = value;
544 s.set = set;
545 if(caps1 & LSNES_CORE_CAP1_CHEAT)
546 entrypoint(id, s);
547 else
548 messages << "Cheat functions not supported by core" << std::endl;
550 void c_execute_action(unsigned aid, const std::vector<interface_action_paramval>& p)
552 if(!(caps1 & LSNES_CORE_CAP1_ACTION)) {
553 messages << "Core does not support actions." << std::endl;
554 return;
556 interface_action* act = NULL;
557 for(auto& i : actions) {
558 if(i.id == aid) {
559 act = &i;
560 break;
563 if(!act) {
564 messages << "Unknown action id #" << aid << std::endl;
565 return;
567 size_t j = 0;
568 std::vector<lsnes_core_execute_action_param> parameters;
569 std::list<std::vector<char>> strtmp;
570 for(auto& b : act->params) {
571 std::string m = b.model;
572 if(m == "bool") {
573 //Boolean.
574 lsnes_core_execute_action_param tp;
575 tp.boolean = p[j++].b;
576 parameters.push_back(tp);
577 } else if(regex_match("int:.*", m)) {
578 //Integer.
579 lsnes_core_execute_action_param tp;
580 tp.integer = p[j++].i;
581 parameters.push_back(tp);
582 } else if(regex_match("string(:.*)?", m) || regex_match("enum:.*", m)) {
583 //String.
584 strtmp.push_back(std::vector<char>());
585 auto& i = strtmp.back();
586 i.resize(p[j].s.length() + 1);
587 std::copy(p[j].s.begin(), p[j].s.end(), i.begin());
588 lsnes_core_execute_action_param tp;
589 tp.string.base = &i[0];
590 tp.string.length = p[j++].s.length();
591 parameters.push_back(tp);
592 } else if(m == "toggle") {
593 //Skip.
594 } else {
595 messages << "Unknown model '" << m << "' in action id #" << aid << std::endl;
596 return;
599 lsnes_core_execute_action s;
600 s.action = aid;
601 s.params = &parameters[0];
602 entrypoint(id, s);
604 framebuffer::raw& c_draw_cover()
606 lsnes_core_draw_cover r;
607 if(caps1 & LSNES_CORE_CAP1_COVER) {
608 if(!entrypoint(id, r))
609 goto failed;
610 framebuffer::info fbinfo = translate_info(r.coverpage);
611 size_t needed = fbinfo.physwidth * fbinfo.physheight * fbinfo.type->get_bpp();
612 if(covermem.size() < needed) covermem.resize(needed);
613 memcpy(&covermem[0], fbinfo.mem, needed);
614 fbinfo.mem = &covermem[0];
615 cover = framebuffer::raw(fbinfo);
616 return cover;
618 failed:
619 if(covermem.size() < 1024) covermem.resize(1024);
620 framebuffer::info fbi;
621 fbi.type = &framebuffer::pixfmt_rgb16;
622 fbi.mem = &covermem[0];
623 fbi.physwidth = 512;
624 fbi.physheight = 448;
625 fbi.physstride = 0;
626 fbi.width = 512;
627 fbi.height = 448;
628 fbi.stride = 0;
629 fbi.offset_x = 0;
630 fbi.offset_y = 0;
631 cover = framebuffer::raw(fbi);
632 return cover;
634 std::list<core_vma_info> c_vma_list()
636 lsnes_core_get_vma_list r;
637 if(caps1 & LSNES_CORE_CAP1_MEMWATCH) {
638 if(!entrypoint(id, r))
639 goto failed;
640 std::list<core_vma_info> vmalist;
641 for(lsnes_core_get_vma_list_vma** vmas = r.vmas; *vmas; vmas++) {
642 lsnes_core_get_vma_list_vma* vma = *vmas;
643 core_vma_info _vma;
644 _vma.name = vma->name;
645 _vma.base = vma->base;
646 _vma.size = vma->size;
647 _vma.endian = vma->endian;
648 _vma.readonly = ((vma->flags & LSNES_CORE_VMA_READONLY) != 0);
649 _vma.special = ((vma->flags & LSNES_CORE_VMA_SPECIAL) != 0);
650 _vma.volatile_flag = ((vma->flags & LSNES_CORE_VMA_VOLATILE) != 0);
651 _vma.backing_ram = vma->direct_map;
652 _vma.read = vma->read;
653 _vma.write = vma->write;
654 vmalist.push_back(_vma);
656 return vmalist;
658 failed:
659 return std::list<core_vma_info>();
661 std::map<unsigned, port_type*> get_ports()
663 return ports;
665 void set_internal_pflag()
667 internal_pflag = true;
669 private:
670 std::string fullname;
671 std::string shortname;
672 unsigned id;
673 bool internal_pflag;
674 unsigned caps1;
675 std::vector<std::string> trace_cpus;
676 std::map<unsigned, port_type*> ports;
677 std::map<unsigned, core_region*> regions;
678 std::vector<interface_action> actions;
679 framebuffer::raw cover;
680 std::vector<char> covermem;
681 entrypoint_fn entrypoint;
682 c_lib_init* plugin;
685 struct c_core_type : public core_type
687 c_core_type(c_lib_init& lib, core_type_params& p, std::map<unsigned, port_type*> _ports,
688 unsigned _rcount, unsigned _id)
689 : core_type(p), ports(_ports), entrypoint(lib.get_entrypoint()), rcount(_rcount), id(_id)
692 ~c_core_type()
695 int t_load_rom(core_romimage* images, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
696 uint64_t rtc_subsec)
698 lsnes_core_load_rom r;
699 std::vector<char> tmpmem;
700 std::vector<lsnes_core_system_setting> tmpmem2;
701 r.rtc_sec = rtc_sec;
702 r.rtc_subsec = rtc_subsec;
703 copy_settings(tmpmem, tmpmem2, settings);
704 r.settings = &tmpmem2[0];
706 std::vector<lsnes_core_load_rom_image> imgs;
707 imgs.resize(rcount);
708 for(unsigned i = 0; i < rcount; i++) {
709 imgs[i].data = (const char*)images[i].data;
710 imgs[i].size = images[i].size;
711 imgs[i].markup = images[i].markup;
713 r.images = &imgs[0];
714 unsigned _id = id;
715 entrypoint(_id, r, [_id](const char* name, const char* err) {
716 (stringfmt() << "LSNES_CORE_LOAD_ROM(" << _id << ") failed: " << err).throwex();
718 return 0;
720 controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
722 lsnes_core_get_controllerconfig r;
723 std::vector<char> tmpmem;
724 std::vector<lsnes_core_system_setting> tmpmem2;
725 copy_settings(tmpmem, tmpmem2, settings);
726 r.settings = &tmpmem2[0];
727 unsigned _id = id;
728 entrypoint(_id, r, [_id](const char* name, const char* err) {
729 (stringfmt() << "LSNES_CORE_GET_CONTROLLERCONFIG(" << _id << ") failed: "
730 << err).throwex();
732 controller_set cset;
733 for(unsigned* pt = r.controller_types; *pt != 0xFFFFFFFFU; pt++) {
734 unsigned _pt = *pt;
735 if(!ports.count(_pt))
736 throw std::runtime_error("Illegal port type selected by core");
737 port_type* pt2 = ports[_pt];
738 cset.ports.push_back(pt2);
740 for(lsnes_core_get_controllerconfig_logical_entry* le = r.logical_map;
741 le->port | le->controller; le++) {
742 cset.logical_map.push_back(std::make_pair(le->port, le->controller));
744 return cset;
746 private:
747 void copy_settings(std::vector<char>& tmpmem, std::vector<lsnes_core_system_setting>& tmpmem2,
748 std::map<std::string, std::string>& settings)
750 size_t asize = 0;
751 lsnes_core_get_controllerconfig r;
752 for(auto i : settings)
753 asize += i.first.length() + i.second.length() + 2;
754 tmpmem.resize(asize);
755 asize = 0;
756 for(auto i : settings) {
757 lsnes_core_system_setting s;
758 std::copy(i.first.begin(), i.first.end(), tmpmem.begin() + asize);
759 s.name = &tmpmem[asize];
760 asize += i.first.length();
761 tmpmem[asize++] = 0;
762 std::copy(i.second.begin(), i.second.end(), tmpmem.begin() + asize);
763 s.value = &tmpmem[asize];
764 asize += i.second.length();
765 tmpmem[asize++] = 0;
766 tmpmem2.push_back(s);
768 lsnes_core_system_setting s;
769 s.name = NULL;
770 s.value = NULL;
771 tmpmem2.push_back(s);
773 std::map<unsigned, port_type*> ports;
774 entrypoint_fn entrypoint;
775 unsigned rcount;
776 unsigned id;
779 std::vector<char> msgbuf;
781 void callback_message(const char* msg, size_t length)
783 std::string _msg(msg, msg + length);
784 messages << _msg << std::endl;
787 short callback_get_input(unsigned port, unsigned index, unsigned control)
789 short v = ecore_callbacks->get_input(port, index, control);
790 if(current_core && (port || index || v))
791 current_core->set_internal_pflag();
792 return v;
795 void callback_notify_action_update()
797 ecore_callbacks->action_state_updated();
800 void callback_timer_tick(uint32_t increment, uint32_t per_second)
802 ecore_callbacks->timer_tick(increment, per_second);
805 const char* callback_get_firmware_path()
807 std::string fwp = ecore_callbacks->get_firmware_path();
808 msgbuf.resize(fwp.length() + 1);
809 std::copy(fwp.begin(), fwp.end(), msgbuf.begin());
810 msgbuf[fwp.length()] = 0;
811 return &msgbuf[0];
814 const char* callback_get_base_path()
816 std::string fwp = ecore_callbacks->get_base_path();
817 msgbuf.resize(fwp.length() + 1);
818 std::copy(fwp.begin(), fwp.end(), msgbuf.begin());
819 msgbuf[fwp.length()] = 0;
820 return &msgbuf[0];
823 time_t callback_get_time()
825 return ecore_callbacks->get_time();
828 time_t callback_get_randomseed()
830 return ecore_callbacks->get_randomseed();
833 void callback_memory_read(uint64_t addr, uint64_t value)
835 ecore_callbacks->memory_read(addr, value);
838 void callback_memory_write(uint64_t addr, uint64_t value)
840 ecore_callbacks->memory_write(addr, value);
843 void callback_memory_execute(uint64_t addr, uint64_t cpunum)
845 ecore_callbacks->memory_execute(addr, cpunum);
848 void callback_memory_trace(uint64_t proc, const char* str, int insn)
850 ecore_callbacks->memory_trace(proc, str, insn);
853 void callback_submit_sound(const int16_t* samples, size_t count, int stereo, double rate)
855 audioapi_submit_buffer((int16_t*)samples, count, stereo, rate);
858 void callback_notify_latch(const char** params)
860 std::list<std::string> ps;
861 if(params)
862 for(const char** p = params; *p; p++)
863 ps.push_back(*p);
864 ecore_callbacks->notify_latch(ps);
867 void callback_submit_frame(struct lsnes_core_framebuffer_info* _fb, uint32_t fps_n, uint32_t fps_d)
869 framebuffer::info fbinfo = translate_info(_fb);
870 framebuffer::raw fb(fbinfo);
871 ecore_callbacks->output_frame(fb, fps_n, fps_d);
874 struct fpcfn
876 std::function<unsigned char()> fn;
877 static unsigned char call(void* ctx)
879 return reinterpret_cast<fpcfn*>(ctx)->fn();
883 class ccore_disasm : public disassembler
885 public:
886 ccore_disasm(struct lsnes_core_disassembler* disasm)
887 : disassembler(disasm->name)
889 fn = disasm->fn;
891 ~ccore_disasm()
894 std::string disassemble(uint64_t base, std::function<unsigned char()> fetchpc)
896 fpcfn y;
897 y.fn = fetchpc;
898 const char* out = fn(base, fpcfn::call, &y);
899 return out;
901 private:
902 const char* (*fn)(uint64_t base, unsigned char(*fetch)(void* ctx), void* ctx);
905 void* callback_add_disasm(struct lsnes_core_disassembler* disasm)
907 return new ccore_disasm(disasm);
910 void callback_remove_disasm(void* handle)
912 delete reinterpret_cast<ccore_disasm*>(handle);
915 core_sysregion* create_sysregion(entrypoint_fn& entrypoint, std::map<unsigned, core_region*>& regions,
916 std::map<unsigned, c_core_type*>& types, unsigned sysreg)
918 struct lsnes_core_get_sysregion_info r;
919 entrypoint(sysreg, r, [sysreg](const char* name, const char* err) {
920 (stringfmt() << "LSNES_CORE_GET_SYSREGION_INFO(" << sysreg << ") failed: " << err).throwex();
922 register_sysregion_mapping(r.name, r.for_system);
923 if(!types.count(r.type))
924 throw std::runtime_error("create_sysregion: Unknown type");
925 if(!regions.count(r.region))
926 throw std::runtime_error("create_sysregion: Unknown region");
927 return new core_sysregion(r.name, *types[r.type], *regions[r.region]);
930 core_region* create_region(entrypoint_fn& entrypoint, unsigned region)
932 struct lsnes_core_get_region_info r;
933 entrypoint(region, r, [region](const char* name, const char* err) {
934 (stringfmt() << "LSNES_CORE_GET_REGION_INFO(" << region << ") failed: " << err).throwex();
936 core_region_params p;
937 p.iname = r.iname;
938 p.hname = r.hname;
939 p.priority = r.priority;
940 p.handle = region;
941 p.multi = r.multi;
942 p.framemagic[0] = r.fps_n;
943 p.framemagic[1] = r.fps_d;
944 for(size_t i = 0; r.compatible_runs[i] != 0xFFFFFFFFU; i++)
945 p.compatible_runs.push_back(r.compatible_runs[i]);
946 return new core_region(p);
949 c_core_core* create_core(c_lib_init& lib, entrypoint_fn& entrypoint,
950 std::map<unsigned, core_region*>& regions, unsigned core)
952 c_core_core_params p;
953 struct lsnes_core_get_core_info r;
954 entrypoint(core, r, [core](const char* name, const char* err) {
955 (stringfmt() << "LSNES_CORE_GET_CORE_INFO(" << core << ") failed: " << err).throwex();
957 //Read ports.
958 JSON::node root(r.json);
959 JSON::pointer rootptr(r.root_ptr);
960 size_t count = root[rootptr].index_count();
961 for(size_t i = 0; i < count; i++) {
962 JSON::pointer j = rootptr.index(i);
963 p.ports.push_back(new port_type_generic(root, j.as_string8()));
965 //Read actions.
966 if(r.cap_flags1 & LSNES_CORE_CAP1_ACTION) {
967 for(lsnes_core_get_core_info_action* i = r.actions; i->iname; i++) {
968 interface_action a;
969 a.id = i->id;
970 a._symbol = i->iname;
971 a._title = i->hname;
972 if(!i->parameters)
973 goto no_parameters;
974 for(lsnes_core_get_core_info_aparam* k = i->parameters; k->name; k++) {
975 interface_action_param b;
976 b.name = strduplicate(k->name);
977 b.model = strduplicate(k->model);
978 a.params.push_back(b);
980 no_parameters:
981 p.actions.push_back(a);
984 //Read trace CPUs.
985 if(r.cap_flags1 & LSNES_CORE_CAP1_TRACE) {
986 for(const char** i = r.trace_cpu_list; *i; i++) {
987 p.trace_cpus.push_back(*i);
990 for(auto & j : regions)
991 p.regions[j.first] = j.second;
992 p.shortname = r.shortname;
993 p.fullname = r.fullname;
994 p.flags = r.cap_flags1;
995 p.id = core;
996 p.library = &lib;
997 return new c_core_core(p);
1000 c_core_type* create_type(c_lib_init& lib, entrypoint_fn& entrypoint, std::map<unsigned, c_core_core*>& cores,
1001 std::map<unsigned, core_region*>& regions, unsigned type)
1003 std::vector<core_romimage_info_params> rlist;
1004 std::vector<core_setting_param> plist;
1005 core_type_params p;
1006 struct lsnes_core_get_type_info r;
1007 entrypoint(type, r, [type](const char* name, const char* err) {
1008 (stringfmt() << "LSNES_CORE_GET_TYPE_INFO(" << type << ") failed: " << err).throwex();
1010 if(r.settings) {
1011 for(lsnes_core_get_type_info_param* param = r.settings; param->iname; param++) {
1012 core_setting_param _pr;
1013 _pr.iname = strduplicate(param->iname);
1014 _pr.hname = strduplicate(param->hname);
1015 _pr.dflt = strduplicate(param->dflt);
1016 _pr.regex = strduplicate(param->regex);
1017 if(!param->values)
1018 goto no_values;
1019 for(lsnes_core_get_type_info_paramval* pval = param->values; pval->iname; pval++) {
1020 core_setting_value_param pv;
1021 pv.iname = strduplicate(pval->iname);
1022 pv.hname = strduplicate(pval->hname);
1023 pv.index = pval->index;
1024 _pr.values.push_back(pv);
1026 no_values:
1027 plist.push_back(_pr);
1030 unsigned rcount = 0;
1031 if(r.images) {
1032 for(lsnes_core_get_type_info_romimage* rimg = r.images; rimg->iname; rimg++) {
1033 core_romimage_info_params rp;
1034 rp.iname = rimg->iname;
1035 rp.hname = rimg->hname;
1036 rp.mandatory = rimg->mandatory;
1037 rp.pass_mode = rimg->pass_mode;
1038 rp.headersize = rimg->headersize;
1039 rp.extensions = rimg->extensions;
1040 rlist.push_back(rp);
1041 rcount++;
1044 unsigned _core = r.core;
1045 p.id = type;
1046 p.iname = r.iname;
1047 p.hname = r.hname;
1048 p.sysname = r.sysname;
1049 p.bios = r.bios;
1050 p.settings = plist;
1051 p.images = rlist;
1052 if(!cores.count(_core))
1053 throw std::runtime_error("create_type: Unknown core");
1054 p.core = cores[_core];
1055 for(unsigned* reg = r.regions; *reg != 0xFFFFFFFFU; reg++) {
1056 if(!regions.count(*reg))
1057 throw std::runtime_error("create_type: Unknown region");
1058 p.regions.push_back(regions[*reg]);
1060 return new c_core_type(lib, p, cores[_core]->get_ports(), rcount, type);
1063 void initialize_core2(entrypoint_fn fn, std::map<unsigned, core_sysregion*>& sysregs,
1064 std::map<unsigned, core_region*>& regions, std::map<unsigned, c_core_type*>& types,
1065 std::map<unsigned, c_core_core*>& cores)
1067 c_lib_init& lib = *new c_lib_init(fn);
1068 for(auto& i : regions)
1069 i.second = create_region(fn, i.first);
1070 for(auto& i : cores)
1071 i.second = create_core(lib, fn, regions, i.first);
1072 for(auto& i : types)
1073 i.second = create_type(lib, fn, cores, regions, i.first);
1074 for(auto& i : sysregs)
1075 i.second = create_sysregion(fn, regions, types, i.first);
1076 //We don't call install_handler, because that is done automatically.
1079 void initialize_core(lsnes_core_func_t fn)
1081 //Enumerate what the thing supports.
1082 entrypoint_fn entrypoint(fn);
1083 lsnes_core_enumerate_cores r;
1084 r.emu_flags1 = 1;
1085 r.message = callback_message;
1086 r.get_input = callback_get_input;
1087 r.notify_action_update = callback_notify_action_update;
1088 r.timer_tick = callback_timer_tick;
1089 r.get_firmware_path = callback_get_firmware_path;
1090 r.get_base_path = callback_get_base_path;
1091 r.get_time = callback_get_time;
1092 r.get_randomseed = callback_get_randomseed;
1093 r.memory_read = callback_memory_read;
1094 r.memory_write = callback_memory_write;
1095 r.memory_execute = callback_memory_execute;
1096 r.memory_trace = callback_memory_trace;
1097 r.submit_sound = callback_submit_sound;
1098 r.notify_latch = callback_notify_latch;
1099 r.submit_frame = callback_submit_frame;
1100 r.add_disasm = callback_add_disasm;
1101 r.remove_disasm = callback_remove_disasm;
1102 entrypoint(0, r, [](const char* name, const char* err) {
1103 (stringfmt() << "LSNES_CORE_ENUMERATE_CORES(0) failed: " << err).throwex();
1105 //Collect sysregions, types and cores.
1106 std::map<unsigned, core_region*> regions;
1107 std::map<unsigned, core_sysregion*> sysregs;
1108 std::map<unsigned, c_core_type*> types;
1109 std::map<unsigned, c_core_core*> cores;
1110 for(size_t i = 0; r.sysregions[i] != 0xFFFFFFFFU; i++) {
1111 unsigned sysreg = r.sysregions[i];
1112 sysregs.insert(std::make_pair(sysreg, nullptr));
1113 struct lsnes_core_get_sysregion_info r2;
1114 entrypoint(sysreg, r2, [sysreg](const char* name, const char* err) {
1115 (stringfmt() << "LSNES_CORE_GET_SYSREGION_INFO(" << sysreg << ") failed: "
1116 << err).throwex();
1118 unsigned type = r2.type;
1119 types.insert(std::make_pair(type, nullptr));
1120 struct lsnes_core_get_type_info r3;
1121 entrypoint(type, r3, [type](const char* name, const char* err) {
1122 (stringfmt() << "LSNES_CORE_GET_TYPE_INFO(" << type << ") failed: "
1123 << err).throwex();
1125 cores.insert(std::make_pair(r3.core, nullptr));
1126 for(size_t j = 0; r3.regions[j] != 0xFFFFFFFFU; j++) {
1127 regions.insert(std::make_pair(r3.regions[j], nullptr));
1130 //Do the rest.
1131 initialize_core2(entrypoint, sysregs, regions, types, cores);
1135 void lsnes_register_builtin_core(lsnes_core_func_t fn)
1137 corequeue().push_back(fn);
1140 void try_init_c_module(const loadlib::module& module)
1142 try {
1143 lsnes_core_func_t fn = module.fn<int, unsigned, unsigned, void*,
1144 const char**>("lsnes_core_entrypoint");
1145 initialize_core(fn);
1146 } catch(std::exception& e) {
1147 messages << "Can't initialize core: " << e.what() << std::endl;
1151 void initialize_all_builtin_c_cores()
1153 while(!corequeue().empty()) {
1154 lsnes_core_func_t fn = corequeue().front();
1155 corequeue().pop_front();
1156 try {
1157 initialize_core(fn);
1158 } catch(std::exception& e) {
1159 messages << "Can't initialize core: " << e.what() << std::endl;