Updates to 0.9.25.

This commit is contained in:
Themaister 2012-10-13 15:31:49 +02:00
parent 895970399a
commit 32a02748fe
96 changed files with 8958 additions and 6884 deletions

View File

@ -51,25 +51,32 @@ PSX_SOURCES := $(PSX_DIR)/psx.cpp \
$(PSX_DIR)/gte.cpp \
$(PSX_DIR)/dis.cpp \
$(PSX_DIR)/cdc.cpp \
$(MEDNAFEN_LIBRETRO_DIR)/psx/spu.cpp \
$(PSX_DIR)/spu.cpp \
$(PSX_DIR)/gpu.cpp \
$(PSX_DIR)/mdec.cpp \
$(PSX_DIR)/input/gamepad.cpp \
$(PSX_DIR)/input/dualanalog.cpp \
$(PSX_DIR)/input/dualshock.cpp \
$(PSX_DIR)/input/justifier.cpp \
$(PSX_DIR)/input/guncon.cpp \
$(PSX_DIR)/input/negcon.cpp \
$(PSX_DIR)/input/memcard.cpp \
$(PSX_DIR)/input/multitap.cpp \
$(PSX_DIR)/input/mouse.cpp
MEDNAFEN_SOURCES := $(MEDNAFEN_DIR)/cdrom/cdromif.cpp \
$(MEDNAFEN_LIBRETRO_DIR)/mednafen-libretro.cpp \
$(MEDNAFEN_DIR)/mednafen.cpp \
$(MEDNAFEN_DIR)/PSFLoader.cpp \
$(MEDNAFEN_DIR)/error.cpp \
$(MEDNAFEN_DIR)/math_ops.cpp \
$(MEDNAFEN_DIR)/settings.cpp \
$(MEDNAFEN_DIR)/general.cpp \
$(MEDNAFEN_DIR)/player.cpp \
$(MEDNAFEN_LIBRETRO_DIR)/cdplay.cpp \
$(MEDNAFEN_DIR)/cdplay.cpp \
$(MEDNAFEN_DIR)/FileWrapper.cpp \
$(MEDNAFEN_DIR)/FileStream.cpp \
$(MEDNAFEN_DIR)/MemoryStream.cpp \
$(MEDNAFEN_DIR)/Stream.cpp \
$(MEDNAFEN_DIR)/state.cpp \
$(MEDNAFEN_DIR)/tests.cpp \
$(MEDNAFEN_DIR)/endian.cpp \
@ -117,6 +124,7 @@ SOURCES_C := $(MEDNAFEN_DIR)/trio/trio.c \
$(MEDNAFEN_DIR)/trio/trionan.c \
$(MEDNAFEN_DIR)/trio/triostr.c \
$(MEDNAFEN_DIR)/string/world_strtod.c \
$(MEDNAFEN_DIR)/resampler/resample.c \
$(MEDNAFEN_DIR)/compress/blz.c \
$(MEDNAFEN_DIR)/compress/unzip.c \
$(MEDNAFEN_DIR)/compress/minilzo.c \
@ -150,8 +158,8 @@ WARNINGS := -Wall \
-Wno-overflow
FLAGS += $(ENDIANNESS_DEFINES) -DSIZEOF_DOUBLE=8 $(WARNINGS) \
-DMEDNAFEN_VERSION=\"0.9.24\" -DPACKAGE=\"mednafen\" -DMEDNAFEN_VERSION_NUMERIC=924 -DPSS_STYLE=1 -DMPC_FIXED_POINT -DARCH_X86 \
-DWANT_PSX_EMU -DSTDC_HEADERS
-DMEDNAFEN_VERSION=\"0.9.25\" -DPACKAGE=\"mednafen\" -DMEDNAFEN_VERSION_NUMERIC=925 -DPSS_STYLE=1 -DMPC_FIXED_POINT -DARCH_X86 \
-DWANT_PSX_EMU -DSTDC_HEADERS -D__STDC_LIMIT_MACROS
CXXFLAGS += $(FLAGS)
CFLAGS += $(FLAGS) -std=gnu99

View File

@ -20,6 +20,9 @@ static uint16_t *conv_buf;
static uint32_t *mednafen_buf;
static bool failed_init;
std::string retro_base_directory;
std::string retro_base_name;
void retro_init()
{
std::vector<MDFNGI*> ext;
@ -49,6 +52,8 @@ void retro_init()
settings.push_back(na_setting);
settings.push_back(filesys);
MDFNI_Initialize(dir, settings);
retro_base_directory = dir;
}
else
{
@ -80,6 +85,17 @@ bool retro_load_game(const struct retro_game_info *info)
if (environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
rgb32 = true;
const char *base = strrchr(info->path, '/');
if (!base)
base = strrchr(info->path, '\\');
if (base)
retro_base_name = base + 1;
else
retro_base_name = info->path;
retro_base_name = retro_base_name.substr(0, retro_base_name.find_last_of('.'));
game = MDFNI_LoadGame("psx", info->path);
if (!game)
return false;
@ -93,6 +109,7 @@ bool retro_load_game(const struct retro_game_info *info)
MDFN_PixelFormat pix_fmt(MDFN_COLORSPACE_RGB, 16, 8, 0, 24);
surf = new MDFN_Surface(mednafen_buf, fbWidth, fbHeight, 680, pix_fmt);
return game;
}
@ -315,7 +332,7 @@ void retro_get_system_info(struct retro_system_info *info)
{
memset(info, 0, sizeof(*info));
info->library_name = "Mednafen PSX";
info->library_version = "0.9.24";
info->library_version = "0.9.25";
info->need_fullpath = true;
info->valid_extensions = "cue|CUE";
}

View File

@ -1,503 +0,0 @@
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//#include <mednafen/mednafen.h>
#include "mednafen.h"
#include "cdrom/cdromif.h"
#include "netplay.h"
#include <blip/Blip_Buffer.h>
#include <trio/trio.h>
#include <vector>
#include <math.h>
using namespace CDUtility;
namespace MDFN_IEN_CDPLAY
{
static std::vector<double> sqrt_lut; //[65536];
static std::vector<double> sin_lut; //[65536];
static uint8 *controller_ptr;
static uint8 last_controller;
enum
{
PLAYMODE_PAUSE = -1,
PLAYMODE_STOP = 0,
PLAYMODE_PLAY = 1,
PLAYMODE_SCAN_FORWARD = 2,
PLAYMODE_SCAN_REVERSE = 3,
};
static int PlayMode;
static uint32 PlaySector;
static int16 CDDABuffer[588 * 2];
static uint32 PrevRate;
static std::vector<CDIF *> *cdifs;
static int32 CurrentATLI;
struct AudioTrackInfo
{
inline AudioTrackInfo(unsigned disc_, int32 track_, int32 lba_, int32 final_lba_)
{
disc = disc_;
track = track_;
lba = lba_;
final_lba = final_lba_;
}
unsigned disc;
int32 track;
int32 lba;
int32 final_lba; // Inclusive.
};
static std::vector<AudioTrackInfo> AudioTrackList;
static void InitLUT(void);
static int LoadCD(std::vector<CDIF *> *CDInterfaces)
{
cdifs = CDInterfaces;
AudioTrackList.clear();
for(unsigned disc = 0; disc < cdifs->size(); disc++)
{
TOC toc;
(*cdifs)[disc]->ReadTOC(&toc);
for(int32 track = toc.first_track; track <= toc.last_track; track++)
{
if(!(toc.tracks[track].control & 0x4))
{
AudioTrackList.push_back(AudioTrackInfo(disc, track, toc.tracks[track].lba, toc.tracks[track + 1].lba - 1));
}
}
}
if(!AudioTrackList.size())
{
puts("Audio track doesn't exist");
return(0);
}
CurrentATLI = 0;
PlaySector = AudioTrackList[CurrentATLI].lba;
PlayMode = PLAYMODE_PLAY; //STOP;
InitLUT();
return(1);
}
static bool TestMagicCD(std::vector<CDIF *> *CDInterfaces)
{
CDUtility::TOC magic_toc;
for(unsigned i = 0; i < CDInterfaces->size(); i++)
{
(*CDInterfaces)[i]->ReadTOC(&magic_toc);
// If any audio track is found, return true.
for(int32 track = magic_toc.first_track; track <= magic_toc.last_track; track++)
if(!(magic_toc.tracks[track].control & 0x4))
return(true);
}
return(false);
}
static void CloseGame(void)
{
sin_lut.resize(0);
sqrt_lut.resize(0);
}
static uint8 SubQBuf[3][0xC];
static void GenSubQFromSubPW(uint8 *SubPWBuf)
{
uint8 sq[0xC];
memset(sq, 0, 0xC);
for(int i = 0; i < 96; i++)
sq[i >> 3] |= ((SubPWBuf[i] & 0x40) >> 6) << (7 - (i & 7));
if(!subq_check_checksum(sq))
puts("SubQ checksum error!");
else
{
uint8 adr = sq[0] & 0xF;
if(adr <= 0x3)
memcpy(SubQBuf[adr], sq, 0xC);
}
}
static const int lobes = 2;
static const int oversample_shift = 7; //1; //7;
static const int oversample = 1 << oversample_shift;
static const int oversample_mo = oversample - 1;
static void InitLUT(void)
{
sqrt_lut.resize(65536);
sin_lut.resize(65536);
for(int i = 0; i < 65536; i++)
sqrt_lut[i] = sqrt((double)i / 65536);
for(int i = 0; i < 65536; i++)
sin_lut[i] = sin((double)i * M_PI * 2 / 65536);
}
static void Emulate(EmulateSpecStruct *espec)
{
uint8 sector_buffer[2352 + 96];
uint8 new_controller = *controller_ptr;
espec->MasterCycles = 588;
//printf("%d %d\n", toc.tracks[100].lba, AudioTrackList[AudioTrackList.size() - 1] + 1);
if(PlaySector > AudioTrackList[CurrentATLI].final_lba)
{
if((CurrentATLI + 1) < AudioTrackList.size())
CurrentATLI++;
else
{
CurrentATLI = 0;
PlayMode = PLAYMODE_STOP;
}
PlaySector = AudioTrackList[CurrentATLI].lba;
}
if(PlayMode == PLAYMODE_STOP || PlayMode == PLAYMODE_PAUSE)
{
}
else
{
(*cdifs)[AudioTrackList[CurrentATLI].disc]->ReadRawSector(sector_buffer, PlaySector);
GenSubQFromSubPW(sector_buffer + 2352);
for(int i = 0; i < 588 * 2; i++)
{
CDDABuffer[i] = MDFN_de16lsb(&sector_buffer[i * sizeof(int16)]);
}
}
if(espec->SoundBuf)
{
}
// for(int i = 0; i < espec->SoundBufSize * 2; i++)
// espec->SoundBuf[i] = (rand() & 0x7FFF) - 0x4000; //(rand() * 192) >> 8
if(!espec->skip)
{
char tmpbuf[256];
const MDFN_PixelFormat &format = espec->surface->format;
uint32 *pixels = espec->surface->pixels;
uint32 text_color = format.MakeColor(0xE0, 0xE0, 0xE0);
uint32 text_shadow_color = format.MakeColor(0x20, 0x20, 0x20);
uint32 cur_sector = PlaySector;
espec->DisplayRect.x = 0;
espec->DisplayRect.y = 0;
espec->DisplayRect.w = 320;
espec->DisplayRect.h = 240;
espec->surface->Fill(0, 0, 0, 0);
{
uint32 color_table[256];
for(int i = 0; i < 170; i++)
{
int m = 255 * i / 170;
color_table[i] = format.MakeColor(m, 0, m);
//printf("%d %d %08x\n", m, i, color_table[i]);
}
for(int i = 0; i < 588; i++)
{
int32 unip_samp;
int32 next_unip_samp;
unip_samp = ((CDDABuffer[i * 2 + 0] + CDDABuffer[i * 2 + 1]) >> 1) + 32768;
next_unip_samp = ((CDDABuffer[(i * 2 + 2) % 1176] + CDDABuffer[(i * 2 + 3) % 1176]) >> 1) + 32768;
for(int osi = 0; osi < oversample; osi++)
{
double sample;
int x;
int y;
double x_raw, y_raw;
double x_raw2, y_raw2;
double x_raw_prime, y_raw_prime;
sample = (double)(unip_samp * (oversample - osi) + next_unip_samp * osi) / (oversample * 65536);
int32 theta_i = (int64)65536 * (i * oversample + osi) / (oversample * 588);
int32 theta_i_alt = (int64)65536 * (i * oversample + osi) / (oversample * 588);
double radius = sin_lut[(lobes * theta_i) & 0xFFFF]; // * sin_lut[(16384 + (theta_i)) & 0xFFFF];
double radius2 = sin_lut[(lobes * (theta_i + 1)) & 0xFFFF]; // * sin_lut[(16384 + ((theta_i + 1))) & 0xFFFF];
x_raw = radius * sin_lut[(16384 + theta_i_alt) & 0xFFFF];
y_raw = radius * sin_lut[theta_i_alt & 0xFFFF];
x_raw2 = radius2 * sin_lut[(16384 + theta_i_alt + 1) & 0xFFFF];
y_raw2 = radius2 * sin_lut[(theta_i_alt + 1) & 0xFFFF];
// Approximation, of course.
x_raw_prime = (x_raw2 - x_raw) / (1 * M_PI * 2 / 65536);
y_raw_prime = (y_raw2 - y_raw) / (1 * M_PI * 2 / 65536);
// printf("%f %f\n", y_raw_prime, sin_lut[(16384 + lobes * theta_i_alt) & 0xFFFF] + sin_lut[(16384 + theta_i_alt) & 0xFFFF]);
if(x_raw_prime || y_raw_prime)
{
x_raw_prime = x_raw_prime / sqrt(x_raw_prime * x_raw_prime + y_raw_prime * y_raw_prime);
y_raw_prime = y_raw_prime / sqrt(x_raw_prime * x_raw_prime + y_raw_prime * y_raw_prime);
}
x_raw += (sample - 0.5) * y_raw_prime / 2;
y_raw += (sample - 0.5) * -x_raw_prime / 2;
x = 160 + 100 * x_raw;
y = 120 + 100 * y_raw;
if((x >= 0 && x < 320) && (y >= 0 && y < 240))
pixels[x + y * espec->surface->pitch32] = format.MakeColor(255, 255, 255); //color_table[(int)(sample * 150)]; //x * x + y * y; //format.MakeColor(sample * 255, 0, sample * 255);
}
}
}
{
TOC toc;
(*cdifs)[AudioTrackList[CurrentATLI].disc]->ReadTOC(&toc);
trio_snprintf(tmpbuf, 256, "Disc: %d/%d", AudioTrackList[CurrentATLI].disc + 1, cdifs->size());
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
trio_snprintf(tmpbuf, 256, "Track: %d/%d", AudioTrackList[CurrentATLI].track, toc.last_track);
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
trio_snprintf(tmpbuf, 256, "Sector: %d/%d", cur_sector, toc.tracks[100].lba - 1);
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
}
pixels += 22 * espec->surface->pitch32;
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)"SubQ", text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
//trio_snprintf(tmpbuf, 256, "Q-Mode: %01x", SubQBuf[1][0] & 0xF);
//DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
//pixels += 22 * espec->surface->pitch32;
trio_snprintf(tmpbuf, 256, "Track: %d", BCD_to_U8(SubQBuf[1][1]));
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
trio_snprintf(tmpbuf, 256, "Index: %d", BCD_to_U8(SubQBuf[1][2]));
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
trio_snprintf(tmpbuf, 256, "Relative: %02d:%02d:%02d", BCD_to_U8(SubQBuf[1][3]), BCD_to_U8(SubQBuf[1][4]), BCD_to_U8(SubQBuf[1][5]));
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
trio_snprintf(tmpbuf, 256, "Absolute: %02d:%02d:%02d", BCD_to_U8(SubQBuf[1][7]), BCD_to_U8(SubQBuf[1][8]), BCD_to_U8(SubQBuf[1][9]));
DrawTextTransShadow(pixels, espec->surface->pitch32 * 4, 320, (UTF8 *)tmpbuf, text_color, text_shadow_color, 0, MDFN_FONT_9x18_18x18);
pixels += 22 * espec->surface->pitch32;
}
if(PlayMode != PLAYMODE_STOP && PlayMode != PLAYMODE_PAUSE)
PlaySector++;
if(!(last_controller & 0x1) && (new_controller & 1))
{
PlayMode = (PlayMode == PLAYMODE_PLAY) ? PLAYMODE_PAUSE : PLAYMODE_PLAY;
}
if(!(last_controller & 0x2) && (new_controller & 2)) // Stop
{
PlayMode = PLAYMODE_STOP;
PlaySector = AudioTrackList[CurrentATLI].lba;
}
if(!(last_controller & 0x4) && (new_controller & 4))
{
if(CurrentATLI < (AudioTrackList.size() - 1))
CurrentATLI++;
PlaySector = AudioTrackList[CurrentATLI].lba;
}
if(!(last_controller & 0x8) && (new_controller & 8))
{
if(CurrentATLI)
CurrentATLI--;
PlaySector = AudioTrackList[CurrentATLI].lba;
}
if(!(last_controller & 0x10) && (new_controller & 0x10))
{
CurrentATLI = std::min<int>(CurrentATLI + 10, AudioTrackList.size() - 1);
PlaySector = AudioTrackList[CurrentATLI].lba;
}
if(!(last_controller & 0x20) && (new_controller & 0x20))
{
CurrentATLI = std::max<int>(CurrentATLI - 10, 0);
PlaySector = AudioTrackList[CurrentATLI].lba;
}
last_controller = new_controller;
}
static const FileExtensionSpecStruct KnownExtensions[] =
{
{ NULL, NULL }
};
static void SetInput(int port, const char *type, void *ptr)
{
controller_ptr = (uint8 *)ptr;
}
static void DoSimpleCommand(int cmd)
{
switch(cmd)
{
case MDFNNPCMD_POWER:
case MDFNNPCMD_RESET: break;
}
}
static MDFNSetting CDPlaySettings[] =
{
{ NULL }
};
static const InputDeviceInputInfoStruct IDII[] =
{
{ "play_pause", "Play/Pause", 0, IDIT_BUTTON, NULL },
{ "stop", "Stop", 1, IDIT_BUTTON, NULL },
{ "next_track", "Next Track", 2, IDIT_BUTTON, NULL },
{ "previous_track", "Previous Track", 3, IDIT_BUTTON, NULL },
{ "next_track_10", "Next Track 10", 4, IDIT_BUTTON, NULL },
{ "previous_track_10", "Previous Track 10", 5, IDIT_BUTTON, NULL },
{ "scan_forward", "Scan Forward", 6, IDIT_BUTTON, NULL },
{ "scan_reverse", "Scan Reverse", 7, IDIT_BUTTON, NULL },
//{ "reverse_seek", "Reverse Seek", 1, IDIT_BUTTON, NULL },
//{ "forward_seek", "Forward Seek", 2, IDIT_BUTTON, NULL },
//{ "fast_reverse_seek", "Fast Reverse Seek", 3, IDIT_BUTTON, NULL },
//{ "fast_forward_seek", "Fast Forward Seek", 4, IDIT_BUTTON, NULL },
};
static InputDeviceInfoStruct InputDeviceInfo[] =
{
{
"controller",
"Controller",
NULL,
sizeof(IDII) / sizeof(InputDeviceInputInfoStruct),
IDII,
}
};
static const InputPortInfoStruct PortInfo[] =
{
{ 0, "builtin", "Built-In", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo }
};
static InputInfoStruct InputInfo =
{
sizeof(PortInfo) / sizeof(InputPortInfoStruct),
PortInfo
};
}
using namespace MDFN_IEN_CDPLAY;
MDFNGI EmulatedCDPlay =
{
"cdplay",
"Mednafen Test CD-DA Player",
KnownExtensions,
MODPRIO_INTERNAL_EXTRA_LOW,
NULL, // Debug info
&InputInfo, //
NULL,
NULL,
LoadCD,
TestMagicCD,
CloseGame,
NULL,
NULL, // Layer names, null-delimited
NULL,
NULL,
NULL,
NULL,
NULL,
false,
NULL, //StateAction,
Emulate,
SetInput,
DoSimpleCommand,
CDPlaySettings,
MDFN_MASTERCLOCK_FIXED(44100),
75 * 65536 * 256,
false, // Multires possible?
320, // lcm_width
240, // lcm_height
NULL, // Dummy
320, // Nominal width
240, // Nominal height
512, // Framebuffer width
256, // Framebuffer height
2, // Number of output sound channels
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,338 +0,0 @@
#ifndef __MDFN_PSX_SPU_H
#define __MDFN_PSX_SPU_H
namespace MDFN_IEN_PSX
{
enum
{
ADSR_ATTACK = 0,
ADSR_DECAY = 1,
ADSR_SUSTAIN = 2,
ADSR_RELEASE = 3
};
struct SPU_ADSR
{
uint16 EnvLevel; // We typecast it to (int16) in several places, but keep it here as (uint16) to prevent signed overflow/underflow, which compilers
// may not treat consistently.
uint32 Divider;
uint32 Phase;
bool AttackExp;
bool SustainExp;
bool SustainDec;
bool ReleaseExp;
int32 AttackRate; // Ar
int32 DecayRate; // Dr * 4
int32 SustainRate; // Sr
int32 ReleaseRate; // Rr * 4
int32 SustainLevel; // (Sl + 1) << 11
};
class PS_SPU;
class SPU_Sweep
{
friend class PS_SPU; // For save states - FIXME(remove in future?)
public:
SPU_Sweep() { }
~SPU_Sweep() { }
void Power(void);
void WriteControl(uint16 value);
int16 ReadVolume(void);
void WriteVolume(int16 value);
void Clock(void);
private:
uint16 Control;
int16 Current;
uint32 Divider;
};
struct SPU_Voice
{
int32 DecodeBuffer[32 + 4]; // + 4 so we don't have to do & 0x1F in our MAC
int32 DecodeWritePos;
uint8 DecodeFlags;
SPU_Sweep Sweep[2];
uint16 Pitch;
uint32 CurPhase;
int32 CurPhase_SD; // Offseted compared to CurPhase, used for triggering sample decode.
uint32 StartAddr;
uint32 CurAddr;
uint32 ADSRControl;
uint32 LoopAddr;
int32 PreLRSample; // After enveloping, but before L/R volume. Range of -32768 to 32767
SPU_ADSR ADSR;
};
class PS_SPU
{
public:
PS_SPU();
~PS_SPU();
int StateAction(StateMem *sm, int load, int data_only);
void Power(void);
void Write(pscpu_timestamp_t timestamp, uint32 A, uint16 V);
uint16 Read(pscpu_timestamp_t timestamp, uint32 A);
void WriteDMA(uint32 V);
uint32 ReadDMA(void);
void StartFrame(double rate, uint32 quality);
int32 EndFrame(int16 *SoundBuf);
int32 UpdateFromCDC(int32 clocks);
//pscpu_timestamp_t Update(pscpu_timestamp_t timestamp);
static void DecodeADPCM(const uint8 *input, int16 *output, const unsigned shift, const unsigned weight);
private:
void CheckIRQAddr(uint32 addr);
void WriteSPURAM(uint32 addr, uint16 value);
uint16 ReadSPURAM(uint32 addr);
void DecodeSamples(SPU_Voice *voice);
void CacheEnvelope(SPU_Voice *voice);
void ResetEnvelope(SPU_Voice *voice);
void ReleaseEnvelope(SPU_Voice *voice);
void RunEnvelope(SPU_Voice *voice);
void RunReverb(int32 in_l, int32 in_r, int32 &out_l, int32 &out_r);
bool GetCDAudio(int32 &l, int32 &r);
SPU_Voice Voices[24];
uint32 NoiseCounter;
uint16 LFSR;
uint32 FM_Mode;
uint32 Noise_Mode;
uint32 Reverb_Mode;
int32 ReverbWA;
SPU_Sweep GlobalSweep[2]; // Doesn't affect reverb volume!
int32 ReverbVol[2];
int32 CDVol[2];
int32 ExternVol[2];
uint32 IRQAddr;
uint32 RWAddr;
uint16 SPUControl;
uint32 VoiceOn;
uint32 VoiceOff;
uint32 BlockEnd;
uint32 CWA;
int32 CDXA_ResampBuffer[2][4];
int32 CDXA_CurPhase;
union
{
uint16 Regs[0x100];
struct
{
uint16 VoiceRegs[0xC0];
union
{
uint16 GlobalRegs[0x20];
struct
{
uint16 _Global0[0x17];
uint16 SPUStatus;
uint16 _Global1[0x08];
};
};
union
{
int16 ReverbRegs[0x20];
struct
{
int16 FB_SRC_A;
int16 FB_SRC_B;
int16 IIR_ALPHA;
int16 ACC_COEF_A;
int16 ACC_COEF_B;
int16 ACC_COEF_C;
int16 ACC_COEF_D;
int16 IIR_COEF;
int16 FB_ALPHA;
int16 FB_X;
int16 IIR_DEST_A0;
int16 IIR_DEST_A1;
int16 ACC_SRC_A0;
int16 ACC_SRC_A1;
int16 ACC_SRC_B0;
int16 ACC_SRC_B1;
int16 IIR_SRC_A0;
int16 IIR_SRC_A1;
int16 IIR_DEST_B0;
int16 IIR_DEST_B1;
int16 ACC_SRC_C0;
int16 ACC_SRC_C1;
int16 ACC_SRC_D0;
int16 ACC_SRC_D1;
int16 IIR_SRC_B1;
int16 IIR_SRC_B0;
int16 MIX_DEST_A0;
int16 MIX_DEST_A1;
int16 MIX_DEST_B0;
int16 MIX_DEST_B1;
int16 IN_COEF_L;
int16 IN_COEF_R;
};
};
};
};
uint16 AuxRegs[0x10];
int16 RDSB[2][128]; // [40]
int32 RDSB_WP;
int16 RUSB[2][128];
int32 RUSB_WP;
int32 ReverbCur;
int32 Get_Reverb_Offset(int32 offset);
int32 RD_RVB(int16 raw_offs);
void WR_RVB(int16 raw_offs, int32 sample, int32 extra_offs = 0);
bool IRQAsserted;
//pscpu_timestamp_t lastts;
int32 clock_divider;
uint16 SPURAM[524288 / sizeof(uint16)];
int last_rate;
uint32 last_quality;
// Buffers 44.1KHz samples, should have enough for one video frame(~735 frames NTSC, ~882 PAL) plus jitter plus enough for the resampler leftovers.
// We'll just go with 4096 because powers of 2 are AWESOME and such.
uint32 IntermediateBufferPos;
int16 IntermediateBuffer[4096][2];
public:
enum
{
GSREG_SPUCONTROL = 0,
GSREG_FM_ON,
GSREG_NOISE_ON,
GSREG_REVERB_ON,
GSREG_CDVOL_L,
GSREG_CDVOL_R,
GSREG_DRYVOL_CTRL_L,
GSREG_DRYVOL_CTRL_R,
GSREG_DRYVOL_L,
GSREG_DRYVOL_R,
GSREG_WETVOL_L,
GSREG_WETVOL_R,
GSREG_RWADDR,
GSREG_IRQADDR,
GSREG_REVERBWA,
GSREG_VOICEON,
GSREG_VOICEOFF,
GSREG_BLOCKEND,
// Note: the order of these should match the reverb reg array
GSREG_FB_SRC_A,
GSREG_FB_SRC_B,
GSREG_IIR_ALPHA,
GSREG_ACC_COEF_A,
GSREG_ACC_COEF_B,
GSREG_ACC_COEF_C,
GSREG_ACC_COEF_D,
GSREG_IIR_COEF,
GSREG_FB_ALPHA,
GSREG_FB_X,
GSREG_IIR_DEST_A0,
GSREG_IIR_DEST_A1,
GSREG_ACC_SRC_A0,
GSREG_ACC_SRC_A1,
GSREG_ACC_SRC_B0,
GSREG_ACC_SRC_B1,
GSREG_IIR_SRC_A0,
GSREG_IIR_SRC_A1,
GSREG_IIR_DEST_B0,
GSREG_IIR_DEST_B1,
GSREG_ACC_SRC_C0,
GSREG_ACC_SRC_C1,
GSREG_ACC_SRC_D0,
GSREG_ACC_SRC_D1,
GSREG_IIR_SRC_B1,
GSREG_IIR_SRC_B0,
GSREG_MIX_DEST_A0,
GSREG_MIX_DEST_A1,
GSREG_MIX_DEST_B0,
GSREG_MIX_DEST_B1,
GSREG_IN_COEF_L,
GSREG_IN_COEF_R,
// Multiply v * 256 for each extra voice
GSREG_V0_VOL_CTRL_L = 0x8000,
GSREG_V0_VOL_CTRL_R,
GSREG_V0_VOL_L,
GSREG_V0_VOL_R,
GSREG_V0_PITCH,
GSREG_V0_STARTADDR,
GSREG_V0_ADSR_CTRL,
GSREG_V0_ADSR_LEVEL,
GSREG_V0_LOOP_ADDR,
GSREG_V0_READ_ADDR
};
uint32 GetRegister(unsigned int which, char *special, const uint32 special_len);
void SetRegister(unsigned int which, uint32 value);
uint16 PeekSPURAM(uint32 address);
void PokeSPURAM(uint32 address, uint16 value);
};
}
#endif

96
mednafen/FileStream.cpp Normal file
View File

@ -0,0 +1,96 @@
// TODO/WIP
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "mednafen.h"
#include "Stream.h"
#include "FileStream.h"
#include <trio/trio.h>
FileStream::FileStream(const char *path, const int mode) : fw(path, mode), OpenedMode(mode)
{
}
FileStream::~FileStream()
{
}
uint64 FileStream::attributes(void)
{
uint64 ret = ATTRIBUTE_SEEKABLE;
switch(OpenedMode)
{
case MODE_READ:
ret |= ATTRIBUTE_READABLE;
break;
case MODE_WRITE_SAFE:
case MODE_WRITE:
ret |= ATTRIBUTE_WRITEABLE;
break;
}
return ret;
}
uint8 *FileStream::map(void)
{
//return fw.map();
return(NULL);
}
void FileStream::unmap(void)
{
//fw.unmap();
}
uint64 FileStream::read(void *data, uint64 count, bool error_on_eos)
{
return fw.read(data, count, error_on_eos);
}
void FileStream::write(const void *data, uint64 count)
{
fw.write(data, count);
}
void FileStream::seek(int64 offset, int whence)
{
fw.seek(offset, whence);
}
int64 FileStream::tell(void)
{
return fw.tell();
}
int64 FileStream::size(void)
{
return fw.size();
}
void FileStream::close(void)
{
fw.close();
}

59
mednafen/FileStream.h Normal file
View File

@ -0,0 +1,59 @@
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// TODO/WIP
#ifndef __MDFN_FILESTREAM_H
#define __MDFN_FILESTREAM_H
#include "Stream.h"
#include "FileWrapper.h"
class FileStream : public Stream
{
public:
enum
{
MODE_READ = FileWrapper::MODE_READ,
MODE_WRITE = FileWrapper::MODE_WRITE,
MODE_WRITE_SAFE = FileWrapper::MODE_WRITE_SAFE
};
FileStream(const char *path, const int mode);
virtual ~FileStream();
virtual uint64 attributes(void);
virtual uint8 *map(void);
virtual void unmap(void);
virtual uint64 read(void *data, uint64 count, bool error_on_eos = true);
virtual void write(const void *data, uint64 count);
virtual void seek(int64 offset, int whence);
virtual int64 tell(void);
virtual int64 size(void);
virtual void close(void);
private:
FileWrapper fw;
const int OpenedMode;
};
#endif

257
mednafen/MemoryStream.cpp Normal file
View File

@ -0,0 +1,257 @@
#include "MemoryStream.h"
#include <stdint.h>
/*
TODO:
Write and Seek expansion that fail should not corrupt the state.
Copy and assignment constructor fixes.
*/
// TODO 128-bit integers for range checking?
MemoryStream::MemoryStream() : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0)
{
data_buffer_size = 0;
data_buffer_alloced = 64;
if(!(data_buffer = (uint8*)realloc(data_buffer, data_buffer_alloced)))
throw MDFN_Error(ErrnoHolder(errno));
}
MemoryStream::MemoryStream(uint64 size_hint) : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0)
{
data_buffer_size = 0;
data_buffer_alloced = (size_hint > SIZE_MAX) ? SIZE_MAX : size_hint;
if(!(data_buffer = (uint8*)realloc(data_buffer, data_buffer_alloced)))
throw MDFN_Error(ErrnoHolder(errno));
}
MemoryStream::MemoryStream(Stream *stream) : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0)
{
try
{
if((position = stream->tell()) != 0)
stream->seek(0, SEEK_SET);
data_buffer_size = stream->size();
data_buffer_alloced = data_buffer_size;
if(!(data_buffer = (uint8*)realloc(data_buffer, data_buffer_alloced)))
throw MDFN_Error(ErrnoHolder(errno));
stream->read(data_buffer, data_buffer_size);
stream->close();
}
catch(...)
{
if(data_buffer)
{
free(data_buffer);
data_buffer = NULL;
}
delete stream;
throw;
}
delete stream;
}
MemoryStream::MemoryStream(const MemoryStream &zs)
{
data_buffer_size = zs.data_buffer_size;
data_buffer_alloced = zs.data_buffer_alloced;
if(!(data_buffer = (uint8*)malloc(data_buffer_alloced)))
throw MDFN_Error(ErrnoHolder(errno));
memcpy(data_buffer, zs.data_buffer, data_buffer_size);
position = zs.position;
}
#if 0
MemoryStream & MemoryStream::operator=(const MemoryStream &zs)
{
if(this != &zs)
{
if(data_buffer)
{
free(data_buffer);
data_buffer = NULL;
}
data_buffer_size = zs.data_buffer_size;
data_buffer_alloced = zs.data_buffer_alloced;
if(!(data_buffer = (uint8*)malloc(data_buffer_alloced)))
throw MDFN_Error(ErrnoHolder(errno));
memcpy(data_buffer, zs.data_buffer, data_buffer_size);
position = zs.position;
}
return(*this);
}
#endif
MemoryStream::~MemoryStream()
{
if(data_buffer)
{
free(data_buffer);
data_buffer = NULL;
}
}
uint64 MemoryStream::attributes(void)
{
return (ATTRIBUTE_READABLE | ATTRIBUTE_WRITEABLE | ATTRIBUTE_SEEKABLE);
}
uint8 *MemoryStream::map(void)
{
return data_buffer;
}
void MemoryStream::unmap(void)
{
}
INLINE void MemoryStream::grow_if_necessary(uint64 new_required_size)
{
if(new_required_size > data_buffer_size)
{
if(new_required_size > data_buffer_alloced)
{
uint64 new_required_alloced = round_up_pow2(new_required_size);
uint8 *new_data_buffer;
// first condition will happen at new_required_size > (1ULL << 63) due to round_up_pow2() "wrapping".
// second condition can occur when running on a 32-bit system.
if(new_required_alloced < new_required_size || new_required_alloced > SIZE_MAX)
new_required_alloced = SIZE_MAX;
// If constrained alloc size isn't enough, throw an out-of-memory/address-space type error.
if(new_required_alloced < new_required_size)
throw MDFN_Error(ErrnoHolder(ENOMEM));
if(!(new_data_buffer = (uint8*)realloc(data_buffer, new_required_alloced)))
throw MDFN_Error(ErrnoHolder(errno));
//
// Assign all in one go after the realloc() so we don't leave our object in an inconsistent state if the realloc() fails.
//
data_buffer = new_data_buffer;
data_buffer_size = new_required_size;
data_buffer_alloced = new_required_alloced;
}
else
data_buffer_size = new_required_size;
}
}
uint64 MemoryStream::read(void *data, uint64 count, bool error_on_eos)
{
if(count > data_buffer_size)
{
if(error_on_eos)
throw MDFN_Error(0, _("EOF"));
count = data_buffer_size;
}
if((uint64)position > (data_buffer_size - count))
{
if(error_on_eos)
throw MDFN_Error(0, _("EOF"));
count = data_buffer_size - position;
}
memmove(data, &data_buffer[position], count);
position += count;
return count;
}
void MemoryStream::write(const void *data, uint64 count)
{
uint64 nrs = position + count;
if(nrs < position)
throw MDFN_Error(ErrnoHolder(EFBIG));
grow_if_necessary(nrs);
memmove(&data_buffer[position], data, count);
position += count;
}
void MemoryStream::seek(int64 offset, int whence)
{
int64 new_position;
switch(whence)
{
default:
throw MDFN_Error(ErrnoHolder(EINVAL));
break;
case SEEK_SET:
new_position = offset;
break;
case SEEK_CUR:
new_position = position + offset;
break;
case SEEK_END:
new_position = data_buffer_size + offset;
break;
}
if(new_position < 0)
throw MDFN_Error(ErrnoHolder(EINVAL));
else
grow_if_necessary(new_position);
position = new_position;
}
int64 MemoryStream::tell(void)
{
return position;
}
int64 MemoryStream::size(void)
{
return data_buffer_size;
}
void MemoryStream::close(void)
{
}
int MemoryStream::get_line(std::string &str)
{
str.clear(); // or str.resize(0)??
while(position < data_buffer_size)
{
uint8 c = data_buffer[position++];
if(c == '\r' || c == '\n' || c == 0)
return(c);
str.push_back(c); // Should be faster than str.append(1, c)
}
return(-1);
}

70
mednafen/MemoryStream.h Normal file
View File

@ -0,0 +1,70 @@
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// TODO/WIP
#include "Stream.h"
class MemoryStream : public Stream
{
public:
MemoryStream();
MemoryStream(uint64 size_hint);
MemoryStream(Stream *stream); // Will create a MemoryStream equivalent of the contents of "stream", and then "delete stream".
// Will only work if stream->tell() == 0, or if "stream" is seekable.
// stream will be deleted even if this constructor throws.
MemoryStream(const MemoryStream &zs);
MemoryStream & operator=(const MemoryStream &zs);
#if 0
enum GrowMode
{
GROWMODE_POW2 = 0,
GROWMODE_
};
void set_grow_mode(
#endif
virtual ~MemoryStream();
virtual uint64 attributes(void);
virtual uint8 *map(void);
virtual void unmap(void);
virtual uint64 read(void *data, uint64 count, bool error_on_eos = true);
virtual void write(const void *data, uint64 count);
virtual void seek(int64 offset, int whence);
virtual int64 tell(void);
virtual int64 size(void);
virtual void close(void);
virtual int get_line(std::string &str);
private:
uint8 *data_buffer;
uint64 data_buffer_size;
uint64 data_buffer_alloced;
int64 position;
void grow_if_necessary(uint64 new_required_size);
};

126
mednafen/Stream.cpp Normal file
View File

@ -0,0 +1,126 @@
// TODO/WIP
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "mednafen.h"
#include "Stream.h"
#include <trio/trio.h>
Stream::Stream()
{
}
Stream::~Stream()
{
}
void Stream::printf(const char *format, ...)
{
char *str = NULL;
int rc;
va_list ap;
va_start(ap, format);
rc = trio_vasprintf(&str, format, ap);
va_end(ap);
if(rc < 0)
throw MDFN_Error(0, "Error in trio_vasprintf()");
else
{
try // Bleck
{
write(str, rc);
}
catch(...)
{
free(str);
throw;
}
free(str);
}
}
#if 0
int Stream::scanf(const char *format, ...)
{
}
void Stream::printf(const char *format, ...)
{
}
void Stream::put_string(const char *str)
{
write(str, strlen(str));
}
void Stream::put_string(const std::string &str)
{
write(str.data(), str.size());
}
#endif
int Stream::get_line(std::string &str)
{
uint8 c;
str.clear(); // or str.resize(0)??
while(read(&c, sizeof(c), false) > 0)
{
if(c == '\r' || c == '\n' || c == 0)
return(c);
str.push_back(c);
}
return(-1);
}
StreamFilter::StreamFilter()
{
target_stream = NULL;
}
StreamFilter::StreamFilter(Stream *target_arg)
{
target_stream = target_arg;
}
StreamFilter::~StreamFilter()
{
if(target_stream)
delete target_stream;
}
Stream* StreamFilter::steal(void)
{
Stream *ret = target_stream;
target_stream = NULL;
return ret;
}

188
mednafen/Stream.h Normal file
View File

@ -0,0 +1,188 @@
#ifndef __MDFN_STREAM_H
#define __MDFN_STREAM_H
// TODO/WIP
// TODO?: BufferedStream, no virtual functions, yes inline functions, constructor takes a Stream* argument.
#include "mednafen.h"
#include <errno.h>
#include <stdio.h> // For SEEK_* defines, which we will use in Stream out of FORCE OF HABIT.
class Stream
{
public:
Stream();
virtual ~Stream();
enum
{
ATTRIBUTE_READABLE = 0,
ATTRIBUTE_WRITEABLE,
ATTRIBUTE_SEEKABLE
};
virtual uint64 attributes(void) = 0;
virtual uint8 *map(void) = 0; // Map the entirety of the stream data into the address space of the process, if possible, and return a pointer.
// (the returned pointer must be cached, and returned on any subsequent calls to map() without an unmap()
// in-between, to facilitate a sort of "feature-testing", to determine if an alternative like "MemoryStream"
// should be used).
virtual void unmap(void) = 0; // Unmap the stream data from the address space. (Possibly invalidating the pointer returned from map()).
// (must automatically be called, if necessary, from the destructor).
virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) = 0;
virtual void write(const void *data, uint64 count) = 0;
virtual void seek(int64 offset, int whence) = 0;
virtual int64 tell(void) = 0;
virtual int64 size(void) = 0;
virtual void close(void) = 0; // Flushes(in the case of writeable streams) and closes the stream.
// Necessary since this operation can fail(running out of disk space, for instance),
// and throw an exception in the destructor would be a Bad Idea(TM).
//
// Manually calling this function isn't strictly necessary, but recommended when the
// stream is writeable; it will be called automatically from the destructor, with any
// exceptions thrown caught and logged.
//
// Utility functions(TODO):
//
INLINE uint8 get_u8(void)
{
uint8 ret;
read(&ret, sizeof(ret));
return ret;
}
INLINE void put_u8(uint8 c)
{
write(&c, sizeof(c));
}
template<typename T>
INLINE T get_NE(void)
{
T ret;
read(&ret, sizeof(ret));
return ret;
}
template<typename T>
INLINE void put_NE(T c)
{
write(&c, sizeof(c));
}
template<typename T>
INLINE T get_RE(void)
{
uint8 tmp[sizeof(T)];
T ret = 0;
read(tmp, sizeof(tmp));
for(unsigned i = 0; i < sizeof(T); i++)
ret |= (T)tmp[i] << (i * 8);
return ret;
}
template<typename T>
INLINE void put_RE(T c)
{
uint8 tmp[sizeof(T)];
for(unsigned i = 0; i < sizeof(T); i++)
tmp[i] = ((uint8 *)&c)[sizeof(T) - 1 - i];
write(tmp, sizeof(tmp));
}
template<typename T>
INLINE T get_LE(void)
{
#ifdef LSB_FIRST
return get_NE<T>();
#else
return get_RE<T>();
#endif
}
template<typename T>
INLINE void put_LE(T c)
{
#ifdef LSB_FIRST
return put_NE<T>(c);
#else
return put_RE<T>(c);
#endif
}
template<typename T>
INLINE T get_BE(void)
{
#ifndef LSB_FIRST
return get_NE<T>();
#else
return get_RE<T>();
#endif
}
template<typename T>
INLINE void put_BE(T c)
{
#ifndef LSB_FIRST
return put_NE<T>(c);
#else
return put_RE<T>(c);
#endif
}
// Reads a line into "str", overwriting its contents; returns the line-end char('\n' or '\r' or '\0'), or -1 on EOF.
// The line-end char won't be added to "str".
// It's up to the caller to handle extraneous empty lines caused by DOS-format text lines(\r\n).
// ("str" is passed by reference for the possibility of improved performance by reusing alloced memory for the std::string, though part
// of it would be up to the STL implementation).
// Implemented as virtual so that a higher-performance version can be implemented if possible(IE with MemoryStream)
virtual int get_line(std::string &str);
virtual void printf(const char *format, ...) MDFN_FORMATSTR(printf, 2, 3);
#if 0
int scanf(const char *format, ...) MDFN_FORMATSTR(scanf, 2, 3);
void put_string(const char *str);
void put_string(const std::string &str);
#endif
};
// StreamFilter takes ownership of the Stream pointer passed, and will delete it in its destructor.
class StreamFilter : public Stream
{
public:
StreamFilter();
StreamFilter(Stream *target_arg);
virtual ~StreamFilter();
virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) = 0;
virtual void write(const void *data, uint64 count) = 0;
virtual void seek(int64 offset, int whence) = 0;
virtual int64 tell(void) = 0;
virtual int64 size(void) = 0;
virtual void close(void) = 0;
virtual Stream *steal(void);
private:
Stream *target_stream;
};
#endif

View File

@ -48,7 +48,7 @@ enum
};
static int PlayMode;
static uint32 PlaySector;
static int32 PlaySector;
static int16 CDDABuffer[588 * 2];
static int16 ResampBuffer[588 * 2][2]; // Resampler input buffer, * 2 for resampler leftovers
@ -199,7 +199,21 @@ static void Emulate(EmulateSpecStruct *espec)
//printf("%d %d\n", toc.tracks[100].lba, AudioTrackList[AudioTrackList.size() - 1] + 1);
if(PlaySector > AudioTrackList[CurrentATLI].final_lba)
if(PlaySector < AudioTrackList[CurrentATLI].lba) // Reverse-scanning handling.
{
if(CurrentATLI > 0)
{
CurrentATLI--;
PlaySector = AudioTrackList[CurrentATLI].final_lba;
}
else
{
CurrentATLI = 0;
PlayMode = PLAYMODE_STOP;
PlaySector = AudioTrackList[CurrentATLI].lba;
}
}
else if(PlaySector > AudioTrackList[CurrentATLI].final_lba)
{
if((CurrentATLI + 1) < AudioTrackList.size())
CurrentATLI++;
@ -207,11 +221,11 @@ static void Emulate(EmulateSpecStruct *espec)
{
CurrentATLI = 0;
PlayMode = PLAYMODE_STOP;
}
}
PlaySector = AudioTrackList[CurrentATLI].lba;
}
if(PlayMode == PLAYMODE_STOP || PlayMode == PLAYMODE_PAUSE)
{
//memset(CDDABuffer, 0, sizeof(CDDABuffer));
@ -407,7 +421,16 @@ static void Emulate(EmulateSpecStruct *espec)
}
if(PlayMode != PLAYMODE_STOP && PlayMode != PLAYMODE_PAUSE)
PlaySector++;
{
const int scan_amount = 4; //16;
if(new_controller & 0x40)
PlaySector += scan_amount;
else if(new_controller & 0x80)
PlaySector -= scan_amount;
else
PlaySector++;
}
if(!(last_controller & 0x1) && (new_controller & 1))
{
@ -501,6 +524,7 @@ static InputDeviceInfoStruct InputDeviceInfo[] =
"controller",
"Controller",
NULL,
NULL,
sizeof(IDII) / sizeof(InputDeviceInputInfoStruct),
IDII,
}
@ -508,7 +532,7 @@ static InputDeviceInfoStruct InputDeviceInfo[] =
static const InputPortInfoStruct PortInfo[] =
{
{ 0, "builtin", "Built-In", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo }
{ "builtin", "Built-In", sizeof(InputDeviceInfo) / sizeof(InputDeviceInfoStruct), InputDeviceInfo }
};
static InputInfoStruct InputInfo =

View File

@ -41,7 +41,7 @@ CDAccess::~CDAccess()
}
CDAccess *cdaccess_open(const char *path)
CDAccess *cdaccess_open(const char *path, bool image_memcache)
{
CDAccess *ret;
struct stat stat_buf;
@ -51,7 +51,7 @@ CDAccess *cdaccess_open(const char *path)
ret = new CDAccess_Physical(path);
else
#endif
ret = new CDAccess_Image(path);
ret = new CDAccess_Image(path, image_memcache);
return ret;
}

View File

@ -21,6 +21,6 @@ class CDAccess
virtual void Eject(bool eject_status) = 0; // Eject a disc if it's physical, otherwise NOP. Returns true on success(or NOP), false on error
};
CDAccess *cdaccess_open(const char *path);
CDAccess *cdaccess_open(const char *path, bool image_memcache);
#endif

View File

@ -43,7 +43,8 @@
#include "../general.h"
#include "../mednafen-endian.h"
#include "../FileWrapper.h"
#include "../FileStream.h"
#include "../MemoryStream.h"
#include "CDAccess.h"
#include "CDAccess_Image.h"
@ -161,53 +162,26 @@ uint32 CDAccess_Image::GetSectorCount(CDRFILE_TRACK_INFO *track)
return(((track->AReader->FrameCount() * 4) - track->FileOffset) / 2352);
else
{
struct stat stat_buf;
fstat(fileno(track->fp), &stat_buf);
const int64 size = track->fp->size();
//printf("%d %d %d\n", (int)stat_buf.st_size, (int)track->FileOffset, (int)stat_buf.st_size - (int)track->FileOffset);
if(track->SubchannelMode)
return((stat_buf.st_size - track->FileOffset) / (2352 + 96));
return((size - track->FileOffset) / (2352 + 96));
else
return((stat_buf.st_size - track->FileOffset) / 2352);
return((size - track->FileOffset) / 2352);
}
}
else
{
struct stat stat_buf;
if(fstat(fileno(track->fp), &stat_buf))
{
ErrnoHolder ene(errno);
throw MDFN_Error(ene.Errno(), "%s", ene.StrError());
}
return((stat_buf.st_size - track->FileOffset) / DI_Size_Table[track->DIFormat]);
const int64 size = track->fp->size();
return((size - track->FileOffset) / DI_Size_Table[track->DIFormat]);
}
return(0);
}
CDAccess_Image::~CDAccess_Image()
{
for(int32 track = FirstTrack; track < (FirstTrack + NumTracks); track++)
{
CDRFILE_TRACK_INFO *this_track = &Tracks[track];
if(this_track->FirstFileInstance)
{
if(Tracks[track].AReader)
{
delete Tracks[track].AReader;
Tracks[track].AReader = NULL;
}
else if(this_track->fp)
fclose(this_track->fp);
}
}
}
void CDAccess_Image::ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int tracknum, const char *filename, const char *binoffset, const char *msfoffset, const char *length)
void CDAccess_Image::ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int tracknum, const char *filename, const char *binoffset, const char *msfoffset, const char *length, bool image_memcache)
{
long offset = 0; // In bytes!
long tmp_long;
@ -217,13 +191,9 @@ void CDAccess_Image::ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int t
std::string efn;
efn = MDFN_EvalFIP(base_dir, filename);
if(NULL == (track->fp = fopen(efn.c_str(), "rb")))
{
ErrnoHolder ene(errno);
throw MDFN_Error(ene.Errno(), _("Could not open referenced file \"%s\": %s\n"), efn.c_str(), ene.StrError());
}
track->fp = new FileStream(efn.c_str(), FileStream::MODE_READ);
if(image_memcache)
track->fp = new MemoryStream(track->fp);
if(strlen(filename) >= 4 && !strcasecmp(filename + strlen(filename) - 4, ".wav"))
{
@ -287,7 +257,7 @@ void CDAccess_Image::ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int t
void CDAccess_Image::ImageOpen(const char *path)
void CDAccess_Image::ImageOpen(const char *path, bool image_memcache)
{
FileWrapper fp(path, FileWrapper::MODE_READ);
bool IsTOC = FALSE;
@ -306,6 +276,22 @@ void CDAccess_Image::ImageOpen(const char *path)
puts("TOC file detected.");
IsTOC = true;
}
// Check for annoying UTF-8 BOM.
if(!IsTOC)
{
uint8 bom_tmp[3];
if(fp.read(bom_tmp, 3, false) == 3 && bom_tmp[0] == 0xEF && bom_tmp[1] == 0xBB && bom_tmp[2] == 0xBF)
{
// Print an annoying error message, but don't actually error out.
MDFN_PrintError(_("UTF-8 BOM detected at start of CUE sheet."));
}
else
fp.seek(0, SEEK_SET);
}
// Assign opposite maximum values so our tests will work!
FirstTrack = 99;
LastTrack = 0;
@ -429,7 +415,7 @@ void CDAccess_Image::ImageOpen(const char *path)
length = args[2];
}
//printf("%s, %s, %s, %s\n", args[0], binoffset, msfoffset, length);
ParseTOCFileLineInfo(&TmpTrack, active_track, args[0], binoffset, msfoffset, length);
ParseTOCFileLineInfo(&TmpTrack, active_track, args[0], binoffset, msfoffset, length, image_memcache);
}
else if(!strcasecmp(cmdbuf, "DATAFILE"))
{
@ -444,7 +430,7 @@ void CDAccess_Image::ImageOpen(const char *path)
else
length = args[1];
ParseTOCFileLineInfo(&TmpTrack, active_track, args[0], binoffset, NULL, length);
ParseTOCFileLineInfo(&TmpTrack, active_track, args[0], binoffset, NULL, length, image_memcache);
}
else if(!strcasecmp(cmdbuf, "INDEX"))
{
@ -488,14 +474,12 @@ void CDAccess_Image::ImageOpen(const char *path)
}
std::string efn = MDFN_EvalFIP(base_dir, args[0]);
if(NULL == (TmpTrack.fp = fopen(efn.c_str(), "rb")))
{
ErrnoHolder ene(errno);
throw(MDFN_Error(ene.Errno(), _("Could not open referenced file \"%s\": %s\n"), efn.c_str(), ene.StrError()));
}
TmpTrack.fp = new FileStream(efn.c_str(), FileStream::MODE_READ);
TmpTrack.FirstFileInstance = 1;
if(image_memcache)
TmpTrack.fp = new MemoryStream(TmpTrack.fp);
if(!strcasecmp(args[1], "BINARY"))
{
//TmpTrack.Format = TRACK_FORMAT_DATA;
@ -683,9 +667,47 @@ void CDAccess_Image::ImageOpen(const char *path)
total_sectors = RunningLBA;
}
CDAccess_Image::CDAccess_Image(const char *path)
void CDAccess_Image::Cleanup(void)
{
ImageOpen(path);
for(int32 track = 0; track < 100; track++)
{
CDRFILE_TRACK_INFO *this_track = &Tracks[track];
if(this_track->FirstFileInstance)
{
if(Tracks[track].AReader)
{
delete Tracks[track].AReader;
Tracks[track].AReader = NULL;
}
if(this_track->fp)
{
delete this_track->fp;
this_track->fp = NULL;
}
}
}
}
CDAccess_Image::CDAccess_Image(const char *path, bool image_memcache) : NumTracks(0), FirstTrack(0), LastTrack(0), total_sectors(0)
{
memset(Tracks, 0, sizeof(Tracks));
try
{
ImageOpen(path, image_memcache);
}
catch(...)
{
Cleanup();
throw;
}
}
CDAccess_Image::~CDAccess_Image()
{
Cleanup();
}
void CDAccess_Image::Read_Raw_Sector(uint8 *buf, int32 lba)
@ -744,29 +766,29 @@ void CDAccess_Image::Read_Raw_Sector(uint8 *buf, int32 lba)
if(ct->SubchannelMode)
SeekPos += 96 * (lba - ct->LBA);
fseek(ct->fp, SeekPos, SEEK_SET);
ct->fp->seek(SeekPos, SEEK_SET);
switch(ct->DIFormat)
{
case DI_FORMAT_AUDIO:
fread(buf, 1, 2352, ct->fp);
ct->fp->read(buf, 2352);
if(ct->RawAudioMSBFirst)
Endian_A16_Swap(buf, 588 * 2);
break;
case DI_FORMAT_MODE1:
fread(buf + 12 + 3 + 1, 1, 2048, ct->fp);
ct->fp->read(buf + 12 + 3 + 1, 2048);
encode_mode1_sector(lba + 150, buf);
break;
case DI_FORMAT_MODE1_RAW:
case DI_FORMAT_MODE2_RAW:
fread(buf, 1, 2352, ct->fp);
ct->fp->read(buf, 2352);
break;
case DI_FORMAT_MODE2:
fread(buf + 16, 1, 2336, ct->fp);
ct->fp->read(buf + 16, 2336);
encode_mode2_sector(lba + 150, buf);
break;
@ -774,19 +796,19 @@ void CDAccess_Image::Read_Raw_Sector(uint8 *buf, int32 lba)
// FIXME: M2F1, M2F2, does sub-header come before or after user data(standards say before, but I wonder
// about cdrdao...).
case DI_FORMAT_MODE2_FORM1:
fread(buf + 24, 1, 2048, ct->fp);
ct->fp->read(buf + 24, 2048);
//encode_mode2_form1_sector(lba + 150, buf);
break;
case DI_FORMAT_MODE2_FORM2:
fread(buf + 24, 1, 2324, ct->fp);
ct->fp->read(buf + 24, 2324);
//encode_mode2_form2_sector(lba + 150, buf);
break;
}
if(ct->SubchannelMode)
fread(buf + 2352, 1, 96, ct->fp);
ct->fp->read(buf + 2352, 96);
}
} // end if audible part of audio track read.
break;

View File

@ -1,6 +1,7 @@
#ifndef __MDFN_CDACCESS_IMAGE_H
#define __MDFN_CDACCESS_IMAGE_H
class Stream;
class AudioReader;
struct CDRFILE_TRACK_INFO
@ -18,7 +19,7 @@ struct CDRFILE_TRACK_INFO
int32 index[2];
int32 sectors; // Not including pregap sectors!
FILE *fp;
Stream *fp;
bool FirstFileInstance;
bool RawAudioMSBFirst;
long FileOffset;
@ -60,7 +61,7 @@ class CDAccess_Image : public CDAccess
{
public:
CDAccess_Image(const char *path);
CDAccess_Image(const char *path, bool image_memcache);
virtual ~CDAccess_Image();
virtual void Read_Raw_Sector(uint8 *buf, int32 lba);
@ -80,12 +81,13 @@ class CDAccess_Image : public CDAccess
std::string base_dir;
void ImageOpen(const char *path);
void ImageOpen(const char *path, bool image_memcache);
void Cleanup(void);
// MakeSubPQ will OR the simulated P and Q subchannel data into SubPWBuf.
void MakeSubPQ(int32 lba, uint8 *SubPWBuf);
void ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int tracknum, const char *filename, const char *binoffset, const char *msfoffset, const char *length);
void ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int tracknum, const char *filename, const char *binoffset, const char *msfoffset, const char *length, bool image_memcache);
uint32 GetSectorCount(CDRFILE_TRACK_INFO *track);
};

View File

@ -15,6 +15,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// AR_Open(), and AudioReader, will NOT take "ownership" of the Stream object(IE it won't ever delete it). Though it does assume it has exclusive access
// to it for as long as the AudioReader object exists.
// Don't allow exceptions to propagate into the vorbis/musepack/etc. libraries, as it could easily leave the state of the library's decoder "object" in an
// inconsistent state, which would cause all sorts of unfun when we try to destroy it while handling the exception farther up.
#include "../mednafen.h"
#include "audioreader.h"
@ -28,15 +34,18 @@
#include <sndfile.h>
#endif
#ifdef HAVE_OPUSFILE
#include "audioreader_opus.h"
#endif
#include <string.h>
#include <errno.h>
#include <time.h>
#include <trio/trio.h>
#include "../general.h"
#include "../mednafen-endian.h"
AudioReader::AudioReader()
AudioReader::AudioReader() : LastReadPos(0)
{
}
@ -64,78 +73,253 @@ int64 AudioReader::FrameCount(void)
return(0);
}
/*
**
**
**
**
**
**
**
**
**
*/
class OggVorbisReader : public AudioReader
{
public:
OggVorbisReader(FILE *fp)
{
fseek(fp, 0, SEEK_SET);
lseek(fileno(fp), 0, SEEK_SET);
OggVorbisReader(Stream *fp);
~OggVorbisReader();
if(ov_open(fp, &ovfile, NULL, 0))
throw(0);
}
~OggVorbisReader()
{
ov_clear(&ovfile);
}
int64 Read_(int16 *buffer, int64 frames)
{
uint8 *tw_buf = (uint8 *)buffer;
int cursection = 0;
long toread = frames * sizeof(int16) * 2;
while(toread > 0)
{
long didread = ov_read(&ovfile, (char*)tw_buf, toread, &cursection);
if(didread == 0)
break;
tw_buf = (uint8 *)tw_buf + didread;
toread -= didread;
}
return(frames - toread / sizeof(int16) / 2);
}
bool Seek_(int64 frame_offset)
{
ov_pcm_seek(&ovfile, frame_offset);
return(true);
}
int64 FrameCount(void)
{
return(ov_pcm_total(&ovfile, -1));
}
int64 Read_(int16 *buffer, int64 frames);
bool Seek_(int64 frame_offset);
int64 FrameCount(void);
private:
OggVorbis_File ovfile;
Stream *fw;
};
static size_t iov_read_func(void *ptr, size_t size, size_t nmemb, void *user_data)
{
Stream *fw = (Stream*)user_data;
if(!size)
return(0);
try
{
return fw->read(ptr, size * nmemb, false) / size;
}
catch(...)
{
return(0);
}
}
static int iov_seek_func(void *user_data, ogg_int64_t offset, int whence)
{
Stream *fw = (Stream*)user_data;
try
{
fw->seek(offset, whence);
return(0);
}
catch(...)
{
return(-1);
}
}
static int iov_close_func(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
fw->close();
return(0);
}
catch(...)
{
return EOF;
}
}
static long iov_tell_func(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
return fw->tell();
}
catch(...)
{
return(-1);
}
}
OggVorbisReader::OggVorbisReader(Stream *fp) : fw(fp)
{
ov_callbacks cb;
memset(&cb, 0, sizeof(cb));
cb.read_func = iov_read_func;
cb.seek_func = iov_seek_func;
cb.close_func = iov_close_func;
cb.tell_func = iov_tell_func;
fp->seek(0, SEEK_SET);
if(ov_open_callbacks(fp, &ovfile, NULL, 0, cb))
throw(0);
}
OggVorbisReader::~OggVorbisReader()
{
ov_clear(&ovfile);
}
int64 OggVorbisReader::Read_(int16 *buffer, int64 frames)
{
uint8 *tw_buf = (uint8 *)buffer;
int cursection = 0;
long toread = frames * sizeof(int16) * 2;
while(toread > 0)
{
long didread = ov_read(&ovfile, (char*)tw_buf, toread, &cursection);
if(didread == 0)
break;
tw_buf = (uint8 *)tw_buf + didread;
toread -= didread;
}
return(frames - toread / sizeof(int16) / 2);
}
bool OggVorbisReader::Seek_(int64 frame_offset)
{
ov_pcm_seek(&ovfile, frame_offset);
return(true);
}
int64 OggVorbisReader::FrameCount(void)
{
return(ov_pcm_total(&ovfile, -1));
}
class MPCReader : public AudioReader
{
public:
MPCReader(FILE *fp)
{
mpc_status err;
MPCReader(Stream *fp);
~MPCReader();
fseek(fp, 0, SEEK_SET);
int64 Read_(int16 *buffer, int64 frames);
bool Seek_(int64 frame_offset);
int64 FrameCount(void);
private:
mpc_reader reader;
mpc_demux *demux;
mpc_streaminfo si;
MPC_SAMPLE_FORMAT MPCBuffer[MPC_DECODER_BUFFER_LENGTH];
uint32 MPCBufferIn;
uint32 MPCBufferOffs;
Stream *fw;
};
/// Reads size bytes of data into buffer at ptr.
static mpc_int32_t impc_read(mpc_reader *p_reader, void *ptr, mpc_int32_t size)
{
Stream *fw = (Stream*)(p_reader->data);
try
{
return fw->read(ptr, size, false);
}
catch(...)
{
return(MPC_STATUS_FAIL);
}
}
/// Seeks to byte position offset.
static mpc_bool_t impc_seek(mpc_reader *p_reader, mpc_int32_t offset)
{
Stream *fw = (Stream*)(p_reader->data);
try
{
fw->seek(offset, SEEK_SET);
return(MPC_TRUE);
}
catch(...)
{
return(MPC_FALSE);
}
}
/// Returns the current byte offset in the stream.
static mpc_int32_t impc_tell(mpc_reader *p_reader)
{
Stream *fw = (Stream*)(p_reader->data);
try
{
return fw->tell();
}
catch(...)
{
return(MPC_STATUS_FAIL);
}
}
/// Returns the total length of the source stream, in bytes.
static mpc_int32_t impc_get_size(mpc_reader *p_reader)
{
Stream *fw = (Stream*)(p_reader->data);
try
{
return fw->size();
}
catch(...)
{
return(MPC_STATUS_FAIL);
}
}
/// True if the stream is a seekable stream.
static mpc_bool_t impc_canseek(mpc_reader *p_reader)
{
return(MPC_TRUE);
}
MPCReader::MPCReader(Stream *fp) : fw(fp)
{
fp->seek(0, SEEK_SET);
demux = NULL;
memset(&reader, 0, sizeof(reader));
memset(&si, 0, sizeof(si));
memset(MPCBuffer, 0, sizeof(MPCBuffer));
MPCBufferOffs = 0;
MPCBufferIn = 0;
if((err = mpc_reader_init_stdio_stream(&reader, fp)) < 0)
{
throw(MDFN_Error(0, _("Error initializing MusePack decoder!\n")));
}
memset(&reader, 0, sizeof(reader));
reader.read = impc_read;
reader.seek = impc_seek;
reader.tell = impc_tell;
reader.get_size = impc_get_size;
reader.canseek = impc_canseek;
reader.data = (void*)fp;
if(!(demux = mpc_demux_init(&reader)))
{
@ -147,28 +331,28 @@ class MPCReader : public AudioReader
{
mpc_demux_exit(demux);
demux = NULL;
throw MDFN_Error(0, _("MusePack stream has wrong number of channels(%d); the correct number is 2."), si.channels);
throw MDFN_Error(0, _("MusePack stream has wrong number of channels(%u); the correct number is 2."), si.channels);
}
if(si.sample_freq != 44100)
{
mpc_demux_exit(demux);
demux = NULL;
throw MDFN_Error(0, _("MusePack stream has wrong samplerate(%d Hz); the current samplerate is 44100 Hz."), si.sample_freq);
throw MDFN_Error(0, _("MusePack stream has wrong samplerate(%u Hz); the current samplerate is 44100 Hz."), si.sample_freq);
}
}
}
~MPCReader()
MPCReader::~MPCReader()
{
if(demux)
{
if(demux)
{
mpc_demux_exit(demux);
demux = NULL;
}
mpc_demux_exit(demux);
demux = NULL;
}
}
int64 Read_(int16 *buffer, int64 frames)
{
int64 MPCReader::Read_(int16 *buffer, int64 frames)
{
mpc_status err;
int16 *cowbuf = (int16 *)buffer;
int32 toread = frames * 2;
@ -219,120 +403,198 @@ class MPCReader : public AudioReader
}
return(frames - toread / 2);
}
}
bool Seek_(int64 frame_offset)
{
MPCBufferOffs = 0;
MPCBufferIn = 0;
bool MPCReader::Seek_(int64 frame_offset)
{
MPCBufferOffs = 0;
MPCBufferIn = 0;
if(mpc_demux_seek_sample(demux, frame_offset) < 0)
return(false);
if(mpc_demux_seek_sample(demux, frame_offset) < 0)
return(false);
return(true);
}
return(true);
}
int64 FrameCount(void)
{
return(mpc_streaminfo_get_length_samples(&si));
}
int64 MPCReader::FrameCount(void)
{
return(mpc_streaminfo_get_length_samples(&si));
}
private:
mpc_reader reader;
mpc_demux *demux;
mpc_streaminfo si;
MPC_SAMPLE_FORMAT MPCBuffer[MPC_DECODER_BUFFER_LENGTH];
uint32 MPCBufferIn;
uint32 MPCBufferOffs;
};
/*
**
**
**
**
**
**
**
**
**
*/
#ifdef HAVE_LIBSNDFILE
class SFReader : public AudioReader
{
public:
SFReader(FILE *fp)
{
memset(&sfinfo, 0, sizeof(sfinfo));
fseek(fp, 0, SEEK_SET);
lseek(fileno(fp), 0, SEEK_SET);
sf = sf_open_fd(fileno(fp), SFM_READ, &sfinfo, 0);
if(!sf)
throw(0);
}
SFReader(Stream *fp);
~SFReader();
~SFReader()
{
sf_close(sf);
}
int64 Read_(int16 *buffer, int64 frames)
{
return(sf_read_short(sf, (short*)buffer, frames * 2) / 2);
}
bool Seek_(int64 frame_offset)
{
// FIXME error condition
if(sf_seek(sf, frame_offset, SEEK_SET) != frame_offset)
return(false);
return(true);
}
int64 FrameCount(void)
{
return(sfinfo.frames);
}
int64 Read_(int16 *buffer, int64 frames);
bool Seek_(int64 frame_offset);
int64 FrameCount(void);
private:
SNDFILE *sf;
SF_INFO sfinfo;
SF_VIRTUAL_IO sfvf;
Stream *fw;
};
#endif
AudioReader *AR_Open(FILE *fp)
static sf_count_t isf_get_filelen(void *user_data)
{
AudioReader *AReader = NULL;
Stream *fw = (Stream*)user_data;
if(!AReader)
try
{
try
{
AReader = new MPCReader(fp);
}
catch(int i)
{
}
return fw->size();
}
if(!AReader)
catch(...)
{
try
{
AReader = new OggVorbisReader(fp);
}
catch(int i)
{
}
return(-1);
}
#ifdef HAVE_LIBSNDFILE
if(!AReader)
{
try
{
AReader = new SFReader(fp);
}
catch(int i)
{
}
}
#endif
return(AReader);
}
static sf_count_t isf_seek(sf_count_t offset, int whence, void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
fw->seek(offset, whence);
return fw->tell();
}
catch(...)
{
return(-1);
}
}
static sf_count_t isf_read(void *ptr, sf_count_t count, void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
return fw->read(ptr, count);
}
catch(...)
{
return(0);
}
}
static sf_count_t isf_write(const void *ptr, sf_count_t count, void *user_data)
{
return(0);
}
static sf_count_t isf_tell(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
return fw->tell();
}
catch(...)
{
return(-1);
}
}
SFReader::SFReader(Stream *fp) : fw(fp)
{
fp->seek(0, SEEK_SET);
memset(&sfvf, 0, sizeof(sfvf));
sfvf.get_filelen = isf_get_filelen;
sfvf.seek = isf_seek;
sfvf.read = isf_read;
sfvf.write = isf_write;
sfvf.tell = isf_tell;
memset(&sfinfo, 0, sizeof(sfinfo));
if(!(sf = sf_open_virtual(&sfvf, SFM_READ, &sfinfo, (void*)fp)))
throw(0);
}
SFReader::~SFReader()
{
sf_close(sf);
}
int64 SFReader::Read_(int16 *buffer, int64 frames)
{
return(sf_read_short(sf, (short*)buffer, frames * 2) / 2);
}
bool SFReader::Seek_(int64 frame_offset)
{
// FIXME error condition
if(sf_seek(sf, frame_offset, SEEK_SET) != frame_offset)
return(false);
return(true);
}
int64 SFReader::FrameCount(void)
{
return(sfinfo.frames);
}
#endif
AudioReader *AR_Open(Stream *fp)
{
try
{
return new MPCReader(fp);
}
catch(int i)
{
}
#ifdef HAVE_OPUSFILE
try
{
return new OpusReader(fp);
}
catch(int i)
{
}
#endif
try
{
return new OggVorbisReader(fp);
}
catch(int i)
{
}
#ifdef HAVE_LIBSNDFILE
try
{
return new SFReader(fp);
}
catch(int i)
{
}
#endif
return(NULL);
}

View File

@ -1,46 +1,14 @@
#ifndef __MDFN_AUDIOREADER_H
#define __MDFN_AUDIOREADER_H
class MDFN_Object
{
public:
INLINE MDFN_Object()
{
#include "../Stream.h"
}
INLINE ~MDFN_Object()
{
}
static void *operator new(size_t bcount)
{
void *ret = calloc(1, bcount);
if(!ret)
{
throw(MDFN_Error(0, _("Error allocating %llu bytes of memory."), (unsigned long long)bcount));
}
return(ret);
}
static void operator delete(void *ptr)
{
free(ptr);
}
};
class AudioReader : public MDFN_Object
class AudioReader
{
public:
AudioReader();
virtual ~AudioReader();
virtual int64 Read_(int16 *buffer, int64 frames);
virtual bool Seek_(int64 frame_offset);
virtual int64 FrameCount(void);
INLINE int64 Read(int64 frame_offset, int16 *buffer, int64 frames)
{
@ -62,10 +30,14 @@ class AudioReader : public MDFN_Object
}
private:
virtual int64 Read_(int16 *buffer, int64 frames);
virtual bool Seek_(int64 frame_offset);
int64 LastReadPos;
};
AudioReader *AR_Open(FILE *fp);
// AR_Open(), and AudioReader, will NOT take "ownership" of the Stream object(IE it won't ever delete it). Though it does assume it has exclusive access
// to it for as long as the AudioReader object exists.
AudioReader *AR_Open(Stream *fp);
#endif

View File

@ -0,0 +1,185 @@
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../mednafen.h"
#include "audioreader.h"
#include "audioreader_opus.h"
// OPUS SUPPORT NOT DONE YET!!!
/*
(int64)op_pcm_total() * 44100 / 48000
resampling vs seek, filter delay, etc. to consider
*/
static size_t iop_read_func(void *ptr, size_t size, size_t nmemb, void *user_data)
{
Stream *fw = (Stream*)user_data;
if(!size)
return(0);
try
{
return fw->read(ptr, size * nmemb, false) / size;
}
catch(...)
{
return(0);
}
}
static int iop_seek_func(void *user_data, opus_int64 offset, int whence)
{
Stream *fw = (Stream*)user_data;
try
{
fw->seek(offset, whence);
return(0);
}
catch(...)
{
return(-1);
}
}
static int iop_close_func(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
fw->close();
return(0);
}
catch(...)
{
return EOF;
}
}
static opus_int64 iop_tell_func(void *user_data)
{
Stream *fw = (Stream*)user_data;
try
{
return fw->tell();
}
catch(...)
{
return(-1);
}
}
/* Error strings copied from libopusfile header file comments. */
static const char *op_errstring(int error)
{
static const struct
{
int code;
const char *str;
} error_table[] =
{
{ OP_EREAD, gettext_noop("OP_EREAD: An underlying read, seek, or tell operation failed when it should have succeeded.") },
{ OP_EFAULT, gettext_noop("OP_EFAULT: A NULL pointer was passed where one was unexpected, or an internal memory allocation failed, or an internal library error was encountered.") },
{ OP_EIMPL, gettext_noop("OP_EIMPL: The stream used a feature that is not implemented, such as an unsupported channel family.") },
{ OP_EINVAL, gettext_noop("OP_EINVAL: One or more parameters to a function were invalid.") },
{ OP_ENOTFORMAT, gettext_noop("OP_ENOTFORMAT: A purported Ogg Opus stream did not begin with an Ogg page, or a purported header packet did not start with one of the required strings, \"OpusHead\" or \"OpusTags\".") },
{ OP_EBADHEADER, gettext_noop("OP_EBADHEADER: A required header packet was not properly formatted, contained illegal values, or was missing altogether.") },
{ OP_EVERSION, gettext_noop("OP_EVERSION: The ID header contained an unrecognized version number.") },
{ OP_EBADPACKET, gettext_noop("OP_EBADPACKET: An audio packet failed to decode properly.") },
{ OP_EBADLINK, gettext_noop("OP_EBADLINK: We failed to find data we had seen before, or the bitstream structure was sufficiently malformed that seeking to the target destination was impossible.") },
{ OP_ENOSEEK, gettext_noop("OP_ENOSEEK: An operation that requires seeking was requested on an unseekable stream.") },
{ OP_EBADTIMESTAMP, gettext_noop("OP_EBADTIMESTAMP: The first or last granule position of a link failed basic validity checks.") },
};
for(unsigned i = 0; i < sizeof(error_table) / sizeof(error_table[0]); i++)
{
if(error_table[i].code == error)
{
return _(error_table[i].str);
}
}
return _("Unknown");
}
OggOpusReader::OggOpusReader(Stream *fp) : fw(fp)
{
OpusFileCallbacks cb;
int error = 0;
memset(&cb, 0, sizeof(cb));
cb.read_func = iop_read_func;
cb.seek_func = iop_seek_func;
cb.close_func = iop_close_func;
cb.tell_func = iop_tell_func;
fp->seek(0, SEEK_SET);
if(!(opfile = op_open_callbacks((void*)fp, &cb, NULL, 0, &error)))
{
switch(error)
{
default:
throw MDFN_Error(0, _("opusfile: error code: %d(%s)", error, op_errstring(error)));
break;
case OP_ENOTFORMAT:
throw(0);
break;
}
}
}
OggOpusReader::~OggOpusReader()
{
op_free(opfile);
}
int64 OggOpusReader::Read_(int16 *buffer, int64 frames)
{
int16 *tr_buffer = buffer;
int64 tr_count = frames * 2;
while(tr_count > 0)
{
int64 didread = op_read(opfile, tr_buffer, tr_count, NULL);
if(didread == 0)
break;
tr_buffer += didread * 2;
tr_count -= didread * 2;
}
return(frames - (tr_count / 2));
}
bool OggOpusReader::Seek_(int64 frame_offset)
{
op_pcm_seek(opfile, frame_offset);
return(true);
}
int64 OggOpusReader::FrameCount(void)
{
return(op_pcm_total(pvfile, -1));
}

View File

@ -0,0 +1,21 @@
#ifndef __MDFN_AUDIOREADER_OPUS_H
#define __MDFN_AUDIOREADER_OPUS_H
#include <opus/opusfile.h>
class OggOpusReader : public AudioReader
{
public:
OggOpusReader(Stream *fp);
~OggOpusReader();
int64 Read_(int16 *buffer, int64 frames);
bool Seek_(int64 frame_offset);
int64 FrameCount(void);
private:
OggOpus_File *opfile;
Stream *fw;
};
#endif

View File

@ -23,8 +23,21 @@
#include "CDAccess.h"
#include "../general.h"
#include <algorithm>
using namespace CDUtility;
CDIF::CDIF() : UnrecoverableError(false), is_phys_cache(false), disc_cdaccess(NULL), DiscEjected(false)
{
}
CDIF::~CDIF()
{
}
CDIF_Message::CDIF_Message()
{
message = 0;
@ -104,7 +117,7 @@ void CDIF_Queue::Write(const CDIF_Message &message)
}
void CDIF::RT_EjectDisc(bool eject_status, bool skip_actual_eject)
void CDIF_MT::RT_EjectDisc(bool eject_status, bool skip_actual_eject)
{
int32 old_de = DiscEjected;
@ -135,7 +148,7 @@ void CDIF::RT_EjectDisc(bool eject_status, bool skip_actual_eject)
struct RTS_Args
{
CDIF *cdif_ptr;
CDIF_MT *cdif_ptr;
const char *device_name;
};
@ -155,7 +168,7 @@ static int ReadThreadStart_C(void *v_arg)
return args->cdif_ptr->ReadThreadStart(NULL);
}
int CDIF::ReadThreadStart(const char *device_name)
int CDIF_MT::ReadThreadStart(const char *device_name)
{
bool Running = TRUE;
@ -167,7 +180,7 @@ int CDIF::ReadThreadStart(const char *device_name)
try
{
disc_cdaccess = cdaccess_open(device_name ? device_name : NULL);
disc_cdaccess = cdaccess_open(device_name ? device_name : NULL, false);
RT_EjectDisc(false, true);
}
catch(std::exception &e)
@ -283,23 +296,42 @@ int CDIF::ReadThreadStart(const char *device_name)
return(1);
}
CDIF::CDIF(const char *device_name)
CDIF_MT::CDIF_MT(const char *device_name) : CDReadThread(NULL), SBMutex(NULL)
{
CDIF_Message msg;
RTS_Args s;
try
{
CDIF_Message msg;
RTS_Args s;
SBMutex = MDFND_CreateMutex();
UnrecoverableError = false;
SBMutex = MDFND_CreateMutex();
UnrecoverableError = false;
s.cdif_ptr = this;
s.device_name = device_name;
s.cdif_ptr = this;
s.device_name = device_name;
CDReadThread = MDFND_CreateThread(ReadThreadStart_C, &s);
EmuThreadQueue.Read(&msg);
CDReadThread = MDFND_CreateThread(ReadThreadStart_C, &s);
EmuThreadQueue.Read(&msg);
}
catch(...)
{
if(CDReadThread)
{
MDFND_WaitThread(CDReadThread, NULL);
CDReadThread = NULL;
}
if(SBMutex)
{
MDFND_DestroyMutex(SBMutex);
SBMutex = NULL;
}
throw;
}
}
CDIF::~CDIF()
CDIF_MT::~CDIF_MT()
{
bool thread_murdered_with_kitchen_knife = false;
@ -337,7 +369,7 @@ bool CDIF::ValidateRawSector(uint8 *buf)
return(true);
}
bool CDIF::ReadRawSector(uint8 *buf, uint32 lba)
bool CDIF_MT::ReadRawSector(uint8 *buf, uint32 lba)
{
bool found = FALSE;
bool error_condition = false;
@ -381,7 +413,7 @@ bool CDIF::ReadRawSector(uint8 *buf, uint32 lba)
return(!error_condition);
}
void CDIF::HintReadSector(uint32 lba)
void CDIF_MT::HintReadSector(uint32 lba)
{
if(UnrecoverableError)
return;
@ -394,10 +426,7 @@ int CDIF::ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors)
int ret = 0;
if(UnrecoverableError)
{
return(0);
}
return(false);
while(nSectors--)
{
@ -442,12 +471,7 @@ int CDIF::ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors)
return(ret);
}
void CDIF::ReadTOC(CDUtility::TOC *read_target)
{
*read_target = disc_toc;
}
bool CDIF::Eject(bool eject_status)
bool CDIF_MT::Eject(bool eject_status)
{
if(UnrecoverableError)
return(false);
@ -468,3 +492,237 @@ bool CDIF::Eject(bool eject_status)
return(true);
}
//
//
// Single-threaded implementation follows.
//
//
CDIF_ST::CDIF_ST(const char *device_name, bool di_memcache)
{
puts("***WARNING USING SINGLE-THREADED CD READER***");
disc_cdaccess = cdaccess_open(device_name ? device_name : NULL, false);
is_phys_cache = disc_cdaccess->Is_Physical();
UnrecoverableError = false;
DiscEjected = false;
disc_cdaccess->Read_TOC(&disc_toc);
if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track)
{
throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track));
}
}
CDIF_ST::~CDIF_ST()
{
if(disc_cdaccess)
{
delete disc_cdaccess;
disc_cdaccess = NULL;
}
}
void CDIF_ST::HintReadSector(uint32 lba)
{
// TODO: disc_cdaccess seek hint? (probably not, would require asynchronousitycamel)
}
bool CDIF_ST::ReadRawSector(uint8 *buf, uint32 lba)
{
if(UnrecoverableError)
{
memset(buf, 0, 2352 + 96);
return(false);
}
try
{
disc_cdaccess->Read_Raw_Sector(buf, lba);
}
catch(std::exception &e)
{
MDFN_PrintError(_("Sector %u read error: %s"), lba, e.what());
memset(buf, 0, 2352 + 96);
return(false);
}
return(true);
}
bool CDIF_ST::Eject(bool eject_status)
{
if(UnrecoverableError)
return(false);
try
{
int32 old_de = DiscEjected;
DiscEjected = eject_status;
if(old_de != DiscEjected)
{
disc_cdaccess->Eject(eject_status);
if(!eject_status) // Re-read the TOC
{
disc_cdaccess->Read_TOC(&disc_toc);
if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track)
{
throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track));
}
}
}
}
catch(std::exception &e)
{
MDFN_PrintError("%s", e.what());
return(false);
}
return(true);
}
class CDIF_Stream_Thing : public Stream
{
public:
CDIF_Stream_Thing(CDIF *cdintf_arg, uint32 lba_arg, uint32 sector_count_arg);
~CDIF_Stream_Thing();
virtual uint64 attributes(void);
virtual uint8 *map(void);
virtual void unmap(void);
virtual uint64 read(void *data, uint64 count, bool error_on_eos = true);
virtual void write(const void *data, uint64 count);
virtual void seek(int64 offset, int whence);
virtual int64 tell(void);
virtual int64 size(void);
virtual void close(void);
private:
CDIF *cdintf;
const uint32 start_lba;
const uint32 sector_count;
int64 position;
};
CDIF_Stream_Thing::CDIF_Stream_Thing(CDIF *cdintf_arg, uint32 start_lba_arg, uint32 sector_count_arg) : cdintf(cdintf_arg), start_lba(start_lba_arg), sector_count(sector_count_arg)
{
}
CDIF_Stream_Thing::~CDIF_Stream_Thing()
{
}
uint64 CDIF_Stream_Thing::attributes(void)
{
return(ATTRIBUTE_READABLE | ATTRIBUTE_SEEKABLE);
}
uint8 *CDIF_Stream_Thing::map(void)
{
return NULL;
}
void CDIF_Stream_Thing::unmap(void)
{
}
uint64 CDIF_Stream_Thing::read(void *data, uint64 count, bool error_on_eos)
{
if(count > (((uint64)sector_count * 2048) - position))
{
if(error_on_eos)
{
throw MDFN_Error(0, "EOF");
}
count = ((uint64)sector_count * 2048) - position;
}
if(!count)
return(0);
for(uint64 rp = position; rp < (position + count); rp = (rp &~ 2047) + 2048)
{
uint8 buf[2048];
if(!cdintf->ReadSector(buf, start_lba + (rp / 2048), 1))
{
throw MDFN_Error(ErrnoHolder(EIO));
}
//::printf("Meow: %08llx -- %08llx\n", count, (rp - position) + std::min<uint64>(2048 - (rp & 2047), count - (rp - position)));
memcpy((uint8*)data + (rp - position), buf + (rp & 2047), std::min<uint64>(2048 - (rp & 2047), count - (rp - position)));
}
position += count;
return count;
}
void CDIF_Stream_Thing::write(const void *data, uint64 count)
{
throw MDFN_Error(ErrnoHolder(EBADF));
}
void CDIF_Stream_Thing::seek(int64 offset, int whence)
{
int64 new_position;
switch(whence)
{
default:
throw MDFN_Error(ErrnoHolder(EINVAL));
break;
case SEEK_SET:
new_position = offset;
break;
case SEEK_CUR:
new_position = position + offset;
break;
case SEEK_END:
new_position = ((int64)sector_count * 2048) + offset;
break;
}
if(new_position < 0 || new_position > ((int64)sector_count * 2048))
throw MDFN_Error(ErrnoHolder(EINVAL));
position = new_position;
}
int64 CDIF_Stream_Thing::tell(void)
{
return position;
}
int64 CDIF_Stream_Thing::size(void)
{
return(sector_count * 2048);
}
void CDIF_Stream_Thing::close(void)
{
}
Stream *CDIF::MakeStream(uint32 lba, uint32 sector_count)
{
return new CDIF_Stream_Thing(this, lba, sector_count);
}

View File

@ -19,10 +19,53 @@
#define __MDFN_CDROM_CDROMIF_H
#include "CDUtility.h"
#include "../Stream.h"
#include <queue>
typedef CDUtility::TOC CD_TOC;
class CDAccess;
class CDIF
{
public:
CDIF();
virtual ~CDIF();
inline void ReadTOC(CDUtility::TOC *read_target)
{
*read_target = disc_toc;
}
virtual void HintReadSector(uint32 lba) = 0;
virtual bool ReadRawSector(uint8 *buf, uint32 lba) = 0;
// Call for mode 1 or mode 2 form 1 only.
bool ValidateRawSector(uint8 *buf);
// Utility/Wrapped functions
// Reads mode 1 and mode2 form 1 sectors(2048 bytes per sector returned)
// Will return the type(1, 2) of the first sector read to the buffer supplied, 0 on error
int ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors);
// Return true if operation succeeded or it was a NOP(either due to not being implemented, or the current status matches eject_status).
// Returns false on failure(usually drive error of some kind; not completely fatal, can try again).
virtual bool Eject(bool eject_status) = 0;
inline bool IsPhysical(void) { return(is_phys_cache); }
// For Mode 1, or Mode 2 Form 1.
// No reference counting or whatever is done, so if you destroy the CDIF object before you destroy the returned Stream, things will go BOOM.
Stream *MakeStream(uint32 lba, uint32 sector_count);
protected:
bool UnrecoverableError;
bool is_phys_cache;
CDUtility::TOC disc_toc;
CDAccess *disc_cdaccess;
bool DiscEjected;
};
enum
{
@ -83,43 +126,26 @@ typedef struct
uint8 data[2352 + 96];
} CDIF_Sector_Buffer;
class CDAccess;
// TODO: prohibit copy constructor
class CDIF
class CDIF_MT : public CDIF
{
public:
CDIF(const char *device_name);
~CDIF();
CDIF_MT(const char *device_name);
virtual ~CDIF_MT();
void ReadTOC(CDUtility::TOC *read_target);
void HintReadSector(uint32 lba);
bool ReadRawSector(uint8 *buf, uint32 lba);
// Call for mode 1 or mode 2 form 1 only.
bool ValidateRawSector(uint8 *buf);
// Utility/Wrapped functions
// Reads mode 1 and mode2 form 1 sectors(2048 bytes per sector returned)
// Will return the type(1, 2) of the first sector read to the buffer supplied, 0 on error
int ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors);
virtual void HintReadSector(uint32 lba);
virtual bool ReadRawSector(uint8 *buf, uint32 lba);
// Return true if operation succeeded or it was a NOP(either due to not being implemented, or the current status matches eject_status).
// Returns false on failure(usually drive error of some kind; not completely fatal, can try again).
bool Eject(bool eject_status);
inline bool IsPhysical(void) { return is_phys_cache; }
virtual bool Eject(bool eject_status);
// FIXME: Semi-private:
int ReadThreadStart(const char *device_name);
private:
bool is_phys_cache;
CDUtility::TOC disc_toc;
CDAccess *disc_cdaccess;
MDFN_Thread *CDReadThread;
// Queue for messages to the read thread.
@ -135,7 +161,6 @@ class CDIF
uint32 SBWritePos;
MDFN_Mutex *SBMutex;
bool UnrecoverableError;
//
@ -146,7 +171,20 @@ class CDIF
uint32 ra_lba;
int ra_count;
uint32 last_read_lba;
bool DiscEjected;
};
// TODO: prohibit copy constructor
class CDIF_ST : public CDIF
{
public:
CDIF_ST(const char *device_name, bool di_memcache);
virtual ~CDIF_ST();
virtual void HintReadSector(uint32 lba);
virtual bool ReadRawSector(uint8 *buf, uint32 lba);
virtual bool Eject(bool eject_status);
};
#endif

View File

@ -0,0 +1,124 @@
============================================================================
miniLZO -- mini subset of the LZO real-time data compression library
============================================================================
Author : Markus Franz Xaver Johannes Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/opensource/lzo/
Version : 2.06
Date : 12 Aug 2011
I've created miniLZO for projects where it is inconvenient to
include (or require) the full LZO source code just because you
want to add a little bit of data compression to your application.
miniLZO implements the LZO1X-1 compressor and both the standard and
safe LZO1X decompressor. Apart from fast compression it also useful
for situations where you want to use pre-compressed data files (which
must have been compressed with LZO1X-999).
miniLZO consists of one C source file and three header files:
minilzo.c
minilzo.h, lzoconf.h, lzodefs.h
To use miniLZO just copy these files into your source directory, add
minilzo.c to your Makefile and #include minilzo.h from your program.
Note: you also must distribute this file ('README.LZO') with your project.
minilzo.o compiles to about 6 KiB (using gcc or Visual C on an i386), and
the sources are about 30 KiB when packed with zip - so there's no more
excuse that your application doesn't support data compression :-)
For more information, documentation, example programs and other support
files (like Makefiles and build scripts) please download the full LZO
package from
http://www.oberhumer.com/opensource/lzo/
Have fun,
Markus
P.S. minilzo.c is generated automatically from the LZO sources and
therefore functionality is completely identical
Appendix A: building miniLZO
----------------------------
miniLZO is written such a way that it should compile and run
out-of-the-box on most machines.
If you are running on a very unusual architecture and lzo_init() fails then
you should first recompile with '-DLZO_DEBUG' to see what causes the failure.
The most probable case is something like 'sizeof(void *) != sizeof(size_t)'.
After identifying the problem you can compile by adding some defines
like '-DSIZEOF_VOID_P=8' to your Makefile.
The best solution is (of course) using Autoconf - if your project uses
Autoconf anyway just add '-DMINILZO_HAVE_CONFIG_H' to your compiler
flags when compiling minilzo.c. See the LZO distribution for an example
how to set up configure.ac.
Appendix B: list of public functions available in miniLZO
---------------------------------------------------------
Library initialization
lzo_init()
Compression
lzo1x_1_compress()
Decompression
lzo1x_decompress()
lzo1x_decompress_safe()
Checksum functions
lzo_adler32()
Version functions
lzo_version()
lzo_version_string()
lzo_version_date()
Portable (but slow) string functions
lzo_memcmp()
lzo_memcpy()
lzo_memmove()
lzo_memset()
Appendix C: suggested macros for 'configure.ac' when using Autoconf
-------------------------------------------------------------------
Checks for typedefs and structures
AC_CHECK_TYPE(ptrdiff_t,long)
AC_TYPE_SIZE_T
AC_CHECK_SIZEOF(short)
AC_CHECK_SIZEOF(int)
AC_CHECK_SIZEOF(long)
AC_CHECK_SIZEOF(long long)
AC_CHECK_SIZEOF(__int64)
AC_CHECK_SIZEOF(void *)
AC_CHECK_SIZEOF(size_t)
AC_CHECK_SIZEOF(ptrdiff_t)
Checks for compiler characteristics
AC_C_CONST
Checks for library functions
AC_CHECK_FUNCS(memcmp memcpy memmove memset)
Appendix D: Copyright
---------------------
LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001,
2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Markus Franz Xaver Oberhumer <markus@oberhumer.com>.
LZO and miniLZO are distributed under the terms of the GNU General
Public License (GPL). See the file COPYING.
Special licenses for commercial and other applications which
are not willing to accept the GNU General Public License
are available by contacting the author.

View File

@ -1,7 +1,13 @@
/* lzoconf.h -- configuration for the LZO real-time data compression library
/* lzoconf.h -- configuration of the LZO data compression library
This file is part of the LZO real-time data compression library.
Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
@ -27,7 +33,7 @@
You should have received a copy of the GNU General Public License
along with the LZO library; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
@ -36,11 +42,11 @@
#ifndef __LZOCONF_H_INCLUDED
#define __LZOCONF_H_INCLUDED
#define __LZOCONF_H_INCLUDED 1
#define LZO_VERSION 0x2010
#define LZO_VERSION_STRING "2.01"
#define LZO_VERSION_DATE "Jun 27 2005"
#define LZO_VERSION 0x2060
#define LZO_VERSION_STRING "2.06"
#define LZO_VERSION_DATE "Aug 12 2011"
/* internal Autoconf configuration file - only used when building LZO */
#if defined(LZO_HAVE_CONFIG_H)
@ -76,7 +82,7 @@ extern "C" {
/***********************************************************************
//
// some core defines
************************************************************************/
#if !defined(LZO_UINT32_C)
@ -154,22 +160,43 @@ extern "C" {
# endif
#endif
/* Integral types with exactly 64 bits. */
#if !defined(LZO_UINT64_MAX)
# if (LZO_UINT_MAX >= LZO_0xffffffffL)
# if ((((LZO_UINT_MAX) >> 31) >> 31) == 3)
# define lzo_uint64 lzo_uint
# define lzo_int64 lzo_int
# define LZO_UINT64_MAX LZO_UINT_MAX
# define LZO_INT64_MAX LZO_INT_MAX
# define LZO_INT64_MIN LZO_INT_MIN
# endif
# elif (ULONG_MAX >= LZO_0xffffffffL)
# if ((((ULONG_MAX) >> 31) >> 31) == 3)
typedef unsigned long lzo_uint64;
typedef long lzo_int64;
# define LZO_UINT64_MAX ULONG_MAX
# define LZO_INT64_MAX LONG_MAX
# define LZO_INT64_MIN LONG_MIN
# endif
# endif
#endif
/* The larger type of lzo_uint and lzo_uint32. */
#if (LZO_UINT_MAX >= LZO_UINT32_MAX)
# define lzo_xint lzo_uint
# define lzo_xint lzo_uint
#else
# define lzo_xint lzo_uint32
# define lzo_xint lzo_uint32
#endif
/* Memory model that allows to access memory at offsets of lzo_uint. */
#if !defined(__LZO_MMODEL)
# if (LZO_UINT_MAX <= UINT_MAX)
# define __LZO_MMODEL
# define __LZO_MMODEL /*empty*/
# elif defined(LZO_HAVE_MM_HUGE_PTR)
# define __LZO_MMODEL_HUGE 1
# define __LZO_MMODEL __huge
# else
# define __LZO_MMODEL
# define __LZO_MMODEL /*empty*/
# endif
#endif
@ -181,12 +208,16 @@ extern "C" {
#define lzo_ushortp unsigned short __LZO_MMODEL *
#define lzo_uint32p lzo_uint32 __LZO_MMODEL *
#define lzo_int32p lzo_int32 __LZO_MMODEL *
#if defined(LZO_UINT64_MAX)
#define lzo_uint64p lzo_uint64 __LZO_MMODEL *
#define lzo_int64p lzo_int64 __LZO_MMODEL *
#endif
#define lzo_uintp lzo_uint __LZO_MMODEL *
#define lzo_intp lzo_int __LZO_MMODEL *
#define lzo_xintp lzo_xint __LZO_MMODEL *
#define lzo_voidpp lzo_voidp __LZO_MMODEL *
#define lzo_bytepp lzo_bytep __LZO_MMODEL *
/* deprecated - use `lzo_bytep' instead of `lzo_byte *' */
/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */
#define lzo_byte unsigned char __LZO_MMODEL
typedef int lzo_bool;
@ -212,10 +243,10 @@ typedef int lzo_bool;
/* DLL export information */
#if !defined(__LZO_EXPORT1)
# define __LZO_EXPORT1
# define __LZO_EXPORT1 /*empty*/
#endif
#if !defined(__LZO_EXPORT2)
# define __LZO_EXPORT2
# define __LZO_EXPORT2 /*empty*/
#endif
/* __cdecl calling convention for public C and assembly functions */
@ -284,9 +315,9 @@ struct lzo_callback_t
/* a progress indicator callback function (set to 0 to disable) */
lzo_progress_func_t nprogress;
/* NOTE: the first parameter of nalloc/nfree/nprogress callbacks ("self")
* points back to this struct, so you are free to store some extra
* info in the following variables. */
/* NOTE: the first parameter "self" of the nalloc/nfree/nprogress
* callbacks points back to this struct, so you are free to store
* some extra info in the following variables. */
lzo_voidp user1;
lzo_xint user2;
lzo_xint user3;
@ -303,7 +334,7 @@ struct lzo_callback_t
*/
#define LZO_E_OK 0
#define LZO_E_ERROR (-1)
#define LZO_E_OUT_OF_MEMORY (-2) /* [not used right now] */
#define LZO_E_OUT_OF_MEMORY (-2) /* [lzo_alloc_func_t failure] */
#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */
#define LZO_E_INPUT_OVERRUN (-4)
#define LZO_E_OUTPUT_OVERRUN (-5)
@ -311,6 +342,7 @@ struct lzo_callback_t
#define LZO_E_EOF_NOT_FOUND (-7)
#define LZO_E_INPUT_NOT_CONSUMED (-8)
#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */
#define LZO_E_INVALID_ARGUMENT (-10)
#ifndef lzo_sizeof_dict_t
@ -338,32 +370,32 @@ LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
/* string functions */
LZO_EXTERN(int)
lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len);
lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len);
LZO_EXTERN(lzo_voidp)
lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
LZO_EXTERN(lzo_voidp)
lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
LZO_EXTERN(lzo_voidp)
lzo_memset(lzo_voidp _s, int _c, lzo_uint _len);
lzo_memset(lzo_voidp buf, int c, lzo_uint len);
/* checksum functions */
LZO_EXTERN(lzo_uint32)
lzo_adler32(lzo_uint32 _adler, const lzo_bytep _buf, lzo_uint _len);
lzo_adler32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
LZO_EXTERN(lzo_uint32)
lzo_crc32(lzo_uint32 _c, const lzo_bytep _buf, lzo_uint _len);
lzo_crc32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
LZO_EXTERN(const lzo_uint32p)
lzo_get_crc32_table(void);
lzo_get_crc32_table(void);
/* misc. */
LZO_EXTERN(int) _lzo_config_check(void);
typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u;
typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u;
typedef union { void *vp; lzo_bytep bp; lzo_uint32 u32; long l; } lzo_align_t;
typedef union { void *vp; lzo_bytep bp; lzo_uint u; lzo_uint32 u32; unsigned long l; } lzo_align_t;
/* align a char pointer on a boundary that is a multiple of `size' */
LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size);
#define LZO_PTR_ALIGN_UP(_ptr,_size) \
((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size)))
/* align a char pointer on a boundary that is a multiple of 'size' */
LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size);
#define LZO_PTR_ALIGN_UP(p,size) \
((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size)))
/***********************************************************************
@ -392,11 +424,11 @@ LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size);
# define __LZO_WIN 1
#endif
#define __LZO_CMODEL
#define __LZO_DMODEL
#define __LZO_CMODEL /*empty*/
#define __LZO_DMODEL /*empty*/
#define __LZO_ENTRY __LZO_CDECL
#define LZO_EXTERN_CDECL LZO_EXTERN
#define LZO_ALIGN LZO_PTR_ALIGN_UP
#define LZO_EXTERN_CDECL LZO_EXTERN
#define LZO_ALIGN LZO_PTR_ALIGN_UP
#define lzo_compress_asm_t lzo_compress_t
#define lzo_decompress_asm_t lzo_decompress_t
@ -410,3 +442,5 @@ LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size);
#endif /* already included */
/* vim:set ts=4 et: */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,12 @@
This file is part of the LZO real-time data compression library.
Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
@ -27,7 +33,7 @@
You should have received a copy of the GNU General Public License
along with the LZO library; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
@ -42,9 +48,9 @@
#ifndef __MINILZO_H
#define __MINILZO_H
#define __MINILZO_H 1
#define MINILZO_VERSION 0x2010
#define MINILZO_VERSION 0x2060
#ifdef __LZOCONF_H
# error "you cannot use both LZO and miniLZO"

View File

@ -39,12 +39,12 @@ int qlz_get_setting(int setting)
return -1;
}
static __inline unsigned int hash_func(unsigned int i)
__inline unsigned int hash_func(unsigned int i)
{
return ((i >> 12) ^ i) & 0x0fff;
}
static __inline unsigned int fast_read(void const *src, unsigned int bytes)
__inline unsigned int fast_read(void const *src, unsigned int bytes)
{
#ifndef X86X64
unsigned char *p = (unsigned char*)src;
@ -68,7 +68,7 @@ static __inline unsigned int fast_read(void const *src, unsigned int bytes)
#endif
}
static __inline void fast_write(unsigned int f, void *dst, unsigned int bytes)
__inline void fast_write(unsigned int f, void *dst, unsigned int bytes)
{
#ifndef X86X64
unsigned char *p = (unsigned char*)dst;
@ -118,7 +118,7 @@ static __inline void fast_write(unsigned int f, void *dst, unsigned int bytes)
#endif
}
static __inline void memcpy_up(unsigned char *dst, const unsigned char *src, unsigned int n)
__inline void memcpy_up(unsigned char *dst, const unsigned char *src, unsigned int n)
{
// cannot be replaced by overlap handling of memmove() due to LZSS algorithm
#ifndef X86X64
@ -151,7 +151,7 @@ static __inline void memcpy_up(unsigned char *dst, const unsigned char *src, uns
#endif
}
static __inline unsigned int fast_read_safe(void const *src, unsigned int bytes, const unsigned char *invalid)
__inline unsigned int fast_read_safe(void const *src, unsigned int bytes, const unsigned char *invalid)
{
#ifdef memory_safe
if ((const unsigned char *)src + 4 > (const unsigned char *)invalid)

View File

@ -64,13 +64,14 @@ static bool IsAbsolutePath(const char *path)
return(TRUE);
}
// FIXME if we add DOS support(HAHAHAHA).
#if defined(WIN32)
#if defined(WIN32) || defined(DOS)
if((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z'))
{
if(path[1] == ':')
{
return(TRUE);
}
}
#endif
return(FALSE);
@ -248,6 +249,7 @@ static void CreateMissingDirs(const char *path)
}
#endif
#if 0
std::string MDFN_MakeFName(MakeFName_Type type, int id1, const char *cd1)
{
char tmp_path[4096];
@ -317,7 +319,7 @@ std::string MDFN_MakeFName(MakeFName_Type type, int id1, const char *cd1)
}
else if(type == MDFNMKF_SAV)
{
dir = "";
dir = MDFN_GetSettingS("filesys.path_sav");
fstring = MDFN_GetSettingS("filesys.fname_sav");
fmap['x'] = std::string(cd1);
}
@ -391,19 +393,19 @@ std::string MDFN_MakeFName(MakeFName_Type type, int id1, const char *cd1)
std::string overpath = MDFN_GetSettingS("filesys.path_cheat");
if(IsAbsolutePath(overpath))
trio_snprintf(tmp_path, 4096, "%s"PSS"%s.%scht",overpath.c_str(), MDFNGameInfo->shortname, (type == MDFNMKF_CHEAT_TMP) ? "tmp" : "");
trio_snprintf(tmp_path, 4096, "%s" PSS "%s.%scht",overpath.c_str(), MDFNGameInfo->shortname, (type == MDFNMKF_CHEAT_TMP) ? "tmp" : "");
else
trio_snprintf(tmp_path, 4096, "%s"PSS"%s"PSS"%s.%scht", BaseDirectory.c_str(), overpath.c_str(), MDFNGameInfo->shortname, (type == MDFNMKF_CHEAT_TMP) ? "tmp" : "");
trio_snprintf(tmp_path, 4096, "%s" PSS "%s" PSS "%s.%scht", BaseDirectory.c_str(), overpath.c_str(), MDFNGameInfo->shortname, (type == MDFNMKF_CHEAT_TMP) ? "tmp" : "");
}
break;
case MDFNMKF_AUX: if(IsAbsolutePath(cd1))
trio_snprintf(tmp_path, 4096, "%s", (char *)cd1);
else
trio_snprintf(tmp_path, 4096, "%s"PSS"%s", FileBaseDirectory.c_str(), (char *)cd1);
trio_snprintf(tmp_path, 4096, "%s" PSS "%s", FileBaseDirectory.c_str(), (char *)cd1);
break;
case MDFNMKF_IPS: trio_snprintf(tmp_path, 4096, "%s"PSS"%s%s.ips", FileBaseDirectory.c_str(), FileBase.c_str(), FileExt.c_str());
case MDFNMKF_IPS: trio_snprintf(tmp_path, 4096, "%s" PSS "%s%s.ips", FileBaseDirectory.c_str(), FileBase.c_str(), FileExt.c_str());
break;
case MDFNMKF_FIRMWARE:
@ -417,14 +419,14 @@ std::string MDFN_MakeFName(MakeFName_Type type, int id1, const char *cd1)
else
{
if(IsAbsolutePath(overpath))
trio_snprintf(tmp_path, 4096, "%s"PSS"%s",overpath.c_str(), cd1);
trio_snprintf(tmp_path, 4096, "%s" PSS "%s",overpath.c_str(), cd1);
else
{
trio_snprintf(tmp_path, 4096, "%s"PSS"%s"PSS"%s", BaseDirectory.c_str(), overpath.c_str(), cd1);
trio_snprintf(tmp_path, 4096, "%s" PSS "%s" PSS "%s", BaseDirectory.c_str(), overpath.c_str(), cd1);
// For backwards-compatibility with < 0.9.0
if(stat(tmp_path,&tmpstat) == -1)
trio_snprintf(tmp_path, 4096, "%s"PSS"%s", BaseDirectory.c_str(), cd1);
trio_snprintf(tmp_path, 4096, "%s" PSS "%s", BaseDirectory.c_str(), cd1);
}
}
}
@ -439,20 +441,21 @@ std::string MDFN_MakeFName(MakeFName_Type type, int id1, const char *cd1)
else
eff_dir = std::string(BaseDirectory) + std::string(PSS) + overpath;
trio_snprintf(tmp_path, 4096, "%s"PSS"%s.pal", eff_dir.c_str(), FileBase.c_str());
trio_snprintf(tmp_path, 4096, "%s" PSS "%s.pal", eff_dir.c_str(), FileBase.c_str());
if(stat(tmp_path,&tmpstat) == -1 && errno == ENOENT)
{
trio_snprintf(tmp_path, 4096, "%s"PSS"%s.%s.pal", eff_dir.c_str(), FileBase.c_str(), md5_context::asciistr(MDFNGameInfo->MD5, 0).c_str());
trio_snprintf(tmp_path, 4096, "%s" PSS "%s.%s.pal", eff_dir.c_str(), FileBase.c_str(), md5_context::asciistr(MDFNGameInfo->MD5, 0).c_str());
if(stat(tmp_path, &tmpstat) == -1 && errno == ENOENT)
trio_snprintf(tmp_path, 4096, "%s"PSS"%s.pal", eff_dir.c_str(), cd1 ? cd1 : MDFNGameInfo->shortname);
trio_snprintf(tmp_path, 4096, "%s" PSS "%s.pal", eff_dir.c_str(), cd1 ? cd1 : MDFNGameInfo->shortname);
}
}
break;
}
return(tmp_path);
}
#endif
const char * GetFNComponent(const char *str)
{

View File

@ -4,7 +4,6 @@
#include <string>
#include "video.h"
#include "sound.h"
typedef struct
{
@ -57,12 +56,15 @@ typedef enum
IDIT_BUTTON, // 1-bit
IDIT_BUTTON_CAN_RAPID, // 1-bit
IDIT_BUTTON_BYTE, // 8-bits, Button as a byte instead of a bit.
IDIT_X_AXIS, // 32-bits
IDIT_Y_AXIS, // 32-bits
IDIT_X_AXIS_REL, // 32-bits, signed
IDIT_Y_AXIS_REL, // 32-bits, signed
IDIT_X_AXIS, // (mouse) 32-bits, signed, fixed-point: 1.15.16 - in-screen/window range: [0.0, nominal_width)
IDIT_Y_AXIS, // (mouse) 32-bits, signed, fixed-point: 1.15.16 - in-screen/window range: [0.0, nominal_height)
IDIT_X_AXIS_REL, // (mouse) 32-bits, signed
IDIT_Y_AXIS_REL, // (mouse) 32-bits, signed
IDIT_BYTE_SPECIAL,
IDIT_BUTTON_ANALOG, // 32-bits, 0 - 32767
IDIT_RUMBLE, // 32-bits, lower 8 bits are weak rumble(0-255), next 8 bits are strong rumble(0-255), 0=no rumble, 255=max rumble. Somewhat subjective, too...
// May extend to 16-bit each in the future.
// It's also rather a special case of game module->driver code communication.
} InputDeviceInputType;
#include "git-virtb.h"
@ -86,9 +88,10 @@ typedef struct
{
const char *ShortName;
const char *FullName;
const char *Description;
//struct InputPortInfoStruct *PortExpanderDeviceInfo;
const void *PortExpanderDeviceInfo;
const void *PortExpanderDeviceInfo; // DON'T USE, IT'S NOT IMPLEMENTED PROPERLY CURRENTLY.
int NumInputs; // Usually just the number of buttons....OR if PortExpanderDeviceInfo is non-NULL, it's the number of input
// ports this port expander device provides.
const InputDeviceInputInfoStruct *IDII;
@ -96,7 +99,6 @@ typedef struct
typedef struct
{
const int pid_offset;
const char *ShortName;
const char *FullName;
int NumTypes; // Number of unique input devices available for this input port
@ -169,8 +171,8 @@ enum
typedef struct
{
// Pitch(32-bit) must be equal to width and >= the pitch specified in the MDFNGI struct for the emulated system.
// Height must be >= to the fb_height specified in the MDFNGI struct for the emulated system.
// Pitch(32-bit) must be equal to width and >= the "fb_width" specified in the MDFNGI struct for the emulated system.
// Height must be >= to the "fb_height" specified in the MDFNGI struct for the emulated system.
// The framebuffer pointed to by surface->pixels is written to by the system emulation code.
MDFN_Surface *surface;
@ -326,7 +328,7 @@ typedef struct
const MDFNSetting *Settings;
// Time base for EmulateSpecStruct::MasterCycles
#define MDFN_MASTERCLOCK_FIXED(n) ((n) * (1LL << 32))
#define MDFN_MASTERCLOCK_FIXED(n) ((int64)((double)(n) * (1LL << 32)))
int64 MasterClock;
uint32 fps; // frames per second * 65536 * 256, truncated

View File

@ -30,6 +30,9 @@
language is requested. */
#undef ENABLE_NLS
/* Define to 1 if you have the `accept' function. */
#undef HAVE_ACCEPT
/* Define to 1 if you have `alloca', as a function or macro. */
#undef HAVE_ALLOCA
@ -61,6 +64,9 @@
/* Define to 1 if you have the `asprintf' function. */
#undef HAVE_ASPRINTF
/* Define to 1 if you have the `bind' function. */
#undef HAVE_BIND
/* Define to 1 if the compiler understands __builtin_expect. */
#undef HAVE_BUILTIN_EXPECT
@ -75,6 +81,12 @@
/* Define to 1 if you have the `clock_gettime' function. */
#undef HAVE_CLOCK_GETTIME
/* Define to 1 if you have the `close' function. */
#undef HAVE_CLOSE
/* Define to 1 if you have the `connect' function. */
#undef HAVE_CONNECT
/* Define if the GNU dcgettext() function is already present or preinstalled.
*/
#undef HAVE_DCGETTEXT
@ -114,6 +126,9 @@
/* Define to 1 if you have the `fopen64' function. */
#undef HAVE_FOPEN64
/* Define to 1 if you have the `freeaddrinfo' function. */
#undef HAVE_FREEADDRINFO
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
#undef HAVE_FSEEKO
@ -132,6 +147,12 @@
/* Define to 1 if you have the `fwprintf' function. */
#undef HAVE_FWPRINTF
/* Define to 1 if you have the `gai_strerror' function. */
#undef HAVE_GAI_STRERROR
/* Define to 1 if you have the `getaddrinfo' function. */
#undef HAVE_GETADDRINFO
/* Define to 1 if you have the `getcwd' function. */
#undef HAVE_GETCWD
@ -147,12 +168,21 @@
/* Define to 1 if you have the `getgid' function. */
#undef HAVE_GETGID
/* Define to 1 if you have the `gethostbyaddr' function. */
#undef HAVE_GETHOSTBYADDR
/* Define to 1 if you have the `gethostbyname' function. */
#undef HAVE_GETHOSTBYNAME
/* Define to 1 if you have the `getpagesize' function. */
#undef HAVE_GETPAGESIZE
/* Define to 1 if you have the `getpwuid' function. */
#undef HAVE_GETPWUID
/* Define to 1 if you have the `getsockopt' function. */
#undef HAVE_GETSOCKOPT
/* Define if the GNU gettext() function is already present or preinstalled. */
#undef HAVE_GETTEXT
@ -199,6 +229,12 @@
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define if we are compiling with Linux joystick support. */
#undef HAVE_LINUX_JOYSTICK
/* Define to 1 if you have the `listen' function. */
#undef HAVE_LISTEN
/* Define to 1 if the system has the type `long long int'. */
#undef HAVE_LONG_LONG_INT
@ -235,6 +271,9 @@
/* Define to 1 if you have the `munmap' function. */
#undef HAVE_MUNMAP
/* Define to 1 if you have the `nanosleep' function. */
#undef HAVE_NANOSLEEP
/* Define to 1 if you have the `newlocale' function. */
#undef HAVE_NEWLOCALE
@ -244,6 +283,9 @@
/* Define if your printf() function supports format strings with positions. */
#undef HAVE_POSIX_PRINTF
/* Define if we are compiling with POSIX sockets support. */
#undef HAVE_POSIX_SOCKETS
/* Define if the <pthread.h> defines PTHREAD_MUTEX_RECURSIVE. */
#undef HAVE_PTHREAD_MUTEX_RECURSIVE
@ -253,11 +295,17 @@
/* Define to 1 if you have the `putenv' function. */
#undef HAVE_PUTENV
/* Define to 1 if you have the `recv' function. */
#undef HAVE_RECV
/* Define if we are compiling with SDL sound support. */
#undef HAVE_SDL
/* Define if we are compiling with SDL_net support. */
#undef HAVE_SDL_NET
/* Define to 1 if you have the `select' function. */
#undef HAVE_SELECT
/* Define to 1 if you have the `send' function. */
#undef HAVE_SEND
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
@ -265,6 +313,9 @@
/* Define to 1 if you have the `setlocale' function. */
#undef HAVE_SETLOCALE
/* Define to 1 if you have the `setsockopt' function. */
#undef HAVE_SETSOCKOPT
/* Define to 1 if you have the `sigaction' function. */
#undef HAVE_SIGACTION
@ -274,6 +325,9 @@
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
/* Define to 1 if you have the `socket' function. */
#undef HAVE_SOCKET
/* Define to 1 if you have the <stddef.h> header file. */
#undef HAVE_STDDEF_H

View File

@ -30,6 +30,9 @@
language is requested. */
#undef ENABLE_NLS
/* Define to 1 if you have the `accept' function. */
#undef HAVE_ACCEPT
/* Define to 1 if you have `alloca', as a function or macro. */
#undef HAVE_ALLOCA
@ -61,6 +64,9 @@
/* Define to 1 if you have the `asprintf' function. */
#undef HAVE_ASPRINTF
/* Define to 1 if you have the `bind' function. */
#undef HAVE_BIND
/* Define to 1 if the compiler understands __builtin_expect. */
#undef HAVE_BUILTIN_EXPECT
@ -75,6 +81,12 @@
/* Define to 1 if you have the `clock_gettime' function. */
#undef HAVE_CLOCK_GETTIME
/* Define to 1 if you have the `close' function. */
#undef HAVE_CLOSE
/* Define to 1 if you have the `connect' function. */
#undef HAVE_CONNECT
/* Define if the GNU dcgettext() function is already present or preinstalled.
*/
#undef HAVE_DCGETTEXT
@ -114,6 +126,9 @@
/* Define to 1 if you have the `fopen64' function. */
#undef HAVE_FOPEN64
/* Define to 1 if you have the `freeaddrinfo' function. */
#undef HAVE_FREEADDRINFO
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
#undef HAVE_FSEEKO
@ -132,6 +147,12 @@
/* Define to 1 if you have the `fwprintf' function. */
#undef HAVE_FWPRINTF
/* Define to 1 if you have the `gai_strerror' function. */
#undef HAVE_GAI_STRERROR
/* Define to 1 if you have the `getaddrinfo' function. */
#undef HAVE_GETADDRINFO
/* Define to 1 if you have the `getcwd' function. */
#undef HAVE_GETCWD
@ -147,12 +168,21 @@
/* Define to 1 if you have the `getgid' function. */
#undef HAVE_GETGID
/* Define to 1 if you have the `gethostbyaddr' function. */
#undef HAVE_GETHOSTBYADDR
/* Define to 1 if you have the `gethostbyname' function. */
#undef HAVE_GETHOSTBYNAME
/* Define to 1 if you have the `getpagesize' function. */
#undef HAVE_GETPAGESIZE
/* Define to 1 if you have the `getpwuid' function. */
#undef HAVE_GETPWUID
/* Define to 1 if you have the `getsockopt' function. */
#undef HAVE_GETSOCKOPT
/* Define if the GNU gettext() function is already present or preinstalled. */
#undef HAVE_GETTEXT
@ -199,6 +229,9 @@
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define to 1 if you have the `listen' function. */
#undef HAVE_LISTEN
/* Define to 1 if the system has the type `long long int'. */
#undef HAVE_LONG_LONG_INT
@ -235,6 +268,9 @@
/* Define to 1 if you have the `munmap' function. */
#undef HAVE_MUNMAP
/* Define to 1 if you have the `nanosleep' function. */
#undef HAVE_NANOSLEEP
/* Define to 1 if you have the `newlocale' function. */
#undef HAVE_NEWLOCALE
@ -244,6 +280,9 @@
/* Define if your printf() function supports format strings with positions. */
#undef HAVE_POSIX_PRINTF
/* Define if we are compiling with POSIX sockets support. */
#undef HAVE_POSIX_SOCKETS
/* Define if the <pthread.h> defines PTHREAD_MUTEX_RECURSIVE. */
#undef HAVE_PTHREAD_MUTEX_RECURSIVE
@ -253,11 +292,17 @@
/* Define to 1 if you have the `putenv' function. */
#undef HAVE_PUTENV
/* Define to 1 if you have the `recv' function. */
#undef HAVE_RECV
/* Define if we are compiling with SDL sound support. */
#undef HAVE_SDL
/* Define if we are compiling with SDL_net support. */
#undef HAVE_SDL_NET
/* Define to 1 if you have the `select' function. */
#undef HAVE_SELECT
/* Define to 1 if you have the `send' function. */
#undef HAVE_SEND
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
@ -265,6 +310,9 @@
/* Define to 1 if you have the `setlocale' function. */
#undef HAVE_SETLOCALE
/* Define to 1 if you have the `setsockopt' function. */
#undef HAVE_SETSOCKOPT
/* Define to 1 if you have the `sigaction' function. */
#undef HAVE_SIGACTION
@ -274,6 +322,9 @@
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
/* Define to 1 if you have the `socket' function. */
#undef HAVE_SOCKET
/* Define to 1 if you have the <stddef.h> header file. */
#undef HAVE_STDDEF_H
@ -400,9 +451,6 @@
/* Define to use fixed-point MPC decoder. */
#undef MPC_FIXED_POINT
/* Define on little-endian platforms. */
#undef MPC_LITTLE_ENDIAN
/* Define on big-endian platforms. */
#undef MSB_FIRST

View File

@ -57,9 +57,6 @@ int MDFND_UnlockMutex(MDFN_Mutex *mutex);
void MDFNI_Reset(void);
void MDFNI_Power(void);
/* Called from the physical CD disc reading code. */
bool MDFND_ExitBlockingLoop(void);
/* path = path of game/file to load. returns NULL on failure. */
MDFNGI *MDFNI_LoadGame(const char *force_module, const char *path);

View File

@ -55,13 +55,13 @@ void FlipByteOrder(uint8 *src, uint32 count);
// The following functions can encode/decode to unaligned addresses.
static INLINE void MDFN_en16lsb(uint8 *buf, uint16 morp)
static inline void MDFN_en16lsb(uint8 *buf, uint16 morp)
{
buf[0]=morp;
buf[1]=morp>>8;
}
static INLINE void MDFN_en24lsb(uint8 *buf, uint32 morp)
static inline void MDFN_en24lsb(uint8 *buf, uint32 morp)
{
buf[0]=morp;
buf[1]=morp>>8;
@ -69,7 +69,7 @@ static INLINE void MDFN_en24lsb(uint8 *buf, uint32 morp)
}
static INLINE void MDFN_en32lsb(uint8 *buf, uint32 morp)
static inline void MDFN_en32lsb(uint8 *buf, uint32 morp)
{
buf[0]=morp;
buf[1]=morp>>8;
@ -77,7 +77,7 @@ static INLINE void MDFN_en32lsb(uint8 *buf, uint32 morp)
buf[3]=morp>>24;
}
static INLINE void MDFN_en64lsb(uint8 *buf, uint64 morp)
static inline void MDFN_en64lsb(uint8 *buf, uint64 morp)
{
buf[0]=morp >> 0;
buf[1]=morp >> 8;
@ -90,20 +90,20 @@ static INLINE void MDFN_en64lsb(uint8 *buf, uint64 morp)
}
static INLINE void MDFN_en16msb(uint8 *buf, uint16 morp)
static inline void MDFN_en16msb(uint8 *buf, uint16 morp)
{
buf[0] = morp >> 8;
buf[1] = morp;
}
static INLINE void MDFN_en24msb(uint8 *buf, uint32 morp)
static inline void MDFN_en24msb(uint8 *buf, uint32 morp)
{
buf[0] = morp >> 16;
buf[1] = morp >> 8;
buf[2] = morp;
}
static INLINE void MDFN_en32msb(uint8 *buf, uint32 morp)
static inline void MDFN_en32msb(uint8 *buf, uint32 morp)
{
buf[0] = morp >> 24;
buf[1] = morp >> 16;
@ -111,7 +111,7 @@ static INLINE void MDFN_en32msb(uint8 *buf, uint32 morp)
buf[3] = morp;
}
static INLINE void MDFN_en64msb(uint8 *buf, uint64 morp)
static inline void MDFN_en64msb(uint8 *buf, uint64 morp)
{
buf[0] = morp >> 56;
buf[1] = morp >> 48;
@ -125,39 +125,39 @@ static INLINE void MDFN_en64msb(uint8 *buf, uint64 morp)
// Overloaded functions, yay.
static INLINE void MDFN_enlsb(uint16 * buf, uint16 value)
static inline void MDFN_enlsb(uint16 * buf, uint16 value)
{
MDFN_en16lsb((uint8 *)buf, value);
}
static INLINE void MDFN_enlsb(uint32 * buf, uint32 value)
static inline void MDFN_enlsb(uint32 * buf, uint32 value)
{
MDFN_en32lsb((uint8 *)buf, value);
}
static INLINE void MDFN_enlsb(uint64 * buf, uint64 value)
static inline void MDFN_enlsb(uint64 * buf, uint64 value)
{
MDFN_en64lsb((uint8 *)buf, value);
}
static INLINE uint16 MDFN_de16lsb(const uint8 *morp)
static inline uint16 MDFN_de16lsb(const uint8 *morp)
{
return(morp[0] | (morp[1] << 8));
}
static INLINE uint32 MDFN_de24lsb(const uint8 *morp)
static inline uint32 MDFN_de24lsb(const uint8 *morp)
{
return(morp[0]|(morp[1]<<8)|(morp[2]<<16));
}
static INLINE uint32 MDFN_de32lsb(const uint8 *morp)
static inline uint32 MDFN_de32lsb(const uint8 *morp)
{
return(morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24));
}
static INLINE uint64 MDFN_de64lsb(const uint8 *morp)
static inline uint64 MDFN_de64lsb(const uint8 *morp)
{
uint64 ret = 0;
@ -173,33 +173,33 @@ static INLINE uint64 MDFN_de64lsb(const uint8 *morp)
return(ret);
}
static INLINE uint16 MDFN_delsb(const uint16 *buf)
static inline uint16 MDFN_delsb(const uint16 *buf)
{
return(MDFN_de16lsb((uint8 *)buf));
}
static INLINE uint32 MDFN_delsb(const uint32 *buf)
static inline uint32 MDFN_delsb(const uint32 *buf)
{
return(MDFN_de32lsb((uint8 *)buf));
}
static INLINE uint64 MDFN_delsb(const uint64 *buf)
static inline uint64 MDFN_delsb(const uint64 *buf)
{
return(MDFN_de64lsb((uint8 *)buf));
}
static INLINE uint16 MDFN_de16msb(const uint8 *morp)
static inline uint16 MDFN_de16msb(const uint8 *morp)
{
return(morp[1] | (morp[0] << 8));
}
static INLINE uint32 MDFN_de24msb(const uint8 *morp)
static inline uint32 MDFN_de24msb(const uint8 *morp)
{
return((morp[2]<<0)|(morp[1]<<8)|(morp[0]<<16));
}
static INLINE uint32 MDFN_de32msb(const uint8 *morp)
static inline uint32 MDFN_de32msb(const uint8 *morp)
{
return(morp[3]|(morp[2]<<8)|(morp[1]<<16)|(morp[0]<<24));
}

View File

@ -67,20 +67,6 @@ static MDFNSetting_EnumList CompressorList[] =
{ NULL, 0 },
};
static MDFNSetting_EnumList VCodec_List[] =
{
{ "raw", (int)QTRecord::VCODEC_RAW, "Raw",
gettext_noop("A fast codec, computationally, but will cause enormous file size and may exceed your storage medium's sustained write rate.") },
{ "cscd", (int)QTRecord::VCODEC_CSCD, "CamStudio Screen Codec",
gettext_noop("A good balance between performance and compression ratio.") },
{ "png", (int)QTRecord::VCODEC_PNG, "PNG",
gettext_noop("Has a better compression ratio than \"cscd\", but is much more CPU intensive. Use for compatibility with official QuickTime in cases where you have insufficient disk space for \"raw\".") },
{ NULL, 0 },
};
static const char *fname_extra = gettext_noop("See fname_format.txt for more information. Edit at your own risk.");
static MDFNSetting MednafenSettings[] =
@ -108,11 +94,6 @@ static MDFNSetting MednafenSettings[] =
{ "filesys.disablesavegz", MDFNSF_NOFLAGS, gettext_noop("Disable gzip compression when saving save states and backup memory."), NULL, MDFNST_BOOL, "0" },
{ "qtrecord.w_double_threshold", MDFNSF_NOFLAGS, gettext_noop("Double the raw image's width if it's below this threshold."), NULL, MDFNST_UINT, "384", "0", "1073741824" },
{ "qtrecord.h_double_threshold", MDFNSF_NOFLAGS, gettext_noop("Double the raw image's height if it's below this threshold."), NULL, MDFNST_UINT, "256", "0", "1073741824" },
{ "qtrecord.vcodec", MDFNSF_NOFLAGS, gettext_noop("Video codec to use."), NULL, MDFNST_ENUM, "cscd", NULL, NULL, NULL, NULL, VCodec_List },
{ NULL }
};
@ -145,6 +126,10 @@ static MDFNSetting RenamedSettings[] =
{ "glvsync", MDFNSF_NOFLAGS, NULL, NULL, MDFNST_ALIAS , "video.glvsync" },
{ "fs", MDFNSF_NOFLAGS, NULL, NULL, MDFNST_ALIAS , "video.fs" },
{ "autofirefreq", MDFNSF_NOFLAGS, NULL, NULL, MDFNST_ALIAS , "input.autofirefreq" },
{ "analogthreshold", MDFNSF_NOFLAGS, NULL, NULL, MDFNST_ALIAS , "input.joystick.axis_threshold" },
{ "ckdelay", MDFNSF_NOFLAGS, NULL, NULL, MDFNST_ALIAS , "input.ckdelay" },
{ NULL }
};
@ -154,7 +139,6 @@ static uint32 PortDataLenCache[16];
MDFNGI *MDFNGameInfo = NULL;
static QTRecord *qtrecorder = NULL;
static WAVRecord *wavrecorder = NULL;
static Fir_Resampler<16> ff_resampler;
static double LastSoundMultiplier;
@ -169,93 +153,10 @@ static Deinterlacer deint;
static std::vector<CDIF *> CDInterfaces; // FIXME: Cleanup on error out.
bool MDFNI_StartWAVRecord(const char *path, double SoundRate)
{
try
{
wavrecorder = new WAVRecord(path, SoundRate, MDFNGameInfo->soundchan);
}
catch(std::exception &e)
{
MDFND_PrintError(e.what());
return(false);
}
return(true);
}
bool MDFNI_StartAVRecord(const char *path, double SoundRate)
{
try
{
QTRecord::VideoSpec spec;
memset(&spec, 0, sizeof(spec));
spec.SoundRate = SoundRate;
spec.SoundChan = MDFNGameInfo->soundchan;
spec.VideoWidth = MDFNGameInfo->lcm_width;
spec.VideoHeight = MDFNGameInfo->lcm_height;
spec.VideoCodec = MDFN_GetSettingI("qtrecord.vcodec");
if(spec.VideoWidth < MDFN_GetSettingUI("qtrecord.w_double_threshold"))
spec.VideoWidth *= 2;
if(spec.VideoHeight < MDFN_GetSettingUI("qtrecord.h_double_threshold"))
spec.VideoHeight *= 2;
spec.AspectXAdjust = ((double)MDFNGameInfo->nominal_width * 2) / spec.VideoWidth;
spec.AspectYAdjust = ((double)MDFNGameInfo->nominal_height * 2) / spec.VideoHeight;
MDFN_printf("\n");
MDFN_printf(_("Starting QuickTime recording to file \"%s\":\n"), path);
MDFN_indent(1);
MDFN_printf(_("Video width: %u\n"), spec.VideoWidth);
MDFN_printf(_("Video height: %u\n"), spec.VideoHeight);
MDFN_printf(_("Video codec: %s\n"), MDFN_GetSettingS("qtrecord.vcodec").c_str());
MDFN_printf(_("Sound rate: %u\n"), spec.SoundRate);
MDFN_printf(_("Sound channels: %u\n"), spec.SoundChan);
MDFN_indent(-1);
MDFN_printf("\n");
qtrecorder = new QTRecord(path, spec);
}
catch(std::exception &e)
{
MDFND_PrintError(e.what());
return(false);
}
return(true);
}
void MDFNI_StopAVRecord(void)
{
if(qtrecorder)
{
delete qtrecorder;
qtrecorder = NULL;
}
}
void MDFNI_StopWAVRecord(void)
{
if(wavrecorder)
{
delete wavrecorder;
wavrecorder = NULL;
}
}
void MDFNI_CloseGame(void)
{
if(MDFNGameInfo)
{
if(MDFNnetplay)
MDFNI_NetplayStop();
MDFNMOV_Stop();
if(MDFNGameInfo->GameType != GMT_PLAYER)
MDFN_FlushGameCheats(0);
@ -294,68 +195,10 @@ void MDFNI_CloseGame(void)
memset(PortDeviceCache, 0, sizeof(PortDeviceCache));
}
int MDFNI_NetplayStart(uint32 local_players, const std::string &nickname, const std::string &game_key, const std::string &connect_password)
{
return(NetplayStart((const char**)PortDeviceCache, PortDataLenCache, local_players, nickname, game_key, connect_password));
}
#ifdef WANT_NES_EMU
extern MDFNGI EmulatedNES;
#endif
#ifdef WANT_SNES_EMU
extern MDFNGI EmulatedSNES;
#endif
#ifdef WANT_GBA_EMU
extern MDFNGI EmulatedGBA;
#endif
#ifdef WANT_GB_EMU
extern MDFNGI EmulatedGB;
#endif
#ifdef WANT_LYNX_EMU
extern MDFNGI EmulatedLynx;
#endif
#ifdef WANT_MD_EMU
extern MDFNGI EmulatedMD;
#endif
#ifdef WANT_NGP_EMU
extern MDFNGI EmulatedNGP;
#endif
#ifdef WANT_PCE_EMU
extern MDFNGI EmulatedPCE;
#endif
#ifdef WANT_PCE_FAST_EMU
extern MDFNGI EmulatedPCE_Fast;
#endif
#ifdef WANT_PCFX_EMU
extern MDFNGI EmulatedPCFX;
#endif
#ifdef WANT_PSX_EMU
extern MDFNGI EmulatedPSX;
#endif
#ifdef WANT_VB_EMU
extern MDFNGI EmulatedVB;
#endif
#ifdef WANT_WSWAN_EMU
extern MDFNGI EmulatedWSwan;
#endif
#ifdef WANT_SMS_EMU
extern MDFNGI EmulatedSMS, EmulatedGG;
#endif
extern MDFNGI EmulatedCDPlay;
std::vector<MDFNGI *> MDFNSystems;
@ -449,14 +292,22 @@ MDFNGI *MDFNI_LoadCD(const char *force_module, const char *devicename)
for(unsigned i = 0; i < file_list.size(); i++)
{
CDInterfaces.push_back(new CDIF(file_list[i].c_str()));
#if 1
CDInterfaces.push_back(new CDIF_MT(file_list[i].c_str()));
#else
CDInterfaces.push_back(new CDIF_ST(file_list[i].c_str()));
#endif
}
GetFileBase(devicename);
}
else
{
CDInterfaces.push_back(new CDIF(devicename));
#if 1
CDInterfaces.push_back(new CDIF_MT(devicename));
#else
CDInterfaces.push_back(new CDIF_ST(devicename));
#endif
if(CDInterfaces[0]->IsPhysical())
{
GetFileBase("cdrom");
@ -602,7 +453,6 @@ MDFNGI *MDFNI_LoadCD(const char *force_module, const char *devicename)
#endif
MDFNSS_CheckStates();
MDFNMOV_CheckMovies();
MDFN_ResetMessages(); // Save state, status messages, etc.
@ -636,7 +486,9 @@ static bool LoadIPS(MDFNFILE &GameFile, const char *path)
{
ErrnoHolder ene(errno);
MDFN_indent(1);
MDFN_printf(_("Failed: %s\n"), ene.StrError());
MDFN_indent(-1);
if(ene.Errno() == ENOENT)
return(1);
@ -786,6 +638,21 @@ MDFNGI *MDFNI_LoadGame(const char *force_module, const char *name)
MDFNGameInfo->name = NULL;
MDFNGameInfo->rotated = 0;
//
// Load per-game settings
//
// Maybe we should make a "pgcfg" subdir, and automatically load all files in it?
#if 0
{
char hash_string[n + 1];
const char *section_names[3] = { MDFNGameInfo->shortname, hash_string, NULL };
//asdfasdfMDFN_LoadSettings(std::string(basedir) + std::string(PSS) + std::string("pergame.cfg");
}
#endif
// End load per-game settings
//
if(MDFNGameInfo->Load(name, &GameFile) <= 0)
{
GameFile.Close();
@ -807,7 +674,6 @@ MDFNGI *MDFNI_LoadGame(const char *force_module, const char *name)
#endif
MDFNSS_CheckStates();
MDFNMOV_CheckMovies();
MDFN_ResetMessages(); // Save state, status messages, etc.
@ -1029,25 +895,18 @@ bool MDFNI_InitializeModules(const std::vector<MDFNGI *> &ExternalSystems)
MDFNSystemsPrio.sort(MDFNSystemsPrio_CompareFunc);
#if 0
std::string a_modules;
std::list<MDFNGI *>:iterator it;
for(it = MDFNSystemsPrio.
f
#endif
CDUtility::CDUtility_Init();
return(1);
}
static std::string settings_file_path;
int MDFNI_Initialize(const char *basedir, const std::vector<MDFNSetting> &DriverSettings)
{
// FIXME static
static std::vector<MDFNSetting> dynamic_settings;
// DO NOT REMOVE/DISABLE THESE MATH AND COMPILER SANITY TESTS. THEY EXIST FOR A REASON.
if(!MDFN_RunMathTests())
{
return(0);
@ -1109,7 +968,8 @@ int MDFNI_Initialize(const char *basedir, const std::vector<MDFNSetting> &Driver
MDFN_MergeSettings(RenamedSettings);
if(!MFDN_LoadSettings(basedir))
settings_file_path = std::string(basedir) + std::string(PSS) + std::string("mednafen-09x.cfg");
if(!MDFN_LoadSettings(settings_file_path.c_str()))
return(0);
#ifdef WANT_DEBUGGER
@ -1121,7 +981,8 @@ int MDFNI_Initialize(const char *basedir, const std::vector<MDFNSetting> &Driver
void MDFNI_Kill(void)
{
MDFN_SaveSettings();
MDFN_SaveSettings(settings_file_path.c_str());
MDFN_KillSettings();
}
static double multiplier_save, volume_save;
@ -1142,15 +1003,6 @@ static void ProcessAudio(EmulateSpecStruct *espec)
const int32 SoundBufMaxSize = espec->SoundBufMaxSize - espec->SoundBufSizeALMS;
if(qtrecorder && (volume_save != 1 || multiplier_save != 1))
{
int32 orig_size = SoundBufPristine.size();
SoundBufPristine.resize(orig_size + SoundBufSize * MDFNGameInfo->soundchan);
for(int i = 0; i < SoundBufSize * MDFNGameInfo->soundchan; i++)
SoundBufPristine[orig_size + i] = SoundBuf[i];
}
if(espec->NeedSoundReverse)
{
int16 *yaybuf = SoundBuf;
@ -1176,18 +1028,6 @@ static void ProcessAudio(EmulateSpecStruct *espec)
}
}
try
{
if(wavrecorder)
wavrecorder->WriteSound(SoundBuf, SoundBufSize);
}
catch(std::exception &e)
{
MDFND_PrintError(e.what());
delete wavrecorder;
wavrecorder = NULL;
}
if(multiplier_save != LastSoundMultiplier)
{
ff_resampler.time_ratio(multiplier_save, 0.9965);
@ -1283,17 +1123,10 @@ static void ProcessAudio(EmulateSpecStruct *espec)
void MDFN_MidSync(EmulateSpecStruct *espec)
{
if(MDFNnetplay)
return;
ProcessAudio(espec);
MDFND_MidSync(espec);
for(int x = 0; x < 16; x++)
if(PortDataCache[x])
MDFNMOV_AddJoy(PortDataCache[x], PortDataLenCache[x]);
espec->SoundBufSizeALMS = espec->SoundBufSize;
espec->MasterCyclesALMS = espec->MasterCycles;
}
@ -1331,45 +1164,12 @@ void MDFNI_Emulate(EmulateSpecStruct *espec)
ff_resampler.buffer_size((espec->SoundRate / 2) * 2);
}
// We want to record movies without any dropped video frames and without fast-forwarding sound distortion and without custom volume.
// The same goes for WAV recording(sans the dropped video frames bit :b).
if(qtrecorder || wavrecorder)
{
multiplier_save = espec->soundmultiplier;
espec->soundmultiplier = 1;
volume_save = espec->SoundVolume;
espec->SoundVolume = 1;
}
if(MDFNnetplay)
{
NetplayUpdate((const char**)PortDeviceCache, PortDataCache, PortDataLenCache, MDFNGameInfo->InputInfo->InputPorts);
}
for(int x = 0; x < 16; x++)
if(PortDataCache[x])
MDFNMOV_AddJoy(PortDataCache[x], PortDataLenCache[x]);
if(qtrecorder)
espec->skip = 0;
if(TBlur_IsOn())
espec->skip = 0;
if(espec->NeedRewind)
{
if(MDFNMOV_IsPlaying())
{
espec->NeedRewind = 0;
MDFN_DispMessage(_("Can't rewind during movie playback."));
}
else if(MDFNnetplay)
{
espec->NeedRewind = 0;
MDFN_DispMessage(_("Can't rewind during netplay."));
}
else if(MDFNGameInfo->GameType == GMT_PLAYER)
if(MDFNGameInfo->GameType == GMT_PLAYER)
{
espec->NeedRewind = 0;
MDFN_DispMessage(_("Music player rewinding is unsupported."));
@ -1379,9 +1179,6 @@ void MDFNI_Emulate(EmulateSpecStruct *espec)
// Don't even save states with state rewinding if netplay is enabled, it will degrade netplay performance, and can cause
// desynchs with some emulation(IE SNES based on bsnes).
if(MDFNnetplay)
espec->NeedSoundReverse = false;
else
espec->NeedSoundReverse = MDFN_StateEvil(espec->NeedRewind);
MDFNGameInfo->Emulate(espec);
@ -1417,34 +1214,6 @@ void MDFNI_Emulate(EmulateSpecStruct *espec)
ProcessAudio(espec);
if(qtrecorder)
{
int16 *sb_backup = espec->SoundBuf;
int32 sbs_backup = espec->SoundBufSize;
if(SoundBufPristine.size())
{
espec->SoundBuf = &SoundBufPristine[0];
espec->SoundBufSize = SoundBufPristine.size() / MDFNGameInfo->soundchan;
}
try
{
qtrecorder->WriteFrame(espec->surface, espec->DisplayRect, espec->LineWidths, espec->SoundBuf, espec->SoundBufSize);
}
catch(std::exception &e)
{
MDFND_PrintError(e.what());
delete qtrecorder;
qtrecorder = NULL;
}
SoundBufPristine.clear();
espec->SoundBuf = sb_backup;
espec->SoundBufSize = sbs_backup;
}
TBlur_Run(espec);
}
@ -1578,16 +1347,6 @@ void MDFN_DoSimpleCommand(int cmd)
void MDFN_QSimpleCommand(int cmd)
{
if(MDFNnetplay)
NetplaySendCommand(cmd, 0);
else
{
if(!MDFNMOV_IsPlaying())
{
MDFN_DoSimpleCommand(cmd);
MDFNMOV_AddCommand(cmd);
}
}
}
void MDFNI_Power(void)

View File

@ -1,8 +1,9 @@
#ifndef _MDFN_MEMORY_H
#include <stdint.h>
// These functions can be used from driver code or from internal Mednafen code.
//
#include <stdint.h>
#define MDFN_malloc(size, purpose) MDFN_malloc_real(size, purpose, __FILE__, __LINE__)
#define MDFN_calloc(nmemb, size, purpose) MDFN_calloc_real(nmemb, size, purpose, __FILE__, __LINE__)
@ -37,7 +38,7 @@ static inline void MDFN_FastU32MemsetM8(uint32_t *array, uint32_t value_32, unsi
#else
for(uint32 *ai = array; ai < array + u32len; ai += 2)
for(uint32_t *ai = array; ai < array + u32len; ai += 2)
{
ai[0] = value_32;
ai[1] = value_32;

View File

@ -116,6 +116,8 @@ ALLOCA = @ALLOCA@
ALSA_CFLAGS = @ALSA_CFLAGS@
ALSA_LIBS = @ALSA_LIBS@
AMTAR = @AMTAR@
AM_CFLAGS = @AM_CFLAGS@
AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
@ -234,6 +236,8 @@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
SNDFILE_LIBS = @SNDFILE_LIBS@
SNES_EXTRA_CXXFLAGS = @SNES_EXTRA_CXXFLAGS@
SNES_EXTRA_FLAGS = @SNES_EXTRA_FLAGS@
SSE2_CFLAGS = @SSE2_CFLAGS@
SSE3_CFLAGS = @SSE3_CFLAGS@
SSE_CFLAGS = @SSE_CFLAGS@
@ -242,6 +246,7 @@ TRIO_CFLAGS = @TRIO_CFLAGS@
USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
WARNING_FLAGS = @WARNING_FLAGS@
WINDRES = @WINDRES@
WOE32 = @WOE32@
WOE32DLL = @WOE32DLL@

View File

@ -36,7 +36,6 @@
#include "reader.h"
#include "internal.h"
#include <stdio.h>
#include <string.h>
#define STDIO_MAGIC 0xF34B963C ///< Just a random safe-check value...
typedef struct mpc_reader_stdio_t {

View File

@ -23,14 +23,13 @@
// #include "mpcenc.h"
#include <stdio.h>
#include <string.h>
#include "mpc_types.h"
#ifdef _WIN32
# include <windows.h>
#endif
#include <string.h>
#ifdef _MSC_VER
# define strncasecmp strnicmp
#endif

View File

@ -1,413 +0,0 @@
cpu.o: cpu.cpp psx.h ../../mednafen/mednafen.h ../../mednafen/types.h \
../../include/config.h /usr/include/assert.h /usr/include/features.h \
/usr/include/bits/predefs.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-64.h /usr/include/inttypes.h \
/usr/include/stdint.h /usr/include/bits/wchar.h ../../mednafen/error.h \
/usr/include/errno.h /usr/include/bits/errno.h \
/usr/include/linux/errno.h /usr/include/asm/errno.h \
/usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
/usr/include/string.h \
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/include/stddef.h \
/usr/include/xlocale.h /usr/include/c++/4.4/exception \
/usr/include/c++/4.4/x86_64-linux-gnu/bits/c++config.h \
/usr/include/c++/4.4/x86_64-linux-gnu/bits/os_defines.h \
/usr/include/c++/4.4/x86_64-linux-gnu/bits/cpu_defines.h \
/usr/include/stdio.h /usr/include/bits/types.h \
/usr/include/bits/typesizes.h /usr/include/libio.h \
/usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/bits/stdio.h /usr/include/stdlib.h \
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
/usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/sys/types.h \
/usr/include/time.h /usr/include/sys/select.h /usr/include/bits/select.h \
/usr/include/bits/sigset.h /usr/include/bits/time.h \
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
/usr/include/alloca.h ../../mednafen/gettext.h /usr/include/libintl.h \
../../mednafen/math_ops.h ../../mednafen/git.h \
/usr/include/c++/4.4/string /usr/include/c++/4.4/bits/stringfwd.h \
/usr/include/c++/4.4/bits/char_traits.h \
/usr/include/c++/4.4/bits/stl_algobase.h /usr/include/c++/4.4/cstddef \
/usr/include/c++/4.4/bits/functexcept.h \
/usr/include/c++/4.4/exception_defines.h \
/usr/include/c++/4.4/bits/cpp_type_traits.h \
/usr/include/c++/4.4/ext/type_traits.h \
/usr/include/c++/4.4/ext/numeric_traits.h \
/usr/include/c++/4.4/bits/stl_pair.h /usr/include/c++/4.4/bits/move.h \
/usr/include/c++/4.4/bits/concept_check.h \
/usr/include/c++/4.4/bits/stl_iterator_base_types.h \
/usr/include/c++/4.4/bits/stl_iterator_base_funcs.h \
/usr/include/c++/4.4/bits/stl_iterator.h \
/usr/include/c++/4.4/debug/debug.h /usr/include/c++/4.4/bits/postypes.h \
/usr/include/c++/4.4/cwchar /usr/include/c++/4.4/bits/allocator.h \
/usr/include/c++/4.4/x86_64-linux-gnu/bits/c++allocator.h \
/usr/include/c++/4.4/ext/new_allocator.h /usr/include/c++/4.4/new \
/usr/include/c++/4.4/bits/localefwd.h \
/usr/include/c++/4.4/x86_64-linux-gnu/bits/c++locale.h \
/usr/include/c++/4.4/clocale /usr/include/locale.h \
/usr/include/bits/locale.h /usr/include/c++/4.4/iosfwd \
/usr/include/c++/4.4/cctype /usr/include/ctype.h \
/usr/include/c++/4.4/bits/ostream_insert.h \
/usr/include/c++/4.4/cxxabi-forced.h \
/usr/include/c++/4.4/bits/stl_function.h \
/usr/include/c++/4.4/backward/binders.h \
/usr/include/c++/4.4/bits/basic_string.h \
/usr/include/c++/4.4/ext/atomicity.h \
/usr/include/c++/4.4/x86_64-linux-gnu/bits/gthr.h \
/usr/include/c++/4.4/x86_64-linux-gnu/bits/gthr-default.h \
/usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \
/usr/include/signal.h /usr/include/bits/setjmp.h /usr/include/unistd.h \
/usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
/usr/include/bits/confname.h /usr/include/getopt.h \
/usr/include/c++/4.4/x86_64-linux-gnu/bits/atomic_word.h \
/usr/include/c++/4.4/initializer_list \
/usr/include/c++/4.4/bits/basic_string.tcc ../../mednafen/video.h \
../../mednafen/video/surface.h /usr/include/c++/4.4/vector \
/usr/include/c++/4.4/bits/stl_construct.h \
/usr/include/c++/4.4/bits/stl_uninitialized.h \
/usr/include/c++/4.4/bits/stl_vector.h \
/usr/include/c++/4.4/bits/stl_bvector.h \
/usr/include/c++/4.4/bits/vector.tcc ../../mednafen/video/primitives.h \
../../mednafen/video/text.h /usr/include/c++/4.4/algorithm \
/usr/include/c++/4.4/bits/stl_algo.h /usr/include/c++/4.4/cstdlib \
/usr/include/c++/4.4/bits/algorithmfwd.h \
/usr/include/c++/4.4/bits/stl_heap.h \
/usr/include/c++/4.4/bits/stl_tempbuf.h ../../mednafen/sound.h \
../../mednafen/file.h ../../mednafen/state.h /usr/include/zlib.h \
/usr/include/zconf.h /usr/include/zlibdefs.h \
../../mednafen/state-common.h ../../mednafen/settings-common.h \
../../mednafen/debug.h ../../mednafen/git-virtb.h \
../../mednafen/settings.h ../../mednafen/mednafen-driver.h \
../../mednafen/endian.h ../../mednafen/memory.h ../../mednafen/masmem.h \
../../include/trio/trio.h ../../include/trio/triop.h \
../../include/trio/triodef.h ../cdrom/cdromif.h ../cdrom/CDUtility.h \
/usr/include/c++/4.4/queue /usr/include/c++/4.4/deque \
/usr/include/c++/4.4/bits/stl_deque.h \
/usr/include/c++/4.4/bits/deque.tcc \
/usr/include/c++/4.4/bits/stl_queue.h ../general.h ../FileWrapper.h \
dis.h cpu.h gte.h irq.h gpu.h ../cdrom/SimpleFIFO.h \
../cdrom/../math_ops.h dma.h debug.h
psx.h:
../../mednafen/mednafen.h:
../../mednafen/types.h:
../../include/config.h:
/usr/include/assert.h:
/usr/include/features.h:
/usr/include/bits/predefs.h:
/usr/include/sys/cdefs.h:
/usr/include/bits/wordsize.h:
/usr/include/gnu/stubs.h:
/usr/include/gnu/stubs-64.h:
/usr/include/inttypes.h:
/usr/include/stdint.h:
/usr/include/bits/wchar.h:
../../mednafen/error.h:
/usr/include/errno.h:
/usr/include/bits/errno.h:
/usr/include/linux/errno.h:
/usr/include/asm/errno.h:
/usr/include/asm-generic/errno.h:
/usr/include/asm-generic/errno-base.h:
/usr/include/string.h:
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/include/stddef.h:
/usr/include/xlocale.h:
/usr/include/c++/4.4/exception:
/usr/include/c++/4.4/x86_64-linux-gnu/bits/c++config.h:
/usr/include/c++/4.4/x86_64-linux-gnu/bits/os_defines.h:
/usr/include/c++/4.4/x86_64-linux-gnu/bits/cpu_defines.h:
/usr/include/stdio.h:
/usr/include/bits/types.h:
/usr/include/bits/typesizes.h:
/usr/include/libio.h:
/usr/include/_G_config.h:
/usr/include/wchar.h:
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/include/stdarg.h:
/usr/include/bits/stdio_lim.h:
/usr/include/bits/sys_errlist.h:
/usr/include/bits/stdio.h:
/usr/include/stdlib.h:
/usr/include/bits/waitflags.h:
/usr/include/bits/waitstatus.h:
/usr/include/endian.h:
/usr/include/bits/endian.h:
/usr/include/bits/byteswap.h:
/usr/include/sys/types.h:
/usr/include/time.h:
/usr/include/sys/select.h:
/usr/include/bits/select.h:
/usr/include/bits/sigset.h:
/usr/include/bits/time.h:
/usr/include/sys/sysmacros.h:
/usr/include/bits/pthreadtypes.h:
/usr/include/alloca.h:
../../mednafen/gettext.h:
/usr/include/libintl.h:
../../mednafen/math_ops.h:
../../mednafen/git.h:
/usr/include/c++/4.4/string:
/usr/include/c++/4.4/bits/stringfwd.h:
/usr/include/c++/4.4/bits/char_traits.h:
/usr/include/c++/4.4/bits/stl_algobase.h:
/usr/include/c++/4.4/cstddef:
/usr/include/c++/4.4/bits/functexcept.h:
/usr/include/c++/4.4/exception_defines.h:
/usr/include/c++/4.4/bits/cpp_type_traits.h:
/usr/include/c++/4.4/ext/type_traits.h:
/usr/include/c++/4.4/ext/numeric_traits.h:
/usr/include/c++/4.4/bits/stl_pair.h:
/usr/include/c++/4.4/bits/move.h:
/usr/include/c++/4.4/bits/concept_check.h:
/usr/include/c++/4.4/bits/stl_iterator_base_types.h:
/usr/include/c++/4.4/bits/stl_iterator_base_funcs.h:
/usr/include/c++/4.4/bits/stl_iterator.h:
/usr/include/c++/4.4/debug/debug.h:
/usr/include/c++/4.4/bits/postypes.h:
/usr/include/c++/4.4/cwchar:
/usr/include/c++/4.4/bits/allocator.h:
/usr/include/c++/4.4/x86_64-linux-gnu/bits/c++allocator.h:
/usr/include/c++/4.4/ext/new_allocator.h:
/usr/include/c++/4.4/new:
/usr/include/c++/4.4/bits/localefwd.h:
/usr/include/c++/4.4/x86_64-linux-gnu/bits/c++locale.h:
/usr/include/c++/4.4/clocale:
/usr/include/locale.h:
/usr/include/bits/locale.h:
/usr/include/c++/4.4/iosfwd:
/usr/include/c++/4.4/cctype:
/usr/include/ctype.h:
/usr/include/c++/4.4/bits/ostream_insert.h:
/usr/include/c++/4.4/cxxabi-forced.h:
/usr/include/c++/4.4/bits/stl_function.h:
/usr/include/c++/4.4/backward/binders.h:
/usr/include/c++/4.4/bits/basic_string.h:
/usr/include/c++/4.4/ext/atomicity.h:
/usr/include/c++/4.4/x86_64-linux-gnu/bits/gthr.h:
/usr/include/c++/4.4/x86_64-linux-gnu/bits/gthr-default.h:
/usr/include/pthread.h:
/usr/include/sched.h:
/usr/include/bits/sched.h:
/usr/include/signal.h:
/usr/include/bits/setjmp.h:
/usr/include/unistd.h:
/usr/include/bits/posix_opt.h:
/usr/include/bits/environments.h:
/usr/include/bits/confname.h:
/usr/include/getopt.h:
/usr/include/c++/4.4/x86_64-linux-gnu/bits/atomic_word.h:
/usr/include/c++/4.4/initializer_list:
/usr/include/c++/4.4/bits/basic_string.tcc:
../../mednafen/video.h:
../../mednafen/video/surface.h:
/usr/include/c++/4.4/vector:
/usr/include/c++/4.4/bits/stl_construct.h:
/usr/include/c++/4.4/bits/stl_uninitialized.h:
/usr/include/c++/4.4/bits/stl_vector.h:
/usr/include/c++/4.4/bits/stl_bvector.h:
/usr/include/c++/4.4/bits/vector.tcc:
../../mednafen/video/primitives.h:
../../mednafen/video/text.h:
/usr/include/c++/4.4/algorithm:
/usr/include/c++/4.4/bits/stl_algo.h:
/usr/include/c++/4.4/cstdlib:
/usr/include/c++/4.4/bits/algorithmfwd.h:
/usr/include/c++/4.4/bits/stl_heap.h:
/usr/include/c++/4.4/bits/stl_tempbuf.h:
../../mednafen/sound.h:
../../mednafen/file.h:
../../mednafen/state.h:
/usr/include/zlib.h:
/usr/include/zconf.h:
/usr/include/zlibdefs.h:
../../mednafen/state-common.h:
../../mednafen/settings-common.h:
../../mednafen/debug.h:
../../mednafen/git-virtb.h:
../../mednafen/settings.h:
../../mednafen/mednafen-driver.h:
../../mednafen/endian.h:
../../mednafen/memory.h:
../../mednafen/masmem.h:
../../include/trio/trio.h:
../../include/trio/triop.h:
../../include/trio/triodef.h:
../cdrom/cdromif.h:
../cdrom/CDUtility.h:
/usr/include/c++/4.4/queue:
/usr/include/c++/4.4/deque:
/usr/include/c++/4.4/bits/stl_deque.h:
/usr/include/c++/4.4/bits/deque.tcc:
/usr/include/c++/4.4/bits/stl_queue.h:
../general.h:
../FileWrapper.h:
dis.h:
cpu.h:
gte.h:
irq.h:
gpu.h:
../cdrom/SimpleFIFO.h:
../cdrom/../math_ops.h:
dma.h:
debug.h:

View File

@ -4,7 +4,8 @@ DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/intl -I$(top_srcdir
noinst_LIBRARIES = libpsx.a
libpsx_a_SOURCES = psx.cpp irq.cpp timer.cpp dma.cpp frontio.cpp sio.cpp cpu.cpp gte.cpp dis.cpp cdc.cpp spu.cpp gpu.cpp mdec.cpp
libpsx_a_SOURCES += input/gamepad.cpp input/dualanalog.cpp input/memcard.cpp input/multitap.cpp input/mouse.cpp
libpsx_a_SOURCES += input/gamepad.cpp input/dualanalog.cpp input/dualshock.cpp input/memcard.cpp input/multitap.cpp input/mouse.cpp input/negcon.cpp input/guncon.cpp input/justifier.cpp
if WANT_DEBUGGER
libpsx_a_SOURCES += debug.cpp

View File

@ -78,15 +78,19 @@ libpsx_a_LIBADD =
am__libpsx_a_SOURCES_DIST = psx.cpp irq.cpp timer.cpp dma.cpp \
frontio.cpp sio.cpp cpu.cpp gte.cpp dis.cpp cdc.cpp spu.cpp \
gpu.cpp mdec.cpp input/gamepad.cpp input/dualanalog.cpp \
input/memcard.cpp input/multitap.cpp input/mouse.cpp debug.cpp
input/dualshock.cpp input/memcard.cpp input/multitap.cpp \
input/mouse.cpp input/negcon.cpp input/guncon.cpp \
input/justifier.cpp debug.cpp
am__dirstamp = $(am__leading_dot)dirstamp
@WANT_DEBUGGER_TRUE@am__objects_1 = debug.$(OBJEXT)
am_libpsx_a_OBJECTS = psx.$(OBJEXT) irq.$(OBJEXT) timer.$(OBJEXT) \
dma.$(OBJEXT) frontio.$(OBJEXT) sio.$(OBJEXT) cpu.$(OBJEXT) \
gte.$(OBJEXT) dis.$(OBJEXT) cdc.$(OBJEXT) spu.$(OBJEXT) \
gpu.$(OBJEXT) mdec.$(OBJEXT) input/gamepad.$(OBJEXT) \
input/dualanalog.$(OBJEXT) input/memcard.$(OBJEXT) \
input/multitap.$(OBJEXT) input/mouse.$(OBJEXT) \
input/dualanalog.$(OBJEXT) input/dualshock.$(OBJEXT) \
input/memcard.$(OBJEXT) input/multitap.$(OBJEXT) \
input/mouse.$(OBJEXT) input/negcon.$(OBJEXT) \
input/guncon.$(OBJEXT) input/justifier.$(OBJEXT) \
$(am__objects_1)
libpsx_a_OBJECTS = $(am_libpsx_a_OBJECTS)
depcomp = $(SHELL) $(top_srcdir)/depcomp
@ -325,8 +329,9 @@ noinst_LIBRARIES = libpsx.a
libpsx_a_SOURCES = psx.cpp irq.cpp timer.cpp dma.cpp frontio.cpp \
sio.cpp cpu.cpp gte.cpp dis.cpp cdc.cpp spu.cpp gpu.cpp \
mdec.cpp input/gamepad.cpp input/dualanalog.cpp \
input/memcard.cpp input/multitap.cpp input/mouse.cpp \
$(am__append_1)
input/dualshock.cpp input/memcard.cpp input/multitap.cpp \
input/mouse.cpp input/negcon.cpp input/guncon.cpp \
input/justifier.cpp $(am__append_1)
all: all-am
.SUFFIXES:
@ -374,12 +379,20 @@ input/gamepad.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/dualanalog.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/dualshock.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/memcard.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/multitap.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/mouse.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/negcon.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/guncon.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
input/justifier.$(OBJEXT): input/$(am__dirstamp) \
input/$(DEPDIR)/$(am__dirstamp)
libpsx.a: $(libpsx_a_OBJECTS) $(libpsx_a_DEPENDENCIES)
$(AM_V_at)-rm -f libpsx.a
$(AM_V_AR)$(libpsx_a_AR) libpsx.a $(libpsx_a_OBJECTS) $(libpsx_a_LIBADD)
@ -388,10 +401,14 @@ libpsx.a: $(libpsx_a_OBJECTS) $(libpsx_a_DEPENDENCIES)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
-rm -f input/dualanalog.$(OBJEXT)
-rm -f input/dualshock.$(OBJEXT)
-rm -f input/gamepad.$(OBJEXT)
-rm -f input/guncon.$(OBJEXT)
-rm -f input/justifier.$(OBJEXT)
-rm -f input/memcard.$(OBJEXT)
-rm -f input/mouse.$(OBJEXT)
-rm -f input/multitap.$(OBJEXT)
-rm -f input/negcon.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@ -411,10 +428,14 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spu.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/dualanalog.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/dualshock.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/gamepad.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/guncon.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/justifier.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/memcard.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/mouse.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/multitap.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/negcon.Po@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\

View File

@ -10,12 +10,19 @@ Tiny Toon Adventures - Plucky's Big Adventure is failing and BREAK'ing for some
Shadow Master has broken startup images.
Rayman (Europe) has somewhat broken FMV.
Crusaders of Might and Magic - The CD-XA buffering increase for ToD II is apparently exacerbating the early voice cutoff problem in this game.
Crash Team Racing - Noticed a game lockup once in the arcade mode stage select screen, having trouble reproducing it.
Misadventures of Trone Bonne - Voice problems, lockup, possibly due to excessively long seek delays?
Dance Dance Revolution - The music is...totally wonky.
Medal of Honor - Sound issues.
Fuuraiki - Hangs at black screen when trying to start a new game.
Test time delta between GPU LL DMA end and GPU non-busy status for various primitive types in sequence on a PS1.
Test IRQ and COP0 latencies; PSX IRQ controller latency, software IRQ bit latency, latency of both relevant COP0 IRQ enable bits.

View File

@ -81,11 +81,13 @@ void PS_CDC::SetDisc(bool tray_open, CDIF *cdif, const char *disc_id)
PendingCommandPhase = 0;
}
HeaderBufValid = false;
DriveStatus = DS_STOPPED;
ClearAIP();
}
else
{
HeaderBufValid = false;
DiscStartupDelay = (int64)1000 * 33868800 / 1000;
DiscChanged = true;
@ -168,6 +170,7 @@ void PS_CDC::SoftReset(void)
Mode = 0;
HeaderBufValid = false;
DriveStatus = DS_STOPPED;
ClearAIP();
StatusAfterSeek = DS_STOPPED;
@ -360,10 +363,8 @@ void PS_CDC::WriteResult(uint8 V)
ResultsWP = (ResultsWP + 1) & 0xF;
ResultsIn = (ResultsIn + 1) & 0x1F;
#if 0
if(!ResultsIn)
PSX_WARNING("[CDC] Results buffer overflow!");
#endif
}
uint8 PS_CDC::ReadResult(void)
@ -553,8 +554,8 @@ void PS_CDC::XA_ProcessSector(const uint8 *sdata, CD_Audio_Buffer *ab)
uint8 ibuffer[28];
int16 obuffer[2 + 28];
if(param != param_copy)
printf("%d %02x %02x\n", unit, param, param_copy);
//if(param != param_copy)
// printf("%d %02x %02x\n", unit, param, param_copy);
for(unsigned i = 0; i < 28; i++)
{
@ -624,12 +625,10 @@ void PS_CDC::CheckAIP(void)
void PS_CDC::SetAIP(unsigned irq, unsigned result_count, uint8 *r)
{
#if 0
if(AsyncIRQPending)
{
PSX_WARNING("***WARNING*** Previous notification skipped: CurSector=%d, old_notification=0x%02x", CurSector, AsyncIRQPending);
}
#endif
ClearAIP();
AsyncResultsPendingCount = result_count;
@ -681,7 +680,7 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
if(DiscStartupDelay <= 0)
{
DriveStatus = DS_PAUSED;
DriveStatus = DS_PAUSED; // or is it supposed to be DS_STANDBY?
}
}
@ -719,7 +718,7 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
CurSector = 0;
CommandLoc = 0;
DriveStatus = DS_PAUSED;
DriveStatus = DS_PAUSED; // or DS_STANDBY?
ClearAIP();
}
else if(DriveStatus == DS_SEEKING)
@ -730,7 +729,7 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
DriveStatus = StatusAfterSeek;
if(DriveStatus != DS_PAUSED)
if(DriveStatus != DS_PAUSED && DriveStatus != DS_STANDBY)
{
PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
}
@ -744,7 +743,7 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
DriveStatus = StatusAfterSeek;
if(DriveStatus != DS_PAUSED)
if(DriveStatus != DS_PAUSED && DriveStatus != DS_STANDBY)
{
PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
}
@ -770,13 +769,14 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
DecodeSubQ(buf + 2352);
memcpy(HeaderBuf, buf + 12, 12);
HeaderBufValid = true;
if((Mode & MODE_STRSND) && (buf[12 + 3] == 0x2) && (buf[12 + 6] & 0x20) && (buf[12 + 6] & 0x04))
{
if(XA_Test(buf))
{
if(AudioBuffer_ReadPos & 0xFFF)
printf("readpos=%04x(rabl=%04x) writepos=%04x\n", AudioBuffer_ReadPos, AudioBuffer[AudioBuffer_ReadPos >> 12].Size, AudioBuffer_WritePos);
//if(AudioBuffer_ReadPos & 0xFFF)
//printf("readpos=%04x(rabl=%04x) writepos=%04x\n", AudioBuffer_ReadPos, AudioBuffer[AudioBuffer_ReadPos >> 12].Size, AudioBuffer_WritePos);
//if(AudioBuffer_UsedCount == 0)
// AudioBuffer_InPrebuffer = true;
@ -801,10 +801,8 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
}
}
#if 0
if(!(Mode & 0x30) && (buf[12 + 6] & 0x20))
PSX_WARNING("BORK: %d", CurSector);
#endif
{
int32 offs = (Mode & 0x20) ? 0 : 12;
@ -831,6 +829,7 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
{
if(CurSector >= (int32)toc.tracks[100].lba)
{
HeaderBufValid = false;
DriveStatus = DS_STOPPED;
SetAIP(CDCIRQ_DISC_ERROR, MakeStatus() | 0x04, 0x04); // TODO: Verify
}
@ -930,10 +929,8 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
else
CurSector++;
}
#if 0
else
PSX_WARNING("[CDC] BUG CDDA buffer full");
#endif
}
} // end if playing
@ -1041,7 +1038,6 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
break;
case 0x00:
#if 0
if(PendingCommandCounter > 0)
{
PSX_WARNING("[CDC] WARNING: Interrupting command 0x%02x, phase=%d, timeleft=%d with command=0x%02x", PendingCommand, PendingCommandPhase,
@ -1057,7 +1053,6 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
{
PSX_WARNING("[CDC] Attempting to start command(0x%02x) while command results(count=%d) still in buffer.", V, ResultsIn);
}
#endif
PendingCommandCounter = 8192; //1024; //128; //256; //16; //1024;
PendingCommand = V;
@ -1068,12 +1063,10 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
ArgsBuf[ArgsIn & 0xF] = V;
ArgsIn = (ArgsIn + 1) & 0x1F;
#if 0
if(!(ArgsIn & 0x0F))
{
PSX_WARNING("[CDC] Argument buffer overflow");
}
#endif
break;
case 0x02:
@ -1096,12 +1089,10 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
SB_In = 0;
}
}
#if 0
else
{
//PSX_WARNING("[CDC] Attempt to start data transfer via 0x80->1803 when %d bytes still in buffer", DMABuffer.CanRead());
}
#endif
}
else if(V & 0x40) // Something CD-DA related(along with & 0x20 ???)?
{
@ -1162,7 +1153,6 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
{
memcpy(DecodeVolume, Pending_DecodeVolume, sizeof(DecodeVolume));
#if 0
for(int i = 0; i < 2; i++)
{
for(int o = 0; o < 2; o++)
@ -1170,7 +1160,6 @@ void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
//fprintf(stderr, "Input Channel %d, Output Channel %d -- Volume=%d\n", i, o, DecodeVolume[i][o]);
}
}
#endif
}
break;
}
@ -1212,12 +1201,10 @@ uint8 PS_CDC::Read(const pscpu_timestamp_t timestamp, uint32 A)
case 0x02:
if(DMABuffer.CanRead())
ret = DMABuffer.ReadByte();
#if 0
else
{
PSX_WARNING("[CDC] CD data transfer port read, but no data present!");
}
#endif
break;
case 0x03:
@ -1305,7 +1292,7 @@ int32 PS_CDC::Command_Setloc(const int arg_count, const uint8 *args)
return(0);
}
static int32 CalcSeekTime(int32 initial, int32 target, bool motor_on, bool paused)
int32 PS_CDC::CalcSeekTime(int32 initial, int32 target, bool motor_on, bool paused)
{
int32 ret = 0;
@ -1320,7 +1307,25 @@ static int32 CalcSeekTime(int32 initial, int32 target, bool motor_on, bool pause
if(abs(initial - target) >= 2250)
ret += (int64)33868800 * 300 / 1000;
else if(paused)
ret += (int64)33868800 * 150 / 1000;
{
// The delay to restart from a Pause state is...very....WEIRD. The time it takes is related to the amount of time that has passed since the pause, and
// where on the disc the laser head is, with generally more time passed = longer to resume, except that there's a window of time where it takes a
// ridiculous amount of time when not much time has passed.
//
// What we have here will be EXTREMELY simplified.
//
//
//if(time_passed >= 67737)
//{
//}
//else
{
// Take twice as long for 1x mode.
ret += 1247952 * ((Mode & MODE_SPEED) ? 1 : 2);
}
}
//printf("%d\n", ret);
@ -1386,9 +1391,10 @@ int32 PS_CDC::Command_Play(const int arg_count, const uint8 *args)
PlayTrackMatch = track;
//printf("[CDC] Play track: %d\n", track);
printf("[CDC] Play track: %d\n", track);
SeekTarget = toc.tracks[track].lba;
PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
HeaderBufValid = false;
PreSeekHack(SeekTarget);
DriveStatus = DS_SEEKING;
@ -1396,13 +1402,14 @@ int32 PS_CDC::Command_Play(const int arg_count, const uint8 *args)
}
else
{
if(CommandLoc_Dirty || (DriveStatus != DS_PLAYING && DriveStatus != DS_PAUSED))
if(CommandLoc_Dirty || (DriveStatus != DS_PLAYING && DriveStatus != DS_PAUSED && DriveStatus != DS_STANDBY))
{
ClearAudioBuffers();
SeekTarget = CommandLoc;
PlayTrackMatch = -1;
PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
HeaderBufValid = false;
PreSeekHack(SeekTarget);
DriveStatus = DS_SEEKING;
@ -1415,6 +1422,7 @@ int32 PS_CDC::Command_Play(const int arg_count, const uint8 *args)
PlayTrackMatch = -1;
PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
HeaderBufValid = false;
PreSeekHack(SeekTarget);
DriveStatus = DS_SEEKING;
@ -1484,6 +1492,7 @@ void PS_CDC::ReadBase(void)
SeekTarget = CommandLoc;
PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
HeaderBufValid = false;
PreSeekHack(SeekTarget);
DriveStatus = DS_SEEKING_LOGICAL;
@ -1503,14 +1512,6 @@ int32 PS_CDC::Command_ReadS(const int arg_count, const uint8 *args)
return 0;
}
#if 0
int32 PS_CDC::Command_Standby(const int arg_count, const uint8 *args)
{
return(0);
}
#endif
int32 PS_CDC::Command_Stop(const int arg_count, const uint8 *args)
{
if(!CommandCheckDiscPresent())
@ -1528,6 +1529,7 @@ int32 PS_CDC::Command_Stop(const int arg_count, const uint8 *args)
ClearAudioBuffers();
ClearAIP();
DriveStatus = DS_STOPPED;
HeaderBufValid = false;
return(33868); // FIXME, should be much higher.
}
@ -1543,8 +1545,39 @@ int32 PS_CDC::Command_Stop_Part2(void)
return(0);
}
int32 PS_CDC::Command_Standby(const int arg_count, const uint8 *args)
{
if(!CommandCheckDiscPresent())
return(0);
if(DriveStatus != DS_STOPPED)
{
WriteResult(MakeStatus(true));
WriteResult(0x20);
WriteIRQ(CDCIRQ_DISC_ERROR);
return(0);
}
WriteResult(MakeStatus());
WriteIRQ(CDCIRQ_ACKNOWLEDGE);
ClearAudioBuffers();
ClearAIP();
DriveStatus = DS_STANDBY;
return((int64)33868800 * 100 / 1000); // No idea, FIXME.
}
int32 PS_CDC::Command_Standby_Part2(void)
{
PSRCounter = 0;
WriteResult(MakeStatus());
WriteIRQ(CDCIRQ_COMPLETE);
return(0);
}
// TODO: Pause speed depends on speed(1x/2x) and current position. Also check restart(for ReadN/ReadS and Play) 'delay'.
int32 PS_CDC::Command_Pause(const int arg_count, const uint8 *args)
{
if(!CommandCheckDiscPresent())
@ -1564,7 +1597,8 @@ int32 PS_CDC::Command_Pause(const int arg_count, const uint8 *args)
ClearAIP();
DriveStatus = DS_PAUSED;
return((int64)33868800 * 100 / 1000);
// An approximation.
return((1124584 + ((int64)CurSector * 42596 / (75 * 60))) * ((Mode & MODE_SPEED) ? 1 : 2));
}
}
@ -1585,6 +1619,7 @@ int32 PS_CDC::Command_Reset(const int arg_count, const uint8 *args)
if(DriveStatus != DS_RESETTING)
{
HeaderBufValid = false;
DriveStatus = DS_RESETTING;
PSRCounter = 1136000;
}
@ -1655,7 +1690,7 @@ int32 PS_CDC::Command_GetlocL(const int arg_count, const uint8 *args)
if(!CommandCheckDiscPresent())
return(0);
if(DriveStatus != DS_READING)
if(!HeaderBufValid)
{
WriteResult(MakeStatus(true));
WriteResult(0x80);
@ -1767,10 +1802,11 @@ int32 PS_CDC::Command_SeekL(const int arg_count, const uint8 *args)
SeekTarget = CommandLoc;
PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, false); //DriveStatus == DS_PAUSED);
PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
HeaderBufValid = false;
PreSeekHack(SeekTarget);
DriveStatus = DS_SEEKING_LOGICAL;
StatusAfterSeek = DS_PAUSED;
StatusAfterSeek = DS_STANDBY;
ClearAIP();
return(PSRCounter);
@ -1786,10 +1822,11 @@ int32 PS_CDC::Command_SeekP(const int arg_count, const uint8 *args)
SeekTarget = CommandLoc;
PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, false); //DriveStatus == DS_PAUSED);
PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
HeaderBufValid = false;
PreSeekHack(SeekTarget);
DriveStatus = DS_SEEKING;
StatusAfterSeek = DS_PAUSED;
StatusAfterSeek = DS_STANDBY;
ClearAIP();
return(PSRCounter);
@ -1797,7 +1834,7 @@ int32 PS_CDC::Command_SeekP(const int arg_count, const uint8 *args)
int32 PS_CDC::Command_Seek_PartN(void)
{
if(DriveStatus == DS_PAUSED)
if(DriveStatus == DS_STANDBY)
{
BeginResults();
WriteResult(MakeStatus());
@ -1946,8 +1983,9 @@ int32 PS_CDC::Command_ID(const int arg_count, const uint8 *args)
WriteResult(MakeStatus());
WriteIRQ(CDCIRQ_ACKNOWLEDGE);
HeaderBufValid = false;
PSRCounter = 0;
DriveStatus = DS_PAUSED;
DriveStatus = DS_PAUSED; // or DS_STANDBY?
ClearAIP();
return(33868);
@ -2002,6 +2040,7 @@ int32 PS_CDC::Command_ReadTOC(const int arg_count, const uint8 *args)
//if(!CommandCheckDiscPresent())
// return(0);
HeaderBufValid = false;
WriteResult(MakeStatus());
WriteIRQ(CDCIRQ_ACKNOWLEDGE);
@ -2010,7 +2049,7 @@ int32 PS_CDC::Command_ReadTOC(const int arg_count, const uint8 *args)
int32 PS_CDC::Command_ReadTOC_Part2(void)
{
DriveStatus = DS_PAUSED;
DriveStatus = DS_PAUSED; // or DS_STANDBY?
ClearAIP();
WriteResult(MakeStatus());
@ -2035,7 +2074,7 @@ PS_CDC::CDC_CTEntry PS_CDC::Commands[0x20] =
{ /* 0x04, */ 0, 0, "Forward", &PS_CDC::Command_Forward, NULL },
{ /* 0x05, */ 0, 0, "Backward", &PS_CDC::Command_Backward, NULL },
{ /* 0x06, */ 0, 0, "ReadN", &PS_CDC::Command_ReadN, NULL },
{ /* 0x07, */ 0, 0, "Standby", &PS_CDC::Command_Pause, &PS_CDC::Command_Pause_Part2 },
{ /* 0x07, */ 0, 0, "Standby", &PS_CDC::Command_Standby, &PS_CDC::Command_Standby_Part2 },
{ /* 0x08, */ 0, 0, "Stop", &PS_CDC::Command_Stop, &PS_CDC::Command_Stop_Part2 },
{ /* 0x09, */ 0, 0, "Pause", &PS_CDC::Command_Pause, &PS_CDC::Command_Pause_Part2 },
{ /* 0x0A, */ 0, 0, "Reset", &PS_CDC::Command_Reset, NULL },

View File

@ -132,6 +132,7 @@ class PS_CDC
uint8 SubQBuf_Safe[0xC];
bool SubQChecksumOK;
bool HeaderBufValid;
uint8 HeaderBuf[12];
void RecalcIRQ(void);
@ -189,6 +190,7 @@ class PS_CDC
enum
{
DS_STANDBY = -2,
DS_PAUSED = -1,
DS_STOPPED = 0,
DS_SEEKING,
@ -214,6 +216,8 @@ class PS_CDC
uint8 AsyncResultsPending[16];
uint8 AsyncResultsPendingCount;
int32 CalcSeekTime(int32 initial, int32 target, bool motor_on, bool paused);
void ClearAIP(void);
void CheckAIP(void);
void SetAIP(unsigned irq, unsigned result_count, uint8 *r);
@ -265,6 +269,7 @@ class PS_CDC
int32 Command_Backward(const int arg_count, const uint8 *args);
int32 Command_ReadN(const int arg_count, const uint8 *args);
int32 Command_Standby(const int arg_count, const uint8 *args);
int32 Command_Standby_Part2(void);
int32 Command_Stop(const int arg_count, const uint8 *args);
int32 Command_Stop_Part2(void);
int32 Command_Pause(const int arg_count, const uint8 *args);

View File

@ -123,8 +123,6 @@ int PS_CPU::StateAction(StateMem *sm, int load, int data_only)
SFVAR(next_event_ts),
SFVAR(gte_ts_done),
SFVAR(Running), // Important for save states in step mode in the debugger.
SFARRAY32(CP0.Regs, 32),
SFEND
@ -141,12 +139,6 @@ int PS_CPU::StateAction(StateMem *sm, int load, int data_only)
return(ret);
}
void PS_CPU::Exit(void)
{
Running = false;
}
void PS_CPU::AssertIRQ(int which, bool asserted)
{
assert(which >= 0 && which <= 5);
@ -272,9 +264,7 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in)
BACKING_TO_ACTIVE;
Running = true;
while(Running)
do
{
//printf("Running: %d %d\n", timestamp, next_event_ts);
while(timestamp < next_event_ts)
@ -303,6 +293,11 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in)
//if(GPR[4] == 'L')
// DBG_Break();
fputc(GPR[4], stderr);
//if(GPR[4] == '\n')
//{
// fputc('%', stderr);
// fputc(' ', stderr);
//}
}
}
}
@ -340,11 +335,14 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in)
{ \
uint32 old_PC = PC; \
PC = (PC & new_PC_mask) + new_PC; \
if(old_PC == ((PC & (mask)) + (offset))) \
if(old_PC == ((PC & (mask)) + (offset))) \
{ \
if(*(uint32 *)&FastMap[PC >> FAST_MAP_SHIFT][PC] == 0) \
{ \
timestamp = next_event_ts; \
if(next_event_ts > timestamp) /* Necessary since next_event_ts might be set to something like "0" to force a call to the event handler. */ \
{ \
timestamp = next_event_ts; \
} \
} \
} \
} \
@ -640,12 +638,10 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in)
uint32 rd = (instr >> 11) & 0x1F;
uint32 val = GPR[rt];
#if 0
if(rd != CP0REG_CAUSE && rd != CP0REG_SR && val)
{
PSX_WARNING("[CPU] Unimplemented MTC0: rt=%d(%08x) -> rd=%d", rt, GPR[rt], rd);
}
#endif
switch(rd)
{
@ -1647,9 +1643,7 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in)
//printf("\n");
}
next_event_ts = PSX_EventHandler(timestamp);
}
} while(PSX_EventHandler(timestamp));
if(gte_ts_done > 0)
gte_ts_done -= timestamp;
@ -1768,7 +1762,6 @@ void PS_CPU::SetRegister(unsigned int which, uint32 value)
#define BEGIN_OPF(op, funct) case MK_OPF(op, funct): {
#define END_OPF } break;
// FIXME: should we breakpoint on an illegal address? And with LWC2/SWC2 if CP2 isn't enabled?
void PS_CPU::CheckBreakpoints(void (*callback)(bool write, uint32 address, unsigned int len), uint32 instr)
{

View File

@ -25,15 +25,8 @@ class PS_CPU
next_event_ts = next_event_ts_arg;
}
INLINE pscpu_timestamp_t GetEventNT(void)
{
return(next_event_ts);
}
pscpu_timestamp_t Run(pscpu_timestamp_t timestamp_in, bool ILHMode);
void Exit(void);
void Power(void);
// which ranges 0-5, inclusive
@ -67,7 +60,6 @@ class PS_CPU
pscpu_timestamp_t next_event_ts;
pscpu_timestamp_t gte_ts_done;
bool Running;
uint8 *FastMap[1 << (32 - FAST_MAP_SHIFT)];
uint8 DummyPage[FAST_MAP_PSIZE];

View File

@ -26,33 +26,6 @@ namespace MDFN_IEN_PSX
extern PS_GPU *GPU;
extern PS_SPU *SPU;
//
//
//
void DBG_GPUScanlineHook(unsigned scanline)
{
}
//
//
//
static void (*CPUHook)(uint32) = NULL;
static void (*BPCallB)(uint32 PC) = NULL;
@ -350,6 +323,60 @@ static void Disassemble(uint32 &A, uint32 SpecialA, char *TextBuf)
A += 4;
}
static MDFN_Surface *GfxDecode_Buf = NULL;
static int GfxDecode_Line = -1;
static int GfxDecode_Layer = 0;
static int GfxDecode_Scroll = 0;
static int GfxDecode_PBN = 0;
static void DoGfxDecode(void)
{
unsigned tp_w, tp_h;
tp_w = 256;
tp_h = 256;
if(GfxDecode_Buf)
{
for(int sy = 0; sy < GfxDecode_Buf->h; sy++)
{
for(int sx = 0; sx < GfxDecode_Buf->w; sx++)
{
unsigned fb_x = ((sx % GfxDecode_Buf->w) + ((sy + GfxDecode_Scroll) / GfxDecode_Buf->w * GfxDecode_Buf->w)) & 1023;
unsigned fb_y = (((sy + GfxDecode_Scroll) % GfxDecode_Buf->w) + ((((sx % GfxDecode_Buf->w) + ((sy + GfxDecode_Scroll) / GfxDecode_Buf->w * GfxDecode_Buf->w)) / 1024) * 256)) & 511;
uint16 pixel = GPU->PeekRAM(fb_y * 1024 + fb_x);
GfxDecode_Buf->pixels[(sy * GfxDecode_Buf->w * 3) + sx] = GfxDecode_Buf->MakeColor(((pixel >> 0) & 0x1F) * 255 / 31,
((pixel >> 5) & 0x1F) * 255 / 31,
((pixel >> 10) & 0x1F) * 255 / 31, 0xFF);
}
}
}
}
void DBG_GPUScanlineHook(unsigned scanline)
{
if((int)scanline == GfxDecode_Line)
{
DoGfxDecode();
}
}
static void SetGraphicsDecode(MDFN_Surface *surface, int line, int which, int xscroll, int yscroll, int pbn)
{
GfxDecode_Buf = surface;
GfxDecode_Line = line;
GfxDecode_Layer = which;
GfxDecode_Scroll = yscroll;
GfxDecode_PBN = pbn;
if(GfxDecode_Buf && GfxDecode_Line == -1)
DoGfxDecode();
}
DebuggerInfoStruct PSX_DBGInfo =
{
"shift_jis",
@ -358,7 +385,7 @@ DebuggerInfoStruct PSX_DBGInfo =
32, // Logical address bits
32, // Physical address bits
0x00000000, // Default watch addr
~0, // ZP addr
~0U, // ZP addr
MemPeek,
Disassemble,
@ -370,7 +397,7 @@ DebuggerInfoStruct PSX_DBGInfo =
SetCPUCallback,
SetBPCallback,
GetBranchTrace,
NULL, //KING_SetGraphicsDecode,
SetGraphicsDecode,
NULL, //PCFXDBG_SetLogFunc,
};
@ -639,3 +666,4 @@ bool DBG_Init(void)
}

View File

@ -136,10 +136,10 @@ static void RecalcHalt(void)
if((DMACH[0].WordCounter || (DMACH[0].ChanControl & (1 << 24))) && (DMACH[0].ChanControl & 0x200) /*&& MDEC_DMACanWrite()*/)
Halt = true;
if((DMACH[1].WordCounter || (DMACH[1].ChanControl & (1 << 24))) && (DMACH[1].ChanControl & 0x200) && MDEC_DMACanRead())
if((DMACH[1].WordCounter || (DMACH[1].ChanControl & (1 << 24))) && (DMACH[1].ChanControl & 0x200) && (DMACH[1].WordCounter || MDEC_DMACanRead()))
Halt = true;
if((DMACH[2].WordCounter || (DMACH[2].ChanControl & (1 << 24))) && (DMACH[2].ChanControl & 0x200) && ((DMACH[2].ChanControl & 0x1) && GPU->DMACanWrite()))
if((DMACH[2].WordCounter || (DMACH[2].ChanControl & (1 << 24))) && (DMACH[2].ChanControl & 0x200) && ((DMACH[2].ChanControl & 0x1) && (DMACH[2].WordCounter || GPU->DMACanWrite())))
Halt = true;
if((DMACH[3].WordCounter || (DMACH[3].ChanControl & (1 << 24))) && !(DMACH[3].ChanControl & 0x100))
@ -278,6 +278,8 @@ static INLINE void RunChannelT(pscpu_timestamp_t timestamp, int32 clocks)
if(DMACH[ch].NextAddr & 0x800000)
{
//if(ch == 2)
// PSX_WARNING("[DMA] LL Channel 2 ended normally: %d\n", GPU->GetScanlineNum());
DMACH[ch].ChanControl &= ~(0x11 << 24);
if(DMAIntControl & (1 << (16 + ch)))
{
@ -287,15 +289,12 @@ static INLINE void RunChannelT(pscpu_timestamp_t timestamp, int32 clocks)
break;
}
if(!ChCan<ch, write_mode>())
break;
if((DMACH[ch].ChanControl & (1 << 10)) && write_mode)
{
uint32 header;
uint32 null_bull = 0;
if(!ChCan<ch, write_mode>())
break;
ChRW<ch, write_mode>(timestamp, &null_bull);
DMACH[ch].CurAddr = DMACH[ch].NextAddr & 0x1FFFFC;
header = MainRAM.ReadU32(DMACH[ch].CurAddr);
@ -304,6 +303,9 @@ static INLINE void RunChannelT(pscpu_timestamp_t timestamp, int32 clocks)
DMACH[ch].WordCounter = header >> 24;
DMACH[ch].NextAddr = header & 0xFFFFFF;
if(DMACH[ch].WordCounter > 0x10)
printf("What the lala? 0x%02x @ 0x%08x\n", DMACH[ch].WordCounter, DMACH[ch].CurAddr - 4);
if(DMACH[ch].WordCounter)
DMACH[ch].ClockCounter -= 15;
else
@ -324,8 +326,12 @@ static INLINE void RunChannelT(pscpu_timestamp_t timestamp, int32 clocks)
}
}
if(!ChCan<ch, write_mode>())
break;
if(ch != 2 && ch != 1)
{
if(!ChCan<ch, write_mode>())
break;
}
{
uint32 vtmp;
@ -487,17 +493,23 @@ void DMA_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V)
if((DMACH[ch].ChanControl & (1 << 24)) && !(V & (1 << 24)))
{
DMACH[ch].ChanControl &= ~(1 << 24); // Clear bit before RunChannel(), so it will only finish the block it's on at most.
RunChannel(timestamp, 128, ch);
RunChannel(timestamp, 128 * 16, ch);
DMACH[ch].BlockCounter = 0;
DMACH[ch].WordCounter = 0;
#if 0 // TODO(maybe, need to work out worst-case performance for abnormally/brokenly large block sizes)
DMACH[ch].ClockCounter = (1 << 30);
RunChannel(timestamp, 1, ch);
DMACH[ch].ClockCounter = 0;
#endif
if(ch == 2)
{
GPU->Write(timestamp, 0x04, 0x01 << 24);
GPU->AbortDMA();
}
PSX_WARNING("[DMA] Forced stop for channel %d -- scanline=%d", ch, GPU->GetScanlineNum());
MDFN_DispMessage("[DMA] Forced stop for channel %d", ch);
//MDFN_DispMessage("[DMA] Forced stop for channel %d", ch);
}
if(ch == 6)
@ -507,6 +519,8 @@ void DMA_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V)
if(!(OldCC & (1 << 24)) && (V & (1 << 24)))
{
//if(ch == 2)
//if(ch == 4)
//PSX_WARNING("[DMA] Started DMA for channel=%d --- CHCR=0x%08x --- BCR=0x%08x --- scanline=%d", ch, DMACH[ch].ChanControl, DMACH[ch].BlockControl, GPU->GetScanlineNum());
DMACH[ch].ClockCounter = 0;

View File

@ -21,7 +21,12 @@
#include "input/gamepad.h"
#include "input/dualanalog.h"
#include "input/dualshock.h"
#include "input/mouse.h"
#include "input/negcon.h"
#include "input/guncon.h"
#include "input/justifier.h"
#include "input/memcard.h"
#include "input/multitap.h"
@ -53,6 +58,26 @@ void InputDevice::ResetTS(void)
}
void InputDevice::SetAMCT(bool)
{
}
void InputDevice::SetCrosshairsColor(uint32 color)
{
}
bool InputDevice::RequireNoFrameskip(void)
{
return(false);
}
pscpu_timestamp_t InputDevice::GPULineHook(const pscpu_timestamp_t timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock)
{
return(PSX_EVENT_MAXTS);
}
void InputDevice::UpdateInput(const void *data)
{
@ -158,11 +183,13 @@ FrontIO::FrontIO(bool emulate_memcards_[8], bool emulate_multitap_[2])
DummyDevice = new InputDevice();
for(int i = 0; i < 8; i++)
for(unsigned i = 0; i < 8; i++)
{
DeviceData[i] = NULL;
Devices[i] = new InputDevice();
DevicesMC[i] = Device_Memcard_Create();
chair_colors[i] = 1 << 24;
Devices[i]->SetCrosshairsColor(chair_colors[i]);
}
for(unsigned i = 0; i < 2; i++)
@ -173,6 +200,23 @@ FrontIO::FrontIO(bool emulate_memcards_[8], bool emulate_multitap_[2])
MapDevicesToPorts();
}
void FrontIO::SetAMCT(bool enabled)
{
for(unsigned i = 0; i < 8; i++)
{
Devices[i]->SetAMCT(enabled);
}
amct_enabled = enabled;
}
void FrontIO::SetCrosshairsColor(unsigned port, uint32 color)
{
assert(port >= 0 && port < 8);
chair_colors[port] = color;
Devices[port]->SetCrosshairsColor(color);
}
FrontIO::~FrontIO()
{
for(int i = 0; i < 8; i++)
@ -205,8 +249,10 @@ FrontIO::~FrontIO()
}
}
int32 FrontIO::CalcNextEvent(int32 next_event)
pscpu_timestamp_t FrontIO::CalcNextEventTS(pscpu_timestamp_t timestamp, int32 next_event)
{
pscpu_timestamp_t ret;
if(ClockDivider > 0 && ClockDivider < next_event)
next_event = ClockDivider;
@ -214,7 +260,15 @@ int32 FrontIO::CalcNextEvent(int32 next_event)
if(dsr_pulse_delay[i] > 0 && next_event > dsr_pulse_delay[i])
next_event = dsr_pulse_delay[i];
return(next_event);
ret = timestamp + next_event;
if(irq10_pulse_ts[0] < ret)
ret = irq10_pulse_ts[0];
if(irq10_pulse_ts[1] < ret)
ret = irq10_pulse_ts[1];
return(ret);
}
void FrontIO::CheckStartStopPending(pscpu_timestamp_t timestamp, bool skip_event_set)
@ -256,7 +310,7 @@ void FrontIO::CheckStartStopPending(pscpu_timestamp_t timestamp, bool skip_event
ClockDivider = 0;
if(!(skip_event_set))
PSX_SetEventNT(PSX_EVENT_FIO, timestamp + CalcNextEvent(0x10000000));
PSX_SetEventNT(PSX_EVENT_FIO, CalcNextEventTS(timestamp, 0x10000000));
}
// DSR IRQ bit setting appears(from indirect tests on real PS1) to be level-sensitive, not edge-sensitive
@ -295,6 +349,7 @@ void FrontIO::Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V)
if(ClockDivider > 0 && ((V & 0x2000) != (Control & 0x2000)) && ((Control & 0x2) == (V & 0x2)) )
fprintf(stderr, "FIO device selection changed during comm %04x->%04x", Control, V);
//printf("Control: %d, %04x\n", timestamp, V);
Control = V & 0x3F2F;
if(V & 0x10)
@ -439,6 +494,16 @@ pscpu_timestamp_t FrontIO::Update(pscpu_timestamp_t timestamp)
}
}
for(int i = 0; i < 2; i++)
{
if(timestamp >= irq10_pulse_ts[i])
{
//printf("Yay: %d %u\n", i, timestamp);
irq10_pulse_ts[i] = PSX_EVENT_MAXTS;
IRQ_Assert(IRQ_PIO, true);
IRQ_Assert(IRQ_PIO, false);
}
}
if(ClockDivider > 0)
{
@ -510,7 +575,7 @@ pscpu_timestamp_t FrontIO::Update(pscpu_timestamp_t timestamp)
CheckStartStopPending(timestamp, true);
}
return(timestamp + CalcNextEvent(0x10000000));
return(CalcNextEventTS(timestamp, 0x10000000));
}
void FrontIO::ResetTS(void)
@ -530,6 +595,12 @@ void FrontIO::ResetTS(void)
DevicesTap[i]->ResetTS();
}
for(int i = 0; i < 2; i++)
{
if(irq10_pulse_ts[i] != PSX_EVENT_MAXTS)
irq10_pulse_ts[i] -= lastts;
}
for(int i = 0; i < 4; i++)
{
if(dsr_active_until_ts[i] >= 0)
@ -550,6 +621,11 @@ void FrontIO::Power(void)
dsr_active_until_ts[i] = -1;
}
for(int i = 0; i < 2; i++)
{
irq10_pulse_ts[i] = PSX_EVENT_MAXTS;
}
lastts = 0;
//
@ -595,17 +671,34 @@ void FrontIO::SetInput(unsigned int port, const char *type, void *ptr)
delete Devices[port];
Devices[port] = NULL;
if(port < 2)
irq10_pulse_ts[port] = PSX_EVENT_MAXTS;
if(!strcmp(type, "gamepad"))
Devices[port] = Device_Gamepad_Create();
else if(!strcmp(type, "dualanalog"))
Devices[port] = Device_DualAnalog_Create(false);
else if(!strcmp(type, "analogjoy"))
Devices[port] = Device_DualAnalog_Create(true);
else if(!strcmp(type, "dualshock"))
{
char name[256];
trio_snprintf(name, 256, _("DualShock on port %u"), port + 1);
Devices[port] = Device_DualShock_Create(std::string(name));
}
else if(!strcmp(type, "mouse"))
Devices[port] = Device_Mouse_Create();
else if(!strcmp(type, "negcon"))
Devices[port] = Device_neGcon_Create();
else if(!strcmp(type, "guncon"))
Devices[port] = Device_GunCon_Create();
else if(!strcmp(type, "justifier"))
Devices[port] = Device_Justifier_Create();
else
Devices[port] = new InputDevice();
Devices[port]->SetAMCT(amct_enabled);
Devices[port]->SetCrosshairsColor(chair_colors[port]);
DeviceData[port] = ptr;
MapDevicesToPorts();
@ -667,7 +760,38 @@ void FrontIO::SaveMemcard(unsigned int which, const char *path)
}
}
bool FrontIO::RequireNoFrameskip(void)
{
for(unsigned i = 0; i < 8; i++)
if(Devices[i]->RequireNoFrameskip())
return(true);
return(false);
}
void FrontIO::GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock)
{
Update(timestamp);
for(unsigned i = 0; i < 8; i++)
{
pscpu_timestamp_t plts = Devices[i]->GPULineHook(line_timestamp, vsync, pixels, format, width, pix_clock_offset, pix_clock);
if(i < 2)
{
irq10_pulse_ts[i] = plts;
if(irq10_pulse_ts[i] <= timestamp)
{
irq10_pulse_ts[i] = PSX_EVENT_MAXTS;
IRQ_Assert(IRQ_PIO, true);
IRQ_Assert(IRQ_PIO, false);
}
}
}
PSX_SetEventNT(PSX_EVENT_FIO, CalcNextEventTS(timestamp, 0x10000000));
}
static InputDeviceInfoStruct InputDeviceInfoPSXPort[] =
{
@ -676,6 +800,7 @@ static InputDeviceInfoStruct InputDeviceInfoPSXPort[] =
"none",
"none",
NULL,
NULL,
0,
NULL
},
@ -684,15 +809,27 @@ static InputDeviceInfoStruct InputDeviceInfoPSXPort[] =
{
"gamepad",
"Digital Gamepad",
"PlayStation digital gamepad; SCPH-1080.",
NULL,
sizeof(Device_Gamepad_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_Gamepad_IDII,
},
// Dual Shock Gamepad(SCPH-1200)
{
"dualshock",
"DualShock",
"DualShock gamepad; SCPH-1200. Emulation in Mednafen includes the analog mode toggle button.",
NULL,
sizeof(Device_DualShock_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_DualShock_IDII,
},
// Dual Analog Gamepad(SCPH-1180), forced to analog mode.
{
"dualanalog",
"Dual Analog",
"Dual Analog gamepad; SCPH-1180. It is the predecessor/prototype to the more advanced DualShock. Emulated in Mednafen as forced to analog mode, and without rumble.",
NULL,
sizeof(Device_DualAnalog_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_DualAnalog_IDII,
@ -703,6 +840,7 @@ static InputDeviceInfoStruct InputDeviceInfoPSXPort[] =
{
"analogjoy",
"Analog Joystick",
"Flight-game-oriented dual-joystick controller; SCPH-1110. Emulated in Mednafen as forced to analog mode.",
NULL,
sizeof(Device_AnalogJoy_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_AnalogJoy_IDII,
@ -712,22 +850,50 @@ static InputDeviceInfoStruct InputDeviceInfoPSXPort[] =
"mouse",
"Mouse",
NULL,
NULL,
sizeof(Device_Mouse_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_Mouse_IDII,
},
{
"negcon",
"neGcon",
"Namco's unconventional twisty racing-game-oriented gamepad; NPC-101.",
NULL,
sizeof(Device_neGcon_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_neGcon_IDII,
},
{
"guncon",
"GunCon",
"Namco's light gun; NPC-103.",
NULL,
sizeof(Device_GunCon_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_GunCon_IDII,
},
{
"justifier",
"Konami Justifier",
"Konami's light gun; SLUH-00017. Rumored to be wrought of the coagulated rage of all who tried to shoot The Dog. If the game you want to play supports the \"GunCon\", you should use that instead. NOTE: Currently does not work properly when on any of ports 1B-1D and 2B-2D.",
NULL,
sizeof(Device_Justifier_IDII) / sizeof(InputDeviceInputInfoStruct),
Device_Justifier_IDII,
},
};
static const InputPortInfoStruct PortInfo[] =
{
{ 0, "port1", "Port 1/1A", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ 0, "port2", "Port 2/2A", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ 0, "port3", "Port 1B", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ 0, "port4", "Port 1C", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ 0, "port5", "Port 1D", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ 0, "port6", "Port 2B", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ 0, "port7", "Port 2C", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ 0, "port8", "Port 2D", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port1", "Port 1/1A", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port2", "Port 2/2A", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port3", "Port 1B", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port4", "Port 1C", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port5", "Port 1D", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port6", "Port 2B", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port7", "Port 2C", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
{ "port8", "Port 2D", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
};
InputInfoStruct FIO_InputInfo =

View File

@ -16,13 +16,23 @@ class InputDevice
virtual void Power(void);
virtual void UpdateInput(const void *data);
virtual void Update(const pscpu_timestamp_t timestamp);
virtual bool RequireNoFrameskip(void);
virtual pscpu_timestamp_t GPULineHook(const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock);
virtual void Update(const pscpu_timestamp_t timestamp); // Partially-implemented, don't rely on for timing any more fine-grained than a video frame for now.
virtual void ResetTS(void);
//
//
//
virtual void SetAMCT(bool enabled);
virtual void SetCrosshairsColor(uint32 color);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool GetDSR(void);
virtual bool GetDSR(void); // Currently unused.
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
@ -50,12 +60,17 @@ class FrontIO
void Power(void);
void Write(pscpu_timestamp_t timestamp, uint32 A, uint32 V);
uint32 Read(pscpu_timestamp_t timestamp, uint32 A);
int32 CalcNextEvent(int32 next_event);
pscpu_timestamp_t CalcNextEventTS(pscpu_timestamp_t timestamp, int32 next_event);
pscpu_timestamp_t Update(pscpu_timestamp_t timestamp);
void ResetTS(void);
bool RequireNoFrameskip(void);
void GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock);
void UpdateInput(void);
void SetInput(unsigned int port, const char *type, void *ptr);
void SetAMCT(bool enabled);
void SetCrosshairsColor(unsigned port, uint32 color);
uint64 GetMemcardDirtyCount(unsigned int which);
void LoadMemcard(unsigned int which, const char *path);
@ -110,9 +125,15 @@ class FrontIO
bool istatus;
//
//
pscpu_timestamp_t irq10_pulse_ts[2];
int32 dsr_pulse_delay[4];
int32 dsr_active_until_ts[4];
int32 lastts;
//
//
bool amct_enabled;
uint32 chair_colors[8];
};
extern InputInfoStruct FIO_InputInfo;

View File

@ -88,7 +88,7 @@ static const int32 dither_table[4][4] =
{ 3, -1, 2, -2 },
};
PS_GPU::PS_GPU(bool pal_clock_and_tv) : BlitterFIFO(0x10)
PS_GPU::PS_GPU(bool pal_clock_and_tv) : BlitterFIFO(0x20) // 0x10 on actual PS1 GPU, 0x20 here(see comment at top of gpu.h) // 0x10)
{
HardwarePALType = pal_clock_and_tv;
@ -135,12 +135,11 @@ void PS_GPU::SoftReset(void) // Control command 0x00
{
DMAControl = 0;
BlitterFIFO.Flush();
if(DrawTimeAvail < 0)
DrawTimeAvail = 0;
ParsingLineOrPolygonCommand = false;
InPLine = false;
InFBRead = false;
InFBWrite = false;
BlitterFIFO.Flush();
InCmd = INCMD_NONE;
DisplayMode = 0;
DisplayOff = 1;
@ -190,11 +189,7 @@ void PS_GPU::Power(void)
BlitterFIFO.Flush();
ParsingLineOrPolygonCommand = false;
InPLine = false;
InFBRead = false;
InFBWrite = false;
InCmd = INCMD_NONE;
FBRW_X = 0;
FBRW_Y = 0;
FBRW_W = 0;
@ -402,6 +397,7 @@ void PS_GPU::Command_FBFill(const uint32 *cb)
int32 height = (cb[2] >> 16) & 0x1FF;
//printf("[GPU] FB Fill %d:%d w=%d, h=%d\n", destX, destY, width, height);
DrawTimeAvail -= 46; // Approximate
DrawTimeAvail -= ((width * height) >> 3) + (height * 9);
for(int32 y = 0; y < height; y++)
@ -459,7 +455,7 @@ void PS_GPU::Command_FBCopy(const uint32 *cb)
void PS_GPU::Command_FBWrite(const uint32 *cb)
{
assert(!InFBRead);
assert(InCmd == INCMD_NONE);
FBRW_X = (cb[1] >> 0) & 0x3FF;
FBRW_Y = (cb[1] >> 16) & 0x3FF;
@ -476,15 +472,13 @@ void PS_GPU::Command_FBWrite(const uint32 *cb)
FBRW_CurX = FBRW_X;
FBRW_CurY = FBRW_Y;
InFBWrite = true;
if(FBRW_W == 0 || FBRW_H == 0)
InFBWrite = false;
if(FBRW_W != 0 && FBRW_H != 0)
InCmd = INCMD_FBWRITE;
}
void PS_GPU::Command_FBRead(const uint32 *cb)
{
assert(!InFBWrite);
assert(InCmd == INCMD_NONE);
FBRW_X = (cb[1] >> 0) & 0x3FF;
FBRW_Y = (cb[1] >> 16) & 0x3FF;
@ -501,10 +495,8 @@ void PS_GPU::Command_FBRead(const uint32 *cb)
FBRW_CurX = FBRW_X;
FBRW_CurY = FBRW_Y;
InFBRead = true;
if(FBRW_W == 0 || FBRW_H == 0)
InFBRead = false;
if(FBRW_W != 0 && FBRW_H != 0)
InCmd = INCMD_FBREAD;
}
@ -622,70 +614,109 @@ CTEntry PS_GPU::Commands[4][256] =
static uint64 PrimitiveCounter[256] = { 0 }; // Debug
void PS_GPU::ProcessFIFO(bool force)
void PS_GPU::ProcessFIFO(void)
{
if(!BlitterFIFO.CanRead())
return;
if(DrawTimeAvail < 0 && !force)
return;
if(InFBWrite)
switch(InCmd)
{
uint32 InData = BlitterFIFO.ReadUnit();
default:
abort();
break;
for(int i = 0; i < 2; i++)
{
if(!(GPURAM[FBRW_CurY & 511][FBRW_CurX & 1023] & MaskEvalAND))
GPURAM[FBRW_CurY & 511][FBRW_CurX & 1023] = InData | MaskSetOR;
case INCMD_NONE:
break;
FBRW_CurX++;
if(FBRW_CurX == (FBRW_X + FBRW_W))
{
FBRW_CurX = FBRW_X;
FBRW_CurY++;
if(FBRW_CurY == (FBRW_Y + FBRW_H))
{
InFBWrite = false;
break;
}
}
InData >>= 16;
}
return;
}
case INCMD_FBREAD:
puts("BOGUS SALAMANDERS, CAPTAIN!");
return;
if(InPLine)
{
const uint32 cc = InPLine;
const CTEntry *command = &Commands[abr][cc];
unsigned vl = 1 + (bool)(InPLine & 0x10);
uint32 CB[2];
case INCMD_FBWRITE:
{
uint32 InData = BlitterFIFO.ReadUnit();
if((BlitterFIFO.ReadUnit(true) & 0xF000F000) == 0x50005000)
{
BlitterFIFO.ReadUnit();
InPLine = false;
ParsingLineOrPolygonCommand = false;
return;
}
for(int i = 0; i < 2; i++)
{
if(!(GPURAM[FBRW_CurY & 511][FBRW_CurX & 1023] & MaskEvalAND))
GPURAM[FBRW_CurY & 511][FBRW_CurX & 1023] = InData | MaskSetOR;
if(BlitterFIFO.CanRead() >= vl)
{
for(unsigned i = 0; i < vl; i++)
{
CB[i] = BlitterFIFO.ReadUnit();
}
FBRW_CurX++;
if(FBRW_CurX == (FBRW_X + FBRW_W))
{
FBRW_CurX = FBRW_X;
FBRW_CurY++;
if(FBRW_CurY == (FBRW_Y + FBRW_H))
{
InCmd = INCMD_NONE;
break; // Break out of the for() loop.
}
}
InData >>= 16;
}
return;
}
break;
((this)->*(command->func[TexMode | (MaskEvalAND ? 0x4 : 0x0)]))(CB);
}
return;
case INCMD_QUAD:
{
if(DrawTimeAvail < 0)
return;
const uint32 cc = InCmd_CC;
const CTEntry *command = &Commands[abr][cc];
unsigned vl = 1 + (bool)(cc & 0x4) + (bool)(cc & 0x10);
uint32 CB[3];
if(BlitterFIFO.CanRead() >= vl)
{
for(unsigned i = 0; i < vl; i++)
{
CB[i] = BlitterFIFO.ReadUnit();
}
((this)->*(command->func[TexMode | (MaskEvalAND ? 0x4 : 0x0)]))(CB);
}
return;
}
break;
case INCMD_PLINE:
{
if(DrawTimeAvail < 0)
return;
const uint32 cc = InCmd_CC;
const CTEntry *command = &Commands[abr][cc];
unsigned vl = 1 + (bool)(InCmd_CC & 0x10);
uint32 CB[2];
if((BlitterFIFO.ReadUnit(true) & 0xF000F000) == 0x50005000)
{
BlitterFIFO.ReadUnit();
InCmd = INCMD_NONE;
return;
}
if(BlitterFIFO.CanRead() >= vl)
{
for(unsigned i = 0; i < vl; i++)
{
CB[i] = BlitterFIFO.ReadUnit();
}
((this)->*(command->func[TexMode | (MaskEvalAND ? 0x4 : 0x0)]))(CB);
}
return;
}
break;
}
const uint32 cc = BlitterFIFO.ReadUnit(true) >> 24;
const CTEntry *command = &Commands[0][cc];
ParsingLineOrPolygonCommand = (cc >= 0x20 && cc < 0x60);
if(DrawTimeAvail < 0 && !command->ss_cmd)
return;
if(BlitterFIFO.CanRead() >= command->len)
{
@ -694,14 +725,15 @@ void PS_GPU::ProcessFIFO(bool force)
for(unsigned i = 0; i < command->len; i++)
CB[i] = BlitterFIFO.ReadUnit();
DrawTimeAvail -= 2;
if(!command->ss_cmd)
DrawTimeAvail -= 2;
PrimitiveCounter[cc]++;
if(!command->func[TexMode])
{
if(CB[0])
PSX_WARNING("[GPU] Unknown command: %08x, %d", CB[0], scanline);
//if(CB[0])
// PSX_WARNING("[GPU] Unknown command: %08x, %d", CB[0], scanline);
}
else
{
@ -737,16 +769,17 @@ void PS_GPU::ProcessFIFO(bool force)
((this)->*(command->func[TexMode | (MaskEvalAND ? 0x4 : 0x0)]))(CB);
//printf("COMMAND: %08x -- %8d ---- scanline=%d -- adta=%8d\n", CB[0], DrawTimeAvail - olddt, scanline, DrawTimeAvail);
}
if(!InPLine)
ParsingLineOrPolygonCommand = false;
}
}
INLINE void PS_GPU::WriteCB(uint32 InData)
{
if(!BlitterFIFO.CanWrite())
ProcessFIFO(true);
if(BlitterFIFO.CanRead() >= 0x10 && (InCmd != INCMD_NONE || (BlitterFIFO.CanRead() - 0x10) >= Commands[0][BlitterFIFO.ReadUnit(true) >> 24].fifo_fb_len))
{
MDFN_DispMessage("GPU FIFO overflow!!!");
fprintf(stderr, "GPU FIFO overflow!!!");
return;
}
BlitterFIFO.WriteUnit(InData);
ProcessFIFO();
@ -776,14 +809,10 @@ void PS_GPU::Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V)
break;
case 0x01: // Reset command buffer
//if(DrawTimeAvail < 0)
// DrawTimeAvail = 0;
if(DrawTimeAvail < 0)
DrawTimeAvail = 0;
BlitterFIFO.Flush();
ParsingLineOrPolygonCommand = false;
InPLine = false;
InFBRead = false;
InFBWrite = false;
InCmd = INCMD_NONE;
break;
case 0x02: // Reset IRQ ???
@ -881,14 +910,13 @@ uint32 PS_GPU::Read(const pscpu_timestamp_t timestamp, uint32 A)
ret |= DisplayOff << 23;
if(!InFBRead && !InFBWrite && !InPLine && DrawTimeAvail >= 0 && BlitterFIFO.CanWrite() == 0x10) // GPU idle bit.
if(InCmd == INCMD_NONE && DrawTimeAvail >= 0 && BlitterFIFO.CanRead() == 0x00) // GPU idle bit.
ret |= 1 << 26;
if(InFBRead)
if(InCmd == INCMD_FBREAD) // Might want to more accurately emulate this in the future?
ret |= (1 << 27);
if(BlitterFIFO.CanWrite() && !ParsingLineOrPolygonCommand) // FIFO has room bit? (kinda).
ret |= (1 << 28);
ret |= CalcFIFOReadyBit() << 28; // FIFO has room bit? (kinda).
//
//
@ -908,7 +936,7 @@ uint32 PS_GPU::Read(const pscpu_timestamp_t timestamp, uint32 A)
}
else // "Data"
{
if(InFBRead)
if(InCmd == INCMD_FBREAD)
{
DataReadBuffer = 0;
for(int i = 0; i < 2; i++)
@ -922,7 +950,7 @@ uint32 PS_GPU::Read(const pscpu_timestamp_t timestamp, uint32 A)
FBRW_CurY++;
if(FBRW_CurY == (FBRW_Y + FBRW_H))
{
InFBRead = false;
InCmd = INCMD_NONE;
break;
}
}
@ -984,11 +1012,10 @@ pscpu_timestamp_t PS_GPU::Update(const pscpu_timestamp_t sys_timestamp)
{
static const uint32 DotClockRatios[5] = { 10, 8, 5, 4, 7 };
const uint32 dmc = (DisplayMode & 0x40) ? 4 : (DisplayMode & 0x3);
const uint32 dmw = 2720 / DotClockRatios[dmc];
const uint32 dmw = 2720 / DotClockRatios[dmc]; // Must be <= 768
int32 sys_clocks = sys_timestamp - lastts;
int32 gpu_clocks;
int32 dot_clocks;
//printf("GPUISH: %d\n", sys_timestamp - lastts);
@ -1009,33 +1036,42 @@ pscpu_timestamp_t PS_GPU::Update(const pscpu_timestamp_t sys_timestamp)
gpu_clocks = GPUClockCounter >> 16;
GPUClockCounter -= gpu_clocks << 16;
DotClockCounter += gpu_clocks;
dot_clocks = DotClockCounter / DotClockRatios[DisplayMode & 0x3];
DotClockCounter -= dot_clocks * DotClockRatios[DisplayMode & 0x3];
TIMER_AddDotClocks(dot_clocks);
while(gpu_clocks > 0)
{
int32 chunk_clocks = gpu_clocks;
int32 dot_clocks;
if(chunk_clocks > LineClockCounter)
{
//printf("Chunk: %u, LCC: %u\n", chunk_clocks, LineClockCounter);
chunk_clocks = LineClockCounter;
}
gpu_clocks -= chunk_clocks;
LineClockCounter -= chunk_clocks;
DotClockCounter += chunk_clocks;
dot_clocks = DotClockCounter / DotClockRatios[DisplayMode & 0x3];
DotClockCounter -= dot_clocks * DotClockRatios[DisplayMode & 0x3];
TIMER_AddDotClocks(dot_clocks);
if(!LineClockCounter)
{
PSX_SetEventNT(PSX_EVENT_TIMER, TIMER_Update(sys_timestamp)); // We could just call this at the top of GPU_Update(), but do it here for slightly less CPU usage(presumably).
LinePhase = (LinePhase + 1) & 1;
if(LinePhase)
{
TIMER_SetHRetrace(true);
LineClockCounter = 200;
TIMER_ClockHRetrace();
}
else
{
TIMER_SetHRetrace(false);
if(PALMode)
LineClockCounter = 3405 - 200;
else
@ -1046,6 +1082,7 @@ pscpu_timestamp_t PS_GPU::Update(const pscpu_timestamp_t sys_timestamp)
if(scanline == (LinesPerField - 1))
{
//printf("Exit: scanline=%u, st=%u\n", scanline, sys_timestamp);
PSX_RequestMLExit();
}
@ -1069,11 +1106,17 @@ pscpu_timestamp_t PS_GPU::Update(const pscpu_timestamp_t sys_timestamp)
memset(PrimitiveCounter, 0, sizeof(PrimitiveCounter));
#endif
//MDFN_DispMessage("%8d %d %d %d", DrawTimeAvail, InFBRead, InFBWrite, DMA_GPUWriteActive());
IRQ_Assert(IRQ_VSYNC, true);
IRQ_Assert(IRQ_VSYNC, false);
}
// Might not be right:
if(scanline == 0)
TIMER_SetVBlank(true);
else if(scanline == VisibleStartLine)
TIMER_SetVBlank(false);
if(scanline == 0)
{
field_atvs = field;
@ -1127,9 +1170,9 @@ pscpu_timestamp_t PS_GPU::Update(const pscpu_timestamp_t sys_timestamp)
DisplayFB_CurYOffset = 0;
}
const int32 VS_Adjust = 7; //PALMode ? (34 - 6) : 7;
const uint32 VS_Adjust = 7; //PALMode ? (34 - 6) : 7;
if(scanline == (5 + field_atvs))
if(scanline == (5U + field_atvs))
{
if(FrameInterlaced)
{
@ -1192,7 +1235,7 @@ pscpu_timestamp_t PS_GPU::Update(const pscpu_timestamp_t sys_timestamp)
dx_start = 0;
}
if(dx_end > dmw)
if((uint32)dx_end > dmw)
dx_end = dmw;
if(!DisplayHeightCounter || DisplayOff)
@ -1224,9 +1267,18 @@ pscpu_timestamp_t PS_GPU::Update(const pscpu_timestamp_t sys_timestamp)
else
ReorderRGB_Var(surface->format.Rshift, surface->format.Gshift, surface->format.Bshift, DisplayMode & 0x10, src, dest, dx_start, dx_end, fb_x);
for(int32 x = dx_end; x < dmw; x++)
for(uint32 x = dx_end; x < dmw; x++)
dest[x] = black;
}
//if(scanline == 64)
// printf("%u\n", sys_timestamp - ((uint64)gpu_clocks * 65536) / GPUClockRatio);
PSX_GPULineHook(sys_timestamp, sys_timestamp - ((uint64)gpu_clocks * 65536) / GPUClockRatio, scanline == 0, dest, &surface->format, dmw, (528 - 146) / DotClockRatios[dmc], (HardwarePALType ? 53203425 : 53693182) / DotClockRatios[dmc]);
}
else
{
PSX_GPULineHook(sys_timestamp, sys_timestamp - ((uint64)gpu_clocks * 65536) / GPUClockRatio, scanline == 0, NULL, &surface->format, 0, 0, 0);
}
if(DisplayHeightCounter)

View File

@ -1,3 +1,6 @@
// WARNING WARNING WARNING: ONLY use CanRead() method of BlitterFIFO, and NOT CanWrite(), since the FIFO is larger than the actual PS1 GPU FIFO to accommodate
// our lack of fancy superscalarish command sequencer.
#ifndef __MDFN_PSX_GPU_H
#define __MDFN_PSX_GPU_H
@ -10,12 +13,20 @@ class PS_GPU;
struct CTEntry
{
uint32 len;
uint8 len;
uint8 fifo_fb_len;
bool ss_cmd;
const char *name;
void (PS_GPU::*func[8])(const uint32 *cb);
};
struct tri_vertex;
struct tri_vertex
{
int32 x, y;
int32 u, v;
int32 r, g, b;
};
struct i_group;
struct i_deltas;
@ -42,9 +53,32 @@ class PS_GPU
void Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V);
INLINE bool CalcFIFOReadyBit(void)
{
if(InCmd & (INCMD_PLINE | INCMD_QUAD))
return(false);
if(BlitterFIFO.CanRead() == 0)
return(true);
if(InCmd & (INCMD_FBREAD | INCMD_FBWRITE))
return(false);
if(BlitterFIFO.CanRead() >= Commands[0][BlitterFIFO.ReadUnit(true) >> 24].fifo_fb_len)
return(false);
return(true);
}
INLINE bool DMACanWrite(void)
{
return BlitterFIFO.CanWrite(); // && (DMAControl & 2);
return CalcFIFOReadyBit();
}
INLINE void AbortDMA(void)
{
BlitterFIFO.Flush();
InCmd = INCMD_NONE;
}
void WriteDMA(uint32 V);
@ -66,20 +100,9 @@ class PS_GPU
GPURAM[(A >> 10) & 0x1FF][A & 0x3FF] = V;
}
INLINE void DTAResetKludge(void)
{
DrawTimeAvail = 0;
}
INLINE int32 DTAGetWaitKludge(void)
{
return std::max<int32>((0 - DrawTimeAvail) >> 1, 0);
}
private:
void ProcessFIFO(bool force = false);
void ProcessFIFO(void);
void WriteCB(uint32 data);
void SoftReset(void);
@ -194,14 +217,26 @@ class PS_GPU
uint32 DataReadBuffer;
bool ParsingLineOrPolygonCommand;
//
//
//
// Powers of 2 for faster multiple equality testing(just for multi-testing; InCmd itself will only contain 0, or a power of 2).
enum
{
INCMD_NONE = 0,
INCMD_PLINE = (1 << 0),
INCMD_QUAD = (1 << 1),
INCMD_FBWRITE = (1 << 2),
INCMD_FBREAD = (1 << 3)
};
uint8 InCmd;
uint8 InCmd_CC;
tri_vertex InQuad_F3Vertices[3];
uint32 InQuad_clut;
uint32 InPLine;
line_point InPLine_PrevPoint;
bool InFBWrite;
bool InFBRead;
uint32 FBRW_X;
uint32 FBRW_Y;
uint32 FBRW_W;

View File

@ -1,8 +1,8 @@
#define POLY_HELPER_SUB(cv, tm, mam) \
&PS_GPU::Command_DrawPolygon<3 + ((cv & 0x8) >> 3), ((cv & 0x10) >> 4), ((cv & 0x4) >> 2), ((cv & 0x2) >> 1) ? BLENDMODE_MAC : -1, ((cv & 1) ^ 1) & ((cv & 0x4) >> 2), tm, mam >
#define POLY_HELPER(cv) { 1 + (3 + ((cv & 0x8) >> 3)) * ( 1 + ((cv & 0x4) >> 2) + ((cv & 0x10) >> 4) ) - ((cv & 0x10) >> 4), \
"Polygon", { POLY_HELPER_SUB(cv, ((cv & 0x4) ? 0 : 0), 0), POLY_HELPER_SUB(cv, ((cv & 0x4) ? 1 : 0), 0), \
#define POLY_HELPER(cv) { 1 + (3 /*+ ((cv & 0x8) >> 3)*/) * ( 1 + ((cv & 0x4) >> 2) + ((cv & 0x10) >> 4) ) - ((cv & 0x10) >> 4), \
1, false, "Polygon", { POLY_HELPER_SUB(cv, ((cv & 0x4) ? 0 : 0), 0), POLY_HELPER_SUB(cv, ((cv & 0x4) ? 1 : 0), 0), \
POLY_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 0), POLY_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 0), \
POLY_HELPER_SUB(cv, ((cv & 0x4) ? 0 : 0), 1), POLY_HELPER_SUB(cv, ((cv & 0x4) ? 1 : 0), 1), \
POLY_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 1), POLY_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 1), \
@ -13,7 +13,7 @@
#define SPR_HELPER_SUB(cv, tm, mam) &PS_GPU::Command_DrawSprite<(cv >> 3) & 0x3, ((cv & 0x4) >> 2), ((cv & 0x2) >> 1) ? BLENDMODE_MAC : -1, ((cv & 1) ^ 1) & ((cv & 0x4) >> 2), tm, mam>
#define SPR_HELPER(cv) { 2 + ((cv & 0x4) >> 2) + ((cv & 0x18) ? 0 : 1), "Sprite", { \
#define SPR_HELPER(cv) { 2 + ((cv & 0x4) >> 2) + ((cv & 0x18) ? 0 : 1), 2 | ((cv & 0x4) >> 2) | ((cv & 0x18) ? 0 : 1), false, "Sprite", { \
SPR_HELPER_SUB(cv, ((cv & 0x4) ? 0 : 0), 0), SPR_HELPER_SUB(cv, ((cv & 0x4) ? 1 : 0), 0), \
SPR_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 0), SPR_HELPER_SUB(cv, ((cv & 0x4) ? 2 : 0), 0), \
SPR_HELPER_SUB(cv, ((cv & 0x4) ? 0 : 0), 1), SPR_HELPER_SUB(cv, ((cv & 0x4) ? 1 : 0), 1), \
@ -25,22 +25,22 @@
#define LINE_HELPER_SUB(cv, mam) &PS_GPU::Command_DrawLine<((cv & 0x08) >> 3), ((cv & 0x10) >> 4), ((cv & 0x2) >> 1) ? BLENDMODE_MAC : -1, mam>
#define LINE_HELPER(cv) { 3 + ((cv & 0x10) >> 4), "Line", \
#define LINE_HELPER(cv) { 3 + ((cv & 0x10) >> 4), 1, false, "Line", \
{ LINE_HELPER_SUB(cv, 0), LINE_HELPER_SUB(cv, 0), LINE_HELPER_SUB(cv, 0), LINE_HELPER_SUB(cv, 0), \
LINE_HELPER_SUB(cv, 1), LINE_HELPER_SUB(cv, 1), LINE_HELPER_SUB(cv, 1), LINE_HELPER_SUB(cv, 1), } }
//
//
#define OTHER_HELPER(arg_cs, arg_name, arg_ptr) { arg_cs, arg_name, { arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr } }
#define OTHER_HELPER(arg_cs, arg_fbcs, arg_ss, arg_name, arg_ptr) { arg_cs, arg_fbcs, arg_ss, arg_name, { arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr } }
#define NULLCMD() { 1, NULL, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }
#define NULLCMD() { 1, 1, true, NULL, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }
/* 0x00 */
OTHER_HELPER(1, "UNKNOWN", NULL),
OTHER_HELPER(1, "Clear Cache", &PS_GPU::Command_ClearCache),
OTHER_HELPER(3, "FB Fill", &PS_GPU::Command_FBFill),
NULLCMD(),
OTHER_HELPER(1, 2, false, "Clear Cache", &PS_GPU::Command_ClearCache),
OTHER_HELPER(3, 3, false, "FB Fill", &PS_GPU::Command_FBFill),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
@ -150,7 +150,7 @@
SPR_HELPER(0x7f),
/* 0x80 */
OTHER_HELPER(4, "FB Copy", &PS_GPU::Command_FBCopy),
OTHER_HELPER(4, 2, false, "FB Copy", &PS_GPU::Command_FBCopy),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
@ -159,7 +159,7 @@
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
/* 0xA0 */
OTHER_HELPER(3, "FB Write", &PS_GPU::Command_FBWrite),
OTHER_HELPER(3, 2, false, "FB Write", &PS_GPU::Command_FBWrite),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
@ -168,7 +168,7 @@
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
/* 0xC0 */
OTHER_HELPER(3, "FB Read", &PS_GPU::Command_FBRead),
OTHER_HELPER(3, 2, false, "FB Read", &PS_GPU::Command_FBRead),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
@ -179,12 +179,12 @@
/* 0xE0 */
NULLCMD(),
OTHER_HELPER(1, "Draw mode settings", &PS_GPU::Command_DrawMode),
OTHER_HELPER(1, "Texture window settings", &PS_GPU::Command_TexWindow),
OTHER_HELPER(1, "Drawing area top left", &PS_GPU::Command_Clip0),
OTHER_HELPER(1, "Drawing area bottom right", &PS_GPU::Command_Clip1),
OTHER_HELPER(1, "Drawing offset", &PS_GPU::Command_DrawingOffset),
OTHER_HELPER(1, "Mask settings", &PS_GPU::Command_MaskSetting),
OTHER_HELPER(1, 2, false, "Draw mode settings", &PS_GPU::Command_DrawMode),
OTHER_HELPER(1, 2, false, "Texture window settings", &PS_GPU::Command_TexWindow),
OTHER_HELPER(1, 1, true, "Drawing area top left", &PS_GPU::Command_Clip0),
OTHER_HELPER(1, 1, true, "Drawing area bottom right", &PS_GPU::Command_Clip1),
OTHER_HELPER(1, 1, true, "Drawing offset", &PS_GPU::Command_DrawingOffset),
OTHER_HELPER(1, 2, false, "Mask settings", &PS_GPU::Command_MaskSetting),
NULLCMD(),
NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),

View File

@ -198,7 +198,7 @@ void PS_GPU::Command_DrawLine(const uint32 *cb)
DrawTimeAvail -= 16; // FIXME, correct time.
if(polyline && InPLine)
if(polyline && InCmd == INCMD_PLINE)
{
//printf("PLINE N\n");
points[0] = InPLine_PrevPoint;
@ -237,8 +237,11 @@ void PS_GPU::Command_DrawLine(const uint32 *cb)
{
InPLine_PrevPoint = points[1];
if(!InPLine)
InPLine = cc;
if(InCmd != INCMD_PLINE)
{
InCmd = INCMD_PLINE;
InCmd_CC = cc;
}
}
DrawLine<goraud, BlendMode, MaskEval_TA>(points);

View File

@ -1,10 +1,3 @@
struct tri_vertex
{
int32 x, y;
int32 u, v;
int32 r, g, b;
};
struct i_group
{
int32 u, v;
@ -408,133 +401,89 @@ void PS_GPU::DrawTriangle(tri_vertex *vertices, uint32 clut)
template<int numvertices, bool goraud, bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA>
void PS_GPU::Command_DrawPolygon(const uint32 *cb)
{
tri_vertex vertices[4];
uint32 raw_colors[4];
const unsigned cb0 = cb[0];
tri_vertex vertices[3];
uint32 clut = 0;
unsigned sv = 0;
//uint32 tpage = 0;
if(numvertices == 4)
DrawTimeAvail -= 64; // FIXME, correct time.
// Base timing is approximate, and could be improved.
if(numvertices == 4 && InCmd == INCMD_QUAD)
DrawTimeAvail -= (28 + 18);
else
DrawTimeAvail -= 32; // FIXME, correct time.
DrawTimeAvail -= (64 + 18);
memset(vertices, 0, sizeof(vertices));
raw_colors[0] = (*cb & 0xFFFFFF);
cb++;
vertices[0].x = (int16)(*cb & 0xFFFF);
vertices[0].y = (int16)(*cb >> 16);
cb++;
if(textured)
{
vertices[0].u = (*cb & 0xFF);
vertices[0].v = (*cb >> 8) & 0xFF;
clut = ((*cb >> 16) & 0xFFFF) << 4;
cb++;
}
if(goraud)
{
raw_colors[1] = (*cb & 0xFFFFFF);
cb++;
}
vertices[1].x = (int16)(*cb & 0xFFFF);
vertices[1].y = (int16)(*cb >> 16);
cb++;
if(textured)
{
vertices[1].u = (*cb & 0xFF);
vertices[1].v = (*cb >> 8) & 0xFF;
cb++;
}
if(goraud)
{
raw_colors[2] = (*cb & 0xFFFFFF);
cb++;
}
vertices[2].x = (int16)(*cb & 0xFFFF);
vertices[2].y = (int16)(*cb >> 16);
cb++;
if(textured)
{
vertices[2].u = (*cb & 0xFF);
vertices[2].v = (*cb >> 8) & 0xFF;
cb++;
}
if(goraud && textured)
DrawTimeAvail -= 150 * 3;
else if(goraud)
DrawTimeAvail -= 96 * 3;
else if(textured)
DrawTimeAvail -= 60 * 3;
if(numvertices == 4)
{
if(goraud)
if(InCmd == INCMD_QUAD)
{
raw_colors[3] = (*cb & 0xFFFFFF);
memcpy(&vertices[0], &InQuad_F3Vertices[1], 2 * sizeof(tri_vertex));
clut = InQuad_clut;
sv = 2;
}
}
//else
// memset(vertices, 0, sizeof(vertices));
for(unsigned v = sv; v < 3; v++)
{
if(v == 0 || goraud)
{
uint32 raw_color = (*cb & 0xFFFFFF);
vertices[v].r = raw_color & 0xFF;
vertices[v].g = (raw_color >> 8) & 0xFF;
vertices[v].b = (raw_color >> 16) & 0xFF;
cb++;
}
else
{
vertices[v].r = vertices[0].r;
vertices[v].g = vertices[0].g;
vertices[v].b = vertices[0].b;
}
vertices[3].x = (int16)(*cb & 0xFFFF);
vertices[3].y = (int16)(*cb >> 16);
vertices[v].x = sign_x_to_s32(11, ((int16)(*cb & 0xFFFF))) + OffsX;
vertices[v].y = sign_x_to_s32(11, ((int16)(*cb >> 16))) + OffsY;
cb++;
if(textured)
{
vertices[3].u = (*cb & 0xFF);
vertices[3].v = (*cb >> 8) & 0xFF;
vertices[v].u = (*cb & 0xFF);
vertices[v].v = (*cb >> 8) & 0xFF;
if(v == 0)
{
clut = ((*cb >> 16) & 0xFFFF) << 4;
}
cb++;
}
}
else
if(numvertices == 4)
{
raw_colors[3] = raw_colors[0];
if(InCmd == INCMD_QUAD)
{
InCmd = INCMD_NONE;
}
else
{
InCmd = INCMD_QUAD;
InCmd_CC = cb0 >> 24;
memcpy(&InQuad_F3Vertices[0], &vertices[0], sizeof(tri_vertex) * 3);
InQuad_clut = clut;
}
}
if(!goraud)
raw_colors[1] = raw_colors[2] = raw_colors[3] = raw_colors[0];
for(int i = 0; i < numvertices; i++)
{
//raw_colors[i] = rand() & 0xFFFFFF;
vertices[i].r = raw_colors[i] & 0xFF;
vertices[i].g = (raw_colors[i] >> 8) & 0xFF;
vertices[i].b = (raw_colors[i] >> 16) & 0xFF;
}
for(int i = 0; i < numvertices; i++)
{
vertices[i].x = sign_x_to_s32(11, vertices[i].x) + OffsX;
vertices[i].y = sign_x_to_s32(11, vertices[i].y) + OffsY;
}
#if 0
printf("Draw polygon %d: ", numvertices);
for(int i = 0; i < numvertices; i++)
{
printf("%d:%d ", vertices[i].x, vertices[i].y);
//GPURAM[vertices[i].y & 511][vertices[i].x & 1023] = rand();
}
printf("\n");
#endif
if(numvertices == 3)
DrawTriangle<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(vertices, clut);
else
{
tri_vertex vertices_tmp[3];
memcpy(&vertices_tmp[0], &vertices[1], 3 * sizeof(tri_vertex));
DrawTriangle<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(vertices, clut);
DrawTriangle<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(vertices_tmp, clut);
}
DrawTriangle<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(vertices, clut);
}

View File

@ -84,7 +84,7 @@ void InputDevice_DualAnalog::UpdateInput(const void *data)
{
int32 tmp;
tmp = 32768 + MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 4) - ((int32)MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 8) * 32768 / 32768);
tmp = 32768 + MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 4) - ((int32)MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 8) * 32768 / 32767);
tmp >>= 8;
axes[stick][axis] = tmp;
@ -195,7 +195,10 @@ bool InputDevice_DualAnalog::Clock(bool TxD, int32 &dsr_pulse_delay)
transmit_count = 0;
}
break;
case 2:
//if(receive_buffer)
// printf("%d: %02x\n", 7 - transmit_count, receive_buffer);
break;
}
}
@ -261,10 +264,10 @@ InputDeviceInputInfoStruct Device_AnalogJoy_IDII[24] =
{ "l1", "Left stick, L-thumb", 0, IDIT_BUTTON, NULL },
{ "r1", "Left stick, R-thumb", 1, IDIT_BUTTON, NULL },
{ "triangle", "Right stick, Pinky", 13, IDIT_BUTTON_CAN_RAPID, NULL },
{ "circle", "Right stick, R-thumb", 11, IDIT_BUTTON_CAN_RAPID, NULL },
{ "cross", "Right stick, L-thumb", 10, IDIT_BUTTON_CAN_RAPID, NULL },
{ "square", "Right stick, Trigger", 12, IDIT_BUTTON_CAN_RAPID, NULL },
{ "triangle", "Right stick, Pinky", 13, IDIT_BUTTON, NULL },
{ "circle", "Right stick, R-thumb", 11, IDIT_BUTTON, NULL },
{ "cross", "Right stick, L-thumb", 10, IDIT_BUTTON, NULL },
{ "square", "Right stick, Trigger", 12, IDIT_BUTTON, NULL },
{ "rstick_right", "Right Stick, RIGHT →", 21, IDIT_BUTTON_ANALOG },
{ "rstick_left", "Right Stick, LEFT ←", 20, IDIT_BUTTON_ANALOG },

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
#ifndef __MDFN_PSX_INPUT_DUALSHOCK_H
#define __MDFN_PSX_INPUT_DUALSHOCK_H
#include <string>
namespace MDFN_IEN_PSX
{
InputDevice *Device_DualShock_Create(const std::string &name);
extern InputDeviceInputInfoStruct Device_DualShock_IDII[26];
}
#endif

View File

@ -0,0 +1,396 @@
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../psx.h"
#include "../frontio.h"
#include "guncon.h"
namespace MDFN_IEN_PSX
{
class InputDevice_GunCon : public InputDevice
{
public:
InputDevice_GunCon(void);
virtual ~InputDevice_GunCon();
virtual void Power(void);
virtual void UpdateInput(const void *data);
virtual void SetCrosshairsColor(uint32 color);
virtual bool RequireNoFrameskip(void);
virtual pscpu_timestamp_t GPULineHook(const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool GetDSR(void);
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
private:
bool dtr;
uint8 buttons;
bool trigger_eff;
bool trigger_noclear;
uint16 hit_x, hit_y;
int32 nom_x, nom_y;
int32 os_shot_counter;
bool prev_oss;
int32 command_phase;
uint32 bitpos;
uint8 receive_buffer;
uint8 command;
uint8 transmit_buffer[16];
uint32 transmit_pos;
uint32 transmit_count;
//
// Video timing stuff
bool prev_vsync;
int line_counter;
//
unsigned chair_r, chair_g, chair_b;
bool draw_chair;
};
InputDevice_GunCon::InputDevice_GunCon(void) : chair_r(0), chair_g(0), chair_b(0), draw_chair(false)
{
Power();
}
InputDevice_GunCon::~InputDevice_GunCon()
{
}
void InputDevice_GunCon::SetCrosshairsColor(uint32 color)
{
chair_r = (color >> 16) & 0xFF;
chair_g = (color >> 8) & 0xFF;
chair_b = (color >> 0) & 0xFF;
draw_chair = (color != (1 << 24));
}
void InputDevice_GunCon::Power(void)
{
dtr = 0;
buttons = 0;
trigger_eff = 0;
trigger_noclear = 0;
hit_x = 0;
hit_y = 0;
nom_x = 0;
nom_y = 0;
os_shot_counter = 0;
prev_oss = 0;
command_phase = 0;
bitpos = 0;
receive_buffer = 0;
command = 0;
memset(transmit_buffer, 0, sizeof(transmit_buffer));
transmit_pos = 0;
transmit_count = 0;
prev_vsync = 0;
line_counter = 0;
}
void InputDevice_GunCon::UpdateInput(const void *data)
{
uint8 *d8 = (uint8 *)data;
nom_x = MDFN_de32lsb(&d8[0]);
nom_y = MDFN_de32lsb(&d8[4]);
trigger_noclear = (bool)(d8[8] & 0x1);
trigger_eff |= trigger_noclear;
buttons = d8[8] >> 1;
if(os_shot_counter > 0) // FIXME if UpdateInput() is ever called more than once per video frame(at ~50 or ~60Hz).
os_shot_counter--;
// Eeeeiiiiiight.
if((d8[8] & 0x8) && !prev_oss && os_shot_counter == 0)
os_shot_counter = 4;
prev_oss = d8[8] & 0x8;
//MDFN_DispMessage("%08x %08x", nom_x, nom_y);
}
bool InputDevice_GunCon::RequireNoFrameskip(void)
{
return(true);
}
pscpu_timestamp_t InputDevice_GunCon::GPULineHook(const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width,
const unsigned pix_clock_offset, const unsigned pix_clock)
{
if(vsync && !prev_vsync)
line_counter = 0;
if(pixels && pix_clock)
{
const int avs = 22; // Not 22 for PAL, fixme.
int32 gx;
int32 gy;
gx = ((int64)nom_x * width / MDFNGameInfo->nominal_width + 0x8000) >> 16;
gy = (nom_y + 0x8000) >> 16;
for(int32 ix = gx; ix < (gx + (int32)(pix_clock / 762925)); ix++)
{
if(ix >= 0 && (unsigned)ix < width && line_counter >= (avs + gy) && line_counter < (avs + gy + 8))
{
int r, g, b, a;
format->DecodeColor(pixels[ix], r, g, b, a);
if((r + g + b) >= 0x40) // Wrong, but not COMPLETELY ABSOLUTELY wrong, at least. ;)
{
hit_x = (int64)(ix + pix_clock_offset) * 8000000 / pix_clock; // GunCon has what appears to be an 8.00MHz ceramic resonator in it.
hit_y = line_counter;
}
}
}
if(draw_chair)
{
if(line_counter == (avs + gy))
{
const int ic = pix_clock / 762925;
for(int32 x = std::max<int32>(0, gx - ic); x < std::min<int32>(width, gx + ic); x++)
{
int r, g, b, a;
int nr, ng, nb;
format->DecodeColor(pixels[x], r, g, b, a);
nr = (r + chair_r * 3) >> 2;
ng = (g + chair_g * 3) >> 2;
nb = (b + chair_b * 3) >> 2;
if(abs((r * 76 + g * 150 + b * 29) - (nr * 76 + ng * 150 + nb * 29)) < 16384)
{
nr >>= 1;
ng >>= 1;
nb >>= 1;
}
pixels[x] = format->MakeColor(nr, ng, nb, a);
}
}
else if(line_counter >= (avs + gy - 8) && line_counter <= (avs + gy + 8))
{
int r, g, b, a;
int nr, ng, nb;
format->DecodeColor(pixels[gx], r, g, b, a);
nr = (r + chair_r * 3) >> 2;
ng = (g + chair_g * 3) >> 2;
nb = (b + chair_b * 3) >> 2;
if(abs((r * 76 + g * 150 + b * 29) - (nr * 76 + ng * 150 + nb * 29)) < 16384)
{
nr >>= 1;
ng >>= 1;
nb >>= 1;
}
pixels[gx] = format->MakeColor(nr, ng, nb, a);
}
}
}
line_counter++;
return(PSX_EVENT_MAXTS);
}
void InputDevice_GunCon::SetDTR(bool new_dtr)
{
if(!dtr && new_dtr)
{
command_phase = 0;
bitpos = 0;
transmit_pos = 0;
transmit_count = 0;
}
else if(dtr && !new_dtr)
{
//if(bitpos || transmit_count)
// printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
}
dtr = new_dtr;
}
bool InputDevice_GunCon::GetDSR(void)
{
if(!dtr)
return(0);
if(!bitpos && transmit_count)
return(1);
return(0);
}
bool InputDevice_GunCon::Clock(bool TxD, int32 &dsr_pulse_delay)
{
bool ret = 1;
dsr_pulse_delay = 0;
if(!dtr)
return(1);
if(transmit_count)
ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
receive_buffer &= ~(1 << bitpos);
receive_buffer |= TxD << bitpos;
bitpos = (bitpos + 1) & 0x7;
if(!bitpos)
{
//printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
if(transmit_count)
{
transmit_pos++;
transmit_count--;
}
switch(command_phase)
{
case 0:
if(receive_buffer != 0x01)
command_phase = -1;
else
{
transmit_buffer[0] = 0x63;
transmit_pos = 0;
transmit_count = 1;
command_phase++;
}
break;
case 2:
//if(receive_buffer)
// printf("%02x\n", receive_buffer);
break;
case 1:
command = receive_buffer;
command_phase++;
transmit_buffer[0] = 0x5A;
//puts("MOO");
//if(command != 0x42)
// fprintf(stderr, "GunCon unhandled command: 0x%02x\n", command);
//assert(command == 0x42);
if(command == 0x42)
{
transmit_buffer[1] = 0xFF ^ ((buttons & 0x01) << 3);
transmit_buffer[2] = 0xFF ^ (trigger_eff << 5) ^ ((buttons & 0x02) << 5);
if(os_shot_counter > 0)
{
hit_x = 0x01;
hit_y = 0x0A;
transmit_buffer[2] |= (1 << 5);
if(os_shot_counter == 2 || os_shot_counter == 3)
{
transmit_buffer[2] &= ~(1 << 5);
}
}
MDFN_en16lsb(&transmit_buffer[3], hit_x);
MDFN_en16lsb(&transmit_buffer[5], hit_y);
hit_x = 0x01;
hit_y = 0x0A;
transmit_pos = 0;
transmit_count = 7;
trigger_eff = trigger_noclear;
}
else
{
command_phase = -1;
transmit_buffer[1] = 0;
transmit_buffer[2] = 0;
transmit_pos = 0;
transmit_count = 0;
}
break;
}
}
if(!bitpos && transmit_count)
dsr_pulse_delay = 100; //0x80; //0x40;
return(ret);
}
InputDevice *Device_GunCon_Create(void)
{
return new InputDevice_GunCon();
}
InputDeviceInputInfoStruct Device_GunCon_IDII[6] =
{
{ "x_axis", "X Axis", -1, IDIT_X_AXIS },
{ "y_axis", "Y Axis", -1, IDIT_Y_AXIS },
{ "trigger", "Trigger", 0, IDIT_BUTTON, NULL },
{ "a", "A", 1, IDIT_BUTTON, NULL },
{ "b", "B", 2, IDIT_BUTTON, NULL },
{ "offscreen_shot", "Offscreen Shot(Simulated)", 3, IDIT_BUTTON, NULL }, // Useful for "Judge Dredd", and probably not much else.
};
}

View File

@ -0,0 +1,11 @@
#ifndef __MDFN_PSX_INPUT_GUNCON_H
#define __MDFN_PSX_INPUT_GUNCON_H
namespace MDFN_IEN_PSX
{
InputDevice *Device_GunCon_Create(void);
extern InputDeviceInputInfoStruct Device_GunCon_IDII[6];
}
#endif

View File

@ -0,0 +1,393 @@
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../psx.h"
#include "../frontio.h"
#include "justifier.h"
namespace MDFN_IEN_PSX
{
class InputDevice_Justifier : public InputDevice
{
public:
InputDevice_Justifier(void);
virtual ~InputDevice_Justifier();
virtual void Power(void);
virtual void UpdateInput(const void *data);
virtual void SetCrosshairsColor(uint32 color);
virtual bool RequireNoFrameskip(void);
virtual pscpu_timestamp_t GPULineHook(const pscpu_timestamp_t timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool GetDSR(void);
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
private:
bool dtr;
uint8 buttons;
bool trigger_eff;
bool trigger_noclear;
bool need_hit_detect;
int32 nom_x, nom_y;
int32 os_shot_counter;
bool prev_oss;
int32 command_phase;
uint32 bitpos;
uint8 receive_buffer;
uint8 command;
uint8 transmit_buffer[16];
uint32 transmit_pos;
uint32 transmit_count;
//
// Video timing stuff
bool prev_vsync;
int line_counter;
//
unsigned chair_r, chair_g, chair_b;
bool draw_chair;
};
InputDevice_Justifier::InputDevice_Justifier(void) : chair_r(0), chair_g(0), chair_b(0), draw_chair(false)
{
Power();
}
InputDevice_Justifier::~InputDevice_Justifier()
{
}
void InputDevice_Justifier::SetCrosshairsColor(uint32 color)
{
chair_r = (color >> 16) & 0xFF;
chair_g = (color >> 8) & 0xFF;
chair_b = (color >> 0) & 0xFF;
draw_chair = (color != (1 << 24));
}
void InputDevice_Justifier::Power(void)
{
dtr = 0;
buttons = 0;
trigger_eff = 0;
trigger_noclear = 0;
need_hit_detect = false;
nom_x = 0;
nom_y = 0;
os_shot_counter = 0;
prev_oss = 0;
command_phase = 0;
bitpos = 0;
receive_buffer = 0;
command = 0;
memset(transmit_buffer, 0, sizeof(transmit_buffer));
transmit_pos = 0;
transmit_count = 0;
prev_vsync = 0;
line_counter = 0;
}
void InputDevice_Justifier::UpdateInput(const void *data)
{
uint8 *d8 = (uint8 *)data;
nom_x = MDFN_de32lsb(&d8[0]);
nom_y = MDFN_de32lsb(&d8[4]);
trigger_noclear = (bool)(d8[8] & 0x1);
trigger_eff |= trigger_noclear;
buttons = (d8[8] >> 1) & 0x3;
if(os_shot_counter > 0) // FIXME if UpdateInput() is ever called more than once per video frame(at ~50 or ~60Hz).
os_shot_counter--;
if((d8[8] & 0x8) && !prev_oss && os_shot_counter == 0)
os_shot_counter = 10;
prev_oss = d8[8] & 0x8;
}
bool InputDevice_Justifier::RequireNoFrameskip(void)
{
return(true);
}
pscpu_timestamp_t InputDevice_Justifier::GPULineHook(const pscpu_timestamp_t timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width,
const unsigned pix_clock_offset, const unsigned pix_clock)
{
pscpu_timestamp_t ret = PSX_EVENT_MAXTS;
if(vsync && !prev_vsync)
line_counter = 0;
if(pixels && pix_clock)
{
const int avs = 22; // Not 22 for PAL, fixme.
int32 gx;
int32 gy;
int32 gxa;
gx = ((int64)nom_x * width / MDFNGameInfo->nominal_width + 0x8000) >> 16;
gy = (nom_y + 0x8000) >> 16;
gxa = gx; // - (pix_clock / 400000);
//if(gxa < 0 && gx >= 0)
// gxa = 0;
if(!os_shot_counter && need_hit_detect && gxa >= 0 && gxa < (int)width && line_counter >= (avs + gy - 1) && line_counter <= (avs + gy + 1))
{
int r, g, b, a;
format->DecodeColor(pixels[gxa], r, g, b, a);
if((r + g + b) >= 0x40) // Wrong, but not COMPLETELY ABSOLUTELY wrong, at least. ;)
{
ret = timestamp + (int64)(gxa + pix_clock_offset) * (44100 * 768) / pix_clock - 181;
}
}
if(draw_chair)
{
if(line_counter == (avs + gy))
{
const int ic = pix_clock / 762925;
for(int32 x = std::max<int32>(0, gx - ic); x < std::min<int32>(width, gx + ic); x++)
{
int r, g, b, a;
int nr, ng, nb;
format->DecodeColor(pixels[x], r, g, b, a);
nr = (r + chair_r * 3) >> 2;
ng = (g + chair_g * 3) >> 2;
nb = (b + chair_b * 3) >> 2;
if(abs((r * 76 + g * 150 + b * 29) - (nr * 76 + ng * 150 + nb * 29)) < 16384)
{
nr >>= 1;
ng >>= 1;
nb >>= 1;
}
pixels[x] = format->MakeColor(nr, ng, nb, a);
}
}
else if(line_counter >= (avs + gy - 8) && line_counter <= (avs + gy + 8))
{
int r, g, b, a;
int nr, ng, nb;
format->DecodeColor(pixels[gx], r, g, b, a);
nr = (r + chair_r * 3) >> 2;
ng = (g + chair_g * 3) >> 2;
nb = (b + chair_b * 3) >> 2;
if(abs((r * 76 + g * 150 + b * 29) - (nr * 76 + ng * 150 + nb * 29)) < 16384)
{
nr >>= 1;
ng >>= 1;
nb >>= 1;
}
pixels[gx] = format->MakeColor(nr, ng, nb, a);
}
}
}
line_counter++;
return(ret);
}
void InputDevice_Justifier::SetDTR(bool new_dtr)
{
if(!dtr && new_dtr)
{
command_phase = 0;
bitpos = 0;
transmit_pos = 0;
transmit_count = 0;
}
else if(dtr && !new_dtr)
{
//if(bitpos || transmit_count)
// printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
}
dtr = new_dtr;
}
bool InputDevice_Justifier::GetDSR(void)
{
if(!dtr)
return(0);
if(!bitpos && transmit_count)
return(1);
return(0);
}
bool InputDevice_Justifier::Clock(bool TxD, int32 &dsr_pulse_delay)
{
bool ret = 1;
dsr_pulse_delay = 0;
if(!dtr)
return(1);
if(transmit_count)
ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
receive_buffer &= ~(1 << bitpos);
receive_buffer |= TxD << bitpos;
bitpos = (bitpos + 1) & 0x7;
if(!bitpos)
{
//printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
if(transmit_count)
{
transmit_pos++;
transmit_count--;
}
switch(command_phase)
{
case 0:
if(receive_buffer != 0x01)
command_phase = -1;
else
{
transmit_buffer[0] = 0x31;
transmit_pos = 0;
transmit_count = 1;
command_phase++;
}
break;
case 2:
//if(receive_buffer)
// printf("%02x\n", receive_buffer);
command_phase++;
break;
case 3:
need_hit_detect = receive_buffer & 0x10; // TODO, see if it's (val&0x10) == 0x10, or some other mask value.
command_phase++;
break;
case 1:
command = receive_buffer;
command_phase++;
transmit_buffer[0] = 0x5A;
//if(command != 0x42)
// fprintf(stderr, "Justifier unhandled command: 0x%02x\n", command);
//assert(command == 0x42);
if(command == 0x42)
{
transmit_buffer[1] = 0xFF ^ ((buttons & 2) << 2);
transmit_buffer[2] = 0xFF ^ (trigger_eff << 7) ^ ((buttons & 1) << 6);
if(os_shot_counter > 0)
{
transmit_buffer[2] |= (1 << 7);
if(os_shot_counter == 6 || os_shot_counter == 5)
{
transmit_buffer[2] &= ~(1 << 7);
}
}
transmit_pos = 0;
transmit_count = 3;
trigger_eff = trigger_noclear;
}
else
{
command_phase = -1;
transmit_buffer[1] = 0;
transmit_buffer[2] = 0;
transmit_pos = 0;
transmit_count = 0;
}
break;
}
}
if(!bitpos && transmit_count)
dsr_pulse_delay = 200;
return(ret);
}
InputDevice *Device_Justifier_Create(void)
{
return new InputDevice_Justifier();
}
InputDeviceInputInfoStruct Device_Justifier_IDII[6] =
{
{ "x_axis", "X Axis", -1, IDIT_X_AXIS },
{ "y_axis", "Y Axis", -1, IDIT_Y_AXIS },
{ "trigger", "Trigger", 0, IDIT_BUTTON, NULL },
{ "o", "O", 1, IDIT_BUTTON, NULL },
{ "start", "Start", 2, IDIT_BUTTON, NULL },
{ "offscreen_shot", "Offscreen Shot(Simulated)", 3, IDIT_BUTTON, NULL },
};
}

View File

@ -0,0 +1,11 @@
#ifndef __MDFN_PSX_INPUT_JUSTIFIER_H
#define __MDFN_PSX_INPUT_JUSTIFIER_H
namespace MDFN_IEN_PSX
{
InputDevice *Device_Justifier_Create(void);
extern InputDeviceInputInfoStruct Device_Justifier_IDII[6];
}
#endif

View File

@ -15,7 +15,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// TODO: is &ing the address ok, or should we report an error to the game if it tries to read/write an out-of-range area?
// I could find no other commands than 'R', 'W', and 'S' (not sure what 'S' is for, however)
#include "../psx.h"
#include "../frontio.h"
@ -179,7 +179,8 @@ bool InputDevice_Memcard::Clock(bool TxD, int32 &dsr_pulse_delay)
if(!bitpos)
{
//printf("Receive=0x%02x\n", receive_buffer);
//if(command_phase > 0 || transmit_count)
// printf("[MCRDATA] Received_data=0x%02x, Sent_data=0x%02x\n", receive_buffer, transmit_buffer);
if(transmit_count)
{
@ -264,6 +265,13 @@ bool InputDevice_Memcard::Clock(bool TxD, int32 &dsr_pulse_delay)
transmit_buffer = ']';
transmit_count = 1;
command_phase++;
// TODO: enable this code(or something like it) when CPU instruction timing is a bit better.
//
//dsr_pulse_delay = 32000;
//goto SkipDPD;
//
break;
case 1003:
@ -326,7 +334,6 @@ bool InputDevice_Memcard::Clock(bool TxD, int32 &dsr_pulse_delay)
calced_xor ^= receive_buffer;
addr |= receive_buffer & 0xFF;
//printf("[MCR] WRITE ADDR=0x%04x\n", addr);
addr &= (sizeof(card_data) >> 7) - 1;
transmit_buffer = receive_buffer;
transmit_count = 1;
command_phase = 2048;
@ -357,7 +364,12 @@ bool InputDevice_Memcard::Clock(bool TxD, int32 &dsr_pulse_delay)
case (2048 + 130): // End flag
//MDFN_DispMessage("%02x %02x", calced_xor, write_xor);
//printf("[MCR] Write End. Actual_XOR=0x%02x, CW_XOR=0x%02x\n", calced_xor, write_xor);
if(calced_xor == write_xor)
if(calced_xor != write_xor)
transmit_buffer = 'N';
else if(addr >= (sizeof(card_data) >> 7))
transmit_buffer = 0xFF;
else
{
transmit_buffer = 'G';
presence_new = false;
@ -370,8 +382,6 @@ bool InputDevice_Memcard::Clock(bool TxD, int32 &dsr_pulse_delay)
dirty_count++;
}
}
else
transmit_buffer = 'N';
transmit_count = 1;
command_phase = -1;
@ -386,6 +396,8 @@ bool InputDevice_Memcard::Clock(bool TxD, int32 &dsr_pulse_delay)
if(!bitpos && transmit_count)
dsr_pulse_delay = 0x100;
//SkipDPD: ;
return(ret);
}

View File

@ -0,0 +1,259 @@
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../psx.h"
#include "../frontio.h"
#include "negcon.h"
namespace MDFN_IEN_PSX
{
class InputDevice_neGcon : public InputDevice
{
public:
InputDevice_neGcon(void);
virtual ~InputDevice_neGcon();
virtual void Power(void);
virtual void UpdateInput(const void *data);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool GetDSR(void);
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
private:
bool dtr;
uint8 buttons[2];
uint8 twist;
uint8 anabuttons[3];
int32 command_phase;
uint32 bitpos;
uint8 receive_buffer;
uint8 command;
uint8 transmit_buffer[8];
uint32 transmit_pos;
uint32 transmit_count;
};
InputDevice_neGcon::InputDevice_neGcon(void)
{
Power();
}
InputDevice_neGcon::~InputDevice_neGcon()
{
}
void InputDevice_neGcon::Power(void)
{
dtr = 0;
buttons[0] = buttons[1] = 0;
twist = 0;
anabuttons[0] = 0;
anabuttons[1] = 0;
anabuttons[2] = 0;
command_phase = 0;
bitpos = 0;
receive_buffer = 0;
command = 0;
memset(transmit_buffer, 0, sizeof(transmit_buffer));
transmit_pos = 0;
transmit_count = 0;
}
void InputDevice_neGcon::UpdateInput(const void *data)
{
uint8 *d8 = (uint8 *)data;
buttons[0] = d8[0];
buttons[1] = d8[1];
twist = ((32768 + MDFN_de32lsb((const uint8 *)data + 4) - (((int32)MDFN_de32lsb((const uint8 *)data + 8) * 32768 + 16383) / 32767)) * 255 + 32767) / 65535;
anabuttons[0] = (MDFN_de32lsb((const uint8 *)data + 12) * 255 + 16383) / 32767;
anabuttons[1] = (MDFN_de32lsb((const uint8 *)data + 16) * 255 + 16383) / 32767;
anabuttons[2] = (MDFN_de32lsb((const uint8 *)data + 20) * 255 + 16383) / 32767;
//printf("%02x %02x %02x %02x\n", twist, anabuttons[0], anabuttons[1], anabuttons[2]);
}
void InputDevice_neGcon::SetDTR(bool new_dtr)
{
if(!dtr && new_dtr)
{
command_phase = 0;
bitpos = 0;
transmit_pos = 0;
transmit_count = 0;
}
else if(dtr && !new_dtr)
{
//if(bitpos || transmit_count)
// printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
}
dtr = new_dtr;
}
bool InputDevice_neGcon::GetDSR(void)
{
if(!dtr)
return(0);
if(!bitpos && transmit_count)
return(1);
return(0);
}
bool InputDevice_neGcon::Clock(bool TxD, int32 &dsr_pulse_delay)
{
bool ret = 1;
dsr_pulse_delay = 0;
if(!dtr)
return(1);
if(transmit_count)
ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
receive_buffer &= ~(1 << bitpos);
receive_buffer |= TxD << bitpos;
bitpos = (bitpos + 1) & 0x7;
if(!bitpos)
{
//printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
if(transmit_count)
{
transmit_pos++;
transmit_count--;
}
switch(command_phase)
{
case 0:
if(receive_buffer != 0x01)
command_phase = -1;
else
{
transmit_buffer[0] = 0x23;
transmit_pos = 0;
transmit_count = 1;
command_phase++;
dsr_pulse_delay = 256;
}
break;
case 1:
command = receive_buffer;
command_phase++;
transmit_buffer[0] = 0x5A;
//if(command != 0x42)
// fprintf(stderr, "Gamepad unhandled command: 0x%02x\n", command);
if(command == 0x42)
{
transmit_buffer[1] = 0xFF ^ buttons[0];
transmit_buffer[2] = 0xFF ^ buttons[1];
transmit_buffer[3] = twist; // Twist, 0x00 through 0xFF, 0x80 center.
transmit_buffer[4] = anabuttons[0]; // Analog button I, 0x00 through 0xFF, 0x00 = no pressing, 0xFF = max.
transmit_buffer[5] = anabuttons[1]; // Analog button II, ""
transmit_buffer[6] = anabuttons[2]; // Left shoulder analog button, ""
transmit_pos = 0;
transmit_count = 7;
dsr_pulse_delay = 256;
}
else
{
command_phase = -1;
transmit_buffer[1] = 0;
transmit_buffer[2] = 0;
transmit_pos = 0;
transmit_count = 0;
}
break;
case 2:
if(transmit_count > 0)
dsr_pulse_delay = 128;
break;
}
}
return(ret);
}
InputDevice *Device_neGcon_Create(void)
{
return new InputDevice_neGcon();
}
InputDeviceInputInfoStruct Device_neGcon_IDII[21] =
{
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ "start", "START", 4, IDIT_BUTTON, NULL },
{ "up", "D-Pad UP ↑", 0, IDIT_BUTTON, "down" },
{ "right", "D-Pad RIGHT →", 3, IDIT_BUTTON, "left" },
{ "down", "D-Pad DOWN ↓", 1, IDIT_BUTTON, "up" },
{ "left", "D-Pad LEFT ←", 2, IDIT_BUTTON, "right" },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ "r", "Right Shoulder", 12, IDIT_BUTTON },
{ "b", "B", 9, IDIT_BUTTON, NULL },
{ "a", "A", 10, IDIT_BUTTON, NULL },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ NULL, "empty", -1, IDIT_BUTTON, NULL },
{ "twist_cwise", "Twist ↓|↑ (Analog, Turn Right)", 6, IDIT_BUTTON_ANALOG },
{ "twist_ccwise", "Twist ↑|↓ (Analog, Turn Left)", 5, IDIT_BUTTON_ANALOG },
{ "i", "I (Analog)", 8, IDIT_BUTTON_ANALOG },
{ "ii", "II (Analog)", 7, IDIT_BUTTON_ANALOG },
{ "l", "Left Shoulder (Analog)", 11, IDIT_BUTTON_ANALOG },
};
}

View File

@ -0,0 +1,9 @@
#ifndef __MDFN_PSX_INPUT_NEGCON_H
#define __MDFN_PSX_INPUT_NEGCON_H
namespace MDFN_IEN_PSX
{
InputDevice *Device_neGcon_Create(void);
extern InputDeviceInputInfoStruct Device_neGcon_IDII[21];
}
#endif

View File

@ -432,6 +432,7 @@ uint32 MDEC_DMARead(void)
}
else
{
puts("BONUS GNOMES");
V = rand();
}
return(V);
@ -439,7 +440,7 @@ uint32 MDEC_DMARead(void)
bool MDEC_DMACanRead(void)
{
return (OutBuffer.CanRead() >= 2) || ((Command & 0xF5FF0000) != 0x30000000);
return(OutBuffer.CanRead() >= 2); //(OutBuffer.CanRead() >= 2) || ((Command & 0xF5FF0000) != 0x30000000);
}
void MDEC_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V)

View File

@ -22,6 +22,7 @@
#include "sio.h"
#include "cdc.h"
#include "spu.h"
#include "../mednafen-endian.h"
#include "../mempatcher.h"
#include "../PSFLoader.h"
#include "../player.h"
@ -111,116 +112,235 @@ static struct
};
} SysControl;
//
// Event stuff
//
static pscpu_timestamp_t next_timestamps[6];
// Comment out this define for extra speeeeed.
#define PSX_EVENT_SYSTEM_CHECKS 1
static pscpu_timestamp_t Running; // Set to -1 when not desiring exit, and 0 when we are.
struct event_list_entry
{
uint32 which;
pscpu_timestamp_t event_time;
event_list_entry *prev;
event_list_entry *next;
};
static event_list_entry events[PSX_EVENT__COUNT];
static void EventReset(void)
{
next_timestamps[PSX_EVENT_GPU] = PSX_EVENT_MAXTS;
next_timestamps[PSX_EVENT_CDC] = PSX_EVENT_MAXTS;
//next_timestamps[PSX_EVENT_SPU] = PSX_EVENT_MAXTS;
next_timestamps[PSX_EVENT_TIMER] = PSX_EVENT_MAXTS;
next_timestamps[PSX_EVENT_DMA] = PSX_EVENT_MAXTS;
next_timestamps[PSX_EVENT_FIO] = PSX_EVENT_MAXTS;
for(unsigned i = 0; i < PSX_EVENT__COUNT; i++)
{
events[i].which = i;
if(i == PSX_EVENT__SYNFIRST)
events[i].event_time = 0;
else if(i == PSX_EVENT__SYNLAST)
events[i].event_time = 0x7FFFFFFF;
else
events[i].event_time = PSX_EVENT_MAXTS;
events[i].prev = (i > 0) ? &events[i - 1] : NULL;
events[i].next = (i < (PSX_EVENT__COUNT - 1)) ? &events[i + 1] : NULL;
}
}
static INLINE pscpu_timestamp_t CalcNextTS(void)
{
pscpu_timestamp_t next_timestamp = next_timestamps[PSX_EVENT_GPU];
if(next_timestamp > next_timestamps[PSX_EVENT_CDC])
next_timestamp = next_timestamps[PSX_EVENT_CDC];
//if(next_timestamp > next_timestamps[PSX_EVENT_SPU])
// next_timestamp = next_timestamps[PSX_EVENT_SPU];
if(next_timestamp > next_timestamps[PSX_EVENT_TIMER])
next_timestamp = next_timestamps[PSX_EVENT_TIMER];
if(next_timestamp > next_timestamps[PSX_EVENT_DMA])
next_timestamp = next_timestamps[PSX_EVENT_DMA];
if(next_timestamp > next_timestamps[PSX_EVENT_FIO])
next_timestamp = next_timestamps[PSX_EVENT_FIO];
//printf("%d %d %d %d %d %d -- %08x\n", next_timestamps[PSX_EVENT_GPU], next_timestamps[PSX_EVENT_CDC], next_timestamps[PSX_EVENT_SPU], next_timestamps[PSX_EVENT_TIMER], next_timestamps[PSX_EVENT_DMA], next_timestamps[PSX_EVENT_FIO], next_timestamp);
return(next_timestamp);
}
//static void RemoveEvent(event_list_entry *e)
//{
// e->prev->next = e->next;
// e->next->prev = e->prev;
//}
static void RebaseTS(const pscpu_timestamp_t timestamp)
{
//printf("Rebase: %08x %08x %08x\n", timestamp, next_vip_ts, next_timestamps[PSX_EVENT_TIMER]);
assert(next_timestamps[PSX_EVENT_GPU] > timestamp);
assert(next_timestamps[PSX_EVENT_CDC] > timestamp);
//assert(next_timestamps[PSX_EVENT_SPU] > timestamp);
assert(next_timestamps[PSX_EVENT_TIMER] > timestamp);
assert(next_timestamps[PSX_EVENT_DMA] > timestamp);
assert(next_timestamps[PSX_EVENT_FIO] > timestamp);
for(unsigned i = 0; i < PSX_EVENT__COUNT; i++)
{
if(i == PSX_EVENT__SYNFIRST || i == PSX_EVENT__SYNLAST)
continue;
next_timestamps[PSX_EVENT_GPU] -= timestamp;
next_timestamps[PSX_EVENT_CDC] -= timestamp;
//next_timestamps[PSX_EVENT_SPU] -= timestamp;
next_timestamps[PSX_EVENT_TIMER] -= timestamp;
next_timestamps[PSX_EVENT_DMA] -= timestamp;
next_timestamps[PSX_EVENT_FIO] -= timestamp;
assert(events[i].event_time > timestamp);
events[i].event_time -= timestamp;
}
CPU->SetEventNT(CalcNextTS());
CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time);
}
void PSX_SetEventNT(const int type, const pscpu_timestamp_t next_timestamp)
{
//assert(next_timestamp > VB_V810->v810_timestamp);
assert(type > PSX_EVENT__SYNFIRST && type < PSX_EVENT__SYNLAST);
event_list_entry *e = &events[type];
assert(type >= 0 && type < 6);
if(next_timestamp < e->event_time)
{
event_list_entry *fe = e;
next_timestamps[type] = next_timestamp;
do
{
fe = fe->prev;
}
while(next_timestamp < fe->event_time);
if(next_timestamp < CPU->GetEventNT())
CPU->SetEventNT(next_timestamp);
// Remove this event from the list, temporarily of course.
e->prev->next = e->next;
e->next->prev = e->prev;
// Insert into the list, just after "fe".
e->prev = fe;
e->next = fe->next;
fe->next->prev = e;
fe->next = e;
e->event_time = next_timestamp;
}
else if(next_timestamp > e->event_time)
{
event_list_entry *fe = e;
do
{
fe = fe->next;
} while(next_timestamp > fe->event_time);
// Remove this event from the list, temporarily of course
e->prev->next = e->next;
e->next->prev = e->prev;
// Insert into the list, just BEFORE "fe".
e->prev = fe->prev;
e->next = fe;
fe->prev->next = e;
fe->prev = e;
e->event_time = next_timestamp;
}
CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time & Running);
}
static void ForceEventUpdates(const pscpu_timestamp_t timestamp)
{
next_timestamps[PSX_EVENT_GPU] = GPU->Update(timestamp);
next_timestamps[PSX_EVENT_CDC] = CDC->Update(timestamp);
//next_timestamps[PSX_EVENT_SPU] = SPU->Update(timestamp);
PSX_SetEventNT(PSX_EVENT_GPU, GPU->Update(timestamp));
PSX_SetEventNT(PSX_EVENT_CDC, CDC->Update(timestamp));
next_timestamps[PSX_EVENT_TIMER] = TIMER_Update(timestamp);
PSX_SetEventNT(PSX_EVENT_TIMER, TIMER_Update(timestamp));
next_timestamps[PSX_EVENT_DMA] = DMA_Update(timestamp);
PSX_SetEventNT(PSX_EVENT_DMA, DMA_Update(timestamp));
next_timestamps[PSX_EVENT_FIO] = FIO->Update(timestamp);
PSX_SetEventNT(PSX_EVENT_FIO, FIO->Update(timestamp));
CPU->SetEventNT(CalcNextTS());
CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time);
}
bool MDFN_FASTCALL PSX_EventHandler(const pscpu_timestamp_t timestamp)
{
event_list_entry *e = events[PSX_EVENT__SYNFIRST].next;
#ifdef PSX_EVENT_SYSTEM_CHECKS
pscpu_timestamp_t prev_event_time = 0;
#endif
#if 0
{
printf("EventHandler - timestamp=%8d\n", timestamp);
event_list_entry *moo = &events[PSX_EVENT__SYNFIRST];
while(moo)
{
printf("%u: %8d\n", moo->which, moo->event_time);
moo = moo->next;
}
}
#endif
#ifdef PSX_EVENT_SYSTEM_CHECKS
assert(Running == 0 || timestamp >= e->event_time); // If Running == 0, our EventHandler
#endif
while(timestamp >= e->event_time) // If Running = 0, PSX_EventHandler() may be called even if there isn't an event per-se, so while() instead of do { ... } while
{
event_list_entry *prev = e->prev;
pscpu_timestamp_t nt;
#ifdef PSX_EVENT_SYSTEM_CHECKS
// Sanity test to make sure events are being evaluated in temporal order.
if(e->event_time < prev_event_time)
abort();
prev_event_time = e->event_time;
#endif
//printf("Event: %u %8d\n", e->which, e->event_time);
#ifdef PSX_EVENT_SYSTEM_CHECKS
if((timestamp - e->event_time) > 50)
printf("Late: %u %d --- %8d\n", e->which, timestamp - e->event_time, timestamp);
#endif
switch(e->which)
{
default: abort();
case PSX_EVENT_GPU:
nt = GPU->Update(e->event_time);
break;
case PSX_EVENT_CDC:
nt = CDC->Update(e->event_time);
break;
case PSX_EVENT_TIMER:
nt = TIMER_Update(e->event_time);
break;
case PSX_EVENT_DMA:
nt = DMA_Update(e->event_time);
break;
case PSX_EVENT_FIO:
nt = FIO->Update(e->event_time);
break;
}
#ifdef PSX_EVENT_SYSTEM_CHECKS
assert(nt > e->event_time);
#endif
PSX_SetEventNT(e->which, nt);
// Order of events can change due to calling PSX_SetEventNT(), this prev business ensures we don't miss an event due to reordering.
e = prev->next;
}
#ifdef PSX_EVENT_SYSTEM_CHECKS
for(int i = PSX_EVENT__SYNFIRST + 1; i < PSX_EVENT__SYNLAST; i++)
{
if(timestamp >= events[i].event_time)
{
printf("BUG: %u\n", i);
event_list_entry *moo = &events[PSX_EVENT__SYNFIRST];
while(moo)
{
printf("%u: %8d\n", moo->which, moo->event_time);
moo = moo->next;
}
abort();
}
}
#endif
//#ifdef PSX_EVENT_SYSTEM_CHECKS
// abort();
//#endif
return(Running);
}
pscpu_timestamp_t MDFN_FASTCALL PSX_EventHandler(const pscpu_timestamp_t timestamp)
void PSX_RequestMLExit(void)
{
// FIXME: This seems rather inefficient.
if(timestamp >= next_timestamps[PSX_EVENT_GPU])
next_timestamps[PSX_EVENT_GPU] = GPU->Update(timestamp);
if(timestamp >= next_timestamps[PSX_EVENT_CDC])
next_timestamps[PSX_EVENT_CDC] = CDC->Update(timestamp);
//if(timestamp >= next_timestamps[PSX_EVENT_SPU])
// next_timestamps[PSX_EVENT_SPU] = SPU->Update(timestamp);
if(timestamp >= next_timestamps[PSX_EVENT_TIMER])
next_timestamps[PSX_EVENT_TIMER] = TIMER_Update(timestamp);
if(timestamp >= next_timestamps[PSX_EVENT_DMA])
next_timestamps[PSX_EVENT_DMA] = DMA_Update(timestamp);
if(timestamp >= next_timestamps[PSX_EVENT_FIO])
next_timestamps[PSX_EVENT_FIO] = FIO->Update(timestamp);
return(CalcNextTS());
Running = 0;
CPU->SetEventNT(0);
}
@ -308,6 +428,9 @@ template<typename T, bool IsWrite, bool Access24, bool Peek> static INLINE void
return;
}
if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time)
PSX_EventHandler(timestamp);
if(A >= 0x1F801000 && A <= 0x1F802FFF && !Peek) // Hardware register region. (TODO: Implement proper peek suppor)
{
#if 0
@ -598,7 +721,8 @@ uint32 PSX_MemPeek32(uint32 A)
return(V);
}
void PSX_Power(void)
// FIXME: Add PSX_Reset() and FrontIO::Reset() so that emulated input devices don't get power-reset on reset-button reset.
static void PSX_Power(void)
{
memset(MainRAM.data32, 0, 2048 * 1024);
memset(ScratchRAM.data32, 0, 1024);
@ -626,9 +750,10 @@ void PSX_Power(void)
ForceEventUpdates(0);
}
void PSX_RequestMLExit(void)
void PSX_GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock)
{
CPU->Exit();
FIO->GPULineHook(timestamp, line_timestamp, vsync, pixels, format, width, pix_clock_offset, pix_clock);
}
}
@ -640,6 +765,12 @@ static void Emulate(EmulateSpecStruct *espec)
{
pscpu_timestamp_t timestamp = 0;
if(FIO->RequireNoFrameskip())
{
//puts("MEOW");
espec->skip = false; //TODO: Save here, and restore at end of Emulate() ?
}
MDFNGameInfo->mouse_sensitivity = MDFN_GetSettingF("psx.input.mouse_sensitivity");
MDFNMP_ApplyPeriodicCheats();
@ -652,13 +783,16 @@ static void Emulate(EmulateSpecStruct *espec)
GPU->StartFrame(psf_loader ? NULL : espec);
SPU->StartFrame(espec->SoundRate, MDFN_GetSettingUI("psx.spu.resamp_quality"));
Running = -1;
timestamp = CPU->Run(timestamp, psf_loader != NULL);
//printf("Timestamp: %d\n", timestamp);
assert(timestamp);
ForceEventUpdates(timestamp);
if(GPU->GetScanlineNum() < 100)
printf("[BUUUUUUUG] Frame timing end glitch; scanline=%u, st=%u\n", GPU->GetScanlineNum(), timestamp);
//printf("scanline=%u, st=%u\n", GPU->GetScanlineNum(), timestamp);
espec->SoundBufSize = SPU->EndFrame(espec->SoundBuf);
@ -697,7 +831,7 @@ static void Emulate(EmulateSpecStruct *espec)
Memcard_SaveDelay[i] += timestamp;
if(Memcard_SaveDelay[i] >= (33868800 * 2)) // Wait until about 2 seconds of no new writes.
{
fprintf(stderr, "Saving memcard %d...\n", i);
//fprintf(stderr, "Saving memcard %d...\n", i);
try
{
char ext[64];
@ -711,7 +845,7 @@ static void Emulate(EmulateSpecStruct *espec)
MDFN_PrintError("Memcard %d save error: %s", i, e.what());
MDFN_DispMessage("Memcard %d save error: %s", i, e.what());
}
MDFN_DispMessage("Memcard %d saved.", i);
//MDFN_DispMessage("Memcard %d saved.", i);
}
}
}
@ -748,6 +882,14 @@ static bool TestMagic(const char *name, MDFNFILE *fp)
static bool TestMagicCD(std::vector<CDIF *> *CDInterfaces)
{
uint8 buf[2048];
CDUtility::TOC toc;
int dt;
(*CDInterfaces)[0]->ReadTOC(&toc);
dt = toc.FindTrackByLBA(4);
if(dt > 0 && !(toc.tracks[dt].control & 0x4))
return(false);
if((*CDInterfaces)[0]->ReadSector(buf, 4, 1) != 0x2)
return(false);
@ -765,6 +907,138 @@ static bool TestMagicCD(std::vector<CDIF *> *CDInterfaces)
return(true);
}
static const char *CalcDiscSCEx_BySYSTEMCNF(CDIF *c, unsigned *rr)
{
const char *ret = NULL;
Stream *fp = NULL;
CDUtility::TOC toc;
//(*CDInterfaces)[disc]->ReadTOC(&toc);
//if(toc.first_track > 1 || toc.
try
{
uint8 pvd[2048];
unsigned pvd_search_count = 0;
fp = c->MakeStream(0, ~0U);
fp->seek(0x8000, SEEK_SET);
do
{
if((pvd_search_count++) == 32)
throw MDFN_Error(0, "PVD search count limit met.");
fp->read(pvd, 2048);
if(memcmp(&pvd[1], "CD001", 5))
throw MDFN_Error(0, "Not ISO-9660");
if(pvd[0] == 0xFF)
throw MDFN_Error(0, "Missing Primary Volume Descriptor");
} while(pvd[0] != 0x01);
//[156 ... 189], 34 bytes
uint32 rdel = MDFN_de32lsb(&pvd[0x9E]);
uint32 rdel_len = MDFN_de32lsb(&pvd[0xA6]);
if(rdel_len >= (1024 * 1024 * 10)) // Arbitrary sanity check.
throw MDFN_Error(0, "Root directory table too large");
fp->seek((int64)rdel * 2048, SEEK_SET);
//printf("%08x, %08x\n", rdel * 2048, rdel_len);
while(fp->tell() < (((int64)rdel * 2048) + rdel_len))
{
uint8 len_dr = fp->get_u8();
uint8 dr[256 + 1];
memset(dr, 0xFF, sizeof(dr));
if(!len_dr)
break;
memset(dr, 0, sizeof(dr));
dr[0] = len_dr;
fp->read(dr + 1, len_dr - 1);
uint8 len_fi = dr[0x20];
if(len_fi == 12 && !memcmp(&dr[0x21], "SYSTEM.CNF;1", 12))
{
uint32 file_lba = MDFN_de32lsb(&dr[0x02]);
//uint32 file_len = MDFN_de32lsb(&dr[0x0A]);
uint8 fb[2048 + 1];
char *bootpos;
memset(fb, 0, sizeof(fb));
fp->seek(file_lba * 2048, SEEK_SET);
fp->read(fb, 2048);
bootpos = strstr((char*)fb, "BOOT") + 4;
while(*bootpos == ' ' || *bootpos == '\t') bootpos++;
if(*bootpos == '=')
{
bootpos++;
while(*bootpos == ' ' || *bootpos == '\t') bootpos++;
if(!strncasecmp(bootpos, "cdrom:\\", 7))
{
bootpos += 7;
char *tmp;
if((tmp = strchr(bootpos, '_'))) *tmp = 0;
if((tmp = strchr(bootpos, '.'))) *tmp = 0;
if((tmp = strchr(bootpos, ';'))) *tmp = 0;
//puts(bootpos);
if(strlen(bootpos) == 4 && bootpos[0] == 'S' && (bootpos[1] == 'C' || bootpos[1] == 'L' || bootpos[1] == 'I'))
{
switch(bootpos[2])
{
case 'E': if(rr)
*rr = REGION_EU;
ret = "SCEE";
goto Breakout;
case 'U': if(rr)
*rr = REGION_NA;
ret = "SCEA";
goto Breakout;
case 'K': // Korea?
case 'B':
case 'P': if(rr)
*rr = REGION_JP;
ret = "SCEI";
goto Breakout;
}
}
}
}
//puts((char*)fb);
//puts("ASOFKOASDFKO");
}
}
}
catch(std::exception &e)
{
//puts(e.what());
}
catch(...)
{
}
Breakout:
if(fp != NULL)
{
delete fp;
fp = NULL;
}
return(ret);
}
static unsigned CalcDiscSCEx(void)
{
const char *prev_valid_id = NULL;
@ -780,9 +1054,12 @@ if(cdifs)
uint8 fbuf[2048 + 1];
unsigned ipos, opos;
id = CalcDiscSCEx_BySYSTEMCNF((*cdifs)[i], (i == 0) ? &ret_region : NULL);
memset(fbuf, 0, sizeof(fbuf));
if((*cdifs)[i]->ReadSector(buf, 4, 1) == 0x2)
if(id == NULL && (*cdifs)[i]->ReadSector(buf, 4, 1) == 0x2)
{
for(ipos = 0, opos = 0; ipos < 0x48; ipos++)
{
@ -865,14 +1142,14 @@ static bool InitCommon(std::vector<CDIF *> *CDInterfaces, const bool EmulateMemc
for(unsigned i = 0; i < 8; i++)
{
char buf[64];
trio_snprintf(buf, sizeof(buf), "psx.input.port%d.memcard", i + 1);
trio_snprintf(buf, sizeof(buf), "psx.input.port%u.memcard", i + 1);
emulate_memcard[i] = EmulateMemcards && MDFN_GetSettingB(buf);
}
for(unsigned i = 0; i < 2; i++)
{
char buf[64];
trio_snprintf(buf, sizeof(buf), "psx.input.port%d.multitap", i + 1);
trio_snprintf(buf, sizeof(buf), "psx.input.port%u.multitap", i + 1);
emulate_multitap[i] = MDFN_GetSettingB(buf);
}
@ -888,6 +1165,14 @@ static bool InitCommon(std::vector<CDIF *> *CDInterfaces, const bool EmulateMemc
GPU = new PS_GPU(region == REGION_EU);
CDC = new PS_CDC();
FIO = new FrontIO(emulate_memcard, emulate_multitap);
FIO->SetAMCT(MDFN_GetSettingB("psx.input.analog_mode_ct"));
for(unsigned i = 0; i < 8; i++)
{
char buf[64];
trio_snprintf(buf, sizeof(buf), "psx.input.port%u.gun_chairs", i + 1);
FIO->SetCrosshairsColor(i, MDFN_GetSettingUI(buf));
}
DMA_Init();
if(region == REGION_EU)
@ -895,7 +1180,7 @@ static bool InitCommon(std::vector<CDIF *> *CDInterfaces, const bool EmulateMemc
EmulatedPSX.nominal_width = 367; // Dunno. :(
EmulatedPSX.nominal_height = 288;
EmulatedPSX.fb_width = 1024;
EmulatedPSX.fb_width = 768;
EmulatedPSX.fb_height = 576;
}
else
@ -903,10 +1188,10 @@ static bool InitCommon(std::vector<CDIF *> *CDInterfaces, const bool EmulateMemc
EmulatedPSX.lcm_width = 2720;
EmulatedPSX.lcm_height = 480;
EmulatedPSX.nominal_width = 306;
EmulatedPSX.nominal_width = 310;
EmulatedPSX.nominal_height = 240;
EmulatedPSX.fb_width = 1024;
EmulatedPSX.fb_width = 768;
EmulatedPSX.fb_height = 480;
}
@ -1169,13 +1454,19 @@ static int Load(const char *name, MDFNFILE *fp)
const bool IsPSF = PSFLoader::TestMagic(0x01, fp);
if(!TestMagic(name, fp))
{
MDFN_PrintError(_("File format is unknown to module \"%s\"."), MDFNGameInfo->shortname);
return(0);
}
// For testing.
#if 0
#warning "GREMLINS GREMLINS EVERYWHEREE IYEEEEEE"
#warning "Seriously, GREMLINS! Or peanut butter. Or maybe...DINOSAURS."
static std::vector<CDIF *> CDInterfaces;
CDInterfaces.push_back(new CDIF("/extra/games/PSX/Jumping Flash! (USA)/Jumping Flash! (USA).cue"));
CDInterfaces.push_back(new CDIF_MT("/extra/games/PSX/Jumping Flash! (USA)/Jumping Flash! (USA).cue"));
//CDInterfaces.push_back(new CDIF("/extra/games/PSX/Tony Hawk's Pro Skater 2 (USA)/Tony Hawk's Pro Skater 2 (USA).cue"));
if(!InitCommon(&CDInterfaces, !IsPSF))
@ -1218,7 +1509,7 @@ static int LoadCD(std::vector<CDIF *> *CDInterfaces)
// TODO: fastboot setting
if(MDFN_GetSettingB("psx.fastboot"))
BIOSROM->WriteU32(0x6990, 0);
BIOSROM->WriteU32(0x6990, 0);
MDFNGameInfo->GameType = GMT_CDROM;
@ -1310,7 +1601,10 @@ static void CloseGame(void)
static void SetInput(int port, const char *type, void *ptr)
{
FIO->SetInput(port, type, ptr);
if(psf_loader)
FIO->SetInput(port, "none", NULL);
else
FIO->SetInput(port, type, ptr);
}
static int StateAction(StateMem *sm, int load, int data_only)
@ -1323,7 +1617,7 @@ static int StateAction(StateMem *sm, int load, int data_only)
SFARRAY(MainRAM.data8, 1024 * 2048),
SFARRAY(ScratchRAM.data8, 1024),
SFARRAY32(SysControl.Regs, 9),
SFARRAY32(next_timestamps, sizeof(next_timestamps) / sizeof(next_timestamps[0])),
//SFARRAY32(next_timestamps, sizeof(next_timestamps) / sizeof(next_timestamps[0])),
SFEND
};
@ -1444,6 +1738,8 @@ static MDFNSetting PSXSettings[] =
{
{ "psx.input.mouse_sensitivity", MDFNSF_NOFLAGS, gettext_noop("Emulated mouse sensitivity."), NULL, MDFNST_FLOAT, "1.00", NULL, NULL },
{ "psx.input.analog_mode_ct", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Enable analog mode combo-button alternate toggle."), gettext_noop("When enabled, instead of the configured Analog mode toggle button for the emulated DualShock, use a combination of buttons to toggle it instead. When Select, Start, and all four shoulder buttons are held down for about 1 second, the mode will toggle."), MDFNST_BOOL, "0", NULL, NULL },
{ "psx.input.port1.multitap", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Enable multitap on PSX port 1."), gettext_noop("Makes ports 1B-1D available."), MDFNST_BOOL, "0", NULL, NULL },
{ "psx.input.port2.multitap", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Enable multitap on PSX port 2."), gettext_noop("Makes ports 2B-2D available."), MDFNST_BOOL, "0", NULL, NULL },
@ -1457,7 +1753,16 @@ static MDFNSetting PSXSettings[] =
{ "psx.input.port8.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memcard on port 2D."), NULL, MDFNST_BOOL, "1", NULL, NULL, },
{ "psx.fastboot", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Skip BIOS intro sequence."), gettext_noop("MAY BREAK GAMES."), MDFNST_BOOL, "1" },
{ "psx.input.port1.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on port 1/1A."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0xFF0000", "0x000000", "0x1000000" },
{ "psx.input.port2.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on port 2/2A."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x00FF00", "0x000000", "0x1000000" },
{ "psx.input.port3.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on port 1B."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0xFF00FF", "0x000000", "0x1000000" },
{ "psx.input.port4.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on port 1C."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0xFF8000", "0x000000", "0x1000000" },
{ "psx.input.port5.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on port 1D."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0xFFFF00", "0x000000", "0x1000000" },
{ "psx.input.port6.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on port 2B."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x00FFFF", "0x000000", "0x1000000" },
{ "psx.input.port7.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on port 2C."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x0080FF", "0x000000", "0x1000000" },
{ "psx.input.port8.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on port 2D."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x8000FF", "0x000000", "0x1000000" },
{ "psx.fastboot", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Skip BIOS intro sequence."), gettext_noop("MAY BREAK GAMES."), MDFNST_BOOL, "0" },
{ "psx.region_autodetect", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Attempt to auto-detect region of game."), NULL, MDFNST_BOOL, "1" },
{ "psx.region_default", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Default region to use."), gettext_noop("Used if region autodetection fails or is disabled."), MDFNST_ENUM, "jp", NULL, NULL, NULL, NULL, Region_List },
@ -1470,7 +1775,9 @@ static MDFNSetting PSXSettings[] =
{ NULL },
};
// Note for the future: If we ever support PSX emulation with non-8-bit RGB color components, or add a new linear RGB colorspace to MDFN_PixelFormat, we'll need
// to buffer the intermediate 24-bit non-linear RGB calculation into an array and pass that into the GPULineHook stuff, otherwise netplay could break when
// an emulated GunCon is used. This IS assuming, of course, that we ever implement save state support so that netplay actually works at all...
MDFNGI EmulatedPSX =
{
"psx",
@ -1489,7 +1796,7 @@ MDFNGI EmulatedPSX =
TestMagicCD,
CloseGame,
NULL, //ToggleLayer,
NULL, //"Background Scroll\0Foreground Scroll\0Sprites\0",
"GPU\0", //"Background Scroll\0Foreground Scroll\0Sprites\0",
NULL,
NULL,
NULL,
@ -1513,7 +1820,7 @@ MDFNGI EmulatedPSX =
0, // lcm_height
NULL, // Dummy
306, // Nominal width
310, // Nominal width
240, // Nominal height
0, // Framebuffer width

View File

@ -9,19 +9,16 @@
#include "../general.h"
#include "../FileWrapper.h"
#ifdef DEBUG
#define PSX_WARNING(format, ...) { printf(format "\n", ## __VA_ARGS__); }
#define PSX_DBGINFO(format, ...) { /*printf(format "\n", ## __VA_ARGS__);*/ }
#else
#define PSX_WARNING(format, ...) ((void)0)
#define PSX_DBGINFO(format, ...) ((void)0)
#endif
//#define PSX_WARNING(format, ...) { printf(format "\n", ## __VA_ARGS__); }
//#define PSX_DBGINFO(format, ...) { /*printf(format "\n", ## __VA_ARGS__);*/ }
#define PSX_WARNING(format, ...)
#define PSX_DBGINFO(format, ...)
namespace MDFN_IEN_PSX
{
typedef int32 pscpu_timestamp_t;
pscpu_timestamp_t MDFN_FASTCALL PSX_EventHandler(const pscpu_timestamp_t timestamp);
bool MDFN_FASTCALL PSX_EventHandler(const pscpu_timestamp_t timestamp);
void MDFN_FASTCALL PSX_MemWrite8(const pscpu_timestamp_t timestamp, uint32 A, uint32 V);
void MDFN_FASTCALL PSX_MemWrite16(const pscpu_timestamp_t timestamp, uint32 A, uint32 V);
@ -46,19 +43,23 @@ namespace MDFN_IEN_PSX
void PSX_RequestMLExit(void);
// Insert new event types at end, not in the beginning or middile.
enum
{
PSX_EVENT_GPU = 0,
PSX_EVENT__SYNFIRST = 0,
PSX_EVENT_GPU,
PSX_EVENT_CDC,
PSX_EVENT_SPU,
//PSX_EVENT_SPU,
PSX_EVENT_TIMER,
PSX_EVENT_DMA,
PSX_EVENT_FIO,
PSX_EVENT__SYNLAST,
PSX_EVENT__COUNT,
};
#define PSX_EVENT_MAXTS 0x20000000
void PSX_SetEventNT(const int type, const pscpu_timestamp_t next_timestamp);
void PSX_GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock);
};

View File

@ -1,256 +1,256 @@
{ 0x12c7, 0x59b3, 0x1307, 0xffff },
{ 0x1288, 0x59b2, 0x1347, 0xffff },
{ 0x1249, 0x59b0, 0x1388, 0xffff },
{ 0x120b, 0x59ad, 0x13c9, 0xffff },
{ 0x11cd, 0x59a9, 0x140b, 0xffff },
{ 0x118f, 0x59a4, 0x144d, 0xffff },
{ 0x1153, 0x599e, 0x1490, 0xffff },
{ 0x1116, 0x5997, 0x14d4, 0xffff },
{ 0x10db, 0x598f, 0x1517, 0xffff },
{ 0x109f, 0x5986, 0x155c, 0xffff },
{ 0x1065, 0x597c, 0x15a0, 0xffff },
{ 0x102a, 0x5971, 0x15e6, 0xffff },
{ 0x0ff1, 0x5965, 0x162c, 0xffff },
{ 0x0fb7, 0x5958, 0x1672, 0xffff },
{ 0x0f7f, 0x5949, 0x16b9, 0xffff },
{ 0x0f46, 0x593a, 0x1700, 0xffff },
{ 0x0f0f, 0x592a, 0x1747, 0x0000 },
{ 0x0ed7, 0x5919, 0x1790, 0x0000 },
{ 0x0ea1, 0x5907, 0x17d8, 0x0000 },
{ 0x0e6b, 0x58f4, 0x1821, 0x0000 },
{ 0x0e35, 0x58e0, 0x186b, 0x0000 },
{ 0x0e00, 0x58cb, 0x18b5, 0x0000 },
{ 0x0dcb, 0x58b5, 0x1900, 0x0000 },
{ 0x0d97, 0x589e, 0x194b, 0x0001 },
{ 0x0d63, 0x5886, 0x1996, 0x0001 },
{ 0x0d30, 0x586d, 0x19e2, 0x0001 },
{ 0x0cfd, 0x5853, 0x1a2e, 0x0001 },
{ 0x0ccb, 0x5838, 0x1a7b, 0x0002 },
{ 0x0c99, 0x581c, 0x1ac8, 0x0002 },
{ 0x0c68, 0x57ff, 0x1b16, 0x0002 },
{ 0x0c38, 0x57e2, 0x1b64, 0x0003 },
{ 0x0c07, 0x57c3, 0x1bb3, 0x0003 },
{ 0x0bd8, 0x57a3, 0x1c02, 0x0003 },
{ 0x0ba9, 0x5782, 0x1c51, 0x0004 },
{ 0x0b7a, 0x5761, 0x1ca1, 0x0004 },
{ 0x0b4c, 0x573e, 0x1cf1, 0x0005 },
{ 0x0b1e, 0x571b, 0x1d42, 0x0005 },
{ 0x0af1, 0x56f6, 0x1d93, 0x0006 },
{ 0x0ac4, 0x56d1, 0x1de5, 0x0007 },
{ 0x0a98, 0x56ab, 0x1e37, 0x0007 },
{ 0x0a6c, 0x5684, 0x1e89, 0x0008 },
{ 0x0a40, 0x565b, 0x1edc, 0x0009 },
{ 0x0a16, 0x5632, 0x1f2f, 0x0009 },
{ 0x09eb, 0x5609, 0x1f82, 0x000a },
{ 0x09c1, 0x55de, 0x1fd6, 0x000b },
{ 0x0998, 0x55b2, 0x202a, 0x000c },
{ 0x096f, 0x5585, 0x207f, 0x000d },
{ 0x0946, 0x5558, 0x20d4, 0x000e },
{ 0x091e, 0x5529, 0x2129, 0x000f },
{ 0x08f7, 0x54fa, 0x217f, 0x0010 },
{ 0x08d0, 0x54ca, 0x21d5, 0x0011 },
{ 0x08a9, 0x5499, 0x222c, 0x0012 },
{ 0x0883, 0x5467, 0x2282, 0x0013 },
{ 0x085d, 0x5434, 0x22da, 0x0015 },
{ 0x0838, 0x5401, 0x2331, 0x0016 },
{ 0x0813, 0x53cc, 0x2389, 0x0018 },
{ 0x07ef, 0x5397, 0x23e1, 0x0019 },
{ 0x07cb, 0x5361, 0x2439, 0x001b },
{ 0x07a7, 0x532a, 0x2492, 0x001c },
{ 0x0784, 0x52f3, 0x24eb, 0x001e },
{ 0x0762, 0x52ba, 0x2545, 0x0020 },
{ 0x0740, 0x5281, 0x259e, 0x0021 },
{ 0x071e, 0x5247, 0x25f8, 0x0023 },
{ 0x06fd, 0x520c, 0x2653, 0x0025 },
{ 0x06dc, 0x51d0, 0x26ad, 0x0027 },
{ 0x06bb, 0x5194, 0x2708, 0x0029 },
{ 0x069b, 0x5156, 0x2763, 0x002c },
{ 0x067c, 0x5118, 0x27be, 0x002e },
{ 0x065c, 0x50da, 0x281a, 0x0030 },
{ 0x063e, 0x509a, 0x2876, 0x0033 },
{ 0x061f, 0x505a, 0x28d2, 0x0035 },
{ 0x0601, 0x5019, 0x292e, 0x0038 },
{ 0x05e4, 0x4fd7, 0x298b, 0x003a },
{ 0x05c7, 0x4f95, 0x29e7, 0x003d },
{ 0x05aa, 0x4f52, 0x2a44, 0x0040 },
{ 0x058e, 0x4f0e, 0x2aa1, 0x0043 },
{ 0x0572, 0x4ec9, 0x2aff, 0x0046 },
{ 0x0556, 0x4e84, 0x2b5c, 0x0049 },
{ 0x053b, 0x4e3e, 0x2bba, 0x004d },
{ 0x0520, 0x4df7, 0x2c18, 0x0050 },
{ 0x0506, 0x4db0, 0x2c76, 0x0054 },
{ 0x04ec, 0x4d68, 0x2cd4, 0x0057 },
{ 0x04d2, 0x4d20, 0x2d33, 0x005b },
{ 0x04b9, 0x4cd7, 0x2d91, 0x005f },
{ 0x04a0, 0x4c8d, 0x2df0, 0x0063 },
{ 0x0488, 0x4c42, 0x2e4f, 0x0067 },
{ 0x0470, 0x4bf7, 0x2eae, 0x006b },
{ 0x0458, 0x4bac, 0x2f0d, 0x006f },
{ 0x0441, 0x4b5f, 0x2f6c, 0x0074 },
{ 0x042a, 0x4b13, 0x2fcc, 0x0078 },
{ 0x0413, 0x4ac5, 0x302b, 0x007d },
{ 0x03fc, 0x4a77, 0x308b, 0x0082 },
{ 0x03e7, 0x4a29, 0x30ea, 0x0087 },
{ 0x03d1, 0x49d9, 0x314a, 0x008c },
{ 0x03bc, 0x498a, 0x31aa, 0x0091 },
{ 0x03a7, 0x493a, 0x3209, 0x0096 },
{ 0x0392, 0x48e9, 0x3269, 0x009c },
{ 0x037e, 0x4898, 0x32c9, 0x00a1 },
{ 0x036a, 0x4846, 0x3329, 0x00a7 },
{ 0x0356, 0x47f4, 0x3389, 0x00ad },
{ 0x0343, 0x47a1, 0x33e9, 0x00b3 },
{ 0x0330, 0x474e, 0x3449, 0x00ba },
{ 0x031d, 0x46fa, 0x34a9, 0x00c0 },
{ 0x030b, 0x46a6, 0x3509, 0x00c7 },
{ 0x02f9, 0x4651, 0x3569, 0x00cd },
{ 0x02e7, 0x45fc, 0x35c9, 0x00d4 },
{ 0x02d6, 0x45a6, 0x3629, 0x00db },
{ 0x02c4, 0x4550, 0x3689, 0x00e3 },
{ 0x02b4, 0x44fa, 0x36e8, 0x00ea },
{ 0x02a3, 0x44a3, 0x3748, 0x00f2 },
{ 0x0293, 0x444c, 0x37a8, 0x00fa },
{ 0x0283, 0x43f4, 0x3807, 0x0101 },
{ 0x0273, 0x439c, 0x3867, 0x010a },
{ 0x0264, 0x4344, 0x38c6, 0x0112 },
{ 0x0255, 0x42eb, 0x3926, 0x011b },
{ 0x0246, 0x4292, 0x3985, 0x0123 },
{ 0x0237, 0x4239, 0x39e4, 0x012c },
{ 0x0229, 0x41df, 0x3a43, 0x0135 },
{ 0x021b, 0x4185, 0x3aa2, 0x013f },
{ 0x020d, 0x412a, 0x3b00, 0x0148 },
{ 0x0200, 0x40d0, 0x3b5f, 0x0152 },
{ 0x01f2, 0x4074, 0x3bbd, 0x015c },
{ 0x01e5, 0x4019, 0x3c1b, 0x0166 },
{ 0x01d9, 0x3fbd, 0x3c79, 0x0171 },
{ 0x01cc, 0x3f62, 0x3cd7, 0x017b },
{ 0x01c0, 0x3f05, 0x3d35, 0x0186 },
{ 0x01b4, 0x3ea9, 0x3d92, 0x0191 },
{ 0x01a8, 0x3e4c, 0x3def, 0x019c },
{ 0x019c, 0x3def, 0x3e4c, 0x01a8 },
{ 0x0191, 0x3d92, 0x3ea9, 0x01b4 },
{ 0x0186, 0x3d35, 0x3f05, 0x01c0 },
{ 0x017b, 0x3cd7, 0x3f62, 0x01cc },
{ 0x0171, 0x3c79, 0x3fbd, 0x01d9 },
{ 0x0166, 0x3c1b, 0x4019, 0x01e5 },
{ 0x015c, 0x3bbd, 0x4074, 0x01f2 },
{ 0x0152, 0x3b5f, 0x40d0, 0x0200 },
{ 0x0148, 0x3b00, 0x412a, 0x020d },
{ 0x013f, 0x3aa2, 0x4185, 0x021b },
{ 0x0135, 0x3a43, 0x41df, 0x0229 },
{ 0x012c, 0x39e4, 0x4239, 0x0237 },
{ 0x0123, 0x3985, 0x4292, 0x0246 },
{ 0x011b, 0x3926, 0x42eb, 0x0255 },
{ 0x0112, 0x38c6, 0x4344, 0x0264 },
{ 0x010a, 0x3867, 0x439c, 0x0273 },
{ 0x0101, 0x3807, 0x43f4, 0x0283 },
{ 0x00fa, 0x37a8, 0x444c, 0x0293 },
{ 0x00f2, 0x3748, 0x44a3, 0x02a3 },
{ 0x00ea, 0x36e8, 0x44fa, 0x02b4 },
{ 0x00e3, 0x3689, 0x4550, 0x02c4 },
{ 0x00db, 0x3629, 0x45a6, 0x02d6 },
{ 0x00d4, 0x35c9, 0x45fc, 0x02e7 },
{ 0x00cd, 0x3569, 0x4651, 0x02f9 },
{ 0x00c7, 0x3509, 0x46a6, 0x030b },
{ 0x00c0, 0x34a9, 0x46fa, 0x031d },
{ 0x00ba, 0x3449, 0x474e, 0x0330 },
{ 0x00b3, 0x33e9, 0x47a1, 0x0343 },
{ 0x00ad, 0x3389, 0x47f4, 0x0356 },
{ 0x00a7, 0x3329, 0x4846, 0x036a },
{ 0x00a1, 0x32c9, 0x4898, 0x037e },
{ 0x009c, 0x3269, 0x48e9, 0x0392 },
{ 0x0096, 0x3209, 0x493a, 0x03a7 },
{ 0x0091, 0x31aa, 0x498a, 0x03bc },
{ 0x008c, 0x314a, 0x49d9, 0x03d1 },
{ 0x0087, 0x30ea, 0x4a29, 0x03e7 },
{ 0x0082, 0x308b, 0x4a77, 0x03fc },
{ 0x007d, 0x302b, 0x4ac5, 0x0413 },
{ 0x0078, 0x2fcc, 0x4b13, 0x042a },
{ 0x0074, 0x2f6c, 0x4b5f, 0x0441 },
{ 0x006f, 0x2f0d, 0x4bac, 0x0458 },
{ 0x006b, 0x2eae, 0x4bf7, 0x0470 },
{ 0x0067, 0x2e4f, 0x4c42, 0x0488 },
{ 0x0063, 0x2df0, 0x4c8d, 0x04a0 },
{ 0x005f, 0x2d91, 0x4cd7, 0x04b9 },
{ 0x005b, 0x2d33, 0x4d20, 0x04d2 },
{ 0x0057, 0x2cd4, 0x4d68, 0x04ec },
{ 0x0054, 0x2c76, 0x4db0, 0x0506 },
{ 0x0050, 0x2c18, 0x4df7, 0x0520 },
{ 0x004d, 0x2bba, 0x4e3e, 0x053b },
{ 0x0049, 0x2b5c, 0x4e84, 0x0556 },
{ 0x0046, 0x2aff, 0x4ec9, 0x0572 },
{ 0x0043, 0x2aa1, 0x4f0e, 0x058e },
{ 0x0040, 0x2a44, 0x4f52, 0x05aa },
{ 0x003d, 0x29e7, 0x4f95, 0x05c7 },
{ 0x003a, 0x298b, 0x4fd7, 0x05e4 },
{ 0x0038, 0x292e, 0x5019, 0x0601 },
{ 0x0035, 0x28d2, 0x505a, 0x061f },
{ 0x0033, 0x2876, 0x509a, 0x063e },
{ 0x0030, 0x281a, 0x50da, 0x065c },
{ 0x002e, 0x27be, 0x5118, 0x067c },
{ 0x002c, 0x2763, 0x5156, 0x069b },
{ 0x0029, 0x2708, 0x5194, 0x06bb },
{ 0x0027, 0x26ad, 0x51d0, 0x06dc },
{ 0x0025, 0x2653, 0x520c, 0x06fd },
{ 0x0023, 0x25f8, 0x5247, 0x071e },
{ 0x0021, 0x259e, 0x5281, 0x0740 },
{ 0x0020, 0x2545, 0x52ba, 0x0762 },
{ 0x001e, 0x24eb, 0x52f3, 0x0784 },
{ 0x001c, 0x2492, 0x532a, 0x07a7 },
{ 0x001b, 0x2439, 0x5361, 0x07cb },
{ 0x0019, 0x23e1, 0x5397, 0x07ef },
{ 0x0018, 0x2389, 0x53cc, 0x0813 },
{ 0x0016, 0x2331, 0x5401, 0x0838 },
{ 0x0015, 0x22da, 0x5434, 0x085d },
{ 0x0013, 0x2282, 0x5467, 0x0883 },
{ 0x0012, 0x222c, 0x5499, 0x08a9 },
{ 0x0011, 0x21d5, 0x54ca, 0x08d0 },
{ 0x0010, 0x217f, 0x54fa, 0x08f7 },
{ 0x000f, 0x2129, 0x5529, 0x091e },
{ 0x000e, 0x20d4, 0x5558, 0x0946 },
{ 0x000d, 0x207f, 0x5585, 0x096f },
{ 0x000c, 0x202a, 0x55b2, 0x0998 },
{ 0x000b, 0x1fd6, 0x55de, 0x09c1 },
{ 0x000a, 0x1f82, 0x5609, 0x09eb },
{ 0x0009, 0x1f2f, 0x5632, 0x0a16 },
{ 0x0009, 0x1edc, 0x565b, 0x0a40 },
{ 0x0008, 0x1e89, 0x5684, 0x0a6c },
{ 0x0007, 0x1e37, 0x56ab, 0x0a98 },
{ 0x0007, 0x1de5, 0x56d1, 0x0ac4 },
{ 0x0006, 0x1d93, 0x56f6, 0x0af1 },
{ 0x0005, 0x1d42, 0x571b, 0x0b1e },
{ 0x0005, 0x1cf1, 0x573e, 0x0b4c },
{ 0x0004, 0x1ca1, 0x5761, 0x0b7a },
{ 0x0004, 0x1c51, 0x5782, 0x0ba9 },
{ 0x0003, 0x1c02, 0x57a3, 0x0bd8 },
{ 0x0003, 0x1bb3, 0x57c3, 0x0c07 },
{ 0x0003, 0x1b64, 0x57e2, 0x0c38 },
{ 0x0002, 0x1b16, 0x57ff, 0x0c68 },
{ 0x0002, 0x1ac8, 0x581c, 0x0c99 },
{ 0x0002, 0x1a7b, 0x5838, 0x0ccb },
{ 0x0001, 0x1a2e, 0x5853, 0x0cfd },
{ 0x0001, 0x19e2, 0x586d, 0x0d30 },
{ 0x0001, 0x1996, 0x5886, 0x0d63 },
{ 0x0001, 0x194b, 0x589e, 0x0d97 },
{ 0x0000, 0x1900, 0x58b5, 0x0dcb },
{ 0x0000, 0x18b5, 0x58cb, 0x0e00 },
{ 0x0000, 0x186b, 0x58e0, 0x0e35 },
{ 0x0000, 0x1821, 0x58f4, 0x0e6b },
{ 0x0000, 0x17d8, 0x5907, 0x0ea1 },
{ 0x0000, 0x1790, 0x5919, 0x0ed7 },
{ 0x0000, 0x1747, 0x592a, 0x0f0f },
{ 0xffff, 0x1700, 0x593a, 0x0f46 },
{ 0xffff, 0x16b9, 0x5949, 0x0f7f },
{ 0xffff, 0x1672, 0x5958, 0x0fb7 },
{ 0xffff, 0x162c, 0x5965, 0x0ff1 },
{ 0xffff, 0x15e6, 0x5971, 0x102a },
{ 0xffff, 0x15a0, 0x597c, 0x1065 },
{ 0xffff, 0x155c, 0x5986, 0x109f },
{ 0xffff, 0x1517, 0x598f, 0x10db },
{ 0xffff, 0x14d4, 0x5997, 0x1116 },
{ 0xffff, 0x1490, 0x599e, 0x1153 },
{ 0xffff, 0x144d, 0x59a4, 0x118f },
{ 0xffff, 0x140b, 0x59a9, 0x11cd },
{ 0xffff, 0x13c9, 0x59ad, 0x120b },
{ 0xffff, 0x1388, 0x59b0, 0x1249 },
{ 0xffff, 0x1347, 0x59b2, 0x1288 },
{ 0xffff, 0x1307, 0x59b3, 0x12c7 },
{ (int16)0x12c7, (int16)0x59b3, (int16)0x1307, (int16)0xffff },
{ (int16)0x1288, (int16)0x59b2, (int16)0x1347, (int16)0xffff },
{ (int16)0x1249, (int16)0x59b0, (int16)0x1388, (int16)0xffff },
{ (int16)0x120b, (int16)0x59ad, (int16)0x13c9, (int16)0xffff },
{ (int16)0x11cd, (int16)0x59a9, (int16)0x140b, (int16)0xffff },
{ (int16)0x118f, (int16)0x59a4, (int16)0x144d, (int16)0xffff },
{ (int16)0x1153, (int16)0x599e, (int16)0x1490, (int16)0xffff },
{ (int16)0x1116, (int16)0x5997, (int16)0x14d4, (int16)0xffff },
{ (int16)0x10db, (int16)0x598f, (int16)0x1517, (int16)0xffff },
{ (int16)0x109f, (int16)0x5986, (int16)0x155c, (int16)0xffff },
{ (int16)0x1065, (int16)0x597c, (int16)0x15a0, (int16)0xffff },
{ (int16)0x102a, (int16)0x5971, (int16)0x15e6, (int16)0xffff },
{ (int16)0x0ff1, (int16)0x5965, (int16)0x162c, (int16)0xffff },
{ (int16)0x0fb7, (int16)0x5958, (int16)0x1672, (int16)0xffff },
{ (int16)0x0f7f, (int16)0x5949, (int16)0x16b9, (int16)0xffff },
{ (int16)0x0f46, (int16)0x593a, (int16)0x1700, (int16)0xffff },
{ (int16)0x0f0f, (int16)0x592a, (int16)0x1747, (int16)0x0000 },
{ (int16)0x0ed7, (int16)0x5919, (int16)0x1790, (int16)0x0000 },
{ (int16)0x0ea1, (int16)0x5907, (int16)0x17d8, (int16)0x0000 },
{ (int16)0x0e6b, (int16)0x58f4, (int16)0x1821, (int16)0x0000 },
{ (int16)0x0e35, (int16)0x58e0, (int16)0x186b, (int16)0x0000 },
{ (int16)0x0e00, (int16)0x58cb, (int16)0x18b5, (int16)0x0000 },
{ (int16)0x0dcb, (int16)0x58b5, (int16)0x1900, (int16)0x0000 },
{ (int16)0x0d97, (int16)0x589e, (int16)0x194b, (int16)0x0001 },
{ (int16)0x0d63, (int16)0x5886, (int16)0x1996, (int16)0x0001 },
{ (int16)0x0d30, (int16)0x586d, (int16)0x19e2, (int16)0x0001 },
{ (int16)0x0cfd, (int16)0x5853, (int16)0x1a2e, (int16)0x0001 },
{ (int16)0x0ccb, (int16)0x5838, (int16)0x1a7b, (int16)0x0002 },
{ (int16)0x0c99, (int16)0x581c, (int16)0x1ac8, (int16)0x0002 },
{ (int16)0x0c68, (int16)0x57ff, (int16)0x1b16, (int16)0x0002 },
{ (int16)0x0c38, (int16)0x57e2, (int16)0x1b64, (int16)0x0003 },
{ (int16)0x0c07, (int16)0x57c3, (int16)0x1bb3, (int16)0x0003 },
{ (int16)0x0bd8, (int16)0x57a3, (int16)0x1c02, (int16)0x0003 },
{ (int16)0x0ba9, (int16)0x5782, (int16)0x1c51, (int16)0x0004 },
{ (int16)0x0b7a, (int16)0x5761, (int16)0x1ca1, (int16)0x0004 },
{ (int16)0x0b4c, (int16)0x573e, (int16)0x1cf1, (int16)0x0005 },
{ (int16)0x0b1e, (int16)0x571b, (int16)0x1d42, (int16)0x0005 },
{ (int16)0x0af1, (int16)0x56f6, (int16)0x1d93, (int16)0x0006 },
{ (int16)0x0ac4, (int16)0x56d1, (int16)0x1de5, (int16)0x0007 },
{ (int16)0x0a98, (int16)0x56ab, (int16)0x1e37, (int16)0x0007 },
{ (int16)0x0a6c, (int16)0x5684, (int16)0x1e89, (int16)0x0008 },
{ (int16)0x0a40, (int16)0x565b, (int16)0x1edc, (int16)0x0009 },
{ (int16)0x0a16, (int16)0x5632, (int16)0x1f2f, (int16)0x0009 },
{ (int16)0x09eb, (int16)0x5609, (int16)0x1f82, (int16)0x000a },
{ (int16)0x09c1, (int16)0x55de, (int16)0x1fd6, (int16)0x000b },
{ (int16)0x0998, (int16)0x55b2, (int16)0x202a, (int16)0x000c },
{ (int16)0x096f, (int16)0x5585, (int16)0x207f, (int16)0x000d },
{ (int16)0x0946, (int16)0x5558, (int16)0x20d4, (int16)0x000e },
{ (int16)0x091e, (int16)0x5529, (int16)0x2129, (int16)0x000f },
{ (int16)0x08f7, (int16)0x54fa, (int16)0x217f, (int16)0x0010 },
{ (int16)0x08d0, (int16)0x54ca, (int16)0x21d5, (int16)0x0011 },
{ (int16)0x08a9, (int16)0x5499, (int16)0x222c, (int16)0x0012 },
{ (int16)0x0883, (int16)0x5467, (int16)0x2282, (int16)0x0013 },
{ (int16)0x085d, (int16)0x5434, (int16)0x22da, (int16)0x0015 },
{ (int16)0x0838, (int16)0x5401, (int16)0x2331, (int16)0x0016 },
{ (int16)0x0813, (int16)0x53cc, (int16)0x2389, (int16)0x0018 },
{ (int16)0x07ef, (int16)0x5397, (int16)0x23e1, (int16)0x0019 },
{ (int16)0x07cb, (int16)0x5361, (int16)0x2439, (int16)0x001b },
{ (int16)0x07a7, (int16)0x532a, (int16)0x2492, (int16)0x001c },
{ (int16)0x0784, (int16)0x52f3, (int16)0x24eb, (int16)0x001e },
{ (int16)0x0762, (int16)0x52ba, (int16)0x2545, (int16)0x0020 },
{ (int16)0x0740, (int16)0x5281, (int16)0x259e, (int16)0x0021 },
{ (int16)0x071e, (int16)0x5247, (int16)0x25f8, (int16)0x0023 },
{ (int16)0x06fd, (int16)0x520c, (int16)0x2653, (int16)0x0025 },
{ (int16)0x06dc, (int16)0x51d0, (int16)0x26ad, (int16)0x0027 },
{ (int16)0x06bb, (int16)0x5194, (int16)0x2708, (int16)0x0029 },
{ (int16)0x069b, (int16)0x5156, (int16)0x2763, (int16)0x002c },
{ (int16)0x067c, (int16)0x5118, (int16)0x27be, (int16)0x002e },
{ (int16)0x065c, (int16)0x50da, (int16)0x281a, (int16)0x0030 },
{ (int16)0x063e, (int16)0x509a, (int16)0x2876, (int16)0x0033 },
{ (int16)0x061f, (int16)0x505a, (int16)0x28d2, (int16)0x0035 },
{ (int16)0x0601, (int16)0x5019, (int16)0x292e, (int16)0x0038 },
{ (int16)0x05e4, (int16)0x4fd7, (int16)0x298b, (int16)0x003a },
{ (int16)0x05c7, (int16)0x4f95, (int16)0x29e7, (int16)0x003d },
{ (int16)0x05aa, (int16)0x4f52, (int16)0x2a44, (int16)0x0040 },
{ (int16)0x058e, (int16)0x4f0e, (int16)0x2aa1, (int16)0x0043 },
{ (int16)0x0572, (int16)0x4ec9, (int16)0x2aff, (int16)0x0046 },
{ (int16)0x0556, (int16)0x4e84, (int16)0x2b5c, (int16)0x0049 },
{ (int16)0x053b, (int16)0x4e3e, (int16)0x2bba, (int16)0x004d },
{ (int16)0x0520, (int16)0x4df7, (int16)0x2c18, (int16)0x0050 },
{ (int16)0x0506, (int16)0x4db0, (int16)0x2c76, (int16)0x0054 },
{ (int16)0x04ec, (int16)0x4d68, (int16)0x2cd4, (int16)0x0057 },
{ (int16)0x04d2, (int16)0x4d20, (int16)0x2d33, (int16)0x005b },
{ (int16)0x04b9, (int16)0x4cd7, (int16)0x2d91, (int16)0x005f },
{ (int16)0x04a0, (int16)0x4c8d, (int16)0x2df0, (int16)0x0063 },
{ (int16)0x0488, (int16)0x4c42, (int16)0x2e4f, (int16)0x0067 },
{ (int16)0x0470, (int16)0x4bf7, (int16)0x2eae, (int16)0x006b },
{ (int16)0x0458, (int16)0x4bac, (int16)0x2f0d, (int16)0x006f },
{ (int16)0x0441, (int16)0x4b5f, (int16)0x2f6c, (int16)0x0074 },
{ (int16)0x042a, (int16)0x4b13, (int16)0x2fcc, (int16)0x0078 },
{ (int16)0x0413, (int16)0x4ac5, (int16)0x302b, (int16)0x007d },
{ (int16)0x03fc, (int16)0x4a77, (int16)0x308b, (int16)0x0082 },
{ (int16)0x03e7, (int16)0x4a29, (int16)0x30ea, (int16)0x0087 },
{ (int16)0x03d1, (int16)0x49d9, (int16)0x314a, (int16)0x008c },
{ (int16)0x03bc, (int16)0x498a, (int16)0x31aa, (int16)0x0091 },
{ (int16)0x03a7, (int16)0x493a, (int16)0x3209, (int16)0x0096 },
{ (int16)0x0392, (int16)0x48e9, (int16)0x3269, (int16)0x009c },
{ (int16)0x037e, (int16)0x4898, (int16)0x32c9, (int16)0x00a1 },
{ (int16)0x036a, (int16)0x4846, (int16)0x3329, (int16)0x00a7 },
{ (int16)0x0356, (int16)0x47f4, (int16)0x3389, (int16)0x00ad },
{ (int16)0x0343, (int16)0x47a1, (int16)0x33e9, (int16)0x00b3 },
{ (int16)0x0330, (int16)0x474e, (int16)0x3449, (int16)0x00ba },
{ (int16)0x031d, (int16)0x46fa, (int16)0x34a9, (int16)0x00c0 },
{ (int16)0x030b, (int16)0x46a6, (int16)0x3509, (int16)0x00c7 },
{ (int16)0x02f9, (int16)0x4651, (int16)0x3569, (int16)0x00cd },
{ (int16)0x02e7, (int16)0x45fc, (int16)0x35c9, (int16)0x00d4 },
{ (int16)0x02d6, (int16)0x45a6, (int16)0x3629, (int16)0x00db },
{ (int16)0x02c4, (int16)0x4550, (int16)0x3689, (int16)0x00e3 },
{ (int16)0x02b4, (int16)0x44fa, (int16)0x36e8, (int16)0x00ea },
{ (int16)0x02a3, (int16)0x44a3, (int16)0x3748, (int16)0x00f2 },
{ (int16)0x0293, (int16)0x444c, (int16)0x37a8, (int16)0x00fa },
{ (int16)0x0283, (int16)0x43f4, (int16)0x3807, (int16)0x0101 },
{ (int16)0x0273, (int16)0x439c, (int16)0x3867, (int16)0x010a },
{ (int16)0x0264, (int16)0x4344, (int16)0x38c6, (int16)0x0112 },
{ (int16)0x0255, (int16)0x42eb, (int16)0x3926, (int16)0x011b },
{ (int16)0x0246, (int16)0x4292, (int16)0x3985, (int16)0x0123 },
{ (int16)0x0237, (int16)0x4239, (int16)0x39e4, (int16)0x012c },
{ (int16)0x0229, (int16)0x41df, (int16)0x3a43, (int16)0x0135 },
{ (int16)0x021b, (int16)0x4185, (int16)0x3aa2, (int16)0x013f },
{ (int16)0x020d, (int16)0x412a, (int16)0x3b00, (int16)0x0148 },
{ (int16)0x0200, (int16)0x40d0, (int16)0x3b5f, (int16)0x0152 },
{ (int16)0x01f2, (int16)0x4074, (int16)0x3bbd, (int16)0x015c },
{ (int16)0x01e5, (int16)0x4019, (int16)0x3c1b, (int16)0x0166 },
{ (int16)0x01d9, (int16)0x3fbd, (int16)0x3c79, (int16)0x0171 },
{ (int16)0x01cc, (int16)0x3f62, (int16)0x3cd7, (int16)0x017b },
{ (int16)0x01c0, (int16)0x3f05, (int16)0x3d35, (int16)0x0186 },
{ (int16)0x01b4, (int16)0x3ea9, (int16)0x3d92, (int16)0x0191 },
{ (int16)0x01a8, (int16)0x3e4c, (int16)0x3def, (int16)0x019c },
{ (int16)0x019c, (int16)0x3def, (int16)0x3e4c, (int16)0x01a8 },
{ (int16)0x0191, (int16)0x3d92, (int16)0x3ea9, (int16)0x01b4 },
{ (int16)0x0186, (int16)0x3d35, (int16)0x3f05, (int16)0x01c0 },
{ (int16)0x017b, (int16)0x3cd7, (int16)0x3f62, (int16)0x01cc },
{ (int16)0x0171, (int16)0x3c79, (int16)0x3fbd, (int16)0x01d9 },
{ (int16)0x0166, (int16)0x3c1b, (int16)0x4019, (int16)0x01e5 },
{ (int16)0x015c, (int16)0x3bbd, (int16)0x4074, (int16)0x01f2 },
{ (int16)0x0152, (int16)0x3b5f, (int16)0x40d0, (int16)0x0200 },
{ (int16)0x0148, (int16)0x3b00, (int16)0x412a, (int16)0x020d },
{ (int16)0x013f, (int16)0x3aa2, (int16)0x4185, (int16)0x021b },
{ (int16)0x0135, (int16)0x3a43, (int16)0x41df, (int16)0x0229 },
{ (int16)0x012c, (int16)0x39e4, (int16)0x4239, (int16)0x0237 },
{ (int16)0x0123, (int16)0x3985, (int16)0x4292, (int16)0x0246 },
{ (int16)0x011b, (int16)0x3926, (int16)0x42eb, (int16)0x0255 },
{ (int16)0x0112, (int16)0x38c6, (int16)0x4344, (int16)0x0264 },
{ (int16)0x010a, (int16)0x3867, (int16)0x439c, (int16)0x0273 },
{ (int16)0x0101, (int16)0x3807, (int16)0x43f4, (int16)0x0283 },
{ (int16)0x00fa, (int16)0x37a8, (int16)0x444c, (int16)0x0293 },
{ (int16)0x00f2, (int16)0x3748, (int16)0x44a3, (int16)0x02a3 },
{ (int16)0x00ea, (int16)0x36e8, (int16)0x44fa, (int16)0x02b4 },
{ (int16)0x00e3, (int16)0x3689, (int16)0x4550, (int16)0x02c4 },
{ (int16)0x00db, (int16)0x3629, (int16)0x45a6, (int16)0x02d6 },
{ (int16)0x00d4, (int16)0x35c9, (int16)0x45fc, (int16)0x02e7 },
{ (int16)0x00cd, (int16)0x3569, (int16)0x4651, (int16)0x02f9 },
{ (int16)0x00c7, (int16)0x3509, (int16)0x46a6, (int16)0x030b },
{ (int16)0x00c0, (int16)0x34a9, (int16)0x46fa, (int16)0x031d },
{ (int16)0x00ba, (int16)0x3449, (int16)0x474e, (int16)0x0330 },
{ (int16)0x00b3, (int16)0x33e9, (int16)0x47a1, (int16)0x0343 },
{ (int16)0x00ad, (int16)0x3389, (int16)0x47f4, (int16)0x0356 },
{ (int16)0x00a7, (int16)0x3329, (int16)0x4846, (int16)0x036a },
{ (int16)0x00a1, (int16)0x32c9, (int16)0x4898, (int16)0x037e },
{ (int16)0x009c, (int16)0x3269, (int16)0x48e9, (int16)0x0392 },
{ (int16)0x0096, (int16)0x3209, (int16)0x493a, (int16)0x03a7 },
{ (int16)0x0091, (int16)0x31aa, (int16)0x498a, (int16)0x03bc },
{ (int16)0x008c, (int16)0x314a, (int16)0x49d9, (int16)0x03d1 },
{ (int16)0x0087, (int16)0x30ea, (int16)0x4a29, (int16)0x03e7 },
{ (int16)0x0082, (int16)0x308b, (int16)0x4a77, (int16)0x03fc },
{ (int16)0x007d, (int16)0x302b, (int16)0x4ac5, (int16)0x0413 },
{ (int16)0x0078, (int16)0x2fcc, (int16)0x4b13, (int16)0x042a },
{ (int16)0x0074, (int16)0x2f6c, (int16)0x4b5f, (int16)0x0441 },
{ (int16)0x006f, (int16)0x2f0d, (int16)0x4bac, (int16)0x0458 },
{ (int16)0x006b, (int16)0x2eae, (int16)0x4bf7, (int16)0x0470 },
{ (int16)0x0067, (int16)0x2e4f, (int16)0x4c42, (int16)0x0488 },
{ (int16)0x0063, (int16)0x2df0, (int16)0x4c8d, (int16)0x04a0 },
{ (int16)0x005f, (int16)0x2d91, (int16)0x4cd7, (int16)0x04b9 },
{ (int16)0x005b, (int16)0x2d33, (int16)0x4d20, (int16)0x04d2 },
{ (int16)0x0057, (int16)0x2cd4, (int16)0x4d68, (int16)0x04ec },
{ (int16)0x0054, (int16)0x2c76, (int16)0x4db0, (int16)0x0506 },
{ (int16)0x0050, (int16)0x2c18, (int16)0x4df7, (int16)0x0520 },
{ (int16)0x004d, (int16)0x2bba, (int16)0x4e3e, (int16)0x053b },
{ (int16)0x0049, (int16)0x2b5c, (int16)0x4e84, (int16)0x0556 },
{ (int16)0x0046, (int16)0x2aff, (int16)0x4ec9, (int16)0x0572 },
{ (int16)0x0043, (int16)0x2aa1, (int16)0x4f0e, (int16)0x058e },
{ (int16)0x0040, (int16)0x2a44, (int16)0x4f52, (int16)0x05aa },
{ (int16)0x003d, (int16)0x29e7, (int16)0x4f95, (int16)0x05c7 },
{ (int16)0x003a, (int16)0x298b, (int16)0x4fd7, (int16)0x05e4 },
{ (int16)0x0038, (int16)0x292e, (int16)0x5019, (int16)0x0601 },
{ (int16)0x0035, (int16)0x28d2, (int16)0x505a, (int16)0x061f },
{ (int16)0x0033, (int16)0x2876, (int16)0x509a, (int16)0x063e },
{ (int16)0x0030, (int16)0x281a, (int16)0x50da, (int16)0x065c },
{ (int16)0x002e, (int16)0x27be, (int16)0x5118, (int16)0x067c },
{ (int16)0x002c, (int16)0x2763, (int16)0x5156, (int16)0x069b },
{ (int16)0x0029, (int16)0x2708, (int16)0x5194, (int16)0x06bb },
{ (int16)0x0027, (int16)0x26ad, (int16)0x51d0, (int16)0x06dc },
{ (int16)0x0025, (int16)0x2653, (int16)0x520c, (int16)0x06fd },
{ (int16)0x0023, (int16)0x25f8, (int16)0x5247, (int16)0x071e },
{ (int16)0x0021, (int16)0x259e, (int16)0x5281, (int16)0x0740 },
{ (int16)0x0020, (int16)0x2545, (int16)0x52ba, (int16)0x0762 },
{ (int16)0x001e, (int16)0x24eb, (int16)0x52f3, (int16)0x0784 },
{ (int16)0x001c, (int16)0x2492, (int16)0x532a, (int16)0x07a7 },
{ (int16)0x001b, (int16)0x2439, (int16)0x5361, (int16)0x07cb },
{ (int16)0x0019, (int16)0x23e1, (int16)0x5397, (int16)0x07ef },
{ (int16)0x0018, (int16)0x2389, (int16)0x53cc, (int16)0x0813 },
{ (int16)0x0016, (int16)0x2331, (int16)0x5401, (int16)0x0838 },
{ (int16)0x0015, (int16)0x22da, (int16)0x5434, (int16)0x085d },
{ (int16)0x0013, (int16)0x2282, (int16)0x5467, (int16)0x0883 },
{ (int16)0x0012, (int16)0x222c, (int16)0x5499, (int16)0x08a9 },
{ (int16)0x0011, (int16)0x21d5, (int16)0x54ca, (int16)0x08d0 },
{ (int16)0x0010, (int16)0x217f, (int16)0x54fa, (int16)0x08f7 },
{ (int16)0x000f, (int16)0x2129, (int16)0x5529, (int16)0x091e },
{ (int16)0x000e, (int16)0x20d4, (int16)0x5558, (int16)0x0946 },
{ (int16)0x000d, (int16)0x207f, (int16)0x5585, (int16)0x096f },
{ (int16)0x000c, (int16)0x202a, (int16)0x55b2, (int16)0x0998 },
{ (int16)0x000b, (int16)0x1fd6, (int16)0x55de, (int16)0x09c1 },
{ (int16)0x000a, (int16)0x1f82, (int16)0x5609, (int16)0x09eb },
{ (int16)0x0009, (int16)0x1f2f, (int16)0x5632, (int16)0x0a16 },
{ (int16)0x0009, (int16)0x1edc, (int16)0x565b, (int16)0x0a40 },
{ (int16)0x0008, (int16)0x1e89, (int16)0x5684, (int16)0x0a6c },
{ (int16)0x0007, (int16)0x1e37, (int16)0x56ab, (int16)0x0a98 },
{ (int16)0x0007, (int16)0x1de5, (int16)0x56d1, (int16)0x0ac4 },
{ (int16)0x0006, (int16)0x1d93, (int16)0x56f6, (int16)0x0af1 },
{ (int16)0x0005, (int16)0x1d42, (int16)0x571b, (int16)0x0b1e },
{ (int16)0x0005, (int16)0x1cf1, (int16)0x573e, (int16)0x0b4c },
{ (int16)0x0004, (int16)0x1ca1, (int16)0x5761, (int16)0x0b7a },
{ (int16)0x0004, (int16)0x1c51, (int16)0x5782, (int16)0x0ba9 },
{ (int16)0x0003, (int16)0x1c02, (int16)0x57a3, (int16)0x0bd8 },
{ (int16)0x0003, (int16)0x1bb3, (int16)0x57c3, (int16)0x0c07 },
{ (int16)0x0003, (int16)0x1b64, (int16)0x57e2, (int16)0x0c38 },
{ (int16)0x0002, (int16)0x1b16, (int16)0x57ff, (int16)0x0c68 },
{ (int16)0x0002, (int16)0x1ac8, (int16)0x581c, (int16)0x0c99 },
{ (int16)0x0002, (int16)0x1a7b, (int16)0x5838, (int16)0x0ccb },
{ (int16)0x0001, (int16)0x1a2e, (int16)0x5853, (int16)0x0cfd },
{ (int16)0x0001, (int16)0x19e2, (int16)0x586d, (int16)0x0d30 },
{ (int16)0x0001, (int16)0x1996, (int16)0x5886, (int16)0x0d63 },
{ (int16)0x0001, (int16)0x194b, (int16)0x589e, (int16)0x0d97 },
{ (int16)0x0000, (int16)0x1900, (int16)0x58b5, (int16)0x0dcb },
{ (int16)0x0000, (int16)0x18b5, (int16)0x58cb, (int16)0x0e00 },
{ (int16)0x0000, (int16)0x186b, (int16)0x58e0, (int16)0x0e35 },
{ (int16)0x0000, (int16)0x1821, (int16)0x58f4, (int16)0x0e6b },
{ (int16)0x0000, (int16)0x17d8, (int16)0x5907, (int16)0x0ea1 },
{ (int16)0x0000, (int16)0x1790, (int16)0x5919, (int16)0x0ed7 },
{ (int16)0x0000, (int16)0x1747, (int16)0x592a, (int16)0x0f0f },
{ (int16)0xffff, (int16)0x1700, (int16)0x593a, (int16)0x0f46 },
{ (int16)0xffff, (int16)0x16b9, (int16)0x5949, (int16)0x0f7f },
{ (int16)0xffff, (int16)0x1672, (int16)0x5958, (int16)0x0fb7 },
{ (int16)0xffff, (int16)0x162c, (int16)0x5965, (int16)0x0ff1 },
{ (int16)0xffff, (int16)0x15e6, (int16)0x5971, (int16)0x102a },
{ (int16)0xffff, (int16)0x15a0, (int16)0x597c, (int16)0x1065 },
{ (int16)0xffff, (int16)0x155c, (int16)0x5986, (int16)0x109f },
{ (int16)0xffff, (int16)0x1517, (int16)0x598f, (int16)0x10db },
{ (int16)0xffff, (int16)0x14d4, (int16)0x5997, (int16)0x1116 },
{ (int16)0xffff, (int16)0x1490, (int16)0x599e, (int16)0x1153 },
{ (int16)0xffff, (int16)0x144d, (int16)0x59a4, (int16)0x118f },
{ (int16)0xffff, (int16)0x140b, (int16)0x59a9, (int16)0x11cd },
{ (int16)0xffff, (int16)0x13c9, (int16)0x59ad, (int16)0x120b },
{ (int16)0xffff, (int16)0x1388, (int16)0x59b0, (int16)0x1249 },
{ (int16)0xffff, (int16)0x1347, (int16)0x59b2, (int16)0x1288 },
{ (int16)0xffff, (int16)0x1307, (int16)0x59b3, (int16)0x12c7 },

View File

@ -63,46 +63,46 @@ static INLINE int32 Reverb4422(const int16 *src)
{
static const int16 ResampTable[40] =
{
0xffff,
0x0000,
0x0002,
0x0000,
0xfff6,
0x0000,
0x0023,
0x0000,
0xff99,
0x0000,
0x010a,
0x0000,
0xfd98,
0x0000,
0x0534,
0x0000,
0xf470,
0x0000,
0x2806,
0x4000,
0x2806,
0x0000,
0xf470,
0x0000,
0x0534,
0x0000,
0xfd98,
0x0000,
0x010a,
0x0000,
0xff99,
0x0000,
0x0023,
0x0000,
0xfff6,
0x0000,
0x0002,
0x0000,
0xffff,
0x0000,
(int16)0xffff,
(int16)0x0000,
(int16)0x0002,
(int16)0x0000,
(int16)0xfff6,
(int16)0x0000,
(int16)0x0023,
(int16)0x0000,
(int16)0xff99,
(int16)0x0000,
(int16)0x010a,
(int16)0x0000,
(int16)0xfd98,
(int16)0x0000,
(int16)0x0534,
(int16)0x0000,
(int16)0xf470,
(int16)0x0000,
(int16)0x2806,
(int16)0x4000,
(int16)0x2806,
(int16)0x0000,
(int16)0xf470,
(int16)0x0000,
(int16)0x0534,
(int16)0x0000,
(int16)0xfd98,
(int16)0x0000,
(int16)0x010a,
(int16)0x0000,
(int16)0xff99,
(int16)0x0000,
(int16)0x0023,
(int16)0x0000,
(int16)0xfff6,
(int16)0x0000,
(int16)0x0002,
(int16)0x0000,
(int16)0xffff,
(int16)0x0000,
};
int32 out = 0; // 32-bits is adequate(it won't overflow)

View File

@ -87,8 +87,11 @@ struct Timer
int32 Div8Counter;
bool IRQDone;
int32 DoZeCounting;
};
static bool vblank;
static bool hretrace;
static Timer Timers[3];
static pscpu_timestamp_t lastts;
@ -123,6 +126,9 @@ static int32 CalcNextEvent(int32 next_event)
{
int32 tmp_clocks;
if(Timers[i].DoZeCounting <= 0)
continue;
if((i == 0x2) && (Timers[i].Mode & 0x1))
continue;
@ -150,6 +156,9 @@ static void ClockTimer(int i, uint32 clocks)
int32 target = 0x10000;
bool zero_tm = false;
if(Timers[i].DoZeCounting <= 0)
clocks = 0;
if(i == 0x2)
{
uint32 d8_clocks;
@ -218,6 +227,52 @@ static void ClockTimer(int i, uint32 clocks)
}
void TIMER_SetVBlank(bool status)
{
switch(Timers[1].Mode & 0x7)
{
case 0x1:
Timers[1].DoZeCounting = !status;
break;
case 0x3:
if(vblank && !status)
Timers[1].Counter = 0;
break;
case 0x5:
Timers[1].DoZeCounting = status;
if(vblank && !status)
Timers[1].Counter = 0;
break;
case 0x7:
if(Timers[1].DoZeCounting == -1)
{
if(!vblank && status)
Timers[1].DoZeCounting = 0;
}
else if(Timers[1].DoZeCounting == 0)
{
if(vblank && !status)
Timers[1].DoZeCounting = 1;
}
break;
}
vblank = status;
}
void TIMER_SetHRetrace(bool status)
{
if(hretrace && !status)
{
if((Timers[0].Mode & 0x7) == 0x3)
Timers[0].Counter = 0;
}
hretrace = status;
}
void TIMER_AddDotClocks(uint32 count)
{
if(Timers[0].Mode & 0x100)
@ -249,6 +304,33 @@ pscpu_timestamp_t TIMER_Update(const pscpu_timestamp_t timestamp)
return(timestamp + CalcNextEvent(1024));
}
static void CalcCountingStart(unsigned which)
{
Timers[which].DoZeCounting = true;
switch(which)
{
case 1:
switch(Timers[which].Mode & 0x07)
{
case 0x1:
Timers[which].DoZeCounting = !vblank;
break;
case 0x5:
Timers[which].DoZeCounting = vblank;
break;
case 0x7:
Timers[which].DoZeCounting = -1;
break;
}
break;
}
}
void TIMER_Write(const pscpu_timestamp_t timestamp, uint32 A, uint16 V)
{
TIMER_Update(timestamp);
@ -257,7 +339,7 @@ void TIMER_Write(const pscpu_timestamp_t timestamp, uint32 A, uint16 V)
assert(!(A & 3));
PSX_DBGINFO("[TIMER] Write: %08x %04x", A, V);
PSX_DBGINFO("[TIMER] Write: %08x %04x\n", A, V);
if(which >= 3)
return;
@ -296,6 +378,7 @@ void TIMER_Write(const pscpu_timestamp_t timestamp, uint32 A, uint16 V)
}
Timers[which].Counter = 0;
#endif
CalcCountingStart(which); // Call after setting .Mode
break;
case 0x8: Timers[which].Target = V & 0xFFFF;
@ -350,6 +433,8 @@ void TIMER_Power(void)
{
lastts = 0;
hretrace = false;
vblank = false;
memset(Timers, 0, sizeof(Timers));
}

View File

@ -28,7 +28,8 @@ uint16 TIMER_Read(const pscpu_timestamp_t timestamp, uint32 A);
void TIMER_AddDotClocks(uint32 count);
void TIMER_ClockHRetrace(void);
void TIMER_SetVSync(bool status); // TODO
void TIMER_SetHRetrace(bool status);
void TIMER_SetVBlank(bool status);
pscpu_timestamp_t TIMER_Update(const pscpu_timestamp_t);
void TIMER_ResetTS(void);

View File

@ -939,7 +939,7 @@ void QTRecord::Write_udta(void)
atom_begin("@swr");
qtfile.put_string("Mednafen "MEDNAFEN_VERSION" -- qtrecord.cpp compiled " __DATE__ " " __TIME__);
qtfile.put_string("Mednafen " MEDNAFEN_VERSION " -- qtrecord.cpp compiled " __DATE__ " " __TIME__);
atom_end();

View File

@ -75,7 +75,7 @@
#endif
#ifndef OUTSIDE_SPEEX
#include "speex/speex_mednafen-types.h"
#include "speex/speex_types.h"
#endif
#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */

View File

@ -91,7 +91,7 @@
#else /* OUTSIDE_SPEEX */
#include "speex/speex_mednafen-types.h"
#include "speex/speex_types.h"
#endif /* OUTSIDE_SPEEX */

View File

@ -27,7 +27,8 @@
#include "md5.h"
#include "string/world_strtod.h"
#include "string/escape.h"
#include "FileWrapper.h"
#include "FileStream.h"
#include "MemoryStream.h"
typedef struct
{
@ -76,7 +77,7 @@ static bool TranslateSettingValueI(const char *value, long long &tlated_value)
}
static bool ValidateSetting(const char *value, const MDFNSetting *setting)
static void ValidateSetting(const char *value, const MDFNSetting *setting)
{
MDFNSettingType base_type = setting->type;
@ -86,8 +87,7 @@ static bool ValidateSetting(const char *value, const MDFNSetting *setting)
if(!TranslateSettingValueUI(value, ullvalue))
{
MDFN_PrintError(_("Setting \"%s\", value \"%s\", is not set to a valid unsigned integer."), setting->name, value);
return(0);
throw MDFN_Error(0, _("Setting \"%s\", value \"%s\", is not set to a valid unsigned integer."), setting->name, value);
}
if(setting->minimum)
{
@ -96,8 +96,7 @@ static bool ValidateSetting(const char *value, const MDFNSetting *setting)
TranslateSettingValueUI(setting->minimum, minimum);
if(ullvalue < minimum)
{
MDFN_PrintError(_("Setting \"%s\" is set too small(\"%s\"); the minimum acceptable value is \"%s\"."), setting->name, value, setting->minimum);
return(0);
throw MDFN_Error(0, _("Setting \"%s\" is set too small(\"%s\"); the minimum acceptable value is \"%s\"."), setting->name, value, setting->minimum);
}
}
if(setting->maximum)
@ -107,8 +106,7 @@ static bool ValidateSetting(const char *value, const MDFNSetting *setting)
TranslateSettingValueUI(setting->maximum, maximum);
if(ullvalue > maximum)
{
MDFN_PrintError(_("Setting \"%s\" is set too large(\"%s\"); the maximum acceptable value is \"%s\"."), setting->name, value, setting->maximum);
return(0);
throw MDFN_Error(0, _("Setting \"%s\" is set too large(\"%s\"); the maximum acceptable value is \"%s\"."), setting->name, value, setting->maximum);
}
}
}
@ -118,8 +116,7 @@ static bool ValidateSetting(const char *value, const MDFNSetting *setting)
if(!TranslateSettingValueI(value, llvalue))
{
MDFN_PrintError(_("Setting \"%s\", value \"%s\", is not set to a valid signed integer."), setting->name, value);
return(0);
throw MDFN_Error(0, _("Setting \"%s\", value \"%s\", is not set to a valid signed integer."), setting->name, value);
}
if(setting->minimum)
{
@ -128,8 +125,7 @@ static bool ValidateSetting(const char *value, const MDFNSetting *setting)
TranslateSettingValueI(setting->minimum, minimum);
if(llvalue < minimum)
{
MDFN_PrintError(_("Setting \"%s\" is set too small(\"%s\"); the minimum acceptable value is \"%s\"."), setting->name, value, setting->minimum);
return(0);
throw MDFN_Error(0, _("Setting \"%s\" is set too small(\"%s\"); the minimum acceptable value is \"%s\"."), setting->name, value, setting->minimum);
}
}
if(setting->maximum)
@ -139,8 +135,7 @@ static bool ValidateSetting(const char *value, const MDFNSetting *setting)
TranslateSettingValueI(setting->maximum, maximum);
if(llvalue > maximum)
{
MDFN_PrintError(_("Setting \"%s\" is set too large(\"%s\"); the maximum acceptable value is \"%s\"."), setting->name, value, setting->maximum);
return(0);
throw MDFN_Error(0, _("Setting \"%s\" is set too large(\"%s\"); the maximum acceptable value is \"%s\"."), setting->name, value, setting->maximum);
}
}
}
@ -153,8 +148,7 @@ static bool ValidateSetting(const char *value, const MDFNSetting *setting)
if(!endptr || *endptr != 0)
{
MDFN_PrintError(_("Setting \"%s\", value \"%s\", is not set to a floating-point(real) number."), setting->name, value);
return(0);
throw MDFN_Error(0, _("Setting \"%s\", value \"%s\", is not set to a floating-point(real) number."), setting->name, value);
}
if(setting->minimum)
{
@ -163,8 +157,7 @@ static bool ValidateSetting(const char *value, const MDFNSetting *setting)
minimum = world_strtod(setting->minimum, NULL);
if(dvalue < minimum)
{
MDFN_PrintError(_("Setting \"%s\" is set too small(\"%s\"); the minimum acceptable value is \"%s\"."), setting->name, value, setting->minimum);
return(0);
throw MDFN_Error(0, _("Setting \"%s\" is set too small(\"%s\"); the minimum acceptable value is \"%s\"."), setting->name, value, setting->minimum);
}
}
if(setting->maximum)
@ -174,8 +167,7 @@ static bool ValidateSetting(const char *value, const MDFNSetting *setting)
maximum = world_strtod(setting->maximum, NULL);
if(dvalue > maximum)
{
MDFN_PrintError(_("Setting \"%s\" is set too large(\"%s\"); the maximum acceptable value is \"%s\"."), setting->name, value, setting->maximum);
return(0);
throw MDFN_Error(0, _("Setting \"%s\" is set too large(\"%s\"); the maximum acceptable value is \"%s\"."), setting->name, value, setting->maximum);
}
}
}
@ -183,8 +175,7 @@ static bool ValidateSetting(const char *value, const MDFNSetting *setting)
{
if(strlen(value) != 1 || (value[0] != '0' && value[0] != '1'))
{
MDFN_PrintError(_("Setting \"%s\", value \"%s\", is not a valid boolean value."), setting->name, value);
return(0);
throw MDFN_Error(0, _("Setting \"%s\", value \"%s\", is not a valid boolean value."), setting->name, value);
}
}
else if(base_type == MDFNST_ENUM)
@ -211,8 +202,7 @@ static bool ValidateSetting(const char *value, const MDFNSetting *setting)
if(!found)
{
MDFN_PrintError(_("Setting \"%s\", value \"%s\", is not a recognized string. Recognized strings: %s"), setting->name, value, valid_string_list.c_str());
return(0);
throw MDFN_Error(0, _("Setting \"%s\", value \"%s\", is not a recognized string. Recognized strings: %s"), setting->name, value, valid_string_list.c_str());
}
}
@ -220,13 +210,10 @@ static bool ValidateSetting(const char *value, const MDFNSetting *setting)
if(setting->validate_func && !setting->validate_func(setting->name, value))
{
if(base_type == MDFNST_STRING)
MDFN_PrintError(_("Setting \"%s\" is not set to a valid string: \"%s\""), setting->name, value);
throw MDFN_Error(0, _("Setting \"%s\" is not set to a valid string: \"%s\""), setting->name, value);
else
MDFN_PrintError(_("Setting \"%s\" is not set to a valid unsigned integer: \"%s\""), setting->name, value);
return(0);
throw MDFN_Error(0, _("Setting \"%s\" is not set to a valid unsigned integer: \"%s\""), setting->name, value);
}
return(1);
}
static uint32 MakeNameHash(const char *name)
@ -238,130 +225,183 @@ static uint32 MakeNameHash(const char *name)
return(name_hash);
}
static bool ParseSettingLine(char *linebuf, bool IsOverrideSetting = false)
static void ParseSettingLine(std::string &linebuf, bool IsOverrideSetting = false)
{
MDFNCS *zesetting;
char *spacepos = strchr(linebuf, ' ');
MDFNCS *zesetting;
size_t spacepos = linebuf.find(' ');
if(!spacepos) return(true); // EOF or bad line
// EOF or bad line
if(spacepos == std::string::npos)
return;
if(spacepos == linebuf) return(true); // No name(key)
if(spacepos[1] == 0) return(true); // No value
if(spacepos[0] == ';') return(true); // Comment
// No name(key)
if(spacepos == 0)
return;
// FIXME
if(linebuf[0] == ';')
return(true);
// No value
if((spacepos + 1) == linebuf.size())
return;
*spacepos = 0;
char *lfpos = strchr(spacepos + 1, '\n');
if(lfpos) *lfpos = 0;
lfpos = strchr(spacepos + 1, '\r');
if(lfpos) *lfpos = 0;
// Comment
if(linebuf[0] == ';')
return;
if(spacepos[1] == 0)
return(true); // No value
linebuf[spacepos] = 0;
zesetting = FindSetting(linebuf.c_str(), true, true);
zesetting = FindSetting(linebuf, true, true);
if(zesetting)
{
char *nv = strdup(linebuf.c_str() + spacepos + 1);
if(zesetting)
if(IsOverrideSetting)
{
char *nv = strdup(spacepos + 1);
if(zesetting->game_override)
free(zesetting->game_override);
if(IsOverrideSetting)
{
if(zesetting->game_override)
free(zesetting->game_override);
zesetting->game_override = nv;
}
else
{
if(zesetting->value)
free(zesetting->value);
zesetting->value = nv;
}
if(!ValidateSetting(nv, zesetting->desc)) // TODO: Validate later(so command line options can override invalid setting file data correctly)
return(false);
zesetting->game_override = nv;
}
else if(!IsOverrideSetting)
else
{
UnknownSetting_t unks;
if(zesetting->value)
free(zesetting->value);
unks.name = strdup(linebuf);
unks.value = strdup(spacepos + 1);
UnknownSettings.push_back(unks);
zesetting->value = nv;
}
return(true);
ValidateSetting(nv, zesetting->desc); // TODO: Validate later(so command line options can override invalid setting file data correctly)
}
else if(!IsOverrideSetting)
{
UnknownSetting_t unks;
unks.name = strdup(linebuf.c_str());
unks.value = strdup(linebuf.c_str() + spacepos + 1);
UnknownSettings.push_back(unks);
}
}
// TODO: not used yet.
void MDFN_LoadPGOSettings(const char *path, const char *section)
static void LoadSettings(Stream *fp, const char *section, bool override)
{
FileWrapper fp(path, FileWrapper::MODE_READ);
char linebuf[1024];
bool InCorrectSection = true; // To allow for all-game overrides at the start of the override file, might be useful in certain scenarios.
bool InCorrectSection = true; // To also allow for all-game overrides at the start of the override file, might be useful in certain scenarios.
std::string linebuf;
while(fp.get_line(linebuf, 1024))
linebuf.reserve(1024);
while(fp->get_line(linebuf) != -1)
{
if(linebuf[0] == '[')
{
if(!strcasecmp(&linebuf[1], section) && linebuf[1 + strlen(section)] == ']')
InCorrectSection = true;
else
InCorrectSection = false;
if(section)
{
if(!strcasecmp(linebuf.c_str() + 1, section) && linebuf[1 + strlen(section)] == ']')
InCorrectSection = true;
else
InCorrectSection = false;
}
}
else if(InCorrectSection)
{
if(!ParseSettingLine(linebuf))
throw(MDFN_Error(0, "I AM ERROR"));
ParseSettingLine(linebuf, override);
}
}
}
bool MFDN_LoadSettings(const char *basedir)
bool MDFN_LoadSettings(const char *path, const char *section, bool override)
{
char linebuf[1024];
FILE *fp;
MDFN_printf(_("Loading settings from \"%s\"..."), path);
fname = basedir;
fname += PSS;
fname += "mednafen-09x.cfg";
MDFN_printf(_("Loading settings from \"%s\"..."), fname.c_str());
//printf("%s\n", fname.c_str());
if(!(fp = fopen(fname.c_str(), "rb")))
try
{
ErrnoHolder ene(errno);
MDFN_printf(_("Failed: %s\n"), ene.StrError());
if(ene.Errno() == ENOENT) // Don't return failure if the file simply doesn't exist.
return(1);
else
return(0);
MemoryStream mp(new FileStream(path, FileStream::MODE_READ));
LoadSettings(&mp, section, override);
}
MDFN_printf("\n");
while(fgets(linebuf, 1024, fp) > 0)
catch(MDFN_Error &e)
{
if(!ParseSettingLine(linebuf))
if(e.GetErrno() == ENOENT)
{
fclose(fp);
MDFN_indent(1);
MDFN_printf(_("Failed: %s\n"), e.what());
MDFN_indent(-1);
return(true);
}
else
{
MDFN_printf("\n");
MDFN_PrintError(_("Failed to load settings from \"%s\": %s"), fname.c_str(), e.what());
return(false);
}
}
catch(std::exception &e)
{
MDFN_printf("\n");
MDFN_PrintError(_("Failed to load settings from \"%s\": %s"), fname.c_str(), e.what());
return(false);
}
MDFN_printf("\n");
return(true);
}
static bool compare_sname(MDFNCS *first, MDFNCS *second)
{
return(strcmp(first->name, second->name) < 0);
}
static void SaveSettings(Stream *fp)
{
std::multimap <uint32, MDFNCS>::iterator sit;
std::list<MDFNCS *> SortedList;
std::list<MDFNCS *>::iterator lit;
fp->printf(";VERSION %s\n", MEDNAFEN_VERSION);
fp->printf(_(";Edit this file at your own risk!\n"));
fp->printf(_(";File format: <key><single space><value><LF or CR+LF>\n\n"));
for(sit = CurrentSettings.begin(); sit != CurrentSettings.end(); sit++)
SortedList.push_back(&sit->second);
SortedList.sort(compare_sname);
for(lit = SortedList.begin(); lit != SortedList.end(); lit++)
{
if((*lit)->desc->type == MDFNST_ALIAS)
continue;
fp->printf(";%s\n%s %s\n\n", _((*lit)->desc->description), (*lit)->name, (*lit)->value);
}
if(UnknownSettings.size())
{
fp->printf("\n;\n;Unrecognized settings follow:\n;\n\n");
for(unsigned int i = 0; i < UnknownSettings.size(); i++)
{
fp->printf("%s %s\n\n", UnknownSettings[i].name, UnknownSettings[i].value);
}
}
fp->close();
}
bool MDFN_SaveSettings(const char *path)
{
try
{
FileStream fp(path, FileStream::MODE_WRITE);
SaveSettings(&fp);
}
catch(std::exception &e)
{
MDFND_PrintError(e.what());
return(0);
}
fclose(fp);
return(1);
}
static INLINE void MergeSettingSub(const MDFNSetting *setting)
{
MDFNCS TempSetting;
@ -371,11 +411,7 @@ static INLINE void MergeSettingSub(const MDFNSetting *setting)
assert(setting->default_value);
if(FindSetting(setting->name, false, true) != NULL)
{
printf("Duplicate setting name %s\n", setting->name);
//abort();
return;
}
name_hash = MakeNameHash(setting->name);
@ -409,64 +445,30 @@ bool MDFN_MergeSettings(const std::vector<MDFNSetting> &setting)
return(1);
}
static bool compare_sname(MDFNCS *first, MDFNCS *second)
{
return(strcmp(first->name, second->name) < 0);
}
bool MDFN_SaveSettings(void)
void MDFN_KillSettings(void)
{
std::multimap <uint32, MDFNCS>::iterator sit;
std::list<MDFNCS *> SortedList;
std::list<MDFNCS *>::iterator lit;
FILE *fp;
if(!(fp = fopen(fname.c_str(), "wb")))
return(0);
trio_fprintf(fp, ";VERSION %s\n", MEDNAFEN_VERSION);
trio_fprintf(fp, _(";Edit this file at your own risk!\n"));
trio_fprintf(fp, _(";File format: <key><single space><value><LF or CR+LF>\n\n"));
for(sit = CurrentSettings.begin(); sit != CurrentSettings.end(); sit++)
{
SortedList.push_back(&sit->second);
//trio_fprintf(fp, ";%s\n%s %s\n\n", _(sit->second.desc->description), sit->second.name, sit->second.value);
//free(sit->second.name);
//free(sit->second.value);
}
SortedList.sort(compare_sname);
for(lit = SortedList.begin(); lit != SortedList.end(); lit++)
{
if((*lit)->desc->type == MDFNST_ALIAS)
if(sit->second.desc->type == MDFNST_ALIAS)
continue;
trio_fprintf(fp, ";%s\n%s %s\n\n", _((*lit)->desc->description), (*lit)->name, (*lit)->value);
free((*lit)->name);
free((*lit)->value);
free(sit->second.name);
free(sit->second.value);
}
if(UnknownSettings.size())
{
trio_fprintf(fp, "\n;\n;Unrecognized settings follow:\n;\n\n");
for(unsigned int i = 0; i < UnknownSettings.size(); i++)
{
trio_fprintf(fp, "%s %s\n\n", UnknownSettings[i].name, UnknownSettings[i].value);
free(UnknownSettings[i].name);
free(UnknownSettings[i].value);
}
}
CurrentSettings.clear(); // Call after the list is all handled
UnknownSettings.clear();
fclose(fp);
return(1);
}
static MDFNCS *FindSetting(const char *name, bool dref_alias, bool dont_freak_out_on_fail)
@ -606,8 +608,13 @@ bool MDFNI_SetSetting(const char *name, const char *value, bool NetplayOverride)
if(zesetting)
{
if(!ValidateSetting(value, zesetting->desc))
try
{
ValidateSetting(value, zesetting->desc);
}
catch(std::exception &e)
{
MDFND_PrintError(e.what());
return(0);
}
@ -621,6 +628,13 @@ bool MDFNI_SetSetting(const char *name, const char *value, bool NetplayOverride)
}
else
{
// Overriding the per-game override. Poetic. Though not really.
if(zesetting->game_override)
{
free(zesetting->game_override);
zesetting->game_override = NULL;
}
if(zesetting->value)
free(zesetting->value);
zesetting->value = strdup(value);
@ -674,9 +688,9 @@ bool MDFNI_SetSettingUI(const char *name, uint64 value)
return(MDFNI_SetSetting(name, tmpstr, FALSE));
}
bool MDFNI_DumpSettingsDef(const char *path)
void MDFNI_DumpSettingsDef(const char *path)
{
FILE *fp = fopen(path, "wb");
FileStream fp(path, FileStream::MODE_WRITE);
std::multimap <uint32, MDFNCS>::iterator sit;
std::list<MDFNCS *> SortedList;
@ -705,7 +719,6 @@ bool MDFNI_DumpSettingsDef(const char *path)
fts[MDFNSF_REQUIRES_RESTART] = "MDFNSF_REQUIRES_RESTART";
for(sit = CurrentSettings.begin(); sit != CurrentSettings.end(); sit++)
SortedList.push_back(&sit->second);
@ -720,32 +733,32 @@ bool MDFNI_DumpSettingsDef(const char *path)
if(setting->type == MDFNST_ALIAS)
continue;
fprintf(fp, "%s\n", setting->name);
fp.printf("%s\n", setting->name);
for(unsigned int i = 0; i < 32; i++)
{
if(setting->flags & (1 << i))
fprintf(fp, "%s ", fts[1 << i]);
fp.printf("%s ", fts[1 << i]);
}
fprintf(fp, "\n");
fp.printf("\n");
desc_escaped = escape_string(setting->description ? setting->description : "");
desc_extra_escaped = escape_string(setting->description_extra ? setting->description_extra : "");
fprintf(fp, "%s\n", desc_escaped);
fprintf(fp, "%s\n", desc_extra_escaped);
fp.printf("%s\n", desc_escaped);
fp.printf("%s\n", desc_extra_escaped);
free(desc_escaped);
free(desc_extra_escaped);
fprintf(fp, "%s\n", tts[setting->type]);
fprintf(fp, "%s\n", setting->default_value ? setting->default_value : "");
fprintf(fp, "%s\n", setting->minimum ? setting->minimum : "");
fprintf(fp, "%s\n", setting->maximum ? setting->maximum : "");
fp.printf("%s\n", tts[setting->type]);
fp.printf("%s\n", setting->default_value ? setting->default_value : "");
fp.printf("%s\n", setting->minimum ? setting->minimum : "");
fp.printf("%s\n", setting->maximum ? setting->maximum : "");
if(!setting->enum_list)
fprintf(fp, "0\n");
fp.printf("0\n");
else
{
const MDFNSetting_EnumList *el = setting->enum_list;
@ -757,7 +770,7 @@ bool MDFNI_DumpSettingsDef(const char *path)
el++;
}
fprintf(fp, "%d\n", count);
fp.printf("%d\n", count);
el = setting->enum_list;
while(el->string)
@ -765,9 +778,9 @@ bool MDFNI_DumpSettingsDef(const char *path)
desc_escaped = escape_string(el->description ? el->description : "");
desc_extra_escaped = escape_string(el->description_extra ? el->description_extra : "");
fprintf(fp, "%s\n", el->string);
fprintf(fp, "%s\n", desc_escaped);
fprintf(fp, "%s\n", desc_extra_escaped);
fp.printf("%s\n", el->string);
fp.printf("%s\n", desc_escaped);
fp.printf("%s\n", desc_extra_escaped);
free(desc_escaped);
free(desc_extra_escaped);
@ -777,9 +790,5 @@ bool MDFNI_DumpSettingsDef(const char *path)
}
}
fclose(fp);
return(1);
fp.close();
}

View File

@ -5,10 +5,12 @@
#include "settings-common.h"
bool MFDN_LoadSettings(const char *);
bool MDFN_LoadSettings(const char *path, const char *section = NULL, bool override = false);
bool MDFN_MergeSettings(const MDFNSetting *);
bool MDFN_MergeSettings(const std::vector<MDFNSetting> &);
bool MDFN_SaveSettings(void);
bool MDFN_SaveSettings(const char *path);
void MDFN_KillSettings(void); // Free any resources acquired.
// This should assert() or something if the setting isn't found, since it would
// be a totally tubular error!

View File

@ -4,4 +4,4 @@ DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/intl -I$(top_buildd
noinst_LIBRARIES = libmdfnsound.a
libmdfnsound_a_SOURCES = sound.cpp Blip_Buffer.cpp Stereo_Buffer.cpp Fir_Resampler.cpp WAVRecord.cpp
libmdfnsound_a_SOURCES = Blip_Buffer.cpp Stereo_Buffer.cpp Fir_Resampler.cpp WAVRecord.cpp

View File

@ -74,7 +74,7 @@ am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
am__v_at_0 = @
libmdfnsound_a_AR = $(AR) $(ARFLAGS)
libmdfnsound_a_LIBADD =
am_libmdfnsound_a_OBJECTS = sound.$(OBJEXT) Blip_Buffer.$(OBJEXT) \
am_libmdfnsound_a_OBJECTS = Blip_Buffer.$(OBJEXT) \
Stereo_Buffer.$(OBJEXT) Fir_Resampler.$(OBJEXT) \
WAVRecord.$(OBJEXT)
libmdfnsound_a_OBJECTS = $(am_libmdfnsound_a_OBJECTS)
@ -113,6 +113,8 @@ ALLOCA = @ALLOCA@
ALSA_CFLAGS = @ALSA_CFLAGS@
ALSA_LIBS = @ALSA_LIBS@
AMTAR = @AMTAR@
AM_CFLAGS = @AM_CFLAGS@
AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
@ -231,6 +233,8 @@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
SNDFILE_LIBS = @SNDFILE_LIBS@
SNES_EXTRA_CXXFLAGS = @SNES_EXTRA_CXXFLAGS@
SNES_EXTRA_FLAGS = @SNES_EXTRA_FLAGS@
SSE2_CFLAGS = @SSE2_CFLAGS@
SSE3_CFLAGS = @SSE3_CFLAGS@
SSE_CFLAGS = @SSE_CFLAGS@
@ -239,6 +243,7 @@ TRIO_CFLAGS = @TRIO_CFLAGS@
USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
WARNING_FLAGS = @WARNING_FLAGS@
WINDRES = @WINDRES@
WOE32 = @WOE32@
WOE32DLL = @WOE32DLL@
@ -306,7 +311,7 @@ top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = subdir-objects
DEFAULT_INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/intl -I$(top_builddir)/include/blip
noinst_LIBRARIES = libmdfnsound.a
libmdfnsound_a_SOURCES = sound.cpp Blip_Buffer.cpp Stereo_Buffer.cpp Fir_Resampler.cpp WAVRecord.cpp
libmdfnsound_a_SOURCES = Blip_Buffer.cpp Stereo_Buffer.cpp Fir_Resampler.cpp WAVRecord.cpp
all: all-am
.SUFFIXES:
@ -359,7 +364,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Fir_Resampler.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Stereo_Buffer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WAVRecord.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sound.Po@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\

View File

@ -20,24 +20,23 @@
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <time.h>
#include "include/trio/trio.h"
#include <trio/trio.h>
#include "driver.h"
#include "general.h"
#include "state.h"
#include "movie.h"
#include "netplay.h"
#include "video.h"
#include "video/resize.h"
static int SaveStateStatus[10];
#define RLSB MDFNSTATE_RLSB //0x80000000
static int32 smem_read(StateMem *st, void *buffer, uint32 len)
int32 smem_read(StateMem *st, void *buffer, uint32 len)
{
if((len + st->loc) > st->len)
return(0);
@ -48,7 +47,7 @@ static int32 smem_read(StateMem *st, void *buffer, uint32 len)
return(len);
}
static int32 smem_write(StateMem *st, void *buffer, uint32 len)
int32 smem_write(StateMem *st, void *buffer, uint32 len)
{
if((len + st->loc) > st->malloced)
{
@ -67,7 +66,7 @@ static int32 smem_write(StateMem *st, void *buffer, uint32 len)
return(len);
}
static int32 smem_putc(StateMem *st, int value)
int32 smem_putc(StateMem *st, int value)
{
uint8 tmpval = value;
if(smem_write(st, &tmpval, 1) != 1)
@ -75,12 +74,12 @@ static int32 smem_putc(StateMem *st, int value)
return(1);
}
static int32 smem_tell(StateMem *st)
int32 smem_tell(StateMem *st)
{
return(st->loc);
}
static int32 smem_seek(StateMem *st, uint32 offset, int whence)
int32 smem_seek(StateMem *st, uint32 offset, int whence)
{
switch(whence)
{
@ -104,7 +103,7 @@ static int32 smem_seek(StateMem *st, uint32 offset, int whence)
return(0);
}
static int smem_write32le(StateMem *st, uint32 b)
int smem_write32le(StateMem *st, uint32 b)
{
uint8 s[4];
s[0]=b;
@ -114,7 +113,7 @@ static int smem_write32le(StateMem *st, uint32 b)
return((smem_write(st, s, 4)<4)?0:4);
}
static int smem_read32le(StateMem *st, uint32 *b)
int smem_read32le(StateMem *st, uint32 *b)
{
uint8 s[4];
@ -126,6 +125,7 @@ static int smem_read32le(StateMem *st, uint32 *b)
return(4);
}
static bool ValidateSFStructure(SFORMAT *sf)
{
SFORMAT *saved_sf = sf;
@ -153,6 +153,8 @@ static bool ValidateSFStructure(SFORMAT *sf)
static bool SubWrite(StateMem *st, SFORMAT *sf, int data_only, const char *name_prefix = NULL)
{
// FIXME? It's kind of slow, and we definitely don't want it on with state rewinding...
if(!data_only)
ValidateSFStructure(sf);
while(sf->size || sf->name) // Size can sometimes be zero, so also check for the text name. These two should both be zero only at the end of a struct.
@ -165,7 +167,7 @@ static bool SubWrite(StateMem *st, SFORMAT *sf, int data_only, const char *name_
if(sf->size == (uint32)~0) /* Link to another struct. */
{
if(!SubWrite(st, (SFORMAT *)sf->v, 0, name_prefix))
if(!SubWrite(st, (SFORMAT *)sf->v, data_only, name_prefix))
return(0);
sf++;
@ -174,6 +176,15 @@ static bool SubWrite(StateMem *st, SFORMAT *sf, int data_only, const char *name_
int32 bytesize = sf->size;
// If we're only saving the raw data, and we come across a bool type, we save it as it is in memory, rather than converting it to
// 1-byte. In the SFORMAT structure, the size member for bool entries is the number of bool elements, not the total in-memory size,
// so we adjust it here.
if(data_only && (sf->flags & MDFNSTATE_BOOL))
{
bytesize *= sizeof(bool);
}
if(!data_only)
{
char nameo[1 + 256];
int slen;
@ -207,7 +218,7 @@ static bool SubWrite(StateMem *st, SFORMAT *sf, int data_only, const char *name_
// Special case for the evil bool type, to convert bool to 1-byte elements.
// Don't do it if we're only saving the raw data.
if((sf->flags & MDFNSTATE_BOOL))
if((sf->flags & MDFNSTATE_BOOL) && !data_only)
{
for(int32 bool_monster = 0; bool_monster < bytesize; bool_monster++)
{
@ -219,6 +230,7 @@ static bool SubWrite(StateMem *st, SFORMAT *sf, int data_only, const char *name_
else
smem_write(st, (uint8 *)sf->v, bytesize);
if(!data_only)
{
/* Now restore the original byte order. */
if(sf->flags & MDFNSTATE_BOOL)
@ -245,6 +257,7 @@ static int WriteStateChunk(StateMem *st, const char *sname, SFORMAT *sf, int dat
int32 data_start_pos;
int32 end_pos;
if(!data_only)
{
uint8 sname_tmp[32];
@ -261,11 +274,12 @@ static int WriteStateChunk(StateMem *st, const char *sname, SFORMAT *sf, int dat
data_start_pos = smem_tell(st);
if(!SubWrite(st, sf, 0))
if(!SubWrite(st, sf, data_only))
return(0);
end_pos = smem_tell(st);
if(!data_only)
{
smem_seek(st, data_start_pos - 4, SEEK_SET);
smem_write32le(st, end_pos - data_start_pos);
@ -311,10 +325,47 @@ static void MakeSFMap(SFORMAT *sf, SFMap_t &sfmap)
}
}
// Fast raw chunk reader
static void DOReadChunk(StateMem *st, SFORMAT *sf)
{
while(sf->size || sf->name) // Size can sometimes be zero, so also check for the text name.
// These two should both be zero only at the end of a struct.
{
if(!sf->size || !sf->v)
{
sf++;
continue;
}
if(sf->size == (uint32) ~0) // Link to another SFORMAT struct
{
DOReadChunk(st, (SFORMAT *)sf->v);
sf++;
continue;
}
int32 bytesize = sf->size;
// Loading raw data, bool types are stored as they appear in memory, not as single bytes in the full state format.
// In the SFORMAT structure, the size member for bool entries is the number of bool elements, not the total in-memory size,
// so we adjust it here.
if(sf->flags & MDFNSTATE_BOOL)
bytesize *= sizeof(bool);
smem_read(st, (uint8 *)sf->v, bytesize);
sf++;
}
}
static int ReadStateChunk(StateMem *st, SFORMAT *sf, int size, int data_only)
{
int temp;
if(data_only)
{
DOReadChunk(st, sf);
}
else
{
SFMap_t sfmap;
SFMap_t sfmap_found; // Used for identifying variables that are missing in the save state.
@ -419,6 +470,14 @@ int MDFNSS_StateAction(StateMem *st, int load, int data_only, std::vector <SSDes
if(load)
{
if(data_only)
{
for(section = sections.begin(); section != sections.end(); section++)
{
ReadStateChunk(st, section->sf, ~0, 1);
}
}
else
{
char sname[32];
@ -448,6 +507,7 @@ int MDFNSS_StateAction(StateMem *st, int load, int data_only, std::vector <SSDes
}
else
{
// puts("SEEK");
if(smem_seek(st, tmp_size, SEEK_CUR) < 0)
{
puts("Chunk seek failure");
@ -472,7 +532,7 @@ int MDFNSS_StateAction(StateMem *st, int load, int data_only, std::vector <SSDes
{
for(section = sections.begin(); section != sections.end(); section++)
{
if(!WriteStateChunk(st, section->name, section->sf, 0))
if(!WriteStateChunk(st, section->name, section->sf, data_only))
return(0);
}
}
@ -485,34 +545,116 @@ int MDFNSS_StateAction(StateMem *st, int load, int data_only, SFORMAT *sf, const
std::vector <SSDescriptor> love;
love.push_back(SSDescriptor(sf, name, optional));
return(MDFNSS_StateAction(st, load, 0, love));
return(MDFNSS_StateAction(st, load, data_only, love));
}
int MDFNSS_SaveSM(StateMem *st)
int MDFNSS_SaveSM(StateMem *st, int wantpreview_and_ts, int data_only, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const MDFN_Rect *LineWidths)
{
static const char *header_magic = "MDFNSVST";
uint8 header[32];
int neowidth = 0, neoheight = 0;
memset(header, 0, sizeof(header));
memcpy(header, header_magic, 8);
MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC);
MDFN_en32lsb(header + 24, neowidth);
MDFN_en32lsb(header + 28, neoheight);
smem_write(st, header, 32);
if(wantpreview_and_ts)
{
bool is_multires = FALSE;
if(!MDFNGameInfo->StateAction(st, 0, 0))
// We'll want to use the nominal width if the source rectangle is > 25% off on either axis, or the source image has
// multiple horizontal resolutions.
neowidth = MDFNGameInfo->nominal_width;
neoheight = MDFNGameInfo->nominal_height;
if(LineWidths[0].w != ~0)
{
uint32 first_w = LineWidths[DisplayRect->y].w;
for(int y = 0; y < DisplayRect->h; y++)
if(LineWidths[DisplayRect->y + y].w != first_w)
{
puts("Multires!");
is_multires = TRUE;
}
}
if(!is_multires)
{
if(((double)DisplayRect->w / MDFNGameInfo->nominal_width) > 0.75 && ((double)DisplayRect->w / MDFNGameInfo->nominal_width) < 1.25)
neowidth = DisplayRect->w;
if(((double)DisplayRect->h / MDFNGameInfo->nominal_height) > 0.75 && ((double)DisplayRect->h / MDFNGameInfo->nominal_height) < 1.25)
neoheight = DisplayRect->h;
}
}
if(!data_only)
{
memcpy(header, header_magic, 8);
if(wantpreview_and_ts)
MDFN_en64lsb(header + 8, time(NULL));
MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC);
MDFN_en32lsb(header + 24, neowidth);
MDFN_en32lsb(header + 28, neoheight);
smem_write(st, header, 32);
}
if(wantpreview_and_ts)
{
uint8 *previewbuffer = (uint8 *)malloc(4 * neowidth * neoheight);
MDFN_Surface *dest_surface = new MDFN_Surface((uint32 *)previewbuffer, neowidth, neoheight, neowidth, surface->format);
MDFN_Rect dest_rect;
dest_rect.x = 0;
dest_rect.y = 0;
dest_rect.w = neowidth;
dest_rect.h = neoheight;
MDFN_ResizeSurface(surface, DisplayRect, (LineWidths[0].w != ~0) ? LineWidths : NULL, dest_surface, &dest_rect);
{
uint32 a, b = 0;
for(a = 0; a < neowidth * neoheight * 4; a+=4)
{
uint32 c = *(uint32 *)&previewbuffer[a];
int nr, ng, nb;
surface->DecodeColor(c, nr, ng, nb);
previewbuffer[b + 0] = nr;
previewbuffer[b + 1] = ng;
previewbuffer[b + 2] = nb;
b += 3;
}
}
smem_write(st, previewbuffer, 3 * neowidth * neoheight);
free(previewbuffer);
delete dest_surface;
}
// State rewinding code path hack, FIXME
if(data_only)
{
if(!MDFN_RawInputStateAction(st, 0, data_only))
return(0);
}
if(!MDFNGameInfo->StateAction(st, 0, data_only))
return(0);
uint32 sizy = smem_tell(st);
smem_seek(st, 16 + 4, SEEK_SET);
smem_write32le(st, sizy);
if(!data_only)
{
uint32 sizy = smem_tell(st);
smem_seek(st, 16 + 4, SEEK_SET);
smem_write32le(st, sizy);
}
return(1);
}
static int MDFNSS_Save(const char *fname, const char *suffix)
int MDFNSS_Save(const char *fname, const char *suffix, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const MDFN_Rect *LineWidths)
{
StateMem st;
@ -525,7 +667,7 @@ static int MDFNSS_Save(const char *fname, const char *suffix)
return(0);
}
if(!MDFNSS_SaveSM(&st))
if(!MDFNSS_SaveSM(&st, (DisplayRect && LineWidths), 0, surface, DisplayRect, LineWidths))
{
if(st.data)
free(st.data);
@ -556,22 +698,74 @@ static int MDFNSS_Save(const char *fname, const char *suffix)
return(1);
}
int MDFNSS_LoadSM(StateMem *st)
// Convenience function for movie.cpp
int MDFNSS_SaveFP(gzFile fp, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const MDFN_Rect *LineWidths)
{
uint8 header[32];
uint32 stateversion;
StateMem st;
smem_read(st, header, 32);
memset(&st, 0, sizeof(StateMem));
if(memcmp(header, "MEDNAFENSVESTATE", 16) && memcmp(header, "MDFNSVST", 8))
if(!MDFNSS_SaveSM(&st, (DisplayRect && LineWidths), 0, surface, DisplayRect, LineWidths))
{
if(st.data)
free(st.data);
return(0);
}
stateversion = MDFN_de32lsb(header + 16);
if(gzwrite(fp, st.data, st.len) != (int32)st.len)
{
if(st.data)
free(st.data);
return(0);
}
return(MDFNGameInfo->StateAction(st, stateversion, 0));
if(st.data)
free(st.data);
return(1);
}
static int MDFNSS_LoadFP(gzFile fp)
int MDFNSS_LoadSM(StateMem *st, int haspreview, int data_only)
{
uint8 header[32];
uint32 stateversion;
if(data_only)
{
stateversion = MEDNAFEN_VERSION_NUMERIC;
}
else
{
smem_read(st, header, 32);
if(memcmp(header, "MEDNAFENSVESTATE", 16) && memcmp(header, "MDFNSVST", 8))
return(0);
stateversion = MDFN_de32lsb(header + 16);
}
if(haspreview)
{
uint32 width = MDFN_de32lsb(header + 24);
uint32 height = MDFN_de32lsb(header + 28);
uint32 psize;
psize = width * height * 3;
smem_seek(st, psize, SEEK_CUR); // Skip preview
}
// State rewinding code path hack, FIXME
if(data_only)
{
if(!MDFN_RawInputStateAction(st, stateversion, data_only))
return(0);
}
return(MDFNGameInfo->StateAction(st, stateversion, data_only));
}
int MDFNSS_LoadFP(gzFile fp)
{
uint8 header[32];
StateMem st;
@ -596,7 +790,7 @@ static int MDFNSS_LoadFP(gzFile fp)
free(st.data);
return(0);
}
if(!MDFNSS_LoadSM(&st))
if(!MDFNSS_LoadSM(&st, 1, 0))
{
free(st.data);
return(0);
@ -605,7 +799,7 @@ static int MDFNSS_LoadFP(gzFile fp)
return(1);
}
static int MDFNSS_Load(const char *fname, const char *suffix)
int MDFNSS_Load(const char *fname, const char *suffix)
{
gzFile st;
@ -665,7 +859,7 @@ void MDFNSS_CheckStates(void)
struct stat stat_buf;
SaveStateStatus[ssel] = 0;
//printf("%s\n", MDFN_MakeFName(MDFNMKF_STATE, ssel, 0).c_str());
if(stat(MDFN_MakeFName(MDFNMKF_STATE, ssel, 0).c_str(), &stat_buf) == 0)
{
SaveStateStatus[ssel] = 1;
@ -684,6 +878,9 @@ void MDFNSS_CheckStates(void)
void MDFNSS_GetStateInfo(const char *filename, StateStatusStruct *status)
{
gzFile fp;
uint32 StateShowPBWidth;
uint32 StateShowPBHeight;
uint8 *previewbuffer = NULL;
fp = gzopen(filename, "rb");
if(fp)
@ -691,12 +888,35 @@ void MDFNSS_GetStateInfo(const char *filename, StateStatusStruct *status)
uint8 header[32];
gzread(fp, header, 32);
uint32 width = MDFN_de32lsb(header + 24);
uint32 height = MDFN_de32lsb(header + 28);
if(width > 1024) width = 1024;
if(height > 1024) height = 1024;
if(!(previewbuffer = (uint8 *)MDFN_malloc(3 * width * height, _("Save state preview buffer"))))
{
StateShowPBWidth = 0;
StateShowPBHeight = 0;
}
else
{
gzread(fp, previewbuffer, 3 * width * height);
StateShowPBWidth = width;
StateShowPBHeight = height;
}
gzclose(fp);
}
else
{
StateShowPBWidth = MDFNGameInfo->nominal_width;
StateShowPBHeight = MDFNGameInfo->nominal_height;
}
status->gfx = previewbuffer;
status->w = StateShowPBWidth;
status->h = StateShowPBHeight;
}
void MDFNI_SelectState(int w)
@ -736,13 +956,13 @@ void MDFNI_SelectState(int w)
MDFND_SetStateStatus(status);
}
void MDFNI_SaveState(const char *fname, const char *suffix)
void MDFNI_SaveState(const char *fname, const char *suffix, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const MDFN_Rect *LineWidths)
{
if(!MDFNGameInfo->StateAction)
return;
MDFND_SetStateStatus(NULL);
MDFNSS_Save(fname, suffix);
MDFNSS_Save(fname, suffix, surface, DisplayRect, LineWidths);
}
void MDFNI_LoadState(const char *fname, const char *suffix)
@ -752,5 +972,271 @@ void MDFNI_LoadState(const char *fname, const char *suffix)
MDFND_SetStateStatus(NULL);
MDFNSS_Load(fname, suffix);
/* For network play and movies, be load the state locally, and then save the state to a temporary buffer,
and send or record that. This ensures that if an older state is loaded that is missing some
information expected in newer save states, desynchronization won't occur(at least not
from this ;)).
*/
if(MDFNSS_Load(fname, suffix))
{
}
}
#include "compress/minilzo.h"
#include "compress/quicklz.h"
#include "compress/blz.h"
static union
{
char qlz_scratch_compress[/*QLZ_*/SCRATCH_COMPRESS];
char qlz_scratch_decompress[/*QLZ_*/SCRATCH_DECOMPRESS];
};
enum
{
SRW_COMPRESSOR_MINILZO = 0,
SRW_COMPRESSOR_QUICKLZ,
SRW_COMPRESSOR_BLZ
};
struct StateMemPacket
{
uint8 *data;
uint32 compressed_len;
uint32 uncompressed_len;
StateMem MovieLove;
};
static int SRW_NUM = 600;
static int SRWCompressor;
static int EvilEnabled = 0;
static StateMemPacket *bcs;
static int32 bcspos;
void MDFN_StateEvilBegin(void)
{
int x;
std::string srwcompstring;
if(!EvilEnabled)
return;
SRW_NUM = MDFN_GetSettingUI("srwframes");
SRWCompressor = SRW_COMPRESSOR_MINILZO;
srwcompstring = MDFN_GetSettingS("srwcompressor");
if(srwcompstring == "minilzo")
SRWCompressor = SRW_COMPRESSOR_MINILZO;
else if(srwcompstring == "quicklz")
SRWCompressor = SRW_COMPRESSOR_QUICKLZ;
else if(srwcompstring == "blz")
SRWCompressor = SRW_COMPRESSOR_BLZ;
bcs = (StateMemPacket *)calloc(SRW_NUM, sizeof(StateMemPacket));
bcspos = 0;
for(x=0;x<SRW_NUM;x++)
{
bcs[x].data = NULL;
bcs[x].compressed_len = 0;
bcs[x].uncompressed_len = 0;
memset(&bcs[x].MovieLove, 0, sizeof(StateMem));
}
}
bool MDFN_StateEvilIsRunning(void)
{
return(EvilEnabled);
}
void MDFN_StateEvilEnd(void)
{
int x;
if(!EvilEnabled)
return;
if(bcs)
{
for(x = 0;x < SRW_NUM; x++)
{
if(bcs[x].data)
free(bcs[x].data);
bcs[x].data = NULL;
bcs[x].compressed_len = 0;
}
free(bcs);
}
}
void MDFN_StateEvilFlushMovieLove(void)
{
int bahpos = (bcspos + 1) % SRW_NUM;
for(int x = 0; x < SRW_NUM; x++)
{
if(bcs[bahpos].MovieLove.data)
{
free(bcs[bahpos].MovieLove.data);
bcs[bahpos].MovieLove.data = NULL;
}
bahpos = (bahpos + 1) % SRW_NUM;
}
}
int MDFN_StateEvil(int rewind)
{
if(!EvilEnabled)
return(0);
if(rewind)
{
int32 next_bcspos = bcspos;
bool NeedDataFlush = FALSE;
bcspos--;
if(bcspos < 0) bcspos += SRW_NUM;
if(!bcs[bcspos].data)
bcspos = (bcspos + 1) % SRW_NUM;
else
NeedDataFlush = TRUE;
if(bcs[bcspos].compressed_len)
{
uint8 *tmp_buf;
lzo_uint dst_len = bcs[bcspos].uncompressed_len;
tmp_buf = (uint8 *)malloc(bcs[bcspos].uncompressed_len);
if(SRWCompressor == SRW_COMPRESSOR_QUICKLZ)
dst_len = qlz_decompress((char*)bcs[bcspos].data, tmp_buf, qlz_scratch_decompress);
else if(SRWCompressor == SRW_COMPRESSOR_MINILZO)
lzo1x_decompress(bcs[bcspos].data, bcs[bcspos].compressed_len, tmp_buf, &dst_len, NULL);
else if(SRWCompressor == SRW_COMPRESSOR_BLZ)
{
dst_len = blz_unpack(bcs[bcspos].data, tmp_buf);
}
for(uint32 x = 0; x < bcs[bcspos].uncompressed_len && x < bcs[next_bcspos].uncompressed_len; x++)
tmp_buf[x] ^= bcs[next_bcspos].data[x];
free(bcs[bcspos].data);
bcs[bcspos].data = tmp_buf;
bcs[bcspos].compressed_len = 0;
}
if(NeedDataFlush)
{
if(bcs[next_bcspos].MovieLove.data)
{
free(bcs[next_bcspos].MovieLove.data);
bcs[next_bcspos].MovieLove.data = NULL;
}
free(bcs[next_bcspos].data);
bcs[next_bcspos].data = NULL;
bcs[next_bcspos].compressed_len = 0;
bcs[next_bcspos].uncompressed_len = 0;
}
if(bcs[bcspos].uncompressed_len)
{
StateMem sm;
sm.data = bcs[bcspos].data;
sm.loc = 0;
sm.initial_malloc = 0;
sm.malloced = sm.len = bcs[bcspos].uncompressed_len;
MDFNSS_LoadSM(&sm, 0, 1);
return(1);
}
}
else
{
StateMem sm;
int32 prev_bcspos = bcspos;
bcspos = (bcspos + 1) % SRW_NUM;
if(bcs[bcspos].data)
{
free(bcs[bcspos].data);
bcs[bcspos].data = NULL;
}
if(bcs[bcspos].MovieLove.data)
{
free(bcs[bcspos].MovieLove.data);
bcs[bcspos].MovieLove.data = NULL;
}
memset(&sm, 0, sizeof(sm));
MDFNSS_SaveSM(&sm, 0, 1);
bcs[bcspos].data = sm.data;
bcs[bcspos].compressed_len = 0;
bcs[bcspos].uncompressed_len = sm.len;
// Compress the previous save state.
if(bcs[prev_bcspos].data)
{
for(uint32 x = 0; x < bcs[prev_bcspos].uncompressed_len && x < sm.len; x++)
bcs[prev_bcspos].data[x] ^= sm.data[x];
if(SRWCompressor == SRW_COMPRESSOR_QUICKLZ)
{
uint32 dst_len;
uint8 *tmp_buf = (uint8 *)malloc(bcs[prev_bcspos].uncompressed_len + 400);
dst_len = qlz_compress(bcs[prev_bcspos].data, (char*)tmp_buf, bcs[prev_bcspos].uncompressed_len, qlz_scratch_compress);
free(bcs[prev_bcspos].data);
bcs[prev_bcspos].data = (uint8 *)realloc(tmp_buf, dst_len);
bcs[prev_bcspos].compressed_len = dst_len;
}
else if(SRWCompressor == SRW_COMPRESSOR_MINILZO)
{
uint8 workmem[LZO1X_1_MEM_COMPRESS];
uint8 * tmp_buf = (uint8 *)malloc((size_t)(1.10 * bcs[prev_bcspos].uncompressed_len));
lzo_uint dst_len = (lzo_uint)(1.10 * bcs[prev_bcspos].uncompressed_len);
lzo1x_1_compress(bcs[prev_bcspos].data, bcs[prev_bcspos].uncompressed_len, tmp_buf, &dst_len, workmem);
free(bcs[prev_bcspos].data);
bcs[prev_bcspos].data = (uint8 *)realloc(tmp_buf, dst_len);
bcs[prev_bcspos].compressed_len = dst_len;
}
else if(SRWCompressor == SRW_COMPRESSOR_BLZ)
{
blz_pack_t workmem;
uint8 * tmp_buf = (uint8 *)malloc((size_t)(bcs[prev_bcspos].uncompressed_len + blz_pack_extra));
uint32 dst_len = bcs[prev_bcspos].uncompressed_len + blz_pack_extra;
dst_len = blz_pack(bcs[prev_bcspos].data, bcs[prev_bcspos].uncompressed_len, tmp_buf, &workmem);
free(bcs[prev_bcspos].data);
bcs[prev_bcspos].data = (uint8 *)realloc(tmp_buf, dst_len);
bcs[prev_bcspos].compressed_len = dst_len;
}
}
}
return(0);
}
void MDFNI_EnableStateRewind(int enable)
{
if(!MDFNGameInfo->StateAction)
return;
MDFN_StateEvilEnd();
EvilEnabled = enable;
MDFN_StateEvilBegin();
}

View File

@ -1,13 +1,18 @@
#ifndef _STATE_H
#define _STATE_H
#include "zlib.h"
#include <zlib.h>
#include "video.h"
#include "state-common.h"
void MDFNSS_GetStateInfo(const char *filename, StateStatusStruct *status);
int MDFNSS_Save(const char *, const char *suffix, const MDFN_Surface *surface = (MDFN_Surface *)NULL, const MDFN_Rect *DisplayRect = (MDFN_Rect*)NULL, const MDFN_Rect *LineWidths = (MDFN_Rect *)NULL);
int MDFNSS_Load(const char *, const char *suffix);
int MDFNSS_SaveFP(gzFile fp, const MDFN_Surface *surface = (MDFN_Surface *)NULL, const MDFN_Rect *DisplayRect = (MDFN_Rect*)NULL, const MDFN_Rect *LineWidths = (MDFN_Rect *)NULL);
int MDFNSS_LoadFP(gzFile fp);
typedef struct
{
uint8 *data;
@ -19,6 +24,19 @@ typedef struct
uint32 initial_malloc; // A setting!
} StateMem;
// Eh, we abuse the smem_* in-memory stream code
// in a few other places. :)
int32 smem_read(StateMem *st, void *buffer, uint32 len);
int32 smem_write(StateMem *st, void *buffer, uint32 len);
int32 smem_putc(StateMem *st, int value);
int32 smem_tell(StateMem *st);
int32 smem_seek(StateMem *st, uint32 offset, int whence);
int smem_write32le(StateMem *st, uint32 b);
int smem_read32le(StateMem *st, uint32 *b);
int MDFNSS_SaveSM(StateMem *st, int wantpreview_and_ts, int data_only, const MDFN_Surface *surface = (MDFN_Surface *)NULL, const MDFN_Rect *DisplayRect = (MDFN_Rect*)NULL, const MDFN_Rect *LineWidths = (MDFN_Rect *)NULL);
int MDFNSS_LoadSM(StateMem *st, int haspreview, int data_only);
void MDFNSS_CheckStates(void);
// Flag for a single, >= 1 byte native-endian variable
@ -49,49 +67,49 @@ typedef struct {
//uint32 struct_size; // Only used for MDFNSTATE_ARRAYOFS, sizeof(struct) that members of the linked SFORMAT struct are in.
} SFORMAT;
INLINE int SF_IS_BOOL(bool *) { return(1); }
INLINE int SF_IS_BOOL(void *) { return(0); }
INLINE bool SF_IS_BOOL(bool *) { return(1); }
INLINE bool SF_IS_BOOL(void *) { return(0); }
INLINE int SF_FORCE_AB(bool *) { return(0); }
INLINE uint32 SF_FORCE_AB(bool *) { return(0); }
INLINE int SF_FORCE_A8(int8 *) { return(0); }
INLINE int SF_FORCE_A8(uint8 *) { return(0); }
INLINE uint32 SF_FORCE_A8(int8 *) { return(0); }
INLINE uint32 SF_FORCE_A8(uint8 *) { return(0); }
INLINE int SF_FORCE_A16(int16 *) { return(0); }
INLINE int SF_FORCE_A16(uint16 *) { return(0); }
INLINE uint32 SF_FORCE_A16(int16 *) { return(0); }
INLINE uint32 SF_FORCE_A16(uint16 *) { return(0); }
INLINE int SF_FORCE_A32(int32 *) { return(0); }
INLINE int SF_FORCE_A32(uint32 *) { return(0); }
INLINE uint32 SF_FORCE_A32(int32 *) { return(0); }
INLINE uint32 SF_FORCE_A32(uint32 *) { return(0); }
INLINE int SF_FORCE_A64(int64 *) { return(0); }
INLINE int SF_FORCE_A64(uint64 *) { return(0); }
INLINE uint32 SF_FORCE_A64(int64 *) { return(0); }
INLINE uint32 SF_FORCE_A64(uint64 *) { return(0); }
INLINE int SF_FORCE_D(double *) { return(0); }
INLINE uint32 SF_FORCE_D(double *) { return(0); }
#define SFVARN(x, n) { &x, SF_IS_BOOL(&x) ? 1 : sizeof(x), MDFNSTATE_RLSB | (SF_IS_BOOL(&x) ? MDFNSTATE_BOOL : 0), n }
#define SFVAR(x) SFVARN(x, #x)
#define SFVARN(x, n) { &(x), SF_IS_BOOL(&(x)) ? 1 : sizeof(x), MDFNSTATE_RLSB | (SF_IS_BOOL(&(x)) ? MDFNSTATE_BOOL : 0), n }
#define SFVAR(x) SFVARN((x), #x)
#define SFARRAYN(x, l, n) { x, l, 0 | SF_FORCE_A8(x), n }
#define SFARRAY(x, l) SFARRAYN(x, l, #x)
#define SFARRAYN(x, l, n) { (x), (uint32)(l), 0 | SF_FORCE_A8(x), n }
#define SFARRAY(x, l) SFARRAYN((x), (l), #x)
#define SFARRAYBN(x, l, n) { x, l, MDFNSTATE_BOOL | SF_FORCE_AB(x), n }
#define SFARRAYB(x, l) SFARRAYBN(x, l, #x)
#define SFARRAYBN(x, l, n) { (x), (uint32)(l), MDFNSTATE_BOOL | SF_FORCE_AB(x), n }
#define SFARRAYB(x, l) SFARRAYBN((x), (l), #x)
#define SFARRAY16N(x, l, n) {x, (l * sizeof(uint16)), MDFNSTATE_RLSB16 | SF_FORCE_A16(x), n }
#define SFARRAY16(x, l) SFARRAY16N(x, l, #x)
#define SFARRAY16N(x, l, n) { (x), (uint32)((l) * sizeof(uint16)), MDFNSTATE_RLSB16 | SF_FORCE_A16(x), n }
#define SFARRAY16(x, l) SFARRAY16N((x), (l), #x)
#define SFARRAY32N(x, l, n) {x, (l * sizeof(uint32)), MDFNSTATE_RLSB32 | SF_FORCE_A32(x), n }
#define SFARRAY32(x, l) SFARRAY32N(x, l, #x)
#define SFARRAY32N(x, l, n) { (x), (uint32)((l) * sizeof(uint32)), MDFNSTATE_RLSB32 | SF_FORCE_A32(x), n }
#define SFARRAY32(x, l) SFARRAY32N((x), (l), #x)
#define SFARRAY64N(x, l, n) {x, (l * sizeof(uint64)), MDFNSTATE_RLSB64 | SF_FORCE_A64(x), n }
#define SFARRAY64(x, l) SFARRAY64N(x, l, #x)
#define SFARRAY64N(x, l, n) { (x), (uint32)((l) * sizeof(uint64)), MDFNSTATE_RLSB64 | SF_FORCE_A64(x), n }
#define SFARRAY64(x, l) SFARRAY64N((x), (l), #x)
#if SIZEOF_DOUBLE != 8
#error "sizeof(double) != 8"
#endif
#define SFARRAYDN(x, l, n) {x, (l * 8), MDFNSTATE_RLSB64 | SF_FORCE_D(x), n }
#define SFARRAYD(x, l) SFARRAYDN(x, l, #x)
#define SFARRAYDN(x, l, n) { (x), (uint32)((l) * 8), MDFNSTATE_RLSB64 | SF_FORCE_D(x), n }
#define SFARRAYD(x, l) SFARRAYDN((x), (l), #x)
#define SFEND { 0, 0, 0, 0 }
@ -120,7 +138,10 @@ class SSDescriptor
int MDFNSS_StateAction(StateMem *st, int load, int data_only, std::vector <SSDescriptor> &sections);
int MDFNSS_StateAction(StateMem *st, int load, int data_only, SFORMAT *sf, const char *name, bool optional = 0);
int MDFNSS_SaveSM(StateMem *st);
int MDFNSS_LoadSM(StateMem *st);
void MDFN_StateEvilFlushMovieLove(void);
bool MDFN_StateEvilIsRunning(void);
void MDFN_StateEvilBegin(void);
void MDFN_StateEvilEnd(void);
int MDFN_StateEvil(int);
#endif

View File

@ -1,3 +1,5 @@
// DO NOT REMOVE/DISABLE THESE MATH AND COMPILER SANITY TESTS. THEY EXIST FOR A REASON.
/* Mednafen - Multi-system Emulator
*
* This program is free software; you can redistribute it and/or modify
@ -39,7 +41,7 @@ typedef struct
int32 mostnegresult;
} MathTestEntry;
#define ADD_MTE(_bits) { _bits, ((uint32)1 << _bits) - 1, (uint32)1 << (_bits - 1), 0 - ((uint32)1 << (_bits - 1)) }
#define ADD_MTE(_bits) { _bits, ((uint32)1 << _bits) - 1, (uint32)1 << (_bits - 1), (int32)(0 - ((uint32)1 << (_bits - 1))) }
MathTestEntry math_test_vals[] =
{

View File

@ -118,6 +118,8 @@ ALLOCA = @ALLOCA@
ALSA_CFLAGS = @ALSA_CFLAGS@
ALSA_LIBS = @ALSA_LIBS@
AMTAR = @AMTAR@
AM_CFLAGS = @AM_CFLAGS@
AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
@ -236,6 +238,8 @@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
SNDFILE_LIBS = @SNDFILE_LIBS@
SNES_EXTRA_CXXFLAGS = @SNES_EXTRA_CXXFLAGS@
SNES_EXTRA_FLAGS = @SNES_EXTRA_FLAGS@
SSE2_CFLAGS = @SSE2_CFLAGS@
SSE3_CFLAGS = @SSE3_CFLAGS@
SSE_CFLAGS = @SSE_CFLAGS@
@ -244,6 +248,7 @@ TRIO_CFLAGS = @TRIO_CFLAGS@
USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
WARNING_FLAGS = @WARNING_FLAGS@
WINDRES = @WINDRES@
WOE32 = @WOE32@
WOE32DLL = @WOE32DLL@

View File

@ -1,265 +0,0 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: illustrate seeking, and test it too
last mod: $Id: iseeking_example.c 16037 2009-05-26 21:10:58Z xiphmont $
********************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include "ivorbiscodec.h"
#include "ivorbisfile.h"
#ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */
# include <io.h>
# include <fcntl.h>
#endif
void _verify(OggVorbis_File *ov,
ogg_int64_t val,
ogg_int64_t pcmval,
ogg_int64_t timeval,
ogg_int64_t pcmlength,
char *bigassbuffer){
int j;
long bread;
char buffer[4096];
int dummy;
ogg_int64_t pos;
/* verify the raw position, the pcm position and position decode */
if(val!=-1 && ov_raw_tell(ov)<val){
fprintf(stderr,"raw position out of tolerance: requested %ld, got %ld\n",
(long)val,(long)ov_raw_tell(ov));
exit(1);
}
if(pcmval!=-1 && ov_pcm_tell(ov)>pcmval){
fprintf(stderr,"pcm position out of tolerance: requested %ld, got %ld\n",
(long)pcmval,(long)ov_pcm_tell(ov));
exit(1);
}
if(timeval!=-1 && ov_time_tell(ov)>timeval){
fprintf(stderr,"time position out of tolerance: requested %ld, got %ld\n",
(long)timeval,(long)ov_time_tell(ov));
exit(1);
}
pos=ov_pcm_tell(ov);
if(pos<0 || pos>pcmlength){
fprintf(stderr,"pcm position out of bounds: got %ld\n",(long)pos);
exit(1);
}
bread=ov_read(ov,buffer,4096,&dummy);
if(bigassbuffer){
for(j=0;j<bread;j++){
if(buffer[j]!=bigassbuffer[j+pos*4]){
fprintf(stderr,"data position after seek doesn't match pcm position\n");
{
FILE *f=fopen("a.m","w");
for(j=0;j<bread;j++)fprintf(f,"%d\n",(int)buffer[j]);
fclose(f);
f=fopen("b.m","w");
for(j=0;j<bread;j++)fprintf(f,"%d\n",(int)bigassbuffer[j+pos*2]);
fclose(f);
}
exit(1);
}
}
}
}
int main(){
OggVorbis_File ov;
int i,ret;
ogg_int64_t pcmlength;
ogg_int64_t timelength;
char *bigassbuffer;
int dummy;
#ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
_setmode( _fileno( stdin ), _O_BINARY );
#endif
/* open the file/pipe on stdin */
if(ov_open(stdin, &ov, NULL, 0) < 0) {
fprintf(stderr,"Could not open input as an OggVorbis file.\n\n");
exit(1);
}
if(ov_seekable(&ov)){
/* to simplify our own lives, we want to assume the whole file is
stereo. Verify this to avoid potentially mystifying users
(pissing them off is OK, just don't confuse them) */
for(i=0;i<ov.links;i++){
vorbis_info *vi=ov_info(&ov,i);
if(vi->channels!=2){
fprintf(stderr,"Sorry; right now seeking_test can only use Vorbis files\n"
"that are entirely stereo.\n\n");
exit(1);
}
}
/* because we want to do sample-level verification that the seek
does what it claimed, decode the entire file into memory */
pcmlength=ov_pcm_total(&ov,-1);
timelength=ov_time_total(&ov,-1);
bigassbuffer=malloc(pcmlength*4); /* w00t */
if(bigassbuffer){
i=0;
while(i<pcmlength*4){
int ret=ov_read(&ov,bigassbuffer+i,pcmlength*4-i,&dummy);
if(ret<0)continue;
if(ret){
i+=ret;
}else{
pcmlength=i/4;
}
fprintf(stderr,"\rloading.... [%ld left] ",
(long)(pcmlength*4-i));
}
}else{
fprintf(stderr,"\rfile too large to load into memory for read tests;\n\tonly verifying seek positioning...\n");
}
{
ogg_int64_t length=ov.end;
fprintf(stderr,"\rtesting raw seeking to random places in %ld bytes....\n",
(long)length);
for(i=0;i<1000;i++){
ogg_int64_t val=rand()*length/RAND_MAX;
fprintf(stderr,"\r\t%d [raw position %ld]... ",i,(long)val);
ret=ov_raw_seek(&ov,val);
if(ret<0){
fprintf(stderr,"seek failed: %d\n",ret);
exit(1);
}
_verify(&ov,val,-1,-1.,pcmlength,bigassbuffer);
}
}
fprintf(stderr,"\r");
{
fprintf(stderr,"testing pcm page seeking to random places in %ld samples....\n",
(long)pcmlength);
for(i=0;i<1000;i++){
ogg_int64_t val=(double)rand()*pcmlength/RAND_MAX;
fprintf(stderr,"\r\t%d [pcm position %ld]... ",i,(long)val);
ret=ov_pcm_seek_page(&ov,val);
if(ret<0){
fprintf(stderr,"seek failed: %d\n",ret);
exit(1);
}
_verify(&ov,-1,val,-1.,pcmlength,bigassbuffer);
}
}
fprintf(stderr,"\r");
{
fprintf(stderr,"testing pcm exact seeking to random places in %ld samples....\n",
(long)pcmlength);
for(i=0;i<1000;i++){
ogg_int64_t val=(double)rand()*pcmlength/RAND_MAX;
fprintf(stderr,"\r\t%d [pcm position %ld]... ",i,(long)val);
ret=ov_pcm_seek(&ov,val);
if(ret<0){
fprintf(stderr,"seek failed: %d\n",ret);
exit(1);
}
if(ov_pcm_tell(&ov)!=val){
fprintf(stderr,"Declared position didn't perfectly match request: %ld != %ld\n",
(long)val,(long)ov_pcm_tell(&ov));
exit(1);
}
_verify(&ov,-1,val,-1.,pcmlength,bigassbuffer);
}
}
fprintf(stderr,"\r");
{
fprintf(stderr,"testing time page seeking to random places in %ld milliseconds....\n",
(long)timelength);
for(i=0;i<1000;i++){
ogg_int64_t val=(double)rand()*timelength/RAND_MAX;
fprintf(stderr,"\r\t%d [time position %ld]... ",i,(long)val);
ret=ov_time_seek_page(&ov,val);
if(ret<0){
fprintf(stderr,"seek failed: %d\n",ret);
exit(1);
}
_verify(&ov,-1,-1,val,pcmlength,bigassbuffer);
}
}
fprintf(stderr,"\r");
{
fprintf(stderr,"testing time exact seeking to random places in %ld milliseconds....\n",
(long)timelength);
for(i=0;i<1000;i++){
ogg_int64_t val=(double)rand()*timelength/RAND_MAX;
fprintf(stderr,"\r\t%d [time position %ld]... ",i,(long)val);
ret=ov_time_seek(&ov,val);
if(ret<0){
fprintf(stderr,"seek failed: %d\n",ret);
exit(1);
}
if(ov_time_tell(&ov)<val-1 || ov_time_tell(&ov)>val+1){
fprintf(stderr,"Declared position didn't perfectly match request: %ld != %ld\n",
(long)val,(long)ov_time_tell(&ov));
exit(1);
}
_verify(&ov,-1,-1,val,pcmlength,bigassbuffer);
}
}
fprintf(stderr,"\r \nOK.\n\n");
}else{
fprintf(stderr,"Standard input was not seekable.\n");
}
ov_clear(&ov);
return 0;
}

View File

@ -0,0 +1,91 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: simple example decoder using vorbisidec
********************************************************************/
/* Takes a vorbis bitstream from stdin and writes raw stereo PCM to
stdout using vorbisfile. Using vorbisfile is much simpler than
dealing with libvorbis. */
#include <stdio.h>
#include <stdlib.h>
#include "ivorbiscodec.h"
#include "ivorbisfile.h"
#ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */
#include <io.h>
#include <fcntl.h>
#endif
char pcmout[4096]; /* take 4k out of the data segment, not the stack */
int main(){
OggVorbis_File vf;
int eof=0;
int current_section;
#ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
/* Beware the evil ifdef. We avoid these where we can, but this one we
cannot. Don't add any more, you'll probably go to hell if you do. */
_setmode( _fileno( stdin ), _O_BINARY );
_setmode( _fileno( stdout ), _O_BINARY );
#endif
if(ov_open(stdin, &vf, NULL, 0) < 0) {
fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n");
exit(1);
}
/* Throw the comments plus a few lines about the bitstream we're
decoding */
{
char **ptr=ov_comment(&vf,-1)->user_comments;
vorbis_info *vi=ov_info(&vf,-1);
while(*ptr){
fprintf(stderr,"%s\n",*ptr);
++ptr;
}
fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi->channels,vi->rate);
fprintf(stderr,"\nDecoded length: %ld samples\n",
(long)ov_pcm_total(&vf,-1));
fprintf(stderr,"Encoded by: %s\n\n",ov_comment(&vf,-1)->vendor);
}
while(!eof){
long ret=ov_read(&vf,pcmout,sizeof(pcmout),&current_section);
if (ret == 0) {
/* EOF */
eof=1;
} else if (ret < 0) {
if(ret==OV_EBADLINK){
fprintf(stderr,"Corrupt bitstream section! Exiting.\n");
exit(1);
}
/* some other error in the stream. Not a problem, just reporting it in
case we (the app) cares. In this case, we don't. */
} else {
/* we don't bother dealing with sample rate changes, etc, but
you'll have to*/
fwrite(pcmout,1,ret,stdout);
}
}
/* cleanup */
ov_clear(&vf);
fprintf(stderr,"Done.\n");
return(0);
}

View File

@ -112,6 +112,8 @@ ALLOCA = @ALLOCA@
ALSA_CFLAGS = @ALSA_CFLAGS@
ALSA_LIBS = @ALSA_LIBS@
AMTAR = @AMTAR@
AM_CFLAGS = @AM_CFLAGS@
AM_CXXFLAGS = @AM_CXXFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
@ -230,6 +232,8 @@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
SNDFILE_LIBS = @SNDFILE_LIBS@
SNES_EXTRA_CXXFLAGS = @SNES_EXTRA_CXXFLAGS@
SNES_EXTRA_FLAGS = @SNES_EXTRA_FLAGS@
SSE2_CFLAGS = @SSE2_CFLAGS@
SSE3_CFLAGS = @SSE3_CFLAGS@
SSE_CFLAGS = @SSE_CFLAGS@
@ -238,6 +242,7 @@ TRIO_CFLAGS = @TRIO_CFLAGS@
USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
WARNING_FLAGS = @WARNING_FLAGS@
WINDRES = @WINDRES@
WOE32 = @WOE32@
WOE32DLL = @WOE32DLL@

View File

@ -1,3 +1,5 @@
// Note: The size of each these structs shouldn't exceed 256 bytes(current worst-case is about 56 bytes with the 18x18 font).
typedef struct
{
uint16 glyph_num;

View File

@ -0,0 +1,79 @@
#include "video-common.h"
void MDFN_DrawRectangle(uint32 *XBuf, int pitch, int xpos, int ypos, uint32 color, uint32 width, uint32 height)
{
uint32 x;
uint32 y;
XBuf += pitch * ypos + xpos;
/* Draw top and bottom horiz */
for(x=0;x<width;x++)
{
XBuf[x] = color;
XBuf[x + (height-1) * pitch] = color;
}
for(y=0;y<height;y++)
{
XBuf[y * pitch] = color;
XBuf[y * pitch + width-1] = color;
}
}
void MDFN_DrawRectangleAlpha(uint32 *XBuf, int pitch, int xpos, int ypos, uint32 color, uint32 alpha_color, uint32 width, uint32 height)
{
uint32 x;
uint32 y;
XBuf += pitch * ypos + xpos;
/* Draw top and bottom horiz */
for(x=0;x<width;x++)
{
XBuf[x] = color;
XBuf[x + (height-1) * pitch] = color;
}
for(y=0;y<height;y++)
{
XBuf[y * pitch] = color;
XBuf[y * pitch + width-1] = color;
}
/* Now draw inner transparency area. */
XBuf += 1 + 1 * pitch;
for(y=0;y<height-2;y++)
for(x=0;x<width-2;x++)
{
XBuf[y*pitch+x] = alpha_color; //MK_COLORA(0x00, 0x00, 0x00, 0x80);
}
}
void MDFN_DrawRectangleFill(uint32 *XBuf, int pitch, int xpos, int ypos, uint32 color, uint32 fillcolor, uint8 width, uint8 height)
{
int x;
int y;
XBuf += pitch * ypos + xpos;
/* Draw top and bottom horiz */
for(x=0;x<width;x++)
{
XBuf[x] = color;
XBuf[x + (height-1) * pitch] = color;
}
for(y=0;y<height;y++)
{
XBuf[y * pitch] = color;
XBuf[y * pitch + width-1] = color;
}
/* Now draw innerarea. */
XBuf += 1 + 1 * pitch;
for(y=0;y<height-2;y++)
for(x=0;x<width-2;x++)
{
XBuf[y*pitch+x] = fillcolor;
}
}

121
mednafen/video/selblur.cpp Normal file
View File

@ -0,0 +1,121 @@
/* Mednafen - Multi-system Emulator
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../mednafen.h"
#include "selblur.h"
#include <math.h>
#if 0
static INLINE void GetSourcePixel(const SelBlurImage *spec, int32 x, int32 y, unsigned int &r, unsigned int &g, unsigned int &b)
{
uint32 pixel = spec->source[x + y * spec->source_pitch32];
r = (pixel >> spec->red_shift) & 0xFF;
g = (pixel >> spec->green_shift) & 0xFF;
b = (pixel >> spec->blue_shift) & 0xFF;
}
static INLINE void SetDestPixel(const SelBlurImage *spec, int32 x, int32 y, const unsigned int r, const unsigned int g, const unsigned int b)
{
spec->dest[x + y * spec->dest_pitch32] = (r << spec->red_shift) | (g << spec->green_shift) | (b << spec->blue_shift);
}
#endif
#define GetSourcePixel(_x, _y, _r, _g, _b) { uint32 mypixel = source[_x + _y * source_pitch32]; _r = (mypixel >> red_shift) & 0xFF; \
_g = (mypixel >> green_shift) & 0xFF; _b = (mypixel >> blue_shift) & 0xFF; }
#define SetDestPixel(_x, _y, _r, _g, _b) dest[_x + _y * dest_pitch32] = (_r << red_shift) | (_g << green_shift) | (_b << blue_shift);
void MDFN_SelBlur(SelBlurImage *spec)
{
unsigned int red_shift = spec->red_shift;
unsigned int green_shift = spec->green_shift;
unsigned int blue_shift = spec->blue_shift;
uint32 *dest = spec->dest;
uint32 *source = spec->source;
uint32 source_pitch32 = spec->source_pitch32;
uint32 dest_pitch32 = spec->dest_pitch32;
uint8 r_thresh[512];
uint8 g_thresh[512];
uint8 b_thresh[512];
for(int i = 0; i < 512; i++)
{
if((unsigned int)abs(i - 256) <= spec->red_threshold)
r_thresh[i] = 0;
else r_thresh[i] = 8;
if((unsigned int)abs(i - 256) <= spec->green_threshold)
g_thresh[i] = 0;
else g_thresh[i] = 8;
if((unsigned int)abs(i - 256) <= spec->blue_threshold)
b_thresh[i] = 0;
else b_thresh[i] = 8;
}
for(int32 y = 0; y < spec->height; y++)
{
int32 y_min, y_max;
y_min = y - spec->radius;
if(y_min < 0) y_min = 0;
y_max = y + spec->radius;
if(y_max >= spec->height) y_max = spec->height - 1;
for(int32 x = 0; x < spec->width; x++)
{
unsigned int red, green, blue;
unsigned int red_blur, green_blur, blue_blur;
unsigned int blurdiv = 0;
GetSourcePixel(x, y, red, green, blue);
red_blur = green_blur = blue_blur = 0;
for(int32 y_sub = y_min; y_sub <= y_max; y_sub++)
{
int32 x_magic, x_min, x_max;
x_magic = spec->radius - abs(y - y_sub);
x_min = x - x_magic;
x_max = x + x_magic;
if(x_max >= spec->width) x_max = spec->width - 1;
if(x_min < 0) x_min = 0;
for(int32 x_sub = x_min; x_sub <= x_max; x_sub++)
{
unsigned int red_other, green_other, blue_other;
unsigned int smashing;
GetSourcePixel(x_sub, y_sub, red_other, green_other, blue_other);
smashing = r_thresh[256 + red_other - red] | g_thresh[256 + green_other - green] | b_thresh[256 + blue_other - blue];
red_blur += red_other >> smashing;
green_blur += green_other >> smashing;
blue_blur += blue_other >> smashing;
blurdiv += 1 >> smashing;
}
}
SetDestPixel(x, y, red_blur / blurdiv , green_blur / blurdiv, blue_blur / blurdiv);
}
}
}

View File

@ -50,6 +50,18 @@ MDFN_PixelFormat::MDFN_PixelFormat(const unsigned int p_colorspace, const uint8
Aprec = 8;
}
MDFN_Surface::MDFN_Surface()
{
memset(&format, 0, sizeof(format));
pixels = NULL;
pixels16 = NULL;
pixels_is_external = false;
pitchinpix = 0;
w = 0;
h = 0;
}
MDFN_Surface::MDFN_Surface(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf)
{
Init(p_pixels, p_width, p_height, p_pitchinpix, nf);

View File

@ -157,6 +157,7 @@ class MDFN_Surface //typedef struct
{
public:
MDFN_Surface();
MDFN_Surface(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf);
~MDFN_Surface();

View File

@ -21,42 +21,44 @@
typedef struct
{
uint32 glyph_width;
uint32 glyph_height;
int extension;
uint8 glyph_width;
uint8 glyph_height;
int8 extension;
uint8 entry_bsize;
const uint8 *base_ptr;
} FontDescriptor_t;
static FontDescriptor_t FontDescriptors[_MDFN_FONT_COUNT] =
{
#ifdef WANT_INTERNAL_CJK
{ 9, 18, MDFN_FONT_18x18 },
{ 5, 7, -1 },
{ 4, 5, -1 },
{ 6, 13, MDFN_FONT_12x13 },
{ 12, 13, -1 },
{ 18, 18, -1 },
{ 9, 18, MDFN_FONT_18x18, sizeof(FontData9x18[0]), &FontData9x18[0].data[0] },
{ 5, 7, -1, sizeof(FontData5x7[0]), &FontData5x7[0].data[0] },
{ 4, 5, -1, sizeof(FontData4x5[0]), &FontData4x5[0].data[0] },
{ 6, 13, MDFN_FONT_12x13, sizeof(FontData6x13[0]), &FontData6x13[0].data[0] },
{ 12, 13, -1, sizeof(FontData12x13[0]), &FontData12x13[0].data[0] },
{ 18, 18, -1, sizeof(FontData18x18[0]), &FontData18x18[0].data[0] },
#else
{ 9, 18, -1 },
{ 5, 7, -1 },
{ 4, 5, -1 },
{ 6, 13, -1 },
{ 9, 18, -1, sizeof(FontData9x18[0]), &FontData9x18[0].data[0] },
{ 5, 7, -1, sizeof(FontData5x7[0]), &FontData5x7[0].data[0] },
{ 4, 5, -1, sizeof(FontData4x5[0]), &FontData4x5[0].data[0] },
{ 6, 13, -1, sizeof(FontData6x13[0]), &FontData6x13[0].data[0] },
#endif
};
static const uint8 *FontDataCache[_MDFN_FONT_COUNT][65536];
static uint16 FontDataIndexCache[_MDFN_FONT_COUNT][65536];
void MDFN_InitFontData(void)
{
unsigned int x;
unsigned int inx;
memset(FontDataCache, 0, sizeof(FontDataCache));
memset(FontDataIndexCache, 0xFF, sizeof(FontDataIndexCache));
for(inx=x=0;x<65536;x++)
{
if(inx < (FontData4x5_Size / sizeof(font4x5)) && FontData4x5[inx].glyph_num == x)
{
FontDataCache[MDFN_FONT_4x5][x] = FontData4x5[inx].data;
FontDataIndexCache[MDFN_FONT_4x5][x] = inx;
inx++;
}
}
@ -65,7 +67,7 @@ void MDFN_InitFontData(void)
{
if(inx < (FontData5x7_Size / sizeof(font5x7)) && FontData5x7[inx].glyph_num == x)
{
FontDataCache[MDFN_FONT_5x7][x] = FontData5x7[inx].data;
FontDataIndexCache[MDFN_FONT_5x7][x] = inx;
inx++;
}
}
@ -74,7 +76,7 @@ void MDFN_InitFontData(void)
{
if(inx < (FontData6x13_Size / sizeof(font6x13)) && FontData6x13[inx].glyph_num == x)
{
FontDataCache[MDFN_FONT_6x13_12x13][x] = FontData6x13[inx].data;
FontDataIndexCache[MDFN_FONT_6x13_12x13][x] = inx;
inx++;
}
}
@ -83,7 +85,7 @@ void MDFN_InitFontData(void)
{
if(inx < (FontData9x18_Size / sizeof(font9x18)) && FontData9x18[inx].glyph_num == x)
{
FontDataCache[MDFN_FONT_9x18_18x18][x] = FontData9x18[inx].data;
FontDataIndexCache[MDFN_FONT_9x18_18x18][x] = inx;
inx++;
}
}
@ -93,7 +95,7 @@ void MDFN_InitFontData(void)
{
if(inx < (FontData12x13_Size / sizeof(font12x13)) && FontData12x13[inx].glyph_num == x)
{
FontDataCache[MDFN_FONT_12x13][x] = FontData12x13[inx].data;
FontDataIndexCache[MDFN_FONT_12x13][x] = inx;
inx++;
}
}
@ -102,7 +104,7 @@ void MDFN_InitFontData(void)
{
if(inx < (FontData18x18_Size / sizeof(font18x18)) && FontData18x18[inx].glyph_num == x)
{
FontDataCache[MDFN_FONT_18x18][x] = FontData18x18[inx].data;
FontDataIndexCache[MDFN_FONT_18x18][x] = inx;
inx++;
}
}
@ -130,9 +132,9 @@ static void DrawTextSub(const UTF32 *utf32_buf, uint32 &slen, const uint8 **glyp
while(!GlyphFound)
{
if(FontDataCache[recurse_which_font][thisglyph])
if(FontDataIndexCache[recurse_which_font][thisglyph] != 0xFFFF)
{
glyph_ptrs[x] = FontDataCache[recurse_which_font][thisglyph];
glyph_ptrs[x] = FontDescriptors[recurse_which_font].base_ptr + (FontDescriptors[recurse_which_font].entry_bsize * FontDataIndexCache[recurse_which_font][thisglyph]);
glyph_width[x] = FontDescriptors[recurse_which_font].glyph_width;
GlyphFound = TRUE;
}
@ -144,7 +146,7 @@ static void DrawTextSub(const UTF32 *utf32_buf, uint32 &slen, const uint8 **glyp
if(!GlyphFound)
{
glyph_ptrs[x] = FontDataCache[which_font][(unsigned char)'?'];
glyph_ptrs[x] = FontDescriptors[which_font].base_ptr + (FontDescriptors[which_font].entry_bsize * FontDataIndexCache[which_font][(unsigned char)'?']);
glyph_width[x] = FontDescriptors[which_font].glyph_width;
}
@ -307,11 +309,14 @@ uint32 DrawTextTransShadow(uint32 *dest, int pitch, uint32 width, const std::str
}
#if 0
uint32 DrawText(MDFN_Surface *surface, const MDFN_Rect &rect, const std::string &textmsg, uint32 color,
uint32 DrawText(MDFN_Surface *surface, const MDFN_Rect &rect, const char *textmsg, uint32 color,
bool centered, uint32 which_font)
{
MDFN_Rect tr = rect;
if(tr.w < 0 || tr.h < 0)
return;
if((tr.x + tr.w) > surface->w)
tr.w = surface->w - tr.x;

View File

@ -27,10 +27,6 @@
#include "png.h"
void MDFNI_SaveSnapshot(const MDFN_Surface *src, const MDFN_Rect *rect, const MDFN_Rect *LineWidths)
{
}
void MDFN_DispMessage(const char *format, ...) throw()
{
va_list ap;

View File

@ -1,5 +1,6 @@
#include "mednafen/mednafen-types.h"
#include "mednafen/mednafen.h"
#include "mednafen/md5.h"
#include "mednafen/git.h"
#include "mednafen/general.h"
#include "mednafen/mednafen-driver.h"
@ -25,6 +26,35 @@ void MDFND_Sleep(unsigned int time)
#endif
}
extern std::string retro_base_directory;
extern std::string retro_base_name;
// Use a simpler approach to make sure that things go right for libretro.
std::string MDFN_MakeFName(MakeFName_Type type, int id1, const char *cd1)
{
std::string ret;
switch (type)
{
case MDFNMKF_SAV:
ret = retro_base_directory +
std::string(PSS) +
retro_base_name +
std::string(".") +
md5_context::asciistr(MDFNGameInfo->MD5, 0) +
std::string(".") +
std::string(cd1);
break;
case MDFNMKF_FIRMWARE:
ret = std::string(cd1);
break;
default:
break;
}
//fprintf(stderr, "[Mednafen]: Path request: %s\n", ret.c_str());
return ret;
}
void MDFND_DispMessage(unsigned char *str)
{
std::cerr << str;