diff --git a/psx/octoshock/psx/psx.cpp b/psx/octoshock/psx/psx.cpp index 1fb79e8f64..6f69a18b83 100644 --- a/psx/octoshock/psx/psx.cpp +++ b/psx/octoshock/psx/psx.cpp @@ -1,22 +1,22 @@ -/******************************************************************************/ -/* Mednafen Sony PS1 Emulation Module */ -/******************************************************************************/ -/* psx.cpp: -** Copyright (C) 2011-2017 Mednafen Team -** -** This program is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License -** as published by the Free Software Foundation; either version 2 -** of the License, or (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software Foundation, Inc., -** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +/******************************************************************************/ +/* Mednafen Sony PS1 Emulation Module */ +/******************************************************************************/ +/* psx.cpp: +** Copyright (C) 2011-2017 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "octoshock.h" @@ -55,66 +55,67 @@ //extern MDFNGI EmulatedPSX; -int16 soundbuf[1024 * 1024]; //how big? big enough. -int VTBackBuffer = 0; +int16 soundbuf[1024 * 1024]; //how big? big enough. +int VTBackBuffer = 0; bool GpuFrameForLag = false; static MDFN_Rect VTDisplayRects[2]; -#include "video/Deinterlacer.h" -static bool PrevInterlaced; +#include "video/Deinterlacer.h" +static bool PrevInterlaced; static Deinterlacer deint; static EmulateSpecStruct espec; -template inline void reconstruct(T* t) { - t->~T(); - new(t) T(); -} -template inline void reconstruct(T* t, A a) { - t->~T(); - new(t) T(a); -} +template inline void reconstruct(T* t) { + t->~T(); + new(t) T(); +} +template inline void reconstruct(T* t, A a) { + t->~T(); + new(t) T(a); +} namespace MDFN_IEN_PSX { - -#if PSX_DBGPRINT_ENABLE -static unsigned psx_dbg_level = 0; - -void PSX_DBG_BIOS_PUTC(uint8 c) noexcept -{ - if(psx_dbg_level >= PSX_DBG_BIOS_PRINT) - { - if(c == 0x1B) - return; - - fputc(c, stdout); - - //if(c == '\n') - //{ - // fputc('%', stdout); - // fputc(' ', stdout); - //} - fflush(stdout); - } -} - -void PSX_DBG(unsigned level, const char *format, ...) noexcept -{ - if(psx_dbg_level >= level) - { - va_list ap; - - va_start(ap, format); - - trio_vprintf(format, ap); - - va_end(ap); - } -} -#else -static unsigned const psx_dbg_level = 0; + +#if PSX_DBGPRINT_ENABLE +static unsigned psx_dbg_level = 0; + +void PSX_DBG_BIOS_PUTC(uint8 c) noexcept +{ + if(psx_dbg_level >= PSX_DBG_BIOS_PRINT) + { + if(c == 0x1B) + return; + + fputc(c, stdout); + + //if(c == '\n') + //{ + // fputc('%', stdout); + // fputc(' ', stdout); + //} + fflush(stdout); + } +} + +void PSX_DBG(unsigned level, const char *format, ...) noexcept +{ + if(psx_dbg_level >= level) + { + va_list ap; + + va_start(ap, format); + + trio_vprintf(format, ap); + + va_end(ap); + } +} +#else +static unsigned const psx_dbg_level = 0; #endif + struct MDFN_PseudoRNG // Based off(but not the same as) public-domain "JKISS" PRNG. { MDFN_COLD MDFN_PseudoRNG() @@ -122,9 +123,9 @@ struct MDFN_PseudoRNG // Based off(but not the same as) public-domain "JKISS" PR ResetState(); } - u32 RandU32(void) + uint32 RandU32(void) { - u64 t; + uint64 t; x = 314527869 * x + 1234567; y ^= y << 5; y ^= y >> 7; y ^= y << 22; @@ -223,16 +224,17 @@ static struct }; } SysControl; -static unsigned DMACycleSteal = 0; // Doesn't need to be saved in save states, since it's recalculated in the ForceEventUpdates() call chain. - -void PSX_SetDMACycleSteal(unsigned stealage) -{ - if(stealage > 200) // Due to 8-bit limitations in the CPU core. - stealage = 200; - - DMACycleSteal = stealage; -} - +static unsigned DMACycleSteal = 0; // Doesn't need to be saved in save states, since it's recalculated in the ForceEventUpdates() call chain. + +void PSX_SetDMACycleSteal(unsigned stealage) +{ + if(stealage > 200) // Due to 8-bit limitations in the CPU core. + stealage = 200; + + DMACycleSteal = stealage; +} + + // // Event stuff // @@ -353,7 +355,7 @@ void ForceEventUpdates(const pscpu_timestamp_t timestamp) CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time); } -bool PSX_EventHandler(const pscpu_timestamp_t timestamp) +bool MDFN_FASTCALL PSX_EventHandler(const pscpu_timestamp_t timestamp) { event_list_entry *e = events[PSX_EVENT__SYNFIRST].next; @@ -411,7 +413,6 @@ void PSX_RequestMLExit(void) // End event stuff // - // Remember to update MemPeek<>() and MemPoke<>() when we change address decoding in MemRW() template static INLINE void MemRW(pscpu_timestamp_t ×tamp, uint32 A, uint32 &V) { @@ -422,7 +423,7 @@ template static INLINE void MemRW(pscpu printf("Read%d: %08x(orig=%08x)\n", (int)(sizeof(T) * 8), A & mask[A >> 29], A); #endif - if(!IsWrite) + if(!IsWrite) timestamp += DMACycleSteal; if(A < 0x00800000) @@ -498,8 +499,7 @@ template static INLINE void MemRW(pscpu if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time) PSX_EventHandler(timestamp); - //0.9.36.5 - clarified read order by turning into two statements - V = SPU->Read(timestamp, A); + V = SPU->Read(timestamp, A); V |= SPU->Read(timestamp, A | 2) << 16; } } @@ -549,9 +549,9 @@ template static INLINE void MemRW(pscpu if(!IsWrite) timestamp++; - if(IsWrite) - GPU_Write(timestamp, A, V); - else + if(IsWrite) + GPU_Write(timestamp, A, V); + else V = GPU_Read(timestamp, A); return; @@ -562,15 +562,8 @@ template static INLINE void MemRW(pscpu if(!IsWrite) timestamp++; - if (IsWrite) - { - if (A == 0x1F801820) - { - //per pcsx-rr: - GpuFrameForLag = true; - } - MDEC_Write(timestamp, A, V); - } + if(IsWrite) + MDEC_Write(timestamp, A, V); else V = MDEC_Read(timestamp, A); @@ -716,8 +709,8 @@ template static INLINE void MemRW(pscpu else switch(sizeof(T)) { case 1: V = TextMem[(A & 0x7FFFFF) - 65536]; break; - case 2: V = MDFN_de16lsb(&TextMem[(A & 0x7FFFFF) - 65536]); break; - case 4: V = MDFN_de32lsb(&TextMem[(A & 0x7FFFFF) - 65536]); break; + case 2: V = MDFN_de16lsb(&TextMem[(A & 0x7FFFFF) - 65536]); break; + case 4: V = MDFN_de32lsb(&TextMem[(A & 0x7FFFFF) - 65536]); break; } } } @@ -746,27 +739,27 @@ template static INLINE void MemRW(pscpu } } -void PSX_MemWrite8(pscpu_timestamp_t timestamp, uint32 A, uint32 V) +void MDFN_FASTCALL PSX_MemWrite8(pscpu_timestamp_t timestamp, uint32 A, uint32 V) { MemRW(timestamp, A, V); } -void PSX_MemWrite16(pscpu_timestamp_t timestamp, uint32 A, uint32 V) +void MDFN_FASTCALL PSX_MemWrite16(pscpu_timestamp_t timestamp, uint32 A, uint32 V) { MemRW(timestamp, A, V); } -void PSX_MemWrite24(pscpu_timestamp_t timestamp, uint32 A, uint32 V) +void MDFN_FASTCALL PSX_MemWrite24(pscpu_timestamp_t timestamp, uint32 A, uint32 V) { MemRW(timestamp, A, V); } -void PSX_MemWrite32(pscpu_timestamp_t timestamp, uint32 A, uint32 V) +void MDFN_FASTCALL PSX_MemWrite32(pscpu_timestamp_t timestamp, uint32 A, uint32 V) { MemRW(timestamp, A, V); } -uint8 PSX_MemRead8(pscpu_timestamp_t ×tamp, uint32 A) +uint8 MDFN_FASTCALL PSX_MemRead8(pscpu_timestamp_t ×tamp, uint32 A) { uint32 V; @@ -775,7 +768,7 @@ uint8 PSX_MemRead8(pscpu_timestamp_t ×tamp, uint32 A) return(V); } -uint16 PSX_MemRead16(pscpu_timestamp_t ×tamp, uint32 A) +uint16 MDFN_FASTCALL PSX_MemRead16(pscpu_timestamp_t ×tamp, uint32 A) { uint32 V; @@ -784,7 +777,7 @@ uint16 PSX_MemRead16(pscpu_timestamp_t ×tamp, uint32 A) return(V); } -uint32 PSX_MemRead24(pscpu_timestamp_t ×tamp, uint32 A) +uint32 MDFN_FASTCALL PSX_MemRead24(pscpu_timestamp_t ×tamp, uint32 A) { uint32 V; @@ -793,7 +786,7 @@ uint32 PSX_MemRead24(pscpu_timestamp_t ×tamp, uint32 A) return(V); } -uint32 PSX_MemRead32(pscpu_timestamp_t ×tamp, uint32 A) +uint32 MDFN_FASTCALL PSX_MemRead32(pscpu_timestamp_t ×tamp, uint32 A) { uint32 V; @@ -905,8 +898,8 @@ template static INLINE uint32 MemPeek(pscpu_timestamp else switch(sizeof(T)) { case 1: return(TextMem[(A & 0x7FFFFF) - 65536]); break; - case 2: return(MDFN_de16lsb(&TextMem[(A & 0x7FFFFF) - 65536])); break; - case 4: return(MDFN_de32lsb(&TextMem[(A & 0x7FFFFF) - 65536])); break; + case 2: return(MDFN_de16lsb(&TextMem[(A & 0x7FFFFF) - 65536])); break; + case 4: return(MDFN_de32lsb(&TextMem[(A & 0x7FFFFF) - 65536])); break; } } } @@ -934,58 +927,58 @@ uint32 PSX_MemPeek32(uint32 A) return MemPeek(0, A); } -template static INLINE void MemPoke(pscpu_timestamp_t timestamp, uint32 A, T V) -{ - if(A < 0x00800000) - { - if(Access24) - MainRAM.WriteU24(A & 0x1FFFFF, V); - else - MainRAM.Write(A & 0x1FFFFF, V); - - return; - } - - if(A >= 0x1FC00000 && A <= 0x1FC7FFFF) - { - if(Access24) - BIOSROM->WriteU24(A & 0x7FFFF, V); - else - BIOSROM->Write(A & 0x7FFFF, V); - - return; - } - - if(A >= 0x1F801000 && A <= 0x1F802FFF) - { - if(A >= 0x1F801000 && A <= 0x1F801023) - { - unsigned index = (A & 0x1F) >> 2; - SysControl.Regs[index] = (V << ((A & 3) * 8)) & SysControl_Mask[index]; - return; - } - } - - if(A == 0xFFFE0130) - { - CPU->SetBIU(V); - return; - } -} - -void PSX_MemPoke8(uint32 A, uint8 V) -{ - MemPoke(0, A, V); -} - -void PSX_MemPoke16(uint32 A, uint16 V) -{ - MemPoke(0, A, V); -} - -void PSX_MemPoke32(uint32 A, uint32 V) -{ - MemPoke(0, A, V); +template static INLINE void MemPoke(pscpu_timestamp_t timestamp, uint32 A, T V) +{ + if(A < 0x00800000) + { + if(Access24) + MainRAM.WriteU24(A & 0x1FFFFF, V); + else + MainRAM.Write(A & 0x1FFFFF, V); + + return; + } + + if(A >= 0x1FC00000 && A <= 0x1FC7FFFF) + { + if(Access24) + BIOSROM->WriteU24(A & 0x7FFFF, V); + else + BIOSROM->Write(A & 0x7FFFF, V); + + return; + } + + if(A >= 0x1F801000 && A <= 0x1F802FFF) + { + if(A >= 0x1F801000 && A <= 0x1F801023) + { + unsigned index = (A & 0x1F) >> 2; + SysControl.Regs[index] = (V << ((A & 3) * 8)) & SysControl_Mask[index]; + return; + } + } + + if(A == 0xFFFE0130) + { + CPU->SetBIU(V); + return; + } +} + +void PSX_MemPoke8(uint32 A, uint8 V) +{ + MemPoke(0, A, V); +} + +void PSX_MemPoke16(uint32 A, uint16 V) +{ + MemPoke(0, A, V); +} + +void PSX_MemPoke32(uint32 A, uint32 V) +{ + MemPoke(0, A, V); } static void PSX_Power(bool powering_up) @@ -1029,27 +1022,27 @@ void PSX_GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t using namespace MDFN_IEN_PSX; -struct ShockConfig -{ - //// multires is a hint that, if set, indicates that the system has fairly programmable video modes(particularly, the ability - //// to display multiple horizontal resolutions, such as the PCE, PC-FX, or Genesis). In practice, it will cause the driver - //// code to set the linear interpolation on by default. (TRUE for psx) - //// lcm_width and lcm_height are the least common multiples of all possible - //// resolutions in the frame buffer as specified by DisplayRect/LineWidths(Ex for PCE: widths of 256, 341.333333, 512, - //// lcm = 1024) - //// nominal_width and nominal_height specify the resolution that Mednafen should display - //// the framebuffer image in at 1x scaling, scaled from the dimensions of DisplayRect, and optionally the LineWidths array - //// passed through espec to the Emulate() function. - //int lcm_width; - //int lcm_height; - //int nominal_width; - //int nominal_height; - int fb_width; // Width of the framebuffer(not necessarily width of the image). MDFN_Surface width should be >= this. - int fb_height; // Height of the framebuffer passed to the Emulate() function(not necessarily height of the image) - - //last used render options - ShockRenderOptions opts; -} s_ShockConfig; +struct ShockConfig +{ + //// multires is a hint that, if set, indicates that the system has fairly programmable video modes(particularly, the ability + //// to display multiple horizontal resolutions, such as the PCE, PC-FX, or Genesis). In practice, it will cause the driver + //// code to set the linear interpolation on by default. (TRUE for psx) + //// lcm_width and lcm_height are the least common multiples of all possible + //// resolutions in the frame buffer as specified by DisplayRect/LineWidths(Ex for PCE: widths of 256, 341.333333, 512, + //// lcm = 1024) + //// nominal_width and nominal_height specify the resolution that Mednafen should display + //// the framebuffer image in at 1x scaling, scaled from the dimensions of DisplayRect, and optionally the LineWidths array + //// passed through espec to the Emulate() function. + //int lcm_width; + //int lcm_height; + //int nominal_width; + //int nominal_height; + int fb_width; // Width of the framebuffer(not necessarily width of the image). MDFN_Surface width should be >= this. + int fb_height; // Height of the framebuffer passed to the Emulate() function(not necessarily height of the image) + + //last used render options + ShockRenderOptions opts; +} s_ShockConfig; struct ShockState @@ -1277,29 +1270,29 @@ struct { //TODO - once we get flexible here, do some extra condition checks.. whether memcards exist, etc. much like devices. switch(transaction->transaction) { - case eShockMemcardTransaction_Connect: - //cant connect when a memcard is already connected - if(!strcmp(FIO->MCPorts[portnum]->GetName(),"InputDevice_Memcard")) - return SHOCK_NOCANDO; - delete FIO->MCPorts[portnum]; //delete dummy - FIO->MCPorts[portnum] = Device_Memcard_Create(); - - case eShockMemcardTransaction_Disconnect: - return SHOCK_ERROR; //not supported yet - - case eShockMemcardTransaction_Write: - FIO->MCPorts[portnum]->WriteNV((uint8*)transaction->buffer128k,0,128*1024); - FIO->MCPorts[portnum]->ResetNVDirtyCount(); - return SHOCK_OK; - - case eShockMemcardTransaction_Read: - { - const u8* ptr = FIO->MCPorts[portnum]->ReadNV(); - memcpy(transaction->buffer128k,ptr,128*1024); - FIO->MCPorts[portnum]->ResetNVDirtyCount(); - return SHOCK_OK; - } - + case eShockMemcardTransaction_Connect: + //cant connect when a memcard is already connected + if(!strcmp(FIO->MCPorts[portnum]->GetName(),"InputDevice_Memcard")) + return SHOCK_NOCANDO; + delete FIO->MCPorts[portnum]; //delete dummy + FIO->MCPorts[portnum] = Device_Memcard_Create(); + + case eShockMemcardTransaction_Disconnect: + return SHOCK_ERROR; //not supported yet + + case eShockMemcardTransaction_Write: + FIO->MCPorts[portnum]->WriteNV((uint8*)transaction->buffer128k,0,128*1024); + FIO->MCPorts[portnum]->ResetNVDirtyCount(); + return SHOCK_OK; + + case eShockMemcardTransaction_Read: + { + const u8* ptr = FIO->MCPorts[portnum]->ReadNV(); + memcpy(transaction->buffer128k,ptr,128*1024); + FIO->MCPorts[portnum]->ResetNVDirtyCount(); + return SHOCK_OK; + } + case eShockMemcardTransaction_CheckDirty: if(FIO->GetMemcardDirtyCount(portnum)) return SHOCK_TRUE; @@ -1362,7 +1355,7 @@ static void MountCPUAddressSpace() } } -static MDFN_Surface *VTBuffer[2] = { NULL, NULL }; +static MDFN_Surface *VTBuffer[2] = { NULL, NULL }; static int *VTLineWidths[2] = { NULL, NULL }; static bool s_FramebufferNormalized; static bool s_Created; @@ -1382,7 +1375,7 @@ EW_EXPORT s32 shock_Create(void** psx, s32 region, void* firmware512k) //TODO //psx_dbg_level = MDFN_GetSettingUI("psx.dbg_level"); - //DBG_Init(); + //DBG_Init(); //yeah, we only support a static instance. //we'll flag whether it's created though @@ -1402,25 +1395,25 @@ EW_EXPORT s32 shock_Create(void** psx, s32 region, void* firmware512k) SPU = new PS_SPU(); GPU_Init(region == REGION_EU); CDC = new PS_CDC(); - DMA_Init(); + DMA_Init(); //setup gpu output surfaces - MDFN_PixelFormat nf(MDFN_COLORSPACE_RGB, 16, 8, 0, 24); - for(int i=0;i<2;i++) - { - VTBuffer[i] = new MDFN_Surface(NULL, FB_WIDTH, FB_HEIGHT, FB_WIDTH, nf); - VTLineWidths[i] = (int *)calloc(FB_HEIGHT, sizeof(int)); - } - - for(int rc = 0; rc < 0x8000; rc++) - { - const uint8 a = rc; - const uint8 b = rc >> 8; - - (GPU.OutputLUT + 0)[a] = ((a & 0x1F) << (3 + nf.Rshift)) | ((a >> 5) << (3 + nf.Gshift)); - (GPU.OutputLUT + 256)[b] = ((b & 0x3) << (6 + nf.Gshift)) | (((b >> 2) & 0x1F) << (3 + nf.Bshift)); - } + MDFN_PixelFormat nf(MDFN_COLORSPACE_RGB, 16, 8, 0, 24); + for(int i=0;i<2;i++) + { + VTBuffer[i] = new MDFN_Surface(NULL, FB_WIDTH, FB_HEIGHT, FB_WIDTH, nf); + VTLineWidths[i] = (int *)calloc(FB_HEIGHT, sizeof(int)); + } + + for(int rc = 0; rc < 0x8000; rc++) + { + const uint8 a = rc; + const uint8 b = rc >> 8; + + (GPU.OutputLUT + 0)[a] = ((a & 0x1F) << (3 + nf.Rshift)) | ((a >> 5) << (3 + nf.Gshift)); + (GPU.OutputLUT + 256)[b] = ((b & 0x3) << (6 + nf.Gshift)) | (((b >> 2) & 0x1F) << (3 + nf.Bshift)); + } FIO = new FrontIO(); s_ShockPeripheralState.Initialize(); @@ -1442,13 +1435,13 @@ EW_EXPORT s32 shock_Destroy(void* psx) s_Created = false; - for(int i=0;i<2;i++) - { - delete VTBuffer[i]; - VTLineWidths[i] = nullptr; - - free(VTLineWidths[i]); - VTBuffer[i] = nullptr; + for(int i=0;i<2;i++) + { + delete VTBuffer[i]; + VTLineWidths[i] = nullptr; + + free(VTLineWidths[i]); + VTBuffer[i] = nullptr; } TextMem.resize(0); @@ -1498,28 +1491,28 @@ EW_EXPORT s32 shock_Destroy(void* psx) return SHOCK_OK; } -//Sets the power to ON. It is an error to turn an already-on console ON again -EW_EXPORT s32 shock_PowerOn(void* psx) -{ - if(s_ShockState.power) return SHOCK_NOCANDO; - - s_ShockState.power = true; - PSX_Power(true); - - return SHOCK_OK; -} - -//Triggers a soft reset immediately. Returns SHOCK_NOCANDO if console is powered off. -EW_EXPORT s32 shock_SoftReset(void *psx) -{ - if (!s_ShockState.power) return SHOCK_NOCANDO; - - PSX_Power(false); - - return SHOCK_OK; -} - -//Sets the power to OFF. It is an error to turn an already-off console OFF again +//Sets the power to ON. It is an error to turn an already-on console ON again +EW_EXPORT s32 shock_PowerOn(void* psx) +{ + if(s_ShockState.power) return SHOCK_NOCANDO; + + s_ShockState.power = true; + PSX_Power(true); + + return SHOCK_OK; +} + +//Triggers a soft reset immediately. Returns SHOCK_NOCANDO if console is powered off. +EW_EXPORT s32 shock_SoftReset(void *psx) +{ + if (!s_ShockState.power) return SHOCK_NOCANDO; + + PSX_Power(false); + + return SHOCK_OK; +} + +//Sets the power to OFF. It is an error to turn an already-off console OFF again EW_EXPORT s32 shock_PowerOff(void* psx) { if(!s_ShockState.power) return SHOCK_NOCANDO; @@ -1527,71 +1520,71 @@ EW_EXPORT s32 shock_PowerOff(void* psx) //not supported yet return SHOCK_ERROR; } - + EW_EXPORT s32 shock_Step(void* psx, eShockStep step) { //only eShockStep_Frame is supported pscpu_timestamp_t timestamp = 0; - memset(&espec, 0, sizeof(EmulateSpecStruct)); - - espec.VideoFormatChanged = false; - espec.surface = (MDFN_Surface *)VTBuffer[VTBackBuffer]; - espec.LineWidths = (int *)VTLineWidths[VTBackBuffer]; - espec.skip = false; - espec.soundmultiplier = 1.0; - espec.NeedRewind = false; - - espec.MasterCycles = 0; - - espec.SoundBufMaxSize = 1024*1024; - espec.SoundRate = 44100; - espec.SoundBuf = soundbuf; - espec.SoundBufSize = 0; - espec.SoundVolume = 1.0; - - //not sure about this - espec.skip = s_ShockConfig.opts.skip; - - if (s_ShockConfig.opts.deinterlaceMode == eShockDeinterlaceMode_Weave) - deint.SetType(Deinterlacer::DEINT_WEAVE); - if (s_ShockConfig.opts.deinterlaceMode == eShockDeinterlaceMode_Bob) - deint.SetType(Deinterlacer::DEINT_BOB); - if (s_ShockConfig.opts.deinterlaceMode == eShockDeinterlaceMode_BobOffset) - deint.SetType(Deinterlacer::DEINT_BOB_OFFSET); - - //------------------------- - - s_ShockPeripheralState.UpdateInput(); - - //GPU->StartFrame(psf_loader ? NULL : espec); //a reminder that when we do psf, we will be telling the gpu not to draw - GPU_StartFrame(&espec); - - //not that it matters, but we may need to control this at some point - static const int ResampleQuality = 5; + memset(&espec, 0, sizeof(EmulateSpecStruct)); + + espec.VideoFormatChanged = false; + espec.surface = (MDFN_Surface *)VTBuffer[VTBackBuffer]; + espec.LineWidths = (int *)VTLineWidths[VTBackBuffer]; + espec.skip = false; + espec.soundmultiplier = 1.0; + espec.NeedRewind = false; + + espec.MasterCycles = 0; + + espec.SoundBufMaxSize = 1024*1024; + espec.SoundRate = 44100; + espec.SoundBuf = soundbuf; + espec.SoundBufSize = 0; + espec.SoundVolume = 1.0; + + //not sure about this + espec.skip = s_ShockConfig.opts.skip; + + if (s_ShockConfig.opts.deinterlaceMode == eShockDeinterlaceMode_Weave) + deint.SetType(Deinterlacer::DEINT_WEAVE); + if (s_ShockConfig.opts.deinterlaceMode == eShockDeinterlaceMode_Bob) + deint.SetType(Deinterlacer::DEINT_BOB); + if (s_ShockConfig.opts.deinterlaceMode == eShockDeinterlaceMode_BobOffset) + deint.SetType(Deinterlacer::DEINT_BOB_OFFSET); + + //------------------------- + + s_ShockPeripheralState.UpdateInput(); + + //GPU->StartFrame(psf_loader ? NULL : espec); //a reminder that when we do psf, we will be telling the gpu not to draw + GPU_StartFrame(&espec); + + //not that it matters, but we may need to control this at some point + static const int ResampleQuality = 5; SPU->StartFrame(espec.SoundRate, ResampleQuality); GpuFrameForLag = false; - Running = -1; - timestamp = CPU->Run(timestamp, psx_dbg_level >= PSX_DBG_BIOS_PRINT, /*psf_loader != NULL*/ false); //huh? + Running = -1; + timestamp = CPU->Run(timestamp, psx_dbg_level >= PSX_DBG_BIOS_PRINT, /*psf_loader != NULL*/ false); //huh? assert(timestamp); - ForceEventUpdates(timestamp); - if(GPU_GetScanlineNum() < 100) + ForceEventUpdates(timestamp); + if(GPU_GetScanlineNum() < 100) printf("[BUUUUUUUG] Frame timing end glitch; scanline=%u, st=%u\n", GPU_GetScanlineNum(), timestamp); - espec.SoundBufSize = SPU->EndFrame(espec.SoundBuf); - - CDC->ResetTS(); - TIMER_ResetTS(); - DMA_ResetTS(); - GPU_ResetTS(); - FIO->ResetTS(); - - RebaseTS(timestamp); - + espec.SoundBufSize = SPU->EndFrame(espec.SoundBuf); + + CDC->ResetTS(); + TIMER_ResetTS(); + DMA_ResetTS(); + GPU_ResetTS(); + FIO->ResetTS(); + + RebaseTS(timestamp); + espec.MasterCycles = timestamp; //(memcard saving happened here) @@ -1601,26 +1594,26 @@ EW_EXPORT s32 shock_Step(void* psx, eShockStep step) VTDisplayRects[VTBackBuffer] = espec.DisplayRect; //if interlacing is active, do that processing now - if(espec.InterlaceOn) - { - if(!PrevInterlaced) - deint.ClearState(); - - deint.Process(espec.surface, espec.DisplayRect, espec.LineWidths, espec.InterlaceField); - - PrevInterlaced = true; - - espec.InterlaceOn = false; - espec.InterlaceField = 0; - } - - //new frame, hasnt been normalized - s_FramebufferNormalized = false; - s_FramebufferCurrent = 0; - s_FramebufferCurrentWidth = FB_WIDTH; - - //just in case we debug printed or something like that - fflush(stdout); + if(espec.InterlaceOn) + { + if(!PrevInterlaced) + deint.ClearState(); + + deint.Process(espec.surface, espec.DisplayRect, espec.LineWidths, espec.InterlaceField); + + PrevInterlaced = true; + + espec.InterlaceOn = false; + espec.InterlaceField = 0; + } + + //new frame, hasnt been normalized + s_FramebufferNormalized = false; + s_FramebufferCurrent = 0; + s_FramebufferCurrentWidth = FB_WIDTH; + + //just in case we debug printed or something like that + fflush(stdout); fflush(stderr); @@ -1682,30 +1675,30 @@ static void _shock_AnalyzeFramebufferCropInfo(int fbIndex, FramebufferCropInfo* void NormalizeFramebuffer() { //mednafen's advised solution for smooth gaming: "scale the output width to z * nominal_width, and the output height to z * nominal_height, where nominal_width and nominal_height are members of the MDFNGI struct" - //IOW, mednafen's strategy is to put everything in a 320x240 and scale it up 3x to 960x720 by default (which is adequate to contain the largest PSX framebuffer of 700x480) + //IOW, mednafen's strategy is to put everything in a 320x240 and scale it up 3x to 960x720 by default (which is adequate to contain the largest PSX framebuffer of 700x480) //psxtech says horizontal resolutions can be: 256, 320, 512, 640, 368 pixels //mednafen will turn those into 2800/{ 10, 8, 5, 4, 7 } -> 280,350,560,700,400 //additionally with the crop options we can cut it down by 160/X -> { 16, 20, 32, 40, 22 } -> { 264, 330, 528, 660, 378 } //this means our virtual area for doubling is no longer 800 but 756 - //heres my strategy: - //try to do the smart thing, try to get aspect ratio near the right value - //intended AR = 320/240 = 1.3333 - //280x240 - ok (AR 1.1666666666666666666666666666667) - //350x240 - ok (AR 1.4583333333333333333333333333333) - //400x240 - ok (AR 1.6666666666666666666666666666667) - //560x240 - scale vertically by 2 = 560x480 ~ 280x240 - //700x240 - scale vertically by 2 = 700x480 ~ 350x240 - //280x480 - scale horizontally by 2 = 560x480 ~ 280x240 - //350x480 - scale horizontally by 2 = 700x480 ~ 350x240 - //400x480 - scale horizontally by 2 = 800x480 ~ 400x240 - //560x480 - ok ~ 280x240 - //700x480 - ok ~ 350x240 - - //NOTE: this approach is very redundant with the displaymanager AR tracking stuff - //however, it will help us avoid stressing the displaymanager (for example, a 700x240 will freak it out kind of. we could send it a much more sensible 700x480) - + //heres my strategy: + //try to do the smart thing, try to get aspect ratio near the right value + //intended AR = 320/240 = 1.3333 + //280x240 - ok (AR 1.1666666666666666666666666666667) + //350x240 - ok (AR 1.4583333333333333333333333333333) + //400x240 - ok (AR 1.6666666666666666666666666666667) + //560x240 - scale vertically by 2 = 560x480 ~ 280x240 + //700x240 - scale vertically by 2 = 700x480 ~ 350x240 + //280x480 - scale horizontally by 2 = 560x480 ~ 280x240 + //350x480 - scale horizontally by 2 = 700x480 ~ 350x240 + //400x480 - scale horizontally by 2 = 800x480 ~ 400x240 + //560x480 - ok ~ 280x240 + //700x480 - ok ~ 350x240 + + //NOTE: this approach is very redundant with the displaymanager AR tracking stuff + //however, it will help us avoid stressing the displaymanager (for example, a 700x240 will freak it out kind of. we could send it a much more sensible 700x480) + //always fetch description FramebufferCropInfo cropInfo; _shock_AnalyzeFramebufferCropInfo(0, &cropInfo); @@ -1726,9 +1719,9 @@ void NormalizeFramebuffer() virtual_width = 736; } - int xs=1,ys=1; - - //I. as described above + int xs=1,ys=1; + + //I. as described above //if(width == 280 && height == 240) {} //if(width == 350 && height == 240) {} //if(width == 400 && height == 240) {} @@ -1740,10 +1733,10 @@ void NormalizeFramebuffer() //if(width == 560 && height == 480) {} //if(width == 700 && height == 480) {} - //II. as the snes 'always double size framebuffer'. I think thats a better idea, and we already have the concept - //ORIGINALLY (as of r8528 when PAL support was added) a threshold of 276 was used. I'm not sure where that came from. - //288 seems to be a more correct value? (it's the typical PAL half resolution, corresponding to 240 for NTSC) - //maybe I meant to type 576, but that doesnt make sense--the height can't exceed that. + //II. as the snes 'always double size framebuffer'. I think thats a better idea, and we already have the concept + //ORIGINALLY (as of r8528 when PAL support was added) a threshold of 276 was used. I'm not sure where that came from. + //288 seems to be a more correct value? (it's the typical PAL half resolution, corresponding to 240 for NTSC) + //maybe I meant to type 576, but that doesnt make sense--the height can't exceed that. if(width <= 400 && height <= 288) xs=ys=2; if(width > 400 && height <= 288) ys=2; if(width <= 400 && height > 288) xs=2; @@ -1799,17 +1792,17 @@ void NormalizeFramebuffer() espec.DisplayRect.y = 0; espec.DisplayRect.h = height; s_FramebufferCurrentWidth = width; - VTLineWidths[curr^1][0] = VTLineWidths[curr][0]; - VTLineWidths[curr^1][kScanlineWidthHeuristicIndex] = VTLineWidths[curr][kScanlineWidthHeuristicIndex]; - - curr ^= 1; + VTLineWidths[curr^1][0] = VTLineWidths[curr][0]; + VTLineWidths[curr^1][kScanlineWidthHeuristicIndex] = VTLineWidths[curr][kScanlineWidthHeuristicIndex]; + + curr ^= 1; } //2. double the width as needed. but always float it. //note, theres nothing to be done here if the framebuffer is already wide enough if(width != virtual_width) { - uint32* src = VTBuffer[curr]->pixels + (s_ShockConfig.fb_width*espec.DisplayRect.y) + espec.DisplayRect.x; + uint32* src = VTBuffer[curr]->pixels + (s_ShockConfig.fb_width*espec.DisplayRect.y) + espec.DisplayRect.x; uint32* dst = VTBuffer[curr^1]->pixels; for(int y=0;ypixels + (s_FramebufferCurrentWidth*yo) + espec.DisplayRect.x; - uint32* dst = (u32*)fb->ptr; - int tocopy = width*4; - for(int y=0;ypixels + (s_FramebufferCurrentWidth*yo) + espec.DisplayRect.x; + uint32* dst = (u32*)fb->ptr; + int tocopy = width*4; + for(int y=0;ydata8[0x0800]; - MDFN_en32lsb(po, (0x0 << 26) | (31 << 21) | (0x8 << 0)); // JR + MDFN_en32lsb(po, (0x0 << 26) | (31 << 21) | (0x8 << 0)); // JR po += 4; - MDFN_en32lsb(po, 0); // NOP(kinda) + MDFN_en32lsb(po, 0); // NOP(kinda) po += 4; po = &PIOMem->data8[0x1000]; // Load cacheable-region target PC into r2 - MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (0x9F001010 >> 16)); // LUI + MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (0x9F001010 >> 16)); // LUI po += 4; - MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (2 << 16) | (0x9F001010 & 0xFFFF)); // ORI + MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (2 << 16) | (0x9F001010 & 0xFFFF)); // ORI po += 4; // Jump to r2 - MDFN_en32lsb(po, (0x0 << 26) | (2 << 21) | (0x8 << 0)); // JR + MDFN_en32lsb(po, (0x0 << 26) | (2 << 21) | (0x8 << 0)); // JR po += 4; - MDFN_en32lsb(po, 0); // NOP(kinda) + MDFN_en32lsb(po, 0); // NOP(kinda) po += 4; // @@ -2018,42 +2011,42 @@ static MDFN_COLD void LoadEXE(const uint8 *data, const uint32 size, bool ignore_ // Load source address into r8 uint32 sa = 0x9F000000 + 65536; - MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (sa >> 16)); // LUI + MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (sa >> 16)); // LUI po += 4; - MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (8 << 16) | (sa & 0xFFFF)); // ORI + MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (8 << 16) | (sa & 0xFFFF)); // ORI po += 4; // Load dest address into r9 - MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (TextMem_Start >> 16)); // LUI + MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (TextMem_Start >> 16)); // LUI po += 4; - MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (9 << 16) | (TextMem_Start & 0xFFFF)); // ORI + MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (9 << 16) | (TextMem_Start & 0xFFFF)); // ORI po += 4; // Load size into r10 - MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (TextMem.size() >> 16)); // LUI + MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (TextMem.size() >> 16)); // LUI po += 4; - MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (10 << 16) | (TextMem.size() & 0xFFFF)); // ORI + MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (10 << 16) | (TextMem.size() & 0xFFFF)); // ORI po += 4; // // Loop begin // - MDFN_en32lsb(po, (0x24 << 26) | (8 << 21) | (1 << 16)); // LBU to r1 + MDFN_en32lsb(po, (0x24 << 26) | (8 << 21) | (1 << 16)); // LBU to r1 po += 4; - MDFN_en32lsb(po, (0x08 << 26) | (10 << 21) | (10 << 16) | 0xFFFF); // Decrement size + MDFN_en32lsb(po, (0x08 << 26) | (10 << 21) | (10 << 16) | 0xFFFF); // Decrement size po += 4; - MDFN_en32lsb(po, (0x28 << 26) | (9 << 21) | (1 << 16)); // SB from r1 + MDFN_en32lsb(po, (0x28 << 26) | (9 << 21) | (1 << 16)); // SB from r1 po += 4; - MDFN_en32lsb(po, (0x08 << 26) | (8 << 21) | (8 << 16) | 0x0001); // Increment source addr + MDFN_en32lsb(po, (0x08 << 26) | (8 << 21) | (8 << 16) | 0x0001); // Increment source addr po += 4; - MDFN_en32lsb(po, (0x05 << 26) | (0 << 21) | (10 << 16) | (-5 & 0xFFFF)); + MDFN_en32lsb(po, (0x05 << 26) | (0 << 21) | (10 << 16) | (-5 & 0xFFFF)); po += 4; - MDFN_en32lsb(po, (0x08 << 26) | (9 << 21) | (9 << 16) | 0x0001); // Increment dest addr + MDFN_en32lsb(po, (0x08 << 26) | (9 << 21) | (9 << 16) | 0x0001); // Increment dest addr po += 4; // @@ -2067,31 +2060,31 @@ static MDFN_COLD void LoadEXE(const uint8 *data, const uint32 size, bool ignore_ } else { - MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (SP >> 16)); // LUI + MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (SP >> 16)); // LUI po += 4; - MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (29 << 16) | (SP & 0xFFFF)); // ORI + MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (29 << 16) | (SP & 0xFFFF)); // ORI po += 4; // Load PC into r2 - MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | ((PC >> 16) | 0x8000)); // LUI + MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | ((PC >> 16) | 0x8000)); // LUI po += 4; - MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (2 << 16) | (PC & 0xFFFF)); // ORI + MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (2 << 16) | (PC & 0xFFFF)); // ORI po += 4; } // Half-assed instruction cache flush. ;) for(unsigned i = 0; i < 1024; i++) { - MDFN_en32lsb(po, 0); + MDFN_en32lsb(po, 0); po += 4; } // Jump to r2 - MDFN_en32lsb(po, (0x0 << 26) | (2 << 21) | (0x8 << 0)); // JR + MDFN_en32lsb(po, (0x0 << 26) | (2 << 21) | (0x8 << 0)); // JR po += 4; - MDFN_en32lsb(po, 0); // NOP(kinda) + MDFN_en32lsb(po, 0); // NOP(kinda) po += 4; } @@ -2101,49 +2094,49 @@ EW_EXPORT s32 shock_MountEXE(void* psx, void* exebuf, s32 size, s32 ignore_pcsp) return SHOCK_OK; } -EW_EXPORT s32 shock_CreateDisc(ShockDiscRef** outDisc, void *Opaque, s32 lbaCount, ShockDisc_ReadTOC ReadTOC, ShockDisc_ReadLBA ReadLBA2448, bool suppliesDeinterleavedSubcode) -{ - *outDisc = new ShockDiscRef(Opaque, lbaCount, ReadTOC, ReadLBA2448, suppliesDeinterleavedSubcode); - return SHOCK_OK; -} - -ShockDiscRef* s_CurrDisc = NULL; -ShockDiscInfo s_CurrDiscInfo; - -static s32 _shock_SetOrPokeDisc(void* psx, ShockDiscRef* disc, bool poke) -{ - ShockDiscInfo info; - strcpy(info.id,"\0\0\0\0"); - info.region = REGION_NONE; - if(disc != NULL) - { - shock_AnalyzeDisc(disc,&info); - } - - s_CurrDiscInfo = info; - s_CurrDisc = disc; - - CDC->SetDisc(s_CurrDisc,s_CurrDiscInfo.id, poke); - - return SHOCK_OK; -} - +EW_EXPORT s32 shock_CreateDisc(ShockDiscRef** outDisc, void *Opaque, s32 lbaCount, ShockDisc_ReadTOC ReadTOC, ShockDisc_ReadLBA ReadLBA2448, bool suppliesDeinterleavedSubcode) +{ + *outDisc = new ShockDiscRef(Opaque, lbaCount, ReadTOC, ReadLBA2448, suppliesDeinterleavedSubcode); + return SHOCK_OK; +} + +ShockDiscRef* s_CurrDisc = NULL; +ShockDiscInfo s_CurrDiscInfo; + +static s32 _shock_SetOrPokeDisc(void* psx, ShockDiscRef* disc, bool poke) +{ + ShockDiscInfo info; + strcpy(info.id,"\0\0\0\0"); + info.region = REGION_NONE; + if(disc != NULL) + { + shock_AnalyzeDisc(disc,&info); + } + + s_CurrDiscInfo = info; + s_CurrDisc = disc; + + CDC->SetDisc(s_CurrDisc,s_CurrDiscInfo.id, poke); + + return SHOCK_OK; +} + //Sets the disc in the tray. Returns SHOCK_NOCANDO if it's closed (TODO). You can pass NULL to remove a disc from the tray -EW_EXPORT s32 shock_SetDisc(void* psx, ShockDiscRef* disc) -{ - return _shock_SetOrPokeDisc(psx,disc,false); -} - -EW_EXPORT s32 shock_PokeDisc(void* psx, ShockDiscRef* disc) -{ - //let's talk about why this function is needed. well, let's paste an old comment on the subject: - //heres a comment from some old savestating code. something to keep in mind (maybe or maybe not a surprise depending on your point of view) - //"Call SetDisc() BEFORE we load CDC state, since SetDisc() has emulation side effects. We might want to clean this up in the future." - //I'm not really sure I like how SetDisc works, so I'm glad this was brought to our attention - - return _shock_SetOrPokeDisc(psx,disc,true); -} - +EW_EXPORT s32 shock_SetDisc(void* psx, ShockDiscRef* disc) +{ + return _shock_SetOrPokeDisc(psx,disc,false); +} + +EW_EXPORT s32 shock_PokeDisc(void* psx, ShockDiscRef* disc) +{ + //let's talk about why this function is needed. well, let's paste an old comment on the subject: + //heres a comment from some old savestating code. something to keep in mind (maybe or maybe not a surprise depending on your point of view) + //"Call SetDisc() BEFORE we load CDC state, since SetDisc() has emulation side effects. We might want to clean this up in the future." + //I'm not really sure I like how SetDisc works, so I'm glad this was brought to our attention + + return _shock_SetOrPokeDisc(psx,disc,true); +} + EW_EXPORT s32 shock_OpenTray(void* psx) { if(s_ShockState.eject) return SHOCK_NOCANDO; @@ -2159,181 +2152,181 @@ EW_EXPORT s32 shock_CloseTray(void* psx) CDC->CloseTray(false); return SHOCK_OK; } - - -EW_EXPORT s32 shock_DestroyDisc(ShockDiscRef* disc) -{ - delete disc; - return SHOCK_OK; -} - - -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; -}; - -//THIS CODE SHOULD BE REMOVED WHEN A MORE ROBUST ISO PARSER IS ADDED. -class ShockDiscRef_Stream_Thing : public Stream -{ - public: - - ShockDiscRef_Stream_Thing(ShockDiscRef *cdintf_arg, uint32 lba_arg, uint32 sector_count_arg); - ~ShockDiscRef_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: - ShockDiscRef *cdintf; - const uint32 start_lba; - const uint32 sector_count; - int64 position; -}; - -ShockDiscRef_Stream_Thing::ShockDiscRef_Stream_Thing(ShockDiscRef *cdintf_arg, uint32 start_lba_arg, uint32 sector_count_arg) - : cdintf(cdintf_arg) - , start_lba(start_lba_arg) - , sector_count(sector_count_arg) -{ - -} - -ShockDiscRef_Stream_Thing::~ShockDiscRef_Stream_Thing() -{ - -} - -uint64 ShockDiscRef_Stream_Thing::attributes(void) -{ - return(ATTRIBUTE_READABLE | ATTRIBUTE_SEEKABLE); -} - -uint8 *ShockDiscRef_Stream_Thing::map(void) -{ - return NULL; -} - -void ShockDiscRef_Stream_Thing::unmap(void) -{ - -} - -uint64 ShockDiscRef_Stream_Thing::read(void *data, uint64 count, bool error_on_eos) -{ - if(count > (((uint64)sector_count * 2048) - position)) - { - //if(error_on_eos) - //{ - // throw "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->ReadLBA2048(start_lba + (rp / 2048), buf)) - { - //throw MDFN_Error(ErrnoHolder(EIO)); - return 0; //??????????? - } - - //::printf("Meow: %08llx -- %08llx\n", count, (rp - position) + std::min(2048 - (rp & 2047), count - (rp - position))); - memcpy((uint8*)data + (rp - position), buf + (rp & 2047), std::min(2048 - (rp & 2047), count - (rp - position))); - } - - position += count; - - return count; -} - -void ShockDiscRef_Stream_Thing::write(const void *data, uint64 count) -{ - -} - -void ShockDiscRef_Stream_Thing::seek(int64 offset, int whence) -{ - int64 new_position; - - switch(whence) - { - default: - - 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 ShockDiscRef_Stream_Thing::tell(void) -{ - return position; -} - -int64 ShockDiscRef_Stream_Thing::size(void) -{ - return(sector_count * 2048); -} - -void ShockDiscRef_Stream_Thing::close(void) -{ - -} - + + +EW_EXPORT s32 shock_DestroyDisc(ShockDiscRef* disc) +{ + delete disc; + return SHOCK_OK; +} + + +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; +}; + +//THIS CODE SHOULD BE REMOVED WHEN A MORE ROBUST ISO PARSER IS ADDED. +class ShockDiscRef_Stream_Thing : public Stream +{ + public: + + ShockDiscRef_Stream_Thing(ShockDiscRef *cdintf_arg, uint32 lba_arg, uint32 sector_count_arg); + ~ShockDiscRef_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: + ShockDiscRef *cdintf; + const uint32 start_lba; + const uint32 sector_count; + int64 position; +}; + +ShockDiscRef_Stream_Thing::ShockDiscRef_Stream_Thing(ShockDiscRef *cdintf_arg, uint32 start_lba_arg, uint32 sector_count_arg) + : cdintf(cdintf_arg) + , start_lba(start_lba_arg) + , sector_count(sector_count_arg) +{ + +} + +ShockDiscRef_Stream_Thing::~ShockDiscRef_Stream_Thing() +{ + +} + +uint64 ShockDiscRef_Stream_Thing::attributes(void) +{ + return(ATTRIBUTE_READABLE | ATTRIBUTE_SEEKABLE); +} + +uint8 *ShockDiscRef_Stream_Thing::map(void) +{ + return NULL; +} + +void ShockDiscRef_Stream_Thing::unmap(void) +{ + +} + +uint64 ShockDiscRef_Stream_Thing::read(void *data, uint64 count, bool error_on_eos) +{ + if(count > (((uint64)sector_count * 2048) - position)) + { + //if(error_on_eos) + //{ + // throw "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->ReadLBA2048(start_lba + (rp / 2048), buf)) + { + //throw MDFN_Error(ErrnoHolder(EIO)); + return 0; //??????????? + } + + //::printf("Meow: %08llx -- %08llx\n", count, (rp - position) + std::min(2048 - (rp & 2047), count - (rp - position))); + memcpy((uint8*)data + (rp - position), buf + (rp & 2047), std::min(2048 - (rp & 2047), count - (rp - position))); + } + + position += count; + + return count; +} + +void ShockDiscRef_Stream_Thing::write(const void *data, uint64 count) +{ + +} + +void ShockDiscRef_Stream_Thing::seek(int64 offset, int whence) +{ + int64 new_position; + + switch(whence) + { + default: + + 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 ShockDiscRef_Stream_Thing::tell(void) +{ + return position; +} + +int64 ShockDiscRef_Stream_Thing::size(void) +{ + return(sector_count * 2048); +} + +void ShockDiscRef_Stream_Thing::close(void) +{ + +} + //Analyzes the disc by inspecting other things, in case the system.cnf determination failed static s32 AnalyzeDiscEx(ShockDiscRef* disc, ShockDiscInfo* info) { @@ -2396,105 +2389,105 @@ static s32 AnalyzeDiscEx(ShockDiscRef* disc, ShockDiscInfo* info) return SHOCK_ERROR; } - -//this is kind of lame. cant we get a proper iso fs parser here? + +//this is kind of lame. cant we get a proper iso fs parser here? EW_EXPORT s32 shock_AnalyzeDisc(ShockDiscRef* disc, ShockDiscInfo* info) -{ - 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 = new ShockDiscRef_Stream_Thing(disc, 0, ~0); - fp->seek(0x8000, SEEK_SET); - - do - { - if((pvd_search_count++) == 32) - throw "PVD search count limit met."; - - fp->read(pvd, 2048); - - if(memcmp(&pvd[1], "CD001", 5)) - throw "Not ISO-9660"; - - if(pvd[0] == 0xFF) - throw "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 "Root directory table too large"; - - fp->seek((int64)rdel * 2048, SEEK_SET); - //printf("%08x, %08x\n", rdel * 2048, rdel_len); - - //I think this loop is scanning directory entries until it finds system.cnf and if it never finishes we'll just fall out - 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); - - if((bootpos = strstr((char*)fb, "BOOT"))) - { - bootpos += 4; - while(*bootpos == ' ' || *bootpos == '\t') bootpos++; - if(*bootpos == '=') - { - bootpos++; - while(*bootpos == ' ' || *bootpos == '\t') bootpos++; - if(!strncasecmp(bootpos, "cdrom:", 6)) - { - char* tmp; - - bootpos += 6; - - // strrchr() way will pick up Tekken 3, but only enable if needed due to possibility of regressions. - //if((tmp = strrchr(bootpos, '\\'))) - // bootpos = tmp + 1; - while(*bootpos == '\\') - bootpos++; - - if((tmp = strchr(bootpos, '_'))) *tmp = 0; - if((tmp = strchr(bootpos, '.'))) *tmp = 0; - if((tmp = strchr(bootpos, ';'))) *tmp = 0; - //puts(bootpos); - - if(strlen(bootpos) == 4 && toupper(bootpos[0]) == 'S' && (toupper(bootpos[1]) == 'C' || toupper(bootpos[1]) == 'L' || toupper(bootpos[1]) == 'I')) - { - switch(toupper(bootpos[2])) +{ + 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 = new ShockDiscRef_Stream_Thing(disc, 0, ~0); + fp->seek(0x8000, SEEK_SET); + + do + { + if((pvd_search_count++) == 32) + throw "PVD search count limit met."; + + fp->read(pvd, 2048); + + if(memcmp(&pvd[1], "CD001", 5)) + throw "Not ISO-9660"; + + if(pvd[0] == 0xFF) + throw "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 "Root directory table too large"; + + fp->seek((int64)rdel * 2048, SEEK_SET); + //printf("%08x, %08x\n", rdel * 2048, rdel_len); + + //I think this loop is scanning directory entries until it finds system.cnf and if it never finishes we'll just fall out + 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); + + if((bootpos = strstr((char*)fb, "BOOT"))) + { + bootpos += 4; + while(*bootpos == ' ' || *bootpos == '\t') bootpos++; + if(*bootpos == '=') + { + bootpos++; + while(*bootpos == ' ' || *bootpos == '\t') bootpos++; + if(!strncasecmp(bootpos, "cdrom:", 6)) + { + char* tmp; + + bootpos += 6; + + // strrchr() way will pick up Tekken 3, but only enable if needed due to possibility of regressions. + //if((tmp = strrchr(bootpos, '\\'))) + // bootpos = tmp + 1; + while(*bootpos == '\\') + bootpos++; + + if((tmp = strchr(bootpos, '_'))) *tmp = 0; + if((tmp = strchr(bootpos, '.'))) *tmp = 0; + if((tmp = strchr(bootpos, ';'))) *tmp = 0; + //puts(bootpos); + + if(strlen(bootpos) == 4 && toupper(bootpos[0]) == 'S' && (toupper(bootpos[1]) == 'C' || toupper(bootpos[1]) == 'L' || toupper(bootpos[1]) == 'I')) + { + switch(toupper(bootpos[2])) { case 'E': info->region = REGION_EU; @@ -2523,9 +2516,9 @@ EW_EXPORT s32 shock_AnalyzeDisc(ShockDiscRef* disc, ShockDiscInfo* info) } } } - catch(const char* str) - { - //puts(e.what()); + catch(const char* str) + { + //puts(e.what()); } //uhmm couldnt find system.cnf. try another way @@ -2539,7 +2532,7 @@ Breakout: bool ShockDiscRef::ReadLBA_PW(uint8* pwbuf96, int32 lba, bool hint_fullread) { //TODO - whats that hint mean - //reference: static const int32 LBA_Read_Minimum = -150; + //reference: static const int32 LBA_Read_Minimum = -150; //reference: static const int32 LBA_Read_Maximum = 449849; // 100 * 75 * 60 - 150 - 1 u8 tmp[2448]; s32 ret = ReadLBA2448(lba,tmp); @@ -2551,13 +2544,13 @@ bool ShockDiscRef::ReadLBA_PW(uint8* pwbuf96, int32 lba, bool hint_fullread) s32 ShockDiscRef::ReadLBA2448(s32 lba, void* dst2448) { - return InternalReadLBA2448(lba, dst2448, true); + return InternalReadLBA2448(lba, dst2448, true); } s32 ShockDiscRef::InternalReadLBA2448(s32 lba, void* dst2448, bool needSubcode) { - int ret = mcbReadLBA2448(mOpaque, lba, dst2448); - if(ret != SHOCK_OK) + int ret = mcbReadLBA2448(mOpaque, lba, dst2448); + if(ret != SHOCK_OK) return ret; if(needSubcode && mSuppliesDeinterleavedSubcode) @@ -2575,48 +2568,48 @@ s32 ShockDiscRef::InternalReadLBA2448(s32 lba, void* dst2448, bool needSubcode) //adapts the ReadLBA2448 results to a 2048 byte sector and returns the mode, as required s32 ShockDiscRef::ReadLBA2048(s32 lba, void* dst2048) { - union Sector { - struct { - u8 sync[12]; - u8 adr[3]; - u8 mode; - union { - struct { - u8 data2048[2048]; - u8 ecc[4]; - u8 reserved[8]; - u8 ecm[276]; - }; - u8 data2336[2336]; - }; - }; - u8 buf[2352]; - }; - - union XASector { - struct { - u8 sync[12]; - u8 adr[3]; - u8 mode; - u8 subheader[8]; - union { - u8 data2048[2048]; - u8 ecc[4]; - u8 ecm[276]; - } form1; - union { - u8 data2334[2334]; - u8 ecc[4]; - } form2; - }; - u8 buf[2352]; + union Sector { + struct { + u8 sync[12]; + u8 adr[3]; + u8 mode; + union { + struct { + u8 data2048[2048]; + u8 ecc[4]; + u8 reserved[8]; + u8 ecm[276]; + }; + u8 data2336[2336]; + }; + }; + u8 buf[2352]; + }; + + union XASector { + struct { + u8 sync[12]; + u8 adr[3]; + u8 mode; + u8 subheader[8]; + union { + u8 data2048[2048]; + u8 ecc[4]; + u8 ecm[276]; + } form1; + union { + u8 data2334[2334]; + u8 ecc[4]; + } form2; + }; + u8 buf[2352]; }; static union { struct { - union { - XASector xasector; - Sector sector; + union { + XASector xasector; + Sector sector; }; u8 subcode[96]; }; @@ -2627,10 +2620,10 @@ s32 ShockDiscRef::ReadLBA2048(s32 lba, void* dst2048) if(ret != SHOCK_OK) return ret; - if(sector.mode == 1) - memcpy(dst2048,sector.data2048,2048); - else - memcpy(dst2048,xasector.form1.data2048,2048); + if(sector.mode == 1) + memcpy(dst2048,sector.data2048,2048); + else + memcpy(dst2048,xasector.form1.data2048,2048); return sector.mode; } @@ -2691,8 +2684,8 @@ SYNCFUNC(PSX) TSS(CPU); - ns->EnterSection("GTE"); - GTE_SyncState(isReader,ns); + ns->EnterSection("GTE"); + GTE_SyncState(isReader,ns); ns->ExitSection("GTE"); ns->EnterSection("DMA"); @@ -2740,39 +2733,39 @@ EW_EXPORT s32 shock_StateTransaction(void *psx, ShockStateTransaction* transacti { switch(transaction->transaction) { - case eShockStateTransaction_BinarySize: - { - EW::NewStateDummy dummy; - s_PSX.SyncState(&dummy); - return dummy.GetLength(); - } - case eShockStateTransaction_BinaryLoad: - { - if(transaction->buffer == NULL) return SHOCK_ERROR; - EW::NewStateExternalBuffer loader((char*)transaction->buffer, transaction->bufferLength); - s_PSX.SyncState(&loader); - if(!loader.Overflow() && loader.GetLength() == transaction->bufferLength) - return SHOCK_OK; - else return SHOCK_ERROR; - } - case eShockStateTransaction_BinarySave: - { - if(transaction->buffer == NULL) return SHOCK_ERROR; - EW::NewStateExternalBuffer saver((char*)transaction->buffer, transaction->bufferLength); - s_PSX.SyncState(&saver); - if(!saver.Overflow() && saver.GetLength() == transaction->bufferLength) - return SHOCK_OK; - else return SHOCK_ERROR; - } - case eShockStateTransaction_TextLoad: - { - EW::NewStateExternalFunctions saver(&transaction->ff); - s_PSX.SyncState(&saver); - return SHOCK_OK; - } + case eShockStateTransaction_BinarySize: + { + EW::NewStateDummy dummy; + s_PSX.SyncState(&dummy); + return dummy.GetLength(); + } + case eShockStateTransaction_BinaryLoad: + { + if(transaction->buffer == NULL) return SHOCK_ERROR; + EW::NewStateExternalBuffer loader((char*)transaction->buffer, transaction->bufferLength); + s_PSX.SyncState(&loader); + if(!loader.Overflow() && loader.GetLength() == transaction->bufferLength) + return SHOCK_OK; + else return SHOCK_ERROR; + } + case eShockStateTransaction_BinarySave: + { + if(transaction->buffer == NULL) return SHOCK_ERROR; + EW::NewStateExternalBuffer saver((char*)transaction->buffer, transaction->bufferLength); + s_PSX.SyncState(&saver); + if(!saver.Overflow() && saver.GetLength() == transaction->bufferLength) + return SHOCK_OK; + else return SHOCK_ERROR; + } + case eShockStateTransaction_TextLoad: + { + EW::NewStateExternalFunctions saver(&transaction->ff); + s_PSX.SyncState(&saver); + return SHOCK_OK; + } case eShockStateTransaction_TextSave: { - EW::NewStateExternalFunctions loader(&transaction->ff); + EW::NewStateExternalFunctions loader(&transaction->ff); s_PSX.SyncState(&loader); return SHOCK_OK; } @@ -2787,10 +2780,10 @@ EW_EXPORT s32 shock_GetRegisters_CPU(void* psx, ShockRegisters_CPU* buffer) { memcpy(buffer->GPR,CPU->debug_GetGPRPtr(),32*4); buffer->PC = CPU->GetRegister(PS_CPU::GSREG_PC_NEXT,NULL,0); - buffer->PC_NEXT = CPU->GetRegister(PS_CPU::GSREG_PC_NEXT,NULL,0); - buffer->IN_BD_SLOT = CPU->GetRegister(PS_CPU::GSREG_IN_BD_SLOT,NULL,0); - buffer->LO = CPU->GetRegister(PS_CPU::GSREG_LO,NULL,0); - buffer->HI = CPU->GetRegister(PS_CPU::GSREG_HI,NULL,0); + buffer->PC_NEXT = CPU->GetRegister(PS_CPU::GSREG_PC_NEXT,NULL,0); + buffer->IN_BD_SLOT = CPU->GetRegister(PS_CPU::GSREG_IN_BD_SLOT,NULL,0); + buffer->LO = CPU->GetRegister(PS_CPU::GSREG_LO,NULL,0); + buffer->HI = CPU->GetRegister(PS_CPU::GSREG_HI,NULL,0); buffer->SR = CPU->GetRegister(PS_CPU::GSREG_SR,NULL,0); buffer->CAUSE = CPU->GetRegister(PS_CPU::GSREG_CAUSE,NULL,0); buffer->EPC = CPU->GetRegister(PS_CPU::GSREG_EPC,NULL,0); @@ -2798,54 +2791,54 @@ EW_EXPORT s32 shock_GetRegisters_CPU(void* psx, ShockRegisters_CPU* buffer) return SHOCK_OK; } -//Sets a CPU register. Rather than have an enum for the registers, lets just use the index (not offset) within the struct -EW_EXPORT s32 shock_SetRegister_CPU(void* psx, s32 index, u32 value) -{ - //takes advantage of layout of GSREG_ matchign our struct (not an accident!) - CPU->SetRegister((u32)index,value); - - return SHOCK_OK; -} - -EW_EXPORT s32 shock_SetRenderOptions(void* pxs, ShockRenderOptions* opts) -{ - GPU.SetRenderOptions(opts); - s_ShockConfig.opts = *opts; - return SHOCK_OK; -} - -extern void* g_ShockTraceCallbackOpaque; -extern ShockCallback_Trace g_ShockTraceCallback; -extern ShockCallback_Mem g_ShockMemCallback; -extern eShockMemCb g_ShockMemCbType; - -//Sets the callback to be used for CPU tracing -EW_EXPORT s32 shock_SetTraceCallback(void* psx, void* opaque, ShockCallback_Trace callback) -{ - g_ShockTraceCallbackOpaque = opaque; - g_ShockTraceCallback = callback; - - return SHOCK_OK; -} - -//Sets the callback to be used for memory hook events -EW_EXPORT s32 shock_SetMemCb(void* psx, ShockCallback_Mem callback, eShockMemCb cbMask) -{ - g_ShockMemCallback = callback; - g_ShockMemCbType = cbMask; - return SHOCK_OK; -} - -//Sets whether LEC is enabled (sector level error correction). Defaults to FALSE (disabled) -EW_EXPORT s32 shock_SetLEC(void* psx, bool enabled) -{ - CDC->SetLEC(enabled); - return SHOCK_OK; -} - -//whether "determine lag from GPU frames" signal is set (GPU did something considered non-lag) -//returns SHOCK_TRUE or SHOCK_FALSE -EW_EXPORT s32 shock_GetGPUUnlagged(void* psx) -{ - return GpuFrameForLag ? SHOCK_TRUE : SHOCK_FALSE; +//Sets a CPU register. Rather than have an enum for the registers, lets just use the index (not offset) within the struct +EW_EXPORT s32 shock_SetRegister_CPU(void* psx, s32 index, u32 value) +{ + //takes advantage of layout of GSREG_ matchign our struct (not an accident!) + CPU->SetRegister((u32)index,value); + + return SHOCK_OK; +} + +EW_EXPORT s32 shock_SetRenderOptions(void* pxs, ShockRenderOptions* opts) +{ + GPU.SetRenderOptions(opts); + s_ShockConfig.opts = *opts; + return SHOCK_OK; +} + +extern void* g_ShockTraceCallbackOpaque; +extern ShockCallback_Trace g_ShockTraceCallback; +extern ShockCallback_Mem g_ShockMemCallback; +extern eShockMemCb g_ShockMemCbType; + +//Sets the callback to be used for CPU tracing +EW_EXPORT s32 shock_SetTraceCallback(void* psx, void* opaque, ShockCallback_Trace callback) +{ + g_ShockTraceCallbackOpaque = opaque; + g_ShockTraceCallback = callback; + + return SHOCK_OK; +} + +//Sets the callback to be used for memory hook events +EW_EXPORT s32 shock_SetMemCb(void* psx, ShockCallback_Mem callback, eShockMemCb cbMask) +{ + g_ShockMemCallback = callback; + g_ShockMemCbType = cbMask; + return SHOCK_OK; +} + +//Sets whether LEC is enabled (sector level error correction). Defaults to FALSE (disabled) +EW_EXPORT s32 shock_SetLEC(void* psx, bool enabled) +{ + CDC->SetLEC(enabled); + return SHOCK_OK; +} + +//whether "determine lag from GPU frames" signal is set (GPU did something considered non-lag) +//returns SHOCK_TRUE or SHOCK_FALSE +EW_EXPORT s32 shock_GetGPUUnlagged(void* psx) +{ + return GpuFrameForLag ? SHOCK_TRUE : SHOCK_FALSE; } \ No newline at end of file diff --git a/psx/octoshock/psx/psx.h b/psx/octoshock/psx/psx.h index cbd5ce9743..6b8696b249 100644 --- a/psx/octoshock/psx/psx.h +++ b/psx/octoshock/psx/psx.h @@ -1,22 +1,22 @@ -/******************************************************************************/ -/* Mednafen Sony PS1 Emulation Module */ -/******************************************************************************/ -/* psx.h: -** Copyright (C) 2011-2016 Mednafen Team -** -** This program is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License -** as published by the Free Software Foundation; either version 2 -** of the License, or (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software Foundation, Inc., -** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +/******************************************************************************/ +/* Mednafen Sony PS1 Emulation Module */ +/******************************************************************************/ +/* psx.h: +** Copyright (C) 2011-2016 Mednafen Team +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once @@ -54,7 +54,7 @@ namespace MDFN_IEN_PSX #define PSX_DBG_FLOOD 4 // Heavy informational debug messages(GPU commands; TODO). #if PSX_DBGPRINT_ENABLE - void PSX_DBG(unsigned level, const char *format, ...) noexcept MDFN_COLD MDFN_FORMATSTR(gnu_printf, 2, 3); + void PSX_DBG(unsigned level, const char *format, ...) noexcept MDFN_COLD MDFN_FORMATSTR(gnu_printf, 2, 3); void PSX_DBG_BIOS_PUTC(uint8 c) noexcept; #define PSX_WARNING(format, ...) { PSX_DBG(PSX_DBG_WARNING, format "\n", ## __VA_ARGS__); } @@ -68,17 +68,17 @@ namespace MDFN_IEN_PSX typedef int32 pscpu_timestamp_t; - bool PSX_EventHandler(const pscpu_timestamp_t timestamp); + bool MDFN_FASTCALL PSX_EventHandler(const pscpu_timestamp_t timestamp); - void PSX_MemWrite8(pscpu_timestamp_t timestamp, uint32 A, uint32 V); - void PSX_MemWrite16(pscpu_timestamp_t timestamp, uint32 A, uint32 V); - void PSX_MemWrite24(pscpu_timestamp_t timestamp, uint32 A, uint32 V); - void PSX_MemWrite32(pscpu_timestamp_t timestamp, uint32 A, uint32 V); + void MDFN_FASTCALL PSX_MemWrite8(pscpu_timestamp_t timestamp, uint32 A, uint32 V); + void MDFN_FASTCALL PSX_MemWrite16(pscpu_timestamp_t timestamp, uint32 A, uint32 V); + void MDFN_FASTCALL PSX_MemWrite24(pscpu_timestamp_t timestamp, uint32 A, uint32 V); + void MDFN_FASTCALL PSX_MemWrite32(pscpu_timestamp_t timestamp, uint32 A, uint32 V); - uint8 PSX_MemRead8(pscpu_timestamp_t ×tamp, uint32 A); - uint16 PSX_MemRead16(pscpu_timestamp_t ×tamp, uint32 A); - uint32 PSX_MemRead24(pscpu_timestamp_t ×tamp, uint32 A); - uint32 PSX_MemRead32(pscpu_timestamp_t ×tamp, uint32 A); + uint8 MDFN_FASTCALL PSX_MemRead8(pscpu_timestamp_t ×tamp, uint32 A); + uint16 MDFN_FASTCALL PSX_MemRead16(pscpu_timestamp_t ×tamp, uint32 A); + uint32 MDFN_FASTCALL PSX_MemRead24(pscpu_timestamp_t ×tamp, uint32 A); + uint32 MDFN_FASTCALL PSX_MemRead32(pscpu_timestamp_t ×tamp, uint32 A); uint8 PSX_MemPeek8(uint32 A); uint16 PSX_MemPeek16(uint32 A); @@ -129,10 +129,10 @@ namespace MDFN_IEN_PSX class PS_CDC; class PS_SPU; - extern PS_CPU *CPU; - extern PS_CDC *CDC; - extern PS_SPU *SPU; - extern MultiAccessSizeMem<2048 * 1024, false> MainRAM; + MDFN_HIDE extern PS_CPU *CPU; + MDFN_HIDE extern PS_CDC *CDC; + MDFN_HIDE extern PS_SPU *SPU; + MDFN_HIDE extern MultiAccessSizeMem<2048 * 1024, false> MainRAM; } enum eRegion @@ -143,11 +143,11 @@ enum eRegion REGION_NONE = 3 }; -enum eShockDeinterlaceMode -{ - eShockDeinterlaceMode_Weave, - eShockDeinterlaceMode_Bob, - eShockDeinterlaceMode_BobOffset +enum eShockDeinterlaceMode +{ + eShockDeinterlaceMode_Weave, + eShockDeinterlaceMode_Bob, + eShockDeinterlaceMode_BobOffset }; enum eShockStep @@ -195,31 +195,31 @@ enum ePeripheralType ePeripheralType_Multitap = 10, }; -enum eShockStateTransaction : s32 -{ - eShockStateTransaction_BinarySize = 0, - eShockStateTransaction_BinaryLoad = 1, - eShockStateTransaction_BinarySave = 2, - eShockStateTransaction_TextLoad = 3, - eShockStateTransaction_TextSave = 4 +enum eShockStateTransaction : s32 +{ + eShockStateTransaction_BinarySize = 0, + eShockStateTransaction_BinaryLoad = 1, + eShockStateTransaction_BinarySave = 2, + eShockStateTransaction_TextLoad = 3, + eShockStateTransaction_TextSave = 4 }; -enum eShockMemcardTransaction -{ - eShockMemcardTransaction_Connect = 0, //connects it to the addressed port (not supported yet) - eShockMemcardTransaction_Disconnect = 1, //disconnects it from the addressed port (not supported yet) - eShockMemcardTransaction_Write = 2, //writes from the frontend to the memcard - eShockMemcardTransaction_Read = 3, //reads from the memcard to the frontend. Also clears the dirty flag - eShockMemcardTransaction_CheckDirty = 4, //checks whether the memcard is dirty +enum eShockMemcardTransaction +{ + eShockMemcardTransaction_Connect = 0, //connects it to the addressed port (not supported yet) + eShockMemcardTransaction_Disconnect = 1, //disconnects it from the addressed port (not supported yet) + eShockMemcardTransaction_Write = 2, //writes from the frontend to the memcard + eShockMemcardTransaction_Read = 3, //reads from the memcard to the frontend. Also clears the dirty flag + eShockMemcardTransaction_CheckDirty = 4, //checks whether the memcard is dirty }; -enum eShockMemCb -{ - eShockMemCb_None = 0, - eShockMemCb_Read = 1, - eShockMemCb_Write = 2, - eShockMemCb_Execute = 4 -}; +enum eShockMemCb +{ + eShockMemCb_None = 0, + eShockMemCb_Read = 1, + eShockMemCb_Write = 2, + eShockMemCb_Execute = 4 +}; #define MDFN_MSC_RESET 0 #define MDFN_MSC_POWER 1 @@ -249,67 +249,67 @@ struct ShockTOC u8 disc_type; }; -struct ShockRegisters_CPU -{ - u32 GPR[32]; - u32 PC, PC_NEXT; - u32 IN_BD_SLOT; - u32 LO, HI; - u32 SR, CAUSE, EPC; +struct ShockRegisters_CPU +{ + u32 GPR[32]; + u32 PC, PC_NEXT; + u32 IN_BD_SLOT; + u32 LO, HI; + u32 SR, CAUSE, EPC; }; // [0] is unused, [100] is for the leadout track. // Also, for convenience, tracks[last_track + 1] will always refer // to the leadout track(even if last_track < 99, IE the leadout track details are duplicated). -typedef s32 (*ShockDisc_ReadTOC)(void* opaque, ShockTOC *read_target, ShockTOCTrack tracks[100 + 1]); -typedef s32 (*ShockDisc_ReadLBA)(void* opaque, s32 lba, void* dst); - -//The callback to be issued for traces -typedef void (*ShockCallback_Trace)(void* opaque, u32 PC, u32 inst, const char* msg); - -//the callback to be issued for memory hook events -//note: only one callback can be set. the type is sent to mask that one callback, not indicate which event type the callback is fore. -//there isnt one callback per type. -typedef void (*ShockCallback_Mem)(u32 address, eShockMemCb type, u32 size, u32 value); - -class ShockDiscRef -{ -public: - ShockDiscRef(void *opaque, s32 lbaCount, ShockDisc_ReadTOC cbReadTOC, ShockDisc_ReadLBA cbReadLBA2448, bool suppliesDeinterleavedSubcode) - : mOpaque(opaque) - , mLbaCount(lbaCount) - , mcbReadTOC(cbReadTOC) - , mcbReadLBA2448(cbReadLBA2448) - , mSuppliesDeinterleavedSubcode(suppliesDeinterleavedSubcode) - { - } - - s32 ReadTOC( ShockTOC *read_target, ShockTOCTrack tracks[100 + 1]) - { - return mcbReadTOC(mOpaque, read_target, tracks); - } - - //formerly ReadRawSector - //Reads 2352 + 96 - s32 ReadLBA2448(s32 lba, void* dst2448); - - //formerly ReadRawSectorPWOnly - //Reads 96 bytes (of raw subchannel PW data) into pwbuf. - //Probably the same format as what's at the end of ReadLBA2448 - //TODO - reorder args - bool ReadLBA_PW(uint8* pwbuf96, int32 lba, bool hint_fullread); - - //only used by disc analysis stuff which should be refactored anyway. should eventually be removed - s32 ReadLBA2048(s32 lba, void* dst2048); - -private: - s32 InternalReadLBA2448(s32 lba, void* dst2448, bool needSubcode); - void *mOpaque; - s32 mLbaCount; - ShockDisc_ReadTOC mcbReadTOC; - ShockDisc_ReadLBA mcbReadLBA2448; - bool mSuppliesDeinterleavedSubcode; -}; +typedef s32 (*ShockDisc_ReadTOC)(void* opaque, ShockTOC *read_target, ShockTOCTrack tracks[100 + 1]); +typedef s32 (*ShockDisc_ReadLBA)(void* opaque, s32 lba, void* dst); + +//The callback to be issued for traces +typedef void (*ShockCallback_Trace)(void* opaque, u32 PC, u32 inst, const char* msg); + +//the callback to be issued for memory hook events +//note: only one callback can be set. the type is sent to mask that one callback, not indicate which event type the callback is fore. +//there isnt one callback per type. +typedef void (*ShockCallback_Mem)(u32 address, eShockMemCb type, u32 size, u32 value); + +class ShockDiscRef +{ +public: + ShockDiscRef(void *opaque, s32 lbaCount, ShockDisc_ReadTOC cbReadTOC, ShockDisc_ReadLBA cbReadLBA2448, bool suppliesDeinterleavedSubcode) + : mOpaque(opaque) + , mLbaCount(lbaCount) + , mcbReadTOC(cbReadTOC) + , mcbReadLBA2448(cbReadLBA2448) + , mSuppliesDeinterleavedSubcode(suppliesDeinterleavedSubcode) + { + } + + s32 ReadTOC( ShockTOC *read_target, ShockTOCTrack tracks[100 + 1]) + { + return mcbReadTOC(mOpaque, read_target, tracks); + } + + //formerly ReadRawSector + //Reads 2352 + 96 + s32 ReadLBA2448(s32 lba, void* dst2448); + + //formerly ReadRawSectorPWOnly + //Reads 96 bytes (of raw subchannel PW data) into pwbuf. + //Probably the same format as what's at the end of ReadLBA2448 + //TODO - reorder args + bool ReadLBA_PW(uint8* pwbuf96, int32 lba, bool hint_fullread); + + //only used by disc analysis stuff which should be refactored anyway. should eventually be removed + s32 ReadLBA2048(s32 lba, void* dst2048); + +private: + s32 InternalReadLBA2448(s32 lba, void* dst2448, bool needSubcode); + void *mOpaque; + s32 mLbaCount; + ShockDisc_ReadTOC mcbReadTOC; + ShockDisc_ReadLBA mcbReadLBA2448; + bool mSuppliesDeinterleavedSubcode; +}; struct ShockDiscInfo { @@ -322,87 +322,87 @@ struct ShockFramebufferInfo s32 width, height; s32 flags; void* ptr; -}; - -struct ShockRenderOptions -{ - s32 scanline_start, scanline_end; - eShockRenderType renderType; - eShockDeinterlaceMode deinterlaceMode; - bool skip; -}; - -struct ShockMemcardTransaction -{ - eShockMemcardTransaction transaction; - void* buffer128k; -}; +}; + +struct ShockRenderOptions +{ + s32 scanline_start, scanline_end; + eShockRenderType renderType; + eShockDeinterlaceMode deinterlaceMode; + bool skip; +}; + +struct ShockMemcardTransaction +{ + eShockMemcardTransaction transaction; + void* buffer128k; +}; struct ShockStateTransaction { eShockStateTransaction transaction; - void *buffer; - s32 bufferLength; - - //originally this was a pointer, however, we had problems getting it to marshal correctly - EW::FPtrs ff; + void *buffer; + s32 bufferLength; + + //originally this was a pointer, however, we had problems getting it to marshal correctly + EW::FPtrs ff; }; - -//Creates a ShockDiscRef (representing a disc) with the given properties. Returns it in the specified output pointer. -//The ReadLBA2048 function should return 0x01 or 0x02 depending on which mode was there. -//Others should return SHOCK_OK -EW_EXPORT s32 shock_CreateDisc(ShockDiscRef** outDisc, void *Opaque, s32 lbaCount, ShockDisc_ReadTOC ReadTOC, ShockDisc_ReadLBA ReadLBA2448, bool suppliesDeinterleavedSubcode); - -//Destroys a ShockDiscRef created with shock_CreateDisc. Make sure you havent left it in the playstation before destroying it! -EW_EXPORT s32 shock_DestroyDisc(ShockDiscRef* disc); - -//Inspects a disc by looking for the system.cnf and retrieves some necessary information about it. -//Useful for determining the region of a disc -EW_EXPORT s32 shock_AnalyzeDisc(ShockDiscRef* disc, ShockDiscInfo* info); - + +//Creates a ShockDiscRef (representing a disc) with the given properties. Returns it in the specified output pointer. +//The ReadLBA2048 function should return 0x01 or 0x02 depending on which mode was there. +//Others should return SHOCK_OK +EW_EXPORT s32 shock_CreateDisc(ShockDiscRef** outDisc, void *Opaque, s32 lbaCount, ShockDisc_ReadTOC ReadTOC, ShockDisc_ReadLBA ReadLBA2448, bool suppliesDeinterleavedSubcode); + +//Destroys a ShockDiscRef created with shock_CreateDisc. Make sure you havent left it in the playstation before destroying it! +EW_EXPORT s32 shock_DestroyDisc(ShockDiscRef* disc); + +//Inspects a disc by looking for the system.cnf and retrieves some necessary information about it. +//Useful for determining the region of a disc +EW_EXPORT s32 shock_AnalyzeDisc(ShockDiscRef* disc, ShockDiscInfo* info); + //Creates the psx instance as a console of the specified region. //Additionally mounts the firmware from the provided buffer (the contents are copied) //TODO - receive a model number parameter instead -EW_EXPORT s32 shock_Create(void** psx, s32 region, void* firmware512k); - -//Frees the psx instance created with shock_Create -EW_EXPORT s32 shock_Destroy(void* psx); - -//Attaches (or detaches) a peripheral at the given address. -//Send ePeripheralType_None to detach. -//Do not attach when something is already attached. -//You can detach when nothing is attached. -//Returns SHOCK_NOCANDO if something inappropriate is done. -//Presently this has only been validated as functioning correctly before the initial PowerOn, but we would like to use it other times. -EW_EXPORT s32 shock_Peripheral_Connect(void* psx, s32 address, s32 type); - -//Sets pad-type input (pad,dualshock,dualanalog) on the specified address; -//Read more about the input format (buttons, analog range) here: TBD -EW_EXPORT s32 shock_Peripheral_SetPadInput(void* psx, s32 address, u32 buttons, u8 left_x, u8 left_y, u8 right_x, u8 right_y); - -//Performs one of several transactions on an attached memory card. -EW_EXPORT s32 shock_Peripheral_MemcardTransact(void* psx, s32 address, ShockMemcardTransaction* transaction); - -//Polls the given peripheral address for it's active flag status (inverse of lag flag) -//If you want, the lag flag can be cleared -//Returns SHOCK_TRUE if the input has been read this frame -//Returns SHOCK_FALSE if the input hasnt been read this frame (is lagging) -//Returns SHOCK_NOCANDO if there is no peripheral there -//Returns SHOCK_INVALID_ADDRESS if address is invalid -//Returns SHOCK_ERROR for other errors. -EW_EXPORT s32 shock_Peripheral_PollActive(void* psx, s32 address, s32 clear); - -//Mounts a PS-EXE executable -EW_EXPORT s32 shock_MountEXE(void* psx, void* exebuf, s32 size, s32 ignore_pcsp); - -//Sets the power to ON. Returns SHOCK_NOCANDO if already on. -EW_EXPORT s32 shock_PowerOn(void* psx); - -//Triggers a soft reset immediately. Returns SHOCK_NOCANDO if console is powered off. -EW_EXPORT s32 shock_SoftReset(void* psx); - -//Sets the power to OFF. Returns SHOCK_NOCANDO if already off. -EW_EXPORT s32 shock_PowerOff(void* psx); +EW_EXPORT s32 shock_Create(void** psx, s32 region, void* firmware512k); + +//Frees the psx instance created with shock_Create +EW_EXPORT s32 shock_Destroy(void* psx); + +//Attaches (or detaches) a peripheral at the given address. +//Send ePeripheralType_None to detach. +//Do not attach when something is already attached. +//You can detach when nothing is attached. +//Returns SHOCK_NOCANDO if something inappropriate is done. +//Presently this has only been validated as functioning correctly before the initial PowerOn, but we would like to use it other times. +EW_EXPORT s32 shock_Peripheral_Connect(void* psx, s32 address, s32 type); + +//Sets pad-type input (pad,dualshock,dualanalog) on the specified address; +//Read more about the input format (buttons, analog range) here: TBD +EW_EXPORT s32 shock_Peripheral_SetPadInput(void* psx, s32 address, u32 buttons, u8 left_x, u8 left_y, u8 right_x, u8 right_y); + +//Performs one of several transactions on an attached memory card. +EW_EXPORT s32 shock_Peripheral_MemcardTransact(void* psx, s32 address, ShockMemcardTransaction* transaction); + +//Polls the given peripheral address for it's active flag status (inverse of lag flag) +//If you want, the lag flag can be cleared +//Returns SHOCK_TRUE if the input has been read this frame +//Returns SHOCK_FALSE if the input hasnt been read this frame (is lagging) +//Returns SHOCK_NOCANDO if there is no peripheral there +//Returns SHOCK_INVALID_ADDRESS if address is invalid +//Returns SHOCK_ERROR for other errors. +EW_EXPORT s32 shock_Peripheral_PollActive(void* psx, s32 address, s32 clear); + +//Mounts a PS-EXE executable +EW_EXPORT s32 shock_MountEXE(void* psx, void* exebuf, s32 size, s32 ignore_pcsp); + +//Sets the power to ON. Returns SHOCK_NOCANDO if already on. +EW_EXPORT s32 shock_PowerOn(void* psx); + +//Triggers a soft reset immediately. Returns SHOCK_NOCANDO if console is powered off. +EW_EXPORT s32 shock_SoftReset(void* psx); + +//Sets the power to OFF. Returns SHOCK_NOCANDO if already off. +EW_EXPORT s32 shock_PowerOff(void* psx); //Opens the disc tray. Returns SHOCK_NOCANDO if already open. EW_EXPORT s32 shock_OpenTray(void* psx); @@ -437,20 +437,20 @@ EW_EXPORT s32 shock_GetSamples(void* psx, void* buffer); EW_EXPORT s32 shock_GetMemData(void* psx, void** ptr, s32* size, s32 memType); //Savestate work. Returns the size if that's what was requested, otherwise error codes -EW_EXPORT s32 shock_StateTransaction(void *psx, ShockStateTransaction* transaction); - -//Retrieves the CPU registers in a compact struct -EW_EXPORT s32 shock_GetRegisters_CPU(void* psx, ShockRegisters_CPU* buffer); - -//Sets a CPU register. Rather than have an enum for the registers, lets just use the index (not offset) within the struct -EW_EXPORT s32 shock_SetRegister_CPU(void* psx, s32 index, u32 value); - -//Sets the callback to be used for CPU tracing -EW_EXPORT s32 shock_SetTraceCallback(void* psx, void* opaque, ShockCallback_Trace callback); - -//Sets whether LEC is enabled (sector level error correction). Defaults to FALSE (disabled) -EW_EXPORT s32 shock_SetLEC(void* psx, bool enabled); - -//whether "determine lag from GPU frames" signal is set (GPU did something considered non-lag) -//returns SHOCK_TRUE or SHOCK_FALSE -EW_EXPORT s32 shock_GetGPUUnlagged(void* psx); +EW_EXPORT s32 shock_StateTransaction(void *psx, ShockStateTransaction* transaction); + +//Retrieves the CPU registers in a compact struct +EW_EXPORT s32 shock_GetRegisters_CPU(void* psx, ShockRegisters_CPU* buffer); + +//Sets a CPU register. Rather than have an enum for the registers, lets just use the index (not offset) within the struct +EW_EXPORT s32 shock_SetRegister_CPU(void* psx, s32 index, u32 value); + +//Sets the callback to be used for CPU tracing +EW_EXPORT s32 shock_SetTraceCallback(void* psx, void* opaque, ShockCallback_Trace callback); + +//Sets whether LEC is enabled (sector level error correction). Defaults to FALSE (disabled) +EW_EXPORT s32 shock_SetLEC(void* psx, bool enabled); + +//whether "determine lag from GPU frames" signal is set (GPU did something considered non-lag) +//returns SHOCK_TRUE or SHOCK_FALSE +EW_EXPORT s32 shock_GetGPUUnlagged(void* psx);