641 lines
27 KiB
C
641 lines
27 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Mupen64plus - savestates.c *
|
|
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
|
* Copyright (C) 2012 CasualJames *
|
|
* Copyright (C) 2009 Olejl Tillin9 *
|
|
* Copyright (C) 2008 Richard42 Tillin9 *
|
|
* Copyright (C) 2002 Hacktarux *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "usf/usf.h"
|
|
|
|
#include "usf/usf_internal.h"
|
|
|
|
#define M64P_CORE_PROTOTYPES 1
|
|
#include "api/m64p_types.h"
|
|
#include "api/callbacks.h"
|
|
|
|
#include "savestates.h"
|
|
#include "main.h"
|
|
#include "rom.h"
|
|
#include "util.h"
|
|
|
|
#include "ai/ai_controller.h"
|
|
#include "memory/memory.h"
|
|
#include "r4300/tlb.h"
|
|
#include "r4300/cp0.h"
|
|
#include "r4300/cp1.h"
|
|
#include "r4300/r4300.h"
|
|
#include "r4300/r4300_core.h"
|
|
#include "r4300/cached_interp.h"
|
|
#include "r4300/interupt.h"
|
|
#include "pi/pi_controller.h"
|
|
#ifdef NEW_DYNAREC
|
|
#include "r4300/new_dynarec/new_dynarec.h"
|
|
#endif
|
|
#include "rdp/rdp_core.h"
|
|
#include "ri/ri_controller.h"
|
|
#include "rsp/rsp_core.h"
|
|
#include "si/si_controller.h"
|
|
#include "vi/vi_controller.h"
|
|
|
|
static const char* savestate_magic = "M64+SAVE";
|
|
static const int savestate_latest_version = 0x00010000; /* 1.0 */
|
|
static const unsigned char pj64_magic[4] = { 0xC8, 0xA6, 0xD8, 0x23 };
|
|
|
|
#define GETARRAY(buff, type, count) \
|
|
(to_little_endian_buffer(buff, sizeof(type),count), \
|
|
buff += count*sizeof(type), \
|
|
(type *)(buff-count*sizeof(type)))
|
|
#define COPYARRAY(dst, buff, type, count) \
|
|
memcpy(dst, GETARRAY(buff, type, count), sizeof(type)*count)
|
|
#define GETDATA(buff, type) *GETARRAY(buff, type, 1)
|
|
|
|
#define PUTARRAY(src, buff, type, count) \
|
|
memcpy(buff, src, sizeof(type)*count); \
|
|
to_little_endian_buffer(buff, sizeof(type), count); \
|
|
buff += count*sizeof(type);
|
|
|
|
#define PUTDATA(buff, type, value) \
|
|
do { type x = value; PUTARRAY(&x, buff, type, 1); } while(0)
|
|
|
|
#define read_bytes(ptr, size) \
|
|
{ \
|
|
if ((size) > state_size) \
|
|
{ \
|
|
if (savestateData) free(savestateData); \
|
|
return 0; \
|
|
} \
|
|
memcpy((ptr), state_ptr, (size)); \
|
|
state_ptr += (size); \
|
|
state_size -= (size); \
|
|
}
|
|
|
|
static int savestates_load_m64p(usf_state_t * state, unsigned char * ptr, unsigned int size)
|
|
{
|
|
unsigned char header[44];
|
|
int version;
|
|
int i;
|
|
|
|
unsigned char * state_ptr = ptr;
|
|
unsigned int state_size = size;
|
|
|
|
size_t savestateSize;
|
|
unsigned char *savestateData = 0, *curr;
|
|
char queue[1024];
|
|
|
|
/* Read and check Mupen64Plus magic number. */
|
|
read_bytes(header, 44);
|
|
curr = header;
|
|
|
|
if(strncmp((char *)curr, savestate_magic, 8)!=0)
|
|
return 0;
|
|
curr += 8;
|
|
|
|
version = *curr++;
|
|
version = (version << 8) | *curr++;
|
|
version = (version << 8) | *curr++;
|
|
version = (version << 8) | *curr++;
|
|
if(version != 0x00010000)
|
|
return 0;
|
|
|
|
/* skip MD5 */
|
|
curr += 32;
|
|
|
|
/* Read the rest of the savestate */
|
|
savestateSize = 16788244;
|
|
if (state_size < savestateSize + sizeof(queue))
|
|
return 0;
|
|
|
|
savestateData = curr = malloc(savestateSize);
|
|
if (!savestateData)
|
|
return 0;
|
|
|
|
read_bytes(savestateData, savestateSize);
|
|
read_bytes(queue, sizeof(queue));
|
|
|
|
// Parse savestate
|
|
state->g_ri.rdram.regs[RDRAM_CONFIG_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_DEVICE_ID_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_DELAY_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_MODE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_REF_INTERVAL_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_REF_ROW_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_RAS_INTERVAL_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_MIN_INTERVAL_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_ADDR_SELECT_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_DEVICE_MANUF_REG] = GETDATA(curr, uint32_t);
|
|
|
|
curr += 4; /* Padding from old implementation */
|
|
state->g_r4300.mi.regs[MI_INIT_MODE_REG] = GETDATA(curr, uint32_t);
|
|
curr += 4; // Duplicate MI init mode flags from old implementation
|
|
state->g_r4300.mi.regs[MI_VERSION_REG] = GETDATA(curr, uint32_t);
|
|
state->g_r4300.mi.regs[MI_INTR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_r4300.mi.regs[MI_INTR_MASK_REG] = GETDATA(curr, uint32_t);
|
|
curr += 4; /* Padding from old implementation */
|
|
curr += 8; // Duplicated MI intr flags and padding from old implementation
|
|
|
|
state->g_pi.regs[PI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_CART_ADDR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_RD_LEN_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_WR_LEN_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_STATUS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM1_LAT_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM1_PWD_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM1_PGS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM1_RLS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM2_LAT_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM2_PWD_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM2_PGS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM2_RLS_REG] = GETDATA(curr, uint32_t);
|
|
|
|
state->g_sp.regs[SP_MEM_ADDR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs[SP_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs[SP_RD_LEN_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs[SP_WR_LEN_REG] = GETDATA(curr, uint32_t);
|
|
curr += 4; /* Padding from old implementation */
|
|
state->g_sp.regs[SP_STATUS_REG] = GETDATA(curr, uint32_t);
|
|
curr += 16; // Duplicated SP flags and padding from old implementation
|
|
state->g_sp.regs[SP_DMA_FULL_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs[SP_DMA_BUSY_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs[SP_SEMAPHORE_REG] = GETDATA(curr, uint32_t);
|
|
|
|
state->g_sp.regs2[SP_PC_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs2[SP_IBIST_REG] = GETDATA(curr, uint32_t);
|
|
|
|
state->g_si.regs[SI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_si.regs[SI_PIF_ADDR_RD64B_REG] = GETDATA(curr, uint32_t);
|
|
state->g_si.regs[SI_PIF_ADDR_WR64B_REG] = GETDATA(curr, uint32_t);
|
|
state->g_si.regs[SI_STATUS_REG] = GETDATA(curr, uint32_t);
|
|
|
|
state->g_vi.regs[VI_STATUS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_ORIGIN_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_WIDTH_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_V_INTR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_CURRENT_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_BURST_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_V_SYNC_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_H_SYNC_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_LEAP_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_H_START_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_V_START_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_V_BURST_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_X_SCALE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_Y_SCALE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.delay = GETDATA(curr, unsigned int);
|
|
|
|
state->g_ri.regs[RI_MODE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_CONFIG_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_CURRENT_LOAD_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_SELECT_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_REFRESH_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_LATENCY_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_ERROR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_WERROR_REG] = GETDATA(curr, uint32_t);
|
|
|
|
state->g_ai.regs[AI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ai.regs[AI_LEN_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ai.regs[AI_CONTROL_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ai.regs[AI_STATUS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ai.regs[AI_DACRATE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ai.regs[AI_BITRATE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ai.fifo[1].duration = GETDATA(curr, unsigned int);
|
|
state->g_ai.fifo[1].length = GETDATA(curr, uint32_t);
|
|
state->g_ai.fifo[0].duration = GETDATA(curr, unsigned int);
|
|
state->g_ai.fifo[0].length = GETDATA(curr, uint32_t);
|
|
/* best effort initialization of fifo addresses...
|
|
* You might get a small sound "pop" because address might be wrong.
|
|
* Proper initialization requires changes to savestate format
|
|
*/
|
|
state->g_ai.fifo[0].address = state->g_ai.regs[AI_DRAM_ADDR_REG];
|
|
state->g_ai.fifo[1].address = state->g_ai.regs[AI_DRAM_ADDR_REG];
|
|
state->g_ai.samples_format_changed = 1;
|
|
|
|
state->g_dp.dpc_regs[DPC_START_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dpc_regs[DPC_END_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dpc_regs[DPC_CURRENT_REG] = GETDATA(curr, uint32_t);
|
|
curr += 4; // Padding from old implementation
|
|
state->g_dp.dpc_regs[DPC_STATUS_REG] = GETDATA(curr, uint32_t);
|
|
curr += 12; // Duplicated DPC flags and padding from old implementation
|
|
state->g_dp.dpc_regs[DPC_CLOCK_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dpc_regs[DPC_BUFBUSY_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dpc_regs[DPC_PIPEBUSY_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dpc_regs[DPC_TMEM_REG] = GETDATA(curr, uint32_t);
|
|
|
|
state->g_dp.dps_regs[DPS_TBIST_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dps_regs[DPS_TEST_MODE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dps_regs[DPS_BUFTEST_ADDR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dps_regs[DPS_BUFTEST_DATA_REG] = GETDATA(curr, uint32_t);
|
|
|
|
COPYARRAY(state->g_rdram, curr, uint32_t, RDRAM_MAX_SIZE/4);
|
|
COPYARRAY(state->g_sp.mem, curr, uint32_t, SP_MEM_SIZE/4);
|
|
COPYARRAY(state->g_si.pif.ram, curr, uint8_t, PIF_RAM_SIZE);
|
|
|
|
/*state->g_pi.use_flashram =*/ (void)GETDATA(curr, int);
|
|
/*state->g_pi.flashram.mode =*/ (void)GETDATA(curr, int);
|
|
/*state->g_pi.flashram.status =*/ (void)GETDATA(curr, unsigned long long);
|
|
/*state->g_pi.flashram.erase_offset =*/ (void)GETDATA(curr, unsigned int);
|
|
/*state->g_pi.flashram.write_pointer =*/ (void)GETDATA(curr, unsigned int);
|
|
|
|
COPYARRAY(state->tlb_LUT_r, curr, unsigned int, 0x100000);
|
|
COPYARRAY(state->tlb_LUT_w, curr, unsigned int, 0x100000);
|
|
|
|
state->llbit = GETDATA(curr, unsigned int);
|
|
COPYARRAY(state->reg, curr, long long int, 32);
|
|
COPYARRAY(state->g_cp0_regs, curr, unsigned int, CP0_REGS_COUNT);
|
|
set_fpr_pointers(state, state->g_cp0_regs[CP0_STATUS_REG]);
|
|
state->lo = GETDATA(curr, long long int);
|
|
state->hi = GETDATA(curr, long long int);
|
|
COPYARRAY(state->reg_cop1_fgr_64, curr, long long int, 32);
|
|
if ((state->g_cp0_regs[CP0_STATUS_REG] & 0x04000000) == 0) // 32-bit FPR mode requires data shuffling because 64-bit layout is always stored in savestate file
|
|
shuffle_fpr_data(state, 0x04000000, 0);
|
|
state->FCR0 = GETDATA(curr, int);
|
|
state->FCR31 = GETDATA(curr, int);
|
|
|
|
for (i = 0; i < 32; i++)
|
|
{
|
|
state->tlb_e[i].mask = GETDATA(curr, short);
|
|
curr += 2;
|
|
state->tlb_e[i].vpn2 = GETDATA(curr, int);
|
|
state->tlb_e[i].g = GETDATA(curr, char);
|
|
state->tlb_e[i].asid = GETDATA(curr, unsigned char);
|
|
curr += 2;
|
|
state->tlb_e[i].pfn_even = GETDATA(curr, int);
|
|
state->tlb_e[i].c_even = GETDATA(curr, char);
|
|
state->tlb_e[i].d_even = GETDATA(curr, char);
|
|
state->tlb_e[i].v_even = GETDATA(curr, char);
|
|
curr++;
|
|
state->tlb_e[i].pfn_odd = GETDATA(curr, int);
|
|
state->tlb_e[i].c_odd = GETDATA(curr, char);
|
|
state->tlb_e[i].d_odd = GETDATA(curr, char);
|
|
state->tlb_e[i].v_odd = GETDATA(curr, char);
|
|
state->tlb_e[i].r = GETDATA(curr, char);
|
|
|
|
state->tlb_e[i].start_even = GETDATA(curr, unsigned int);
|
|
state->tlb_e[i].end_even = GETDATA(curr, unsigned int);
|
|
state->tlb_e[i].phys_even = GETDATA(curr, unsigned int);
|
|
state->tlb_e[i].start_odd = GETDATA(curr, unsigned int);
|
|
state->tlb_e[i].end_odd = GETDATA(curr, unsigned int);
|
|
state->tlb_e[i].phys_odd = GETDATA(curr, unsigned int);
|
|
}
|
|
|
|
#ifdef NEW_DYNAREC
|
|
if (state->r4300emu == CORE_DYNAREC) {
|
|
state->pcaddr = GETDATA(curr, unsigned int);
|
|
state->pending_exception = 1;
|
|
invalidate_all_pages(state);
|
|
} else {
|
|
if(state->r4300emu != CORE_PURE_INTERPRETER)
|
|
{
|
|
for (i = 0; i < 0x100000; i++)
|
|
state->invalid_code[i] = 1;
|
|
}
|
|
generic_jump_to(state, GETDATA(curr, unsigned int)); // PC
|
|
}
|
|
#else
|
|
if(state->r4300emu != CORE_PURE_INTERPRETER)
|
|
{
|
|
for (i = 0; i < 0x100000; i++)
|
|
state->invalid_code[i] = 1;
|
|
}
|
|
generic_jump_to(state, GETDATA(curr, unsigned int)); // PC
|
|
#endif
|
|
|
|
state->next_interupt = GETDATA(curr, unsigned int);
|
|
state->g_vi.next_vi = GETDATA(curr, unsigned int);
|
|
state->g_vi.field = GETDATA(curr, unsigned int);
|
|
|
|
free(savestateData);
|
|
|
|
// assert(savestateData+savestateSize == curr)
|
|
|
|
to_little_endian_buffer(queue, 4, 256);
|
|
load_eventqueue_infos(state, queue);
|
|
|
|
#ifdef NEW_DYNAREC
|
|
if (state->r4300emu == CORE_DYNAREC)
|
|
state->last_addr = state->pcaddr;
|
|
else
|
|
state->last_addr = state->PC->addr;
|
|
#else
|
|
state->last_addr = state->PC->addr;
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int savestates_load_pj64(usf_state_t * state, unsigned char * ptr, unsigned int size)
|
|
{
|
|
char buffer[1024];
|
|
unsigned int vi_timer, SaveRDRAMSize;
|
|
int i;
|
|
#ifdef DYNAREC
|
|
unsigned long long dummy;
|
|
#endif
|
|
|
|
unsigned char header[8];
|
|
|
|
unsigned char * state_ptr = ptr;
|
|
unsigned int state_size = size;
|
|
|
|
size_t savestateSize;
|
|
unsigned char *savestateData = 0, *curr;
|
|
|
|
/* Read and check Project64 magic number. */
|
|
read_bytes(header, 8);
|
|
|
|
curr = header;
|
|
if (memcmp(curr, pj64_magic, 4) != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
curr += 4;
|
|
|
|
SaveRDRAMSize = GETDATA(curr, unsigned int);
|
|
|
|
/* Read the rest of the savestate into memory. */
|
|
savestateSize = SaveRDRAMSize + 0x2754;
|
|
savestateData = curr = malloc(savestateSize);
|
|
if (!savestateData)
|
|
return 0;
|
|
|
|
if (state_size < savestateSize)
|
|
{
|
|
free(savestateData);
|
|
return 0;
|
|
}
|
|
|
|
read_bytes(savestateData, savestateSize);
|
|
|
|
// skip ROM header
|
|
curr += 0x40;
|
|
|
|
// vi_timer
|
|
vi_timer = GETDATA(curr, unsigned int);
|
|
|
|
// Program Counter
|
|
state->last_addr = GETDATA(curr, unsigned int);
|
|
|
|
// GPR
|
|
COPYARRAY(state->reg, curr, long long int, 32);
|
|
|
|
// FPR
|
|
COPYARRAY(state->reg_cop1_fgr_64, curr, long long int, 32);
|
|
|
|
// CP0
|
|
COPYARRAY(state->g_cp0_regs, curr, unsigned int, CP0_REGS_COUNT);
|
|
|
|
set_fpr_pointers(state, state->g_cp0_regs[CP0_STATUS_REG]);
|
|
if ((state->g_cp0_regs[CP0_STATUS_REG] & 0x04000000) == 0) // TODO not sure how pj64 handles this
|
|
shuffle_fpr_data(state, 0x04000000, 0);
|
|
|
|
// Initialze the interupts
|
|
vi_timer += state->g_cp0_regs[CP0_COUNT_REG];
|
|
state->next_interupt = (state->g_cp0_regs[CP0_COMPARE_REG] < vi_timer)
|
|
? state->g_cp0_regs[CP0_COMPARE_REG]
|
|
: vi_timer;
|
|
state->g_vi.next_vi = vi_timer;
|
|
state->g_vi.field = 0;
|
|
*((unsigned int*)&buffer[0]) = VI_INT;
|
|
*((unsigned int*)&buffer[4]) = vi_timer;
|
|
*((unsigned int*)&buffer[8]) = COMPARE_INT;
|
|
*((unsigned int*)&buffer[12]) = state->g_cp0_regs[CP0_COMPARE_REG];
|
|
*((unsigned int*)&buffer[16]) = 0xFFFFFFFF;
|
|
|
|
load_eventqueue_infos(state, buffer);
|
|
|
|
// FPCR
|
|
state->FCR0 = GETDATA(curr, int);
|
|
curr += 30 * 4; // FCR1...FCR30 not supported
|
|
state->FCR31 = GETDATA(curr, int);
|
|
|
|
// hi / lo
|
|
state->hi = GETDATA(curr, long long int);
|
|
state->lo = GETDATA(curr, long long int);
|
|
|
|
// rdram register
|
|
state->g_ri.rdram.regs[RDRAM_CONFIG_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_DEVICE_ID_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_DELAY_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_MODE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_REF_INTERVAL_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_REF_ROW_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_RAS_INTERVAL_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_MIN_INTERVAL_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_ADDR_SELECT_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.rdram.regs[RDRAM_DEVICE_MANUF_REG] = GETDATA(curr, uint32_t);
|
|
|
|
// sp_register
|
|
state->g_sp.regs[SP_MEM_ADDR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs[SP_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs[SP_RD_LEN_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs[SP_WR_LEN_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs[SP_STATUS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs[SP_DMA_FULL_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs[SP_DMA_BUSY_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs[SP_SEMAPHORE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs2[SP_PC_REG] = GETDATA(curr, uint32_t);
|
|
state->g_sp.regs2[SP_IBIST_REG] = GETDATA(curr, uint32_t);
|
|
|
|
// dpc_register
|
|
state->g_dp.dpc_regs[DPC_START_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dpc_regs[DPC_END_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dpc_regs[DPC_CURRENT_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dpc_regs[DPC_STATUS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dpc_regs[DPC_CLOCK_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dpc_regs[DPC_BUFBUSY_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dpc_regs[DPC_PIPEBUSY_REG] = GETDATA(curr, uint32_t);
|
|
state->g_dp.dpc_regs[DPC_TMEM_REG] = GETDATA(curr, uint32_t);
|
|
(void)GETDATA(curr, unsigned int); // Dummy read
|
|
(void)GETDATA(curr, unsigned int); // Dummy read
|
|
|
|
// mi_register
|
|
state->g_r4300.mi.regs[MI_INIT_MODE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_r4300.mi.regs[MI_VERSION_REG] = GETDATA(curr, uint32_t);
|
|
state->g_r4300.mi.regs[MI_INTR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_r4300.mi.regs[MI_INTR_MASK_REG] = GETDATA(curr, uint32_t);
|
|
|
|
// vi_register
|
|
state->g_vi.regs[VI_STATUS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_ORIGIN_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_WIDTH_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_V_INTR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_CURRENT_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_BURST_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_V_SYNC_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_H_SYNC_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_LEAP_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_H_START_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_V_START_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_V_BURST_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_X_SCALE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.regs[VI_Y_SCALE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_vi.delay = (state->g_vi.regs[VI_V_SYNC_REG] == 0)
|
|
? 500000
|
|
: (state->g_vi.regs[VI_V_SYNC_REG] + 1)*1500;
|
|
|
|
// ai_register
|
|
state->g_ai.regs[AI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ai.regs[AI_LEN_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ai.regs[AI_CONTROL_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ai.regs[AI_STATUS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ai.regs[AI_DACRATE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ai.regs[AI_BITRATE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ai.samples_format_changed = 1;
|
|
// XXX USF
|
|
state->g_ai.regs[AI_STATUS_REG] = 0;
|
|
|
|
// pi_register
|
|
state->g_pi.regs[PI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_CART_ADDR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_RD_LEN_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_WR_LEN_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_STATUS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM1_LAT_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM1_PWD_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM1_PGS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM1_RLS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM2_LAT_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM2_PWD_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM2_PGS_REG] = GETDATA(curr, uint32_t);
|
|
state->g_pi.regs[PI_BSD_DOM2_RLS_REG] = GETDATA(curr, uint32_t);
|
|
|
|
// ri_register
|
|
state->g_ri.regs[RI_MODE_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_CONFIG_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_CURRENT_LOAD_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_SELECT_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_REFRESH_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_LATENCY_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_ERROR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_ri.regs[RI_WERROR_REG] = GETDATA(curr, uint32_t);
|
|
|
|
// si_register
|
|
state->g_si.regs[SI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t);
|
|
state->g_si.regs[SI_PIF_ADDR_RD64B_REG] = GETDATA(curr, uint32_t);
|
|
state->g_si.regs[SI_PIF_ADDR_WR64B_REG] = GETDATA(curr, uint32_t);
|
|
state->g_si.regs[SI_STATUS_REG] = GETDATA(curr, uint32_t);
|
|
|
|
// tlb
|
|
memset(state->tlb_LUT_r, 0, 0x400000);
|
|
memset(state->tlb_LUT_w, 0, 0x400000);
|
|
for (i=0; i < 32; i++)
|
|
{
|
|
unsigned int MyPageMask, MyEntryHi, MyEntryLo0, MyEntryLo1;
|
|
|
|
(void)GETDATA(curr, unsigned int); // Dummy read - EntryDefined
|
|
MyPageMask = GETDATA(curr, unsigned int);
|
|
MyEntryHi = GETDATA(curr, unsigned int);
|
|
MyEntryLo0 = GETDATA(curr, unsigned int);
|
|
MyEntryLo1 = GETDATA(curr, unsigned int);
|
|
|
|
// This is copied from TLBWI instruction
|
|
state->tlb_e[i].g = (MyEntryLo0 & MyEntryLo1 & 1);
|
|
state->tlb_e[i].pfn_even = (MyEntryLo0 & 0x3FFFFFC0) >> 6;
|
|
state->tlb_e[i].pfn_odd = (MyEntryLo1 & 0x3FFFFFC0) >> 6;
|
|
state->tlb_e[i].c_even = (MyEntryLo0 & 0x38) >> 3;
|
|
state->tlb_e[i].c_odd = (MyEntryLo1 & 0x38) >> 3;
|
|
state->tlb_e[i].d_even = (MyEntryLo0 & 0x4) >> 2;
|
|
state->tlb_e[i].d_odd = (MyEntryLo1 & 0x4) >> 2;
|
|
state->tlb_e[i].v_even = (MyEntryLo0 & 0x2) >> 1;
|
|
state->tlb_e[i].v_odd = (MyEntryLo1 & 0x2) >> 1;
|
|
state->tlb_e[i].asid = (MyEntryHi & 0xFF);
|
|
state->tlb_e[i].vpn2 = (MyEntryHi & 0xFFFFE000) >> 13;
|
|
//state->tlb_e[i].r = (MyEntryHi & 0xC000000000000000LL) >> 62;
|
|
state->tlb_e[i].mask = (MyPageMask & 0x1FFE000) >> 13;
|
|
|
|
state->tlb_e[i].start_even = state->tlb_e[i].vpn2 << 13;
|
|
state->tlb_e[i].end_even = state->tlb_e[i].start_even+
|
|
(state->tlb_e[i].mask << 12) + 0xFFF;
|
|
state->tlb_e[i].phys_even = state->tlb_e[i].pfn_even << 12;
|
|
|
|
state->tlb_e[i].start_odd = state->tlb_e[i].end_even+1;
|
|
state->tlb_e[i].end_odd = state->tlb_e[i].start_odd+
|
|
(state->tlb_e[i].mask << 12) + 0xFFF;
|
|
state->tlb_e[i].phys_odd = state->tlb_e[i].pfn_odd << 12;
|
|
|
|
tlb_map(state, &state->tlb_e[i]);
|
|
}
|
|
|
|
// pif ram
|
|
COPYARRAY(state->g_si.pif.ram, curr, uint8_t, PIF_RAM_SIZE);
|
|
|
|
// RDRAM
|
|
memset(state->g_rdram, 0, RDRAM_MAX_SIZE);
|
|
COPYARRAY(state->g_rdram, curr, uint32_t, SaveRDRAMSize/4);
|
|
|
|
// DMEM + IMEM
|
|
COPYARRAY(state->g_sp.mem, curr, uint32_t, SP_MEM_SIZE/4);
|
|
|
|
// The following values should not matter because we don't have any AI interrupt
|
|
// g_ai.fifo[1].delay = 0; g_ai.fifo[1].length = 0;
|
|
// g_ai.fifo[0].delay = 0; g_ai.fifo[0].length = 0;
|
|
|
|
// The following is not available in PJ64 savestate. Keep the values as is.
|
|
// g_dp.dps_regs[DPS_TBIST_REG] = 0; g_dp.dps_regs[DPS_TEST_MODE_REG] = 0;
|
|
// g_dp.dps_regs[DPS_BUFTEST_ADDR_REG] = 0; g_dp.dps_regs[DPS_BUFTEST_DATA_REG] = 0; llbit = 0;
|
|
|
|
// No flashram info in pj64 savestate.
|
|
//init_flashram(&state->g_pi.flashram);
|
|
|
|
open_rom_header(state, savestateData, sizeof(m64p_rom_header));
|
|
|
|
#ifdef NEW_DYNAREC
|
|
if (state->r4300emu == CORE_DYNAREC) {
|
|
state->pcaddr = state->last_addr;
|
|
state->pending_exception = 1;
|
|
invalidate_all_pages(state);
|
|
} else {
|
|
if(state->r4300emu != CORE_PURE_INTERPRETER)
|
|
{
|
|
for (i = 0; i < 0x100000; i++)
|
|
state->invalid_code[i] = 1;
|
|
}
|
|
generic_jump_to(state, state->last_addr);
|
|
}
|
|
#else
|
|
if(state->r4300emu != CORE_PURE_INTERPRETER)
|
|
{
|
|
for (i = 0; i < 0x100000; i++)
|
|
state->invalid_code[i] = 1;
|
|
}
|
|
#ifdef DYNAREC
|
|
*(void **)&state->return_address = (void *)&dummy;
|
|
#endif
|
|
generic_jump_to(state, state->last_addr);
|
|
#ifdef DYNAREC
|
|
*(void **)&state->return_address = (void *)0;
|
|
#endif
|
|
#endif
|
|
|
|
// assert(savestateData+savestateSize == curr)
|
|
|
|
free(savestateData);
|
|
return 1;
|
|
}
|
|
|
|
int savestates_load(usf_state_t * state, unsigned char * ptr, unsigned int size, unsigned int is_m64p)
|
|
{
|
|
if (is_m64p)
|
|
return savestates_load_m64p(state, ptr, size);
|
|
else
|
|
return savestates_load_pj64(state, ptr, size);
|
|
}
|