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/nosym-reicast.elf
shell/linux/reicast.elf
.map
nosym-reicast.elf
reicast.elf
Makefile
# Visual Studio
generated

View File

@ -82,6 +82,7 @@ bool cfgOpen()
string config_path_read = get_readonly_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");
if(cfgfile != NULL) {
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];
//Mainloop

View File

@ -311,4 +311,76 @@ void AICA_Term();
void WriteAicaReg8(u32 reg,u32 data);
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;
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;
#pragma pack (1)
@ -324,13 +312,17 @@ struct ChannelEx
void (* StepStream)(ChannelEx* ch);
void (* StepStreamInitial)(ChannelEx* ch);
u8 step_stream_lut1=0 ;
u8 step_stream_lut2=0 ;
u8 step_stream_lut3=0 ;
struct
{
s32 val;
__forceinline s32 GetValue() { return val>>AEG_STEP_BITS;}
void SetValue(u32 aegb) { val=aegb<<AEG_STEP_BITS; }
_EG_state state;
_EG_state state=EG_Attack;
u32 AttackRate;
u32 Decay1Rate;
@ -342,7 +334,7 @@ struct ChannelEx
struct
{
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
struct
@ -354,6 +346,8 @@ struct ChannelEx
u8 alfo_shft;
u8 plfo;
u8 plfo_shft;
u8 alfo_calc_lut=0 ;
u8 plfo_calc_lut=0 ;
void (* alfo_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); } }
@ -363,6 +357,7 @@ struct ChannelEx
bool enabled; //set to false to 'freeze' the channel
int ChanelNumber;
void Init(int cn,u8* ccd_raw)
{
ccd=(ChannelCommonData*)&ccd_raw[cn*0x80];
@ -516,6 +511,9 @@ struct ChannelEx
StepStream=STREAM_STEP_LUT[fmt][ccd->LPCTL][ccd->LPSLNK];
StepStreamInitial=STREAM_INITAL_STEP_LUT[fmt];
step_stream_lut1 = fmt ;
step_stream_lut2 = ccd->LPCTL ;
step_stream_lut3 = ccd->LPSLNK ;
}
//SA,PCMS
void UpdateSA()
@ -590,6 +588,8 @@ struct ChannelEx
lfo.alfo_calc=ALFOWS_CALC[ccd->ALFOWS];
lfo.plfo_calc=PLFOWS_CALC[ccd->PLFOWS];
lfo.alfo_calc_lut=ccd->ALFOWS;
lfo.plfo_calc_lut=ccd->PLFOWS;
if (ccd->LFORE)
{
@ -935,7 +935,7 @@ void CalcPlfo(ChannelEx* ch)
rv=(ch->lfo.state>>3)^(ch->lfo.state<<3)^(ch->lfo.state&0xE3);
break;
}
ch->lfo.alfo=rv>>ch->lfo.plfo_shft;
ch->lfo.plfo=rv>>ch->lfo.plfo_shft;
}
template<u32 state>
@ -1169,7 +1169,7 @@ s16 cdda_sector[CDDA_SIZE]={0};
u32 cdda_index=CDDA_SIZE<<1;
static SampleType mxlr[64];
SampleType mxlr[64];
u32 samples_gen;
@ -1381,3 +1381,117 @@ void AICA_Sample()
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;
};
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)
typedef s32 SampleType;
@ -45,3 +58,5 @@ void ReadCommonReg(u32 reg,bool byte);
void WriteCommonReg8(u32 reg,u32 data);
#define clip(x,min,max) if ((x)<(min)) (x)=(min); if ((x)>(max)) (x)=(max);
#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
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_IrqPending;

View File

@ -24,103 +24,14 @@ signed int sns_asc=0;
signed int sns_ascq=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;
static struct
{
u8 command;
} ata_cmd;
static struct
{
bool playing;
u32 repeats;
union
{
u32 FAD;
struct
{
u8 B0; // MSB
u8 B1; // Middle byte
u8 B2; // LSB
};
}CurrAddr,EndAddr,StartAddr;
} cdda;
read_params_t read_params ;
packet_cmd_t packet_cmd ;
read_buff_t read_buff ;
pio_buff_t pio_buff ;
ata_cmd_t ata_cmd ;
cdda_t cdda ;
gd_states gd_state;
DiscType gd_disk_type;
@ -144,16 +55,7 @@ u32 data_write_mode=0;
GD_StatusT GDStatus;
static union
{
struct
{
u8 low;
u8 hi;
};
u16 full;
} ByteCount;
ByteCount_t ByteCount;
//end
@ -217,6 +119,7 @@ void FillReadBuffer()
read_params.remaining_sectors-=count;
}
void gd_set_state(gd_states 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);
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
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_PAUSE 0x01 // Pause
#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));
}
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()
{
memset(flash_data, 0, sizeof(flash_data));
@ -701,6 +715,16 @@ struct maple_microphone: maple_base
{
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()
{
memset(micdata,0,sizeof(micdata));
@ -883,6 +907,20 @@ struct maple_sega_purupuru : maple_base
u16 AST, AST_ms;
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)
{
switch (cmd)
@ -972,12 +1010,6 @@ struct maple_sega_purupuru : maple_base
char EEPROM[0x100];
bool EEPROM_loaded = false;
struct _NaomiState
{
u8 Cmd;
u8 Mode;
u8 Node;
};
_NaomiState State;

View File

@ -31,6 +31,15 @@ struct maple_device
virtual void OnSetup(){};
virtual ~maple_device();
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);

View File

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

View File

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

View File

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

View File

@ -68,62 +68,8 @@ shil_param mk_regi(int 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
};
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;
state_t 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())
{
@ -1042,10 +988,30 @@ bool dec_generic(u32 op)
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)
{
blk=rbi;
state.Setup(blk->addr,blk->fpu_cfg);
state_Setup(blk->addr,blk->fpu_cfg);
ngen_GetFeatures(&state.ngen);
blk->guest_opcodes=0;
@ -1222,4 +1188,5 @@ _end:
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
};
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;
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();
}
void recSh4_Start()
{
Sh4_int_Start();
}
void recSh4_Step()
{
Sh4_int_Step();
@ -485,6 +490,7 @@ void Get_Sh4Recompiler(sh4_if* rv)
{
rv->Run = recSh4_Run;
rv->Stop = recSh4_Stop;
rv->Start = recSh4_Start;
rv->Step = recSh4_Step;
rv->Skip = recSh4_Skip;
rv->Reset = recSh4_Reset;

View File

@ -94,12 +94,6 @@ void ngen_ResetBlocks();
extern void (*ngen_FailedToFindBlock)();
//the dynarec mainloop
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);

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

View File

@ -2129,7 +2129,7 @@ sh4op(i0100_nnnn_0001_1011)
sh4op(i0000_nnnn_0000_0010)//0002
{
u32 n = GetN(op);
r[n] = sr.GetFull();
r[n] = sh4_sr_GetFull();
}
//sts FPSCR,<REG_N>
@ -2155,7 +2155,7 @@ sh4op(i0100_nnnn_0000_0011)
//iNimp("stc.l SR,@-<REG_N>");
u32 n = GetN(op);
r[n] -= 4;
WriteMemU32(r[n], sr.GetFull());
WriteMemU32(r[n], sh4_sr_GetFull());
}
//lds.l @<REG_N>+,FPSCR
@ -2178,7 +2178,7 @@ sh4op(i0100_nnnn_0000_0111)
u32 sr_t;
ReadMemU32(sr_t,r[n]);
sr.SetFull(sr_t);
sh4_sr_SetFull(sr_t);
r[n] += 4;
if (UpdateSR())
{
@ -2198,7 +2198,7 @@ sh4op(i0100_nnnn_0110_1010)
sh4op(i0100_nnnn_0000_1110)
{
u32 n = GetN(op);
sr.SetFull(r[n]);
sh4_sr_SetFull(r[n]);
if (UpdateSR())
{
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);
u32 offs=(u8*)addr-(u8*)&Sh4cntx;
@ -242,3 +242,7 @@ u32 Sh4Context::offset(u32 sh4_reg)
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 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 StopFP();
typedef void StartFP();
typedef void StepFP();
typedef void SkipFP();
typedef void ResetFP(bool Manual);
@ -251,6 +242,7 @@ struct sh4_if
TermFP* ResetCache;
IsCpuRunningFP* IsCpuRunning;
StartFP* Start;
};
@ -294,10 +286,11 @@ struct Sh4Context
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);
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);
@ -324,6 +317,17 @@ struct Sh4RCB
extern Sh4RCB* p_sh4rcb;
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
template<typename T>

View File

@ -38,6 +38,7 @@ enum OpcodeType
//interface
void Sh4_int_Run();
void Sh4_int_Stop();
void Sh4_int_Start();
void Sh4_int_Step();
void Sh4_int_Skip();
void Sh4_int_Reset(bool Manual);
@ -61,4 +62,4 @@ int UpdateSystem_INTC();
#if HOST_OS==OS_LINUX || HOST_OS==OS_DARWIN
}
#endif
#endif

View File

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

View File

@ -24,13 +24,6 @@
u64 sh4_sched_ffb;
u32 sh4_sched_intr;
struct sched_list
{
sh4_sched_callback* cb;
int tag;
int start;
int end;
};
vector<sched_list> list;
@ -173,4 +166,4 @@ void sh4_sched_tick(int cycles)
}
sh4_sched_ffts();
}
}
}

View File

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

View File

@ -17,6 +17,8 @@
libevdev_func2_t libevdev_event_code_get_name;
void dc_stop(void);
bool dc_loadstate(void);
bool dc_savestate(void);
void load_libevdev()
{
@ -179,6 +181,8 @@
load_keycode(&mf, "dreamcast", "btn_z"),
load_keycode(&mf, "dreamcast", "btn_start"),
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_right"),
load_keycode(&mf, "dreamcast", "btn_dpad1_up"),
@ -222,6 +226,8 @@
|| (mapping->Btn_Z == button)
|| (mapping->Btn_Start == button)
|| (mapping->Btn_Escape == button)
|| (mapping->Btn_LoadState == button)
|| (mapping->Btn_SaveState == button)
|| (mapping->Btn_DPad_Left == button)
|| (mapping->Btn_DPad_Right == 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_Start)
|| 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_Right)
|| 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;
char* mapping_path = (char*)malloc(size_needed);
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");
free(mapping_path);
}
@ -359,6 +368,7 @@
{
printf("evdev: reading mapping file: '%s'\n", mapping_fname);
loaded_mappings.insert(std::make_pair(string(mapping_fname), load_mapping(mapping_fd)));
printf("evdev: read mapping file\n") ;
fclose(mapping_fd);
}
@ -416,6 +426,10 @@
SET_FLAG(kcode[port], DC_BTN_START, ie.value);
} else if (ie.code == controller->mapping->Btn_Escape) {
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) {
SET_FLAG(kcode[port], DC_DPAD_LEFT, ie.value);
} else if (ie.code == controller->mapping->Btn_DPad_Right) {

View File

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

View File

@ -42,6 +42,8 @@ Atom wmDeleteMessage;
void* x11_vis;
void dc_stop(void);
bool dc_loadstate(void);
bool dc_savestate(void);
enum
{
@ -113,6 +115,14 @@ void input_x11_handle()
x11_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
{
int dc_key = x11_keymap[e.xkey.keycode];

View File

@ -16,8 +16,12 @@
#include "webui/server.h"
#include "hw/naomi/naomi_cart.h"
#include "reios/reios.h"
#include "hw/sh4/dyna/blockmanager.h"
settings_t settings;
static bool performed_serialization = false;
static cMutex mtx_serialization ;
static cMutex mtx_mainloop ;
/*
libndc
@ -40,6 +44,43 @@ settings_t settings;
#include <windows.h>
#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)
{
cfgLoadStr("config","image",szFileName,"null");
@ -252,9 +293,26 @@ int dc_init()
return rv;
}
bool dc_is_running()
{
return sh4_cpu.IsCpuRunning();
}
void dc_run()
{
sh4_cpu.Run();
while ( true )
{
performed_serialization = false ;
mtx_mainloop.Lock() ;
sh4_cpu.Run();
mtx_mainloop.Unlock() ;
mtx_serialization.Lock() ;
mtx_serialization.Unlock() ;
if (!performed_serialization)
break ;
}
}
void dc_term()
@ -283,6 +341,11 @@ void dc_stop()
sh4_cpu.Stop();
}
void dc_start()
{
sh4_cpu.Start();
}
void LoadSettings()
{
#ifndef _ANDROID
@ -380,3 +443,196 @@ void SaveSettings()
cfgSaveInt("config","Dreamcast.Region", settings.dreamcast.region);
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);
#else
pthread_mutex_lock(&mutx);
#endif
}
bool TryLock()
{
#if HOST_OS==OS_WINDOWS
return TryEnterCriticalSection(&cs);
#else
return pthread_mutex_trylock(&mutx)==0;
#endif
}
void Unlock()

View File

@ -517,6 +517,102 @@ using namespace std;
void 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
#pragma warning( disable : 4127 4996 /*4244*/)
#else

View File

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