add save states

This commit is contained in:
Sven 2018-09-02 09:49:23 -04:00
parent a8711e2cf2
commit daae7c8e68
34 changed files with 2577 additions and 381 deletions

5
.gitignore vendored
View File

@ -35,6 +35,11 @@ reicast-ios.xccheckout
shell/linux/.map shell/linux/.map
shell/linux/nosym-reicast.elf shell/linux/nosym-reicast.elf
shell/linux/reicast.elf shell/linux/reicast.elf
.map
nosym-reicast.elf
reicast.elf
Makefile
# Visual Studio # Visual Studio
generated generated

View File

@ -82,6 +82,7 @@ bool cfgOpen()
string config_path_read = get_readonly_config_path(filename); string config_path_read = get_readonly_config_path(filename);
cfgPath = get_writable_config_path(filename); cfgPath = get_writable_config_path(filename);
printf("opening cfg file %s\n", config_path_read.c_str()) ;
FILE* cfgfile = fopen(config_path_read.c_str(),"r"); FILE* cfgfile = fopen(config_path_read.c_str(),"r");
if(cfgfile != NULL) { if(cfgfile != NULL) {
cfgdb.parse(cfgfile); cfgdb.parse(cfgfile);

View File

@ -83,77 +83,6 @@ void UpdateSh4Ints()
} }
////
//Timers :)
struct AicaTimerData
{
union
{
struct
{
u32 count:8;
u32 md:3;
u32 nil:5;
u32 pad:16;
};
u32 data;
};
};
class AicaTimer
{
public:
AicaTimerData* data;
s32 c_step;
u32 m_step;
u32 id;
void Init(u8* regbase,u32 timer)
{
data=(AicaTimerData*)&regbase[0x2890 + timer*4];
id=timer;
m_step=1<<(data->md);
c_step=m_step;
}
void StepTimer(u32 samples)
{
do
{
c_step--;
if (c_step==0)
{
c_step=m_step;
data->count++;
if (data->count==0)
{
if (id==0)
{
SCIPD->TimerA=1;
MCIPD->TimerA=1;
}
else if (id==1)
{
SCIPD->TimerB=1;
MCIPD->TimerB=1;
}
else
{
SCIPD->TimerC=1;
MCIPD->TimerC=1;
}
}
}
} while(--samples);
}
void RegisterWrite()
{
u32 n_step=1<<(data->md);
if (n_step!=m_step)
{
m_step=n_step;
c_step=m_step;
}
}
};
AicaTimer timers[3]; AicaTimer timers[3];
//Mainloop //Mainloop

View File

@ -312,3 +312,75 @@ void WriteAicaReg8(u32 reg,u32 data);
template<u32 sz> template<u32 sz>
void WriteAicaReg(u32 reg,u32 data); void WriteAicaReg(u32 reg,u32 data);
////
//Timers :)
struct AicaTimerData
{
union
{
struct
{
u32 count:8;
u32 md:3;
u32 nil:5;
u32 pad:16;
};
u32 data;
};
};
class AicaTimer
{
public:
AicaTimerData* data;
s32 c_step;
u32 m_step;
u32 id;
void Init(u8* regbase,u32 timer)
{
data=(AicaTimerData*)&regbase[0x2890 + timer*4];
id=timer;
m_step=1<<(data->md);
c_step=m_step;
}
void StepTimer(u32 samples)
{
do
{
c_step--;
if (c_step==0)
{
c_step=m_step;
data->count++;
if (data->count==0)
{
if (id==0)
{
SCIPD->TimerA=1;
MCIPD->TimerA=1;
}
else if (id==1)
{
SCIPD->TimerB=1;
MCIPD->TimerB=1;
}
else
{
SCIPD->TimerC=1;
MCIPD->TimerC=1;
}
}
}
} while(--samples);
}
void RegisterWrite()
{
u32 n_step=1<<(data->md);
if (n_step!=m_step)
{
m_step=n_step;
c_step=m_step;
}
}
};

View File

@ -93,18 +93,6 @@ void AICA_Sample();
} }
s16 pl=0,pr=0; s16 pl=0,pr=0;
struct DSP_OUT_VOL_REG
{
//-- EFSDL[3:0] -- EFPAN[4:0]
u32 EFPAN:5;
u32 res_1:3;
u32 EFSDL:4;
u32 res_2:4;
u32 pad:16;
};
DSP_OUT_VOL_REG* dsp_out_vol; DSP_OUT_VOL_REG* dsp_out_vol;
#pragma pack (1) #pragma pack (1)
@ -324,13 +312,17 @@ struct ChannelEx
void (* StepStream)(ChannelEx* ch); void (* StepStream)(ChannelEx* ch);
void (* StepStreamInitial)(ChannelEx* ch); void (* StepStreamInitial)(ChannelEx* ch);
u8 step_stream_lut1=0 ;
u8 step_stream_lut2=0 ;
u8 step_stream_lut3=0 ;
struct struct
{ {
s32 val; s32 val;
__forceinline s32 GetValue() { return val>>AEG_STEP_BITS;} __forceinline s32 GetValue() { return val>>AEG_STEP_BITS;}
void SetValue(u32 aegb) { val=aegb<<AEG_STEP_BITS; } void SetValue(u32 aegb) { val=aegb<<AEG_STEP_BITS; }
_EG_state state; _EG_state state=EG_Attack;
u32 AttackRate; u32 AttackRate;
u32 Decay1Rate; u32 Decay1Rate;
@ -342,7 +334,7 @@ struct ChannelEx
struct struct
{ {
s32 value; s32 value;
_EG_state state; _EG_state state=EG_Attack;
} FEG;//i have to figure out how this works w/ AEG and channel state, and the iir values } FEG;//i have to figure out how this works w/ AEG and channel state, and the iir values
struct struct
@ -354,6 +346,8 @@ struct ChannelEx
u8 alfo_shft; u8 alfo_shft;
u8 plfo; u8 plfo;
u8 plfo_shft; u8 plfo_shft;
u8 alfo_calc_lut=0 ;
u8 plfo_calc_lut=0 ;
void (* alfo_calc)(ChannelEx* ch); void (* alfo_calc)(ChannelEx* ch);
void (* plfo_calc)(ChannelEx* ch); void (* plfo_calc)(ChannelEx* ch);
__forceinline void Step(ChannelEx* ch) { counter--;if (counter==0) { state++; counter=start_value; alfo_calc(ch);plfo_calc(ch); } } __forceinline void Step(ChannelEx* ch) { counter--;if (counter==0) { state++; counter=start_value; alfo_calc(ch);plfo_calc(ch); } }
@ -363,6 +357,7 @@ struct ChannelEx
bool enabled; //set to false to 'freeze' the channel bool enabled; //set to false to 'freeze' the channel
int ChanelNumber; int ChanelNumber;
void Init(int cn,u8* ccd_raw) void Init(int cn,u8* ccd_raw)
{ {
ccd=(ChannelCommonData*)&ccd_raw[cn*0x80]; ccd=(ChannelCommonData*)&ccd_raw[cn*0x80];
@ -516,6 +511,9 @@ struct ChannelEx
StepStream=STREAM_STEP_LUT[fmt][ccd->LPCTL][ccd->LPSLNK]; StepStream=STREAM_STEP_LUT[fmt][ccd->LPCTL][ccd->LPSLNK];
StepStreamInitial=STREAM_INITAL_STEP_LUT[fmt]; StepStreamInitial=STREAM_INITAL_STEP_LUT[fmt];
step_stream_lut1 = fmt ;
step_stream_lut2 = ccd->LPCTL ;
step_stream_lut3 = ccd->LPSLNK ;
} }
//SA,PCMS //SA,PCMS
void UpdateSA() void UpdateSA()
@ -590,6 +588,8 @@ struct ChannelEx
lfo.alfo_calc=ALFOWS_CALC[ccd->ALFOWS]; lfo.alfo_calc=ALFOWS_CALC[ccd->ALFOWS];
lfo.plfo_calc=PLFOWS_CALC[ccd->PLFOWS]; lfo.plfo_calc=PLFOWS_CALC[ccd->PLFOWS];
lfo.alfo_calc_lut=ccd->ALFOWS;
lfo.plfo_calc_lut=ccd->PLFOWS;
if (ccd->LFORE) if (ccd->LFORE)
{ {
@ -935,7 +935,7 @@ void CalcPlfo(ChannelEx* ch)
rv=(ch->lfo.state>>3)^(ch->lfo.state<<3)^(ch->lfo.state&0xE3); rv=(ch->lfo.state>>3)^(ch->lfo.state<<3)^(ch->lfo.state&0xE3);
break; break;
} }
ch->lfo.alfo=rv>>ch->lfo.plfo_shft; ch->lfo.plfo=rv>>ch->lfo.plfo_shft;
} }
template<u32 state> template<u32 state>
@ -1169,7 +1169,7 @@ s16 cdda_sector[CDDA_SIZE]={0};
u32 cdda_index=CDDA_SIZE<<1; u32 cdda_index=CDDA_SIZE<<1;
static SampleType mxlr[64]; SampleType mxlr[64];
u32 samples_gen; u32 samples_gen;
@ -1381,3 +1381,117 @@ void AICA_Sample()
WriteSample(mixr,mixl); WriteSample(mixr,mixl);
} }
bool channel_serialize(void **data, unsigned int *total_size)
{
int i = 0 ;
int addr = 0 ;
for ( i = 0 ; i < 64 ; i++)
{
addr = Chans[i].SA - (&(aica_ram.data[0])) ;
REICAST_S(addr);
REICAST_S(Chans[i].CA) ;
REICAST_S(Chans[i].step) ;
REICAST_S(Chans[i].update_rate) ;
REICAST_S(Chans[i].s0) ;
REICAST_S(Chans[i].s1) ;
REICAST_S(Chans[i].loop) ;
REICAST_S(Chans[i].adpcm.last_quant) ;
REICAST_S(Chans[i].noise_state) ;
REICAST_S(Chans[i].VolMix.DLAtt) ;
REICAST_S(Chans[i].VolMix.DRAtt) ;
REICAST_S(Chans[i].VolMix.DSPAtt) ;
addr = Chans[i].VolMix.DSPOut - (&(dsp.MIXS[0])) ;
REICAST_S(addr);
REICAST_S(Chans[i].AEG.val) ;
REICAST_S(Chans[i].AEG.state) ;
REICAST_S(Chans[i].AEG.AttackRate) ;
REICAST_S(Chans[i].AEG.Decay1Rate) ;
REICAST_S(Chans[i].AEG.Decay2Rate) ;
REICAST_S(Chans[i].AEG.Decay2Value) ;
REICAST_S(Chans[i].AEG.ReleaseRate) ;
REICAST_S(Chans[i].FEG) ;
REICAST_S(Chans[i].step_stream_lut1) ;
REICAST_S(Chans[i].step_stream_lut2) ;
REICAST_S(Chans[i].step_stream_lut3) ;
REICAST_S(Chans[i].lfo.counter) ;
REICAST_S(Chans[i].lfo.start_value) ;
REICAST_S(Chans[i].lfo.state) ;
REICAST_S(Chans[i].lfo.alfo) ;
REICAST_S(Chans[i].lfo.alfo_shft) ;
REICAST_S(Chans[i].lfo.plfo) ;
REICAST_S(Chans[i].lfo.plfo_shft) ;
REICAST_S(Chans[i].lfo.alfo_calc_lut) ;
REICAST_S(Chans[i].lfo.plfo_calc_lut) ;
REICAST_S(Chans[i].enabled) ;
REICAST_S(Chans[i].ChanelNumber) ;
}
/* TODO/FIXME - no possibility for this to return false? */
return true;
}
bool channel_unserialize(void **data, unsigned int *total_size)
{
int i = 0 ;
int addr = 0 ;
for ( i = 0 ; i < 64 ; i++)
{
REICAST_US(addr);
Chans[i].SA = addr + (&(aica_ram.data[0])) ;
REICAST_US(Chans[i].CA) ;
REICAST_US(Chans[i].step) ;
REICAST_US(Chans[i].update_rate) ;
REICAST_US(Chans[i].s0) ;
REICAST_US(Chans[i].s1) ;
REICAST_US(Chans[i].loop) ;
REICAST_US(Chans[i].adpcm.last_quant) ;
REICAST_US(Chans[i].noise_state) ;
REICAST_US(Chans[i].VolMix.DLAtt) ;
REICAST_US(Chans[i].VolMix.DRAtt) ;
REICAST_US(Chans[i].VolMix.DSPAtt) ;
REICAST_US(addr);
Chans[i].VolMix.DSPOut = addr + (&(dsp.MIXS[0])) ;
REICAST_US(Chans[i].AEG.val) ;
REICAST_US(Chans[i].AEG.state) ;
Chans[i].StepAEG=AEG_STEP_LUT[Chans[i].AEG.state];
REICAST_US(Chans[i].AEG.AttackRate) ;
REICAST_US(Chans[i].AEG.Decay1Rate) ;
REICAST_US(Chans[i].AEG.Decay2Rate) ;
REICAST_US(Chans[i].AEG.Decay2Value) ;
REICAST_US(Chans[i].AEG.ReleaseRate) ;
REICAST_US(Chans[i].FEG) ;
Chans[i].StepFEG=FEG_STEP_LUT[Chans[i].FEG.state];
REICAST_US(Chans[i].step_stream_lut1) ;
REICAST_US(Chans[i].step_stream_lut2) ;
REICAST_US(Chans[i].step_stream_lut3) ;
Chans[i].StepStream=STREAM_STEP_LUT[Chans[i].step_stream_lut1][Chans[i].step_stream_lut2][Chans[i].step_stream_lut3] ;
Chans[i].StepStreamInitial=STREAM_INITAL_STEP_LUT[Chans[i].step_stream_lut1];
REICAST_US(Chans[i].lfo.counter) ;
REICAST_US(Chans[i].lfo.start_value) ;
REICAST_US(Chans[i].lfo.state) ;
REICAST_US(Chans[i].lfo.alfo) ;
REICAST_US(Chans[i].lfo.alfo_shft) ;
REICAST_US(Chans[i].lfo.plfo) ;
REICAST_US(Chans[i].lfo.plfo_shft) ;
REICAST_US(Chans[i].lfo.alfo_calc_lut) ;
REICAST_US(Chans[i].lfo.plfo_calc_lut) ;
Chans[i].lfo.alfo_calc = ALFOWS_CALC[Chans[i].lfo.alfo_calc_lut];
Chans[i].lfo.plfo_calc = PLFOWS_CALC[Chans[i].lfo.plfo_calc_lut];
REICAST_US(Chans[i].enabled) ;
REICAST_US(Chans[i].ChanelNumber) ;
}
/* TODO/FIXME - no possibility for this to return false? */
return true;
}

View File

@ -38,6 +38,19 @@ union fp_20_12
u32 full; u32 full;
}; };
struct DSP_OUT_VOL_REG
{
//-- EFSDL[3:0] -- EFPAN[4:0]
u32 EFPAN:5;
u32 res_1:3;
u32 EFSDL:4;
u32 res_2:4;
u32 pad:16;
};
//#define SAMPLE_TYPE_SHIFT (8) //#define SAMPLE_TYPE_SHIFT (8)
typedef s32 SampleType; typedef s32 SampleType;
@ -45,3 +58,5 @@ void ReadCommonReg(u32 reg,bool byte);
void WriteCommonReg8(u32 reg,u32 data); void WriteCommonReg8(u32 reg,u32 data);
#define clip(x,min,max) if ((x)<(min)) (x)=(min); if ((x)>(max)) (x)=(max); #define clip(x,min,max) if ((x)<(min)) (x)=(min); if ((x)>(max)) (x)=(max);
#define clip16(x) clip(x,-32768,32767) #define clip16(x) clip(x,-32768,32767)
bool channel_serialize(void **data, unsigned int *total_size);
bool channel_unserialize(void **data, unsigned int *total_size);

View File

@ -36,87 +36,6 @@
#define CPUUpdateTicksAccess16(a) 1 #define CPUUpdateTicksAccess16(a) 1
enum
{
RN_CPSR = 16,
RN_SPSR = 17,
R13_IRQ = 18,
R14_IRQ = 19,
SPSR_IRQ = 20,
R13_USR = 26,
R14_USR = 27,
R13_SVC = 28,
R14_SVC = 29,
SPSR_SVC = 30,
R13_ABT = 31,
R14_ABT = 32,
SPSR_ABT = 33,
R13_UND = 34,
R14_UND = 35,
SPSR_UND = 36,
R8_FIQ = 37,
R9_FIQ = 38,
R10_FIQ = 39,
R11_FIQ = 40,
R12_FIQ = 41,
R13_FIQ = 42,
R14_FIQ = 43,
SPSR_FIQ = 44,
RN_PSR_FLAGS = 45,
R15_ARM_NEXT = 46,
INTR_PEND = 47,
CYCL_CNT = 48,
RN_ARM_REG_COUNT,
};
typedef union
{
struct
{
u8 B0;
u8 B1;
u8 B2;
u8 B3;
} B;
struct
{
u16 W0;
u16 W1;
} W;
union
{
struct
{
u32 _pad0 : 28;
u32 V : 1; //Bit 28
u32 C : 1; //Bit 29
u32 Z : 1; //Bit 30
u32 N : 1; //Bit 31
};
struct
{
u32 _pad1 : 28;
u32 NZCV : 4; //Bits [31:28]
};
} FLG;
struct
{
u32 M : 5; //mode, PSR[4:0]
u32 _pad0 : 1; //not used / zero
u32 F : 1; //FIQ disable, PSR[6]
u32 I : 1; //IRQ disable, PSR[7]
u32 _pad1 : 20; //not used / zero
u32 NZCV : 4; //Bits [31:28]
} PSR;
u32 I;
} reg_pair;
//bool arm_FiqPending; -- not used , i use the input directly :) //bool arm_FiqPending; -- not used , i use the input directly :)
//bool arm_IrqPending; //bool arm_IrqPending;

View File

@ -24,103 +24,14 @@ signed int sns_asc=0;
signed int sns_ascq=0; signed int sns_ascq=0;
signed int sns_key=0; signed int sns_key=0;
enum gd_states
{
//Generic
gds_waitcmd,
gds_procata,
gds_waitpacket,
gds_procpacket,
gds_pio_send_data,
gds_pio_get_data,
gds_pio_end,
gds_procpacketdone,
//Command spec.
gds_readsector_pio,
gds_readsector_dma,
gds_process_set_mode,
};
static struct
{
u32 start_sector;
u32 remaining_sectors;
u32 sector_type;
} read_params;
static struct
{
u32 index;
union
{
u16 data_16[6];
u8 data_8[12];
//Spi command structs
union
{
struct
{
u8 cc;
u8 prmtype : 1 ;
u8 expdtype : 3 ;
// u8 datasel : 4 ;
u8 other : 1 ; //"other" data. I guess that means SYNC/ECC/EDC ?
u8 data : 1 ; //user data. 2048 for mode1, 2048 for m2f1, 2324 for m2f2
u8 subh : 1 ; //8 bytes, mode2 subheader
u8 head : 1 ; //4 bytes, main CDROM header
u8 block[10];
};
struct
{
u8 b[12];
};
}GDReadBlock;
};
} packet_cmd;
//Buffer for sector reads [dma]
static struct
{
u32 cache_index;
u32 cache_size;
u8 cache[2352 * 8192]; //up to 8192 sectors
} read_buff;
//pio buffer
static struct
{
gd_states next_state;
u32 index;
u32 size;
u16 data[0x10000>>1]; //64 kb
} pio_buff;
u32 set_mode_offset; u32 set_mode_offset;
static struct read_params_t read_params ;
{ packet_cmd_t packet_cmd ;
u8 command; read_buff_t read_buff ;
} ata_cmd; pio_buff_t pio_buff ;
ata_cmd_t ata_cmd ;
static struct cdda_t cdda ;
{
bool playing;
u32 repeats;
union
{
u32 FAD;
struct
{
u8 B0; // MSB
u8 B1; // Middle byte
u8 B2; // LSB
};
}CurrAddr,EndAddr,StartAddr;
} cdda;
gd_states gd_state; gd_states gd_state;
DiscType gd_disk_type; DiscType gd_disk_type;
@ -144,16 +55,7 @@ u32 data_write_mode=0;
GD_StatusT GDStatus; GD_StatusT GDStatus;
static union ByteCount_t ByteCount;
{
struct
{
u8 low;
u8 hi;
};
u16 full;
} ByteCount;
//end //end
@ -217,6 +119,7 @@ void FillReadBuffer()
read_params.remaining_sectors-=count; read_params.remaining_sectors-=count;
} }
void gd_set_state(gd_states state) void gd_set_state(gd_states state)
{ {
gd_states prev=gd_state; gd_states prev=gd_state;

View File

@ -11,6 +11,24 @@ void gdrom_reg_Reset(bool Manual);
u32 ReadMem_gdrom(u32 Addr, u32 sz); u32 ReadMem_gdrom(u32 Addr, u32 sz);
void WriteMem_gdrom(u32 Addr, u32 data, u32 sz); void WriteMem_gdrom(u32 Addr, u32 data, u32 sz);
enum gd_states
{
//Generic
gds_waitcmd,
gds_procata,
gds_waitpacket,
gds_procpacket,
gds_pio_send_data,
gds_pio_get_data,
gds_pio_end,
gds_procpacketdone,
//Command spec.
gds_readsector_pio,
gds_readsector_dma,
gds_process_set_mode,
};
//Structs & unions //Structs & unions
struct SpiCommandInfo struct SpiCommandInfo
{ {
@ -115,6 +133,95 @@ struct GD_SecNumbT
}; };
}; };
struct read_params_t
{
u32 start_sector;
u32 remaining_sectors;
u32 sector_type;
} ;
struct packet_cmd_t
{
u32 index;
union
{
u16 data_16[6];
u8 data_8[12];
//Spi command structs
union
{
struct
{
u8 cc;
u8 prmtype : 1 ;
u8 expdtype : 3 ;
// u8 datasel : 4 ;
u8 other : 1 ; //"other" data. I guess that means SYNC/ECC/EDC ?
u8 data : 1 ; //user data. 2048 for mode1, 2048 for m2f1, 2324 for m2f2
u8 subh : 1 ; //8 bytes, mode2 subheader
u8 head : 1 ; //4 bytes, main CDROM header
u8 block[10];
};
struct
{
u8 b[12];
};
}GDReadBlock;
};
} ;
//Buffer for sector reads [dma]
struct read_buff_t
{
u32 cache_index;
u32 cache_size;
u8 cache[2352 * 8192]; //up to 8192 sectors
} ;
//pio buffer
struct pio_buff_t
{
gd_states next_state;
u32 index;
u32 size;
u16 data[0x10000>>1]; //64 kb
} ;
struct ata_cmd_t
{
u8 command;
} ;
struct cdda_t
{
bool playing;
u32 repeats;
union
{
u32 FAD;
struct
{
u8 B0; // MSB
u8 B1; // Middle byte
u8 B2; // LSB
};
}CurrAddr,EndAddr,StartAddr;
} ;
union ByteCount_t
{
struct
{
u8 low;
u8 hi;
};
u16 full;
} ;
#define GD_BUSY 0x00 // State transition #define GD_BUSY 0x00 // State transition
#define GD_PAUSE 0x01 // Pause #define GD_PAUSE 0x01 // Pause
#define GD_STANDBY 0x02 // Standby (drive stop) #define GD_STANDBY 0x02 // Standby (drive stop)

View File

@ -286,6 +286,20 @@ struct maple_sega_vmu: maple_base
return (rv == Z_OK && dec_sz == sizeof(flash_data)); return (rv == Z_OK && dec_sz == sizeof(flash_data));
} }
virtual bool maple_serialize(void **data, unsigned int *total_size)
{
REICAST_SA(flash_data,128*1024);
REICAST_SA(lcd_data,192);
REICAST_SA(lcd_data_decoded,48*32);
return true ;
}
virtual bool maple_unserialize(void **data, unsigned int *total_size)
{
REICAST_USA(flash_data,128*1024);
REICAST_USA(lcd_data,192);
REICAST_USA(lcd_data_decoded,48*32);
return true ;
}
virtual void OnSetup() virtual void OnSetup()
{ {
memset(flash_data, 0, sizeof(flash_data)); memset(flash_data, 0, sizeof(flash_data));
@ -701,6 +715,16 @@ struct maple_microphone: maple_base
{ {
u8 micdata[SIZE_OF_MIC_DATA]; u8 micdata[SIZE_OF_MIC_DATA];
virtual bool maple_serialize(void **data, unsigned int *total_size)
{
REICAST_SA(micdata,SIZE_OF_MIC_DATA);
return true ;
}
virtual bool maple_unserialize(void **data, unsigned int *total_size)
{
REICAST_USA(micdata,SIZE_OF_MIC_DATA);
return true ;
}
virtual void OnSetup() virtual void OnSetup()
{ {
memset(micdata,0,sizeof(micdata)); memset(micdata,0,sizeof(micdata));
@ -883,6 +907,20 @@ struct maple_sega_purupuru : maple_base
u16 AST, AST_ms; u16 AST, AST_ms;
u32 VIBSET; u32 VIBSET;
virtual bool maple_serialize(void **data, unsigned int *total_size)
{
REICAST_S(AST);
REICAST_S(AST_ms);
REICAST_S(VIBSET);
return true ;
}
virtual bool maple_unserialize(void **data, unsigned int *total_size)
{
REICAST_US(AST);
REICAST_US(AST_ms);
REICAST_US(VIBSET);
return true ;
}
virtual u32 dma(u32 cmd) virtual u32 dma(u32 cmd)
{ {
switch (cmd) switch (cmd)
@ -972,12 +1010,6 @@ struct maple_sega_purupuru : maple_base
char EEPROM[0x100]; char EEPROM[0x100];
bool EEPROM_loaded = false; bool EEPROM_loaded = false;
struct _NaomiState
{
u8 Cmd;
u8 Mode;
u8 Node;
};
_NaomiState State; _NaomiState State;

View File

@ -31,6 +31,15 @@ struct maple_device
virtual void OnSetup(){}; virtual void OnSetup(){};
virtual ~maple_device(); virtual ~maple_device();
virtual u32 Dma(u32 Command,u32* buffer_in,u32 buffer_in_len,u32* buffer_out,u32& buffer_out_len)=0; virtual u32 Dma(u32 Command,u32* buffer_in,u32 buffer_in_len,u32* buffer_out,u32& buffer_out_len)=0;
virtual bool maple_serialize(void **data, unsigned int *total_size){return true;};
virtual bool maple_unserialize(void **data, unsigned int *total_size){return true;};
};
struct _NaomiState
{
u8 Cmd;
u8 Mode;
u8 Node;
}; };
maple_device* maple_Create(MapleDeviceType type); maple_device* maple_Create(MapleDeviceType type);

View File

@ -42,8 +42,8 @@ A-H (0x41-0x48)
J-N (0x4A-0x4E) J-N (0x4A-0x4E)
P-Z (0x50-0x5A) P-Z (0x50-0x5A)
*/ */
static unsigned char BSerial[]="\xB7"/*CRC1*/"\x19"/*CRC2*/"0123234437897584372973927387463782196719782697849162342198671923649"; unsigned char BSerial[]="\xB7"/*CRC1*/"\x19"/*CRC2*/"0123234437897584372973927387463782196719782697849162342198671923649";
static unsigned char GSerial[]="\xB7"/*CRC1*/"\x19"/*CRC2*/"0123234437897584372973927387463782196719782697849162342198671923649"; unsigned char GSerial[]="\xB7"/*CRC1*/"\x19"/*CRC2*/"0123234437897584372973927387463782196719782697849162342198671923649";
unsigned int ShiftCRC(unsigned int CRC,unsigned int rounds) unsigned int ShiftCRC(unsigned int CRC,unsigned int rounds)
{ {

View File

@ -83,10 +83,10 @@ PolyParam* CurrentPP=&nullPP;
List<PolyParam>* CurrentPPlist; List<PolyParam>* CurrentPPlist;
//TA state vars //TA state vars
DECL_ALIGN(4) static u8 FaceBaseColor[4]; DECL_ALIGN(4) u8 FaceBaseColor[4];
DECL_ALIGN(4) static u8 FaceOffsColor[4]; DECL_ALIGN(4) u8 FaceOffsColor[4];
DECL_ALIGN(4) static u32 SFaceBaseColor; DECL_ALIGN(4) u32 SFaceBaseColor;
DECL_ALIGN(4) static u32 SFaceOffsColor; DECL_ALIGN(4) u32 SFaceOffsColor;

View File

@ -4,6 +4,7 @@
*/ */
#include <algorithm> #include <algorithm>
#include <set>
#include "blockmanager.h" #include "blockmanager.h"
#include "ngen.h" #include "ngen.h"

View File

@ -68,62 +68,8 @@ shil_param mk_regi(int reg)
{ {
return mk_reg((Sh4RegType)reg); return mk_reg((Sh4RegType)reg);
} }
enum NextDecoderOperation
{
NDO_NextOp, //pc+=2
NDO_End, //End the block, Type = BlockEndType
NDO_Delayslot, //pc+=2, NextOp=DelayOp
NDO_Jump, //pc=JumpAddr,NextOp=JumpOp
};
state_t state ;
struct
{
NextDecoderOperation NextOp;
NextDecoderOperation DelayOp;
NextDecoderOperation JumpOp;
u32 JumpAddr;
u32 NextAddr;
BlockEndType BlockType;
struct
{
bool FPR64; //64 bit FPU opcodes
bool FSZ64; //64 bit FPU moves
bool RoundToZero; //false -> Round to nearest.
u32 rpc;
bool is_delayslot;
} cpu;
ngen_features ngen;
struct
{
bool has_readm;
bool has_writem;
bool has_fpu;
} info;
void Setup(u32 rpc,fpscr_t fpu_cfg)
{
cpu.rpc=rpc;
cpu.is_delayslot=false;
cpu.FPR64=fpu_cfg.PR;
cpu.FSZ64=fpu_cfg.SZ;
cpu.RoundToZero=fpu_cfg.RM==1;
verify(fpu_cfg.RM<2);
//what about fp/fs ?
NextOp=NDO_NextOp;
BlockType=BET_SCL_Intr;
JumpAddr=0xFFFFFFFF;
NextAddr=0xFFFFFFFF;
info.has_readm=false;
info.has_writem=false;
info.has_fpu=false;
}
} state;
void Emit(shilop op,shil_param rd=shil_param(),shil_param rs1=shil_param(),shil_param rs2=shil_param(),u32 flags=0,shil_param rs3=shil_param(),shil_param rd2=shil_param()) void Emit(shilop op,shil_param rd=shil_param(),shil_param rs1=shil_param(),shil_param rs2=shil_param(),u32 flags=0,shil_param rs3=shil_param(),shil_param rd2=shil_param())
{ {
@ -1042,10 +988,30 @@ bool dec_generic(u32 op)
return true; return true;
} }
void state_Setup(u32 rpc,fpscr_t fpu_cfg)
{
state.cpu.rpc=rpc;
state.cpu.is_delayslot=false;
state.cpu.FPR64=fpu_cfg.PR;
state.cpu.FSZ64=fpu_cfg.SZ;
state.cpu.RoundToZero=fpu_cfg.RM==1;
verify(fpu_cfg.RM<2);
//what about fp/fs ?
state.NextOp=NDO_NextOp;
state.BlockType=BET_SCL_Intr;
state.JumpAddr=0xFFFFFFFF;
state.NextAddr=0xFFFFFFFF;
state.info.has_readm=false;
state.info.has_writem=false;
state.info.has_fpu=false;
}
void dec_DecodeBlock(RuntimeBlockInfo* rbi,u32 max_cycles) void dec_DecodeBlock(RuntimeBlockInfo* rbi,u32 max_cycles)
{ {
blk=rbi; blk=rbi;
state.Setup(blk->addr,blk->fpu_cfg); state_Setup(blk->addr,blk->fpu_cfg);
ngen_GetFeatures(&state.ngen); ngen_GetFeatures(&state.ngen);
blk->guest_opcodes=0; blk->guest_opcodes=0;
@ -1222,4 +1188,5 @@ _end:
blk=0; blk=0;
} }
#endif #endif

View File

@ -30,6 +30,48 @@ enum BlockEndType
BET_Cond_1=mkbet(BET_CLS_COND,BET_SCL_Jump,1), //sr.T==1 -> BranchBlock else NextBlock BET_Cond_1=mkbet(BET_CLS_COND,BET_SCL_Jump,1), //sr.T==1 -> BranchBlock else NextBlock
}; };
enum NextDecoderOperation
{
NDO_NextOp, //pc+=2
NDO_End, //End the block, Type = BlockEndType
NDO_Delayslot, //pc+=2, NextOp=DelayOp
NDO_Jump, //pc=JumpAddr,NextOp=JumpOp
};
//ngen features
struct ngen_features
{
bool OnlyDynamicEnds; //if set the block endings aren't handled natively and only Dynamic block end type is used
bool InterpreterFallback; //if set all the non-branch opcodes are handled with the ifb opcode
};
struct RuntimeBlockInfo; struct RuntimeBlockInfo;
void dec_DecodeBlock(RuntimeBlockInfo* rbi,u32 max_cycles); void dec_DecodeBlock(RuntimeBlockInfo* rbi,u32 max_cycles);
struct state_t
{
NextDecoderOperation NextOp;
NextDecoderOperation DelayOp;
NextDecoderOperation JumpOp;
u32 JumpAddr;
u32 NextAddr;
BlockEndType BlockType;
struct
{
bool FPR64; //64 bit FPU opcodes
bool FSZ64; //64 bit FPU moves
bool RoundToZero; //false -> Round to nearest.
u32 rpc;
bool is_delayslot;
} cpu;
ngen_features ngen;
struct
{
bool has_readm;
bool has_writem;
bool has_fpu;
} info;
} ;

View File

@ -382,6 +382,11 @@ void recSh4_Stop()
Sh4_int_Stop(); Sh4_int_Stop();
} }
void recSh4_Start()
{
Sh4_int_Start();
}
void recSh4_Step() void recSh4_Step()
{ {
Sh4_int_Step(); Sh4_int_Step();
@ -485,6 +490,7 @@ void Get_Sh4Recompiler(sh4_if* rv)
{ {
rv->Run = recSh4_Run; rv->Run = recSh4_Run;
rv->Stop = recSh4_Stop; rv->Stop = recSh4_Stop;
rv->Start = recSh4_Start;
rv->Step = recSh4_Step; rv->Step = recSh4_Step;
rv->Skip = recSh4_Skip; rv->Skip = recSh4_Skip;
rv->Reset = recSh4_Reset; rv->Reset = recSh4_Reset;

View File

@ -94,12 +94,6 @@ void ngen_ResetBlocks();
extern void (*ngen_FailedToFindBlock)(); extern void (*ngen_FailedToFindBlock)();
//the dynarec mainloop //the dynarec mainloop
void ngen_mainloop(void* cntx); void ngen_mainloop(void* cntx);
//ngen features
struct ngen_features
{
bool OnlyDynamicEnds; //if set the block endings aren't handled natively and only Dynamic block end type is used
bool InterpreterFallback; //if set all the non-branch opcodes are handled with the ifb opcode
};
void ngen_GetFeatures(ngen_features* dst); void ngen_GetFeatures(ngen_features* dst);

View File

@ -82,6 +82,14 @@ void Sh4_int_Stop()
} }
} }
void Sh4_int_Start()
{
if (!sh4_int_bCpuRun)
{
sh4_int_bCpuRun=true;
}
}
void Sh4_int_Step() void Sh4_int_Step()
{ {
if (sh4_int_bCpuRun) if (sh4_int_bCpuRun)
@ -124,7 +132,7 @@ void Sh4_int_Reset(bool Manual)
gbr=ssr=spc=sgr=dbr=vbr=0; gbr=ssr=spc=sgr=dbr=vbr=0;
mac.full=pr=fpul=0; mac.full=pr=fpul=0;
sr.SetFull(0x700000F0); sh4_sr_SetFull(0x700000F0);
old_sr.status=sr.status; old_sr.status=sr.status;
UpdateSR(); UpdateSR();
@ -165,12 +173,12 @@ void ExecuteDelayslot()
void ExecuteDelayslot_RTE() void ExecuteDelayslot_RTE()
{ {
u32 oldsr = sr.GetFull(); u32 oldsr = sh4_sr_GetFull();
#if !defined(NO_MMU) #if !defined(NO_MMU)
try { try {
#endif #endif
sr.SetFull(ssr); sh4_sr_SetFull(ssr);
ExecuteDelayslot(); ExecuteDelayslot();
#if !defined(NO_MMU) #if !defined(NO_MMU)
@ -269,6 +277,7 @@ void Get_Sh4Interpreter(sh4_if* rv)
{ {
rv->Run=Sh4_int_Run; rv->Run=Sh4_int_Run;
rv->Stop=Sh4_int_Stop; rv->Stop=Sh4_int_Stop;
rv->Start=Sh4_int_Start;
rv->Step=Sh4_int_Step; rv->Step=Sh4_int_Step;
rv->Skip=Sh4_int_Skip; rv->Skip=Sh4_int_Skip;
rv->Reset=Sh4_int_Reset; rv->Reset=Sh4_int_Reset;

View File

@ -2129,7 +2129,7 @@ sh4op(i0100_nnnn_0001_1011)
sh4op(i0000_nnnn_0000_0010)//0002 sh4op(i0000_nnnn_0000_0010)//0002
{ {
u32 n = GetN(op); u32 n = GetN(op);
r[n] = sr.GetFull(); r[n] = sh4_sr_GetFull();
} }
//sts FPSCR,<REG_N> //sts FPSCR,<REG_N>
@ -2155,7 +2155,7 @@ sh4op(i0100_nnnn_0000_0011)
//iNimp("stc.l SR,@-<REG_N>"); //iNimp("stc.l SR,@-<REG_N>");
u32 n = GetN(op); u32 n = GetN(op);
r[n] -= 4; r[n] -= 4;
WriteMemU32(r[n], sr.GetFull()); WriteMemU32(r[n], sh4_sr_GetFull());
} }
//lds.l @<REG_N>+,FPSCR //lds.l @<REG_N>+,FPSCR
@ -2178,7 +2178,7 @@ sh4op(i0100_nnnn_0000_0111)
u32 sr_t; u32 sr_t;
ReadMemU32(sr_t,r[n]); ReadMemU32(sr_t,r[n]);
sr.SetFull(sr_t); sh4_sr_SetFull(sr_t);
r[n] += 4; r[n] += 4;
if (UpdateSR()) if (UpdateSR())
{ {
@ -2198,7 +2198,7 @@ sh4op(i0100_nnnn_0110_1010)
sh4op(i0100_nnnn_0000_1110) sh4op(i0100_nnnn_0000_1110)
{ {
u32 n = GetN(op); u32 n = GetN(op);
sr.SetFull(r[n]); sh4_sr_SetFull(r[n]);
if (UpdateSR()) if (UpdateSR())
{ {
UpdateINTC(); UpdateINTC();

View File

@ -234,7 +234,7 @@ u32* Sh4_int_GetRegisterPtr(Sh4RegType reg)
} }
} }
u32 Sh4Context::offset(u32 sh4_reg) u32 sh4context_offset_u32(u32 sh4_reg)
{ {
void* addr=Sh4_int_GetRegisterPtr((Sh4RegType)sh4_reg); void* addr=Sh4_int_GetRegisterPtr((Sh4RegType)sh4_reg);
u32 offs=(u8*)addr-(u8*)&Sh4cntx; u32 offs=(u8*)addr-(u8*)&Sh4cntx;
@ -242,3 +242,7 @@ u32 Sh4Context::offset(u32 sh4_reg)
return offs; return offs;
} }
u32 sh4context_offset_regtype(Sh4RegType sh4_reg)
{
return sh4context_offset_u32(sh4_reg);
}

View File

@ -169,16 +169,6 @@ struct sr_t
u32 status; u32 status;
}; };
u32 T; u32 T;
INLINE u32 GetFull()
{
return (status & 0x700083F2) | T;
}
INLINE void SetFull(u32 value)
{
status=value & 0x700083F2;
T=value&1;
}
}; };
@ -225,6 +215,7 @@ struct fpscr_t
typedef void RunFP(); typedef void RunFP();
typedef void StopFP(); typedef void StopFP();
typedef void StartFP();
typedef void StepFP(); typedef void StepFP();
typedef void SkipFP(); typedef void SkipFP();
typedef void ResetFP(bool Manual); typedef void ResetFP(bool Manual);
@ -251,6 +242,7 @@ struct sh4_if
TermFP* ResetCache; TermFP* ResetCache;
IsCpuRunningFP* IsCpuRunning; IsCpuRunningFP* IsCpuRunning;
StartFP* Start;
}; };
@ -294,10 +286,11 @@ struct Sh4Context
u64 raw[64-8]; u64 raw[64-8];
}; };
u32 offset(u32 sh4_reg);
u32 offset(Sh4RegType sh4_reg) { return offset(sh4_reg); }
}; };
u32 sh4context_offset_u32(u32 sh4_reg);
u32 sh4context_offset_regtype(Sh4RegType sh4_reg);
void DYNACALL do_sqw_mmu(u32 dst); void DYNACALL do_sqw_mmu(u32 dst);
extern "C" void DYNACALL do_sqw_nommu_area_3(u32 dst, u8* sqb); extern "C" void DYNACALL do_sqw_nommu_area_3(u32 dst, u8* sqb);
extern "C" void DYNACALL do_sqw_nommu_area_3_nonvmem(u32 dst, u8* sqb); extern "C" void DYNACALL do_sqw_nommu_area_3_nonvmem(u32 dst, u8* sqb);
@ -324,6 +317,17 @@ struct Sh4RCB
extern Sh4RCB* p_sh4rcb; extern Sh4RCB* p_sh4rcb;
extern u8* sh4_dyna_rcb; extern u8* sh4_dyna_rcb;
INLINE u32 sh4_sr_GetFull()
{
return (p_sh4rcb->cntx.sr.status & 0x700083F2) | p_sh4rcb->cntx.sr.T;
}
INLINE void sh4_sr_SetFull(u32 value)
{
p_sh4rcb->cntx.sr.status=value & 0x700083F2;
p_sh4rcb->cntx.sr.T=value&1;
}
#define do_sqw_nommu sh4rcb.do_sqw_nommu #define do_sqw_nommu sh4rcb.do_sqw_nommu
template<typename T> template<typename T>

View File

@ -38,6 +38,7 @@ enum OpcodeType
//interface //interface
void Sh4_int_Run(); void Sh4_int_Run();
void Sh4_int_Stop(); void Sh4_int_Stop();
void Sh4_int_Start();
void Sh4_int_Step(); void Sh4_int_Step();
void Sh4_int_Skip(); void Sh4_int_Skip();
void Sh4_int_Reset(bool Manual); void Sh4_int_Reset(bool Manual);

View File

@ -146,7 +146,7 @@ bool Do_Interrupt(u32 intEvn)
{ {
CCN_INTEVT = intEvn; CCN_INTEVT = intEvn;
ssr = sr.GetFull(); ssr = sh4_sr_GetFull();
spc = next_pc; spc = next_pc;
sgr = r[15]; sgr = r[15];
sr.BL = 1; sr.BL = 1;
@ -163,7 +163,7 @@ bool Do_Exception(u32 epc, u32 expEvn, u32 CallVect)
verify(sr.BL == 0); verify(sr.BL == 0);
CCN_EXPEVT = expEvn; CCN_EXPEVT = expEvn;
ssr = sr.GetFull(); ssr = sh4_sr_GetFull();
spc = epc; spc = epc;
sgr = r[15]; sgr = r[15];
sr.BL = 1; sr.BL = 1;

View File

@ -24,13 +24,6 @@
u64 sh4_sched_ffb; u64 sh4_sched_ffb;
u32 sh4_sched_intr; u32 sh4_sched_intr;
struct sched_list
{
sh4_sched_callback* cb;
int tag;
int start;
int end;
};
vector<sched_list> list; vector<sched_list> list;

View File

@ -49,4 +49,12 @@ void sh4_sched_tick(int cycles);
extern u32 sh4_sched_intr; extern u32 sh4_sched_intr;
struct sched_list
{
sh4_sched_callback* cb;
int tag;
int start;
int end;
};
#endif //SH4_SCHED_H #endif //SH4_SCHED_H

View File

@ -17,6 +17,8 @@
libevdev_func2_t libevdev_event_code_get_name; libevdev_func2_t libevdev_event_code_get_name;
void dc_stop(void); void dc_stop(void);
bool dc_loadstate(void);
bool dc_savestate(void);
void load_libevdev() void load_libevdev()
{ {
@ -179,6 +181,8 @@
load_keycode(&mf, "dreamcast", "btn_z"), load_keycode(&mf, "dreamcast", "btn_z"),
load_keycode(&mf, "dreamcast", "btn_start"), load_keycode(&mf, "dreamcast", "btn_start"),
load_keycode(&mf, "emulator", "btn_escape"), load_keycode(&mf, "emulator", "btn_escape"),
load_keycode(&mf, "emulator", "btn_loadstate"),
load_keycode(&mf, "emulator", "btn_savestate"),
load_keycode(&mf, "dreamcast", "btn_dpad1_left"), load_keycode(&mf, "dreamcast", "btn_dpad1_left"),
load_keycode(&mf, "dreamcast", "btn_dpad1_right"), load_keycode(&mf, "dreamcast", "btn_dpad1_right"),
load_keycode(&mf, "dreamcast", "btn_dpad1_up"), load_keycode(&mf, "dreamcast", "btn_dpad1_up"),
@ -222,6 +226,8 @@
|| (mapping->Btn_Z == button) || (mapping->Btn_Z == button)
|| (mapping->Btn_Start == button) || (mapping->Btn_Start == button)
|| (mapping->Btn_Escape == button) || (mapping->Btn_Escape == button)
|| (mapping->Btn_LoadState == button)
|| (mapping->Btn_SaveState == button)
|| (mapping->Btn_DPad_Left == button) || (mapping->Btn_DPad_Left == button)
|| (mapping->Btn_DPad_Right == button) || (mapping->Btn_DPad_Right == button)
|| (mapping->Btn_DPad_Up == button) || (mapping->Btn_DPad_Up == button)
@ -245,6 +251,8 @@
|| input_evdev_button_assigned(mapping1, mapping2->Btn_Z) || input_evdev_button_assigned(mapping1, mapping2->Btn_Z)
|| input_evdev_button_assigned(mapping1, mapping2->Btn_Start) || input_evdev_button_assigned(mapping1, mapping2->Btn_Start)
|| input_evdev_button_assigned(mapping1, mapping2->Btn_Escape) || input_evdev_button_assigned(mapping1, mapping2->Btn_Escape)
|| input_evdev_button_assigned(mapping1, mapping2->Btn_LoadState)
|| input_evdev_button_assigned(mapping1, mapping2->Btn_SaveState)
|| input_evdev_button_assigned(mapping1, mapping2->Btn_DPad_Left) || input_evdev_button_assigned(mapping1, mapping2->Btn_DPad_Left)
|| input_evdev_button_assigned(mapping1, mapping2->Btn_DPad_Right) || input_evdev_button_assigned(mapping1, mapping2->Btn_DPad_Right)
|| input_evdev_button_assigned(mapping1, mapping2->Btn_DPad_Up) || input_evdev_button_assigned(mapping1, mapping2->Btn_DPad_Up)
@ -351,6 +359,7 @@
size_t size_needed = snprintf(NULL, 0, EVDEV_MAPPING_PATH, mapping_fname) + 1; size_t size_needed = snprintf(NULL, 0, EVDEV_MAPPING_PATH, mapping_fname) + 1;
char* mapping_path = (char*)malloc(size_needed); char* mapping_path = (char*)malloc(size_needed);
sprintf(mapping_path, EVDEV_MAPPING_PATH, mapping_fname); sprintf(mapping_path, EVDEV_MAPPING_PATH, mapping_fname);
printf("evdev: mapping file : %s\n", get_readonly_data_path(mapping_path).c_str()) ;
mapping_fd = fopen(get_readonly_data_path(mapping_path).c_str(), "r"); mapping_fd = fopen(get_readonly_data_path(mapping_path).c_str(), "r");
free(mapping_path); free(mapping_path);
} }
@ -359,6 +368,7 @@
{ {
printf("evdev: reading mapping file: '%s'\n", mapping_fname); printf("evdev: reading mapping file: '%s'\n", mapping_fname);
loaded_mappings.insert(std::make_pair(string(mapping_fname), load_mapping(mapping_fd))); loaded_mappings.insert(std::make_pair(string(mapping_fname), load_mapping(mapping_fd)));
printf("evdev: read mapping file\n") ;
fclose(mapping_fd); fclose(mapping_fd);
} }
@ -416,6 +426,10 @@
SET_FLAG(kcode[port], DC_BTN_START, ie.value); SET_FLAG(kcode[port], DC_BTN_START, ie.value);
} else if (ie.code == controller->mapping->Btn_Escape) { } else if (ie.code == controller->mapping->Btn_Escape) {
dc_stop(); dc_stop();
} else if (ie.code == controller->mapping->Btn_LoadState) {
dc_loadstate();
} else if (ie.code == controller->mapping->Btn_SaveState) {
dc_savestate();
} else if (ie.code == controller->mapping->Btn_DPad_Left) { } else if (ie.code == controller->mapping->Btn_DPad_Left) {
SET_FLAG(kcode[port], DC_DPAD_LEFT, ie.value); SET_FLAG(kcode[port], DC_DPAD_LEFT, ie.value);
} else if (ie.code == controller->mapping->Btn_DPad_Right) { } else if (ie.code == controller->mapping->Btn_DPad_Right) {

View File

@ -14,6 +14,8 @@ struct EvdevControllerMapping
const int Btn_Z; const int Btn_Z;
const int Btn_Start; const int Btn_Start;
const int Btn_Escape; const int Btn_Escape;
const int Btn_LoadState;
const int Btn_SaveState;
const int Btn_DPad_Left; const int Btn_DPad_Left;
const int Btn_DPad_Right; const int Btn_DPad_Right;
const int Btn_DPad_Up; const int Btn_DPad_Up;

View File

@ -42,6 +42,8 @@ Atom wmDeleteMessage;
void* x11_vis; void* x11_vis;
void dc_stop(void); void dc_stop(void);
bool dc_loadstate(void);
bool dc_savestate(void);
enum enum
{ {
@ -113,6 +115,14 @@ void input_x11_handle()
x11_fullscreen = !x11_fullscreen; x11_fullscreen = !x11_fullscreen;
x11_window_set_fullscreen(x11_fullscreen); x11_window_set_fullscreen(x11_fullscreen);
} }
else if (e.type == KeyRelease && e.xkey.keycode == KEY_F2)
{
dc_savestate() ;
}
else if (e.type == KeyRelease && e.xkey.keycode == KEY_F4)
{
dc_loadstate() ;
}
else else
{ {
int dc_key = x11_keymap[e.xkey.keycode]; int dc_key = x11_keymap[e.xkey.keycode];

View File

@ -16,8 +16,12 @@
#include "webui/server.h" #include "webui/server.h"
#include "hw/naomi/naomi_cart.h" #include "hw/naomi/naomi_cart.h"
#include "reios/reios.h" #include "reios/reios.h"
#include "hw/sh4/dyna/blockmanager.h"
settings_t settings; settings_t settings;
static bool performed_serialization = false;
static cMutex mtx_serialization ;
static cMutex mtx_mainloop ;
/* /*
libndc libndc
@ -40,6 +44,43 @@ settings_t settings;
#include <windows.h> #include <windows.h>
#endif #endif
/**
* cpu_features_get_time_usec:
*
* Gets time in microseconds.
*
* Returns: time in microseconds.
**/
int64_t get_time_usec(void)
{
#if HOST_OS==OS_WINDOWS
static LARGE_INTEGER freq;
LARGE_INTEGER count;
/* Frequency is guaranteed to not change. */
if (!freq.QuadPart && !QueryPerformanceFrequency(&freq))
return 0;
if (!QueryPerformanceCounter(&count))
return 0;
return count.QuadPart * 1000000 / freq.QuadPart;
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__) || HOST_OS==OS_LINUX
struct timespec tv = {0};
if (clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
return 0;
return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;
#elif defined(EMSCRIPTEN)
return emscripten_get_now() * 1000;
#elif defined(__mips__) || defined(DJGPP)
struct timeval tv;
gettimeofday(&tv,NULL);
return (1000000 * tv.tv_sec + tv.tv_usec);
#else
#error "Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue."
#endif
}
int GetFile(char *szFileName, char *szParse=0, u32 flags=0) int GetFile(char *szFileName, char *szParse=0, u32 flags=0)
{ {
cfgLoadStr("config","image",szFileName,"null"); cfgLoadStr("config","image",szFileName,"null");
@ -252,9 +293,26 @@ int dc_init()
return rv; return rv;
} }
bool dc_is_running()
{
return sh4_cpu.IsCpuRunning();
}
void dc_run() void dc_run()
{ {
while ( true )
{
performed_serialization = false ;
mtx_mainloop.Lock() ;
sh4_cpu.Run(); sh4_cpu.Run();
mtx_mainloop.Unlock() ;
mtx_serialization.Lock() ;
mtx_serialization.Unlock() ;
if (!performed_serialization)
break ;
}
} }
void dc_term() void dc_term()
@ -283,6 +341,11 @@ void dc_stop()
sh4_cpu.Stop(); sh4_cpu.Stop();
} }
void dc_start()
{
sh4_cpu.Start();
}
void LoadSettings() void LoadSettings()
{ {
#ifndef _ANDROID #ifndef _ANDROID
@ -380,3 +443,196 @@ void SaveSettings()
cfgSaveInt("config","Dreamcast.Region", settings.dreamcast.region); cfgSaveInt("config","Dreamcast.Region", settings.dreamcast.region);
cfgSaveInt("config","Dreamcast.Broadcast", settings.dreamcast.broadcast); cfgSaveInt("config","Dreamcast.Broadcast", settings.dreamcast.broadcast);
} }
bool wait_until_dc_running()
{
int64_t start_time = get_time_usec() ;
const int64_t FIVE_SECONDS = 5*1000000 ;
while(!dc_is_running())
{
if ( start_time+FIVE_SECONDS < get_time_usec() )
{
//timeout elapsed - dc not getting a chance to run - just bail
return false ;
}
}
return true ;
}
bool acquire_mainloop_lock()
{
bool result = false ;
int64_t start_time = get_time_usec() ;
const int64_t FIVE_SECONDS = 5*1000000 ;
while ( ( start_time+FIVE_SECONDS > get_time_usec() ) && !(result = mtx_mainloop.TryLock()) )
{
//rend_cancel_emu_wait() ;
//retro_run();
}
return result ;
}
void cleanup_serialize(void *data)
{
if ( data != NULL )
free(data) ;
performed_serialization = true ;
dc_start() ;
mtx_serialization.Unlock() ;
mtx_mainloop.Unlock() ;
}
void* dc_savestate_thread(void* p)
{
char filename[2048] ;
unsigned int total_size = 0 ;
void *data = NULL ;
void *data_ptr = NULL ;
FILE *f ;
mtx_serialization.Lock() ;
if ( !wait_until_dc_running()) {
printf("Failed to save state - dc loop kept running\n") ;
mtx_serialization.Unlock() ;
return NULL;
}
dc_stop() ;
if ( !acquire_mainloop_lock() )
{
printf("Failed to save state - could not acquire main loop lock\n") ;
performed_serialization = true ;
dc_start() ;
mtx_serialization.Unlock() ;
return NULL;
}
if ( ! dc_serialize(&data, &total_size) )
{
printf("Failed to save state - could not initialize total size\n") ;
cleanup_serialize(data) ;
return NULL;
}
data = malloc(total_size) ;
if ( data == NULL )
{
printf("Failed to save state - could not malloc %d bytes", total_size) ;
cleanup_serialize(data) ;
return NULL;
}
data_ptr = data ;
if ( ! dc_serialize(&data_ptr, &total_size) )
{
printf("Failed to save state - could not serialize data\n") ;
cleanup_serialize(data) ;
return NULL;
}
snprintf(filename, 2048, "%s%s", get_writable_data_path("/data/").c_str(), "state") ;
f = fopen(filename, "wb") ;
if ( f == NULL )
{
printf("Failed to save state - could not open %s for writing\n", filename) ;
cleanup_serialize(data) ;
return NULL;
}
fwrite(data, 1, total_size, f) ;
fclose(f);
cleanup_serialize(data) ;
printf("Saved state to %s\n", filename) ;
}
void* dc_loadstate_thread(void* p)
{
char filename[2048] ;
unsigned int total_size = 0 ;
void *data = NULL ;
void *data_ptr = NULL ;
FILE *f ;
mtx_serialization.Lock() ;
if ( !wait_until_dc_running()) {
printf("Failed to load state - dc loop kept running\n") ;
mtx_serialization.Unlock() ;
return NULL;
}
dc_stop() ;
if ( !acquire_mainloop_lock() )
{
printf("Failed to load state - could not acquire main loop lock\n") ;
performed_serialization = true ;
dc_start() ;
mtx_serialization.Unlock() ;
return NULL;
}
if ( ! dc_serialize(&data, &total_size) )
{
printf("Failed to load state - could not initialize total size\n") ;
cleanup_serialize(data) ;
return NULL;
}
data = malloc(total_size) ;
if ( data == NULL )
{
printf("Failed to load state - could not malloc %d bytes", total_size) ;
cleanup_serialize(data) ;
return NULL;
}
snprintf(filename, 2048, "%s%s", get_writable_data_path("/data/").c_str(), "state") ;
f = fopen(filename, "rb") ;
if ( f == NULL )
{
printf("Failed to load state - could not open %s for reading\n", filename) ;
cleanup_serialize(data) ;
return NULL;
}
fread(data, 1, total_size, f) ;
fclose(f);
data_ptr = data ;
bm_Reset() ;
if ( ! dc_unserialize(&data_ptr, &total_size) )
{
printf("Failed to load state - could not unserialize data\n") ;
cleanup_serialize(data) ;
return NULL;
}
cleanup_serialize(data) ;
printf("Loaded state from %s\n", filename) ;
}
void dc_savestate()
{
cThread thd(dc_savestate_thread,0);
thd.Start() ;
}
void dc_loadstate()
{
cThread thd(dc_loadstate_thread,0);
thd.Start() ;
}

1673
core/serialize.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -238,6 +238,14 @@ public :
EnterCriticalSection(&cs); EnterCriticalSection(&cs);
#else #else
pthread_mutex_lock(&mutx); pthread_mutex_lock(&mutx);
#endif
}
bool TryLock()
{
#if HOST_OS==OS_WINDOWS
return TryEnterCriticalSection(&cs);
#else
return pthread_mutex_trylock(&mutx)==0;
#endif #endif
} }
void Unlock() void Unlock()

View File

@ -517,6 +517,102 @@ using namespace std;
void os_DebugBreak(); void os_DebugBreak();
#define dbgbreak os_DebugBreak() #define dbgbreak os_DebugBreak()
bool rc_serialize(void *src, unsigned int src_size, void **dest, unsigned int *total_size) ;
bool rc_unserialize(void *src, unsigned int src_size, void **dest, unsigned int *total_size);
bool dc_serialize(void **data, unsigned int *total_size);
bool dc_unserialize(void **data, unsigned int *total_size);
#define REICAST_S(v) rc_serialize(&(v), sizeof(v), data, total_size)
#define REICAST_US(v) rc_unserialize(&(v), sizeof(v), data, total_size)
#define REICAST_SA(v_arr,num) rc_serialize(v_arr, sizeof(v_arr[0])*num, data, total_size)
#define REICAST_USA(v_arr,num) rc_unserialize(v_arr, sizeof(v_arr[0])*num, data, total_size)
enum
{
RN_CPSR = 16,
RN_SPSR = 17,
R13_IRQ = 18,
R14_IRQ = 19,
SPSR_IRQ = 20,
R13_USR = 26,
R14_USR = 27,
R13_SVC = 28,
R14_SVC = 29,
SPSR_SVC = 30,
R13_ABT = 31,
R14_ABT = 32,
SPSR_ABT = 33,
R13_UND = 34,
R14_UND = 35,
SPSR_UND = 36,
R8_FIQ = 37,
R9_FIQ = 38,
R10_FIQ = 39,
R11_FIQ = 40,
R12_FIQ = 41,
R13_FIQ = 42,
R14_FIQ = 43,
SPSR_FIQ = 44,
RN_PSR_FLAGS = 45,
R15_ARM_NEXT = 46,
INTR_PEND = 47,
CYCL_CNT = 48,
RN_ARM_REG_COUNT,
};
typedef union
{
struct
{
u8 B0;
u8 B1;
u8 B2;
u8 B3;
} B;
struct
{
u16 W0;
u16 W1;
} W;
union
{
struct
{
u32 _pad0 : 28;
u32 V : 1; //Bit 28
u32 C : 1; //Bit 29
u32 Z : 1; //Bit 30
u32 N : 1; //Bit 31
};
struct
{
u32 _pad1 : 28;
u32 NZCV : 4; //Bits [31:28]
};
} FLG;
struct
{
u32 M : 5; //mode, PSR[4:0]
u32 _pad0 : 1; //not used / zero
u32 F : 1; //FIQ disable, PSR[6]
u32 I : 1; //IRQ disable, PSR[7]
u32 _pad1 : 20; //not used / zero
u32 NZCV : 4; //Bits [31:28]
} PSR;
u32 I;
} reg_pair;
#if COMPILER_VC==BUILD_COMPILER #if COMPILER_VC==BUILD_COMPILER
#pragma warning( disable : 4127 4996 /*4244*/) #pragma warning( disable : 4127 4996 /*4244*/)
#else #else

View File

@ -1,6 +1,8 @@
[emulator] [emulator]
mapping_name = Generic Controller mapping_name = Generic Controller
btn_escape = 0x13a btn_escape = 0x13a
btn_savestate = 0x3c
btn_loadstate = 0x3e
[dreamcast] [dreamcast]
btn_a = 0x130 btn_a = 0x130