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";
90 c_core_core
* current_core
= NULL
;
92 char* strduplicate(const char* x
)
95 char* out
= (char*)malloc(strlen(x
) + 1);
97 throw std::bad_alloc();
102 std::list
<lsnes_core_func_t
>& corequeue()
104 static std::list
<lsnes_core_func_t
> 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
;
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
;
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
);
147 onerror(ccore_call_param_map
<T
>::name
, err
);
150 template<typename T
> bool operator()(unsigned item
, T
& args
)
152 return (*this)(item
, args
, default_error_function
);
155 lsnes_core_func_t fn
;
161 c_lib_init(entrypoint_fn _entrypoint
)
162 : entrypoint(_entrypoint
)
174 lsnes_core_deinitialize s
;
178 entrypoint_fn
get_entrypoint()
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
;
196 std::map
<unsigned, core_region
*> regions
;
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
;
208 internal_pflag
= false;
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()
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
);
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);
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
);
253 lsnes_core_runtosave s
;
254 if(caps1
& LSNES_CORE_CAP1_RUNTOSAVE
) entrypoint(id
, s
);
259 lsnes_core_emulate s
;
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()
283 lsnes_core_debug_reset s
;
284 if(caps1
& (LSNES_CORE_CAP1_DEBUG
| LSNES_CORE_CAP1_TRACE
| LSNES_CORE_CAP1_CHEAT
))
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
))
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
;
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
) {
320 if(entrypoint(id
, s
)) {
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
) {
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
);
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
;
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
;
367 nlength
+= i
.first
.length() + 1;
368 names
.resize(nlength
);
370 for(auto& i
: sram
) {
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
];
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
;
392 ret
[p
->name
].resize(p
->size
);
393 memcpy(&ret
[p
->name
][0], p
->data
, p
->size
);
400 void c_unserialize(const char* in
, size_t insize
)
402 lsnes_core_loadstate s
;
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
;
413 entrypoint(id
, s
, [](const char* name
, const char* err
) {
414 throw std::runtime_error("Savestate failed: " + std::string(err
));
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
) {
424 return entrypoint(id
, s
) ? s
.flags
: 0;
428 std::vector
<std::string
> c_get_trace_cpus()
432 bool c_set_region(core_region
& region
)
434 lsnes_core_set_region s
;
435 if(caps1
& LSNES_CORE_CAP1_MULTIREGION
) {
437 for(auto i
: regions
)
438 if(i
.second
== ®ion
) {
443 return false; //Bad region.
444 return entrypoint(id
, s
);
446 return (regions
.count(0) && regions
[0] == ®ion
);
449 core_region
& c_get_region()
451 lsnes_core_get_region s
;
452 if(caps1
& LSNES_CORE_CAP1_MULTIREGION
) {
453 if(!entrypoint(id
, s
)) {
455 throw std::runtime_error("No valid regions");
456 return *(regions
.begin()->second
);
458 if(regions
.count(s
.region
))
459 return *regions
[s
.region
];
460 messages
<< "Internal error: Core gave invalid region number."
463 throw std::runtime_error("No valid regions");
464 return *(regions
.begin()->second
);
470 messages
<< "Internal error: Not multi-region core and region 0 not present."
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
)) {
492 namelen
+= strlen(tregs
->name
) + 1;
497 if(regs
.size() < count
+ 1)
498 regs
.resize(count
+ 1);
499 if(namelen
> namebuf
.size())
500 namebuf
.resize(namelen
);
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;
513 regs
[idx
].name
= NULL
; //The sentinel.
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
;
533 s
.clear
= flags_clear
;
534 if(caps1
& LSNES_CORE_CAP1_DEBUG
)
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
;
545 if(caps1
& LSNES_CORE_CAP1_CHEAT
)
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
;
556 interface_action
* act
= NULL
;
557 for(auto& i
: actions
) {
564 messages
<< "Unknown action id #" << aid
<< std::endl
;
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
;
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
)) {
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
)) {
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") {
595 messages
<< "Unknown model '" << m
<< "' in action id #" << aid
<< std::endl
;
599 lsnes_core_execute_action s
;
601 s
.params
= ¶meters
[0];
604 framebuffer::raw
& c_draw_cover()
606 lsnes_core_draw_cover r
;
607 if(caps1
& LSNES_CORE_CAP1_COVER
) {
608 if(!entrypoint(id
, r
))
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
);
619 if(covermem
.size() < 1024) covermem
.resize(1024);
620 framebuffer::info fbi
;
621 fbi
.type
= &framebuffer::pixfmt_rgb16
;
622 fbi
.mem
= &covermem
[0];
624 fbi
.physheight
= 448;
631 cover
= framebuffer::raw(fbi
);
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
))
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
;
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
);
659 return std::list
<core_vma_info
>();
661 std::map
<unsigned, port_type
*> get_ports()
665 void set_internal_pflag()
667 internal_pflag
= true;
670 std::string fullname
;
671 std::string shortname
;
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
;
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
)
695 int t_load_rom(core_romimage
* images
, std::map
<std::string
, std::string
>& settings
, uint64_t rtc_sec
,
698 lsnes_core_load_rom r
;
699 std::vector
<char> tmpmem
;
700 std::vector
<lsnes_core_system_setting
> tmpmem2
;
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
;
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
;
715 entrypoint(_id
, r
, [_id
](const char* name
, const char* err
) {
716 (stringfmt() << "LSNES_CORE_LOAD_ROM(" << _id
<< ") failed: " << err
).throwex();
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];
728 entrypoint(_id
, r
, [_id
](const char* name
, const char* err
) {
729 (stringfmt() << "LSNES_CORE_GET_CONTROLLERCONFIG(" << _id
<< ") failed: "
733 for(unsigned* pt
= r
.controller_types
; *pt
!= 0xFFFFFFFFU
; 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
));
747 void copy_settings(std::vector
<char>& tmpmem
, std::vector
<lsnes_core_system_setting
>& tmpmem2
,
748 std::map
<std::string
, std::string
>& settings
)
751 lsnes_core_get_controllerconfig r
;
752 for(auto i
: settings
)
753 asize
+= i
.first
.length() + i
.second
.length() + 2;
754 tmpmem
.resize(asize
);
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();
762 std::copy(i
.second
.begin(), i
.second
.end(), tmpmem
.begin() + asize
);
763 s
.value
= &tmpmem
[asize
];
764 asize
+= i
.second
.length();
766 tmpmem2
.push_back(s
);
768 lsnes_core_system_setting s
;
771 tmpmem2
.push_back(s
);
773 std::map
<unsigned, port_type
*> ports
;
774 entrypoint_fn entrypoint
;
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();
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;
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;
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
;
862 for(const char** p
= params
; *p
; 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
);
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
886 ccore_disasm(struct lsnes_core_disassembler
* disasm
)
887 : disassembler(disasm
->name
)
894 std::string
disassemble(uint64_t base
, std::function
<unsigned char()> fetchpc
)
898 const char* out
= fn(base
, fpcfn::call
, &y
);
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
;
939 p
.priority
= r
.priority
;
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();
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()));
966 if(r
.cap_flags1
& LSNES_CORE_CAP1_ACTION
) {
967 for(lsnes_core_get_core_info_action
* i
= r
.actions
; i
->iname
; i
++) {
970 a
._symbol
= i
->iname
;
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
);
981 p
.actions
.push_back(a
);
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
;
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
;
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();
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
);
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
);
1027 plist
.push_back(_pr
);
1030 unsigned rcount
= 0;
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
);
1044 unsigned _core
= r
.core
;
1048 p
.sysname
= r
.sysname
;
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
;
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: "
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: "
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));
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
)
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();
1157 initialize_core(fn
);
1158 } catch(std::exception
& e
) {
1159 messages
<< "Can't initialize core: " << e
.what() << std::endl
;