1 #include "interface/c-interface.hpp"
2 #include "interface/callbacks.hpp"
3 #include "interface/romtype.hpp"
4 #include "interface/setting.hpp"
5 #include "interface/disassembler.hpp"
6 #include "library/string.hpp"
7 #include "library/portctrl-parse.hpp"
8 #include "library/framebuffer.hpp"
9 #include "library/framebuffer-pixfmt-rgb15.hpp"
10 #include "library/framebuffer-pixfmt-rgb16.hpp"
11 #include "library/framebuffer-pixfmt-rgb24.hpp"
12 #include "library/framebuffer-pixfmt-rgb32.hpp"
13 #include "library/framebuffer-pixfmt-lrgb.hpp"
14 #include "fonts/wrapper.hpp"
15 #include "core/audioapi.hpp"
16 #include "core/instance.hpp"
17 #include "core/messages.hpp"
19 template<> int ccore_call_param_map
<lsnes_core_enumerate_cores
>::id
= LSNES_CORE_ENUMERATE_CORES
;
20 template<> int ccore_call_param_map
<lsnes_core_get_core_info
>::id
= LSNES_CORE_GET_CORE_INFO
;
21 template<> int ccore_call_param_map
<lsnes_core_get_type_info
>::id
= LSNES_CORE_GET_TYPE_INFO
;
22 template<> int ccore_call_param_map
<lsnes_core_get_region_info
>::id
= LSNES_CORE_GET_REGION_INFO
;
23 template<> int ccore_call_param_map
<lsnes_core_get_sysregion_info
>::id
= LSNES_CORE_GET_SYSREGION_INFO
;
24 template<> int ccore_call_param_map
<lsnes_core_get_av_state
>::id
= LSNES_CORE_GET_AV_STATE
;
25 template<> int ccore_call_param_map
<lsnes_core_emulate
>::id
= LSNES_CORE_EMULATE
;
26 template<> int ccore_call_param_map
<lsnes_core_savestate
>::id
= LSNES_CORE_SAVESTATE
;
27 template<> int ccore_call_param_map
<lsnes_core_loadstate
>::id
= LSNES_CORE_LOADSTATE
;
28 template<> int ccore_call_param_map
<lsnes_core_get_controllerconfig
>::id
= LSNES_CORE_GET_CONTROLLERCONFIG
;
29 template<> int ccore_call_param_map
<lsnes_core_load_rom
>::id
= LSNES_CORE_LOAD_ROM
;
30 template<> int ccore_call_param_map
<lsnes_core_get_region
>::id
= LSNES_CORE_GET_REGION
;
31 template<> int ccore_call_param_map
<lsnes_core_set_region
>::id
= LSNES_CORE_SET_REGION
;
32 template<> int ccore_call_param_map
<lsnes_core_deinitialize
>::id
= LSNES_CORE_DEINITIALIZE
;
33 template<> int ccore_call_param_map
<lsnes_core_get_pflag
>::id
= LSNES_CORE_GET_PFLAG
;
34 template<> int ccore_call_param_map
<lsnes_core_set_pflag
>::id
= LSNES_CORE_SET_PFLAG
;
35 template<> int ccore_call_param_map
<lsnes_core_get_action_flags
>::id
= LSNES_CORE_GET_ACTION_FLAGS
;
36 template<> int ccore_call_param_map
<lsnes_core_execute_action
>::id
= LSNES_CORE_EXECUTE_ACTION
;
37 template<> int ccore_call_param_map
<lsnes_core_get_bus_mapping
>::id
= LSNES_CORE_GET_BUS_MAPPING
;
38 template<> int ccore_call_param_map
<lsnes_core_enumerate_sram
>::id
= LSNES_CORE_ENUMERATE_SRAM
;
39 template<> int ccore_call_param_map
<lsnes_core_save_sram
>::id
= LSNES_CORE_SAVE_SRAM
;
40 template<> int ccore_call_param_map
<lsnes_core_load_sram
>::id
= LSNES_CORE_LOAD_SRAM
;
41 template<> int ccore_call_param_map
<lsnes_core_get_reset_action
>::id
= LSNES_CORE_GET_RESET_ACTION
;
42 template<> int ccore_call_param_map
<lsnes_core_compute_scale
>::id
= LSNES_CORE_COMPUTE_SCALE
;
43 template<> int ccore_call_param_map
<lsnes_core_runtosave
>::id
= LSNES_CORE_RUNTOSAVE
;
44 template<> int ccore_call_param_map
<lsnes_core_poweron
>::id
= LSNES_CORE_POWERON
;
45 template<> int ccore_call_param_map
<lsnes_core_unload_cartridge
>::id
= LSNES_CORE_UNLOAD_CARTRIDGE
;
46 template<> int ccore_call_param_map
<lsnes_core_debug_reset
>::id
= LSNES_CORE_DEBUG_RESET
;
47 template<> int ccore_call_param_map
<lsnes_core_set_debug_flags
>::id
= LSNES_CORE_SET_DEBUG_FLAGS
;
48 template<> int ccore_call_param_map
<lsnes_core_set_cheat
>::id
= LSNES_CORE_SET_CHEAT
;
49 template<> int ccore_call_param_map
<lsnes_core_draw_cover
>::id
= LSNES_CORE_DRAW_COVER
;
50 template<> int ccore_call_param_map
<lsnes_core_pre_emulate
>::id
= LSNES_CORE_PRE_EMULATE
;
51 template<> int ccore_call_param_map
<lsnes_core_get_device_regs
>::id
= LSNES_CORE_GET_DEVICE_REGS
;
52 template<> int ccore_call_param_map
<lsnes_core_get_vma_list
>::id
= LSNES_CORE_GET_VMA_LIST
;
53 template<> int ccore_call_param_map
<lsnes_core_reinit
>::id
= LSNES_CORE_REINIT
;
55 template<> const char* ccore_call_param_map
<lsnes_core_enumerate_cores
>::name
= "LSNES_CORE_ENUMERATE_CORES";
56 template<> const char* ccore_call_param_map
<lsnes_core_get_core_info
>::name
= "LSNES_CORE_GET_CORE_INFO";
57 template<> const char* ccore_call_param_map
<lsnes_core_get_type_info
>::name
= "LSNES_CORE_GET_TYPE_INFO";
58 template<> const char* ccore_call_param_map
<lsnes_core_get_region_info
>::name
= "LSNES_CORE_GET_REGION_INFO";
59 template<> const char* ccore_call_param_map
<lsnes_core_get_sysregion_info
>::name
= "LSNES_CORE_GET_SYSREGION_INFO";
60 template<> const char* ccore_call_param_map
<lsnes_core_get_av_state
>::name
= "LSNES_CORE_GET_AV_STATE";
61 template<> const char* ccore_call_param_map
<lsnes_core_emulate
>::name
= "LSNES_CORE_EMULATE";
62 template<> const char* ccore_call_param_map
<lsnes_core_savestate
>::name
= "LSNES_CORE_SAVESTATE";
63 template<> const char* ccore_call_param_map
<lsnes_core_loadstate
>::name
= "LSNES_CORE_LOADSTATE";
64 template<> const char* ccore_call_param_map
<lsnes_core_get_controllerconfig
>::name
=
65 "LSNES_CORE_GET_CONTROLLERCONFIG";
66 template<> const char* ccore_call_param_map
<lsnes_core_load_rom
>::name
= "LSNES_CORE_LOAD_ROM";
67 template<> const char* ccore_call_param_map
<lsnes_core_get_region
>::name
= "LSNES_CORE_GET_REGION";
68 template<> const char* ccore_call_param_map
<lsnes_core_set_region
>::name
= "LSNES_CORE_SET_REGION";
69 template<> const char* ccore_call_param_map
<lsnes_core_deinitialize
>::name
= "LSNES_CORE_DEINITIALIZE";
70 template<> const char* ccore_call_param_map
<lsnes_core_get_pflag
>::name
= "LSNES_CORE_GET_PFLAG";
71 template<> const char* ccore_call_param_map
<lsnes_core_set_pflag
>::name
= "LSNES_CORE_SET_PFLAG";
72 template<> const char* ccore_call_param_map
<lsnes_core_get_action_flags
>::name
= "LSNES_CORE_GET_ACTION_FLAGS";
73 template<> const char* ccore_call_param_map
<lsnes_core_execute_action
>::name
= "LSNES_CORE_EXECUTE_ACTION";
74 template<> const char* ccore_call_param_map
<lsnes_core_get_bus_mapping
>::name
= "LSNES_CORE_GET_BUS_MAPPING";
75 template<> const char* ccore_call_param_map
<lsnes_core_enumerate_sram
>::name
= "LSNES_CORE_ENUMERATE_SRAM";
76 template<> const char* ccore_call_param_map
<lsnes_core_save_sram
>::name
= "LSNES_CORE_SAVE_SRAM";
77 template<> const char* ccore_call_param_map
<lsnes_core_load_sram
>::name
= "LSNES_CORE_LOAD_SRAM";
78 template<> const char* ccore_call_param_map
<lsnes_core_get_reset_action
>::name
= "LSNES_CORE_GET_RESET_ACTION";
79 template<> const char* ccore_call_param_map
<lsnes_core_compute_scale
>::name
= "LSNES_CORE_COMPUTE_SCALE";
80 template<> const char* ccore_call_param_map
<lsnes_core_runtosave
>::name
= "LSNES_CORE_RUNTOSAVE";
81 template<> const char* ccore_call_param_map
<lsnes_core_poweron
>::name
= "LSNES_CORE_POWERON";
82 template<> const char* ccore_call_param_map
<lsnes_core_unload_cartridge
>::name
= "LSNES_CORE_UNLOAD_CARTRIDGE";
83 template<> const char* ccore_call_param_map
<lsnes_core_debug_reset
>::name
= "LSNES_CORE_DEBUG_RESET";
84 template<> const char* ccore_call_param_map
<lsnes_core_set_debug_flags
>::name
= "LSNES_CORE_SET_DEBUG_FLAGS";
85 template<> const char* ccore_call_param_map
<lsnes_core_set_cheat
>::name
= "LSNES_CORE_SET_CHEAT";
86 template<> const char* ccore_call_param_map
<lsnes_core_draw_cover
>::name
= "LSNES_CORE_DRAW_COVER";
87 template<> const char* ccore_call_param_map
<lsnes_core_pre_emulate
>::name
= "LSNES_CORE_PRE_EMULATE";
88 template<> const char* ccore_call_param_map
<lsnes_core_get_device_regs
>::name
= "LSNES_CORE_GET_DEVICE_REGS";
89 template<> const char* ccore_call_param_map
<lsnes_core_get_vma_list
>::name
= "LSNES_CORE_GET_VMA_LIST";
90 template<> const char* ccore_call_param_map
<lsnes_core_reinit
>::name
= "LSNES_CORE_REINIT";
95 c_core_core
* current_core
= NULL
;
97 char* strduplicate(const char* x
)
100 char* out
= (char*)malloc(strlen(x
) + 1);
102 throw std::bad_alloc();
107 std::list
<lsnes_core_func_t
>& corequeue()
109 static std::list
<lsnes_core_func_t
> x
;
113 void default_error_function(const char* callname
, const char* err
)
115 messages
<< "Warning: " << callname
<< " failed: " << err
<< std::endl
;
118 framebuffer::info
translate_info(lsnes_core_framebuffer_info
* _fb
)
120 framebuffer::info fbinfo
;
122 case LSNES_CORE_PIXFMT_RGB15
: fbinfo
.type
= &framebuffer::pixfmt_rgb15
; break;
123 case LSNES_CORE_PIXFMT_BGR15
: fbinfo
.type
= &framebuffer::pixfmt_bgr15
; break;
124 case LSNES_CORE_PIXFMT_RGB16
: fbinfo
.type
= &framebuffer::pixfmt_rgb16
; break;
125 case LSNES_CORE_PIXFMT_BGR16
: fbinfo
.type
= &framebuffer::pixfmt_bgr16
; break;
126 case LSNES_CORE_PIXFMT_RGB24
: fbinfo
.type
= &framebuffer::pixfmt_rgb24
; break;
127 case LSNES_CORE_PIXFMT_BGR24
: fbinfo
.type
= &framebuffer::pixfmt_bgr24
; break;
128 case LSNES_CORE_PIXFMT_RGB32
: fbinfo
.type
= &framebuffer::pixfmt_rgb32
; break;
129 case LSNES_CORE_PIXFMT_LRGB
: fbinfo
.type
= &framebuffer::pixfmt_lrgb
; break;
131 fbinfo
.mem
= (char*)_fb
->mem
;
132 fbinfo
.physwidth
= _fb
->physwidth
;
133 fbinfo
.physheight
= _fb
->physheight
;
134 fbinfo
.physstride
= _fb
->physstride
;
135 fbinfo
.width
= _fb
->width
;
136 fbinfo
.height
= _fb
->height
;
137 fbinfo
.stride
= _fb
->stride
;
138 fbinfo
.offset_x
= _fb
->offset_x
;
139 fbinfo
.offset_y
= _fb
->offset_y
;
145 entrypoint_fn(lsnes_core_func_t _fn
) : fn(_fn
) {}
146 template<typename T
> bool operator()(unsigned item
, T
& args
,
147 std::function
<void(const char* callname
, const char* err
)> onerror
)
149 const char* err
= NULL
;
150 int r
= fn(ccore_call_param_map
<T
>::id
, item
, &args
, &err
);
152 onerror(ccore_call_param_map
<T
>::name
, err
);
155 template<typename T
> bool operator()(unsigned item
, T
& args
)
157 return (*this)(item
, args
, default_error_function
);
160 lsnes_core_func_t fn
;
166 c_lib_init(entrypoint_fn _entrypoint
)
167 : entrypoint(_entrypoint
)
179 lsnes_core_deinitialize s
;
183 entrypoint_fn
get_entrypoint()
189 entrypoint_fn entrypoint
;
192 struct c_core_core_params
194 std::vector
<interface_action
> actions
;
195 std::vector
<std::string
> trace_cpus
;
196 std::vector
<portctrl::type
*> ports
;
197 const char* shortname
;
198 const char* fullname
;
201 std::map
<unsigned, core_region
*> regions
;
205 struct c_core_core
: public core_core
207 c_core_core(c_core_core_params
& p
)
208 : core_core(p
.ports
, p
.actions
), entrypoint(p
.library
->get_entrypoint()), plugin(p
.library
)
210 fullname
= p
.fullname
;
211 shortname
= p
.shortname
;
213 internal_pflag
= false;
217 trace_cpus
= p
.trace_cpus
;
218 for(size_t i
= 0; i
< p
.ports
.size(); i
++)
219 ports
[i
] = p
.ports
[i
];
221 ~c_core_core() throw();
222 std::string
c_core_identifier() const
226 bool get_av_state(lsnes_core_get_av_state
& s
)
228 return entrypoint(id
, s
);
230 std::pair
<uint32_t, uint32_t> c_video_rate()
232 lsnes_core_get_av_state s
;
233 if(!entrypoint(id
, s
))
234 return std::make_pair(60, 1);
235 return std::make_pair(s
.fps_n
, s
.fps_d
);
239 lsnes_core_get_av_state s
;
240 return entrypoint(id
, s
) ? s
.par
: 1.0;
242 std::pair
<uint32_t, uint32_t> c_audio_rate()
244 lsnes_core_get_av_state s
;
245 return entrypoint(id
, s
) ? std::make_pair(s
.rate_n
, s
.rate_d
) : std::make_pair(48000U, 1U);
249 lsnes_core_poweron s
;
250 if(caps1
& LSNES_CORE_CAP1_POWERON
) entrypoint(id
, s
);
252 void c_unload_cartridge()
254 lsnes_core_unload_cartridge s
;
255 if(caps1
& LSNES_CORE_CAP1_UNLOAD
) entrypoint(id
, s
);
259 lsnes_core_runtosave s
;
260 if(caps1
& LSNES_CORE_CAP1_RUNTOSAVE
) entrypoint(id
, s
);
265 lsnes_core_emulate s
;
271 lsnes_core_get_pflag s
;
272 if(!(caps1
& LSNES_CORE_CAP1_PFLAG
) || !entrypoint(id
, s
))
273 return internal_pflag
;
274 return (s
.pflag
!= 0);
276 void c_set_pflag(bool pflag
)
278 lsnes_core_set_pflag s
;
279 s
.pflag
= pflag
? 1 : 0;
280 if(!(caps1
& LSNES_CORE_CAP1_PFLAG
) || !entrypoint(id
, s
))
281 internal_pflag
= pflag
;
283 std::string
c_get_core_shortname() const
289 lsnes_core_debug_reset s
;
290 if(caps1
& (LSNES_CORE_CAP1_DEBUG
| LSNES_CORE_CAP1_TRACE
| LSNES_CORE_CAP1_CHEAT
))
293 std::pair
<unsigned, unsigned> c_lightgun_scale()
295 lsnes_core_get_av_state s
;
296 if(!(caps1
& LSNES_CORE_CAP1_LIGHTGUN
) || !entrypoint(id
, s
))
297 return std::make_pair(0, 0);
298 return std::make_pair(s
.lightgun_width
, s
.lightgun_height
);
300 std::pair
<uint64_t, uint64_t> c_get_bus_map()
302 lsnes_core_get_bus_mapping s
;
303 if(!(caps1
& LSNES_CORE_CAP1_BUSMAP
) || !entrypoint(id
, s
))
304 return std::make_pair(0, 0);
305 return std::make_pair(s
.base
, s
.size
);
307 int c_reset_action(bool hard
)
309 lsnes_core_get_reset_action s
;
310 if(!(caps1
& LSNES_CORE_CAP1_RESET
) || !entrypoint(id
, s
))
312 return hard
? s
.hardreset
: s
.softreset
;
314 std::pair
<uint32_t, uint32_t> c_get_scale_factors(uint32_t width
, uint32_t height
)
316 lsnes_core_compute_scale s
;
317 uint32_t hscale
, vscale
;
318 if(width
>= 360) hscale
= 1;
319 else hscale
= 360 / width
+ 1;
320 if(height
>= 320) vscale
= 1;
321 else vscale
= 320 / height
+ 1;
322 if(caps1
& LSNES_CORE_CAP1_SCALE
) {
325 if(entrypoint(id
, s
)) {
330 return std::make_pair(hscale
, vscale
);
332 void c_pre_emulate_frame(portctrl::frame
& cf
)
334 lsnes_core_pre_emulate s
;
335 if(caps1
& LSNES_CORE_CAP1_PREEMULATE
) {
337 s
.set_input
= [](void* context
, unsigned port
, unsigned controller
, unsigned index
,
338 short value
) -> void {
339 portctrl::frame
& cf
= *(portctrl::frame
*)context
;
340 cf
.axis3(port
, controller
, index
, value
);
345 std::set
<std::string
> c_srams()
347 lsnes_core_enumerate_sram s
;
348 std::set
<std::string
> ret
;
349 if(caps1
& LSNES_CORE_CAP1_SRAM
) {
350 if(entrypoint(id
, s
)) {
351 const char** sr
= s
.srams
;
360 void c_load_sram(std::map
<std::string
, std::vector
<char>>& sram
) throw(std::bad_alloc
)
362 lsnes_core_load_sram s
;
363 if(caps1
& LSNES_CORE_CAP1_SRAM
) {
364 std::vector
<lsnes_core_sram
> srams
;
365 std::vector
<lsnes_core_sram
*> sramsp
;
366 std::vector
<char> names
;
367 srams
.resize(sram
.size() + 1);
368 srams
[sram
.size()].name
= NULL
;
372 nlength
+= i
.first
.length() + 1;
373 names
.resize(nlength
);
375 for(auto& i
: sram
) {
377 std::copy(i
.first
.begin(), i
.first
.end(), names
.begin() + nidx
);
378 nidx
+= i
.first
.length();
379 names
[nidx
++] = '\0';
380 srams
[idx
].size
= i
.second
.size();
381 srams
[idx
].data
= &i
.second
[0];
382 srams
[idx
].name
= &names
[ntmp
];
389 std::map
<std::string
, std::vector
<char>> c_save_sram() throw(std::bad_alloc
)
391 lsnes_core_save_sram s
;
392 std::map
<std::string
, std::vector
<char>> ret
;
393 if(caps1
& LSNES_CORE_CAP1_SRAM
) {
394 if(entrypoint(id
, s
)) {
395 lsnes_core_sram
* p
= s
.srams
;
397 ret
[p
->name
].resize(p
->size
);
398 memcpy(&ret
[p
->name
][0], p
->data
, p
->size
);
405 void c_unserialize(const char* in
, size_t insize
)
407 lsnes_core_loadstate s
;
410 entrypoint(id
, s
, [](const char* name
, const char* err
) {
411 throw std::runtime_error("Loadstate failed: " + std::string(err
));
414 void c_serialize(std::vector
<char>& out
)
416 lsnes_core_savestate s
;
417 entrypoint(id
, s
, [](const char* name
, const char* err
) {
418 throw std::runtime_error("Savestate failed: " + std::string(err
));
421 memcpy(&out
[0], s
.data
, s
.size
);
423 unsigned c_action_flags(unsigned _id
)
425 lsnes_core_get_action_flags s
;
426 if(caps1
& LSNES_CORE_CAP1_ACTION
) {
428 return entrypoint(id
, s
) ? s
.flags
: 0;
432 std::vector
<std::string
> c_get_trace_cpus()
436 bool c_set_region(core_region
& region
)
438 lsnes_core_set_region s
;
439 if(caps1
& LSNES_CORE_CAP1_MULTIREGION
) {
441 for(auto i
: regions
)
442 if(i
.second
== ®ion
) {
447 return false; //Bad region.
448 return entrypoint(id
, s
);
450 return (regions
.count(0) && regions
[0] == ®ion
);
453 core_region
& c_get_region()
455 lsnes_core_get_region s
;
456 if(caps1
& LSNES_CORE_CAP1_MULTIREGION
) {
457 if(!entrypoint(id
, s
)) {
459 throw std::runtime_error("No valid regions");
460 return *(regions
.begin()->second
);
462 if(regions
.count(s
.region
))
463 return *regions
[s
.region
];
464 messages
<< "Internal error: Core gave invalid region number."
467 throw std::runtime_error("No valid regions");
468 return *(regions
.begin()->second
);
474 messages
<< "Internal error: Not multi-region core and region 0 not present."
477 throw std::runtime_error("No valid regions");
478 return *(regions
.begin()->second
);
482 const struct interface_device_reg
* c_get_registers()
484 static std::vector
<interface_device_reg
> regs
;
485 static std::vector
<char> namebuf
;
486 static interface_device_reg reg_null
= {NULL
};
487 lsnes_core_get_device_regs s
;
488 if(caps1
& LSNES_CORE_CAP1_REGISTERS
) {
489 if(!entrypoint(id
, s
)) {
496 namelen
+= strlen(tregs
->name
) + 1;
501 if(regs
.size() < count
+ 1)
502 regs
.resize(count
+ 1);
503 if(namelen
> namebuf
.size())
504 namebuf
.resize(namelen
);
508 strcpy(&namebuf
[nameptr
], tregs
->name
);
509 regs
[idx
].name
= &namebuf
[nameptr
];
510 regs
[idx
].read
= tregs
->read
;
511 regs
[idx
].write
= tregs
->write
;
512 regs
[idx
].boolean
= tregs
->boolean
;
513 nameptr
+= strlen(tregs
->name
) + 1;
517 regs
[idx
].name
= NULL
; //The sentinel.
524 void c_install_handler()
526 plugin
->initialize();
528 void c_uninstall_handler()
530 plugin
->deinitialize();
532 void c_set_debug_flags(uint64_t addr
, unsigned flags_set
, unsigned flags_clear
)
534 lsnes_core_set_debug_flags s
;
537 s
.clear
= flags_clear
;
538 if(caps1
& LSNES_CORE_CAP1_DEBUG
)
541 messages
<< "Debugging functions not supported by core" << std::endl
;
543 void c_set_cheat(uint64_t addr
, uint64_t value
, bool set
)
545 lsnes_core_set_cheat s
;
549 if(caps1
& LSNES_CORE_CAP1_CHEAT
)
552 messages
<< "Cheat functions not supported by core" << std::endl
;
554 void c_execute_action(unsigned aid
, const std::vector
<interface_action_paramval
>& p
)
556 if(!(caps1
& LSNES_CORE_CAP1_ACTION
)) {
557 messages
<< "Core does not support actions." << std::endl
;
560 interface_action
* act
= NULL
;
561 for(auto& i
: actions
) {
568 messages
<< "Unknown action id #" << aid
<< std::endl
;
572 std::vector
<lsnes_core_execute_action_param
> parameters
;
573 std::list
<std::vector
<char>> strtmp
;
574 for(auto& b
: act
->params
) {
575 std::string m
= b
.model
;
578 lsnes_core_execute_action_param tp
;
579 tp
.boolean
= p
[j
++].b
;
580 parameters
.push_back(tp
);
581 } else if(regex_match("int:.*", m
)) {
583 lsnes_core_execute_action_param tp
;
584 tp
.integer
= p
[j
++].i
;
585 parameters
.push_back(tp
);
586 } else if(regex_match("string(:.*)?", m
) || regex_match("enum:.*", m
)) {
588 strtmp
.push_back(std::vector
<char>());
589 auto& i
= strtmp
.back();
590 i
.resize(p
[j
].s
.length() + 1);
591 std::copy(p
[j
].s
.begin(), p
[j
].s
.end(), i
.begin());
592 lsnes_core_execute_action_param tp
;
593 tp
.string
.base
= &i
[0];
594 tp
.string
.length
= p
[j
++].s
.length();
595 parameters
.push_back(tp
);
596 } else if(m
== "toggle") {
599 messages
<< "Unknown model '" << m
<< "' in action id #" << aid
<< std::endl
;
603 lsnes_core_execute_action s
;
605 s
.params
= ¶meters
[0];
608 framebuffer::raw
& c_draw_cover()
610 lsnes_core_draw_cover r
;
611 if(caps1
& LSNES_CORE_CAP1_COVER
) {
612 if(!entrypoint(id
, r
))
614 framebuffer::info fbinfo
= translate_info(r
.coverpage
);
615 size_t needed
= fbinfo
.physwidth
* fbinfo
.physheight
* fbinfo
.type
->get_bpp();
616 if(covermem
.size() < needed
) covermem
.resize(needed
);
617 memcpy(&covermem
[0], fbinfo
.mem
, needed
);
618 fbinfo
.mem
= &covermem
[0];
619 cover
= framebuffer::raw(fbinfo
);
623 if(covermem
.size() < 1024) covermem
.resize(1024);
624 framebuffer::info fbi
;
625 fbi
.type
= &framebuffer::pixfmt_rgb16
;
626 fbi
.mem
= &covermem
[0];
628 fbi
.physheight
= 448;
635 cover
= framebuffer::raw(fbi
);
638 std::list
<core_vma_info
> c_vma_list()
640 lsnes_core_get_vma_list r
;
641 if(caps1
& LSNES_CORE_CAP1_MEMWATCH
) {
642 if(!entrypoint(id
, r
))
644 std::list
<core_vma_info
> vmalist
;
645 for(lsnes_core_get_vma_list_vma
** vmas
= r
.vmas
; *vmas
; vmas
++) {
646 lsnes_core_get_vma_list_vma
* vma
= *vmas
;
648 _vma
.name
= vma
->name
;
649 _vma
.base
= vma
->base
;
650 _vma
.size
= vma
->size
;
651 _vma
.endian
= vma
->endian
;
652 _vma
.readonly
= ((vma
->flags
& LSNES_CORE_VMA_READONLY
) != 0);
653 _vma
.special
= ((vma
->flags
& LSNES_CORE_VMA_SPECIAL
) != 0);
654 _vma
.volatile_flag
= ((vma
->flags
& LSNES_CORE_VMA_VOLATILE
) != 0);
655 _vma
.backing_ram
= vma
->direct_map
;
656 _vma
.read
= vma
->read
;
657 _vma
.write
= vma
->write
;
658 vmalist
.push_back(_vma
);
663 return std::list
<core_vma_info
>();
665 void c_reset_to_load()
668 if(caps1
& LSNES_CORE_CAP1_REINIT
) {
669 entrypoint(id
, r
, [](const char* name
, const char* err
) {
670 throw std::runtime_error("Resetting state failed: " + std::string(err
));
674 //Emulate by loadstate.
675 c_unserialize(&init_savestate
[0], init_savestate
.size());
677 std::map
<unsigned, portctrl::type
*> get_ports()
681 void set_internal_pflag()
683 internal_pflag
= true;
685 void update_initial_savestate()
687 if((caps1
& LSNES_CORE_CAP1_REINIT
) == 0)
688 c_serialize(init_savestate
);
691 std::string fullname
;
692 std::string shortname
;
696 std::vector
<std::string
> trace_cpus
;
697 std::map
<unsigned, portctrl::type
*> ports
;
698 std::map
<unsigned, core_region
*> regions
;
699 std::vector
<interface_action
> actions
;
700 framebuffer::raw cover
;
701 std::vector
<char> covermem
;
702 std::vector
<char> init_savestate
;
703 entrypoint_fn entrypoint
;
707 c_core_core::~c_core_core() throw()
711 struct c_core_type
: public core_type
713 c_core_type(c_lib_init
& lib
, core_type_params
& p
, std::map
<unsigned, portctrl::type
*> _ports
,
714 unsigned _rcount
, unsigned _id
)
715 : core_type(p
), ports(_ports
), entrypoint(lib
.get_entrypoint()), rcount(_rcount
), id(_id
)
718 ~c_core_type() throw()
721 int t_load_rom(core_romimage
* images
, std::map
<std::string
, std::string
>& settings
, uint64_t rtc_sec
,
724 lsnes_core_load_rom r
;
725 std::vector
<char> tmpmem
;
726 std::vector
<lsnes_core_system_setting
> tmpmem2
;
728 r
.rtc_subsec
= rtc_subsec
;
729 copy_settings(tmpmem
, tmpmem2
, settings
);
730 r
.settings
= &tmpmem2
[0];
732 std::vector
<lsnes_core_load_rom_image
> imgs
;
734 for(unsigned i
= 0; i
< rcount
; i
++) {
735 imgs
[i
].data
= (const char*)images
[i
].data
;
736 imgs
[i
].size
= images
[i
].size
;
737 imgs
[i
].markup
= images
[i
].markup
;
741 entrypoint(_id
, r
, [_id
](const char* name
, const char* err
) {
742 (stringfmt() << "LSNES_CORE_LOAD_ROM(" << _id
<< ") failed: " << err
).throwex();
744 dynamic_cast<c_core_core
*>(get_core())->update_initial_savestate();
747 controller_set
t_controllerconfig(std::map
<std::string
, std::string
>& settings
)
749 lsnes_core_get_controllerconfig r
;
750 std::vector
<char> tmpmem
;
751 std::vector
<lsnes_core_system_setting
> tmpmem2
;
752 copy_settings(tmpmem
, tmpmem2
, settings
);
753 r
.settings
= &tmpmem2
[0];
755 entrypoint(_id
, r
, [_id
](const char* name
, const char* err
) {
756 (stringfmt() << "LSNES_CORE_GET_CONTROLLERCONFIG(" << _id
<< ") failed: "
760 for(unsigned* pt
= r
.controller_types
; *pt
!= 0xFFFFFFFFU
; pt
++) {
762 if(!ports
.count(_pt
))
763 throw std::runtime_error("Illegal port type selected by core");
764 portctrl::type
* pt2
= ports
[_pt
];
765 cset
.ports
.push_back(pt2
);
767 for(lsnes_core_get_controllerconfig_logical_entry
* le
= r
.logical_map
;
768 le
->port
| le
->controller
; le
++) {
769 cset
.logical_map
.push_back(std::make_pair(le
->port
, le
->controller
));
774 void copy_settings(std::vector
<char>& tmpmem
, std::vector
<lsnes_core_system_setting
>& tmpmem2
,
775 std::map
<std::string
, std::string
>& settings
)
778 for(auto i
: settings
)
779 asize
+= i
.first
.length() + i
.second
.length() + 2;
780 tmpmem
.resize(asize
);
782 for(auto i
: settings
) {
783 lsnes_core_system_setting s
;
784 std::copy(i
.first
.begin(), i
.first
.end(), tmpmem
.begin() + asize
);
785 s
.name
= &tmpmem
[asize
];
786 asize
+= i
.first
.length();
788 std::copy(i
.second
.begin(), i
.second
.end(), tmpmem
.begin() + asize
);
789 s
.value
= &tmpmem
[asize
];
790 asize
+= i
.second
.length();
792 tmpmem2
.push_back(s
);
794 lsnes_core_system_setting s
;
797 tmpmem2
.push_back(s
);
799 std::map
<unsigned, portctrl::type
*> ports
;
800 entrypoint_fn entrypoint
;
805 std::vector
<char> msgbuf
;
807 void callback_message(const char* msg
, size_t length
)
809 std::string
_msg(msg
, msg
+ length
);
810 messages
<< _msg
<< std::endl
;
813 short callback_get_input(unsigned port
, unsigned index
, unsigned control
)
815 short v
= ecore_callbacks
->get_input(port
, index
, control
);
816 if(current_core
&& (port
|| index
|| v
))
817 current_core
->set_internal_pflag();
821 void callback_notify_action_update()
823 ecore_callbacks
->action_state_updated();
826 void callback_timer_tick(uint32_t increment
, uint32_t per_second
)
828 ecore_callbacks
->timer_tick(increment
, per_second
);
831 const char* callback_get_firmware_path()
833 std::string fwp
= ecore_callbacks
->get_firmware_path();
834 msgbuf
.resize(fwp
.length() + 1);
835 std::copy(fwp
.begin(), fwp
.end(), msgbuf
.begin());
836 msgbuf
[fwp
.length()] = 0;
840 const char* callback_get_base_path()
842 std::string fwp
= ecore_callbacks
->get_base_path();
843 msgbuf
.resize(fwp
.length() + 1);
844 std::copy(fwp
.begin(), fwp
.end(), msgbuf
.begin());
845 msgbuf
[fwp
.length()] = 0;
849 time_t callback_get_time()
851 return ecore_callbacks
->get_time();
854 time_t callback_get_randomseed()
856 return ecore_callbacks
->get_randomseed();
859 void callback_memory_read(uint64_t addr
, uint64_t value
)
861 ecore_callbacks
->memory_read(addr
, value
);
864 void callback_memory_write(uint64_t addr
, uint64_t value
)
866 ecore_callbacks
->memory_write(addr
, value
);
869 void callback_memory_execute(uint64_t addr
, uint64_t cpunum
)
871 ecore_callbacks
->memory_execute(addr
, cpunum
);
874 void callback_memory_trace(uint64_t proc
, const char* str
, int insn
)
876 ecore_callbacks
->memory_trace(proc
, str
, insn
);
879 void callback_submit_sound(const int16_t* samples
, size_t count
, int stereo
, double rate
)
881 CORE().audio
->submit_buffer((int16_t*)samples
, count
, stereo
, rate
);
884 void callback_notify_latch(const char** params
)
886 std::list
<std::string
> ps
;
888 for(const char** p
= params
; *p
; p
++)
890 ecore_callbacks
->notify_latch(ps
);
893 void callback_submit_frame(struct lsnes_core_framebuffer_info
* _fb
, uint32_t fps_n
, uint32_t fps_d
)
895 framebuffer::info fbinfo
= translate_info(_fb
);
896 framebuffer::raw
fb(fbinfo
);
897 ecore_callbacks
->output_frame(fb
, fps_n
, fps_d
);
902 std::function
<unsigned char()> fn
;
903 static unsigned char call(void* ctx
)
905 return reinterpret_cast<fpcfn
*>(ctx
)->fn();
909 class ccore_disasm
: public disassembler
912 ccore_disasm(struct lsnes_core_disassembler
* disasm
)
913 : disassembler(disasm
->name
)
920 std::string
disassemble(uint64_t base
, std::function
<unsigned char()> fetchpc
)
924 const char* out
= fn(base
, fpcfn::call
, &y
);
928 const char* (*fn
)(uint64_t base
, unsigned char(*fetch
)(void* ctx
), void* ctx
);
931 void* callback_add_disasm(struct lsnes_core_disassembler
* disasm
)
933 return new ccore_disasm(disasm
);
936 void callback_remove_disasm(void* handle
)
938 delete reinterpret_cast<ccore_disasm
*>(handle
);
941 struct utf8_strlen_iter
943 utf8_strlen_iter() { str_len
= 0; }
944 utf8_strlen_iter
& operator++() { str_len
++; return *this; }
945 uint32_t& operator*() { return dummy
; }
951 void callback_render_text2(struct lsnes_core_fontrender_req
& req
, const std::string
& str
)
953 auto size
= main_font
.get_metrics(str
);
954 auto layout
= main_font
.dolayout(str
);
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 for(auto i
: layout
) {
968 T
* _bmp
= bmp
+ (i
.y
* size
.first
+ i
.x
);
969 size_t w
= g
.wide
? 16 : 8;
970 size_t skip
= size
.first
- w
;
971 for(size_t _y
= 0; _y
< 16; _y
++) {
972 uint32_t d
= g
.data
[_y
>> (g
.wide
? 1 : 2)];
974 d
>>= 16 - ((_y
& 1) << 4);
976 d
>>= 24 - ((_y
& 3) << 3);
977 for(size_t _x
= 0; _x
< w
; _x
++, _bmp
++) {
978 uint32_t b
= w
- _x
- 1;
979 *_bmp
= ((d
>> b
) & 1) ? fg
: bg
;
984 req
.width
= size
.first
;
985 req
.height
= size
.second
;
988 void callback_render_text1(struct lsnes_core_fontrender_req
& req
, const std::string
& str
)
990 switch(req
.bytes_pp
) {
992 callback_render_text2
<uint8_t>(req
, str
);
995 callback_render_text2
<uint16_t>(req
, str
);
998 callback_render_text2
<ss_uint24_t
>(req
, str
);
1001 callback_render_text2
<uint32_t>(req
, str
);
1004 throw std::runtime_error("Invalid req.bytes_pp");
1008 int callback_render_text(struct lsnes_core_fontrender_req
* req
)
1011 //If indeterminate length, make it determinate.
1012 if(req
->text_len
< 0)
1013 req
->text_len
= strlen(req
->text
);
1014 const char* text_start
= req
->text
;
1015 const char* text_end
= req
->text
+ req
->text_len
;
1017 std::string
str(text_start
, text_end
);
1018 callback_render_text1(*req
, str
);
1025 core_sysregion
* create_sysregion(entrypoint_fn
& entrypoint
, std::map
<unsigned, core_region
*>& regions
,
1026 std::map
<unsigned, c_core_type
*>& types
, unsigned sysreg
)
1028 struct lsnes_core_get_sysregion_info r
;
1029 entrypoint(sysreg
, r
, [sysreg
](const char* name
, const char* err
) {
1030 (stringfmt() << "LSNES_CORE_GET_SYSREGION_INFO(" << sysreg
<< ") failed: " << err
).throwex();
1032 register_sysregion_mapping(r
.name
, r
.for_system
);
1033 if(!types
.count(r
.type
))
1034 throw std::runtime_error("create_sysregion: Unknown type");
1035 if(!regions
.count(r
.region
))
1036 throw std::runtime_error("create_sysregion: Unknown region");
1037 return new core_sysregion(r
.name
, *types
[r
.type
], *regions
[r
.region
]);
1040 core_region
* create_region(entrypoint_fn
& entrypoint
, unsigned region
)
1042 struct lsnes_core_get_region_info r
;
1043 entrypoint(region
, r
, [region
](const char* name
, const char* err
) {
1044 (stringfmt() << "LSNES_CORE_GET_REGION_INFO(" << region
<< ") failed: " << err
).throwex();
1046 core_region_params p
;
1049 p
.priority
= r
.priority
;
1052 p
.framemagic
[0] = r
.fps_n
;
1053 p
.framemagic
[1] = r
.fps_d
;
1054 for(size_t i
= 0; r
.compatible_runs
[i
] != 0xFFFFFFFFU
; i
++)
1055 p
.compatible_runs
.push_back(r
.compatible_runs
[i
]);
1056 return new core_region(p
);
1059 c_core_core
* create_core(c_lib_init
& lib
, entrypoint_fn
& entrypoint
,
1060 std::map
<unsigned, core_region
*>& regions
, unsigned core
)
1062 c_core_core_params p
;
1063 struct lsnes_core_get_core_info r
;
1064 entrypoint(core
, r
, [core
](const char* name
, const char* err
) {
1065 (stringfmt() << "LSNES_CORE_GET_CORE_INFO(" << core
<< ") failed: " << err
).throwex();
1068 JSON::node
root(r
.json
);
1069 JSON::pointer
rootptr(r
.root_ptr
);
1070 size_t count
= root
[rootptr
].index_count();
1071 for(size_t i
= 0; i
< count
; i
++) {
1072 JSON::pointer j
= rootptr
.index(i
);
1073 p
.ports
.push_back(new portctrl::type_generic(root
, j
.as_string8()));
1076 if(r
.cap_flags1
& LSNES_CORE_CAP1_ACTION
) {
1077 for(lsnes_core_get_core_info_action
* i
= r
.actions
; i
->iname
; i
++) {
1080 a
._symbol
= i
->iname
;
1081 a
._title
= i
->hname
;
1084 for(lsnes_core_get_core_info_aparam
* k
= i
->parameters
; k
->name
; k
++) {
1085 interface_action_param b
;
1086 b
.name
= strduplicate(k
->name
);
1087 b
.model
= strduplicate(k
->model
);
1088 a
.params
.push_back(b
);
1091 p
.actions
.push_back(a
);
1095 if(r
.cap_flags1
& LSNES_CORE_CAP1_TRACE
) {
1096 for(const char** i
= r
.trace_cpu_list
; *i
; i
++) {
1097 p
.trace_cpus
.push_back(*i
);
1100 for(auto & j
: regions
)
1101 p
.regions
[j
.first
] = j
.second
;
1102 p
.shortname
= r
.shortname
;
1103 p
.fullname
= r
.fullname
;
1104 p
.flags
= r
.cap_flags1
;
1107 return new c_core_core(p
);
1110 c_core_type
* create_type(c_lib_init
& lib
, entrypoint_fn
& entrypoint
, std::map
<unsigned, c_core_core
*>& cores
,
1111 std::map
<unsigned, core_region
*>& regions
, unsigned type
)
1113 std::vector
<core_romimage_info_params
> rlist
;
1114 std::vector
<core_setting_param
> plist
;
1116 struct lsnes_core_get_type_info r
;
1117 entrypoint(type
, r
, [type
](const char* name
, const char* err
) {
1118 (stringfmt() << "LSNES_CORE_GET_TYPE_INFO(" << type
<< ") failed: " << err
).throwex();
1121 for(lsnes_core_get_type_info_param
* param
= r
.settings
; param
->iname
; param
++) {
1122 core_setting_param _pr
;
1123 _pr
.iname
= strduplicate(param
->iname
);
1124 _pr
.hname
= strduplicate(param
->hname
);
1125 _pr
.dflt
= strduplicate(param
->dflt
);
1126 _pr
.regex
= strduplicate(param
->regex
);
1129 for(lsnes_core_get_type_info_paramval
* pval
= param
->values
; pval
->iname
; pval
++) {
1130 core_setting_value_param pv
;
1131 pv
.iname
= strduplicate(pval
->iname
);
1132 pv
.hname
= strduplicate(pval
->hname
);
1133 pv
.index
= pval
->index
;
1134 _pr
.values
.push_back(pv
);
1137 plist
.push_back(_pr
);
1140 unsigned rcount
= 0;
1142 for(lsnes_core_get_type_info_romimage
* rimg
= r
.images
; rimg
->iname
; rimg
++) {
1143 core_romimage_info_params rp
;
1144 rp
.iname
= rimg
->iname
;
1145 rp
.hname
= rimg
->hname
;
1146 rp
.mandatory
= rimg
->mandatory
;
1147 rp
.pass_mode
= rimg
->pass_mode
;
1148 rp
.headersize
= rimg
->headersize
;
1149 rp
.extensions
= rimg
->extensions
;
1150 rlist
.push_back(rp
);
1154 unsigned _core
= r
.core
;
1158 p
.sysname
= r
.sysname
;
1162 if(!cores
.count(_core
))
1163 throw std::runtime_error("create_type: Unknown core");
1164 p
.core
= cores
[_core
];
1165 for(unsigned* reg
= r
.regions
; *reg
!= 0xFFFFFFFFU
; reg
++) {
1166 if(!regions
.count(*reg
))
1167 throw std::runtime_error("create_type: Unknown region");
1168 p
.regions
.push_back(regions
[*reg
]);
1170 return new c_core_type(lib
, p
, cores
[_core
]->get_ports(), rcount
, type
);
1173 std::map
<const void*, std::list
<core_sysregion
*>> bylib_sysregion
;
1174 std::map
<const void*, std::list
<core_region
*>> bylib_region
;
1175 std::map
<const void*, std::list
<core_type
*>> bylib_type
;
1176 std::map
<const void*, std::list
<core_core
*>> bylib_core
;
1177 std::map
<const void*, c_lib_init
*> bylib_init
;
1179 void initialize_core2(entrypoint_fn fn
, std::map
<unsigned, core_sysregion
*>& sysregs
,
1180 std::map
<unsigned, core_region
*>& regions
, std::map
<unsigned, c_core_type
*>& types
,
1181 std::map
<unsigned, c_core_core
*>& cores
, const void* mod_id
)
1183 c_lib_init
& lib
= *new c_lib_init(fn
);
1184 for(auto& i
: regions
)
1185 i
.second
= create_region(fn
, i
.first
);
1186 for(auto& i
: cores
)
1187 i
.second
= create_core(lib
, fn
, regions
, i
.first
);
1188 for(auto& i
: types
)
1189 i
.second
= create_type(lib
, fn
, cores
, regions
, i
.first
);
1190 for(auto& i
: sysregs
)
1191 i
.second
= create_sysregion(fn
, regions
, types
, i
.first
);
1194 for(auto& i
: sysregs
) bylib_sysregion
[mod_id
].push_back(i
.second
);
1195 for(auto& i
: regions
) bylib_region
[mod_id
].push_back(i
.second
);
1196 for(auto& i
: types
) bylib_type
[mod_id
].push_back(i
.second
);
1197 for(auto& i
: cores
) bylib_core
[mod_id
].push_back(i
.second
);
1198 bylib_init
[mod_id
] = &lib
;
1200 //We don't call install_handler, because that is done automatically.
1203 void initialize_core(lsnes_core_func_t fn
, const void* mod_id
)
1205 //Enumerate what the thing supports.
1206 entrypoint_fn
entrypoint(fn
);
1207 lsnes_core_enumerate_cores r
;
1209 r
.message
= callback_message
;
1210 r
.get_input
= callback_get_input
;
1211 r
.notify_action_update
= callback_notify_action_update
;
1212 r
.timer_tick
= callback_timer_tick
;
1213 r
.get_firmware_path
= callback_get_firmware_path
;
1214 r
.get_base_path
= callback_get_base_path
;
1215 r
.get_time
= callback_get_time
;
1216 r
.get_randomseed
= callback_get_randomseed
;
1217 r
.memory_read
= callback_memory_read
;
1218 r
.memory_write
= callback_memory_write
;
1219 r
.memory_execute
= callback_memory_execute
;
1220 r
.memory_trace
= callback_memory_trace
;
1221 r
.submit_sound
= callback_submit_sound
;
1222 r
.notify_latch
= callback_notify_latch
;
1223 r
.submit_frame
= callback_submit_frame
;
1224 r
.add_disasm
= callback_add_disasm
;
1225 r
.remove_disasm
= callback_remove_disasm
;
1226 r
.render_text
= callback_render_text
;
1227 entrypoint(0, r
, [](const char* name
, const char* err
) {
1228 (stringfmt() << "LSNES_CORE_ENUMERATE_CORES(0) failed: " << err
).throwex();
1230 //Collect sysregions, types and cores.
1231 std::map
<unsigned, core_region
*> regions
;
1232 std::map
<unsigned, core_sysregion
*> sysregs
;
1233 std::map
<unsigned, c_core_type
*> types
;
1234 std::map
<unsigned, c_core_core
*> cores
;
1235 for(size_t i
= 0; r
.sysregions
[i
] != 0xFFFFFFFFU
; i
++) {
1236 unsigned sysreg
= r
.sysregions
[i
];
1237 sysregs
.insert(std::make_pair(sysreg
, nullptr));
1238 struct lsnes_core_get_sysregion_info r2
;
1239 entrypoint(sysreg
, r2
, [sysreg
](const char* name
, const char* err
) {
1240 (stringfmt() << "LSNES_CORE_GET_SYSREGION_INFO(" << sysreg
<< ") failed: "
1243 unsigned type
= r2
.type
;
1244 types
.insert(std::make_pair(type
, nullptr));
1245 struct lsnes_core_get_type_info r3
;
1246 entrypoint(type
, r3
, [type
](const char* name
, const char* err
) {
1247 (stringfmt() << "LSNES_CORE_GET_TYPE_INFO(" << type
<< ") failed: "
1250 cores
.insert(std::make_pair(r3
.core
, nullptr));
1251 for(size_t j
= 0; r3
.regions
[j
] != 0xFFFFFFFFU
; j
++) {
1252 regions
.insert(std::make_pair(r3
.regions
[j
], nullptr));
1256 initialize_core2(entrypoint
, sysregs
, regions
, types
, cores
, mod_id
);
1259 template<typename T
> void cleanup_list(std::map
<const void*, std::list
<T
*>>& list
, const void* handle
)
1261 if(!list
.count(handle
))
1263 for(auto i
: list
[handle
])
1268 template<typename T
> void cleanup_entry(std::map
<const void*, T
*>& list
, const void* handle
)
1270 if(!list
.count(handle
))
1272 delete list
[handle
];
1278 void lsnes_register_builtin_core(lsnes_core_func_t fn
)
1280 corequeue().push_back(fn
);
1283 void try_init_c_module(const loadlib::module
& module
)
1286 lsnes_core_func_t fn
= module
.fn
<int, unsigned, unsigned, void*,
1287 const char**>("lsnes_core_entrypoint");
1288 initialize_core(fn
, &module
);
1289 } catch(std::exception
& e
) {
1290 messages
<< "Can't initialize core: " << e
.what() << std::endl
;
1294 void try_uninit_c_module(const loadlib::module
& module
)
1296 if(bylib_core
.count(&module
))
1297 for(auto i
: bylib_core
[&module
])
1298 i
->uninstall_handler();
1299 cleanup_list(bylib_sysregion
, &module
);
1300 cleanup_list(bylib_region
, &module
);
1301 cleanup_list(bylib_type
, &module
);
1302 cleanup_list(bylib_core
, &module
);
1303 cleanup_entry(bylib_init
, &module
);
1306 bool core_uses_module(core_core
* core
, const loadlib::module
& module
)
1308 if(!bylib_core
.count(&module
))
1310 for(auto i
: bylib_core
[&module
])
1316 void initialize_all_builtin_c_cores()
1318 while(!corequeue().empty()) {
1319 lsnes_core_func_t fn
= corequeue().front();
1320 corequeue().pop_front();
1322 initialize_core(fn
, NULL
);
1323 } catch(std::exception
& e
) {
1324 messages
<< "Can't initialize core: " << e
.what() << std::endl
;