mupen64plus-oldsvn/main/savestates.c

765 lines
28 KiB
C

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - savestates.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* 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 <zlib.h>
#include "savestates.h"
#include "main.h"
#include "translate.h"
#include "rom.h"
#include "util.h"
#include "config.h"
#include "../memory/memory.h"
#include "../memory/flashram.h"
#include "../r4300/r4300.h"
#include "../r4300/interupt.h"
#include "../opengl/osd.h"
#include "zip/unzip.h"
#include "zip/zip.h"
const char* savestate_magic = "M64+SAVE";
const int savestate_version = 0x00010000; /* 1.0 */
const int pj64_magic = 0x23D8A6C8;
extern unsigned int interp_addr;
int savestates_job = 0;
static unsigned int slot = 0;
static int autoinc_save_slot = 0;
static char fname[1024] = {0};
void savestates_select_slot(unsigned int s)
{
if(s<0||s>9||s==slot)
return;
slot = s;
config_put_number("CurrentSaveSlot", s);
if(rom)
{
char* filename = savestates_get_filename();
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("Selected state file: %s"), filename);
free(filename);
}
else
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("Selected state slot: %d"), slot);
}
/* Returns the currently selected save slot. */
unsigned int savestates_get_slot(void)
{
return slot;
}
/* Sets save state slot autoincrement on or off. */
void savestates_set_autoinc_slot(int b)
{
autoinc_save_slot = b;
}
/* Returns save state slot autoincrement on or off. */
int savestates_get_autoinc_slot(void)
{
return autoinc_save_slot != 0;
}
void savestates_inc_slot(void)
{
if(++slot>9)
slot = 0;
}
void savestates_select_filename(const char* fn)
{
if(strlen((char*)fn)>=1024)
return;
strcpy(fname, fn);
}
char* savestates_get_filename()
{
size_t length;
length = strlen(ROM_SETTINGS.goodname)+4+1;
char* filename = (char*)malloc(length);
snprintf(filename, length, "%s.st%d", ROM_SETTINGS.goodname, slot);
return filename;
}
char* savestates_get_pj64_filename()
{
size_t length;
length = strlen((char*)ROM_HEADER->nom)+8+1;
char* filename = (char*)malloc(length);
snprintf(filename, length, "%s.pj%d.zip", (char*)ROM_HEADER->nom, slot);
return filename;
}
void savestates_save()
{
char *filename, *file, buffer[1024];
unsigned char outbuf[4];
gzFile f;
size_t length;
int queuelength;
if(autoinc_save_slot)
savestates_inc_slot();
if(fname[0]!=0) /* A specific filename was given. */
{
file = malloc(strlen(fname)+1);
filename = malloc(strlen(fname)+1);
strcpy(file, fname);
char *handle = dirfrompath(file);
strcpy(filename, fname+strlen(handle));
free(handle);
fname[0] = 0;
}
else
{
filename = savestates_get_filename();
length = strlen(get_savespath())+strlen(filename)+1;
file = malloc(length);
snprintf(file, length, "%s%s", get_savespath(), filename);
}
f = gzopen(file, "wb");
free(file);
/* Write magic number. */
gzwrite(f, savestate_magic, 8);
/* Write savestate file version in big-endian. */
outbuf[0] = (savestate_version >> 24) & 0xff;
outbuf[1] = (savestate_version >> 16) & 0xff;
outbuf[2] = (savestate_version >> 8) & 0xff;
outbuf[3] = (savestate_version >> 0) & 0xff;
gzwrite(f, outbuf, 4);
gzwrite(f, ROM_SETTINGS.MD5, 32);
gzwrite(f, &rdram_register, sizeof(RDRAM_register));
gzwrite(f, &MI_register, sizeof(mips_register));
gzwrite(f, &pi_register, sizeof(PI_register));
gzwrite(f, &sp_register, sizeof(SP_register));
gzwrite(f, &rsp_register, sizeof(RSP_register));
gzwrite(f, &si_register, sizeof(SI_register));
gzwrite(f, &vi_register, sizeof(VI_register));
gzwrite(f, &ri_register, sizeof(RI_register));
gzwrite(f, &ai_register, sizeof(AI_register));
gzwrite(f, &dpc_register, sizeof(DPC_register));
gzwrite(f, &dps_register, sizeof(DPS_register));
gzwrite(f, rdram, 0x800000);
gzwrite(f, SP_DMEM, 0x1000);
gzwrite(f, SP_IMEM, 0x1000);
gzwrite(f, PIF_RAM, 0x40);
save_flashram_infos(buffer);
gzwrite(f, buffer, 24);
gzwrite(f, tlb_LUT_r, 0x100000*4);
gzwrite(f, tlb_LUT_w, 0x100000*4);
gzwrite(f, &llbit, 4);
gzwrite(f, reg, 32*8);
gzwrite(f, reg_cop0, 32*4);
gzwrite(f, &lo, 8);
gzwrite(f, &hi, 8);
gzwrite(f, reg_cop1_fgr_64, 32*8);
gzwrite(f, &FCR0, 4);
gzwrite(f, &FCR31, 4);
gzwrite(f, tlb_e, 32*sizeof(tlb));
if(!dynacore&&interpcore)
gzwrite(f, &interp_addr, 4);
else
gzwrite(f, &PC->addr, 4);
gzwrite(f, &next_interupt, 4);
gzwrite(f, &next_vi, 4);
gzwrite(f, &vi_field, 4);
queuelength = save_eventqueue_infos(buffer);
gzwrite(f, buffer, queuelength);
gzclose(f);
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("Saved state to: %s"), filename);
free(filename);
}
void savestates_load()
{
char *filename, *file, buffer[1024];
unsigned char inbuf[4];
gzFile f;
size_t length;
int queuelength, i;
if(fname[0]!=0) /* A specific filename was given. */
{
file = malloc(strlen(fname)+1);
filename = malloc(strlen(fname)+1);
strcpy(file, fname);
char *handle = dirfrompath(file);
strcpy(filename, fname+strlen(handle));
free(handle);
}
else
{
filename = savestates_get_filename();
length = strlen(get_savespath())+strlen(filename)+1;
file = malloc(length);
snprintf(file, length, "%s%s", get_savespath(), filename);
}
f = gzopen(file, "rb");
free(file);
if(f==NULL)
{
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("Could not open state file: %s"), filename);
free(filename);
return;
}
/* Read and check Mupen64Plus magic number. */
gzread(f, buffer, 8);
if(strncmp(buffer, savestate_magic, 8)!=0)
{
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("State file: %s is not a valid Mupen64plus savestate. Checking if in Project64 format..."), filename);
free(filename);
gzclose(f);
savestates_load_pj64();
return;
}
fname[0] = 0;
/* Read savestate file version in big-endian order. */
gzread(f, inbuf, 4);
i = inbuf[0];
i = (i << 8) | inbuf[1];
i = (i << 8) | inbuf[2];
i = (i << 8) | inbuf[3];
if(i!=savestate_version)
{
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("State version (%08x) doesn't match current version (%08x)."), i, savestate_version);
free(filename);
gzclose(f);
return;
}
gzread(f, buffer, 32);
if(memcmp(buffer, ROM_SETTINGS.MD5, 32))
{
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("State ROM MD5 does not match current ROM."));
free(filename);
gzclose(f);
return;
}
gzread(f, &rdram_register, sizeof(RDRAM_register));
gzread(f, &MI_register, sizeof(mips_register));
gzread(f, &pi_register, sizeof(PI_register));
gzread(f, &sp_register, sizeof(SP_register));
gzread(f, &rsp_register, sizeof(RSP_register));
gzread(f, &si_register, sizeof(SI_register));
gzread(f, &vi_register, sizeof(VI_register));
gzread(f, &ri_register, sizeof(RI_register));
gzread(f, &ai_register, sizeof(AI_register));
gzread(f, &dpc_register, sizeof(DPC_register));
gzread(f, &dps_register, sizeof(DPS_register));
gzread(f, rdram, 0x800000);
gzread(f, SP_DMEM, 0x1000);
gzread(f, SP_IMEM, 0x1000);
gzread(f, PIF_RAM, 0x40);
gzread(f, buffer, 24);
load_flashram_infos(buffer);
gzread(f, tlb_LUT_r, 0x100000*4);
gzread(f, tlb_LUT_w, 0x100000*4);
gzread(f, &llbit, 4);
gzread(f, reg, 32*8);
gzread(f, reg_cop0, 32*4);
gzread(f, &lo, 8);
gzread(f, &hi, 8);
gzread(f, reg_cop1_fgr_64, 32*8);
gzread(f, &FCR0, 4);
gzread(f, &FCR31, 4);
gzread(f, tlb_e, 32*sizeof(tlb));
if(!dynacore&&interpcore)
gzread(f, &interp_addr, 4);
else
{
int i;
gzread(f, &queuelength, 4);
for (i = 0; i < 0x100000; i++)
invalid_code[i] = 1;
jump_to(queuelength);
}
gzread(f, &next_interupt, 4);
gzread(f, &next_vi, 4);
gzread(f, &vi_field, 4);
queuelength = 0;
while(1)
{
gzread(f, buffer+queuelength, 4);
if(*((unsigned int*)&buffer[queuelength])==0xFFFFFFFF)
break;
gzread(f, buffer+queuelength+4, 4);
queuelength += 8;
}
load_eventqueue_infos(buffer);
gzclose(f);
if(!dynacore&&interpcore)
last_addr = interp_addr;
else
last_addr = PC->addr;
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("State loaded from: %s"), filename);
free(filename);
fname[0] = 0;
}
int savestates_save_pj64()
{
char *file, *filename;
unsigned int i, vi_timer, addr;
size_t length;
TLB_pj64 tlb_pj64[32];
zipFile zipfile;
zip_fileinfo zipfi;
unsigned int dummy = 0;
unsigned int SaveRDRAMSize = 0x800000;
/* Continue only if VI / COMPARE
Otherwise try again in a little while. */
if (get_next_event_type() > COMPARE_INT)
{ return -1; }
if(fname[0]!=0) /* A specific filename was given. */
{
file = malloc(strlen(fname)+1);
filename = malloc(strlen(fname)+1);
strcpy(file, fname);
char *handle = dirfrompath(file);
strcpy(filename, fname+strlen(handle));
free(handle);
}
else
{
filename = savestates_get_pj64_filename();
length = strlen(get_savespath())+strlen(filename)+1;
file = malloc(length);
snprintf(file, length, "%s%s", get_savespath(), filename);
}
zipfile = zipOpen(file, APPEND_STATUS_CREATE);
free(file);
if(zipfile==NULL)
{
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("Could not create PJ64 state file: %s"), filename);
free(filename);
return -2;
}
int retval = zipOpenNewFileInZip(zipfile, filename, &zipfi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
if(retval!=ZIP_OK)
{
zipClose(zipfile, "");
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("Zip error. Could not create state file: %s"), filename);
free(filename);
return -3;
}
vi_timer = get_event(VI_INT) - reg_cop0[9]; /* Subtract current Count according to how PJ64 stores the timer. */
if(!dynacore&&interpcore)
addr = interp_addr;
else
addr = PC->addr;
for (i=0; i < 32;i++)
{
tlb_pj64[i].BreakDownPageMask.Mask = (unsigned int) tlb_e[i].mask;
tlb_pj64[i].BreakDownEntryHi.VPN2 = (unsigned int) tlb_e[i].vpn2;
tlb_pj64[i].BreakDownEntryLo0.GLOBAL = (unsigned int) tlb_e[i].g;
tlb_pj64[i].BreakDownEntryLo1.GLOBAL = (unsigned int) tlb_e[i].g;
tlb_pj64[i].BreakDownEntryHi.ASID = (unsigned int) tlb_e[i].asid;
tlb_pj64[i].BreakDownEntryLo0.PFN = (unsigned int) tlb_e[i].pfn_even;
tlb_pj64[i].BreakDownEntryLo0.C = (unsigned int) tlb_e[i].c_even;
tlb_pj64[i].BreakDownEntryLo0.D = (unsigned int) tlb_e[i].d_even;
tlb_pj64[i].BreakDownEntryLo0.V = (unsigned int) tlb_e[i].v_even;
tlb_pj64[i].BreakDownEntryLo1.PFN = (unsigned int) tlb_e[i].pfn_odd;
tlb_pj64[i].BreakDownEntryLo1.C = (unsigned int) tlb_e[i].c_odd;
tlb_pj64[i].BreakDownEntryLo1.D = (unsigned int) tlb_e[i].d_odd;
tlb_pj64[i].BreakDownEntryLo1.V = (unsigned int) tlb_e[i].v_odd;
}
length = zipWriteInFileInZip(zipfile, &pj64_magic, 4);
length = zipWriteInFileInZip(zipfile, &SaveRDRAMSize, 4);
length = zipWriteInFileInZip(zipfile, rom, 0x40);
length = zipWriteInFileInZip(zipfile, &vi_timer, 4);
length = zipWriteInFileInZip(zipfile, &addr, 4);
length = zipWriteInFileInZip(zipfile, reg, 32*8);
length = zipWriteInFileInZip(zipfile, reg_cop1_fgr_64, 32*8);
length = zipWriteInFileInZip(zipfile, reg_cop0, 32*4);
length = zipWriteInFileInZip(zipfile, &FCR0, 4);
length = zipWriteInFileInZip(zipfile, &dummy, 4*30);
length = zipWriteInFileInZip(zipfile, &FCR31, 4);
length = zipWriteInFileInZip(zipfile, &hi, 8);
length = zipWriteInFileInZip(zipfile, &lo, 8);
length = zipWriteInFileInZip(zipfile, &rdram_register, sizeof(RDRAM_register));
length = zipWriteInFileInZip(zipfile, &sp_register.sp_mem_addr_reg, 4);
length = zipWriteInFileInZip(zipfile, &sp_register.sp_dram_addr_reg, 4);
length = zipWriteInFileInZip(zipfile, &sp_register.sp_rd_len_reg, 4);
length = zipWriteInFileInZip(zipfile, &sp_register.sp_wr_len_reg, 4);
length = zipWriteInFileInZip(zipfile, &sp_register.sp_status_reg, 4);
length = zipWriteInFileInZip(zipfile, &sp_register.sp_dma_full_reg, 4);
length = zipWriteInFileInZip(zipfile, &sp_register.sp_dma_busy_reg, 4);
length = zipWriteInFileInZip(zipfile, &sp_register.sp_semaphore_reg, 4);
length = zipWriteInFileInZip(zipfile, &dummy, 4); // SP_PC_REG
length = zipWriteInFileInZip(zipfile, &dummy, 4); // SP_IBIST_REG
length = zipWriteInFileInZip(zipfile, &dpc_register.dpc_start, 4);
length = zipWriteInFileInZip(zipfile, &dpc_register.dpc_end, 4);
length = zipWriteInFileInZip(zipfile, &dpc_register.dpc_current, 4);
length = zipWriteInFileInZip(zipfile, &dpc_register.dpc_status, 4);
length = zipWriteInFileInZip(zipfile, &dpc_register.dpc_clock, 4);
length = zipWriteInFileInZip(zipfile, &dpc_register.dpc_bufbusy, 4);
length = zipWriteInFileInZip(zipfile, &dpc_register.dpc_pipebusy, 4);
length = zipWriteInFileInZip(zipfile, &dpc_register.dpc_tmem, 4);
length = zipWriteInFileInZip(zipfile, &dummy, 4); // ?
length = zipWriteInFileInZip(zipfile, &dummy, 4); // ?
length = zipWriteInFileInZip(zipfile, &MI_register.mi_init_mode_reg, 4); //TODO Secial handling in pj64
length = zipWriteInFileInZip(zipfile, &MI_register.mi_version_reg, 4);
length = zipWriteInFileInZip(zipfile, &MI_register.mi_intr_reg, 4);
length = zipWriteInFileInZip(zipfile, &MI_register.mi_intr_mask_reg, 4);
length = zipWriteInFileInZip(zipfile, &vi_register, 4*14);
length = zipWriteInFileInZip(zipfile, &ai_register, 4*6);
length = zipWriteInFileInZip(zipfile, &pi_register, sizeof(PI_register));
length = zipWriteInFileInZip(zipfile, &ri_register, sizeof(RI_register));
length = zipWriteInFileInZip(zipfile, &si_register, sizeof(SI_register));
length = zipWriteInFileInZip(zipfile, tlb_pj64, sizeof(TLB_pj64)*32);
length = zipWriteInFileInZip(zipfile, PIF_RAM, 0x40);
length = zipWriteInFileInZip(zipfile, rdram, 0x800000);
length = zipWriteInFileInZip(zipfile, SP_DMEM, 0x1000);
length = zipWriteInFileInZip(zipfile, SP_IMEM, 0x1000);
zipCloseFileInZip(zipfile);
zipClose(zipfile, "");
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("Saved state to: %s"), filename);
free(filename);
return 1;
}
void savestates_load_pj64()
{
char *file, *filename, buffer[1024], RomHeader[64], szFileName[256], szExtraField[256], szComment[256];
unsigned int magic, value, vi_timer, SaveRDRAMSize;
int queuelength, i;
size_t length;
unzFile zipstatefile;
unz_file_info fileinfo;
if(fname[0]!=0) /* A specific filename was given. */
{
file = malloc(strlen(fname)+1);
filename = malloc(strlen(fname)+1);
strcpy(file, fname);
char *handle = dirfrompath(file);
strcpy(filename, fname+strlen(handle));
free(handle);
}
else
{
filename = savestates_get_pj64_filename();
length = strlen(get_savespath())+strlen(filename)+1;
file = malloc(length);
snprintf(file, length, "%s%s", get_savespath(), filename);
}
zipstatefile = unzOpen(file); /*Open the .zip file. */
unsigned char exit = 1;
if(zipstatefile!=NULL)
{
if(unzGoToFirstFile(zipstatefile)==UNZ_OK)
{
if(unzGetCurrentFileInfo(zipstatefile, &fileinfo, szFileName, 255, szExtraField, 255, szComment, 255)==UNZ_OK)
{
if(unzOpenCurrentFile(zipstatefile)==UNZ_OK)
{
if(fileinfo.uncompressed_size>=4)
exit = 0;
}
}
}
}
if(exit)
{
unzClose(zipstatefile);
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("Zip error. Could not open state file: %s"), file);
free(file);
return;
}
/* Read and check Project64 magic number. */
unzReadCurrentFile(zipstatefile, &magic, 4);
if (magic!=pj64_magic)
{
unzClose(zipstatefile);
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("State file: %s is not a valid Project64 savestate. Unrecognized file format."), file);
free(file);
return;
}
unzReadCurrentFile(zipstatefile, &SaveRDRAMSize, 4);
unzReadCurrentFile(zipstatefile, RomHeader, 0x40);
if(memcmp(RomHeader, rom, 0x40)!=0)
{
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("State ROM header does not match current ROM."));
unzClose(zipstatefile);
free(file);
return;
}
// vi_timer
unzReadCurrentFile(zipstatefile, &vi_timer,4);
// Program Counter
if(!dynacore&&interpcore)
unzReadCurrentFile(zipstatefile, &interp_addr,4);
else
{
unzReadCurrentFile(zipstatefile, &queuelength,4);
for (i = 0; i < 0x100000; i++)
{ invalid_code[i] = 1; }
jump_to(queuelength);
}
// GPR
unzReadCurrentFile(zipstatefile, reg,8*32);
// FPR
unzReadCurrentFile(zipstatefile, reg_cop1_fgr_64,8*32);
// CP0
unzReadCurrentFile(zipstatefile, reg_cop0, 4*32);
// Initialze the interupts
vi_timer += reg_cop0[9]; // Add current Count
next_interupt = vi_timer;
next_vi = vi_timer;
vi_field = 0;
*((unsigned int*)&buffer[0]) = VI_INT;
*((unsigned int*)&buffer[4]) = vi_timer;
*((unsigned int*)&buffer[8]) = 0xFFFFFFFF;
load_eventqueue_infos(buffer);
// FPCR
unzReadCurrentFile(zipstatefile, &FCR0,4);
unzReadCurrentFile(zipstatefile, &buffer,120); // Dummy read.
unzReadCurrentFile(zipstatefile, &FCR31,4);
// hi / lo
unzReadCurrentFile(zipstatefile,&hi,8);
unzReadCurrentFile(zipstatefile,&lo,8);
// rdram register
unzReadCurrentFile(zipstatefile, &rdram_register, sizeof(RDRAM_register));
// sp_register
unzReadCurrentFile(zipstatefile, &sp_register.sp_mem_addr_reg, 4);
unzReadCurrentFile(zipstatefile, &sp_register.sp_dram_addr_reg, 4);
unzReadCurrentFile(zipstatefile, &sp_register.sp_rd_len_reg, 4);
unzReadCurrentFile(zipstatefile, &sp_register.sp_wr_len_reg, 4);
unzReadCurrentFile(zipstatefile, &sp_register.w_sp_status_reg, 4);
unzReadCurrentFile(zipstatefile, &sp_register.sp_dma_full_reg, 4);
unzReadCurrentFile(zipstatefile, &sp_register.sp_dma_busy_reg, 4);
unzReadCurrentFile(zipstatefile, &sp_register.sp_semaphore_reg, 4);
unzReadCurrentFile(zipstatefile, &value, 4); // SP_PC_REG -> Not part of mupen savestate. Dummy read.
unzReadCurrentFile(zipstatefile, &value, 4); // SP_IBIST_REG -> Not part of mupen savestate. Dummy read.
update_SP();
// dpc_register
unzReadCurrentFile(zipstatefile, &dpc_register.dpc_start, 4);
unzReadCurrentFile(zipstatefile, &dpc_register.dpc_end, 4);
unzReadCurrentFile(zipstatefile, &dpc_register.dpc_current, 4);
unzReadCurrentFile(zipstatefile, &dpc_register.w_dpc_status, 4);
unzReadCurrentFile(zipstatefile, &dpc_register.dpc_clock, 4);
unzReadCurrentFile(zipstatefile, &dpc_register.dpc_bufbusy, 4);
unzReadCurrentFile(zipstatefile, &dpc_register.dpc_pipebusy, 4);
unzReadCurrentFile(zipstatefile, &dpc_register.dpc_tmem, 4);
unzReadCurrentFile(zipstatefile, &value, 4); // Dummy read
unzReadCurrentFile(zipstatefile, &value, 4); // Dummy read
update_DPC();
// mi_register
unzReadCurrentFile(zipstatefile, &MI_register.w_mi_init_mode_reg, 4);
unzReadCurrentFile(zipstatefile, &MI_register.mi_version_reg, 4);
unzReadCurrentFile(zipstatefile, &MI_register.mi_intr_reg, 4);
unzReadCurrentFile(zipstatefile, &MI_register.w_mi_intr_mask_reg, 4);
update_MI_intr_mask_reg();
update_MI_init_mode_reg();
// vi_register
unzReadCurrentFile(zipstatefile, &vi_register, 4*14);
// ai_register
unzReadCurrentFile(zipstatefile, &ai_register, 4*6);
// TODO: Not avialable in PJ64 savestate
// ai_register.next_delay = 0; ai_register.next_len = 0;
// ai_register.current_delay = 0;//804629; ai_register.current_len = 0;
// pi_register
unzReadCurrentFile(zipstatefile, &pi_register, sizeof(PI_register));
// ri_register
unzReadCurrentFile(zipstatefile, &ri_register, sizeof(RI_register));
// si_register
unzReadCurrentFile(zipstatefile, &si_register, sizeof(SI_register));
// tlb
memset(tlb_LUT_r, 0, 0x400000);
memset(tlb_LUT_w, 0, 0x400000);
TLB_pj64 tlb_pj64;
for (i=0; i < 32; i++)
{
unsigned int j;
unzReadCurrentFile(zipstatefile, &tlb_pj64, sizeof(TLB_pj64));
tlb_e[i].mask = (short) tlb_pj64.BreakDownPageMask.Mask;
tlb_e[i].vpn2 = tlb_pj64.BreakDownEntryHi.VPN2;
tlb_e[i].g = (char) tlb_pj64.BreakDownEntryLo0.GLOBAL & tlb_pj64.BreakDownEntryLo1.GLOBAL;
tlb_e[i].asid = (unsigned char) tlb_pj64.BreakDownEntryHi.ASID;
tlb_e[i].pfn_even = tlb_pj64.BreakDownEntryLo0.PFN;
tlb_e[i].c_even = (char) tlb_pj64.BreakDownEntryLo0.C;
tlb_e[i].d_even = (char) tlb_pj64.BreakDownEntryLo0.D;
tlb_e[i].v_even = (char) tlb_pj64.BreakDownEntryLo0.V;
tlb_e[i].pfn_odd = tlb_pj64.BreakDownEntryLo1.PFN;
tlb_e[i].c_odd = (char) tlb_pj64.BreakDownEntryLo1.C;
tlb_e[i].d_odd = (char) tlb_pj64.BreakDownEntryLo1.D;
tlb_e[i].v_odd = (char) tlb_pj64.BreakDownEntryLo1.V;
// This is copied from TLBWI instruction
// tlb_e[i].r = 0;
tlb_e[i].start_even = (unsigned int) tlb_e[i].vpn2 << 13;
tlb_e[i].end_even = (unsigned int) tlb_e[i].start_even + (tlb_e[i].mask << 12) + 0xFFF;
tlb_e[i].phys_even = (unsigned int) tlb_e[i].pfn_even << 12;;
tlb_e[i].start_odd = (unsigned int) tlb_e[i].end_even + 1;
tlb_e[i].end_odd = (unsigned int) tlb_e[i].start_odd + (tlb_e[i].mask << 12) + 0xFFF;;
tlb_e[i].phys_odd = (unsigned int) tlb_e[i].pfn_odd << 12;
if (tlb_e[i].v_even)
{
if (tlb_e[i].start_even < tlb_e[i].end_even &&
!(tlb_e[i].start_even >= 0x80000000 && tlb_e[i].end_even < 0xC0000000) &&
tlb_e[i].phys_even < 0x20000000)
{
for (j=tlb_e[i].start_even;j<tlb_e[i].end_even;j++)
tlb_LUT_r[j>>12] = 0x80000000 | (tlb_e[i].phys_even +
(j - tlb_e[i].start_even));
if (tlb_e[i].d_even)
for (j=tlb_e[i].start_even;j<tlb_e[i].end_even;j++)
tlb_LUT_w[j>>12] = 0x80000000 | (tlb_e[i].phys_even + (j - tlb_e[i].start_even));
}
for (j=tlb_e[i].start_even>>12; j<=tlb_e[i].end_even>>12; j++)
{
if(blocks[j] && blocks[j]->adler32)
{
if(blocks[j]->adler32 ==
adler32(0,(const Bytef*)&rdram[(tlb_LUT_r[j]&0x7FF000)/4],0x1000))
invalid_code[j] = 0;
}
}
}
if (tlb_e[i].v_odd)
{
if (tlb_e[i].start_odd < tlb_e[i].end_odd &&
!(tlb_e[i].start_odd >= 0x80000000 &&
tlb_e[i].end_odd < 0xC0000000) &&
tlb_e[i].phys_odd < 0x20000000)
{
for (j=tlb_e[i].start_odd;j<tlb_e[i].end_odd;j++)
tlb_LUT_r[j>>12] = 0x80000000 | (tlb_e[i].phys_odd + (j - tlb_e[i].start_odd));
if (tlb_e[i].d_odd)
for (j=tlb_e[i].start_odd;j<tlb_e[i].end_odd;j++)
tlb_LUT_w[j>>12] = 0x80000000 | (tlb_e[i].phys_odd + (j - tlb_e[i].start_odd));
}
for (j=tlb_e[i].start_odd>>12; j<=tlb_e[i].end_odd>>12; j++)
{
if(blocks[j] && blocks[j]->adler32)
{
if(blocks[j]->adler32 == adler32(0,(const Bytef*)&rdram[(tlb_LUT_r[j]&0x7FF000)/4],0x1000))
invalid_code[j] = 0;
}
}
}
}
// pif ram
unzReadCurrentFile(zipstatefile, PIF_RAM, 0x40);
// RDRAM
memset(rdram, 0, 0x800000);
unzReadCurrentFile(zipstatefile, rdram, SaveRDRAMSize);
// DMEM
unzReadCurrentFile(zipstatefile, SP_DMEM, 0x1000);
// IMEM
unzReadCurrentFile(zipstatefile, SP_IMEM, 0x1000);
// TODO: The following is not available in PJ64 savestate. Keep the values as is.
// rsp_register.rsp_pc = 0; rsp_register.rsp_ibist = 0; dps_register.dps_tbist = 0; dps_register.dps_test_mode = 0;
// dps_register.dps_buftest_addr = 0; dps_register.dps_buftest_data = 0; llbit = 0;
// No flashram info in pj64 savestate.
init_flashram();
unzClose(zipstatefile);
if(!dynacore&&interpcore)
last_addr = interp_addr;
else
last_addr = PC->addr;
main_message(1, 1, 1, OSD_BOTTOM_LEFT, tr("State loaded from: %s"), filename);
free(filename);
fname[0] = 0;
}