C interface WIP
This commit is contained in:
parent
3f14664f0c
commit
8e6d005f15
3 changed files with 1272 additions and 0 deletions
801
include/interface/c-interface.h
Normal file
801
include/interface/c-interface.h
Normal file
|
@ -0,0 +1,801 @@
|
||||||
|
#ifndef _interface__c_interface__h__included__
|
||||||
|
#define _interface__c_interface__h__included__
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2013 Ilari Liusvaara
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some general information about the interface:
|
||||||
|
* - The parameter type for LSNES_CORE_FOO is struct lsnes_core_foo*
|
||||||
|
* - There are also some other enumerations/structures.
|
||||||
|
* - The only exposed entry point has fp type of lsnes_core_func_t.
|
||||||
|
* - By nature, this interface does not reference any symbols (exception is lsnes_register_builtin_core).
|
||||||
|
* - Some fields may be conditional on API version.
|
||||||
|
* - The following functions are required:
|
||||||
|
* * LSNES_CORE_ENUMERATE_CORES
|
||||||
|
* * LSNES_CORE_GET_CORE_INFO
|
||||||
|
* * LSNES_CORE_GET_TYPE_INFO
|
||||||
|
* * LSNES_CORE_GET_REGION_INFO
|
||||||
|
* * LSNES_CORE_GET_SYSREGION_INFO
|
||||||
|
* * LSNES_CORE_GET_AV_STATE
|
||||||
|
* * LSNES_CORE_EMULATE
|
||||||
|
* * LSNES_CORE_SAVESTATE
|
||||||
|
* * LSNES_CORE_LOADSTATE
|
||||||
|
* * LSNES_CORE_GET_CONTROLLERCONFIG
|
||||||
|
* * LSNES_CORE_LOAD_ROM
|
||||||
|
* - Scratch buffers from emulator side last for duration of the call.
|
||||||
|
* - Scratch buffers form core side last until next call.
|
||||||
|
* - Never free buffer from emulator in core or vice versa.
|
||||||
|
* - The spaces for Core, Type, Region and Sysregion IDs are distinct.
|
||||||
|
* - If you only have one region, use ID of 0 for that and GET_REGION/SET_REGION are not needed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//API version.
|
||||||
|
#define LSNES_CORE_API 0
|
||||||
|
|
||||||
|
/** Capabilities. **/
|
||||||
|
//Core supports multiple regions (By supporting LSNES_CORE_GET_REGION/LSNES_CORE_SET_REGION).
|
||||||
|
#define LSNES_CORE_CAP1_MULTIREGION 0x00000001U
|
||||||
|
//Core supports poll flags (By supporting LSNES_CORE_GET_PFLAG/LSNES_CORE_SET_PFLAG).
|
||||||
|
#define LSNES_CORE_CAP1_PFLAG 0x00000002U
|
||||||
|
//Core supports actions (By supporting LSNES_CORE_GET_ACTION_FLAGS/LSNES_CORE_EXECUTE_ACTION).
|
||||||
|
#define LSNES_CORE_CAP1_ACTION 0x00000004U
|
||||||
|
//Core supports bus map (By supporting LSNES_CORE_GET_BUS_MAPPING).
|
||||||
|
#define LSNES_CORE_CAP1_BUSMAP 0x00000008U
|
||||||
|
//Core supports SRAM (By supporting LSNES_CORE_ENUMERATE_SRAM/LSNES_CORE_LOAD_SRAM/LSNES_CORE_SAVE_SRAM).
|
||||||
|
#define LSNES_CORE_CAP1_SRAM 0x00000010U
|
||||||
|
//Core supports resets (By supporting LSNES_CORE_GET_RESET_ACTION). LSNES_CORE_CAP1_ACTION is required.
|
||||||
|
#define LSNES_CORE_CAP1_RESET 0x00000020U
|
||||||
|
//Core supports custom scale computation (By supporting LSNES_CORE_COMPUTE_SCALE).
|
||||||
|
#define LSNES_CORE_CAP1_SCALE 0x00000040U
|
||||||
|
//Core supports explicit save points (By supporting LSNES_CORE_RUNTOSAVE).
|
||||||
|
#define LSNES_CORE_CAP1_RUNTOSAVE 0x00000080U
|
||||||
|
//Core supports powerons (By supporting LSNES_CORE_POWERON).
|
||||||
|
#define LSNES_CORE_CAP1_POWERON 0x00000100U
|
||||||
|
//Core supports cartridge unload (By supporting LSNES_CORE_UNLOAD_CARTRIDGE).
|
||||||
|
#define LSNES_CORE_CAP1_UNLOAD 0x00000200U
|
||||||
|
//Core supports debugging (By supporting LSNES_CORE_DEBUG_RESET and LSNES_CORE_SET_DEBUG_FLAGS[breakpoints]).
|
||||||
|
//LSNES_CORE_CAP1_MEMWATCH is required.
|
||||||
|
#define LSNES_CORE_CAP1_DEBUG 0x00000400U
|
||||||
|
//Core supports tracing (By supporting LSNES_CORE_DEBUG_RESET and LSNES_CORE_SET_DEBUG_FLAGS[tracing]).
|
||||||
|
//LSNES_CORE_CAP1_MEMWATCH is required.
|
||||||
|
#define LSNES_CORE_CAP1_TRACE 0x00000800U
|
||||||
|
//Core supports cheating (By supporting LSNES_CORE_DEBUG_RESET and LSNES_CORE_SET_CHEAT).
|
||||||
|
//LSNES_CORE_CAP1_MEMWATCH is required.
|
||||||
|
#define LSNES_CORE_CAP1_CHEAT 0x00001000U
|
||||||
|
//Core supports cover pages (By supporting LSNES_CORE_DRAW_COVER).
|
||||||
|
#define LSNES_CORE_CAP1_COVER 0x00002000U
|
||||||
|
//Core supports pre-emulate (By supporting LSNES_CORE_PRE_EMULATE).
|
||||||
|
#define LSNES_CORE_CAP1_PREEMULATE 0x00004000U
|
||||||
|
//Core supports registers (By supporting LSNES_CORE_GET_DEVICE_REGS).
|
||||||
|
#define LSNES_CORE_CAP1_REGISTERS 0x00008000U
|
||||||
|
//Core supports memory watch (By supporting LSNES_CORE_GET_VMA_LIST).
|
||||||
|
#define LSNES_CORE_CAP1_MEMWATCH 0x00010000U
|
||||||
|
//Core supports lightguns (By setting lightgun_height/lightgun_width in LSNES_CORE_GET_AV_STATE).
|
||||||
|
#define LSNES_CORE_CAP1_LIGHTGUN 0x00020000U
|
||||||
|
//Reserved capabilities.
|
||||||
|
|
||||||
|
#define LSNES_CORE_CAP1_RESERVED18 0x00040000U
|
||||||
|
#define LSNES_CORE_CAP1_RESERVED19 0x00080000U
|
||||||
|
#define LSNES_CORE_CAP1_RESERVED20 0x00100000U
|
||||||
|
#define LSNES_CORE_CAP1_RESERVED21 0x00200000U
|
||||||
|
#define LSNES_CORE_CAP1_RESERVED22 0x00400000U
|
||||||
|
#define LSNES_CORE_CAP1_RESERVED23 0x00800000U
|
||||||
|
#define LSNES_CORE_CAP1_RESERVED24 0x01000000U
|
||||||
|
#define LSNES_CORE_CAP1_RESERVED25 0x02000000U
|
||||||
|
#define LSNES_CORE_CAP1_RESERVED26 0x04000000U
|
||||||
|
#define LSNES_CORE_CAP1_RESERVED27 0x08000000U
|
||||||
|
#define LSNES_CORE_CAP1_RESERVED28 0x10000000U
|
||||||
|
#define LSNES_CORE_CAP1_RESERVED29 0x20000000U
|
||||||
|
#define LSNES_CORE_CAP1_RESERVED30 0x40000000U
|
||||||
|
#define LSNES_CORE_CAP1_CAPS2 0x80000000U
|
||||||
|
|
||||||
|
#define LSNES_END_OF_LIST 0xFFFFFFFFU
|
||||||
|
|
||||||
|
//Do action <action> on item <item> with parameters <params>.
|
||||||
|
//If successful, return 0.
|
||||||
|
//If supported but unsuccessful, return -1 and fill <error> (will not be released, only needs to be stable to next
|
||||||
|
//call).
|
||||||
|
//In dynamic libs, this is looked up as lsnes_core_fn.
|
||||||
|
typedef int(*lsnes_core_func_t)(unsigned action, unsigned item, void* params, const char** error);
|
||||||
|
|
||||||
|
//Pixel format.
|
||||||
|
enum lsnes_core_pixel_format
|
||||||
|
{
|
||||||
|
LSNES_CORE_PIXFMT_RGB15,
|
||||||
|
LSNES_CORE_PIXFMT_BGR15,
|
||||||
|
LSNES_CORE_PIXFMT_RGB16,
|
||||||
|
LSNES_CORE_PIXFMT_BGR16,
|
||||||
|
LSNES_CORE_PIXFMT_RGB24,
|
||||||
|
LSNES_CORE_PIXFMT_BGR24,
|
||||||
|
LSNES_CORE_PIXFMT_RGB32,
|
||||||
|
LSNES_CORE_PIXFMT_LRGB
|
||||||
|
};
|
||||||
|
|
||||||
|
//Framebuffer.
|
||||||
|
struct lsnes_core_framebuffer_info
|
||||||
|
{
|
||||||
|
//Pixel format of framebuffer.
|
||||||
|
enum lsnes_core_pixel_format type;
|
||||||
|
//The physical memory backing the framebuffer.
|
||||||
|
const char* mem;
|
||||||
|
//Physical width of framebuffer.
|
||||||
|
size_t physwidth;
|
||||||
|
//Physical height of framebuffer.
|
||||||
|
size_t physheight;
|
||||||
|
//Physical stride of framebuffer (in bytes).
|
||||||
|
size_t physstride;
|
||||||
|
//Visible width of framebuffer.
|
||||||
|
size_t width;
|
||||||
|
//Visible height of framebuffer.
|
||||||
|
size_t height;
|
||||||
|
//Visible stride of framebuffer (in bytes).
|
||||||
|
size_t stride;
|
||||||
|
//Visible X offset of framebuffer.
|
||||||
|
size_t offset_x;
|
||||||
|
//Visible Y offset of framebuffer.
|
||||||
|
size_t offset_y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lsnes_core_sram
|
||||||
|
{
|
||||||
|
//Name.
|
||||||
|
const char* name;
|
||||||
|
//Content size.
|
||||||
|
size_t size;
|
||||||
|
//Data.
|
||||||
|
const char* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lsnes_core_system_setting
|
||||||
|
{
|
||||||
|
//Name.
|
||||||
|
const char* name;
|
||||||
|
//Value.
|
||||||
|
const char* value;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//Request 0: Initialize and enumerate cores.
|
||||||
|
//Item: 0.
|
||||||
|
//Default action: (required)
|
||||||
|
//Called as the first call. Do the needed initialization and return list of core IDs.
|
||||||
|
#define LSNES_CORE_ENUMERATE_CORES 0
|
||||||
|
struct lsnes_core_enumerate_cores
|
||||||
|
{
|
||||||
|
//Output: List of sysregion ids. Terminated by 0xFFFFFFFF.
|
||||||
|
unsigned* sysregions;
|
||||||
|
//Input: Emulator capability flags 1. Currently always zero.
|
||||||
|
unsigned emu_flags1;
|
||||||
|
//Input: Function to print message line.
|
||||||
|
void (*message)(const char* msg, size_t length);
|
||||||
|
//Input: Get input.
|
||||||
|
short (*get_input)(unsigned port, unsigned index, unsigned control);
|
||||||
|
//Input: Notify that state of action has updated.
|
||||||
|
void (*notify_action_update)();
|
||||||
|
//Input: Notify that time has ticked.
|
||||||
|
void (*timer_tick)(uint32_t increment, uint32_t per_second);
|
||||||
|
//Input: Get firmware path. The return value is temporary.
|
||||||
|
const char* (*get_firmware_path)();
|
||||||
|
//Input: Get cartridge base path. The return value is temporary.
|
||||||
|
const char* (*get_base_path)();
|
||||||
|
//Input: Get current time.
|
||||||
|
time_t (*get_time)();
|
||||||
|
//Input: Get random seed.
|
||||||
|
time_t (*get_randomseed)();
|
||||||
|
//Input: Notify that memory has been read.
|
||||||
|
void (*memory_read)(uint64_t addr, uint64_t value);
|
||||||
|
//Input: Notify that memory is about to be written.
|
||||||
|
void (*memory_write)(uint64_t addr, uint64_t value);
|
||||||
|
//Input: Notify that memory is about to be executed.
|
||||||
|
void (*memory_execute)(uint64_t addr, uint64_t cpunum);
|
||||||
|
//Input: Notify memory trace event. Str needs to be valid during call.
|
||||||
|
void (*memory_trace)(uint64_t proc, const char* str);
|
||||||
|
//Input: Submit sound.
|
||||||
|
void (*submit_sound)(const uint16_t* samples, size_t count, int stereo, double rate);
|
||||||
|
//Input: Notify latch event. Parameters are NULL-terminated and need to be remain during call.
|
||||||
|
void (*notify_latch)(const char** params);
|
||||||
|
//Input: Output a frame.
|
||||||
|
void (*submit_frame)(struct lsnes_core_framebuffer_info* fb, uint32_t fps_n, uint32_t fps_d);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 1: Request information about core.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: (required)
|
||||||
|
//Obtain information about core.
|
||||||
|
#define LSNES_CORE_GET_CORE_INFO 1
|
||||||
|
struct lsnes_core_get_core_info_aparam
|
||||||
|
{
|
||||||
|
//Name of the parameter.
|
||||||
|
const char* name;
|
||||||
|
//Model:
|
||||||
|
//bool: boolean
|
||||||
|
//int:<val>,<val>: Integer in specified range.
|
||||||
|
//string[:<regex>]: String with regex.
|
||||||
|
//enum:<json-array-of-strings>: Enumeration.
|
||||||
|
//toggle: Not a real parameter, boolean toggle, must be the first.
|
||||||
|
const char* model;
|
||||||
|
};
|
||||||
|
struct lsnes_core_get_core_info_action
|
||||||
|
{
|
||||||
|
//Internal name of the action.
|
||||||
|
const char* iname;
|
||||||
|
//Human-readable Name of the action
|
||||||
|
const char* hname;
|
||||||
|
//Array of parameters. Terminated by NULL pointer.
|
||||||
|
struct lsnes_core_get_core_info_aparam** parameters;
|
||||||
|
};
|
||||||
|
struct lsnes_core_get_core_info
|
||||||
|
{
|
||||||
|
//Output: The JSON text.
|
||||||
|
const char* json;
|
||||||
|
//Output: JSON pointer to root of the port array.
|
||||||
|
const char* root_ptr;
|
||||||
|
//Output: Short core name.
|
||||||
|
const char* shortname;
|
||||||
|
//Output: Full core name.
|
||||||
|
const char* fullname;
|
||||||
|
//Output: Capability flags #1 (LSNES_CORE_CAP1_*).
|
||||||
|
unsigned cap_flags1;
|
||||||
|
//Output: Array of actions. Terminated by NULL pointer. Only if LSNES_CORE_CAP1_ACTION is set.
|
||||||
|
struct lsnes_core_get_core_info_action** actions;
|
||||||
|
//Output: List of trace CPUs. Terminated by NULL. Only if LSNES_CORE_CAP1_TRACE is set.
|
||||||
|
const char** trace_cpu_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 2: Request information about system type.
|
||||||
|
//Item id: Type ID.
|
||||||
|
//Default action: (required)
|
||||||
|
//Obtain information about system type.
|
||||||
|
#define LSNES_CORE_GET_TYPE_INFO 2
|
||||||
|
struct lsnes_core_get_type_info_paramval
|
||||||
|
{
|
||||||
|
const char* iname;
|
||||||
|
const char* hname;
|
||||||
|
signed index;
|
||||||
|
};
|
||||||
|
struct lsnes_core_get_type_info_param
|
||||||
|
{
|
||||||
|
//Internal name.
|
||||||
|
const char* iname;
|
||||||
|
//Human-readable name.
|
||||||
|
const char* hname;
|
||||||
|
//Default value.
|
||||||
|
const char* dflt;
|
||||||
|
//Enumeration of values (if enumerated, ended by value with NULL iname).
|
||||||
|
//If values are false and true, this is boolean.
|
||||||
|
struct lsnes_core_get_type_info_paramval* values;
|
||||||
|
//Validation regex (only for non-enumerated).
|
||||||
|
const char* regex;
|
||||||
|
};
|
||||||
|
struct lsnes_core_get_type_info_romimage
|
||||||
|
{
|
||||||
|
//Internal name.
|
||||||
|
const char* iname;
|
||||||
|
//Human-readable name.
|
||||||
|
const char* hname;
|
||||||
|
//Mandatory mask (OR of all preset ones must equal OR of all).
|
||||||
|
unsigned mandatory;
|
||||||
|
//Pass mode: 0 => Content. 1 => Filename, 2 => Directory.
|
||||||
|
int pass_mode;
|
||||||
|
//Optional header size.
|
||||||
|
unsigned headersize;
|
||||||
|
//Standard extensions (split by ;).
|
||||||
|
const char* extensions;
|
||||||
|
};
|
||||||
|
struct lsnes_core_get_type_info
|
||||||
|
{
|
||||||
|
//Output: ID of core emulating this.
|
||||||
|
unsigned core;
|
||||||
|
//Output: internal name.
|
||||||
|
const char* iname;
|
||||||
|
//Output: human-readable name.
|
||||||
|
const char* hname;
|
||||||
|
//Output: Short System name (e.g. SNES).
|
||||||
|
const char* sysname;
|
||||||
|
//Output: BIOS name.
|
||||||
|
const char* bios;
|
||||||
|
//Output: List of regions. Terminated by 0xFFFFFFFF.
|
||||||
|
unsigned* regions;
|
||||||
|
//Output: List of images. Terminated by NULL.
|
||||||
|
struct lsnes_core_get_type_info_romimage** images;
|
||||||
|
//Output: List of settings. Terminated by NULL.
|
||||||
|
struct lsnes_core_get_type_info_param** settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 3: Request information about region.
|
||||||
|
//Item id: Region ID.
|
||||||
|
//Default action: (required)
|
||||||
|
//Obtain information about region.
|
||||||
|
#define LSNES_CORE_GET_REGION_INFO 3
|
||||||
|
struct lsnes_core_get_region_info
|
||||||
|
{
|
||||||
|
//Output: Internal name.
|
||||||
|
const char* iname;
|
||||||
|
//Output: Human-readable name.
|
||||||
|
const char* hname;
|
||||||
|
//Output: Priority
|
||||||
|
unsigned priority;
|
||||||
|
//Output: Multi-region flag.
|
||||||
|
int multi;
|
||||||
|
//Output: Fps numerator.
|
||||||
|
uint32_t fps_n;
|
||||||
|
//Output: Fps denomerator.
|
||||||
|
uint32_t fps_d;
|
||||||
|
//Output: Compatible run regions, ended with 0xFFFFFFFF.
|
||||||
|
unsigned compatible_runs;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 4: Get sysregion info.
|
||||||
|
//Item id: Sysregion ID.
|
||||||
|
//Default action: (required)
|
||||||
|
//Get information about specific sysregion.
|
||||||
|
#define LSNES_CORE_GET_SYSREGION_INFO 4
|
||||||
|
struct lsnes_core_get_sysregion_info
|
||||||
|
{
|
||||||
|
//Output: The type ID.
|
||||||
|
unsigned type;
|
||||||
|
//Output: The region ID.
|
||||||
|
unsigned region;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//Request 5: Get current A/V state.
|
||||||
|
//Item: Core ID.
|
||||||
|
//Default action: (required)
|
||||||
|
//Fill the structure with current A/V state.
|
||||||
|
#define LSNES_CORE_GET_AV_STATE 5
|
||||||
|
struct lsnes_core_get_av_state
|
||||||
|
{
|
||||||
|
uint32_t fps_n;
|
||||||
|
uint32_t fps_d;
|
||||||
|
double par;
|
||||||
|
uint32_t rate_n;
|
||||||
|
uint32_t rate_d;
|
||||||
|
unsigned lightgun_width;
|
||||||
|
unsigned lightgun_height;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//Request 6: Emulate a frame
|
||||||
|
//Item: Core ID.
|
||||||
|
//Default action: (required).
|
||||||
|
//Emulate a frame and output the video and audio data resulting.
|
||||||
|
#define LSNES_CORE_EMULATE 6
|
||||||
|
struct lsnes_core_emulate
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 7: Save state.
|
||||||
|
//Item: Core ID.
|
||||||
|
//Default action: (required).
|
||||||
|
//Save core state.
|
||||||
|
#define LSNES_CORE_SAVESTATE 7
|
||||||
|
struct lsnes_core_savestate
|
||||||
|
{
|
||||||
|
//Output: Size of the savestate.
|
||||||
|
size_t size;
|
||||||
|
//Output: Savestate data. Only needs to be stable to next call.
|
||||||
|
const char* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 8: Load state.
|
||||||
|
//Item: Core ID.
|
||||||
|
//Default action: (required).
|
||||||
|
//Load core state.
|
||||||
|
#define LSNES_CORE_LOADSTATE 8
|
||||||
|
struct lsnes_core_loadstate
|
||||||
|
{
|
||||||
|
//Input: Size of the savestate.
|
||||||
|
size_t size;
|
||||||
|
//Input: Savestate data. Only stable during call.
|
||||||
|
const char* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 9: Get controller set.
|
||||||
|
//Item id: Type ID.
|
||||||
|
//Default action: (required).
|
||||||
|
//Get the controller set.
|
||||||
|
#define LSNES_CORE_GET_CONTROLLERCONFIG 9
|
||||||
|
struct lsnes_core_get_controllerconfig_logical_entry
|
||||||
|
{
|
||||||
|
//port
|
||||||
|
unsigned port;
|
||||||
|
//controller
|
||||||
|
unsigned controller;
|
||||||
|
};
|
||||||
|
struct lsnes_core_get_controllerconfig
|
||||||
|
{
|
||||||
|
//Input: System settings. Ended by entry with NULL name.
|
||||||
|
struct lsnes_core_system_setting* settings;
|
||||||
|
//Output: Port types, indexed by 0-based ID to port type root JSON array. Ended by 0xFFFFFFFF.
|
||||||
|
unsigned* controller_types;
|
||||||
|
//Output: Logical map (ended by 0,0).
|
||||||
|
struct lsnes_core_get_controllerconfig_logical_entry* logical_map;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 10: Load ROM.
|
||||||
|
//Item id: Type ID.
|
||||||
|
//Default action: (required).
|
||||||
|
//Load given ROM.
|
||||||
|
#define LSNES_CORE_LOAD_ROM 10
|
||||||
|
struct lsnes_core_load_rom_image
|
||||||
|
{
|
||||||
|
//ROM image (or filename thereof)
|
||||||
|
const char* data;
|
||||||
|
//Size of ROM image.
|
||||||
|
size_t size;
|
||||||
|
//Markup.
|
||||||
|
const char* markup;
|
||||||
|
};
|
||||||
|
struct lsnes_core_load_rom
|
||||||
|
{
|
||||||
|
//Input: The image set.
|
||||||
|
struct lsnes_core_load_rom_image* images;
|
||||||
|
//Input: System settings. Ended by entry with NULL name.
|
||||||
|
struct lsnes_core_system_setting* settings;
|
||||||
|
//Input: RTC second.
|
||||||
|
uint64_t rtc_sec;
|
||||||
|
//Input: RTC subsecond.
|
||||||
|
uint64_t rtc_subsec;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 11: Get region.
|
||||||
|
//Item: Core ID.
|
||||||
|
//Default action: Fill region 0.
|
||||||
|
//Return the current region.
|
||||||
|
#define LSNES_CORE_GET_REGION 11
|
||||||
|
struct lsnes_core_get_region
|
||||||
|
{
|
||||||
|
//Output: The region.
|
||||||
|
unsigned region;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 12: Set region.
|
||||||
|
//Item: Core ID.
|
||||||
|
//Default action: If region is 0, succeed, otherwise fail.
|
||||||
|
//Set current region.
|
||||||
|
#define LSNES_CORE_SET_REGION 12
|
||||||
|
struct lsnes_core_set_region
|
||||||
|
{
|
||||||
|
//Input: The region ID.
|
||||||
|
unsigned region;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 13: Deinitialize
|
||||||
|
//Item: 0.
|
||||||
|
//Default action: No-op
|
||||||
|
//Deinitialize the state.
|
||||||
|
#define LSNES_CORE_DEINITIALIZE 13
|
||||||
|
struct lsnes_core_deinitialize
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 14: Get poll flag state.
|
||||||
|
//Item: Core ID.
|
||||||
|
//Default action: Return flag inferred from polls.
|
||||||
|
//Return the poll flag state.
|
||||||
|
//The poll flag gets automatically set to 1 if core reads controllers.
|
||||||
|
#define LSNES_CORE_GET_PFLAG 14
|
||||||
|
struct lsnes_core_get_pflag
|
||||||
|
{
|
||||||
|
//Output: The poll flag state.
|
||||||
|
int pflag;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 15: Set poll flag state.
|
||||||
|
//Item: Core ID.
|
||||||
|
//Default action: Set flag inferred from polls.
|
||||||
|
//Sets the poll flag state.
|
||||||
|
#define LSNES_CORE_SET_PFLAG 15
|
||||||
|
struct lsnes_core_set_pflag
|
||||||
|
{
|
||||||
|
//Input: The poll flag state.
|
||||||
|
int pflag;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 16: Get action flags.
|
||||||
|
//Item: Core ID.
|
||||||
|
//Default action: Act as if flags was 1.
|
||||||
|
//Get flags for given action.
|
||||||
|
#define LSNES_CORE_GET_ACTION_FLAGS 16
|
||||||
|
struct lsnes_core_get_action_flags
|
||||||
|
{
|
||||||
|
//Input: The ID of action.
|
||||||
|
unsigned action;
|
||||||
|
//Output: The flags.
|
||||||
|
//Bit 0: Enabled.
|
||||||
|
//Bit 1: Checked.
|
||||||
|
unsigned flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 17: Execute action.
|
||||||
|
//Item: Core ID.
|
||||||
|
//Default action: Do nothing.
|
||||||
|
//Execute given action.
|
||||||
|
#define LSNES_CORE_EXECUTE_ACTION 17
|
||||||
|
struct lsnes_core_execute_action_param
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
int boolean;
|
||||||
|
int64_t integer;
|
||||||
|
struct {
|
||||||
|
const char* base;
|
||||||
|
size_t length;
|
||||||
|
} string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
struct lsnes_core_execute_action
|
||||||
|
{
|
||||||
|
//Input: The ID of action.
|
||||||
|
unsigned action;
|
||||||
|
//Parameters block (length is set by action info).
|
||||||
|
struct lsnes_core_execute_action_param* params;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 18: Get bus mapping.
|
||||||
|
//Item: Core ID.
|
||||||
|
//Default action: base=0, size=0 (no mapping).
|
||||||
|
//Get the base and size of bus mapping.
|
||||||
|
#define LSNES_CORE_GET_BUS_MAPPING 18
|
||||||
|
struct lsnes_core_get_bus_mapping
|
||||||
|
{
|
||||||
|
//Output: The base address of the mapping.
|
||||||
|
uint64_t base;
|
||||||
|
//Output: The size of the mapping.
|
||||||
|
uint64_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 19: Enumerate SRAMs.
|
||||||
|
//Item iD: Core ID.
|
||||||
|
//Default action: Return empty set.
|
||||||
|
//Get the set of SRAMs available.
|
||||||
|
#define LSNES_CORE_ENUMERATE_SRAM 19
|
||||||
|
struct lsnes_core_enumerate_sram
|
||||||
|
{
|
||||||
|
//Output: List of SRAMs, NULL terminated (valid until next call).
|
||||||
|
const char** srams;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 20: Save SRAMs.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Return empty set.
|
||||||
|
//Save the contents of SRAMs.
|
||||||
|
#define LSNES_CORE_SAVE_SRAM 20
|
||||||
|
struct lsnes_core_save_sram
|
||||||
|
{
|
||||||
|
//Output: The SRAMs, terminated by entry with NULL name. Valid until next call.
|
||||||
|
struct lsnes_core_sram* srams;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 21: Load SRAMs.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Warn about any SRAMs present.
|
||||||
|
//Load the contents of SRAMs.
|
||||||
|
#define LSNES_CORE_LOAD_SRAM 21
|
||||||
|
struct lsnes_core_load_sram
|
||||||
|
{
|
||||||
|
//Intput: The SRAMs, terminated by entry with NULL name. Valid during call.
|
||||||
|
struct lsnes_core_sram* srams;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 22: Get reset action number.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Return -1 for both (not supported).
|
||||||
|
//Return the IDs for reset actions.
|
||||||
|
#define LSNES_CORE_GET_RESET_ACTION 22
|
||||||
|
struct lsnes_core_get_reset_action
|
||||||
|
{
|
||||||
|
//Output: Soft reset action (-1 if not supported).
|
||||||
|
int softreset;
|
||||||
|
//Output: Hard reset action (-1 if not supported).
|
||||||
|
int hardreset;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 23: Get scale factors.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Scale to at least 360 width, 320 height.
|
||||||
|
//Compute scale factors for given resolution.
|
||||||
|
#define LSNES_CORE_COMPUTE_SCALE 23
|
||||||
|
struct lsnes_core_compute_scale
|
||||||
|
{
|
||||||
|
//Input: Width
|
||||||
|
unsigned width;
|
||||||
|
//Input: Height.
|
||||||
|
unsigned height;
|
||||||
|
//Output: Horizontal scale factor.
|
||||||
|
uint32_t hfactor;
|
||||||
|
//Output: Vertical scale factor.
|
||||||
|
uint32_t vfactor;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 24: Run to save.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Do nothing.
|
||||||
|
//Run to next save point (can be at most frame).
|
||||||
|
#define LSNES_CORE_RUNTOSAVE 24
|
||||||
|
struct lsnes_core_runtosave
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 25: Poweron the system
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Do nothing.
|
||||||
|
//Powers on the emulate system.
|
||||||
|
#define LSNES_CORE_POWERON 25
|
||||||
|
struct lsnes_core_poweron
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 26: Unload the ROM.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Do nothing.
|
||||||
|
//Signals that the ROM is no longer needed and can be unloaded.
|
||||||
|
#define LSNES_CORE_UNLOAD_CARTRIDGE 26
|
||||||
|
struct lsnes_core_unload_cartridge
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 27: Reset debugging.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Do nothing.
|
||||||
|
//Signals that debugging system should discard all breakpoints, cheats and tracks.
|
||||||
|
#define LSNES_CORE_DEBUG_RESET 27
|
||||||
|
struct lsnes_core_debug_reset
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 28: Set debug flags.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Do nothing.
|
||||||
|
//Set debugging flags.
|
||||||
|
#define LSNES_CORE_SET_DEBUG_FLAGS 28
|
||||||
|
struct lsnes_core_set_debug_flags
|
||||||
|
{
|
||||||
|
//Input: Address or CPU id.
|
||||||
|
uint64_t addr;
|
||||||
|
//Input: Flags to set.
|
||||||
|
//1 => Break on read.
|
||||||
|
//2 => Break on write.
|
||||||
|
//4 => Break on execute.
|
||||||
|
//8 => Trace.
|
||||||
|
unsigned set;
|
||||||
|
//Input: Flags to clear.
|
||||||
|
unsigned clear;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 29: Set cheat.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Do nothing.
|
||||||
|
//Set or clear cheat.
|
||||||
|
#define LSNES_CORE_SET_CHEAT 29
|
||||||
|
struct lsnes_core_set_cheat
|
||||||
|
{
|
||||||
|
//Input: Address to set on.
|
||||||
|
uint64_t addr;
|
||||||
|
//Input: Value to set.
|
||||||
|
uint64_t value;
|
||||||
|
//Input: If nonzero, set cheat, else clear it.
|
||||||
|
int set;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 30: Draw cover page.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Draw black screen.
|
||||||
|
//Draw the cover page.
|
||||||
|
#define LSNES_CORE_DRAW_COVER 30
|
||||||
|
struct lsnes_core_draw_cover
|
||||||
|
{
|
||||||
|
//Output: The cover page. Needs to stay valid to next call.
|
||||||
|
struct lsnes_core_framebuffer_info* coverpage;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 31: Set system controls before emulating frame.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Do nothing.
|
||||||
|
//Set the system controls before frame is emulated.
|
||||||
|
#define LSNES_CORE_PRE_EMULATE 31
|
||||||
|
struct lsnes_core_pre_emulate
|
||||||
|
{
|
||||||
|
//Input: Context to pass to the function.
|
||||||
|
void* context;
|
||||||
|
//Input: Set input function.
|
||||||
|
void (*set_input)(void* context, unsigned port, unsigned controller, unsigned index, short value);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 32: Get list of device registers.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Return no registers.
|
||||||
|
//Return list of device registers.
|
||||||
|
#define LSNES_CORE_GET_DEVICE_REGS 32
|
||||||
|
struct lsnes_core_get_device_regs_reg
|
||||||
|
{
|
||||||
|
//Name of the register.
|
||||||
|
const char* name;
|
||||||
|
//Read function.
|
||||||
|
uint64_t (*read)();
|
||||||
|
//Write function.
|
||||||
|
void (*write)(uint64_t v);
|
||||||
|
//Is boolean?
|
||||||
|
int boolean;
|
||||||
|
};
|
||||||
|
struct lsnes_core_get_device_regs
|
||||||
|
{
|
||||||
|
//Output: List of registers. Terminated with register with NULL name.
|
||||||
|
struct lsnes_core_get_device_regs_reg* regs;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Request 33: Get VMA list.
|
||||||
|
//Item id: Core ID.
|
||||||
|
//Default action: Return no VMAs.
|
||||||
|
//Get the list of VMAs.
|
||||||
|
#define LSNES_CORE_GET_VMA_LIST 33
|
||||||
|
struct lsnes_core_get_vma_list_vma
|
||||||
|
{
|
||||||
|
//Name of region.
|
||||||
|
const char* name;
|
||||||
|
//Base address.
|
||||||
|
uint64_t base;
|
||||||
|
//Size of region.
|
||||||
|
uint64_t size;
|
||||||
|
//Endianess of region (-1 => little, 0 => host, 1 => big).
|
||||||
|
int endian;
|
||||||
|
//Read-only flag.
|
||||||
|
int readonly;
|
||||||
|
//Special flag.
|
||||||
|
//
|
||||||
|
//Signals that this region is not RAM/ROM-like, but is special I/O region where reads and writes might not be
|
||||||
|
//consistent.
|
||||||
|
int special;
|
||||||
|
//Direct mapping for the region. If not NULL, read/write will not be used, instead all operations directly
|
||||||
|
//manipulate this buffer (faster). Must be NULL for special regions.
|
||||||
|
unsigned char* direct_map;
|
||||||
|
//Function to read region (if direct_map is NULL).
|
||||||
|
uint8_t (*read)(uint64_t offset);
|
||||||
|
//Function to write region (if direct_map is NULL and readonly is 0).
|
||||||
|
void (*write)(uint64_t offset, uint8_t value);
|
||||||
|
};
|
||||||
|
struct lsnes_core_get_vma_list
|
||||||
|
{
|
||||||
|
//Output: List of VMAs. NULL-terminated.
|
||||||
|
struct lsnes_core_get_vma_list_vma** regs;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LSNES_BUILD_AS_BUILTIN_CORE
|
||||||
|
void lsnes_register_builtin_core(lsnes_core_func_t fn);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
9
include/interface/c-interface.hpp
Normal file
9
include/interface/c-interface.hpp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef _interface__c_interface__hpp__included__
|
||||||
|
#define _interface__c_interface__hpp__included__
|
||||||
|
|
||||||
|
#define LSNES_BUILD_AS_BUILTIN_CORE
|
||||||
|
#include "c-interface.h"
|
||||||
|
|
||||||
|
lsnes_core_func_t lsnes_interface_get_builtin();
|
||||||
|
|
||||||
|
#endif
|
462
src/interface/c-interface.cpp
Normal file
462
src/interface/c-interface.cpp
Normal file
|
@ -0,0 +1,462 @@
|
||||||
|
#include "interface/c-interface.hpp"
|
||||||
|
#include "core/window.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::list<lsnes_core_func_t>& corequeue()
|
||||||
|
{
|
||||||
|
static std::list<lsnes_core_func_t> x;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct c_core_core
|
||||||
|
{
|
||||||
|
std::string c_core_identifier()
|
||||||
|
{
|
||||||
|
return fullname;
|
||||||
|
}
|
||||||
|
bool get_av_state(lsnes_core_get_av_state& s)
|
||||||
|
{
|
||||||
|
const char* err;
|
||||||
|
int r = entrypoint(LSNES_CORE_GET_AV_STATE, id, &s, &err);
|
||||||
|
if(r < 0)
|
||||||
|
messages << "Warning: LSNES_CORE_GET_AV_STATE failed: " << err << std::endl;
|
||||||
|
return !r;
|
||||||
|
}
|
||||||
|
std::pair<uint32_t, uint32_t> c_video_rate()
|
||||||
|
{
|
||||||
|
lsnes_core_get_av_state s;
|
||||||
|
if(!get_av_state(s))
|
||||||
|
return std::make_pair(60, 1);
|
||||||
|
return std::make_pair(s.fps_n, s.fps_d);
|
||||||
|
}
|
||||||
|
double c_get_PAR()
|
||||||
|
{
|
||||||
|
lsnes_core_get_av_state s;
|
||||||
|
if(!get_av_state(s))
|
||||||
|
return 1.0;
|
||||||
|
return s.par;
|
||||||
|
}
|
||||||
|
std::pair<uint32_t, uint32_t> c_audio_rate()
|
||||||
|
{
|
||||||
|
lsnes_core_get_av_state s;
|
||||||
|
if(!get_av_state(s))
|
||||||
|
return std::make_pair(48000, 1);
|
||||||
|
return std::make_pair(s.rate_n, s.rate_d);
|
||||||
|
}
|
||||||
|
void c_power()
|
||||||
|
{
|
||||||
|
lsnes_core_poweron s;
|
||||||
|
const char* err;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_POWERON) {
|
||||||
|
int r = entrypoint(LSNES_CORE_POWERON, id, &s, &err);
|
||||||
|
if(r > 0)
|
||||||
|
messages << "Warning: LSNES_CORE_POWERON failed: " << err << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void c_unload_cartridge()
|
||||||
|
{
|
||||||
|
lsnes_core_unload_cartridge s;
|
||||||
|
const char* err;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_UNLOAD) {
|
||||||
|
int r = entrypoint(LSNES_CORE_UNLOAD_CARTRIDGE, id, &s, &err);
|
||||||
|
if(r > 0)
|
||||||
|
messages << "Warning: LSNES_CORE_UNLOAD_CARTRIDGE failed: " << err
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void c_runtosave()
|
||||||
|
{
|
||||||
|
lsnes_core_runtosave s;
|
||||||
|
const char* err;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_RUNTOSAVE) {
|
||||||
|
int r = entrypoint(LSNES_CORE_RUNTOSAVE, id, &s, &err);
|
||||||
|
if(r > 0)
|
||||||
|
messages << "Warning: LSNES_CORE_RUNTOSAVE failed: " << err << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void c_emulate()
|
||||||
|
{
|
||||||
|
lsnes_core_emulate s;
|
||||||
|
const char* err;
|
||||||
|
int r = entrypoint(LSNES_CORE_EMULATE, id, &s, &err);
|
||||||
|
if(r < 0)
|
||||||
|
messages << "Warning: LSNES_CORE_EMULATE failed: " << err << std::endl;
|
||||||
|
}
|
||||||
|
bool c_get_pflag()
|
||||||
|
{
|
||||||
|
lsnes_core_get_pflag s;
|
||||||
|
const char* err;
|
||||||
|
int r = -1;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_PFLAG) {
|
||||||
|
r = entrypoint(LSNES_CORE_GET_PFLAG, id, &s, &err);
|
||||||
|
if(r < 0)
|
||||||
|
messages << "Warning: LSNES_CORE_GET_PFLAG failed: " << err << std::endl;
|
||||||
|
}
|
||||||
|
if(r < 0)
|
||||||
|
return internal_pflag;
|
||||||
|
return (s.pflag != 0);
|
||||||
|
}
|
||||||
|
void c_set_pflag(bool pflag)
|
||||||
|
{
|
||||||
|
lsnes_core_set_pflag s;
|
||||||
|
s.pflag = pflag ? 1 : 0;
|
||||||
|
const char* err;
|
||||||
|
int r = -1;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_PFLAG) {
|
||||||
|
r = entrypoint(LSNES_CORE_SET_PFLAG, id, &s, &err);
|
||||||
|
if(r < 0)
|
||||||
|
messages << "Warning: LSNES_CORE_SET_PFLAG failed: " << err << std::endl;
|
||||||
|
}
|
||||||
|
if(r)
|
||||||
|
internal_pflag = pflag;
|
||||||
|
}
|
||||||
|
std::string c_get_core_shortname()
|
||||||
|
{
|
||||||
|
return shortname;
|
||||||
|
}
|
||||||
|
void c_debug_reset()
|
||||||
|
{
|
||||||
|
lsnes_core_debug_reset s;
|
||||||
|
const char* err;
|
||||||
|
if(caps1 & (LSNES_CORE_CAP1_DEBUG | LSNES_CORE_CAP1_TRACE | LSNES_CORE_CAP1_CHEAT)) {
|
||||||
|
int r = entrypoint(LSNES_CORE_DEBUG_RESET, id, &s, &err);
|
||||||
|
if(r > 0)
|
||||||
|
messages << "Warning: LSNES_CORE_DEBUG_RESET failed: " << err << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::pair<unsigned, unsigned> c_lightgun_scale()
|
||||||
|
{
|
||||||
|
lsnes_core_get_av_state s;
|
||||||
|
bool r = false;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_LIGHTGUN)
|
||||||
|
r = get_av_state(s);
|
||||||
|
if(!r)
|
||||||
|
return std::make_pair(0, 0);
|
||||||
|
return std::make_pair(s.lightgun_width, s.lightgun_height);
|
||||||
|
}
|
||||||
|
std::pair<uint64_t, uint64_t> c_get_bus_map()
|
||||||
|
{
|
||||||
|
lsnes_core_get_bus_mapping s;
|
||||||
|
const char* err;
|
||||||
|
int r = -1;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_BUSMAP) {
|
||||||
|
r = entrypoint(LSNES_CORE_GET_BUS_MAPPING, id, &s, &err);
|
||||||
|
if(r > 0)
|
||||||
|
messages << "Warning: LSNES_CORE_GET_BUS_MAPPING failed: " << err
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
if(r)
|
||||||
|
return std::make_pair(0, 0);
|
||||||
|
return std::make_pair(s.base, s.size);
|
||||||
|
}
|
||||||
|
int c_reset_action(bool hard)
|
||||||
|
{
|
||||||
|
lsnes_core_get_reset_action s;
|
||||||
|
const char* err;
|
||||||
|
int r = -1;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_RESET) {
|
||||||
|
r = entrypoint(LSNES_CORE_GET_RESET_ACTION, id, &s, &err);
|
||||||
|
if(r < 0)
|
||||||
|
messages << "Warning: LSNES_CORE_GET_RESET_ACTION failed: " << err
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
if(r)
|
||||||
|
return -1;
|
||||||
|
return hard ? s.hardreset : s.softreset;
|
||||||
|
}
|
||||||
|
std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
lsnes_core_compute_scale s;
|
||||||
|
const char* err;
|
||||||
|
int r = -1;
|
||||||
|
uint32_t hscale, vscale;
|
||||||
|
if(width >= 360) hscale = 1;
|
||||||
|
else hscale = 360 / width + 1;
|
||||||
|
if(height >= 320) hscale = 1;
|
||||||
|
else hscale = 320 / height + 1;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_RESET) {
|
||||||
|
s.width = width;
|
||||||
|
s.height = height;
|
||||||
|
r = entrypoint(LSNES_CORE_GET_RESET_ACTION, id, &s, &err);
|
||||||
|
if(r < 0)
|
||||||
|
messages << "Warning: LSNES_CORE_GET_RESET_ACTION failed: " << err
|
||||||
|
<< std::endl;
|
||||||
|
else {
|
||||||
|
hscale = s.hfactor;
|
||||||
|
vscale = s.vfactor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::make_pair(hscale, vscale);
|
||||||
|
}
|
||||||
|
void c_pre_emulate_frame(controller_frame& cf)
|
||||||
|
{
|
||||||
|
lsnes_core_pre_emulate s;
|
||||||
|
const char* err;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_PREEMULATE) {
|
||||||
|
s.context = &cf;
|
||||||
|
s.set_input = [](void* context, unsigned port, unsigned controller, unsigned index,
|
||||||
|
short value) -> void {
|
||||||
|
controller_frame& cf = *(controller_frame*)context;
|
||||||
|
cf.axis3(port, controller, index, value);
|
||||||
|
};
|
||||||
|
int r = entrypoint(LSNES_CORE_PRE_EMULATE, id, &s, &err);
|
||||||
|
if(r < 0)
|
||||||
|
messages << "Warning: LSNES_CORE_PRE_EMULATE failed: " << err
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::set<std::string> c_srams()
|
||||||
|
{
|
||||||
|
lsnes_core_enumerate_sram s;
|
||||||
|
const char* err;
|
||||||
|
std::set<std::string> ret;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_SRAM) {
|
||||||
|
int r = entrypoint(LSNES_CORE_ENUMERATE_SRAM, id, &s, &err);
|
||||||
|
if(r < 0) {
|
||||||
|
messages << "Warning: LSNES_CORE_ENUMERATE_SRAM failed: " << err
|
||||||
|
<< std::endl;
|
||||||
|
} else {
|
||||||
|
const char** sr = s.srams;
|
||||||
|
while(*sr) {
|
||||||
|
ret.insert(*sr);
|
||||||
|
sr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc)
|
||||||
|
{
|
||||||
|
lsnes_core_load_sram s;
|
||||||
|
const char* err;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_SRAM) {
|
||||||
|
std::vector<lsnes_core_sram> srams;
|
||||||
|
std::vector<lsnes_core_sram*> sramsp;
|
||||||
|
std::vector<char> names;
|
||||||
|
srams.resize(sram.size() + 1);
|
||||||
|
srams[sram.size()].name = NULL;
|
||||||
|
size_t idx = 0;
|
||||||
|
size_t nlength = 0;
|
||||||
|
for(auto& i : sram)
|
||||||
|
nlength += i.first.length() + 1;
|
||||||
|
names.resize(nlength);
|
||||||
|
size_t nidx = 0;
|
||||||
|
for(auto& i : sram) {
|
||||||
|
size_t ntmp = nidx;
|
||||||
|
std::copy(i.first.begin(), i.first.end(), names.begin() + nidx);
|
||||||
|
nidx += i.first.length();
|
||||||
|
names[nidx++] = '\0';
|
||||||
|
srams[idx].size = i.second.size();
|
||||||
|
srams[idx].data = &i.second[0];
|
||||||
|
srams[idx].name = &names[ntmp];
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
s.srams = &srams[0];
|
||||||
|
int r = entrypoint(LSNES_CORE_LOAD_SRAM, id, &s, &err);
|
||||||
|
if(r < 0)
|
||||||
|
messages << "Warning: LSNES_CORE_LOAD_SRAM failed: " << err
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::map<std::string, std::vector<char>> c_save_sram() throw(std::bad_alloc)
|
||||||
|
{
|
||||||
|
lsnes_core_save_sram s;
|
||||||
|
const char* err;
|
||||||
|
std::map<std::string, std::vector<char>> ret;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_SRAM) {
|
||||||
|
int r = entrypoint(LSNES_CORE_SAVE_SRAM, id, &s, &err);
|
||||||
|
if(r < 0) {
|
||||||
|
messages << "Warning: LSNES_CORE_SAVE_SRAM failed: " << err
|
||||||
|
<< std::endl;
|
||||||
|
} else {
|
||||||
|
lsnes_core_sram* p = s.srams;
|
||||||
|
while(p->name) {
|
||||||
|
ret[p->name].resize(p->size);
|
||||||
|
memcpy(&ret[p->name][0], p->data, p->size);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
void c_unserialize(const char* in, size_t insize)
|
||||||
|
{
|
||||||
|
lsnes_core_loadstate s;
|
||||||
|
const char* err;
|
||||||
|
s.data = in;
|
||||||
|
s.size = insize;
|
||||||
|
int r = entrypoint(LSNES_CORE_LOADSTATE, id, &s, &err);
|
||||||
|
if(r < 0)
|
||||||
|
throw std::runtime_error("Loadstate failed: " + std::string(err));
|
||||||
|
}
|
||||||
|
void c_serialize(std::vector<char>& out)
|
||||||
|
{
|
||||||
|
lsnes_core_savestate s;
|
||||||
|
const char* err;
|
||||||
|
int r = entrypoint(LSNES_CORE_SAVESTATE, id, &s, &err);
|
||||||
|
if(r < 0)
|
||||||
|
throw std::runtime_error("Savestate failed: " + std::string(err));
|
||||||
|
out.resize(s.size);
|
||||||
|
memcpy(&out[0], s.data, s.size);
|
||||||
|
}
|
||||||
|
unsigned c_action_flags(unsigned id)
|
||||||
|
{
|
||||||
|
lsnes_core_get_action_flags s;
|
||||||
|
const char* err;
|
||||||
|
int r = -1;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_ACTION) {
|
||||||
|
s.action = id;
|
||||||
|
r = entrypoint(LSNES_CORE_GET_ACTION_FLAGS, id, &s, &err);
|
||||||
|
if(r < 0)
|
||||||
|
messages << "Warning: LSNES_CORE_GET_ACTION_FLAGS failed: " << err
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
if(r < 0)
|
||||||
|
return 0;
|
||||||
|
return s.flags;
|
||||||
|
}
|
||||||
|
std::vector<std::string> c_get_trace_cpus()
|
||||||
|
{
|
||||||
|
return trace_cpus;
|
||||||
|
}
|
||||||
|
bool c_set_region(core_region& region)
|
||||||
|
{
|
||||||
|
lsnes_core_set_region s;
|
||||||
|
const char* err;
|
||||||
|
int r = -1;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_MULTIREGION) {
|
||||||
|
bool hit = false;
|
||||||
|
for(auto i : regions)
|
||||||
|
if(i.second == ®ion) {
|
||||||
|
s.region = i.first;
|
||||||
|
hit = true;
|
||||||
|
}
|
||||||
|
if(!hit)
|
||||||
|
return false; //Bad region.
|
||||||
|
r = entrypoint(LSNES_CORE_GET_ACTION_FLAGS, id, &s, &err);
|
||||||
|
if(r < 0) {
|
||||||
|
messages << "Warning: LSNES_CORE_SET_REGION failed: " << err
|
||||||
|
<< std::endl;
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if(regions.count(0) && regions[0] == ®ion)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core_region& c_get_region()
|
||||||
|
{
|
||||||
|
lsnes_core_set_region s;
|
||||||
|
const char* err;
|
||||||
|
int r = -1;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_MULTIREGION) {
|
||||||
|
r = entrypoint(LSNES_CORE_GET_ACTION_FLAGS, id, &s, &err);
|
||||||
|
if(r < 0) {
|
||||||
|
messages << "Warning: LSNES_CORE_SET_REGION failed: " << err
|
||||||
|
<< std::endl;
|
||||||
|
if(regions.empty())
|
||||||
|
throw std::runtime_error("No valid regions");
|
||||||
|
return *(regions.begin()->second);
|
||||||
|
} else {
|
||||||
|
if(regions.count(s.region))
|
||||||
|
return *regions[s.region];
|
||||||
|
messages << "Internal error: Core gave invalid region number."
|
||||||
|
<< std::endl;
|
||||||
|
if(regions.empty())
|
||||||
|
throw std::runtime_error("No valid regions");
|
||||||
|
return *(regions.begin()->second);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(regions.count(0))
|
||||||
|
return *regions[0];
|
||||||
|
else {
|
||||||
|
messages << "Internal error: Not multi-region core and region 0 not present."
|
||||||
|
<< std::endl;
|
||||||
|
if(regions.empty())
|
||||||
|
throw std::runtime_error("No valid regions");
|
||||||
|
return *(regions.begin()->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const struct interface_device_reg* c_get_registers()
|
||||||
|
{
|
||||||
|
static std::vector<interface_device_reg> regs;
|
||||||
|
static std::vector<char> namebuf;
|
||||||
|
static interface_device_reg reg_null = {NULL};
|
||||||
|
lsnes_core_get_device_regs s;
|
||||||
|
const char* err;
|
||||||
|
int r = -1;
|
||||||
|
if(caps1 & LSNES_CORE_CAP1_REGISTERS) {
|
||||||
|
r = entrypoint(LSNES_CORE_GET_DEVICE_REGS, id, &s, &err);
|
||||||
|
if(r < 0) {
|
||||||
|
messages << "Warning: LSNES_CORE_GET_DEVICE_REGS failed: " << err
|
||||||
|
<< std::endl;
|
||||||
|
return ®_null;
|
||||||
|
} else {
|
||||||
|
size_t count = 0;
|
||||||
|
size_t namelen = 0;
|
||||||
|
auto tregs = s.regs;
|
||||||
|
while(tregs->name) {
|
||||||
|
namelen += strlen(tregs->name) + 1;
|
||||||
|
count++;
|
||||||
|
tregs++;
|
||||||
|
}
|
||||||
|
tregs = s.regs;
|
||||||
|
if(regs.size() < count + 1)
|
||||||
|
regs.resize(count + 1);
|
||||||
|
if(namelen > namebuf.size())
|
||||||
|
namebuf.resize(namelen);
|
||||||
|
size_t idx = 0;
|
||||||
|
size_t nameptr = 0;
|
||||||
|
while(tregs->name) {
|
||||||
|
strcpy(&namebuf[nameptr], tregs->name);
|
||||||
|
regs[idx].name = &namebuf[nameptr];
|
||||||
|
regs[idx].read = tregs->read;
|
||||||
|
regs[idx].write = tregs->write;
|
||||||
|
regs[idx].boolean = tregs->boolean;
|
||||||
|
nameptr += strlen(tregs->name) + 1;
|
||||||
|
tregs++;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
regs[idx].name = NULL; //The sentinel.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ®_null;
|
||||||
|
|
||||||
|
}
|
||||||
|
return ®s[0];
|
||||||
|
}
|
||||||
|
virtual void c_install_handler() = 0;
|
||||||
|
virtual void c_uninstall_handler() = 0;
|
||||||
|
virtual framebuffer::raw& c_draw_cover() = 0;
|
||||||
|
virtual void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p) = 0;
|
||||||
|
virtual std::list<core_vma_info> c_vma_list() = 0;
|
||||||
|
virtual void c_set_debug_flags(uint64_t addr, unsigned flags_set, unsigned flags_clear) = 0;
|
||||||
|
virtual void c_set_cheat(uint64_t addr, uint64_t value, bool set) = 0;
|
||||||
|
private:
|
||||||
|
std::string fullname;
|
||||||
|
std::string shortname;
|
||||||
|
unsigned id;
|
||||||
|
lsnes_core_func_t entrypoint;
|
||||||
|
bool internal_pflag;
|
||||||
|
unsigned caps1;
|
||||||
|
std::vector<std::string> trace_cpus;
|
||||||
|
std::map<unsigned, core_region*> regions;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void lsnes_register_builtin_core(lsnes_core_func_t fn)
|
||||||
|
{
|
||||||
|
corequeue().push_back(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
lsnes_core_func_t lsnes_interface_get_builtin()
|
||||||
|
{
|
||||||
|
lsnes_core_func_t fn = corequeue().front();
|
||||||
|
corequeue().pop_front();
|
||||||
|
return fn;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue