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