mirror of
https://github.com/simple64/simple64.git
synced 2026-11-12 22:58:42 +01:00
update core
This commit is contained in:
1 parent
f871ccb522
commit
18f8e5e953
18 files changed
+102
-35
No files matched your search
@@ -53,8 +53,13 @@ These are the debugger functions, which are also called only from the front-end.
|
||||
|
||||
These configuration functions are exported from the core library and are used by the core and the plugins to store all of their persistent configuration parameters. The front-end application may also use these functions to store its configuration options, or it may use a different mechanism. This section also contains two Operating System Abstraction functions. These functions are used by the core, plugins, and the front-end to find full filepaths to shared data files and user-specific data files.
|
||||
|
||||
|
||||
== Plugin API ==
|
||||
=== [[Mupen64Plus v2.0 Plugin API|Plugin API]] ===
|
||||
|
||||
This section lists all of the functions which are exported by the plugins. The front-end application should only use the <tt>PluginStartup</tt>, <tt>PluginShutdown</tt>, and <tt>PluginGetVersion</tt> functions. All other functions will only be called from the core.
|
||||
|
||||
== Netplay ==
|
||||
|
||||
Starting with version 2.6, Mupen64Plus has support for playing games with multiple players over a network. To support this, a few new command types were added to the CoreDoCommand function, as documented in [[Mupen64Plus v2.0 Core Front-End|front-end functions]]. The core handles the network I/O on its own, and the interface for handling netplay from the perspective of the front-end is very high level. The design of the netplay feature is such that a separate piece of server software (not part of Mupen64Plus) is also required. An example of such a server program is available [https://github.com/loganmc10/m64p-netplay-server here] from [https://github.com/loganmc10 loganmc10] on github. A description of the network protocol which is used for communication between the client emulators and the netplay server is available [[Mupen64Plus v2.0 Core Netplay Protocol|here]].
|
||||
|
||||
@@ -188,7 +188,7 @@ Most libmupen64plus functions return an <tt>m64p_error</tt> return code, which i
|
||||
|-
|
||||
|M64CMD_SET_MEDIA_LOADER
|
||||
|This command allow frontends to register their media (such as GameBoy cartridge or 64DD disk) loading functions. These functions will be called appropriately by the core at startup and when a new media is inserted.
|
||||
|'''<tt>ParamInt</tt>''' must be sizeof(m64p_media_loader).'''<br /><tt>ParamPtr</tt>'''A pointer to the m64p_media_loader to register, cannot be NULL.
|
||||
|'''<tt>ParamInt</tt>''' must be sizeof(m64p_media_loader).'''<br /><tt>ParamPtr</tt>''' A pointer to the m64p_media_loader to register, cannot be NULL.
|
||||
|None
|
||||
|-
|
||||
|M64CMD_NETPLAY_INIT
|
||||
@@ -210,6 +210,11 @@ Most libmupen64plus functions return an <tt>m64p_error</tt> return code, which i
|
||||
|Closes the netplay subsystem, as well as any connections to the netplay server.
|
||||
|N/A
|
||||
|None
|
||||
|-
|
||||
|M64CMD_PIF_OPEN
|
||||
|This will cause the core to read in a binary PIF image provided by the front-end.
|
||||
|'''<tt>ParamInt</tt>''' must be 2048.'''<br /><tt>ParamPtr</tt>''' Pointer to the uncompressed PIF image in memory.
|
||||
|The emulator cannot be currently running.
|
||||
|}
|
||||
<br />
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
= Mupen64Plus Netplay API =
|
||||
[[Mupen64Plus v2.0 Core API v1.0|Mupen64Plus v2.0 API]]
|
||||
|
||||
The Mupen64Plus netplay API is based on a client/server architecture. It supports syncing core settings and save files. It also supports raw input (tested with Raphnet input plugin).
|
||||
= Mupen64Plus Netplay Protocol =
|
||||
|
||||
The Mupen64Plus netplay protocol is based on a client/server architecture. It supports syncing core settings and save files. It also supports raw input (tested with Raphnet input plugin).
|
||||
TCP is used to deal with player registration, and syncing settings and saves.
|
||||
UDP is used to transfer key input data.
|
||||
Data is sent in Network Byte Order (Big Endian).
|
||||
@@ -111,3 +113,4 @@ The server is responsible for maintaining healthy buffers and also for detecting
|
||||
*** byte[0-3] = player registration ID
|
||||
*** byte[4] = player plugin
|
||||
*** byte[5] = whether the player is using raw data input
|
||||
|
||||
@@ -132,7 +132,8 @@
|
||||
M64CMD_READ_SCREEN,
|
||||
M64CMD_RESET,
|
||||
M64CMD_ADVANCE_FRAME,
|
||||
M64CMD_SET_MEDIA_LOADER
|
||||
M64CMD_SET_MEDIA_LOADER,
|
||||
M64CMD_PIF_OPEN
|
||||
} m64p_command;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -196,6 +196,12 @@ EXPORT m64p_error CALL CoreDoCommand(m64p_command Command, int ParamInt, void *P
|
||||
cheat_delete_all(&g_cheat_ctx);
|
||||
cheat_uninit(&g_cheat_ctx);
|
||||
return close_rom();
|
||||
case M64CMD_PIF_OPEN:
|
||||
if (g_EmulatorRunning)
|
||||
return M64ERR_INVALID_STATE;
|
||||
if (ParamPtr == NULL || ParamInt != 2048)
|
||||
return M64ERR_INPUT_ASSERT;
|
||||
return open_pif((const unsigned char *) ParamPtr, ParamInt);
|
||||
case M64CMD_ROM_GET_HEADER:
|
||||
if (!l_ROMOpen)
|
||||
return M64ERR_INVALID_STATE;
|
||||
|
||||
@@ -166,7 +166,8 @@ typedef enum {
|
||||
M64CMD_NETPLAY_INIT,
|
||||
M64CMD_NETPLAY_CONTROL_PLAYER,
|
||||
M64CMD_NETPLAY_GET_VERSION,
|
||||
M64CMD_NETPLAY_CLOSE
|
||||
M64CMD_NETPLAY_CLOSE,
|
||||
M64CMD_PIF_OPEN
|
||||
} m64p_command;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -85,6 +85,7 @@ void init_device(struct device* dev,
|
||||
unsigned int count_per_op,
|
||||
int no_compiled_jump,
|
||||
int randomize_interrupt,
|
||||
uint32_t start_address,
|
||||
/* ai */
|
||||
void* aout, const struct audio_out_backend_interface* iaout,
|
||||
/* si */
|
||||
@@ -150,7 +151,7 @@ void init_device(struct device* dev,
|
||||
{ A(MM_DD_ROM, 0x1ffffff), M64P_MEM_NOTHING, { NULL, RW(open_bus) } },
|
||||
{ A(MM_DOM2_ADDR2, 0x1ffff), M64P_MEM_FLASHRAMSTAT, { &dev->cart, RW(cart_dom2) } },
|
||||
{ A(MM_CART_ROM, rom_size-1), M64P_MEM_ROM, { &dev->cart.cart_rom, RW(cart_rom) } },
|
||||
{ A(MM_PIF_MEM, 0xffff), M64P_MEM_PIF, { &dev->pif, RW(pif_ram) } }
|
||||
{ A(MM_PIF_MEM, 0xffff), M64P_MEM_PIF, { &dev->pif, RW(pif_mem) } }
|
||||
};
|
||||
|
||||
/* init and map DD if present */
|
||||
@@ -176,7 +177,7 @@ void init_device(struct device* dev,
|
||||
init_rdram(&dev->rdram, mem_base_u32(base, MM_RDRAM_DRAM), dram_size, &dev->r4300);
|
||||
|
||||
init_r4300(&dev->r4300, &dev->mem, &dev->mi, &dev->rdram, interrupt_handlers,
|
||||
emumode, count_per_op, no_compiled_jump, randomize_interrupt);
|
||||
emumode, count_per_op, no_compiled_jump, randomize_interrupt, start_address);
|
||||
init_rdp(&dev->dp, &dev->sp, &dev->mi, &dev->mem, &dev->rdram, &dev->r4300);
|
||||
init_rsp(&dev->sp, mem_base_u32(base, MM_RSP_MEM), &dev->mi, &dev->dp, &dev->ri);
|
||||
init_ai(&dev->ai, &dev->mi, &dev->ri, &dev->vi, aout, iaout);
|
||||
|
||||
@@ -120,6 +120,7 @@ void init_device(struct device* dev,
|
||||
unsigned int count_per_op,
|
||||
int no_compiled_jump,
|
||||
int randomize_interrupt,
|
||||
uint32_t start_address,
|
||||
/* ai */
|
||||
void* aout, const struct audio_out_backend_interface* iaout,
|
||||
/* si */
|
||||
|
||||
@@ -47,6 +47,8 @@ static unsigned int get_tv_type(void)
|
||||
|
||||
void pif_bootrom_hle_execute(struct r4300_core* r4300)
|
||||
{
|
||||
if (r4300->start_address == 0xbfc00000) return;
|
||||
|
||||
uint32_t pif24;
|
||||
unsigned int seed; /* seed (depends on CIC version) */
|
||||
unsigned int rom_type; /* 0:Cart, 1:DD */
|
||||
|
||||
@@ -132,6 +132,7 @@ void init_pif(struct pif* pif,
|
||||
{
|
||||
size_t i;
|
||||
|
||||
pif->base = pif_base;
|
||||
pif->ram = pif_base + 0x7c0;
|
||||
|
||||
for (i = 0; i < PIF_CHANNELS_COUNT; ++i) {
|
||||
@@ -282,34 +283,28 @@ void poweron_pif(struct pif* pif)
|
||||
reset_pif(pif, 0); /* cold reset */
|
||||
}
|
||||
|
||||
void read_pif_ram(void* opaque, uint32_t address, uint32_t* value)
|
||||
void read_pif_mem(void* opaque, uint32_t address, uint32_t* value)
|
||||
{
|
||||
struct pif* pif = (struct pif*)opaque;
|
||||
uint32_t addr = pif_ram_address(address);
|
||||
uint32_t addr = pif_address(address);
|
||||
|
||||
if (addr >= PIF_RAM_SIZE)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Invalid PIF address: %08" PRIX32, address);
|
||||
*value = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(value, pif->ram + addr, sizeof(*value));
|
||||
*value = tohl(*value);
|
||||
memcpy(value, pif->base + addr, sizeof(*value));
|
||||
if (addr >= PIF_ROM_SIZE)
|
||||
*value = tohl(*value);
|
||||
}
|
||||
|
||||
void write_pif_ram(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
|
||||
void write_pif_mem(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
|
||||
{
|
||||
struct pif* pif = (struct pif*)opaque;
|
||||
uint32_t addr = pif_ram_address(address);
|
||||
uint32_t addr = pif_address(address);
|
||||
|
||||
if (addr >= PIF_RAM_SIZE)
|
||||
if (addr < PIF_ROM_SIZE)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Invalid PIF address: %08" PRIX32, address);
|
||||
DebugMessage(M64MSG_ERROR, "Invalid write to PIF ROM: %08" PRIX32, address);
|
||||
return;
|
||||
}
|
||||
|
||||
masked_write((uint32_t*)(&pif->ram[addr]), fromhl(value), fromhl(mask));
|
||||
masked_write((uint32_t*)(&pif->base[addr]), fromhl(value), fromhl(mask));
|
||||
|
||||
pif->si->dma_dir = SI_DMA_WRITE;
|
||||
|
||||
@@ -357,10 +352,17 @@ void process_pif_ram(struct pif* pif)
|
||||
clrmask |= 0x08;
|
||||
}
|
||||
|
||||
if (flags & 0x30)
|
||||
{
|
||||
pif->ram[0x3f] = 0x80;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PIF
|
||||
if (flags & 0xf4)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "error in process_pif_ram(): %" PRIX8, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
pif->ram[0x3f] &= ~clrmask;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ size_t setup_pif_channel(struct pif_channel* channel, uint8_t* buf);
|
||||
|
||||
struct pif
|
||||
{
|
||||
uint8_t* base;
|
||||
uint8_t* ram;
|
||||
struct pif_channel channels[PIF_CHANNELS_COUNT];
|
||||
|
||||
@@ -62,9 +63,9 @@ struct pif
|
||||
struct si_controller* si;
|
||||
};
|
||||
|
||||
static osal_inline uint32_t pif_ram_address(uint32_t address)
|
||||
static osal_inline uint32_t pif_address(uint32_t address)
|
||||
{
|
||||
return ((address & 0xfffc) - PIF_ROM_SIZE);
|
||||
return (address & 0xfffc);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,8 +83,8 @@ void reset_pif(struct pif* pif, unsigned int reset_type);
|
||||
|
||||
void setup_channels_format(struct pif* pif);
|
||||
|
||||
void read_pif_ram(void* opaque, uint32_t address, uint32_t* value);
|
||||
void write_pif_ram(void* opaque, uint32_t address, uint32_t value, uint32_t mask);
|
||||
void read_pif_mem(void* opaque, uint32_t address, uint32_t* value);
|
||||
void write_pif_mem(void* opaque, uint32_t address, uint32_t value, uint32_t mask);
|
||||
|
||||
void process_pif_ram(struct pif* pif);
|
||||
void update_pif_ram(struct pif* pif);
|
||||
|
||||
@@ -468,8 +468,8 @@ void nmi_int_handler(void* opaque)
|
||||
r4300->recomp.dyna_interp = 0;
|
||||
#endif
|
||||
// set next instruction address to reset vector
|
||||
r4300->cp0.last_addr = UINT32_C(0xa4000040);
|
||||
generic_jump_to(r4300, UINT32_C(0xa4000040));
|
||||
r4300->cp0.last_addr = r4300->start_address;
|
||||
generic_jump_to(r4300, r4300->start_address);
|
||||
}
|
||||
|
||||
|
||||
@@ -496,7 +496,7 @@ void reset_hard_handler(void* opaque)
|
||||
poweron_device(dev);
|
||||
|
||||
pif_bootrom_hle_execute(r4300);
|
||||
r4300->cp0.last_addr = UINT32_C(0xa4000040);
|
||||
r4300->cp0.last_addr = r4300->start_address;
|
||||
*r4300_cp0_next_interrupt(&r4300->cp0) = 624999;
|
||||
*r4300_cp0_cycle_count(&r4300->cp0) = 0;
|
||||
init_interrupt(&r4300->cp0);
|
||||
|
||||
@@ -713,7 +713,7 @@ void run_pure_interpreter(struct r4300_core* r4300)
|
||||
{
|
||||
*r4300_stop(r4300) = 0;
|
||||
*r4300_pc_struct(r4300) = &r4300->interp_PC;
|
||||
*r4300_pc(r4300) = r4300->cp0.last_addr = 0xa4000040;
|
||||
*r4300_pc(r4300) = r4300->cp0.last_addr = r4300->start_address;
|
||||
|
||||
while (!*r4300_stop(r4300))
|
||||
{
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include <time.h>
|
||||
|
||||
void init_r4300(struct r4300_core* r4300, struct memory* mem, struct mi_controller* mi, struct rdram* rdram, const struct interrupt_handler* interrupt_handlers,
|
||||
unsigned int emumode, unsigned int count_per_op, int no_compiled_jump, int randomize_interrupt)
|
||||
unsigned int emumode, unsigned int count_per_op, int no_compiled_jump, int randomize_interrupt, uint32_t start_address)
|
||||
{
|
||||
struct new_dynarec_hot_state* new_dynarec_hot_state =
|
||||
#ifdef NEW_DYNAREC
|
||||
@@ -62,6 +62,7 @@ void init_r4300(struct r4300_core* r4300, struct memory* mem, struct mi_controll
|
||||
r4300->mi = mi;
|
||||
r4300->rdram = rdram;
|
||||
r4300->randomize_interrupt = randomize_interrupt;
|
||||
r4300->start_address = start_address;
|
||||
srand((unsigned int) time(NULL));
|
||||
}
|
||||
|
||||
@@ -182,7 +183,7 @@ void run_r4300(struct r4300_core* r4300)
|
||||
r4300->cached_interp.recompile_block = cached_interp_recompile_block;
|
||||
|
||||
init_blocks(&r4300->cached_interp);
|
||||
cached_interpreter_jump_to(r4300, UINT32_C(0xa4000040));
|
||||
cached_interpreter_jump_to(r4300, r4300->start_address);
|
||||
|
||||
/* Prevent segfault on failed cached_interpreter_jump_to */
|
||||
if (!r4300->cached_interp.actual->block) {
|
||||
|
||||
@@ -195,6 +195,8 @@ struct r4300_core
|
||||
struct rdram* rdram;
|
||||
|
||||
uint32_t randomize_interrupt;
|
||||
|
||||
uint32_t start_address;
|
||||
};
|
||||
|
||||
#define R4300_KSEG0 UINT32_C(0x80000000)
|
||||
@@ -209,7 +211,7 @@ struct r4300_core
|
||||
offsetof(struct new_dynarec_hot_state, regs))
|
||||
#endif
|
||||
|
||||
void init_r4300(struct r4300_core* r4300, struct memory* mem, struct mi_controller* mi, struct rdram* rdram, const struct interrupt_handler* interrupt_handlers, unsigned int emumode, unsigned int count_per_op, int no_compiled_jump, int randomize_interrupt);
|
||||
void init_r4300(struct r4300_core* r4300, struct memory* mem, struct mi_controller* mi, struct rdram* rdram, const struct interrupt_handler* interrupt_handlers, unsigned int emumode, unsigned int count_per_op, int no_compiled_jump, int randomize_interrupt, uint32_t start_address);
|
||||
void poweron_r4300(struct r4300_core* r4300);
|
||||
|
||||
void run_r4300(struct r4300_core* r4300);
|
||||
|
||||
@@ -891,7 +891,7 @@ void dynarec_setup_code(void)
|
||||
/* The dynarec jumps here after we call dyna_start and it prepares
|
||||
* Here we need to prepare the initial code block and jump to it
|
||||
*/
|
||||
dynarec_jump_to(r4300, UINT32_C(0xa4000040));
|
||||
dynarec_jump_to(r4300, r4300->start_address);
|
||||
|
||||
/* Prevent segfault on failed dynarec_jump_to */
|
||||
if (!r4300->cached_interp.actual->block || !r4300->cached_interp.actual->code) {
|
||||
|
||||
@@ -107,6 +107,8 @@ struct cheat_ctx g_cheat_ctx;
|
||||
*/
|
||||
void* g_mem_base = NULL;
|
||||
|
||||
uint32_t g_start_address = UINT32_C(0xa4000040);
|
||||
|
||||
struct device g_dev;
|
||||
|
||||
m64p_media_loader g_media_loader;
|
||||
@@ -1573,6 +1575,7 @@ m64p_error main_run(void)
|
||||
count_per_op,
|
||||
no_compiled_jump,
|
||||
randomize_interrupt,
|
||||
g_start_address,
|
||||
&g_dev.ai, &g_iaudio_out_backend_plugin_compat,
|
||||
si_dma_duration,
|
||||
rdram_size,
|
||||
@@ -1743,3 +1746,34 @@ void main_stop(void)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
m64p_error open_pif(const unsigned char* pifimage, unsigned int size)
|
||||
{
|
||||
md5_byte_t pif_ntsc_md5[] = {0x49, 0x21, 0xD5, 0xF2, 0x16, 0x5D, 0xEE, 0x6E, 0x24, 0x96, 0xF4, 0x38, 0x8C, 0x4C, 0x81, 0xDA};
|
||||
md5_byte_t pif_pal_md5[] = {0x2B, 0x6E, 0xEC, 0x58, 0x6F, 0xAA, 0x43, 0xF3, 0x46, 0x23, 0x33, 0xB8, 0x44, 0x83, 0x45, 0x54};
|
||||
|
||||
uint32_t *dst32 = mem_base_u32(g_mem_base, MM_PIF_MEM);
|
||||
uint32_t *src32 = (uint32_t*) pifimage;
|
||||
md5_state_t state;
|
||||
md5_byte_t digest[16];
|
||||
|
||||
md5_init(&state);
|
||||
md5_append(&state, (const md5_byte_t*)pifimage, size);
|
||||
md5_finish(&state, digest);
|
||||
|
||||
if (memcmp(digest, pif_ntsc_md5, 16) == 0)
|
||||
DebugMessage(M64MSG_INFO, "Using NTSC PIF ROM");
|
||||
else if (memcmp(digest, pif_pal_md5, 16) == 0)
|
||||
DebugMessage(M64MSG_INFO, "Using PAL PIF ROM");
|
||||
else
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Invalid PIF ROM");
|
||||
return M64ERR_INPUT_INVALID;
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; i += 4)
|
||||
*dst32++ = big32(*src32++);
|
||||
|
||||
g_start_address = UINT32_C(0xbfc00000);
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
@@ -99,5 +99,7 @@ int main_volume_get_muted(void);
|
||||
|
||||
m64p_error main_reset(int do_hard_reset);
|
||||
|
||||
m64p_error open_pif(const unsigned char* pifimage, unsigned int size);
|
||||
|
||||
#endif /* __MAIN_H__ */
|
||||
|
||||
Reference in new issue
Block a user